Version 1.15.0

Merge commit '8407f1da7771279b41fae8ddad02cc160d983a57' into stable
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 21f0ea8..0251c0d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,59 @@
+## 1.15.0 - 2016-03-09
+
+### 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`.
+  * **Breaking** The named `directory` argument of
+    `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.
+
+### Dartium
+
+  * The Chrome-based tools that ship as part of the Dart SDK – Dartium and
+    content shell – are now based on Chrome version 45 (instead of Chrome 39).
+  * Dart browser libraries (`dart:html`, `dart:svg`, etc) have not been updated.
+    * These are still based on Chrome 39.
+    * These APIs will be updated in a future release.
+  * Note that there are experimental APIs which have changed in the underlying
+    browser, and will not work with the older libraries.
+    For example, `Element.animate`.
+
+### Service protocol changes
+
+* Fixed a documentation bug where the field `extensionRPCs` in `Isolate`
+  was not marked optional.
+
+### Experimental 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 additional configuration:
+    ```yaml
+    analyzer:
+      language:
+        enableConditionalDirectives: true
+    ```
+
+    Read about [configuring the analyzer] for more details.
+
+[configuring the analyzer]: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer
+
 ## 1.14.2 - 2016-02-10
 
 Patch release, resolves three issues:
@@ -19,7 +75,7 @@
 during isolate initialization.
 (SDK issue [25618](https://github.com/dart-lang/sdk/issues/25618))
 
-## 1.14.0 - 2016-1-28
+## 1.14.0 - 2016-01-28
 
 ### Core library changes
 * `dart:async`
diff --git a/DEPS b/DEPS
index fd30f1f..38ccb51 100644
--- a/DEPS
+++ b/DEPS
@@ -38,9 +38,9 @@
   "crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
   "csslib_tag" : "@0.12.0",
   "dart2js_info_rev" : "@0a221eaf16aec3879c45719de656680ccb80d8a1",
-  "dartdoc_tag" : "@v0.8.5",
+  "dartdoc_tag" : "@v0.9.0",
   "dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
-  "dart_style_tag": "@0.2.2",
+  "dart_style_tag": "@0.2.4",
   "dev_compiler_rev": "@0.1.9",
   "glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
   "html_tag" : "@0.12.1+1",
@@ -52,7 +52,7 @@
   "intl_rev": "@a8b480b9c436f6c0ec16730804c914bdb4e30d53",
   "jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "@1.1.1",
-  "linter_rev": "@5a599fd32d3b6ef00ffa7c330d1f32bbad287228",
+  "linter_rev": "@ce7aa0ec03ee738f4d314138228e0b4742845810",
   "logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
   "markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
   "matcher_tag": "@0.12.0",
@@ -67,10 +67,11 @@
   "ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
   "plugin_tag": "@0.1.0",
   "pool_tag": "@1.2.1",
-  "pub_rev": "@5738fb4592c96ffb0439e92ae8b823ccdc0a6623",
+  "pub_rev": "@bd5c77abcb609d95340632b96344b59035e70376",
   "pub_cache_tag": "@v0.1.0",
   "pub_semver_tag": "@1.2.1",
   "quiver_tag": "@0.21.4",
+  "resource_rev":"@a49101ba2deb29c728acba6fb86000a8f730f4b1",
   "root_certificates_rev": "@c3a41df63afacec62fcb8135196177e35fe72f71",
   "scheduled_test_tag": "@0.12.4+2",
   "shelf_tag": "@0.6.4+3",
@@ -86,13 +87,12 @@
   "test_tag": "@0.12.6+1",
   "test_reflective_loader_tag": "@0.0.3",
   "utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
-  "unittest_tag": "@0.11.6",
   "usage_rev": "@b5080dac0d26a5609b266f8fdb0d053bc4c1c638",
   "watcher_tag": "@0.9.7",
   "when_tag": "@0.2.0+2",
   "which_tag": "@0.1.3+1",
   "web_components_rev": "@0e636b534d9b12c9e96f841e6679398e91a986ec",
-  "WebCore_rev": "@4f90b41b0165f23f412cecdba07b7d81d3fbb5b5",
+  "WebCore_rev": "@5ecb723fd9ffcc0d108f5e0e24d12b8b3df7b200",
   "yaml_tag": "@2.1.5",
   "zlib_rev": "@c3d0a6190f2f8c924a05ab6cc97b8f975bddd33f",
   "barback-0.13.0_rev": "@34853",
@@ -225,6 +225,8 @@
       Var("chromium_git")
       + "/external/github.com/google/quiver-dart.git"
       + Var("quiver_tag"),
+  Var("dart_root") + "/third_party/pkg/resource":
+    "https://github.com/dart-lang/resource.git" + Var("resource_rev"),
   Var("dart_root") + "/third_party/pkg/scheduled_test":
       (Var("github_mirror") % "scheduled_test") + Var("scheduled_test_tag"),
   Var("dart_root") + "/third_party/pkg/shelf":
@@ -256,8 +258,6 @@
   Var("dart_root") + "/third_party/pkg/test_reflective_loader":
       (Var("github_mirror") % "test_reflective_loader") +
       Var("test_reflective_loader_tag"),
-  Var("dart_root") + "/third_party/pkg/unittest":
-      (Var("github_mirror") % "test") + Var("unittest_tag"),
   Var("dart_root") + "/third_party/pkg/usage":
       (Var("github_mirror") % "usage") + Var("usage_rev"),
   Var("dart_root") + "/third_party/pkg/utf":
@@ -292,24 +292,6 @@
 # without the runtime being available.
 hooks = [
   {
-    "pattern": ".",
-    "action": ["python", Var("dart_root") + "/tools/gyp_dart.py"],
-  },
-  {
-    'name': 'checked_in_dart_binaries',
-    'pattern': '.',
-    'action': [
-      'download_from_google_storage',
-      '--no_auth',
-      '--no_resume',
-      '--bucket',
-      'dart-dependencies',
-      '--recursive',
-      '--directory',
-      Var('dart_root') + '/tools/testing/bin',
-    ],
-  },
-  {
     'name': 'd8_testing_binaries',
     'pattern': '.',
     'action': [
@@ -384,6 +366,22 @@
     ],
   },
   {
+    "name": "unittest",
+    # Unittest is an early version, 0.11.6, of the package "test"
+    # Do not use it in any new tests.
+    "pattern": ".",
+    "action": [
+      "download_from_google_storage",
+      "--no_auth",
+      "--no_resume",
+      "--bucket",
+      "dart-dependencies",
+      "--extract",
+      "-s",
+      Var('dart_root') + "/third_party/pkg/unittest.tar.gz.sha1",
+    ],
+  },
+  {
     "name": "7zip",
     "pattern": ".",
     "action": [
@@ -427,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/WATCHLISTS b/WATCHLISTS
index 9b4f4dc..a6f72e3 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -10,9 +10,6 @@
     'runtime': {
       'filepath': '^runtime/',
     },
-    'tools': {
-      'filepath': 'tools/',
-    },
     'observatory': {
       'filepath': 'runtime/bin/vmservice/' \
                   '|runtime/bin/vmservice*' \
@@ -24,7 +21,6 @@
 
   'WATCHLISTS': {
     'runtime': ['vm-dev@dartlang.org'],
-    'tools': ['ricow@google.com'],
     'observatory': ['johnmccutchan@google.com', 'turnidge@google.com', 'rmacnak@google.com'],
   },
 }
diff --git a/create_sdk.gyp b/create_sdk.gyp
index 749cda5..b13adda 100644
--- a/create_sdk.gyp
+++ b/create_sdk.gyp
@@ -41,6 +41,8 @@
             '<(SHARED_INTERMEDIATE_DIR)/dartfmt.dart.snapshot',
             '<(SHARED_INTERMEDIATE_DIR)/analysis_server.dart.snapshot',
             '<(SHARED_INTERMEDIATE_DIR)/dartdoc.dart.snapshot',
+            '<(SHARED_INTERMEDIATE_DIR)/spec.sum',
+            '<(SHARED_INTERMEDIATE_DIR)/strong.sum',
             'tools/VERSION'
           ],
           'outputs': [
diff --git a/dart.gyp b/dart.gyp
index 3e73877..918e5d6 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -25,7 +25,9 @@
       'type': 'none',
       'dependencies': [
         'runtime/dart-runtime.gyp:dart',
-        'runtime/dart-runtime.gyp:dart_precompiled',
+        'runtime/dart-runtime.gyp:dart_noopt',
+        'runtime/dart-runtime.gyp:dart_precompiled_runtime',
+        'runtime/dart-runtime.gyp:dart_product',
         'runtime/dart-runtime.gyp:dart_no_snapshot',
         'runtime/dart-runtime.gyp:run_vm_tests',
         'runtime/dart-runtime.gyp:process_test',
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index fb3a9e4..25a0c0d 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -1547,7 +1547,7 @@
 Any expression that appears within the initializer list of a constant constructor must be a potentially constant expression, or a compile-time error occurs. 
 
 \LMHash{}
-A {\em potentially constant expression} is an expression $e$ that would be a valid constant expression if all formal parameters of $e$'s immediately enclosing constant constructor were treated as compile-time constants that were guaranteed to evaluate to an integer, boolean or string value as required by their immediately enclosing superexpression.
+A {\em potentially constant expression} is an expression $e$ that would be a valid constant expression if all formal parameters of $e$'s immediately enclosing constant constructor were treated as compile-time constants that were guaranteed to evaluate to an integer, boolean or string value as required by their immediately enclosing superexpression, <em>and</em> where $e$ is also a valid expression if all the formal parameters are treated as non-constant variables.
 
 \commentary{
 Note that a parameter that is not used in a superexpression that is restricted to certain types can be a constant of any type. For example}
diff --git a/pkg/analysis_server/benchmark/integration/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart
index aac45a2..052206e 100644
--- a/pkg/analysis_server/benchmark/integration/driver.dart
+++ b/pkg/analysis_server/benchmark/integration/driver.dart
@@ -134,7 +134,7 @@
       // doesn't exit, then forcibly terminate it.
       sendServerShutdown();
       await server.exitCode.timeout(timeout, onTimeout: () {
-        return server.kill();
+        return server.kill('server failed to exit');
       });
     }
     _resultsReady();
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index f2c4df2..fd1e1ef 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -757,17 +757,28 @@
           </dd><dt class="field"><b><i>packageRoots ( <span style="color:#999999">optional</span> Map&lt;<a href="#type_FilePath">FilePath</a>, <a href="#type_FilePath">FilePath</a>&gt; )</i></b></dt><dd>
             
             <p>
-              A mapping from source directories to target directories
+              A mapping from source directories to package roots
               that should override the normal package: URI resolution
-              mechanism.  The analyzer will behave as though each
+              mechanism.
+            </p>
+            <p>
+              If a package root is a directory, then
+              the analyzer will behave as though the associated
               source directory in the map contains a special
               pubspec.yaml file which resolves any package: URI to the
-              corresponding path within the target directory.  The
-              effect is the same as specifying the target directory as
+              corresponding path within that package root directory.  The
+              effect is the same as specifying the package root directory as
               a "--package_root" parameter to the Dart VM when
               executing any Dart file inside the source directory.
             </p>
             <p>
+              If a package root is a file, then the analyzer
+              will behave as though that file is a ".packages" file in the
+              source directory. The effect is the same as specifying the file
+              as a "--packages" parameter to the Dart VM when
+              executing any Dart file inside the source directory.
+            </p>
+            <p>
               Files in any directories that are not overridden by this
               mapping have their package: URI's resolved using the
               normal pubspec.yaml mechanism.  If this field is absent,
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
index 2da3812..863ced0 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
@@ -61,7 +61,7 @@
       return Assist.EMPTY_LIST;
     }
     CompilationUnit unit =
-        analysisContext.resolveCompilationUnit2(source, libraries[0]);
+        analysisContext.getResolvedCompilationUnit2(source, libraries[0]);
     if (unit == null) {
       return Assist.EMPTY_LIST;
     }
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
index e8f7104..6ef1bed 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -44,7 +44,7 @@
       return Fix.EMPTY_LIST;
     }
     CompilationUnit unit =
-        analysisContext.resolveCompilationUnit2(source, libraries[0]);
+        analysisContext.getResolvedCompilationUnit2(source, libraries[0]);
     if (unit == null) {
       return Fix.EMPTY_LIST;
     }
diff --git a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
index d90344f..eab48cd 100644
--- a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
@@ -1663,12 +1663,19 @@
   }
 
   /**
-   * A mapping from source directories to target directories that should
-   * override the normal package: URI resolution mechanism. The analyzer will
-   * behave as though each source directory in the map contains a special
-   * pubspec.yaml file which resolves any package: URI to the corresponding
-   * path within the target directory. The effect is the same as specifying the
-   * target directory as a "--package_root" parameter to the Dart VM when
+   * A mapping from source directories to package roots that should override
+   * the normal package: URI resolution mechanism.
+   *
+   * If a package root is a directory, then the analyzer will behave as though
+   * the associated source directory in the map contains a special pubspec.yaml
+   * file which resolves any package: URI to the corresponding path within that
+   * package root directory. The effect is the same as specifying the package
+   * root directory as a "--package_root" parameter to the Dart VM when
+   * executing any Dart file inside the source directory.
+   *
+   * If a package root is a file, then the analyzer will behave as though that
+   * file is a ".packages" file in the source directory. The effect is the same
+   * as specifying the file as a "--packages" parameter to the Dart VM when
    * executing any Dart file inside the source directory.
    *
    * Files in any directories that are not overridden by this mapping have
@@ -1679,12 +1686,19 @@
   Map<String, String> get packageRoots => _packageRoots;
 
   /**
-   * A mapping from source directories to target directories that should
-   * override the normal package: URI resolution mechanism. The analyzer will
-   * behave as though each source directory in the map contains a special
-   * pubspec.yaml file which resolves any package: URI to the corresponding
-   * path within the target directory. The effect is the same as specifying the
-   * target directory as a "--package_root" parameter to the Dart VM when
+   * A mapping from source directories to package roots that should override
+   * the normal package: URI resolution mechanism.
+   *
+   * If a package root is a directory, then the analyzer will behave as though
+   * the associated source directory in the map contains a special pubspec.yaml
+   * file which resolves any package: URI to the corresponding path within that
+   * package root directory. The effect is the same as specifying the package
+   * root directory as a "--package_root" parameter to the Dart VM when
+   * executing any Dart file inside the source directory.
+   *
+   * If a package root is a file, then the analyzer will behave as though that
+   * file is a ".packages" file in the source directory. The effect is the same
+   * as specifying the file as a "--packages" parameter to the Dart VM when
    * executing any Dart file inside the source directory.
    *
    * Files in any directories that are not overridden by this mapping have
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index f0d7931..887c34b 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -9,8 +9,8 @@
 import 'dart:core' hide Resource;
 import 'dart:math' show max;
 
-import 'package:analysis_server/plugin/analysis/resolver_provider.dart';
-import 'package:analysis_server/plugin/protocol/protocol.dart' hide Element;
+import 'package:analysis_server/plugin/protocol/protocol.dart'
+    hide AnalysisOptions, Element;
 import 'package:analysis_server/src/analysis_logger.dart';
 import 'package:analysis_server/src/channel/channel.dart';
 import 'package:analysis_server/src/context_manager.dart';
@@ -24,6 +24,8 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/plugin/embedded_resolver_provider.dart';
+import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:analyzer/source/embedder.dart';
 import 'package:analyzer/source/pub_package_map_provider.dart';
 import 'package:analyzer/src/generated/ast.dart';
@@ -114,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.
    */
@@ -139,9 +147,14 @@
   List<RequestHandler> handlers;
 
   /**
-   * The current default [DartSdk].
+   * The function used to create a new SDK using the default SDK.
    */
-  final DartSdk defaultSdk;
+  final SdkCreator defaultSdkCreator;
+
+  /**
+   * The object used to manage the SDK's known to this server.
+   */
+  DartSdkManager sdkManager;
 
   /**
    * The instrumentation service that is to be used by this analysis server.
@@ -149,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;
@@ -273,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.
@@ -299,25 +307,32 @@
       Index _index,
       this.serverPlugin,
       this.options,
-      this.defaultSdk,
+      this.defaultSdkCreator,
       this.instrumentationService,
       {ResolverProvider packageResolverProvider: null,
+      EmbeddedResolverProvider embeddedResolverProvider: null,
       this.rethrowExceptions: true})
       : index = _index,
         searchEngine = _index != null ? createSearchEngine(_index) : null {
     _performance = performanceDuringStartup;
-    operationQueue = new ServerOperationQueue();
-    contextManager = new ContextManagerImpl(resourceProvider,
-        packageResolverProvider, 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();
@@ -336,9 +351,44 @@
     channel.sendNotification(notification);
     channel.listen(handleRequest, onDone: done, onError: error);
     handlers = serverPlugin.createDomains(this);
+    sdkManager = new DartSdkManager(defaultSdkCreator);
   }
 
   /**
+   * 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 {
@@ -421,6 +471,19 @@
   }
 
   /**
+   * Return one of the SDKs that has been created, or `null` if no SDKs have
+   * been created yet.
+   */
+  DartSdk findSdk() {
+    DartSdk sdk = sdkManager.anySdk;
+    if (sdk != null) {
+      return sdk;
+    }
+    // TODO(brianwilkerson) Should we create an SDK using the default options?
+    return null;
+  }
+
+  /**
    * Return the preferred [AnalysisContext] for analyzing the given [path].
    * This will be the context that explicitly contains the path, if any such
    * context exists, otherwise it will be the first analysis context that
@@ -436,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;
@@ -445,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) {
@@ -504,11 +559,13 @@
   ContextSourcePair getContextSourcePair(String path) {
     // try SDK
     {
-      Uri uri = resourceProvider.pathContext.toUri(path);
-      Source sdkSource = defaultSdk.fromFileUri(uri);
-      if (sdkSource != null) {
-        AnalysisContext sdkContext = defaultSdk.context;
-        return new ContextSourcePair(sdkContext, sdkSource);
+      DartSdk sdk = findSdk();
+      if (sdk != null) {
+        Uri uri = resourceProvider.pathContext.toUri(path);
+        Source sdkSource = sdk.fromFileUri(uri);
+        if (sdkSource != null) {
+          return new ContextSourcePair(sdk.context, sdkSource);
+        }
       }
     }
     // try to find the deep-most containing context
@@ -526,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) {
@@ -534,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;
@@ -584,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].
@@ -627,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].
    *
@@ -1086,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;
@@ -1103,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);
@@ -1217,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);
@@ -1228,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;
@@ -1285,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) {
@@ -1294,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.
     //
@@ -1303,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].
@@ -1423,45 +1488,19 @@
    */
   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
-  AnalysisContext addContext(Folder folder, FolderDisposition disposition) {
+  AnalysisContext addContext(
+      Folder folder, AnalysisOptions options, FolderDisposition disposition) {
     InternalAnalysisContext context =
         AnalysisEngine.instance.createAnalysisContext();
     context.contentCache = analysisServer.overlayState;
     analysisServer.folderMap[folder] = context;
     _locateEmbedderYamls(context, disposition);
-    context.sourceFactory = _createSourceFactory(context, disposition);
-    context.analysisOptions =
-        new AnalysisOptionsImpl.from(analysisServer.defaultContextOptions);
+    context.sourceFactory =
+        _createSourceFactory(context, options, disposition, folder);
+    context.analysisOptions = options;
     analysisServer._onContextsChangedController
         .add(new ContextsChangedEvent(added: [context]));
     analysisServer.schedulePerformAnalysisOperation(context);
@@ -1485,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) {
@@ -1511,59 +1544,52 @@
   }
 
   @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];
-    context.sourceFactory = _createSourceFactory(context, disposition);
+    context.sourceFactory = _createSourceFactory(
+        context, context.analysisOptions, disposition, contextFolder);
     analysisServer._onContextsChangedController
         .add(new ContextsChangedEvent(changed: [context]));
     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].
    */
-  SourceFactory _createSourceFactory(
-      InternalAnalysisContext context, FolderDisposition disposition) {
+  SourceFactory _createSourceFactory(InternalAnalysisContext context,
+      AnalysisOptions options, FolderDisposition disposition, Folder folder) {
     List<UriResolver> resolvers = [];
     List<UriResolver> packageUriResolvers =
         disposition.createPackageUriResolvers(resourceProvider);
-    EmbedderUriResolver embedderUriResolver =
+
+    EmbedderUriResolver embedderUriResolver;
+
+    // First check for a resolver provider.
+    ContextManager contextManager = analysisServer.contextManager;
+    if (contextManager is ContextManagerImpl) {
+      EmbeddedResolverProvider resolverProvider =
+          contextManager.embeddedUriResolverProvider;
+      if (resolverProvider != null) {
+        embedderUriResolver = resolverProvider(folder);
+      }
+    }
+
+    // If no embedded URI resolver was provided, defer to a locator-backed one.
+    embedderUriResolver ??=
         new EmbedderUriResolver(context.embedderYamlLocator.embedderYamls);
     if (embedderUriResolver.length == 0) {
       // The embedder uri resolver has no mappings. Use the default Dart SDK
       // uri resolver.
-      resolvers.add(new DartUriResolver(analysisServer.defaultSdk));
+      resolvers.add(new DartUriResolver(
+          analysisServer.sdkManager.getSdkForOptions(options)));
     } else {
       // The embedder uri resolver has mappings, use it instead of the default
       // Dart SDK uri resolver.
       resolvers.add(embedderUriResolver);
     }
+
     resolvers.addAll(packageUriResolvers);
     resolvers.add(new ResourceUriResolver(resourceProvider));
     return new SourceFactory(resolvers, disposition.packages);
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index a91e47d..ed5e8e9 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -5,10 +5,10 @@
 library computer.highlights;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart' hide Element;
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 
 /**
  * A computer for [HighlightRegion]s in a Dart [CompilationUnit].
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
index fc0d77e..5665d49 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
@@ -5,10 +5,10 @@
 library computer.highlights2;
 
 import 'package:analysis_server/plugin/protocol/protocol.dart' hide Element;
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 
 /**
  * A computer for [HighlightRegion]s in a Dart [CompilationUnit].
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 45467ca..02c4f70 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -6,6 +6,7 @@
 
 import 'package:analysis_server/plugin/protocol/protocol.dart'
     show HoverInformation;
+import 'package:analysis_server/src/computer/computer_overrides.dart';
 import 'package:analysis_server/src/utilities/documentation.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/ast.dart';
@@ -69,7 +70,6 @@
             hover.containingLibraryPath = library.source.fullName;
           }
         }
-
         // documentation
         hover.dartdoc = _computeDocumentation(element);
       }
@@ -91,7 +91,23 @@
     if (element is ParameterElement) {
       element = element.enclosingElement;
     }
-    return removeDartDocDelimiters(element.documentationComment);
+    // The documentation of the element itself.
+    if (element.documentationComment != null) {
+      return removeDartDocDelimiters(element.documentationComment);
+    }
+    // Look for documentation comments of overridden members.
+    OverriddenElements overridden = findOverriddenElements(element);
+    for (Element superElement in []
+      ..addAll(overridden.superElements)
+      ..addAll(overridden.interfaceElements)) {
+      String rawDoc = superElement.documentationComment;
+      if (rawDoc != null) {
+        Element interfaceClass = superElement.enclosingElement;
+        return removeDartDocDelimiters(rawDoc) +
+            '\n\nCopied from `${interfaceClass.displayName}`.';
+      }
+    }
+    return null;
   }
 
   static _safeToString(obj) => obj != null ? obj.toString() : null;
diff --git a/pkg/analysis_server/lib/src/computer/computer_overrides.dart b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
index 4e2e00b..4eb93d1 100644
--- a/pkg/analysis_server/lib/src/computer/computer_overrides.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_overrides.dart
@@ -5,15 +5,106 @@
 library computer.overrides;
 
 import 'package:analysis_server/src/collections.dart';
-import 'package:analysis_server/src/protocol_server.dart';
-import 'package:analyzer/dart/element/element.dart' as engine;
-import 'package:analyzer/dart/element/type.dart' as engine;
+import 'package:analysis_server/src/protocol_server.dart' as proto;
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/ast.dart';
 
 /**
+ * Return the elements that the given [element] overrides.
+ */
+OverriddenElements findOverriddenElements(Element element) {
+  if (element?.enclosingElement is ClassElement) {
+    return new _OverriddenElementsFinder(element).find();
+  }
+  return new OverriddenElements(element, <Element>[], <Element>[]);
+}
+
+/**
  * A computer for class member overrides in a Dart [CompilationUnit].
  */
 class DartUnitOverridesComputer {
+  final CompilationUnit _unit;
+  final List<proto.Override> _overrides = <proto.Override>[];
+
+  DartUnitOverridesComputer(this._unit);
+
+  /**
+   * Returns the computed occurrences, not `null`.
+   */
+  List<proto.Override> compute() {
+    for (CompilationUnitMember unitMember in _unit.declarations) {
+      if (unitMember is ClassDeclaration) {
+        for (ClassMember classMember in unitMember.members) {
+          if (classMember is MethodDeclaration) {
+            if (classMember.isStatic) {
+              continue;
+            }
+            _addOverride(classMember.name);
+          }
+          if (classMember is FieldDeclaration) {
+            if (classMember.isStatic) {
+              continue;
+            }
+            List<VariableDeclaration> fields = classMember.fields.variables;
+            for (VariableDeclaration field in fields) {
+              _addOverride(field.name);
+            }
+          }
+        }
+      }
+    }
+    return _overrides;
+  }
+
+  /**
+   * Add a new [Override] for the declaration with the given name [node].
+   */
+  void _addOverride(SimpleIdentifier node) {
+    Element element = node.staticElement;
+    OverriddenElements overridesResult =
+        new _OverriddenElementsFinder(element).find();
+    List<Element> superElements = overridesResult.superElements;
+    List<Element> interfaceElements = overridesResult.interfaceElements;
+    if (superElements.isNotEmpty || interfaceElements.isNotEmpty) {
+      proto.OverriddenMember superMember = superElements.isNotEmpty
+          ? proto.newOverriddenMember_fromEngine(superElements.first)
+          : null;
+      List<proto.OverriddenMember> interfaceMembers = interfaceElements
+          .map((member) => proto.newOverriddenMember_fromEngine(member))
+          .toList();
+      _overrides.add(new proto.Override(node.offset, node.length,
+          superclassMember: superMember,
+          interfaceMembers: nullIfEmpty(interfaceMembers)));
+    }
+  }
+}
+
+/**
+ * The container with elements that a class member overrides.
+ */
+class OverriddenElements {
+  /**
+   * The element that overrides other class members.
+   */
+  final Element element;
+
+  /**
+   * The elements that [element] overrides and which is defined in a class that
+   * is a superclass of the class that defines [element].
+   */
+  final List<Element> superElements;
+
+  /**
+   * The elements that [element] overrides and which is defined in a class that
+   * which is implemented by the class that defines [element].
+   */
+  final List<Element> interfaceElements;
+
+  OverriddenElements(this.element, this.superElements, this.interfaceElements);
+}
+
+class _OverriddenElementsFinder {
   static const List<ElementKind> FIELD_KINDS = const <ElementKind>[
     ElementKind.FIELD,
     ElementKind.GETTER,
@@ -34,138 +125,102 @@
     ElementKind.SETTER
   ];
 
-  final CompilationUnit _unit;
+  Element _seed;
+  LibraryElement _library;
+  ClassElement _class;
+  String _name;
+  List<ElementKind> _kinds;
 
-  final List<Override> _overrides = <Override>[];
-  engine.ClassElement _currentClass;
+  List<Element> _superElements = <Element>[];
+  List<Element> _interfaceElements = <Element>[];
+  Set<InterfaceType> _visited = new Set<InterfaceType>();
 
-  DartUnitOverridesComputer(this._unit);
-
-  /**
-   * Returns the computed occurrences, not `null`.
-   */
-  List<Override> compute() {
-    for (CompilationUnitMember unitMember in _unit.declarations) {
-      if (unitMember is ClassDeclaration) {
-        _currentClass = unitMember.element;
-        for (ClassMember classMember in unitMember.members) {
-          if (classMember is MethodDeclaration) {
-            if (classMember.isStatic) {
-              continue;
-            }
-            SimpleIdentifier nameNode = classMember.name;
-            List<ElementKind> kinds;
-            if (classMember.isGetter) {
-              kinds = GETTER_KINDS;
-            } else if (classMember.isSetter) {
-              kinds = SETTER_KINDS;
-            } else {
-              kinds = METHOD_KINDS;
-            }
-            _addOverride(
-                nameNode.offset, nameNode.length, nameNode.name, kinds);
-          }
-          if (classMember is FieldDeclaration) {
-            if (classMember.isStatic) {
-              continue;
-            }
-            List<VariableDeclaration> fields = classMember.fields.variables;
-            for (VariableDeclaration field in fields) {
-              SimpleIdentifier nameNode = field.name;
-              _addOverride(
-                  nameNode.offset, nameNode.length, nameNode.name, FIELD_KINDS);
-            }
-          }
-        }
-      }
+  _OverriddenElementsFinder(Element seed) {
+    _seed = seed;
+    _class = seed.enclosingElement;
+    _library = _class.library;
+    _name = seed.displayName;
+    if (seed is MethodElement) {
+      _kinds = METHOD_KINDS;
+    } else if (seed is PropertyAccessorElement) {
+      _kinds = seed.isGetter ? GETTER_KINDS : SETTER_KINDS;
+    } else {
+      _kinds = FIELD_KINDS;
     }
-    return _overrides;
   }
 
-  void _addInterfaceOverrides(
-      Set<engine.Element> elements,
-      String name,
-      List<ElementKind> kinds,
-      engine.InterfaceType type,
-      bool checkType,
-      Set<engine.InterfaceType> visited) {
+  /**
+   * Add the [OverriddenElements] for this element.
+   */
+  OverriddenElements find() {
+    _visited.clear();
+    _addSuperOverrides(_class.supertype);
+    _visited.clear();
+    _addInterfaceOverrides(_class.type, false);
+    _superElements.forEach(_interfaceElements.remove);
+    return new OverriddenElements(_seed, _superElements, _interfaceElements);
+  }
+
+  void _addInterfaceOverrides(InterfaceType type, bool checkType) {
     if (type == null) {
       return;
     }
-    if (!visited.add(type)) {
+    if (!_visited.add(type)) {
       return;
     }
-    // check type
+    // this type
     if (checkType) {
-      engine.Element element = _lookupMember(type.element, name, kinds);
-      if (element != null) {
-        elements.add(element);
-        return;
-      }
-    }
-    // check interfaces
-    for (engine.InterfaceType interfaceType in type.interfaces) {
-      _addInterfaceOverrides(
-          elements, name, kinds, interfaceType, true, visited);
-    }
-    // check super
-    _addInterfaceOverrides(
-        elements, name, kinds, type.superclass, checkType, visited);
-  }
-
-  void _addOverride(
-      int offset, int length, String name, List<ElementKind> kinds) {
-    // super
-    engine.Element superEngineElement;
-    {
-      engine.InterfaceType superType = _currentClass.supertype;
-      if (superType != null) {
-        superEngineElement = _lookupMember(superType.element, name, kinds);
+      Element element = _lookupMember(type.element);
+      if (element != null && !_interfaceElements.contains(element)) {
+        _interfaceElements.add(element);
       }
     }
     // interfaces
-    Set<engine.Element> interfaceEngineElements = new Set<engine.Element>();
-    _addInterfaceOverrides(interfaceEngineElements, name, kinds,
-        _currentClass.type, false, new Set<engine.InterfaceType>());
-    interfaceEngineElements.remove(superEngineElement);
-    // is there any override?
-    if (superEngineElement != null || interfaceEngineElements.isNotEmpty) {
-      OverriddenMember superMember = superEngineElement != null
-          ? newOverriddenMember_fromEngine(superEngineElement)
-          : null;
-      List<OverriddenMember> interfaceMembers = interfaceEngineElements
-          .map((member) => newOverriddenMember_fromEngine(member))
-          .toList();
-      _overrides.add(new Override(offset, length,
-          superclassMember: superMember,
-          interfaceMembers: nullIfEmpty(interfaceMembers)));
+    for (InterfaceType interfaceType in type.interfaces) {
+      _addInterfaceOverrides(interfaceType, true);
     }
+    // super
+    _addInterfaceOverrides(type.superclass, checkType);
   }
 
-  static engine.Element _lookupMember(
-      engine.ClassElement classElement, String name, List<ElementKind> kinds) {
+  void _addSuperOverrides(InterfaceType type) {
+    if (type == null) {
+      return;
+    }
+    if (!_visited.add(type)) {
+      return;
+    }
+    // this type
+    Element element = _lookupMember(type.element);
+    if (element != null && !_superElements.contains(element)) {
+      _superElements.add(element);
+    }
+    // super
+    _addSuperOverrides(type.superclass);
+  }
+
+  Element _lookupMember(ClassElement classElement) {
     if (classElement == null) {
       return null;
     }
-    engine.LibraryElement library = classElement.library;
-    engine.Element member;
+    Element member;
     // method
-    if (kinds.contains(ElementKind.METHOD)) {
-      member = classElement.lookUpMethod(name, library);
+    if (_kinds.contains(ElementKind.METHOD)) {
+      member = classElement.lookUpMethod(_name, _library);
       if (member != null) {
         return member;
       }
     }
     // getter
-    if (kinds.contains(ElementKind.GETTER)) {
-      member = classElement.lookUpGetter(name, library);
+    if (_kinds.contains(ElementKind.GETTER)) {
+      member = classElement.lookUpGetter(_name, _library);
       if (member != null) {
         return member;
       }
     }
     // setter
-    if (kinds.contains(ElementKind.SETTER)) {
-      member = classElement.lookUpSetter(name + '=', library);
+    if (_kinds.contains(ElementKind.SETTER)) {
+      member = classElement.lookUpSetter(_name + '=', _library);
       if (member != null) {
         return member;
       }
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index d0862f0..c81ce7f 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -9,11 +9,12 @@
 import 'dart:convert';
 import 'dart:core' hide Resource;
 
-import 'package:analysis_server/plugin/analysis/resolver_provider.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/plugin/embedded_resolver_provider.dart';
 import 'package:analyzer/plugin/options.dart';
+import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:analyzer/source/analysis_options_provider.dart';
 import 'package:analyzer/source/embedder.dart';
 import 'package:analyzer/source/package_map_provider.dart';
@@ -22,6 +23,7 @@
 import 'package:analyzer/source/pub_package_map_provider.dart';
 import 'package:analyzer/source/sdk_ext.dart';
 import 'package:analyzer/src/context/context.dart' as context;
+import 'package:analyzer/src/context/source.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/java_io.dart';
@@ -29,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;
@@ -226,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;
@@ -242,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].
    */
@@ -305,10 +320,12 @@
  */
 abstract class ContextManagerCallbacks {
   /**
-   * Create and return a new analysis context, allowing [disposition] to govern
-   * details of how the context is to be created.
+   * 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.
    */
-  AnalysisContext addContext(Folder folder, FolderDisposition disposition);
+  AnalysisContext addContext(
+      Folder folder, AnalysisOptions options, FolderDisposition disposition);
 
   /**
    * Called when the set of files associated with a context have changed (or
@@ -318,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
@@ -340,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(
@@ -399,6 +402,13 @@
   pathos.Context pathContext;
 
   /**
+   * A function that will return a [UriResolver] that can be used to resolve
+   * URI's for embedded libraries within a given folder, or `null` if we should
+   * fall back to the standard URI resolver.
+   */
+  final EmbeddedResolverProvider embeddedUriResolverProvider;
+
+  /**
    * The list of excluded paths (folders and files) most recently passed to
    * [setRoots].
    */
@@ -439,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;
@@ -453,19 +473,35 @@
   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.
    */
   final Map<Folder, StreamSubscription<WatchEvent>> changeSubscriptions =
       <Folder, StreamSubscription<WatchEvent>>{};
 
-  ContextManagerImpl(this.resourceProvider, this.packageResolverProvider,
-      this._packageMapProvider, this._instrumentationService) {
+  ContextManagerImpl(
+      this.resourceProvider,
+      this.packageResolverProvider,
+      this.embeddedUriResolverProvider,
+      this._packageMapProvider,
+      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 =
@@ -537,15 +573,8 @@
   /**
    * Process [options] for the given context [info].
    */
-  void processOptionsForContext(ContextInfo info, Folder folder,
+  void processOptionsForContext(ContextInfo info, Map<String, Object> options,
       {bool optionsRemoved: false}) {
-    Map<String, Object> options;
-    try {
-      options = analysisOptionsProvider.getOptions(folder);
-    } catch (_) {
-      // Parse errors are reported by GenerateOptionsErrorsTask.
-    }
-
     if (options == null && !optionsRemoved) {
       return;
     }
@@ -600,6 +629,20 @@
     }
   }
 
+  /**
+   * Return the options from the analysis options file in the given [folder], or
+   * `null` if there is no file in the folder or if the contents of the file are
+   * not valid YAML.
+   */
+  Map<String, Object> readOptions(Folder folder) {
+    try {
+      return analysisOptionsProvider.getOptions(folder);
+    } catch (_) {
+      // Parse errors are reported by GenerateOptionsErrorsTask.
+    }
+    return null;
+  }
+
   @override
   void refresh(List<Resource> roots) {
     // Destroy old contexts
@@ -755,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
@@ -802,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;
@@ -822,7 +865,11 @@
     if (AnalysisEngine.isAnalysisOptionsFileName(path, pathContext)) {
       var analysisContext = info.context;
       if (analysisContext is context.AnalysisContextImpl) {
-        processOptionsForContext(info, info.folder,
+        // TODO(brianwilkerson) This doesn't correctly update the source factory
+        // if the changes necessitate it (such as by changing the setting of the
+        // strong-mode option).
+        Map<String, Object> options = readOptions(info.folder);
+        processOptionsForContext(info, options,
             optionsRemoved: changeType == ChangeType.REMOVE);
         analysisContext.invalidateCachedResults();
         callbacks.applyChangesToContext(info.folder, new ChangeSet());
@@ -834,14 +881,56 @@
       String path, ContextInfo info, Folder folder) {
     // Check to see if this is the .packages file for this context and if so,
     // update the context's source factory.
-    if (absolutePathContext.basename(path) == PACKAGE_SPEC_NAME &&
-        info.isPathToPackageDescription(path)) {
+    if (absolutePathContext.basename(path) == PACKAGE_SPEC_NAME) {
       File packagespec = resourceProvider.getFile(path);
       if (packagespec.exists) {
-        Packages packages = _readPackagespec(packagespec);
-        if (packages != null) {
-          callbacks.updateContextPackageUriResolver(
-              folder, new PackagesFileDisposition(packages));
+        // Locate embedder yamls for this .packages file.
+        // If any embedder libs are contributed and this context does not
+        // have an embedded URI resolver, we need to create a new context.
+
+        List<int> bytes = packagespec.readAsStringSync().codeUnits;
+        Map<String, Uri> packages =
+            pkgfile.parse(bytes, new Uri.file(packagespec.path));
+
+        Map<String, List<Folder>> packageMap =
+            new PackagesFileDisposition(new MapPackages(packages))
+                .buildPackageMap(resourceProvider);
+        Map<Folder, YamlMap> embedderYamls =
+            new EmbedderYamlLocator(packageMap).embedderYamls;
+
+        SourceFactory sourceFactory = info.context.sourceFactory;
+
+        // Check for library embedders.
+        if (embedderYamls.values.any(definesEmbeddedLibs)) {
+          // If there is no embedded URI resolver, a new source factory needs to
+          // be recreated.
+          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)
+                  .toList();
+              // Add an embedded URI resolver in its place.
+              resolvers.add(new EmbedderUriResolver(embedderYamls));
+
+              // Set a new source factory.
+              SourceFactoryImpl newFactory = sourceFactory.clone();
+              newFactory.resolvers.clear();
+              newFactory.resolvers.addAll(resolvers);
+              info.context.sourceFactory = newFactory;
+              return;
+            }
+          }
+        }
+
+        // Next check for package URI updates.
+        if (info.isPathToPackageDescription(path)) {
+          Packages packages = _readPackagespec(packagespec);
+          if (packages != null) {
+            callbacks.updateContextPackageUriResolver(
+                folder, new PackagesFileDisposition(packages));
+          }
         }
       }
     }
@@ -885,10 +974,10 @@
     if (packageRoot != null) {
       // TODO(paulberry): We shouldn't be using JavaFile here because it
       // makes the code untestable (see dartbug.com/23909).
-      JavaFile packagesDir = new JavaFile(packageRoot);
+      JavaFile packagesDirOrFile = new JavaFile(packageRoot);
       Map<String, List<Folder>> packageMap = new Map<String, List<Folder>>();
-      if (packagesDir.isDirectory()) {
-        for (JavaFile file in packagesDir.listFiles()) {
+      if (packagesDirOrFile.isDirectory()) {
+        for (JavaFile file in packagesDirOrFile.listFiles()) {
           // Ensure symlinks in packages directory are canonicalized
           // to prevent 'type X cannot be assigned to type X' warnings
           String path;
@@ -905,6 +994,12 @@
           }
         }
         return new PackageMapDisposition(packageMap, packageRoot: packageRoot);
+      } else if (packagesDirOrFile.isFile()) {
+        File packageSpecFile = resourceProvider.getFile(packageRoot);
+        Packages packages = _readPackagespec(packageSpecFile);
+        if (packages != null) {
+          return new PackagesFileDisposition(packages);
+        }
       }
       // The package root does not exist (or is not a folder).  Since
       // [setRoots] ignores any package roots that don't exist (or aren't
@@ -914,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) ==
@@ -933,7 +1028,7 @@
           packageMapInfo = _packageMapProvider.computePackageMap(folder);
         });
       } finally {
-        callbacks.endComputePackageMap();
+        callbacks.computingPackageMap(false);
       }
       for (String dependencyPath in packageMapInfo.dependencies) {
         addDependency(dependencyPath);
@@ -963,11 +1058,16 @@
           _computeFolderDisposition(folder, dependencies.add, packagespecFile);
     }
 
+    Map<String, Object> optionMap = readOptions(info.folder);
+    AnalysisOptions options =
+        new AnalysisOptionsImpl.from(defaultContextOptions);
+    applyToAnalysisOptions(options, optionMap);
+
     info.setDependencies(dependencies);
-    info.context = callbacks.addContext(folder, disposition);
+    info.context = callbacks.addContext(folder, options, disposition);
     info.context.name = folder.path;
 
-    processOptionsForContext(info, folder);
+    processOptionsForContext(info, optionMap);
 
     return info;
   }
@@ -1219,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);
@@ -1403,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_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 8810ff6..f9ea745 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -53,12 +53,17 @@
   CompletionPerformance computeCachePerformance;
 
   /**
+   * The current request being processed or `null` if none.
+   */
+  CompletionRequestImpl _currentRequest;
+
+  /**
    * Initialize a new request handler for the given [server].
    */
   CompletionDomainHandler(this.server);
 
   /**
-   * Compute completion results for the given reqeust and append them to the stream.
+   * Compute completion results for the given request and append them to the stream.
    * Clients should not call this method directly as it is automatically called
    * when a client listens to the stream returned by [results].
    * Subclasses should override this method, append at least one result
@@ -76,7 +81,12 @@
     for (CompletionContributor contributor in newContributors) {
       String contributorTag = 'computeSuggestions - ${contributor.runtimeType}';
       performance.logStartTime(contributorTag);
-      suggestions.addAll(await contributor.computeSuggestions(request));
+      try {
+        suggestions.addAll(await contributor.computeSuggestions(request));
+      } on AbortCompletion {
+        suggestions.clear();
+        break;
+      }
       performance.logElapseTime(contributorTag);
     }
 
@@ -139,7 +149,7 @@
 
     recordRequest(performance, context, source, params.offset);
 
-    CompletionRequest completionRequest = new CompletionRequestImpl(
+    CompletionRequestImpl completionRequest = new CompletionRequestImpl(
         context,
         server.resourceProvider,
         server.searchEngine,
@@ -148,6 +158,9 @@
         performance);
     String completionId = (_nextCompletionId++).toString();
 
+    _abortCurrentRequest();
+    _currentRequest = completionRequest;
+
     // Compute suggestions in the background
     computeSuggestions(completionRequest).then((CompletionResult result) {
       const SEND_NOTIFICATION_TAG = 'send notification';
@@ -161,6 +174,10 @@
       performance.suggestionCountFirst = result.suggestions.length;
       performance.suggestionCountLast = result.suggestions.length;
       performance.complete();
+    }).whenComplete(() {
+      if (_currentRequest == completionRequest) {
+        _currentRequest = null;
+      }
     });
 
     // initial response without results
@@ -198,6 +215,16 @@
             completionId, replacementOffset, replacementLength, results, true)
         .toNotification());
   }
+
+  /**
+   * Abort the current completion request, if any.
+   */
+  void _abortCurrentRequest() {
+    if (_currentRequest != null) {
+      _currentRequest.abort();
+      _currentRequest = null;
+    }
+  }
 }
 
 /**
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index e9bd0c3..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;
@@ -63,6 +61,10 @@
           AnalysisTarget target = iterator.key;
           if (countedTargets.add(target)) {
             CacheEntry cacheEntry = iterator.value;
+            if (cacheEntry == null) {
+              throw new StateError(
+                  "mutated cache key detected: $target (${target.runtimeType})");
+            }
             if (target is Source) {
               if (cacheEntry.explicitlyAdded) {
                 explicitFiles++;
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/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index 5391d5e..42e7213 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -57,21 +57,23 @@
     if (element.isSynthetic || _isStatic(element)) {
       return;
     }
-    String name = element.displayName;
-    if (name != null && _hasOverride(name)) {
+    if (_hasOverride(element)) {
       _addImplementedMember(element);
     }
   }
 
-  bool _hasOverride(String name) {
+  bool _hasOverride(Element element) {
+    String name = element.displayName;
+    LibraryElement library = element.library;
     for (ClassElement subtype in subtypes) {
-      MethodElement method = subtype.getMethod(name);
-      if (method != null) {
-        return !method.isStatic;
+      ClassMemberElement subElement = subtype.getMethod(name);
+      if (subElement == null) {
+        subElement = subtype.getField(name);
       }
-      FieldElement field = subtype.getField(name);
-      if (field != null) {
-        return !field.isStatic;
+      if (subElement != null &&
+          !subElement.isStatic &&
+          subElement.isAccessibleIn(library)) {
+        return true;
       }
     }
     return false;
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index 931d87f..20ddb4f 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -6,11 +6,11 @@
 
 import 'package:analysis_server/plugin/analysis/navigation/navigation_core.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index ce2b38c..4197555 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -20,11 +20,11 @@
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart' as engine;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart' as engine;
 import 'package:analyzer/src/generated/error.dart' as engine;
 import 'package:analyzer/src/generated/parser.dart' as engine;
-import 'package:analyzer/src/generated/scanner.dart' as engine;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:dart_style/dart_style.dart';
 
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/provisional/completion/completion_core.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
index 9a585dd..1aa1c9f 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
@@ -26,6 +26,14 @@
 typedef CompletionContributor CompletionContributorFactory();
 
 /**
+ * [AbortCompletion] is thrown when the current completion request
+ * should be aborted because either
+ * the source changed since the request was made, or
+ * a new completion request was received.
+ */
+class AbortCompletion {}
+
+/**
  * An object used to produce completions at a specific location within a file.
  *
  * Clients may implement this class when implementing plugins.
@@ -33,7 +41,8 @@
 abstract class CompletionContributor {
   /**
    * Return a [Future] that completes with a list of suggestions
-   * for the given completion [request].
+   * for the given completion [request]. This will
+   * throw [AbortCompletion] if the completion request has been aborted.
    */
   Future<List<CompletionSuggestion>> computeSuggestions(
       CompletionRequest request);
@@ -70,4 +79,9 @@
    * Return the source in which the completion is being requested.
    */
   Source get source;
+
+  /**
+   * Throw [AbortCompletion] if the completion request has been aborted.
+   */
+  void checkAborted();
 }
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
index c6a9a74..434ae63 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
@@ -107,16 +107,6 @@
   CompletionTarget get target;
 
   /**
-   * Return a [Future] that completes with a list of directives for the library
-   * in which in which the completion is occurring.
-   * The [Future] may return `null` if the library unit cannot be determined
-   * (e.g. unlinked part file).
-   * Any information obtained from [target] prior to calling this method
-   * should be discarded as it may have changed.
-   */
-  Future<List<Directive>> resolveDirectives();
-
-  /**
    * Return a [Future] that completes when the element associated with
    * the given [expression] in the target compilation unit is available.
    * It may also complete if the expression cannot be resolved
@@ -125,4 +115,24 @@
    * should be discarded as it may have changed.
    */
   Future resolveExpression(Expression expression);
+
+  /**
+     * Return a [Future] that completes with a list of [ImportElement]s
+     * for the library in which in which the completion is occurring.
+     * The [Future] may return `null` if the library unit cannot be determined
+     * (e.g. unlinked part file).
+     * Any information obtained from [target] prior to calling this method
+     * should be discarded as it may have changed.
+     */
+  Future<List<ImportElement>> resolveImports();
+
+  /**
+   * Return a [Future] that completes with a list of [CompilationUnitElement]s
+   * comprising the library in which in which the completion is occurring.
+   * The [Future] may return `null` if the library unit cannot be determined
+   * (e.g. unlinked part file).
+   * Any information obtained from [target] prior to calling this method
+   * should be discarded as it may have changed.
+   */
+  Future<List<CompilationUnitElement>> resolveUnits();
 }
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
index c04ce43..9a03a1e 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
@@ -4,10 +4,10 @@
 
 library analysis_server.src.provisional.completion.dart.completion_target;
 
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
 int _computeArgIndex(AstNode containingNode, Object entity) {
diff --git a/pkg/analysis_server/lib/src/search/type_hierarchy.dart b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
index 793e471..e723722 100644
--- a/pkg/analysis_server/lib/src/search/type_hierarchy.dart
+++ b/pkg/analysis_server/lib/src/search/type_hierarchy.dart
@@ -175,7 +175,7 @@
         result = clazz.getSetter(_pivotName);
       }
     }
-    if (result != null) {
+    if (result != null && result.isAccessibleIn(_pivotLibrary)) {
       return result;
     }
     // try to find in the class mixin
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 5833af4..4f9e472 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -8,7 +8,6 @@
 import 'dart:io';
 import 'dart:math';
 
-import 'package:analysis_server/plugin/analysis/resolver_provider.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/plugin/linter_plugin.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
@@ -20,6 +19,8 @@
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/instrumentation/file_instrumentation.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/plugin/embedded_resolver_provider.dart';
+import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/incremental_logger.dart';
 import 'package:analyzer/src/generated/java_io.dart';
@@ -46,8 +47,9 @@
   // create logger
   if (spec == 'console') {
     logger = new StringSinkLogger(stdout);
-  }
-  if (spec.startsWith('file:')) {
+  } else if (spec == 'stderr') {
+    logger = new StringSinkLogger(stderr);
+  } else if (spec.startsWith('file:')) {
     String fileName = spec.substring('file:'.length);
     File file = new File(fileName);
     IOSink sink = file.openWrite();
@@ -296,6 +298,12 @@
   InstrumentationServer instrumentationServer;
 
   /**
+   * The embedded library URI resolver provider used to override the way
+   * embedded library URI's are resolved in some contexts.
+   */
+  EmbeddedResolverProvider embeddedUriResolverProvider;
+
+  /**
    * The package resolver provider used to override the way package URI's are
    * resolved in some contexts.
    */
@@ -367,14 +375,20 @@
 
     _initIncrementalLogger(results[INCREMENTAL_RESOLUTION_LOG]);
 
-    DartSdk defaultSdk;
+    JavaFile defaultSdkDirectory;
     if (results[SDK_OPTION] != null) {
-      defaultSdk = new DirectoryBasedDartSdk(new JavaFile(results[SDK_OPTION]));
+      defaultSdkDirectory = new JavaFile(results[SDK_OPTION]);
     } else {
-      // No path to the SDK provided; use DirectoryBasedDartSdk.defaultSdk,
-      // which will make a guess.
-      defaultSdk = DirectoryBasedDartSdk.defaultSdk;
+      // No path to the SDK was provided.
+      // Use DirectoryBasedDartSdk.defaultSdkDirectory, which will make a guess.
+      defaultSdkDirectory = DirectoryBasedDartSdk.defaultSdkDirectory;
     }
+    SdkCreator defaultSdkCreator =
+        () => new DirectoryBasedDartSdk(defaultSdkDirectory);
+    // TODO(brianwilkerson) It would be nice to avoid creating an SDK that
+    // cannot be re-used, but the SDK is needed to create a package map provider
+    // in the case where we need to run `pub` in order to get the package map.
+    DirectoryBasedDartSdk defaultSdk = defaultSdkCreator();
     //
     // Initialize the instrumentation service.
     //
@@ -412,8 +426,14 @@
     //
     // Create the sockets and start listening for requests.
     //
-    socketServer = new SocketServer(analysisServerOptions, defaultSdk, service,
-        serverPlugin, packageResolverProvider);
+    socketServer = new SocketServer(
+        analysisServerOptions,
+        defaultSdkCreator,
+        defaultSdk,
+        service,
+        serverPlugin,
+        packageResolverProvider,
+        embeddedUriResolverProvider);
     httpServer = new HttpAnalysisServer(socketServer);
     stdioServer = new StdioAnalysisServer(socketServer);
     socketServer.userDefinedPlugins = _userDefinedPlugins;
@@ -485,7 +505,7 @@
         defaultsTo: false,
         negatable: false);
     parser.addOption(INCREMENTAL_RESOLUTION_LOG,
-        help: "the description of the incremental resolution log");
+        help: "set a destination for the incremental resolver's log");
     parser.addFlag(INCREMENTAL_RESOLUTION_VALIDATION,
         help: "enable validation of incremental resolution results (slow)",
         defaultsTo: false,
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_core.dart b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
index e0635aa..b79a9d8 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
@@ -21,6 +21,14 @@
   @override
   final Source source;
 
+  /**
+   * The content cache modification stamp of the associated [source],
+   * or `null` if the content cache does not override the [source] content.
+   * This is used to determine if the [source] contents have been modified
+   * after the completion request was made.
+   */
+  final int sourceModificationStamp;
+
   @override
   final int offset;
 
@@ -48,16 +56,21 @@
   @override
   final SearchEngine searchEngine;
 
+  bool _aborted = false;
+
   final CompletionPerformance performance;
 
   /**
    * Initialize a newly created completion request based on the given arguments.
    */
-  CompletionRequestImpl(this.context, this.resourceProvider, this.searchEngine,
-      this.source, this.offset, this.performance) {
-    replacementOffset = offset;
-    replacementLength = 0;
-  }
+  CompletionRequestImpl(AnalysisContext context, this.resourceProvider,
+      this.searchEngine, Source source, int offset, this.performance)
+      : this.context = context,
+        this.source = source,
+        this.offset = offset,
+        replacementOffset = offset,
+        replacementLength = 0,
+        sourceModificationStamp = context.getModificationStamp(source);
 
   /**
    * Return the original text from the [replacementOffset] to the [offset]
@@ -69,4 +82,22 @@
         .data
         .substring(replacementOffset, offset);
   }
+
+  /**
+   * Abort the current completion request.
+   */
+  void abort() {
+    _aborted = true;
+  }
+
+  @override
+  void checkAborted() {
+    if (_aborted) {
+      throw new AbortCompletion();
+    }
+    if (sourceModificationStamp != context.getModificationStamp(source)) {
+      _aborted = true;
+      throw new AbortCompletion();
+    }
+  }
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 602503e..b56bd9f 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -18,17 +18,20 @@
 import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart';
 import 'package:analysis_server/src/services/completion/dart/optype.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/context/context.dart'
     show AnalysisFutureHelper, AnalysisContextImpl;
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl;
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/model.dart';
 
 /**
  * [DartCompletionManager] determines if a completion request is Dart specific
@@ -44,17 +47,15 @@
   @override
   Future<List<CompletionSuggestion>> computeSuggestions(
       CompletionRequest request) async {
+    request.checkAborted();
     if (!AnalysisEngine.isDartFileName(request.source.shortName)) {
       return EMPTY_LIST;
     }
 
     CompletionPerformance performance =
         (request as CompletionRequestImpl).performance;
-    const BUILD_REQUEST_TAG = 'build DartCompletionRequestImpl';
-    performance.logStartTime(BUILD_REQUEST_TAG);
     DartCompletionRequestImpl dartRequest =
         await DartCompletionRequestImpl.from(request);
-    performance.logElapseTime(BUILD_REQUEST_TAG);
 
     // Don't suggest in comments.
     if (dartRequest.target.isCommentText) {
@@ -78,6 +79,7 @@
       List<CompletionSuggestion> contributorSuggestions =
           await contributor.computeSuggestions(dartRequest);
       performance.logElapseTime(contributorTag);
+      request.checkAborted();
 
       for (CompletionSuggestion newSuggestion in contributorSuggestions) {
         var oldSuggestion = suggestionMap.putIfAbsent(
@@ -95,6 +97,7 @@
     performance.logStartTime(SORT_TAG);
     await contributionSorter.sort(dartRequest, suggestions);
     performance.logElapseTime(SORT_TAG);
+    request.checkAborted();
     return suggestions;
   }
 }
@@ -137,8 +140,22 @@
    */
   InterfaceType _objectType;
 
+  /**
+   * A list of resolved [ImportElement]s for the imported libraries
+   * or `null` if not computed.
+   */
+  List<ImportElement> _resolvedImports;
+
+  /**
+   * The resolved [CompilationUnitElement]s comprising the library
+   * or `null` if not computed.
+   */
+  List<CompilationUnitElement> _resolvedUnits;
+
   OpType _opType;
 
+  final CompletionRequest _originalRequest;
+
   final CompletionPerformance performance;
 
   DartCompletionRequestImpl._(
@@ -149,6 +166,7 @@
       this.source,
       this.offset,
       CompilationUnit unit,
+      this._originalRequest,
       this.performance) {
     _updateTargets(unit);
   }
@@ -200,26 +218,17 @@
     return _opType;
   }
 
-  // For internal use only
-  @override
-  Future<List<Directive>> resolveDirectives() async {
-    CompilationUnit libUnit;
-    if (librarySource != null) {
-      // TODO(danrubel) only resolve the directives
-      const RESOLVE_DIRECTIVES_TAG = 'resolve directives';
-      performance.logStartTime(RESOLVE_DIRECTIVES_TAG);
-      libUnit = await new AnalysisFutureHelper<CompilationUnit>(
-              context,
-              new LibrarySpecificUnit(librarySource, librarySource),
-              RESOLVED_UNIT3)
-          .computeAsync();
-      performance.logElapseTime(RESOLVE_DIRECTIVES_TAG);
-    }
-    return libUnit?.directives;
+  /**
+   * Throw [AbortCompletion] if the completion request has been aborted.
+   */
+  void checkAborted() {
+    _originalRequest.checkAborted();
   }
 
   @override
   Future resolveExpression(Expression expression) async {
+    checkAborted();
+
     // Return immediately if the expression has already been resolved
     if (expression.propagatedType != null) {
       return;
@@ -233,13 +242,12 @@
     // Resolve declarations in the target unit
     // TODO(danrubel) resolve the expression or containing method
     // rather than the entire complilation unit
-    const RESOLVE_EXPRESSION_TAG = 'resolve expression';
-    performance.logStartTime(RESOLVE_EXPRESSION_TAG);
-    CompilationUnit resolvedUnit =
-        await new AnalysisFutureHelper<CompilationUnit>(context,
-                new LibrarySpecificUnit(librarySource, source), RESOLVED_UNIT)
-            .computeAsync();
-    performance.logElapseTime(RESOLVE_EXPRESSION_TAG);
+    CompilationUnit resolvedUnit = await _computeAsync(
+        this,
+        new LibrarySpecificUnit(librarySource, source),
+        RESOLVED_UNIT,
+        performance,
+        'resolve expression');
 
     // TODO(danrubel) determine if the underlying source has been modified
     // in a way that invalidates the completion request
@@ -254,6 +262,55 @@
     _updateTargets(resolvedUnit);
   }
 
+  @override
+  Future<List<ImportElement>> resolveImports() async {
+    checkAborted();
+    if (_resolvedImports != null) {
+      return _resolvedImports;
+    }
+    LibraryElement libElem = libraryElement;
+    if (libElem == null) {
+      return null;
+    }
+    _resolvedImports = <ImportElement>[];
+    for (ImportElement importElem in libElem.imports) {
+      if (importElem.importedLibrary.exportNamespace == null) {
+        await _computeAsync(this, importElem.importedLibrary.source,
+            LIBRARY_ELEMENT4, performance, 'resolve imported library');
+        checkAborted();
+      }
+      _resolvedImports.add(importElem);
+    }
+    return _resolvedImports;
+  }
+
+  @override
+  Future<List<CompilationUnitElement>> resolveUnits() async {
+    checkAborted();
+    if (_resolvedUnits != null) {
+      return _resolvedUnits;
+    }
+    LibraryElement libElem = libraryElement;
+    if (libElem == null) {
+      return null;
+    }
+    _resolvedUnits = <CompilationUnitElement>[];
+    for (CompilationUnitElement unresolvedUnit in libElem.units) {
+      CompilationUnit unit = await _computeAsync(
+          this,
+          new LibrarySpecificUnit(libElem.source, unresolvedUnit.source),
+          RESOLVED_UNIT3,
+          performance,
+          'resolve library unit');
+      checkAborted();
+      CompilationUnitElement resolvedUnit = unit?.element;
+      if (resolvedUnit != null) {
+        _resolvedUnits.add(resolvedUnit);
+      }
+    }
+    return _resolvedUnits;
+  }
+
   /**
    * Update the completion [target] and [dotTarget] based on the given [unit].
    */
@@ -285,9 +342,12 @@
 
   /**
    * Return a [Future] that completes with a newly created completion request
-   * based on the given [request].
+   * based on the given [request]. This method will throw [AbortCompletion]
+   * if the completion request has been aborted.
    */
-  static Future<DartCompletionRequest> from(CompletionRequest request) async {
+  static Future<DartCompletionRequest> from(CompletionRequest request,
+      {ResultDescriptor resultDescriptor}) async {
+    request.checkAborted();
     CompletionPerformance performance =
         (request as CompletionRequestImpl).performance;
     const BUILD_REQUEST_TAG = 'build DartCompletionRequest';
@@ -313,12 +373,12 @@
 
     // Most (all?) contributors need declarations in scope to be resolved
     if (libSource != null) {
-      const RESOLVE_DECLARATIONS_TAG = 'resolve declarations';
-      performance.logStartTime(RESOLVE_DECLARATIONS_TAG);
-      unit = await new AnalysisFutureHelper<CompilationUnit>(context,
-              new LibrarySpecificUnit(libSource, source), RESOLVED_UNIT3)
-          .computeAsync();
-      performance.logElapseTime(RESOLVE_DECLARATIONS_TAG);
+      unit = await _computeAsync(
+          request,
+          new LibrarySpecificUnit(libSource, source),
+          resultDescriptor ?? RESOLVED_UNIT3,
+          performance,
+          'resolve declarations');
     }
 
     DartCompletionRequestImpl dartRequest = new DartCompletionRequestImpl._(
@@ -329,6 +389,7 @@
         request.source,
         request.offset,
         unit,
+        request,
         performance);
 
     // Resolve the expression in which the completion occurs
@@ -341,12 +402,37 @@
         performance.logStartTime(FUNCTIONAL_ARG_TAG);
         await dartRequest.resolveExpression(node);
         performance.logElapseTime(FUNCTIONAL_ARG_TAG);
+        dartRequest.checkAborted();
       }
     }
 
     performance.logElapseTime(BUILD_REQUEST_TAG);
     return dartRequest;
   }
+
+  static Future _computeAsync(
+      CompletionRequest request,
+      AnalysisTarget target,
+      ResultDescriptor descriptor,
+      CompletionPerformance performance,
+      String perfTag) async {
+    request.checkAborted();
+    performance.logStartTime(perfTag);
+    var result;
+    try {
+      result =
+          await new AnalysisFutureHelper(request.context, target, descriptor)
+              .computeAsync();
+    } catch (e, s) {
+      if (e is AnalysisNotScheduledError) {
+        request.checkAborted();
+      }
+      throw new AnalysisException(
+          'failed to $perfTag', new CaughtException(e, s));
+    }
+    request.checkAborted();
+    return result;
+  }
 }
 
 /**
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
index 736f2a0..abed735 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/imported_reference_contributor.dart
@@ -10,12 +10,11 @@
 import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
 import 'package:analysis_server/src/services/completion/dart/local_library_contributor.dart';
 import 'package:analysis_server/src/services/completion/dart/optype.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/resolver.dart';
 
 import '../../../protocol_server.dart'
     show CompletionSuggestion, CompletionSuggestionKind;
-import 'package:analyzer/src/generated/resolver.dart';
 
 /**
  * A contributor for calculating suggestions for imported top level members.
@@ -31,29 +30,23 @@
       return EMPTY_LIST;
     }
 
-    List<Directive> directives = await request.resolveDirectives();
-    if (directives == null) {
+    List<ImportElement> imports = await request.resolveImports();
+    if (imports == null) {
       return EMPTY_LIST;
     }
 
     this.request = request;
     this.optype = (request as DartCompletionRequestImpl).opType;
+    List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
 
-    // Traverse dart:core
-    List<CompletionSuggestion> suggestions =
-        _buildSuggestions(request.coreLib.exportNamespace);
-
-    // Traverse imports
-    for (Directive directive in directives) {
-      if (directive is ImportDirective) {
-        ImportElement importElem = directive.element;
-        LibraryElement libElem = importElem?.importedLibrary;
-        if (libElem != null) {
-          suggestions.addAll(_buildSuggestions(libElem.exportNamespace,
-              prefix: importElem.prefix?.name,
-              showNames: showNamesIn(importElem),
-              hiddenNames: hiddenNamesIn(importElem)));
-        }
+    // Traverse imports including dart:core
+    for (ImportElement importElem in imports) {
+      LibraryElement libElem = importElem?.importedLibrary;
+      if (libElem != null) {
+        suggestions.addAll(_buildSuggestions(libElem.exportNamespace,
+            prefix: importElem.prefix?.name,
+            showNames: showNamesIn(importElem),
+            hiddenNames: hiddenNamesIn(importElem)));
       }
     }
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 9892a10..6008fe7 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -9,8 +9,9 @@
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 
 const ASYNC = 'async';
 const ASYNC_STAR = 'async*';
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
index 014d4ee..b5bae6c 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/label_contributor.dart
@@ -14,8 +14,9 @@
 import 'package:analysis_server/src/services/completion/dart/local_declaration_visitor.dart'
     show LocalDeclarationVisitor;
 import 'package:analysis_server/src/services/completion/dart/optype.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 import '../../../protocol_server.dart'
@@ -27,6 +28,127 @@
     new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, '', 0)), null);
 
 /**
+* Create a new protocol Element for inclusion in a completion suggestion.
+*/
+protocol.Element createLocalElement(
+    Source source, protocol.ElementKind kind, SimpleIdentifier id,
+    {String parameters,
+    TypeName returnType,
+    bool isAbstract: false,
+    bool isDeprecated: false}) {
+  String name;
+  Location location;
+  if (id != null) {
+    name = id.name;
+    // TODO(danrubel) use lineInfo to determine startLine and startColumn
+    location = new Location(source.fullName, id.offset, id.length, 0, 0);
+  } else {
+    name = '';
+    location = new Location(source.fullName, -1, 0, 1, 0);
+  }
+  int flags = protocol.Element.makeFlags(
+      isAbstract: isAbstract,
+      isDeprecated: isDeprecated,
+      isPrivate: Identifier.isPrivateName(name));
+  return new protocol.Element(kind, name, flags,
+      location: location,
+      parameters: parameters,
+      returnType: nameForType(returnType));
+}
+
+/**
+* Create a new suggestion for the given field.
+* Return the new suggestion or `null` if it could not be created.
+*/
+CompletionSuggestion createLocalFieldSuggestion(
+    Source source, FieldDeclaration fieldDecl, VariableDeclaration varDecl) {
+  bool deprecated = isDeprecated(fieldDecl) || isDeprecated(varDecl);
+  TypeName type = fieldDecl.fields.type;
+  return createLocalSuggestion(
+      varDecl.name, deprecated, DART_RELEVANCE_LOCAL_FIELD, type,
+      classDecl: fieldDecl.parent,
+      element: createLocalElement(
+          source, protocol.ElementKind.FIELD, varDecl.name,
+          returnType: type, isDeprecated: deprecated));
+}
+
+/**
+* Create a new suggestion based upon the given information.
+* Return the new suggestion or `null` if it could not be created.
+*/
+CompletionSuggestion createLocalSuggestion(SimpleIdentifier id,
+    bool isDeprecated, int defaultRelevance, TypeName returnType,
+    {ClassDeclaration classDecl, protocol.Element element}) {
+  if (id == null) {
+    return null;
+  }
+  String completion = id.name;
+  if (completion == null || completion.length <= 0 || completion == '_') {
+    return null;
+  }
+  CompletionSuggestion suggestion = new CompletionSuggestion(
+      CompletionSuggestionKind.INVOCATION,
+      isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance,
+      completion,
+      completion.length,
+      0,
+      isDeprecated,
+      false,
+      returnType: nameForType(returnType),
+      element: element);
+  if (classDecl != null) {
+    SimpleIdentifier classId = classDecl.name;
+    if (classId != null) {
+      String className = classId.name;
+      if (className != null && className.length > 0) {
+        suggestion.declaringType = className;
+      }
+    }
+  }
+  return suggestion;
+}
+
+/**
+* Return `true` if the @deprecated annotation is present
+*/
+bool isDeprecated(AnnotatedNode node) {
+  if (node != null) {
+    NodeList<Annotation> metadata = node.metadata;
+    if (metadata != null) {
+      return metadata.any((Annotation a) {
+        return a.name is SimpleIdentifier && a.name.name == 'deprecated';
+      });
+    }
+  }
+  return false;
+}
+
+/**
+* Return the name for the given type.
+*/
+String nameForType(TypeName type) {
+  if (type == NO_RETURN_TYPE) {
+    return null;
+  }
+  if (type == null) {
+    return DYNAMIC;
+  }
+  Identifier id = type.name;
+  if (id == null) {
+    return DYNAMIC;
+  }
+  String name = id.name;
+  if (name == null || name.length <= 0) {
+    return DYNAMIC;
+  }
+  TypeArgumentList typeArgs = type.typeArguments;
+  if (typeArgs != null) {
+    //TODO (danrubel) include type arguments
+  }
+  return name;
+}
+
+/**
  * A contributor for calculating label suggestions.
  */
 class LabelContributor extends DartCompletionContributor {
@@ -163,124 +285,3 @@
     return null;
   }
 }
-
-/**
-* Create a new protocol Element for inclusion in a completion suggestion.
-*/
-protocol.Element createLocalElement(
-    Source source, protocol.ElementKind kind, SimpleIdentifier id,
-    {String parameters,
-    TypeName returnType,
-    bool isAbstract: false,
-    bool isDeprecated: false}) {
-  String name;
-  Location location;
-  if (id != null) {
-    name = id.name;
-    // TODO(danrubel) use lineInfo to determine startLine and startColumn
-    location = new Location(source.fullName, id.offset, id.length, 0, 0);
-  } else {
-    name = '';
-    location = new Location(source.fullName, -1, 0, 1, 0);
-  }
-  int flags = protocol.Element.makeFlags(
-      isAbstract: isAbstract,
-      isDeprecated: isDeprecated,
-      isPrivate: Identifier.isPrivateName(name));
-  return new protocol.Element(kind, name, flags,
-      location: location,
-      parameters: parameters,
-      returnType: nameForType(returnType));
-}
-
-/**
-* Create a new suggestion for the given field.
-* Return the new suggestion or `null` if it could not be created.
-*/
-CompletionSuggestion createLocalFieldSuggestion(
-    Source source, FieldDeclaration fieldDecl, VariableDeclaration varDecl) {
-  bool deprecated = isDeprecated(fieldDecl) || isDeprecated(varDecl);
-  TypeName type = fieldDecl.fields.type;
-  return createLocalSuggestion(
-      varDecl.name, deprecated, DART_RELEVANCE_LOCAL_FIELD, type,
-      classDecl: fieldDecl.parent,
-      element: createLocalElement(
-          source, protocol.ElementKind.FIELD, varDecl.name,
-          returnType: type, isDeprecated: deprecated));
-}
-
-/**
-* Create a new suggestion based upon the given information.
-* Return the new suggestion or `null` if it could not be created.
-*/
-CompletionSuggestion createLocalSuggestion(SimpleIdentifier id,
-    bool isDeprecated, int defaultRelevance, TypeName returnType,
-    {ClassDeclaration classDecl, protocol.Element element}) {
-  if (id == null) {
-    return null;
-  }
-  String completion = id.name;
-  if (completion == null || completion.length <= 0 || completion == '_') {
-    return null;
-  }
-  CompletionSuggestion suggestion = new CompletionSuggestion(
-      CompletionSuggestionKind.INVOCATION,
-      isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance,
-      completion,
-      completion.length,
-      0,
-      isDeprecated,
-      false,
-      returnType: nameForType(returnType),
-      element: element);
-  if (classDecl != null) {
-    SimpleIdentifier classId = classDecl.name;
-    if (classId != null) {
-      String className = classId.name;
-      if (className != null && className.length > 0) {
-        suggestion.declaringType = className;
-      }
-    }
-  }
-  return suggestion;
-}
-
-/**
-* Return `true` if the @deprecated annotation is present
-*/
-bool isDeprecated(AnnotatedNode node) {
-  if (node != null) {
-    NodeList<Annotation> metadata = node.metadata;
-    if (metadata != null) {
-      return metadata.any((Annotation a) {
-        return a.name is SimpleIdentifier && a.name.name == 'deprecated';
-      });
-    }
-  }
-  return false;
-}
-
-/**
-* Return the name for the given type.
-*/
-String nameForType(TypeName type) {
-  if (type == NO_RETURN_TYPE) {
-    return null;
-  }
-  if (type == null) {
-    return DYNAMIC;
-  }
-  Identifier id = type.name;
-  if (id == null) {
-    return DYNAMIC;
-  }
-  String name = id.name;
-  if (name == null || name.length <= 0) {
-    return DYNAMIC;
-  }
-  TypeArgumentList typeArgs = type.typeArguments;
-  if (typeArgs != null) {
-    //TODO (danrubel) include type arguments
-  }
-  return name;
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
index c7b9590..118103f 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
@@ -34,14 +34,13 @@
     Expression targetId = request.dotTarget;
     if (targetId is SimpleIdentifier && !request.target.isCascade) {
       Element elem = targetId.bestElement;
-      if (elem is PrefixElement) {
-        List<Directive> directives = await request.resolveDirectives();
+      if (elem is PrefixElement && !elem.isSynthetic) {
+        List<ImportElement> imports = await request.resolveImports();
         LibraryElement containingLibrary = request.libraryElement;
         // Gracefully degrade if the library or directives
         // could not be determined (e.g. detached part file or source change)
-        if (containingLibrary != null && directives != null) {
-          return _buildSuggestions(
-              request, elem, containingLibrary, directives);
+        if (containingLibrary != null && imports != null) {
+          return _buildSuggestions(request, elem, containingLibrary, imports);
         }
       }
     }
@@ -52,36 +51,27 @@
       DartCompletionRequest request,
       PrefixElement elem,
       LibraryElement containingLibrary,
-      List<Directive> directives) {
+      List<ImportElement> imports) {
     List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
-    for (Directive directive in directives) {
-      if (directive is ImportDirective) {
-        if (directive.prefix != null) {
-          if (directive.prefix.name == elem.name) {
-            LibraryElement library = directive.uriElement;
+    for (ImportElement importElem in imports) {
+      if (importElem.prefix?.name == elem.name) {
+        LibraryElement library = importElem.importedLibrary;
 
-            // Suggest elements from the imported library
-            if (library != null) {
-              AstNode parent = request.target.containingNode.parent;
-              bool isConstructor = parent.parent is ConstructorName;
-              bool typesOnly = parent is TypeName;
-              bool instCreation = typesOnly && isConstructor;
-              LibraryElementSuggestionBuilder builder =
-                  new LibraryElementSuggestionBuilder(
-                      containingLibrary,
-                      CompletionSuggestionKind.INVOCATION,
-                      typesOnly,
-                      instCreation);
-              library.visitChildren(builder);
-              suggestions.addAll(builder.suggestions);
+        // Suggest elements from the imported library
+        AstNode parent = request.target.containingNode.parent;
+        bool isConstructor = parent.parent is ConstructorName;
+        bool typesOnly = parent is TypeName;
+        bool instCreation = typesOnly && isConstructor;
+        LibraryElementSuggestionBuilder builder =
+            new LibraryElementSuggestionBuilder(containingLibrary,
+                CompletionSuggestionKind.INVOCATION, typesOnly, instCreation);
+        library.visitChildren(builder);
+        suggestions.addAll(builder.suggestions);
 
-              // If the import is 'deferred' then suggest 'loadLibrary'
-              if (directive.deferredKeyword != null) {
-                FunctionElement loadLibFunct = library.loadLibraryFunction;
-                suggestions.add(createSuggestion(loadLibFunct));
-              }
-            }
-          }
+        // If the import is 'deferred' then suggest 'loadLibrary'
+        if (importElem.isDeferred) {
+          FunctionElement loadLibFunct = library.loadLibraryFunction;
+          suggestions.add(createSuggestion(loadLibFunct));
         }
       }
     }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart
index 194e741..a216606 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart
@@ -9,7 +9,6 @@
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
 
 import '../../../protocol_server.dart'
     show CompletionSuggestion, CompletionSuggestionKind;
@@ -26,26 +25,22 @@
       return EMPTY_LIST;
     }
 
-    List<Directive> directives = await request.resolveDirectives();
-    if (directives == null) {
+    List<ImportElement> imports = await request.resolveImports();
+    if (imports == null) {
       return EMPTY_LIST;
     }
 
     List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
-    for (Directive directive in directives) {
-      if (directive is ImportDirective) {
-        SimpleIdentifier prefix = directive.prefix;
-        ImportElement element = directive.element;
-        if (prefix != null && element != null) {
-          String completion = prefix.name;
-          LibraryElement libElem = element.importedLibrary;
-          if (completion != null && completion.length > 0 && libElem != null) {
-            CompletionSuggestion suggestion = createSuggestion(libElem,
-                completion: completion,
-                kind: CompletionSuggestionKind.IDENTIFIER);
-            if (suggestion != null) {
-              suggestions.add(suggestion);
-            }
+    for (ImportElement element in imports) {
+      String completion = element.prefix?.name;
+      if (completion != null && completion.length > 0) {
+        LibraryElement libElem = element.importedLibrary;
+        if (libElem != null) {
+          CompletionSuggestion suggestion = createSuggestion(libElem,
+              completion: completion,
+              kind: CompletionSuggestionKind.IDENTIFIER);
+          if (suggestion != null) {
+            suggestions.add(suggestion);
           }
         }
       }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
index d8d4e36..c05a215 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_constructor_contributor.dart
@@ -15,9 +15,10 @@
     show LocalDeclarationVisitor;
 import 'package:analysis_server/src/services/completion/dart/optype.dart';
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 import '../../../protocol_server.dart'
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_declaration_visitor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_declaration_visitor.dart
index 964c6b4..586eac2 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_declaration_visitor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_declaration_visitor.dart
@@ -4,8 +4,9 @@
 
 library services.completion.dart.local.declaration.visitor;
 
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 
 /**
  * `LocalDeclarationCollector` visits an [AstNode] and its parent recursively
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
index 9469154..9b36935 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_library_contributor.dart
@@ -11,7 +11,6 @@
 import 'package:analysis_server/src/services/completion/dart/optype.dart';
 import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
     show createSuggestion, ElementSuggestionBuilder;
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 
 import '../../../protocol_server.dart'
@@ -30,23 +29,17 @@
       return EMPTY_LIST;
     }
 
-    List<Directive> directives = await request.resolveDirectives();
-    if (directives == null) {
+    List<CompilationUnitElement> libraryUnits = await request.resolveUnits();
+    if (libraryUnits == null) {
       return EMPTY_LIST;
     }
 
     OpType optype = (request as DartCompletionRequestImpl).opType;
     LibraryElementSuggestionBuilder visitor =
         new LibraryElementSuggestionBuilder(request, optype);
-    if (request.librarySource != request.source) {
-      request.libraryElement.definingCompilationUnit.accept(visitor);
-    }
-    for (Directive directive in directives) {
-      if (directive is PartDirective) {
-        CompilationUnitElement partElem = directive.element;
-        if (partElem != null && partElem.source != request.source) {
-          partElem.accept(visitor);
-        }
+    for (CompilationUnitElement unit in libraryUnits) {
+      if (unit != null && unit.source != request.source) {
+        unit.accept(visitor);
       }
     }
     return visitor.suggestions;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index 966f1d9..661f89a 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -15,8 +15,9 @@
     show LocalDeclarationVisitor;
 import 'package:analysis_server/src/services/completion/dart/optype.dart';
 import 'package:analysis_server/src/services/correction/strings.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind;
 
@@ -29,6 +30,116 @@
     new SimpleIdentifier(new StringToken(TokenType.IDENTIFIER, '', 0)), null);
 
 /**
+* Create a new protocol Element for inclusion in a completion suggestion.
+*/
+protocol.Element _createLocalElement(
+    Source source, protocol.ElementKind kind, SimpleIdentifier id,
+    {String parameters,
+    TypeName returnType,
+    bool isAbstract: false,
+    bool isDeprecated: false}) {
+  String name;
+  Location location;
+  if (id != null) {
+    name = id.name;
+    // TODO(danrubel) use lineInfo to determine startLine and startColumn
+    location = new Location(source.fullName, id.offset, id.length, 0, 0);
+  } else {
+    name = '';
+    location = new Location(source.fullName, -1, 0, 1, 0);
+  }
+  int flags = protocol.Element.makeFlags(
+      isAbstract: isAbstract,
+      isDeprecated: isDeprecated,
+      isPrivate: Identifier.isPrivateName(name));
+  return new protocol.Element(kind, name, flags,
+      location: location,
+      parameters: parameters,
+      returnType: _nameForType(returnType));
+}
+
+/**
+* Create a new suggestion based upon the given information.
+* Return the new suggestion or `null` if it could not be created.
+*/
+CompletionSuggestion _createLocalSuggestion(
+    SimpleIdentifier id,
+    CompletionSuggestionKind kind,
+    bool isDeprecated,
+    int defaultRelevance,
+    TypeName returnType,
+    {ClassDeclaration classDecl,
+    protocol.Element element}) {
+  if (id == null) {
+    return null;
+  }
+  String completion = id.name;
+  if (completion == null || completion.length <= 0 || completion == '_') {
+    return null;
+  }
+  CompletionSuggestion suggestion = new CompletionSuggestion(
+      kind,
+      isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance,
+      completion,
+      completion.length,
+      0,
+      isDeprecated,
+      false,
+      returnType: _nameForType(returnType),
+      element: element);
+  if (classDecl != null) {
+    SimpleIdentifier classId = classDecl.name;
+    if (classId != null) {
+      String className = classId.name;
+      if (className != null && className.length > 0) {
+        suggestion.declaringType = className;
+      }
+    }
+  }
+  return suggestion;
+}
+
+/**
+* Return `true` if the @deprecated annotation is present
+*/
+bool _isDeprecated(AnnotatedNode node) {
+  if (node != null) {
+    NodeList<Annotation> metadata = node.metadata;
+    if (metadata != null) {
+      return metadata.any((Annotation a) {
+        return a.name is SimpleIdentifier && a.name.name == 'deprecated';
+      });
+    }
+  }
+  return false;
+}
+
+/**
+* Return the name for the given type.
+*/
+String _nameForType(TypeName type) {
+  if (type == NO_RETURN_TYPE) {
+    return null;
+  }
+  if (type == null) {
+    return DYNAMIC;
+  }
+  Identifier id = type.name;
+  if (id == null) {
+    return DYNAMIC;
+  }
+  String name = id.name;
+  if (name == null || name.length <= 0) {
+    return DYNAMIC;
+  }
+  TypeArgumentList typeArgs = type.typeArguments;
+  if (typeArgs != null) {
+    //TODO (danrubel) include type arguments
+  }
+  return name;
+}
+
+/**
  * A contributor for calculating suggestions for declarations in the local
  * file and containing library.
  */
@@ -259,6 +370,38 @@
     }
   }
 
+  void _addLocalSuggestion(
+      SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
+      {bool isAbstract: false,
+      bool isDeprecated: false,
+      ClassDeclaration classDecl,
+      FormalParameterList param,
+      int relevance: DART_RELEVANCE_DEFAULT}) {
+    CompletionSuggestionKind kind = targetIsFunctionalArgument
+        ? CompletionSuggestionKind.IDENTIFIER
+        : optype.suggestKind;
+    CompletionSuggestion suggestion = _createLocalSuggestion(
+        id, kind, isDeprecated, relevance, typeName,
+        classDecl: classDecl);
+    if (suggestion != null) {
+      if (privateMemberRelevance != null &&
+          suggestion.completion.startsWith('_')) {
+        suggestion.relevance = privateMemberRelevance;
+      }
+      suggestionMap.putIfAbsent(suggestion.completion, () => suggestion);
+      suggestion.element = _createLocalElement(request.source, elemKind, id,
+          isAbstract: isAbstract,
+          isDeprecated: isDeprecated,
+          parameters: param != null ? param.toSource() : null,
+          returnType: typeName);
+      if ((elemKind == protocol.ElementKind.METHOD ||
+              elemKind == protocol.ElementKind.FUNCTION) &&
+          param != null) {
+        _addParameterInfo(suggestion, param);
+      }
+    }
+  }
+
   void _addParameterInfo(
       CompletionSuggestion suggestion, FormalParameterList parameters) {
     var paramList = parameters.parameters;
@@ -296,38 +439,6 @@
         .any((FormalParameter param) => param.kind == ParameterKind.NAMED);
   }
 
-  void _addLocalSuggestion(
-      SimpleIdentifier id, TypeName typeName, protocol.ElementKind elemKind,
-      {bool isAbstract: false,
-      bool isDeprecated: false,
-      ClassDeclaration classDecl,
-      FormalParameterList param,
-      int relevance: DART_RELEVANCE_DEFAULT}) {
-    CompletionSuggestionKind kind = targetIsFunctionalArgument
-        ? CompletionSuggestionKind.IDENTIFIER
-        : optype.suggestKind;
-    CompletionSuggestion suggestion = _createLocalSuggestion(
-        id, kind, isDeprecated, relevance, typeName,
-        classDecl: classDecl);
-    if (suggestion != null) {
-      if (privateMemberRelevance != null &&
-          suggestion.completion.startsWith('_')) {
-        suggestion.relevance = privateMemberRelevance;
-      }
-      suggestionMap.putIfAbsent(suggestion.completion, () => suggestion);
-      suggestion.element = _createLocalElement(request.source, elemKind, id,
-          isAbstract: isAbstract,
-          isDeprecated: isDeprecated,
-          parameters: param != null ? param.toSource() : null,
-          returnType: typeName);
-      if ((elemKind == protocol.ElementKind.METHOD ||
-              elemKind == protocol.ElementKind.FUNCTION) &&
-          param != null) {
-        _addParameterInfo(suggestion, param);
-      }
-    }
-  }
-
   bool _isVoid(TypeName returnType) {
     if (returnType != null) {
       Identifier id = returnType.name;
@@ -338,113 +449,3 @@
     return false;
   }
 }
-
-/**
-* Create a new protocol Element for inclusion in a completion suggestion.
-*/
-protocol.Element _createLocalElement(
-    Source source, protocol.ElementKind kind, SimpleIdentifier id,
-    {String parameters,
-    TypeName returnType,
-    bool isAbstract: false,
-    bool isDeprecated: false}) {
-  String name;
-  Location location;
-  if (id != null) {
-    name = id.name;
-    // TODO(danrubel) use lineInfo to determine startLine and startColumn
-    location = new Location(source.fullName, id.offset, id.length, 0, 0);
-  } else {
-    name = '';
-    location = new Location(source.fullName, -1, 0, 1, 0);
-  }
-  int flags = protocol.Element.makeFlags(
-      isAbstract: isAbstract,
-      isDeprecated: isDeprecated,
-      isPrivate: Identifier.isPrivateName(name));
-  return new protocol.Element(kind, name, flags,
-      location: location,
-      parameters: parameters,
-      returnType: _nameForType(returnType));
-}
-
-/**
-* Create a new suggestion based upon the given information.
-* Return the new suggestion or `null` if it could not be created.
-*/
-CompletionSuggestion _createLocalSuggestion(
-    SimpleIdentifier id,
-    CompletionSuggestionKind kind,
-    bool isDeprecated,
-    int defaultRelevance,
-    TypeName returnType,
-    {ClassDeclaration classDecl,
-    protocol.Element element}) {
-  if (id == null) {
-    return null;
-  }
-  String completion = id.name;
-  if (completion == null || completion.length <= 0 || completion == '_') {
-    return null;
-  }
-  CompletionSuggestion suggestion = new CompletionSuggestion(
-      kind,
-      isDeprecated ? DART_RELEVANCE_LOW : defaultRelevance,
-      completion,
-      completion.length,
-      0,
-      isDeprecated,
-      false,
-      returnType: _nameForType(returnType),
-      element: element);
-  if (classDecl != null) {
-    SimpleIdentifier classId = classDecl.name;
-    if (classId != null) {
-      String className = classId.name;
-      if (className != null && className.length > 0) {
-        suggestion.declaringType = className;
-      }
-    }
-  }
-  return suggestion;
-}
-
-/**
-* Return `true` if the @deprecated annotation is present
-*/
-bool _isDeprecated(AnnotatedNode node) {
-  if (node != null) {
-    NodeList<Annotation> metadata = node.metadata;
-    if (metadata != null) {
-      return metadata.any((Annotation a) {
-        return a.name is SimpleIdentifier && a.name.name == 'deprecated';
-      });
-    }
-  }
-  return false;
-}
-
-/**
-* Return the name for the given type.
-*/
-String _nameForType(TypeName type) {
-  if (type == NO_RETURN_TYPE) {
-    return null;
-  }
-  if (type == null) {
-    return DYNAMIC;
-  }
-  Identifier id = type.name;
-  if (id == null) {
-    return DYNAMIC;
-  }
-  String name = id.name;
-  if (name == null || name.length <= 0) {
-    return DYNAMIC;
-  }
-  TypeArgumentList typeArgs = type.typeArguments;
-  if (typeArgs != null) {
-    //TODO (danrubel) include type arguments
-  }
-  return name;
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
index 9acbf07..71c1bfd 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
@@ -4,10 +4,11 @@
 
 library services.completion.dart.optype;
 
-import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/generated/ast.dart';
 
 /**
  * An [AstVisitor] for determining whether top level suggestions or invocation
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
index 257527b..7a0f760 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -72,7 +72,8 @@
         } else if (elem is LocalVariableElement) {
           type = elem.type;
         }
-        if (type.isDynamic && expression is SimpleIdentifier) {
+        if ((type == null || type.isDynamic) &&
+            expression is SimpleIdentifier) {
           // If the element does not provide a good type
           // then attempt to get a better type from a local declaration
           _LocalBestTypeVisitor visitor =
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 a683638..b5a7ea2 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -17,12 +17,13 @@
 import 'package:analysis_server/src/services/correction/statement_analyzer.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analysis_server/src/services/search/hierarchy.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:path/path.dart';
 
@@ -286,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);
@@ -309,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) {
@@ -1092,17 +1094,15 @@
     Block targetBlock;
     {
       Statement statement = node.getAncestor((n) => n is Statement);
-      prefix = utils.getNodePrefix(statement);
       if (statement is IfStatement && statement.thenStatement is Block) {
         targetBlock = statement.thenStatement;
-      }
-      if (statement is WhileStatement && statement.body is Block) {
+      } else if (statement is WhileStatement && statement.body is Block) {
         targetBlock = statement.body;
+      } else {
+        _coverageMarker();
+        return;
       }
-    }
-    if (targetBlock == null) {
-      _coverageMarker();
-      return;
+      prefix = utils.getNodePrefix(statement);
     }
     // prepare location
     int offset;
@@ -1432,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 fa16435..dc66c45 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -24,9 +24,11 @@
 import 'package:analysis_server/src/services/correction/strings.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analysis_server/src/services/search/hierarchy.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -35,7 +37,6 @@
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -149,6 +150,9 @@
         CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE) {
       _addFix_replaceWithConstInstanceCreation();
     }
+    if (errorCode == CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT) {
+      _addFix_addAsync_asyncFor();
+    }
     if (errorCode == CompileTimeErrorCode.INVALID_ANNOTATION) {
       if (node is Annotation) {
         Annotation annotation = node;
@@ -339,6 +343,12 @@
       _addFix_undefinedClassAccessor_useSimilar();
       _addFix_createField();
     }
+    // lints
+    if (errorCode is LintCode) {
+      if (errorCode.name == LintNames.annotate_overrides) {
+        _addLintFixAddOverrideAnnotation();
+      }
+    }
     // done
     return fixes;
   }
@@ -387,6 +397,7 @@
       FunctionBody body = node.getAncestor((n) => n is FunctionBody);
       if (body != null && body.keyword == null) {
         _addReplaceEdit(rf.rangeStartLength(body, 0), 'async ');
+        _replaceReturnTypeWithFuture(body);
         _addFix(DartFixKind.ADD_ASYNC, []);
         return true;
       }
@@ -394,6 +405,15 @@
     return false;
   }
 
+  void _addFix_addAsync_asyncFor() {
+    FunctionBody body = node.getAncestor((n) => n is FunctionBody);
+    if (body != null && body.keyword == null) {
+      _addReplaceEdit(rf.rangeStartLength(body, 0), 'async ');
+      _replaceReturnTypeWithFuture(body);
+      _addFix(DartFixKind.ADD_ASYNC, []);
+    }
+  }
+
   void _addFix_addMissingParameter() {
     if (node is ArgumentList && node.parent is MethodInvocation) {
       ArgumentList argumentList = node;
@@ -434,7 +454,8 @@
           if (numRequired != 0) {
             sb.append(', ');
           }
-          _appendParameterForArgument(sb, numRequired, argument);
+          _appendParameterForArgument(
+              sb, new Set<String>(), numRequired, argument);
           if (numRequired != numParameters) {
             sb.append(', ');
           }
@@ -450,7 +471,8 @@
             sb.append(', ');
           }
           sb.append('[');
-          _appendParameterForArgument(sb, numRequired, argument);
+          _appendParameterForArgument(
+              sb, new Set<String>(), numRequired, argument);
           sb.append(']');
           // add proposal
           _insertBuilder(sb, targetElement);
@@ -1223,6 +1245,7 @@
       isFirst = false;
     }
     // merge getter/setter pairs into fields
+    String prefix = utils.getIndent(1);
     for (int i = 0; i < elements.length; i++) {
       ExecutableElement element = elements[i];
       if (element.kind == ElementKind.GETTER && i + 1 < elements.length) {
@@ -1233,10 +1256,17 @@
           elements.removeAt(i);
           i--;
           numElements--;
-          // add field
+          // separator
           addEolIfNotFirst();
-          sb.append(utils.getIndent(1));
-          _appendType(sb, element.type.returnType);
+          // @override
+          {
+            sb.append(prefix);
+            sb.append('@override');
+            sb.append(eol);
+          }
+          // add field
+          sb.append(prefix);
+          _appendType(sb, element.type.returnType, orVar: true);
           sb.append(element.name);
           sb.append(';');
           sb.append(eol);
@@ -1346,19 +1376,9 @@
   }
 
   void _addFix_illegalAsyncReturnType() {
-    InterfaceType futureType = context.typeProvider.futureType;
-    String futureTypeCode = utils.getTypeSource(futureType, librariesToImport);
     // prepare the existing type
     TypeName typeName = node.getAncestor((n) => n is TypeName);
-    String nodeCode = utils.getNodeText(typeName);
-    // wrap the existing type with Future
-    String returnTypeCode;
-    if (nodeCode == 'void') {
-      returnTypeCode = futureTypeCode;
-    } else {
-      returnTypeCode = '$futureTypeCode<$nodeCode>';
-    }
-    _addReplaceEdit(rf.rangeNode(typeName), returnTypeCode);
+    _replaceTypeWithFuture(typeName);
     // add proposal
     _addFix(DartFixKind.REPLACE_RETURN_TYPE_FUTURE, []);
   }
@@ -2029,6 +2049,7 @@
 
   void _addFix_undefinedMethod_create_parameters(
       SourceBuilder sb, ArgumentList argumentList) {
+    Set<String> usedNames = new Set<String>();
     // append parameters
     sb.append('(');
     List<Expression> arguments = argumentList.arguments;
@@ -2044,7 +2065,7 @@
         hasNamedParameters = true;
         sb.append('{');
       }
-      _appendParameterForArgument(sb, i, argument);
+      _appendParameterForArgument(sb, usedNames, i, argument);
     }
     if (hasNamedParameters) {
       sb.append('}');
@@ -2187,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].
@@ -2235,7 +2276,7 @@
           {
             sb.startPosition('TYPE$i');
             sb.append(typeSource);
-            _addSuperTypeProposals(sb, new Set(), type);
+            _addSuperTypeProposals(sb, type);
             sb.endPosition();
           }
           sb.append(' ');
@@ -2330,14 +2371,14 @@
   }
 
   void _appendParameterForArgument(
-      SourceBuilder sb, int index, Expression argument) {
+      SourceBuilder sb, Set<String> excluded, int index, Expression argument) {
     // append type name
     DartType type = argument.bestType;
     String typeSource = utils.getTypeSource(type, librariesToImport);
     if (typeSource != 'dynamic') {
       sb.startPosition('TYPE$index');
       sb.append(typeSource);
-      _addSuperTypeProposals(sb, new Set(), type);
+      _addSuperTypeProposals(sb, type);
       sb.endPosition();
       sb.append(' ');
     }
@@ -2345,7 +2386,6 @@
     if (argument is NamedExpression) {
       sb.append(argument.name.label.name);
     } else {
-      Set<String> excluded = new Set<String>();
       List<String> suggestions =
           _getArgumentNameSuggestions(excluded, type, argument, index);
       String favorite = suggestions[0];
@@ -2776,6 +2816,40 @@
     }
   }
 
+  void _replaceReturnTypeWithFuture(AstNode node) {
+    for (; node != null; node = node.parent) {
+      if (node is FunctionDeclaration) {
+        _replaceTypeWithFuture(node.returnType);
+        return;
+      } else if (node is MethodDeclaration) {
+        _replaceTypeWithFuture(node.returnType);
+        return;
+      }
+    }
+  }
+
+  void _replaceTypeWithFuture(TypeName typeName) {
+    InterfaceType futureType = context.typeProvider.futureType;
+    // validate the type
+    DartType type = typeName?.type;
+    if (type == null ||
+        type.isDynamic ||
+        type is InterfaceType && type.element == futureType.element) {
+      return;
+    }
+    // prepare code for the types
+    String futureTypeCode = utils.getTypeSource(futureType, librariesToImport);
+    String nodeCode = utils.getNodeText(typeName);
+    // wrap the existing type with Future
+    String returnTypeCode;
+    if (nodeCode == 'void') {
+      returnTypeCode = futureTypeCode;
+    } else {
+      returnTypeCode = '$futureTypeCode<$nodeCode>';
+    }
+    _addReplaceEdit(rf.rangeNode(typeName), returnTypeCode);
+  }
+
   void _updateFinderWithClassMembers(
       _ClosestElementFinder finder, ClassElement clazz) {
     if (clazz != null) {
@@ -2784,16 +2858,14 @@
     }
   }
 
-  static void _addSuperTypeProposals(
-      SourceBuilder sb, Set<DartType> alreadyAdded, DartType type) {
-    if (type != null &&
-        type.element is ClassElement &&
-        alreadyAdded.add(type)) {
-      ClassElement element = type.element as ClassElement;
-      sb.addSuggestion(LinkedEditSuggestionKind.TYPE, element.name);
-      _addSuperTypeProposals(sb, alreadyAdded, element.supertype);
-      for (InterfaceType interfaceType in element.interfaces) {
-        _addSuperTypeProposals(sb, alreadyAdded, interfaceType);
+  static void _addSuperTypeProposals(SourceBuilder sb, DartType type,
+      [Set<DartType> alreadyAdded]) {
+    alreadyAdded ??= new Set<DartType>();
+    if (type is InterfaceType && alreadyAdded.add(type)) {
+      sb.addSuggestion(LinkedEditSuggestionKind.TYPE, type.displayName);
+      _addSuperTypeProposals(sb, type.superclass, alreadyAdded);
+      for (InterfaceType interfaceType in type.interfaces) {
+        _addSuperTypeProposals(sb, interfaceType, alreadyAdded);
       }
     }
   }
@@ -2838,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/services/correction/organize_directives.dart b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
index a4adfac..9d9faa1 100644
--- a/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
+++ b/pkg/analysis_server/lib/src/services/correction/organize_directives.dart
@@ -7,9 +7,9 @@
 import 'package:analysis_server/plugin/protocol/protocol.dart'
     hide AnalysisError, Element;
 import 'package:analysis_server/src/services/correction/strings.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 
 /**
  * Organizer of directives in the [unit].
diff --git a/pkg/analysis_server/lib/src/services/correction/sort_members.dart b/pkg/analysis_server/lib/src/services/correction/sort_members.dart
index 1810cda..49f104b 100644
--- a/pkg/analysis_server/lib/src/services/correction/sort_members.dart
+++ b/pkg/analysis_server/lib/src/services/correction/sort_members.dart
@@ -6,8 +6,8 @@
 
 import 'package:analysis_server/plugin/protocol/protocol.dart' hide Element;
 import 'package:analysis_server/src/services/correction/strings.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 
 /**
  * Sorter for unit/class members.
diff --git a/pkg/analysis_server/lib/src/services/correction/source_range.dart b/pkg/analysis_server/lib/src/services/correction/source_range.dart
index bf52759..32c98b9 100644
--- a/pkg/analysis_server/lib/src/services/correction/source_range.dart
+++ b/pkg/analysis_server/lib/src/services/correction/source_range.dart
@@ -4,10 +4,10 @@
 
 library services.src.correction.source_range_factory;
 
+import 'package:analyzer/dart/ast/token.dart';
 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/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 SourceRange rangeElementName(Element element) {
diff --git a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
index c25f77a..2ec69eb 100644
--- a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
@@ -9,9 +9,11 @@
 import 'package:analysis_server/src/services/correction/source_range.dart';
 import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/src/services/correction/strings.dart b/pkg/analysis_server/lib/src/services/correction/strings.dart
index 1689c7c..4a0ff76 100644
--- a/pkg/analysis_server/lib/src/services/correction/strings.dart
+++ b/pkg/analysis_server/lib/src/services/correction/strings.dart
@@ -201,6 +201,10 @@
   return str == null || str.isEmpty;
 }
 
+bool isEOL(int c) {
+  return c == 0x0D || c == 0x0A;
+}
+
 bool isLetter(int c) {
   return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A);
 }
@@ -220,7 +224,7 @@
 }
 
 bool isWhitespace(int c) {
-  return isSpace(c) || c == 0x0D || c == 0x0A;
+  return isSpace(c) || isEOL(c);
 }
 
 String remove(String str, String remove) {
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 33a3105..65c12c6 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -12,12 +12,15 @@
     show doSourceChange_addElementEdit;
 import 'package:analysis_server/src/services/correction/source_range.dart';
 import 'package:analysis_server/src/services/correction/strings.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:path/path.dart';
 
@@ -396,17 +399,14 @@
  */
 Expression getNodeQualifier(SimpleIdentifier node) {
   AstNode parent = node.parent;
-  if (parent is PropertyAccess) {
-    PropertyAccess propertyAccess = parent;
-    if (identical(propertyAccess.propertyName, node)) {
-      return propertyAccess.target;
-    }
+  if (parent is MethodInvocation && identical(parent.methodName, node)) {
+    return parent.target;
   }
-  if (parent is PrefixedIdentifier) {
-    PrefixedIdentifier prefixed = parent;
-    if (identical(prefixed.identifier, node)) {
-      return prefixed.prefix;
-    }
+  if (parent is PropertyAccess && identical(parent.propertyName, node)) {
+    return parent.target;
+  }
+  if (parent is PrefixedIdentifier && identical(parent.identifier, node)) {
+    return parent.prefix;
   }
   return null;
 }
@@ -667,7 +667,8 @@
     AstNode enclosingNode = findNode(offset);
     Block enclosingBlock = enclosingNode.getAncestor((node) => node is Block);
     if (enclosingBlock != null) {
-      _CollectReferencedUnprefixedNames visitor = new _CollectReferencedUnprefixedNames();
+      _CollectReferencedUnprefixedNames visitor =
+          new _CollectReferencedUnprefixedNames();
       enclosingBlock.accept(visitor);
       return visitor.names;
     }
@@ -906,10 +907,14 @@
    * Returns a [SourceRange] that covers [range] and extends (if possible) to
    * cover whole lines.
    */
-  SourceRange getLinesRange(SourceRange range) {
+  SourceRange getLinesRange(SourceRange range,
+      {bool skipLeadingEmptyLines: false}) {
     // start
     int startOffset = range.offset;
     int startLineOffset = getLineContentStart(startOffset);
+    if (skipLeadingEmptyLines) {
+      startLineOffset = skipEmptyLinesLeft(startLineOffset);
+    }
     // end
     int endOffset = range.end;
     int afterEndLineOffset = getLineContentEnd(endOffset);
@@ -1031,7 +1036,8 @@
    * Fills [librariesToImport] with [LibraryElement]s whose elements are
    * used by the generated source, but not imported.
    */
-  String getTypeSource(DartType type, Set<LibraryElement> librariesToImport) {
+  String getTypeSource(DartType type, Set<LibraryElement> librariesToImport,
+      {StringBuffer parametersBuffer}) {
     StringBuffer sb = new StringBuffer();
     // type parameter
     if (!_isTypeVisible(type)) {
@@ -1039,7 +1045,21 @@
     }
     // just a Function, not FunctionTypeAliasElement
     if (type is FunctionType && type.element is! FunctionTypeAliasElement) {
-      return "Function";
+      if (parametersBuffer == null) {
+        return "Function";
+      }
+      parametersBuffer.write('(');
+      for (ParameterElement parameter in type.parameters) {
+        String parameterType = getTypeSource(parameter.type, librariesToImport);
+        if (parametersBuffer.length != 1) {
+          parametersBuffer.write(', ');
+        }
+        parametersBuffer.write(parameterType);
+        parametersBuffer.write(' ');
+        parametersBuffer.write(parameter.name);
+      }
+      parametersBuffer.write(')');
+      return getTypeSource(type.returnType, librariesToImport);
     }
     // BottomType
     if (type.isBottom) {
@@ -1224,6 +1244,27 @@
   }
 
   /**
+   * Skip spaces, tabs and EOLs on the left from [index].
+   *
+   * If [index] is the start of a method, then in the most cases return the end
+   * of the previous not-whitespace line.
+   */
+  int skipEmptyLinesLeft(int index) {
+    int lastLine = index;
+    while (index > 0) {
+      int c = _buffer.codeUnitAt(index - 1);
+      if (!isWhitespace(c)) {
+        return lastLine;
+      }
+      if (isEOL(c)) {
+        lastLine = index;
+      }
+      index--;
+    }
+    return 0;
+  }
+
+  /**
    * @return the [ImportElement] used to import given [Element] into [library].
    *         May be `null` if was not imported, i.e. declared in the same library.
    */
diff --git a/pkg/analysis_server/lib/src/services/index/index_contributor.dart b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
index b5eee6b..ebac4d6 100644
--- a/pkg/analysis_server/lib/src/services/index/index_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
@@ -12,12 +12,12 @@
 import 'package:analysis_server/src/services/index/index_store.dart';
 import 'package:analysis_server/src/services/index/indexable_element.dart';
 import 'package:analysis_server/src/services/index/indexable_file.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
index 51db1c2..d91306c 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
@@ -13,9 +13,9 @@
 import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
 import 'package:analysis_server/src/services/search/hierarchy.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index a17bfda..bb513ba 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -17,10 +17,10 @@
 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 const String _TOKEN_SEPARATOR = "\uFFFF";
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 6135237..1cb713a 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -20,17 +20,27 @@
 import 'package:analysis_server/src/services/refactoring/rename_unit_member.dart';
 import 'package:analysis_server/src/services/search/element_visitors.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/resolver.dart' show ExitDetector;
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 const String _TOKEN_SEPARATOR = '\uFFFF';
 
+Element _getLocalElement(SimpleIdentifier node) {
+  Element element = node.staticElement;
+  if (element is LocalVariableElement ||
+      element is ParameterElement ||
+      element is FunctionElement && element.visibleRange != null) {
+    return element;
+  }
+  return null;
+}
+
 /**
  * Returns the "normalized" version of the given source, which is reconstructed
  * from tokens, so ignores all the comments and spaces.
@@ -161,6 +171,10 @@
         }
         // name
         sb.write(parameter.name);
+        // optional function-typed parameter parameters
+        if (parameter.parameters != null) {
+          sb.write(parameter.parameters);
+        }
       }
       sb.write(')');
     }
@@ -662,9 +676,9 @@
   }
 
   /**
-   * Checks if the given [VariableElement] is declared in [selectionRange].
+   * Checks if the given [element] is declared in [selectionRange].
    */
-  bool _isDeclaredInSelection(VariableElement element) {
+  bool _isDeclaredInSelection(Element element) {
     return selectionRange.contains(element.nameOffset);
   }
 
@@ -700,7 +714,7 @@
   /**
    * Checks if [element] is referenced after [selectionRange].
    */
-  bool _isUsedAfterSelection(VariableElement element) {
+  bool _isUsedAfterSelection(Element element) {
     var visitor = new _IsUsedAfterSelectionVisitor(this, element);
     _parentMember.accept(visitor);
     return visitor.result;
@@ -907,18 +921,18 @@
   visitSimpleIdentifier(SimpleIdentifier node) {
     SourceRange nodeRange = rangeNode(node);
     if (partRange.covers(nodeRange)) {
-      VariableElement variableElement =
-          getLocalOrParameterVariableElement(node);
-      if (variableElement != null) {
+      Element element = _getLocalElement(node);
+      if (element != null) {
         // name of a named expression
         if (isNamedExpressionName(node)) {
           return;
         }
         // continue
-        String originalName = variableElement.displayName;
+        String originalName = element.displayName;
         String patternName = pattern.originalToPatternNames[originalName];
         if (patternName == null) {
-          pattern.parameterTypes.add(variableElement.type);
+          DartType parameterType = _getElementType(element);
+          pattern.parameterTypes.add(parameterType);
           patternName = '__refVar${pattern.originalToPatternNames.length}';
           pattern.originalToPatternNames[originalName] = patternName;
         }
@@ -927,6 +941,16 @@
       }
     }
   }
+
+  DartType _getElementType(Element element) {
+    if (element is VariableElement) {
+      return element.type;
+    }
+    if (element is FunctionElement) {
+      return element.type;
+    }
+    throw new StateError('Unknown element type: ${element?.runtimeType}');
+  }
 }
 
 class _HasAwaitVisitor extends GeneralizingAstVisitor {
@@ -1077,23 +1101,28 @@
       return;
     }
     String name = node.name;
-    // analyze local variable
-    VariableElement variableElement = getLocalOrParameterVariableElement(node);
-    if (variableElement != null) {
+    // analyze local element
+    Element element = _getLocalElement(node);
+    if (element != null) {
       // name of the named expression
       if (isNamedExpressionName(node)) {
         return;
       }
       // if declared outside, add parameter
-      if (!ref._isDeclaredInSelection(variableElement)) {
+      if (!ref._isDeclaredInSelection(element)) {
         // add parameter
         RefactoringMethodParameter parameter = ref._parametersMap[name];
         if (parameter == null) {
           DartType parameterType = node.bestType;
-          String parameterTypeCode = ref._getTypeCode(parameterType);
+          StringBuffer parametersBuffer = new StringBuffer();
+          String parameterTypeCode = ref.utils.getTypeSource(
+              parameterType, ref.librariesToImport,
+              parametersBuffer: parametersBuffer);
+          String parametersCode =
+              parametersBuffer.isNotEmpty ? parametersBuffer.toString() : null;
           parameter = new RefactoringMethodParameter(
               RefactoringMethodParameterKind.REQUIRED, parameterTypeCode, name,
-              id: name);
+              parameters: parametersCode, id: name);
           ref._parameters.add(parameter);
           ref._parametersMap[name] = parameter;
         }
@@ -1101,20 +1130,18 @@
         ref._addParameterReference(name, nodeRange);
       }
       // remember, if assigned and used after selection
-      if (isLeftHandOfAssignment(node) &&
-          ref._isUsedAfterSelection(variableElement)) {
-        if (!assignedUsedVariables.contains(variableElement)) {
-          assignedUsedVariables.add(variableElement);
+      if (isLeftHandOfAssignment(node) && ref._isUsedAfterSelection(element)) {
+        if (!assignedUsedVariables.contains(element)) {
+          assignedUsedVariables.add(element);
         }
       }
     }
     // remember information for conflicts checking
-    if (variableElement is LocalElement) {
+    if (element is LocalElement) {
       // declared local elements
-      LocalElement localElement = variableElement as LocalElement;
       if (node.inDeclarationContext()) {
         ref._localNames.putIfAbsent(name, () => <SourceRange>[]);
-        ref._localNames[name].add(localElement.visibleRange);
+        ref._localNames[name].add(element.visibleRange);
       }
     } else {
       // unqualified non-local names
@@ -1127,14 +1154,14 @@
 
 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor {
   final ExtractMethodRefactoringImpl ref;
-  final VariableElement element;
+  final Element element;
   bool result = false;
 
   _IsUsedAfterSelectionVisitor(this.ref, this.element);
 
   @override
   visitSimpleIdentifier(SimpleIdentifier node) {
-    VariableElement nodeElement = getLocalVariableElement(node);
+    Element nodeElement = node.staticElement;
     if (identical(nodeElement, element)) {
       int nodeOffset = node.offset;
       if (nodeOffset > ref.selectionRange.end) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
index 1fe699a..d5c6894 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
@@ -13,10 +13,10 @@
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring_internal.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index 3b3c786..125c7ba 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -102,7 +102,7 @@
     }
   });
   // replace static field "qualifier" with invocation target
-  part._staticFieldOffsets.forEach((String className, List<int> offsets) {
+  part._implicitClassNameOffsets.forEach((String className, List<int> offsets) {
     for (int offset in offsets) {
 //      edits.add(newSourceEdit_range(range, className + '.'));
       edits.add(new SourceEdit(offset, 0, className + '.'));
@@ -263,7 +263,8 @@
     // delete method
     if (deleteSource && inlineAll) {
       SourceRange methodRange = rangeNode(_methodNode);
-      SourceRange linesRange = _methodUtils.getLinesRange(methodRange);
+      SourceRange linesRange =
+          _methodUtils.getLinesRange(methodRange, skipLeadingEmptyLines: true);
       doSourceChange_addElementEdit(
           change, _methodElement, newSourceEdit_range(linesRange, ''));
     }
@@ -682,9 +683,9 @@
   final List<int> _implicitThisOffsets = [];
 
   /**
-   * The offsets of the implicit class references in static field references.
+   * The offsets of the implicit class references in static member references.
    */
-  final Map<String, List<int>> _staticFieldOffsets = {};
+  final Map<String, List<int>> _implicitClassNameOffsets = {};
 
   _SourcePart(this._base, this._source, this._prefix);
 
@@ -692,6 +693,15 @@
     _explicitThisOffsets.add(offset - _base);
   }
 
+  void addImplicitClassNameOffset(String className, int offset) {
+    List<int> offsets = _implicitClassNameOffsets[className];
+    if (offsets == null) {
+      offsets = [];
+      _implicitClassNameOffsets[className] = offsets;
+    }
+    offsets.add(offset - _base);
+  }
+
   void addImplicitThisOffset(int offset) {
     _implicitThisOffsets.add(offset - _base);
   }
@@ -709,15 +719,6 @@
     }
   }
 
-  void addStaticFieldOffset(String className, int offset) {
-    List<int> offsets = _staticFieldOffsets[className];
-    if (offsets == null) {
-      offsets = [];
-      _staticFieldOffsets[className] = offsets;
-    }
-    offsets.add(offset - _base);
-  }
-
   void addVariable(VariableElement element, SourceRange range) {
     List<SourceRange> ranges = _variables[element];
     if (ranges == null) {
@@ -765,7 +766,7 @@
   visitSimpleIdentifier(SimpleIdentifier node) {
     SourceRange nodeRange = rangeNode(node);
     if (bodyRange.covers(nodeRange)) {
-      _addInstanceFieldQualifier(node);
+      _addMemberQualifier(node);
       _addParameter(node);
       _addVariable(node);
     }
@@ -779,19 +780,28 @@
     }
   }
 
-  void _addInstanceFieldQualifier(SimpleIdentifier node) {
-    PropertyAccessorElement accessor = getPropertyAccessorElement(node);
-    if (isFieldAccessorElement(accessor)) {
-      AstNode qualifier = getNodeQualifier(node);
-      if (qualifier == null) {
-        int offset = node.offset;
-        if (accessor.isStatic) {
-          String className = accessor.enclosingElement.displayName;
-          result.addStaticFieldOffset(className, offset);
-        } else {
-          result.addImplicitThisOffset(offset);
-        }
-      }
+  void _addMemberQualifier(SimpleIdentifier node) {
+    // should be unqualified
+    AstNode qualifier = getNodeQualifier(node);
+    if (qualifier != null) {
+      return;
+    }
+    // should be a method or field reference
+    Element element = node.staticElement;
+    if (!(element is MethodElement || element is PropertyAccessorElement)) {
+      return;
+    }
+    if (element.enclosingElement is! ClassElement) {
+      return;
+    }
+    // record the implicit static or instance reference
+    ExecutableElement member = element;
+    int offset = node.offset;
+    if (member.isStatic) {
+      String className = member.enclosingElement.displayName;
+      result.addImplicitClassNameOffset(className, offset);
+    } else {
+      result.addImplicitThisOffset(offset);
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart b/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
index aac5275..892da77 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/naming_conventions.dart
@@ -6,7 +6,7 @@
 
 import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/correction/strings.dart';
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/dart/ast/token.dart';
 
 /**
  * Returns the [RefactoringStatus] with severity:
diff --git a/pkg/analysis_server/lib/src/socket_server.dart b/pkg/analysis_server/lib/src/socket_server.dart
index f3e1c5c..ad1baaa 100644
--- a/pkg/analysis_server/lib/src/socket_server.dart
+++ b/pkg/analysis_server/lib/src/socket_server.dart
@@ -4,7 +4,6 @@
 
 library socket.server;
 
-import 'package:analysis_server/plugin/analysis/resolver_provider.dart';
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/channel/channel.dart';
@@ -13,7 +12,10 @@
 import 'package:analysis_server/src/services/index/local_file_index.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/plugin/embedded_resolver_provider.dart';
+import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:analyzer/source/pub_package_map_provider.dart';
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:plugin/plugin.dart';
 
@@ -25,9 +27,16 @@
  */
 class SocketServer {
   final AnalysisServerOptions analysisServerOptions;
+
+  /**
+   * The function used to create a new SDK using the default SDK.
+   */
+  final SdkCreator defaultSdkCreator;
+
   final DirectoryBasedDartSdk defaultSdk;
   final InstrumentationService instrumentationService;
   final ServerPlugin serverPlugin;
+  final EmbeddedResolverProvider embeddedResolverProvider;
   final ResolverProvider packageResolverProvider;
 
   /**
@@ -43,10 +52,12 @@
 
   SocketServer(
       this.analysisServerOptions,
+      this.defaultSdkCreator,
       this.defaultSdk,
       this.instrumentationService,
       this.serverPlugin,
-      this.packageResolverProvider);
+      this.packageResolverProvider,
+      this.embeddedResolverProvider);
 
   /**
    * Create an analysis server which will communicate with the client using the
@@ -88,9 +99,10 @@
         index,
         serverPlugin,
         analysisServerOptions,
-        defaultSdk,
+        defaultSdkCreator,
         instrumentationService,
         packageResolverProvider: packageResolverProvider,
+        embeddedResolverProvider: embeddedResolverProvider,
         rethrowExceptions: false);
     analysisServer.userDefinedPlugins = userDefinedPlugins;
   }
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 7260013..835488e 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -33,6 +33,7 @@
 import 'package:analyzer/source/error_processor.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
+import 'package:analyzer/src/context/source.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -65,10 +66,10 @@
   int totalDocSpan = 0;
 
   void visit(Element element) {
-    SourceRange docRange = element.docRange;
-    if (docRange != null) {
+    String comment = element.documentationComment;
+    if (comment != null) {
       ++elementsWithDocs;
-      totalDocSpan += docRange.length;
+      totalDocSpan += comment.length;
     }
 
     Type type = element.runtimeType;
@@ -639,8 +640,16 @@
           Set<AnalysisTarget> countedTargets = new HashSet<AnalysisTarget>();
           Map<String, int> sourceTypeCounts = new HashMap<String, int>();
           Map<String, int> typeCounts = new HashMap<String, int>();
-          analysisServer.folderMap
-              .forEach((Folder folder, InternalAnalysisContext context) {
+          int explicitSourceCount = 0;
+          int explicitLineInfoCount = 0;
+          int explicitLineCount = 0;
+          int implicitSourceCount = 0;
+          int implicitLineInfoCount = 0;
+          int implicitLineCount = 0;
+          for (InternalAnalysisContext context
+              in analysisServer.analysisContexts) {
+            Set<Source> explicitSources = new HashSet<Source>();
+            Set<Source> implicitSources = new HashSet<Source>();
             AnalysisCache cache = context.analysisCache;
             MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
             while (iterator.moveNext()) {
@@ -651,8 +660,10 @@
                   String sourceName;
                   if (AnalysisEngine.isDartFileName(name)) {
                     if (iterator.value.explicitlyAdded) {
+                      explicitSources.add(target);
                       sourceName = 'Dart file (explicit)';
                     } else {
+                      implicitSources.add(target);
                       sourceName = 'Dart file (implicit)';
                     }
                   } else if (AnalysisEngine.isHtmlFileName(name)) {
@@ -677,7 +688,27 @@
                 }
               }
             }
-          });
+
+            int lineCount(Set<Source> sources, bool explicit) {
+              return sources.fold(0, (int previousTotal, Source source) {
+                LineInfo lineInfo = context.getLineInfo(source);
+                if (lineInfo is LineInfoWithCount) {
+                  if (explicit) {
+                    explicitLineInfoCount++;
+                  } else {
+                    implicitLineInfoCount++;
+                  }
+                  return previousTotal + lineInfo.lineCount;
+                } else {
+                  return previousTotal;
+                }
+              });
+            }
+            explicitSourceCount += explicitSources.length;
+            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();
@@ -697,6 +728,37 @@
                 classes: [null, "right"]);
           }
           buffer.write('</table>');
+
+          buffer.write('<p><b>Line counts</b></p>');
+          buffer.write(
+              '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
+          _writeRow(buffer, ['Kind', 'Lines of Code', 'Source Counts'],
+              header: true);
+          _writeRow(buffer, [
+            'Explicit',
+            explicitLineCount.toString(),
+            '$explicitLineInfoCount / $explicitSourceCount'
+          ], classes: [
+            null,
+            "right"
+          ]);
+          _writeRow(buffer, [
+            'Implicit',
+            implicitLineCount.toString(),
+            '$implicitLineInfoCount / $implicitSourceCount'
+          ], classes: [
+            null,
+            "right"
+          ]);
+          _writeRow(buffer, [
+            'Total',
+            (explicitLineCount + implicitLineCount).toString(),
+            '${explicitLineInfoCount + implicitLineInfoCount} / ${explicitSourceCount + implicitSourceCount}'
+          ], classes: [
+            null,
+            "right"
+          ]);
+          buffer.write('</table>');
         }, (StringBuffer buffer) {
           //
           // Write task model timing information.
@@ -1293,9 +1355,26 @@
           buffer.write('<p><b>Error Processor count</b>: $processorCount</p>');
         });
 
-        _writeFiles(buffer, 'Priority Files', priorityNames);
-        _writeFiles(buffer, 'Explicitly Analyzed Files', explicitNames);
-        _writeFiles(buffer, 'Implicitly Analyzed Files', implicitNames);
+        SourceFactory sourceFactory = context.sourceFactory;
+        if (sourceFactory is SourceFactoryImpl) {
+          buffer.write('<h3>Resolvers</h3>');
+          for (UriResolver resolver in sourceFactory.resolvers) {
+            buffer.write('<p>');
+            buffer.write(resolver.runtimeType);
+            buffer.write('</p>');
+          }
+        }
+
+        _writeFiles(
+            buffer, 'Priority Files (${priorityNames.length})', priorityNames);
+        _writeFiles(
+            buffer,
+            'Explicitly Analyzed Files (${explicitNames.length})',
+            explicitNames);
+        _writeFiles(
+            buffer,
+            'Implicitly Analyzed Files (${implicitNames.length})',
+            implicitNames);
 
         buffer.write('<h3>Exceptions</h3>');
         if (exceptions.isEmpty) {
@@ -1598,6 +1677,9 @@
           buffer.write('<p>Status: Analyzing</p>');
         }
       }
+      buffer.write('<p>Using package resolver provider: ');
+      buffer.write(_server.packageResolverProvider != null);
+      buffer.write('</p>');
       buffer.write('<p>');
       buffer.write(makeLink(OVERLAYS_PATH, {}, 'All overlay information'));
       buffer.write('</p>');
diff --git a/pkg/analysis_server/lib/src/status/validator.dart b/pkg/analysis_server/lib/src/status/validator.dart
index 10dc8ac..5651b8e 100644
--- a/pkg/analysis_server/lib/src/status/validator.dart
+++ b/pkg/analysis_server/lib/src/status/validator.dart
@@ -6,17 +6,17 @@
 
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisEngine, AnalysisResult, CacheState, ChangeSet;
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/task/dart.dart';
@@ -708,24 +708,6 @@
           (VariableElement element) =>
               element.isFinal ? 'a final $kind' : 'a non-final $kind');
     }
-    if (expected.isPotentiallyMutatedInClosure !=
-        actual.isPotentiallyMutatedInClosure) {
-      _writeMismatch(
-          expected,
-          actual,
-          (VariableElement element) => element.isPotentiallyMutatedInClosure
-              ? 'a $kind that is potentially mutated in a closure'
-              : 'a $kind that is not mutated in a closure');
-    }
-    if (expected.isPotentiallyMutatedInScope !=
-        actual.isPotentiallyMutatedInScope) {
-      _writeMismatch(
-          expected,
-          actual,
-          (VariableElement element) => element.isPotentiallyMutatedInScope
-              ? 'a $kind that is potentially mutated in its scope'
-              : 'a $kind that is not mutated in its scope');
-    }
     if (expected.isStatic != actual.isStatic) {
       _writeMismatch(
           expected,
@@ -756,8 +738,8 @@
    * Write a simple message explaining that the [expected] and [actual] values
    * were different, using the [describe] function to describe the values.
    */
-  void _writeMismatch /*<E>*/ (Object /*=E*/ expected, Object /*=E*/ actual,
-      String describe(Object /*=E*/ value)) {
+  void _writeMismatch/*<E>*/(Object/*=E*/ expected, Object/*=E*/ actual,
+      String describe(Object/*=E*/ value)) {
     _write('Expected ');
     _write(describe(expected));
     _write('; found ');
@@ -1193,11 +1175,10 @@
     //
     // Handle special cases.
     //
-    if (first is ConstantEvaluationTarget_Annotation &&
-        second is ConstantEvaluationTarget_Annotation) {
+    if (first is ElementAnnotationImpl && second is ElementAnnotationImpl) {
       return _equal(first.source, second.source) &&
           _equal(first.librarySource, second.librarySource) &&
-          _equal(first.annotation, second.annotation);
+          _equal(first.annotationAst, second.annotationAst);
     } else if (first is AstNode && second is AstNode) {
       return first.runtimeType == second.runtimeType &&
           first.offset == second.offset &&
@@ -1216,7 +1197,7 @@
     //
     // Handle special cases.
     //
-    if (object is ConstantEvaluationTarget_Annotation) {
+    if (object is ElementAnnotation) {
       return object.source.hashCode;
     } else if (object is AstNode) {
       return object.offset;
@@ -1308,17 +1289,17 @@
 
   bool _compareConstantEvaluationTargets(ConstantEvaluationTarget expected,
       ConstantEvaluationTarget actual, StringBuffer buffer) {
-    if (actual is ConstantEvaluationTarget_Annotation) {
-      ConstantEvaluationTarget_Annotation expectedAnnotation = expected;
-      ConstantEvaluationTarget_Annotation actualAnnotation = actual;
+    if (actual is ElementAnnotation) {
+      ElementAnnotationImpl expectedAnnotation = expected;
+      ElementAnnotationImpl actualAnnotation = actual;
       if (actualAnnotation.source == expectedAnnotation.source &&
           actualAnnotation.librarySource == expectedAnnotation.librarySource &&
-          actualAnnotation.annotation == expectedAnnotation.annotation) {
+          actualAnnotation.annotationAst == expectedAnnotation.annotationAst) {
         return true;
       }
       if (buffer != null) {
-        void write(ConstantEvaluationTarget_Annotation target) {
-          Annotation annotation = target.annotation;
+        void write(ElementAnnotationImpl target) {
+          Annotation annotation = target.annotationAst;
           buffer.write(annotation);
           buffer.write(' at ');
           buffer.write(annotation.offset);
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
index bac921d..51131dc 100644
--- a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
@@ -10,11 +10,11 @@
 import 'package:analysis_server/src/services/correction/name_suggestion.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analysis_server/src/utilities/change_builder_core.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
diff --git a/pkg/analysis_server/lib/starter.dart b/pkg/analysis_server/lib/starter.dart
index ad5b19d..bb2f0f6 100644
--- a/pkg/analysis_server/lib/starter.dart
+++ b/pkg/analysis_server/lib/starter.dart
@@ -4,9 +4,10 @@
 
 library analysis_server.starter;
 
-import 'package:analysis_server/plugin/analysis/resolver_provider.dart';
 import 'package:analysis_server/src/server/driver.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/plugin/embedded_resolver_provider.dart';
+import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:plugin/plugin.dart';
 
 /**
@@ -22,6 +23,14 @@
   factory ServerStarter() = Driver;
 
   /**
+   * Set the embedded resolver provider used to override the way embedded
+   * library URI's are resolved in some contexts. The provider should return
+   * `null` if the embedded library URI resolution scheme should be used
+   * instead.
+   */
+  void set embeddedUriResolverProvider(EmbeddedResolverProvider provider);
+
+  /**
    * Set the instrumentation [server] that is to be used by the analysis server.
    */
   void set instrumentationServer(InstrumentationServer server);
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index cc1a4e4..672e9f2 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -96,6 +96,71 @@
     expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
   }
 
+  test_dartdoc_inherited_methodByMethod_fromInterface() async {
+    addTestFile('''
+class A {
+  /// my doc
+  m() {} // in A
+}
+
+class B implements A {
+  m() {} // in B
+}
+''');
+    HoverInformation hover = await prepareHover('m() {} // in B');
+    expect(hover.dartdoc, '''my doc\n\nCopied from `A`.''');
+  }
+
+  test_dartdoc_inherited_methodByMethod_fromSuper_direct() async {
+    addTestFile('''
+class A {
+  /// my doc
+  m() {} // in A
+}
+
+class B extends A {
+  m() {} // in B
+}
+''');
+    HoverInformation hover = await prepareHover('m() {} // in B');
+    expect(hover.dartdoc, '''my doc\n\nCopied from `A`.''');
+  }
+
+  test_dartdoc_inherited_methodByMethod_fromSuper_indirect() async {
+    addTestFile('''
+class A {
+  /// my doc
+  m() {}
+}
+class B extends A {
+  m() {}
+}
+class C extends B {
+  m() {} // in C
+}''');
+    HoverInformation hover = await prepareHover('m() {} // in C');
+    expect(hover.dartdoc, '''my doc\n\nCopied from `A`.''');
+  }
+
+  test_dartdoc_inherited_methodByMethod_preferSuper() async {
+    addTestFile('''
+class A {
+  /// my doc
+  m() {}
+}
+class B extends A {
+}
+class I {
+  // wrong doc
+  m() {}
+}
+class C extends B implements I {
+  m() {} // in C
+}''');
+    HoverInformation hover = await prepareHover('m() {} // in C');
+    expect(hover.dartdoc, '''my doc\n\nCopied from `A`.''');
+  }
+
   test_enum() async {
     addTestFile('''
 enum MyEnum {AAA, BBB, CCC}
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index d5cde86..ab0e0c1 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -276,6 +276,38 @@
     assertHasImplementedMember('m() {} // A');
   }
 
+  test_method_withMethod_private_differentLib() async {
+    addFile(
+        '$testFolder/lib.dart',
+        r'''
+import 'test.dart';
+class B extends A {
+  void _m() {}
+}
+''');
+    addTestFile('''
+class A {
+  _m() {} // A
+}
+''');
+    await prepareImplementedElements();
+    assertNoImplementedMember('_m() {} // A');
+  }
+
+  test_method_withMethod_private_sameLibrary() async {
+    addTestFile('''
+class A {
+  _m() {} // A
+}
+class B extends A {
+  _m() {} // B
+}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedMember('_m() {} // A');
+    assertNoImplementedMember('_m() {} // B');
+  }
+
   test_method_withMethod_wasAbstract() async {
     addTestFile('''
 abstract class A {
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index ae7551e..61db513 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -229,6 +229,24 @@
     assertNoOverride('fff(x) {} // B');
   }
 
+  test_BAD_privateByPrivate_inDifferentLib() async {
+    addFile(
+        '$testFolder/lib.dart',
+        r'''
+class A {
+  void _m() {}
+}
+''');
+    addTestFile('''
+import 'lib.dart';
+class B extends A {
+  void _m() {} // in B
+}
+''');
+    await prepareOverrides();
+    assertNoOverride('_m() {} // in B');
+  }
+
   test_BAD_setterByGetter() async {
     addTestFile('''
 class A {
@@ -352,7 +370,7 @@
 ''');
     await prepareOverrides();
     assertHasOverride('m() {} // in C');
-    expect(override.interfaceMembers, hasLength(1));
+    expect(override.interfaceMembers, hasLength(2));
     assertHasInterfaceMember('m() {} // in B');
   }
 
@@ -514,6 +532,21 @@
     assertNoInterfaceMembers();
   }
 
+  test_super_method_privateByPrivate() async {
+    addTestFile('''
+class A {
+  _m() {} // in A
+}
+class B extends A {
+  _m() {} // in B
+}
+''');
+    await prepareOverrides();
+    assertHasOverride('_m() {} // in B');
+    assertHasSuperElement('_m() {} // in A');
+    assertNoInterfaceMembers();
+  }
+
   test_super_method_superTypeCycle() async {
     addTestFile('''
 class A extends B {
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/set_priority_files_test.dart b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
index f89ba30..9a1b5c9 100644
--- a/pkg/analysis_server/test/analysis/set_priority_files_test.dart
+++ b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
@@ -58,7 +58,7 @@
     Response response = await _setPriorityFile(filePath);
     expect(response, isResponseSuccess('0'));
     // verify
-    InternalAnalysisContext sdkContext = server.defaultSdk.context;
+    InternalAnalysisContext sdkContext = server.findSdk().context;
     List<Source> prioritySources = sdkContext.prioritySources;
     expect(prioritySources, hasLength(1));
     expect(prioritySources.first.fullName, filePath);
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index 5c0616e..3541d91 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -32,7 +32,8 @@
     int c = search.codeUnitAt(length);
     if (!(c >= 'a'.codeUnitAt(0) && c <= 'z'.codeUnitAt(0) ||
         c >= 'A'.codeUnitAt(0) && c <= 'Z'.codeUnitAt(0) ||
-        c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0))) {
+        c >= '0'.codeUnitAt(0) && c <= '9'.codeUnitAt(0) ||
+        c == '_'.codeUnitAt(0))) {
       break;
     }
     length++;
@@ -125,7 +126,7 @@
         index,
         serverPlugin,
         new AnalysisServerOptions(),
-        new MockSdk(),
+        () => new MockSdk(),
         InstrumentationService.NULL_SERVICE);
   }
 
@@ -170,7 +171,7 @@
    */
   Response handleSuccessfulRequest(Request request) {
     Response response = handler.handleRequest(request);
-    expect(response, isResponseSuccess('0'));
+    expect(response, isResponseSuccess(request.id));
     return response;
   }
 
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 14d9fd6..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,9 +142,9 @@
         resourceProvider,
         packageMapProvider,
         null,
-        new ServerPlugin(),
+        plugin,
         new AnalysisServerOptions(),
-        new MockSdk(),
+        () => new MockSdk(),
         InstrumentationService.NULL_SERVICE,
         rethrowExceptions: true);
     processRequiredPlugins();
@@ -152,12 +155,15 @@
     resourceProvider.newFile('/foo/bar.dart', 'library lib;');
     server.setAnalysisRoots('0', ['/foo'], [], {});
     AnalysisContext context;
-    return pumpEventQueue().then((_) {
-      context = server.getAnalysisContext('/foo/bar.dart');
-      server.setAnalysisRoots('1', [], [], {});
-    }).then((_) => pumpEventQueue()).then((_) {
-      expect(context.isDisposed, isTrue);
-    });
+    return pumpEventQueue()
+        .then((_) {
+          context = server.getAnalysisContext('/foo/bar.dart');
+          server.setAnalysisRoots('1', [], [], {});
+        })
+        .then((_) => pumpEventQueue())
+        .then((_) {
+          expect(context.isDisposed, isTrue);
+        });
   }
 
   Future test_contextsChangedEvent() {
@@ -529,8 +535,9 @@
   void _assertContextOfFolder(
       AnalysisContext context, String expectedFolderPath) {
     Folder expectedFolder = resourceProvider.newFolder(expectedFolderPath);
-    ContextInfo expectedContextInfo = (server.contextManager
-        as ContextManagerImpl).getContextInfoFor(expectedFolder);
+    ContextInfo expectedContextInfo =
+        (server.contextManager as ContextManagerImpl)
+            .getContextInfoFor(expectedFolder);
     expect(expectedContextInfo, isNotNull);
     expect(context, same(expectedContextInfo.context));
   }
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index f6eff47..1472027 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -14,9 +14,11 @@
 import 'package:analyzer/source/error_processor.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/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';
@@ -71,6 +73,8 @@
 
   UriResolver packageResolver = null;
 
+  UriResolver embeddedUriResolver = null;
+
   String projPath = '/my/proj';
 
   AnalysisError missing_return =
@@ -89,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);
 
@@ -126,16 +142,22 @@
     manager.processPlugins(plugins);
   }
 
-  UriResolver providePackageResolver(Folder folder) {
-    return packageResolver;
-  }
+  UriResolver provideEmbeddedUriResolver(Folder folder) => embeddedUriResolver;
+
+  UriResolver providePackageResolver(Folder folder) => packageResolver;
 
   void setUp() {
     processRequiredPlugins();
     resourceProvider = new MemoryResourceProvider();
     packageMapProvider = new MockPackageMapProvider();
-    manager = new ContextManagerImpl(resourceProvider, providePackageResolver,
-        packageMapProvider, InstrumentationService.NULL_SERVICE);
+    manager = new ContextManagerImpl(
+        resourceProvider,
+        providePackageResolver,
+        provideEmbeddedUriResolver,
+        packageMapProvider,
+        analysisFilesGlobs,
+        InstrumentationService.NULL_SERVICE,
+        new AnalysisOptionsImpl());
     callbacks = new TestContextManagerCallbacks(resourceProvider);
     manager.callbacks = callbacks;
     resourceProvider.newFolder(projPath);
@@ -146,7 +168,7 @@
     newFile(
         [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
         r'''
-embedder_libs:
+embedded_libs:
   "dart:foobar": "../sdk_ext/entry.dart"
 analyzer:
   language:
@@ -279,6 +301,59 @@
     expect(contexts, contains(subProjContextInfo.context));
   }
 
+  test_embedder_added() async {
+    // Create files.
+    String libPath = newFolder([projPath, LIB_NAME]);
+    newFile([libPath, 'main.dart']);
+    newFile([libPath, 'nope.dart']);
+    String embedderPath = newFolder([projPath, 'embedder']);
+    newFile([embedderPath, 'entry.dart']);
+    String embedderSrcPath = newFolder([projPath, 'embedder', 'src']);
+    newFile([embedderSrcPath, 'part.dart']);
+
+    // Setup _embedder.yaml.
+    newFile(
+        [libPath, '_embedder.yaml'],
+        r'''
+embedded_libs:
+  "dart:foobar": "../embedder/entry.dart"
+  "dart:typed_data": "../embedder/src/part"
+  ''');
+
+    Folder projectFolder = resourceProvider.newFolder(projPath);
+
+    // NOTE that this is Not in our package path yet.
+
+    // Setup context.
+    manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+    await pumpEventQueue();
+    // Confirm that one context was created.
+    List<AnalysisContext> contexts =
+        manager.contextsInAnalysisRoot(projectFolder);
+    expect(contexts, isNotNull);
+    expect(contexts, hasLength(1));
+
+    // No embedded libs yet.
+    expect(contexts.first.sourceFactory.forUri('dart:typed_data'), isNull);
+
+    // Add .packages file that introduces a dependency with embedded libs.
+    newFile(
+        [projPath, '.packages'],
+        r'''
+test_pack:lib/''');
+
+    await pumpEventQueue();
+
+    contexts = manager.contextsInAnalysisRoot(projectFolder);
+
+    // Confirm that we still have just one context.
+    expect(contexts, isNotNull);
+    expect(contexts, hasLength(1));
+
+    // Embedded lib should be defined now.
+    expect(contexts.first.sourceFactory.forUri('dart:typed_data'), isNotNull);
+  }
+
   test_embedder_options() async {
     // Create files.
     String libPath = newFolder([projPath, LIB_NAME]);
@@ -289,7 +364,7 @@
     newFile(
         [libPath, '_embedder.yaml'],
         r'''
-embedder_libs:
+embedded_libs:
   "dart:foobar": "../sdk_ext/entry.dart"
 analyzer:
   strong-mode: true
@@ -343,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));
@@ -366,7 +443,8 @@
     // Sanity check embedder libs.
     var source = context.sourceFactory.forUri('dart:foobar');
     expect(source, isNotNull);
-    expect(source.fullName, '/my/proj/sdk_ext/entry.dart');
+    expect(source.fullName,
+        '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
   }
 
   test_embedder_packagespec() async {
@@ -382,7 +460,7 @@
     newFile(
         [libPath, '_embedder.yaml'],
         r'''
-embedder_libs:
+embedded_libs:
   "dart:foobar": "../sdk_ext/entry.dart"
   "dart:typed_data": "../sdk_ext/src/part"
   ''');
@@ -403,12 +481,13 @@
     var context = contexts[0];
     var source = context.sourceFactory.forUri('dart:foobar');
     expect(source, isNotNull);
-    expect(source.fullName, equals('/my/proj/sdk_ext/entry.dart'));
+    expect(source.fullName,
+        '/my/proj/sdk_ext/entry.dart'.replaceAll('/', JavaFile.separator));
     // We can't find dart:core because we didn't list it in our
-    // embedder_libs map.
+    // embedded_libs map.
     expect(context.sourceFactory.forUri('dart:core'), isNull);
     // We can find dart:typed_data because we listed it in our
-    // embedder_libs map.
+    // embedded_libs map.
     expect(context.sourceFactory.forUri('dart:typed_data'), isNotNull);
   }
 
@@ -594,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 {
@@ -1289,8 +1370,8 @@
   exclude:
     - 'example'
 ''');
-    manager.setRoots(
-        <String>[project, example], <String>[], <String, String>{});
+    manager
+        .setRoots(<String>[project, example], <String>[], <String, String>{});
     // verify
     {
       ContextInfo rootInfo = manager.rootInfo;
@@ -1353,8 +1434,8 @@
     // create files
     resourceProvider.newFile(projectPubspec, 'name: project');
     resourceProvider.newFile(examplePubspec, 'name: example');
-    manager.setRoots(
-        <String>[example, project], <String>[], <String, String>{});
+    manager
+        .setRoots(<String>[example, project], <String>[], <String, String>{});
     // verify
     {
       ContextInfo rootInfo = manager.rootInfo;
@@ -1381,8 +1462,8 @@
     // create files
     resourceProvider.newFile(projectPubspec, 'name: project');
     resourceProvider.newFolder(example);
-    manager.setRoots(
-        <String>[project, example], <String>[], <String, String>{});
+    manager
+        .setRoots(<String>[project, example], <String>[], <String, String>{});
     // verify
     {
       ContextInfo rootInfo = manager.rootInfo;
@@ -1405,8 +1486,8 @@
     // create files
     resourceProvider.newFile(projectPubspec, 'name: project');
     resourceProvider.newFile(examplePubspec, 'name: example');
-    manager.setRoots(
-        <String>[project, example], <String>[], <String, String>{});
+    manager
+        .setRoots(<String>[project, example], <String>[], <String, String>{});
     // verify
     {
       ContextInfo rootInfo = manager.rootInfo;
@@ -1552,8 +1633,8 @@
     resourceProvider.newFile(subProjectA_file, '// sub-a');
     resourceProvider.newFile(subProjectB_file, '// sub-b');
     // set roots
-    manager.setRoots(
-        <String>[projectA, projectB], <String>[], <String, String>{});
+    manager
+        .setRoots(<String>[projectA, projectB], <String>[], <String, String>{});
     callbacks
         .assertContextPaths([projectA, subProjectA, projectB, subProjectB]);
     callbacks.assertContextFiles(projectA, [projectA_file]);
@@ -1600,8 +1681,8 @@
     resourceProvider.newFile(subProjectA_file, '// sub-a');
     resourceProvider.newFile(subProjectB_file, '// sub-b');
     // set roots
-    manager.setRoots(
-        <String>[projectA, projectB], <String>[], <String, String>{});
+    manager
+        .setRoots(<String>[projectA, projectB], <String>[], <String, String>{});
     callbacks
         .assertContextPaths([projectA, subProjectA, projectB, subProjectB]);
     callbacks.assertContextFiles(projectA, [projectA_file]);
@@ -2301,7 +2382,8 @@
   Iterable<String> get currentContextPaths => currentContextTimestamps.keys;
 
   @override
-  AnalysisContext addContext(Folder folder, FolderDisposition disposition) {
+  AnalysisContext addContext(
+      Folder folder, AnalysisOptions options, FolderDisposition disposition) {
     String path = folder.path;
     expect(currentContextPaths, isNot(contains(path)));
     currentContextTimestamps[path] = now;
@@ -2324,6 +2406,7 @@
     }
     resolvers.addAll(disposition.createPackageUriResolvers(resourceProvider));
     resolvers.add(new FileUriResolver());
+    currentContext.analysisOptions = options;
     currentContext.sourceFactory =
         new SourceFactory(resolvers, disposition.packages);
     return currentContext;
@@ -2362,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));
@@ -2372,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_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index b7f4b34..f8c0afd 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -47,7 +47,7 @@
         null,
         serverPlugin,
         new AnalysisServerOptions(),
-        new MockSdk(),
+        () => new MockSdk(),
         InstrumentationService.NULL_SERVICE);
     handler = new AnalysisDomainHandler(server);
   });
@@ -474,7 +474,7 @@
         null,
         serverPlugin,
         new AnalysisServerOptions(),
-        new MockSdk(),
+        () => new MockSdk(),
         InstrumentationService.NULL_SERVICE);
     handler = new AnalysisDomainHandler(server);
     // listen for notifications
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index acff007..61734b6 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -17,6 +17,7 @@
 
 import 'analysis_abstract.dart';
 import 'domain_completion_util.dart';
+import 'mocks.dart' show pumpEventQueue;
 import 'utils.dart';
 
 main() {
@@ -53,6 +54,76 @@
     });
   }
 
+  test_imports_aborted_new_request() async {
+    addTestFile('''
+        class foo { }
+        c^''');
+
+    // Make a request for suggestions
+    Request request =
+        new CompletionGetSuggestionsParams(testFile, completionOffset)
+            .toRequest('7');
+    Response response = handleSuccessfulRequest(request);
+    var result1 = new CompletionGetSuggestionsResult.fromResponse(response);
+    var completionId1 = result1.id;
+    assertValidId(response.id);
+
+    // Perform some analysis but assert that no suggestions have yet been made
+    completionId = completionId1;
+    await pumpEventQueue(25);
+    expect(suggestionsDone, isFalse);
+    expect(suggestions, hasLength(0));
+
+    // Make another request before the first request completes
+    Request request2 =
+        new CompletionGetSuggestionsParams(testFile, completionOffset)
+            .toRequest('8');
+    Response response2 = handleSuccessfulRequest(request2);
+    var result2 = new CompletionGetSuggestionsResult.fromResponse(response2);
+    var completionId2 = result2.id;
+    assertValidId(completionId2);
+
+    // Wait for both sets of suggestions
+    completionId = completionId2;
+    await pumpEventQueue();
+    expect(allSuggestions[completionId1], hasLength(0));
+    expect(allSuggestions[completionId2], same(suggestions));
+    assertHasResult(CompletionSuggestionKind.KEYWORD, 'class',
+        relevance: DART_RELEVANCE_HIGH);
+  }
+
+  test_imports_aborted_source_changed() async {
+    addTestFile('''
+        class foo { }
+        c^''');
+
+    // Make a request for suggestions
+    Request request =
+        new CompletionGetSuggestionsParams(testFile, completionOffset)
+            .toRequest('0');
+    Response response = handleSuccessfulRequest(request);
+    completionId = response.id;
+    assertValidId(completionId);
+
+    // Perform some analysis but assert that no suggestions have yet been made
+    await pumpEventQueue(25);
+    expect(suggestionsDone, isFalse);
+    expect(suggestions, hasLength(0));
+
+    // Simulate user deleting text after request but before suggestions returned
+    server.updateContent('uc1', {testFile: new AddContentOverlay(testCode)});
+    server.updateContent('uc2', {
+      testFile: new ChangeContentOverlay(
+          [new SourceEdit(completionOffset - 1, 1, '')])
+    });
+
+    // Expect the completion domain to discard request because source changed
+    await pumpEventQueue().then((_) {
+      expect(suggestionsDone, isTrue);
+    });
+    expect(suggestions, hasLength(0));
+  }
+
   test_imports_incremental() async {
     addTestFile('''library foo;
       e^
diff --git a/pkg/analysis_server/test/domain_completion_util.dart b/pkg/analysis_server/test/domain_completion_util.dart
index 29cff99..7c4ed6c 100644
--- a/pkg/analysis_server/test/domain_completion_util.dart
+++ b/pkg/analysis_server/test/domain_completion_util.dart
@@ -24,6 +24,7 @@
   int replacementLength;
   List<CompletionSuggestion> suggestions = [];
   bool suggestionsDone = false;
+  Map<String,List<CompletionSuggestion>> allSuggestions = {};
 
   String addTestFile(String content, {int offset}) {
     completionOffset = content.indexOf('^');
@@ -109,6 +110,7 @@
         expect(suggestionsDone, isNotNull);
         suggestions = params.results;
       }
+      allSuggestions[id] = params.results;
     } else if (notification.event == SERVER_ERROR) {
       fail('server error: ${notification.toJson()}');
     }
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index f234463..277279a 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -53,7 +53,7 @@
         null,
         serverPlugin,
         new AnalysisServerOptions(),
-        new MockSdk(),
+        () => new MockSdk(),
         InstrumentationService.NULL_SERVICE);
     handler = new DiagnosticDomainHandler(server);
   });
@@ -71,14 +71,15 @@
       var request = new DiagnosticGetDiagnosticsParams().toRequest('0');
       var response = handler.handleRequest(request);
 
-      int fileCount = MockSdk.LIBRARIES.length + 1 /* test.dart */;
+      int fileCount = 1 /* test.dart */;
 
       var json = response.toJson()[Response.RESULT];
       expect(json['contexts'], hasLength(1));
       var context = json['contexts'][0];
       expect(context['name'], '/project');
       expect(context['explicitFileCount'], fileCount);
-      expect(context['implicitFileCount'], 0);
+      // dart:core dart:async dart:math dart:_internal
+      expect(context['implicitFileCount'], 4);
       expect(context['workItemQueueLength'], isNotNull);
     });
 
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index a142adb..e6d1dfb 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -48,7 +48,7 @@
           null,
           serverPlugin,
           new AnalysisServerOptions(),
-          new MockSdk(),
+          () => new MockSdk(),
           InstrumentationService.NULL_SERVICE);
       handler = new ExecutionDomainHandler(server);
     });
@@ -124,8 +124,9 @@
 
       group('file to URI', () {
         test('does not exist', () {
-          Request request = new ExecutionMapUriParams(contextId,
-              file: '/a/c.dart').toRequest('2');
+          Request request =
+              new ExecutionMapUriParams(contextId, file: '/a/c.dart')
+                  .toRequest('2');
           Response response = handler.handleRequest(request);
           expect(response, isResponseFailure('2'));
         });
@@ -141,8 +142,9 @@
 
       group('URI to file', () {
         test('invalid', () {
-          Request request = new ExecutionMapUriParams(contextId,
-              uri: 'foo:///a/b.dart').toRequest('2');
+          Request request =
+              new ExecutionMapUriParams(contextId, uri: 'foo:///a/b.dart')
+                  .toRequest('2');
           Response response = handler.handleRequest(request);
           expect(response, isResponseFailure('2'));
         });
@@ -221,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);
@@ -299,7 +301,7 @@
   }
 
   void test_mapUri_file_dartUriKind() {
-    String path = server.defaultSdk.mapDartUri('dart:async').fullName;
+    String path = server.findSdk().mapDartUri('dart:async').fullName;
     // hack - pretend that the SDK file exists in the project FS
     resourceProvider.newFile(path, '// hack');
     // map file
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 51237cd..6dc24d1 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -37,7 +37,7 @@
         null,
         serverPlugin,
         new AnalysisServerOptions(),
-        new MockSdk(),
+        () => new MockSdk(),
         InstrumentationService.NULL_SERVICE);
     handler = new ServerDomainHandler(server);
   });
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index af165f2..2508d56 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -429,13 +429,20 @@
    *
    * packageRoots ( optional Map<FilePath, FilePath> )
    *
-   *   A mapping from source directories to target directories that should
-   *   override the normal package: URI resolution mechanism. The analyzer will
-   *   behave as though each source directory in the map contains a special
+   *   A mapping from source directories to package roots that should override
+   *   the normal package: URI resolution mechanism.
+   *
+   *   If a package root is a directory, then the analyzer will behave as
+   *   though the associated source directory in the map contains a special
    *   pubspec.yaml file which resolves any package: URI to the corresponding
-   *   path within the target directory. The effect is the same as specifying
-   *   the target directory as a "--package_root" parameter to the Dart VM when
-   *   executing any Dart file inside the source directory.
+   *   path within that package root directory. The effect is the same as
+   *   specifying the package root directory as a "--package_root" parameter to
+   *   the Dart VM when executing any Dart file inside the source directory.
+   *
+   *   If a package root is a file, then the analyzer will behave as though
+   *   that file is a ".packages" file in the source directory. The effect is
+   *   the same as specifying the file as a "--packages" parameter to the Dart
+   *   VM when executing any Dart file inside the source directory.
    *
    *   Files in any directories that are not overridden by this mapping have
    *   their package: URI's resolved using the normal pubspec.yaml mechanism.
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index f05a775..5361816 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -174,7 +174,7 @@
     // doesn't exit, then forcibly terminate it.
     sendServerShutdown();
     return server.exitCode.timeout(SHUTDOWN_TIMEOUT, onTimeout: () {
-      return server.kill();
+      return server.kill('server failed to exit');
     });
   }
 
@@ -491,9 +491,9 @@
   /**
    * Stop the server.
    */
-  Future kill() {
+  Future kill(String reason) {
     debugStdio();
-    _recordStdio('PROCESS FORCIBLY TERMINATED');
+    _recordStdio('FORCIBLY TERMINATING PROCESS: $reason');
     _process.kill();
     return _process.exitCode;
   }
@@ -514,7 +514,7 @@
       try {
         message = JSON.decoder.convert(trimmedLine);
       } catch (exception) {
-        _badDataFromServer();
+        _badDataFromServer('JSON decode failure: $exception');
         return;
       }
       expect(message, isMap);
@@ -557,7 +557,7 @@
         .listen((String line) {
       String trimmedLine = line.trim();
       _recordStdio('ERR:  $trimmedLine');
-      _badDataFromServer();
+      _badDataFromServer('Message received on stderr', silent: true);
     });
   }
 
@@ -630,9 +630,8 @@
     return Process.start(dartBinary, arguments).then((Process process) {
       _process = process;
       process.exitCode.then((int code) {
-        _recordStdio('TERMINATED WITH EXIT CODE $code');
         if (code != 0) {
-          _badDataFromServer();
+          _badDataFromServer('server terminated with exit code $code');
         }
       });
     });
@@ -641,7 +640,10 @@
   /**
    * Deal with bad data received from the server.
    */
-  void _badDataFromServer() {
+  void _badDataFromServer(String details, {bool silent: false}) {
+    if (!silent) {
+      _recordStdio('BAD DATA FROM SERVER: $details');
+    }
     if (_receivedBadDataFromServer) {
       // We're already dealing with it.
       return;
@@ -654,7 +656,7 @@
     // entire stacktrace.  Use expectAsync() to prevent the test from
     // ending during this 1 second.
     new Future.delayed(new Duration(seconds: 1), expectAsync(() {
-      fail('Bad data received from server');
+      fail('Bad data received from server: $details');
     }));
   }
 
diff --git a/pkg/analysis_server/test/mock_sdk.dart b/pkg/analysis_server/test/mock_sdk.dart
index 1fbb426..c43ef63 100644
--- a/pkg/analysis_server/test/mock_sdk.dart
+++ b/pkg/analysis_server/test/mock_sdk.dart
@@ -222,12 +222,6 @@
       _analysisContext = new SdkAnalysisContext();
       SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
       _analysisContext.sourceFactory = factory;
-      ChangeSet changeSet = new ChangeSet();
-      for (String uri in uris) {
-        Source source = factory.forUri(uri);
-        changeSet.addedSource(source);
-      }
-      _analysisContext.applyChanges(changeSet);
     }
     return _analysisContext;
   }
diff --git a/pkg/analysis_server/test/search/type_hierarchy_test.dart b/pkg/analysis_server/test/search/type_hierarchy_test.dart
index 1d6ddf9a..c8b62dd 100644
--- a/pkg/analysis_server/test/search/type_hierarchy_test.dart
+++ b/pkg/analysis_server/test/search/type_hierarchy_test.dart
@@ -186,8 +186,9 @@
 class C extends A {}
 ''');
     // configure roots
-    Request request = new AnalysisSetAnalysisRootsParams(
-        [projectPath, '/packages/pkgA'], []).toRequest('0');
+    Request request =
+        new AnalysisSetAnalysisRootsParams([projectPath, '/packages/pkgA'], [])
+            .toRequest('0');
     handleSuccessfulRequest(request);
     // test A type hierarchy
     List<TypeHierarchyItem> items = await _getTypeHierarchy('A {}');
@@ -699,6 +700,66 @@
         itemD.memberElement.location.offset, findOffset('test() {} // in D'));
   }
 
+  test_member_method_private_differentLib() async {
+    addFile(
+        '$testFolder/lib.dart',
+        r'''
+import 'test.dart';
+class A {
+  void _m() {}
+}
+class C extends B {
+  void _m() {}
+}
+''');
+    addTestFile('''
+import 'lib.dart';
+class B extends A {
+  _m() {} // in B
+}
+class D extends C {
+  _m() {} // in D
+}
+''');
+    List<TypeHierarchyItem> items = await _getTypeHierarchy('_m() {} // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass];
+    var itemC = items[itemB.subclasses[0]];
+    var itemD = items[itemC.subclasses[0]];
+    expect(itemB.classElement.name, 'B');
+    expect(itemA.classElement.name, 'A');
+    expect(itemC.classElement.name, 'C');
+    expect(itemD.classElement.name, 'D');
+    expect(itemA.memberElement, isNull);
+    expect(itemC.memberElement, isNull);
+    expect(itemB.memberElement, isNotNull);
+    expect(itemD.memberElement, isNotNull);
+  }
+
+  test_member_method_private_sameLib() async {
+    addTestFile('''
+class A {
+  _m() {} // in A
+}
+class B extends A {
+  _m() {} // in B
+}
+class C extends B {
+  _m() {} // in C
+}
+''');
+    List<TypeHierarchyItem> items = await _getTypeHierarchy('_m() {} // in B');
+    var itemB = items[0];
+    var itemA = items[itemB.superclass];
+    var itemC = items[itemB.subclasses[0]];
+    expect(itemA.classElement.name, 'A');
+    expect(itemB.classElement.name, 'B');
+    expect(itemC.classElement.name, 'C');
+    expect(itemA.memberElement.location.offset, findOffset('_m() {} // in A'));
+    expect(itemB.memberElement.location.offset, findOffset('_m() {} // in B'));
+    expect(itemC.memberElement.location.offset, findOffset('_m() {} // in C'));
+  }
+
   test_member_ofMixin2_method() async {
     addTestFile('''
 class M1 {
@@ -963,8 +1024,9 @@
 
   test_superOnly_fileDoesNotExist() async {
     Request request = new SearchGetTypeHierarchyParams(
-        '/does/not/exist.dart', 0,
-        superOnly: true).toRequest(requestId);
+            '/does/not/exist.dart', 0,
+            superOnly: true)
+        .toRequest(requestId);
     Response response = await serverChannel.sendRequest(request);
     List<TypeHierarchyItem> items =
         new SearchGetTypeHierarchyResult.fromResponse(response).hierarchyItems;
@@ -973,7 +1035,8 @@
 
   Request _createGetTypeHierarchyRequest(String search, {bool superOnly}) {
     return new SearchGetTypeHierarchyParams(testFile, findOffset(search),
-        superOnly: superOnly).toRequest(requestId);
+            superOnly: superOnly)
+        .toRequest(requestId);
   }
 
   Future<List<TypeHierarchyItem>> _getTypeHierarchy(String search,
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index 28c6a09..8ecfc8f 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -436,6 +436,7 @@
   }
 
   Future computeSuggestions([int times = 200]) async {
+    context.analysisPriorityOrder = [testSource];
     CompletionRequestImpl baseRequest = new CompletionRequestImpl(
         context,
         provider,
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart b/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
new file mode 100644
index 0000000..fa43aa1
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/completion_manager_test.dart
@@ -0,0 +1,106 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart.manager;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/completion_core.dart';
+import 'package:analysis_server/src/services/completion/completion_performance.dart';
+import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
+import 'package:analysis_server/src/services/completion/dart/imported_reference_contributor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+main() {
+  initializeTestEnvironment();
+  defineReflectiveTests(CompletionManagerTest);
+}
+
+@reflectiveTest
+class CompletionManagerTest extends DartCompletionContributorTest {
+  @override
+  DartCompletionContributor createContributor() {
+    return new ImportedReferenceContributor();
+  }
+
+  test_resolveDirectives() async {
+    addSource(
+        '/libA.dart',
+        '''
+library libA;
+/// My class.
+/// Short description.
+///
+/// Longer description.
+class A {}
+''');
+    var libSource = addSource(
+        '/libB.dart',
+        '''
+library libB;
+import "/libA.dart" as foo;
+part '$testFile';
+''');
+    addTestSource('part of libB; main() {^}');
+
+    // Associate part with library
+    context.computeResult(
+        new LibrarySpecificUnit(libSource, testSource), LIBRARY_CYCLE_UNITS);
+
+    // Build the request
+    CompletionRequestImpl baseRequest = new CompletionRequestImpl(
+        context,
+        provider,
+        searchEngine,
+        testSource,
+        completionOffset,
+        new CompletionPerformance());
+    Completer<DartCompletionRequest> requestCompleter =
+        new Completer<DartCompletionRequest>();
+    DartCompletionRequestImpl
+        .from(baseRequest, resultDescriptor: RESOLVED_UNIT1)
+        .then((DartCompletionRequest request) {
+      requestCompleter.complete(request);
+    });
+    request = await performAnalysis(200, requestCompleter);
+
+    // Get the unresolved directives
+    var directives = request.target.unit.directives;
+
+    // Assert that the import does not have an export namespace
+    expect(directives[0].element?.library?.exportNamespace, isNull);
+
+    // Resolve directives
+    var importCompleter = new Completer<List<ImportElement>>();
+    request.resolveImports().then((List<ImportElement> elements) {
+      importCompleter.complete(elements);
+    });
+    List<ImportElement> imports = await performAnalysis(200, importCompleter);
+    expect(imports, hasLength(directives.length + 1));
+
+    ImportElement importNamed(String expectedUri) {
+      return imports.firstWhere((elem) => elem.uri == expectedUri, orElse: () {
+        var importedNames = imports.map((elem) => elem.uri);
+        fail('Failed to find $expectedUri in $importedNames');
+      });
+    }
+    void assertImportedLib(String expectedUri) {
+      ImportElement importElem = importNamed(expectedUri);
+      expect(importElem.importedLibrary.exportNamespace, isNotNull);
+    }
+
+    // Assert that the new imports each have an export namespace
+    assertImportedLib(null /* dart:core */);
+    assertImportedLib('/libA.dart');
+  }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index 167e3ab..73642ea 100644
--- a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -7,7 +7,7 @@
 import 'package:analysis_server/plugin/protocol/protocol.dart';
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
@@ -269,6 +269,11 @@
     }
   }
 
+  @override
+  DartCompletionContributor createContributor() {
+    return new KeywordContributor();
+  }
+
   fail_import_partial() async {
     addTestSource('imp^ import "package:foo/foo.dart"; import "bar.dart";');
     await computeSuggestions();
@@ -298,11 +303,6 @@
     assertNotSuggested('class');
   }
 
-  @override
-  DartCompletionContributor createContributor() {
-    return new KeywordContributor();
-  }
-
   test_after_class() async {
     addTestSource('class A {} ^');
     await computeSuggestions();
@@ -1238,13 +1238,6 @@
     assertSuggestKeywords(STMT_START_IN_CLASS, pseudoKeywords: ['await']);
   }
 
-  test_method_body_async_star() async {
-    addTestSource('class A { foo() async* {^}}');
-    await computeSuggestions();
-    assertSuggestKeywords(STMT_START_IN_CLASS,
-        pseudoKeywords: ['await', 'yield', 'yield*']);
-  }
-
   test_method_body_async2() async {
     addTestSource('class A { foo() async => ^}');
     await computeSuggestions();
@@ -1263,6 +1256,13 @@
     assertSuggestKeywords(EXPRESSION_START_INSTANCE, pseudoKeywords: ['await']);
   }
 
+  test_method_body_async_star() async {
+    addTestSource('class A { foo() async* {^}}');
+    await computeSuggestions();
+    assertSuggestKeywords(STMT_START_IN_CLASS,
+        pseudoKeywords: ['await', 'yield', 'yield*']);
+  }
+
   test_method_body_expression1() async {
     addTestSource('class A { foo() {return b == true ? ^}}');
     await computeSuggestions();
diff --git a/pkg/analysis_server/test/services/completion/dart/local_declaration_visitor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_declaration_visitor_test.dart
index f70f720f..5765c68 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_declaration_visitor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_declaration_visitor_test.dart
@@ -5,10 +5,12 @@
 library test.services.completion.local_declaration_visitor_test;
 
 import 'package:analysis_server/src/services/completion/dart/local_declaration_visitor.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analysis_server/test/services/completion/dart/optype_test.dart b/pkg/analysis_server/test/services/completion/dart/optype_test.dart
index 9ed569e..bc7da40 100644
--- a/pkg/analysis_server/test/services/completion/dart/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/optype_test.dart
@@ -1472,6 +1472,9 @@
   _TestSource(this.fullName);
 
   @override
+  String get encoding => fullName;
+
+  @override
   bool get isInSystemLibrary => false;
 
   @override
diff --git a/pkg/analysis_server/test/services/completion/dart/test_all.dart b/pkg/analysis_server/test/services/completion/dart/test_all.dart
index c12f8de..b936392 100644
--- a/pkg/analysis_server/test/services/completion/dart/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/test_all.dart
@@ -9,6 +9,7 @@
 import '../../../utils.dart';
 import 'arglist_contributor_test.dart' as arglist_test;
 import 'combinator_contributor_test.dart' as combinator_test;
+import 'completion_manager_test.dart' as completion_manager;
 import 'common_usage_sorter_test.dart' as common_usage_test;
 import 'field_formal_contributor_test.dart' as field_formal_contributor_test;
 import 'imported_reference_contributor_test.dart' as imported_ref_test;
@@ -34,6 +35,7 @@
   group('dart/completion', () {
     arglist_test.main();
     combinator_test.main();
+    completion_manager.main();
     common_usage_test.main();
     field_formal_contributor_test.main();
     imported_ref_test.main();
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index ed3d7d3..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 {}
@@ -2379,6 +2356,15 @@
     await assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
   }
 
+  test_introduceLocalTestedType_BAD_notStatement() async {
+    resolveTestUnit('''
+class C {
+  bool b;
+  C(v) : b = v is int;
+}''');
+    await assertNoAssistAt('is int', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
+  }
+
   test_introduceLocalTestedType_OK_if_is() async {
     resolveTestUnit('''
 class MyTypeName {}
@@ -3274,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() {
@@ -3322,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 7ce9b90..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 {
@@ -349,6 +426,27 @@
 ''');
   }
 
+  test_addSync_asyncFor() async {
+    resolveTestUnit('''
+import 'dart:async';
+void main(Stream<String> names) {
+  await for (String name in names) {
+    print(name);
+  }
+}
+''');
+    await assertHasFix(
+        DartFixKind.ADD_ASYNC,
+        '''
+import 'dart:async';
+Future main(Stream<String> names) async {
+  await for (String name in names) {
+    print(name);
+  }
+}
+''');
+  }
+
   test_addSync_BAD_nullFunctionBody() async {
     resolveTestUnit('''
 var F = await;
@@ -412,6 +510,98 @@
 ''');
   }
 
+  test_addSync_returnFuture() async {
+    errorFilter = (AnalysisError error) {
+      return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+    };
+    resolveTestUnit('''
+foo() {}
+int main() {
+  await foo();
+  return 42;
+}
+''');
+    await assertHasFix(
+        DartFixKind.ADD_ASYNC,
+        '''
+import 'dart:async';
+
+foo() {}
+Future<int> main() async {
+  await foo();
+  return 42;
+}
+''');
+  }
+
+  test_addSync_returnFuture_alreadyFuture() async {
+    errorFilter = (AnalysisError error) {
+      return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+    };
+    resolveTestUnit('''
+import 'dart:async';
+foo() {}
+Future<int> main() {
+  await foo();
+  return 42;
+}
+''');
+    await assertHasFix(
+        DartFixKind.ADD_ASYNC,
+        '''
+import 'dart:async';
+foo() {}
+Future<int> main() async {
+  await foo();
+  return 42;
+}
+''');
+  }
+
+  test_addSync_returnFuture_dynamic() async {
+    errorFilter = (AnalysisError error) {
+      return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+    };
+    resolveTestUnit('''
+foo() {}
+dynamic main() {
+  await foo();
+  return 42;
+}
+''');
+    await assertHasFix(
+        DartFixKind.ADD_ASYNC,
+        '''
+foo() {}
+dynamic main() async {
+  await foo();
+  return 42;
+}
+''');
+  }
+
+  test_addSync_returnFuture_noType() async {
+    errorFilter = (AnalysisError error) {
+      return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+    };
+    resolveTestUnit('''
+foo() {}
+main() {
+  await foo();
+  return 42;
+}
+''');
+    await assertHasFix(
+        DartFixKind.ADD_ASYNC,
+        '''
+foo() {}
+main() async {
+  await foo();
+  return 42;
+}
+''');
+  }
+
   test_boolean() async {
     resolveTestUnit('''
 main() {
@@ -2014,6 +2204,29 @@
 ''');
   }
 
+  test_createMissingOverrides_field_untyped() async {
+    resolveTestUnit('''
+class A {
+  var f;
+}
+
+class B implements A {
+}
+''');
+    await assertHasFix(
+        DartFixKind.CREATE_MISSING_OVERRIDES,
+        '''
+class A {
+  var f;
+}
+
+class B implements A {
+  @override
+  var f;
+}
+''');
+  }
+
   test_createMissingOverrides_functionTypeAlias() async {
     resolveTestUnit('''
 typedef int Binary(int left, int right);
@@ -2201,8 +2414,10 @@
 }
 
 class B implements A {
+  @override
   int ma;
 
+  @override
   double mc;
 
   @override
@@ -3647,6 +3862,32 @@
 ''');
   }
 
+  test_undefinedFunction_create_duplicateArgumentNames() async {
+    resolveTestUnit('''
+class C {
+  int x;
+}
+
+foo(C c1, C c2) {
+  bar(c1.x, c2.x);
+}
+''');
+    await assertHasFix(
+        DartFixKind.CREATE_FUNCTION,
+        '''
+class C {
+  int x;
+}
+
+foo(C c1, C c2) {
+  bar(c1.x, c2.x);
+}
+
+void bar(int x, int x2) {
+}
+''');
+  }
+
   test_undefinedFunction_create_dynamicArgument() async {
     resolveTestUnit('''
 main() {
@@ -3771,6 +4012,11 @@
 void process(List<int> items) {
 }
 ''');
+    _assertLinkedGroup(
+        change.linkedEditGroups[2],
+        ['List<int> items) {'],
+        expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+            ['List<int>', 'Iterable<int>', 'Object']));
   }
 
   test_undefinedFunction_create_importType() async {
@@ -4293,6 +4539,34 @@
     await assertNoFix(DartFixKind.CREATE_METHOD);
   }
 
+  test_undefinedMethod_createUnqualified_duplicateArgumentNames() async {
+    resolveTestUnit('''
+class C {
+  int x;
+}
+
+class D {
+  foo(C c1, C c2) {
+    bar(c1.x, c2.x);
+  }
+}''');
+    await assertHasFix(
+        DartFixKind.CREATE_METHOD,
+        '''
+class C {
+  int x;
+}
+
+class D {
+  foo(C c1, C c2) {
+    bar(c1.x, c2.x);
+  }
+
+  void bar(int x, int x2) {
+  }
+}''');
+  }
+
   test_undefinedMethod_createUnqualified_parameters() async {
     resolveTestUnit('''
 class A {
@@ -4323,19 +4597,19 @@
         change.linkedEditGroups[index++],
         ['int i'],
         expectedSuggestions(LinkedEditSuggestionKind.TYPE,
-            ['int', 'num', 'Object', 'Comparable']));
+            ['int', 'num', 'Object', 'Comparable<num>']));
     _assertLinkedGroup(change.linkedEditGroups[index++], ['i,']);
     _assertLinkedGroup(
         change.linkedEditGroups[index++],
         ['double d'],
         expectedSuggestions(LinkedEditSuggestionKind.TYPE,
-            ['double', 'num', 'Object', 'Comparable']));
+            ['double', 'num', 'Object', 'Comparable<num>']));
     _assertLinkedGroup(change.linkedEditGroups[index++], ['d,']);
     _assertLinkedGroup(
         change.linkedEditGroups[index++],
         ['String s'],
-        expectedSuggestions(
-            LinkedEditSuggestionKind.TYPE, ['String', 'Object', 'Comparable']));
+        expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+            ['String', 'Object', 'Comparable<String>']));
     _assertLinkedGroup(change.linkedEditGroups[index++], ['s)']);
   }
 
@@ -4369,18 +4643,18 @@
         change.linkedEditGroups[index++],
         ['int i'],
         expectedSuggestions(LinkedEditSuggestionKind.TYPE,
-            ['int', 'num', 'Object', 'Comparable']));
+            ['int', 'num', 'Object', 'Comparable<num>']));
     _assertLinkedGroup(change.linkedEditGroups[index++], ['i,']);
     _assertLinkedGroup(
         change.linkedEditGroups[index++],
         ['double bbb'],
         expectedSuggestions(LinkedEditSuggestionKind.TYPE,
-            ['double', 'num', 'Object', 'Comparable']));
+            ['double', 'num', 'Object', 'Comparable<num>']));
     _assertLinkedGroup(
         change.linkedEditGroups[index++],
         ['String ccc'],
-        expectedSuggestions(
-            LinkedEditSuggestionKind.TYPE, ['String', 'Object', 'Comparable']));
+        expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+            ['String', 'Object', 'Comparable<String>']));
   }
 
   test_undefinedMethod_createUnqualified_returnType() async {
@@ -4749,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/analysis_server/test/services/refactoring/extract_method_test.dart b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
index ff3b3b0..2a5e7e4 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
@@ -175,9 +175,9 @@
   test_bad_doWhile_body() {
     indexTestUnit('''
 main() {
-  do 
+  do
 // start
-  { 
+  {
   }
 // end
   while (true);
@@ -204,10 +204,10 @@
   test_bad_forLoop_conditionAndUpdaters() {
     indexTestUnit('''
 main() {
-  for ( 
+  for (
     int i = 0;
 // start
-    i < 10; 
+    i < 10;
     i++
 // end
   ) {}
@@ -221,7 +221,7 @@
   test_bad_forLoop_init() {
     indexTestUnit('''
 main() {
-  for ( 
+  for (
 // start
     int i = 0
 // end
@@ -238,7 +238,7 @@
   test_bad_forLoop_initAndCondition() {
     indexTestUnit('''
 main() {
-  for ( 
+  for (
 // start
     int i = 0;
     i < 10;
@@ -255,7 +255,7 @@
   test_bad_forLoop_updaters() {
     indexTestUnit('''
 main() {
-  for ( 
+  for (
     int i = 0;
     i < 10;
 // start
@@ -272,7 +272,7 @@
   test_bad_forLoop_updatersAndBody() {
     indexTestUnit('''
 main() {
-  for ( 
+  for (
     int i = 0;
     i < 10;
 // start
@@ -349,10 +349,10 @@
   test_bad_notSameParent() {
     indexTestUnit('''
 main() {
-  while (false) 
+  while (false)
 // start
-  { 
-  } 
+  {
+  }
   print(0);
 // end
 }
@@ -507,7 +507,7 @@
   test_bad_switchCase() {
     indexTestUnit('''
 main() {
-  switch (1) { 
+  switch (1) {
 // start
     case 0: break;
 // end
@@ -552,7 +552,7 @@
     indexTestUnit('''
 main() {
   try
-  {} 
+  {}
   catch (e)
 // start
   {}
@@ -569,7 +569,7 @@
     indexTestUnit('''
 main() {
   try
-  {} 
+  {}
 // start
   catch (e)
   {}
@@ -586,7 +586,7 @@
     indexTestUnit('''
 main() {
   try {
-  } catch ( 
+  } catch (
 // start
   e
 // end
@@ -603,7 +603,7 @@
     indexTestUnit('''
 main() {
   try
-  {} 
+  {}
   finally
 // start
   {}
@@ -621,7 +621,7 @@
 main() {
   try
 // start
-  {} 
+  {}
 // end
   finally
   {}
@@ -646,7 +646,7 @@
   test_bad_variableDeclarationFragment() {
     indexTestUnit('''
 main() {
-  int 
+  int
 // start
     a = 1
 // end
@@ -661,11 +661,11 @@
   test_bad_while_conditionAndBody() {
     indexTestUnit('''
 main() {
-  while 
+  while
 // start
-    (false) 
-  { 
-  } 
+    (false)
+  {
+  }
 // end
 }
 ''');
@@ -2467,6 +2467,41 @@
 ''');
   }
 
+  test_statements_parameters_localFunction() {
+    _addLibraryReturningAsync();
+    indexTestUnit('''
+class C {
+  int f(int a) {
+    int callback(int x, int y) => x + a;
+    int b = a + 1;
+// start
+    int c = callback(b, 2);
+// end
+    int d = c + 1;
+    return d;
+  }
+}''');
+    _createRefactoringForStartEndComments();
+    // apply refactoring
+    return _assertSuccessfulRefactoring('''
+class C {
+  int f(int a) {
+    int callback(int x, int y) => x + a;
+    int b = a + 1;
+// start
+    int c = res(callback, b);
+// end
+    int d = c + 1;
+    return d;
+  }
+
+  int res(int callback(int x, int y), int b) {
+    int c = callback(b, 2);
+    return c;
+  }
+}''');
+  }
+
   test_statements_parameters_noLocalVariableConflict() async {
     indexTestUnit('''
 int f(int x) {
diff --git a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
index 8ff6c84..3433f1e 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
@@ -917,6 +917,81 @@
 ''');
   }
 
+  test_method_methodInstance() {
+    indexTestUnit(r'''
+class A {
+  ma() {}
+}
+class B extends A {
+  test() {
+    ma();
+    mb();
+  }
+  mb() {}
+}
+main(B b) {
+  b.test();
+}
+''');
+    _createRefactoring('test();');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+class A {
+  ma() {}
+}
+class B extends A {
+  test() {
+    ma();
+    mb();
+  }
+  mb() {}
+}
+main(B b) {
+  b.ma();
+  b.mb();
+}
+''');
+  }
+
+  test_method_methodStatic() {
+    indexTestUnit(r'''
+class A {
+  static ma() {}
+}
+class B extends A {
+  static mb() {}
+  test() {
+    mb();
+    A.ma();
+    B.mb();
+  }
+}
+main(B b) {
+  b.test();
+}
+''');
+    _createRefactoring('test();');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+class A {
+  static ma() {}
+}
+class B extends A {
+  static mb() {}
+  test() {
+    mb();
+    A.ma();
+    B.mb();
+  }
+}
+main(B b) {
+  B.mb();
+  A.ma();
+  B.mb();
+}
+''');
+  }
+
   test_method_singleStatement() {
     indexTestUnit(r'''
 class A {
@@ -973,7 +1048,7 @@
 ''');
   }
 
-  test_method_unqualifiedUnvocation() {
+  test_method_unqualifiedInvocation() {
     indexTestUnit(r'''
 class A {
   test(a, b) {
@@ -1198,6 +1273,36 @@
 ''');
   }
 
+  test_removeEmptyLinesBefore_method() {
+    indexTestUnit(r'''
+class A {
+  before() {
+  }
+
+
+  test() {
+    print(0);
+  }
+
+  foo() {
+    test();
+  }
+}
+''');
+    _createRefactoring('test() {');
+    // validate change
+    return _assertSuccessfulRefactoring(r'''
+class A {
+  before() {
+  }
+
+  foo() {
+    print(0);
+  }
+}
+''');
+  }
+
   test_setter_classMember_instance() {
     indexTestUnit(r'''
 class A {
@@ -1361,7 +1466,7 @@
 ''');
   }
 
-  test_singleExpression_wrapIntoParenthesized_bools() {
+  test_singleExpression_wrapIntoParenthesized_bool() {
     indexTestUnit(r'''
 test(bool a, bool b) {
   return a || b;
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index 2190ee1..1175320 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -12,6 +12,7 @@
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:analysis_server/src/socket_server.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:plugin/manager.dart';
 import 'package:unittest/unittest.dart';
@@ -111,11 +112,15 @@
     ServerPlugin serverPlugin = new ServerPlugin();
     ExtensionManager manager = new ExtensionManager();
     manager.processPlugins([serverPlugin]);
+    SdkCreator sdkCreator = () =>
+        new DirectoryBasedDartSdk(DirectoryBasedDartSdk.defaultSdkDirectory);
     return new SocketServer(
         new AnalysisServerOptions(),
-        DirectoryBasedDartSdk.defaultSdk,
+        sdkCreator,
+        sdkCreator(),
         InstrumentationService.NULL_SERVICE,
         serverPlugin,
+        null,
         null);
   }
 }
diff --git a/pkg/analysis_server/test/stress/replay/replay.dart b/pkg/analysis_server/test/stress/replay/replay.dart
index 159944f..6c56047 100644
--- a/pkg/analysis_server/test/stress/replay/replay.dart
+++ b/pkg/analysis_server/test/stress/replay/replay.dart
@@ -11,9 +11,11 @@
 import 'dart:io';
 
 import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/error.dart' as error;
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/util/glob.dart';
 import 'package:args/args.dart';
diff --git a/pkg/analysis_server/test/timing/timing_framework.dart b/pkg/analysis_server/test/timing/timing_framework.dart
index 757819d..cdf24fe 100644
--- a/pkg/analysis_server/test/timing/timing_framework.dart
+++ b/pkg/analysis_server/test/timing/timing_framework.dart
@@ -312,7 +312,7 @@
     // doesn't exit, then forcibly terminate it.
     sendServerShutdown();
     return server.exitCode.timeout(SHUTDOWN_TIMEOUT, onTimeout: () {
-      return server.kill();
+      return server.kill('server failed to exit');
     });
   }
 }
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index e465571..8fb6d55 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -174,13 +174,17 @@
    * @param included A list of the files and directories that should be analyzed.
    * @param excluded A list of the files and directories within the included directories that should
    *         not be analyzed.
-   * @param packageRoots A mapping from source directories to target directories that should override
-   *         the normal package: URI resolution mechanism. The analyzer will behave as though each
-   *         source directory in the map contains a special pubspec.yaml file which resolves any
-   *         package: URI to the corresponding path within the target directory. The effect is the
-   *         same as specifying the target directory as a "--package_root" parameter to the Dart VM
-   *         when executing any Dart file inside the source directory. Files in any directories that
-   *         are not overridden by this mapping have their package: URI's resolved using the normal
+   * @param packageRoots A mapping from source directories to package roots that should override the
+   *         normal package: URI resolution mechanism. If a package root is a directory, then the
+   *         analyzer will behave as though the associated source directory in the map contains a
+   *         special pubspec.yaml file which resolves any package: URI to the corresponding path
+   *         within that package root directory. The effect is the same as specifying the package
+   *         root directory as a "--package_root" parameter to the Dart VM when executing any Dart
+   *         file inside the source directory. If a package root is a file, then the analyzer will
+   *         behave as though that file is a ".packages" file in the source directory. The effect is
+   *         the same as specifying the file as a "--packages" parameter to the Dart VM when
+   *         executing any Dart file inside the source directory. Files in any directories that are
+   *         not overridden by this mapping have their package: URI's resolved using the normal
    *         pubspec.yaml mechanism. If this field is absent, or the empty map is specified, that
    *         indicates that the normal pubspec.yaml mechanism should always be used.
    */
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index c26da51..fa4664f 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -615,17 +615,28 @@
               <value><ref>FilePath</ref></value>
             </map>
             <p>
-              A mapping from source directories to target directories
+              A mapping from source directories to package roots
               that should override the normal package: URI resolution
-              mechanism.  The analyzer will behave as though each
+              mechanism.
+            </p>
+            <p>
+              If a package root is a directory, then
+              the analyzer will behave as though the associated
               source directory in the map contains a special
               pubspec.yaml file which resolves any package: URI to the
-              corresponding path within the target directory.  The
-              effect is the same as specifying the target directory as
+              corresponding path within that package root directory.  The
+              effect is the same as specifying the package root directory as
               a "--package_root" parameter to the Dart VM when
               executing any Dart file inside the source directory.
             </p>
             <p>
+              If a package root is a file, then the analyzer
+              will behave as though that file is a ".packages" file in the
+              source directory. The effect is the same as specifying the file
+              as a "--packages" parameter to the Dart VM when
+              executing any Dart file inside the source directory.
+            </p>
+            <p>
               Files in any directories that are not overridden by this
               mapping have their package: URI's resolved using the
               normal pubspec.yaml mechanism.  If this field is absent,
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 8fdf1a9..ccc5bb9 100644
--- a/pkg/analyzer/example/parser_driver.dart
+++ b/pkg/analyzer/example/parser_driver.dart
@@ -5,10 +5,12 @@
 
 import 'dart:io';
 
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 
 main(List<String> args) {
   print('working dir ${new File('.').resolveSymbolicLinksSync()}');
@@ -41,6 +43,7 @@
 }
 
 class _ASTVisitor extends GeneralizingAstVisitor {
+  @override
   visitNode(AstNode node) {
     print('${node.runtimeType} : <"$node">');
     return super.visitNode(node);
@@ -50,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 74ed79c..3ba20f7 100755
--- a/pkg/analyzer/example/resolver_driver.dart
+++ b/pkg/analyzer/example/resolver_driver.dart
@@ -5,8 +5,9 @@
 
 import 'dart:io';
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
@@ -56,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/example/scanner_driver.dart b/pkg/analyzer/example/scanner_driver.dart
index d403fab..d867f19 100644
--- a/pkg/analyzer/example/scanner_driver.dart
+++ b/pkg/analyzer/example/scanner_driver.dart
@@ -5,7 +5,9 @@
 
 import 'dart:io';
 
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 
 main(List<String> args) {
   print('working dir ${new File('.').resolveSymbolicLinksSync()}');
diff --git a/pkg/analyzer/lib/analyzer.dart b/pkg/analyzer/lib/analyzer.dart
index d0fdc65..fffb006 100644
--- a/pkg/analyzer/lib/analyzer.dart
+++ b/pkg/analyzer/lib/analyzer.dart
@@ -6,17 +6,20 @@
 
 import 'dart:io';
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/error.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/string_source.dart';
 import 'package:path/path.dart' as pathos;
 
+export 'package:analyzer/dart/ast/ast.dart';
+export 'package:analyzer/dart/ast/visitor.dart';
+export 'package:analyzer/src/dart/ast/utilities.dart';
 export 'package:analyzer/src/error.dart';
-export 'package:analyzer/src/generated/ast.dart';
 export 'package:analyzer/src/generated/error.dart';
 export 'package:analyzer/src/generated/utilities_dart.dart';
 
@@ -63,22 +66,6 @@
       suppressErrors: suppressErrors, parseFunctionBodies: parseFunctionBodies);
 }
 
-CompilationUnit _parseSource(String contents, Source source,
-    {bool suppressErrors: false, bool parseFunctionBodies: true}) {
-  var reader = new CharSequenceReader(contents);
-  var errorCollector = new _ErrorCollector();
-  var scanner = new Scanner(source, reader, errorCollector);
-  var token = scanner.tokenize();
-  var parser = new Parser(source, errorCollector)
-    ..parseFunctionBodies = parseFunctionBodies;
-  var unit = parser.parseCompilationUnit(token)
-    ..lineInfo = new LineInfo(scanner.lineStarts);
-
-  if (errorCollector.hasErrors && !suppressErrors) throw errorCollector.group;
-
-  return unit;
-}
-
 /// Parses the script tag and directives in a string of Dart code into an AST.
 ///
 /// Stops parsing when the first non-directive is encountered. The rest of the
@@ -111,6 +98,22 @@
   return literal.stringValue;
 }
 
+CompilationUnit _parseSource(String contents, Source source,
+    {bool suppressErrors: false, bool parseFunctionBodies: true}) {
+  var reader = new CharSequenceReader(contents);
+  var errorCollector = new _ErrorCollector();
+  var scanner = new Scanner(source, reader, errorCollector);
+  var token = scanner.tokenize();
+  var parser = new Parser(source, errorCollector)
+    ..parseFunctionBodies = parseFunctionBodies;
+  var unit = parser.parseCompilationUnit(token)
+    ..lineInfo = new LineInfo(scanner.lineStarts);
+
+  if (errorCollector.hasErrors && !suppressErrors) throw errorCollector.group;
+
+  return unit;
+}
+
 /// A simple error listener that collects errors into an [AnalysisErrorGroup].
 class _ErrorCollector extends AnalysisErrorListener {
   final _errors = <AnalysisError>[];
@@ -124,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
new file mode 100644
index 0000000..d0680c4
--- /dev/null
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -0,0 +1,8101 @@
+// 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.
+
+/**
+ * Defines the AST model. The AST (Abstract Syntax Tree) model describes the
+ * syntactic (as opposed to semantic) structure of Dart code. The semantic
+ * structure of the code is modeled by the
+ * [element model](../element/element.dart).
+ *
+ * An AST consists of nodes (instances of a subclass of [AstNode]). The nodes
+ * are organized in a tree structure in which the children of a node are the
+ * smaller syntactic units from which the node is composed. For example, a
+ * binary expression consists of two sub-expressions (the operands) and an
+ * operator. The two expressions are represented as nodes. The operator is not
+ * represented as a node.
+ *
+ * The AST is constructed by the parser based on the sequence of tokens produced
+ * by the scanner. Most nodes provide direct access to the tokens used to build
+ * the node. For example, the token for the operator in a binary expression can
+ * be accessed from the node representing the binary expression.
+ *
+ * While any node can theoretically be the root of an AST structure, almost all
+ * of the AST structures known to the analyzer have a [CompilationUnit] as the
+ * root of the structure. A compilation unit represents all of the Dart code in
+ * a single file.
+ *
+ * An AST can be either unresolved or resolved. When an AST is unresolved
+ * certain properties will not have been computed and the accessors for those
+ * properties will return `null`. The documentation for those getters should
+ * describe that this is a possibility.
+ *
+ * When an AST is resolved, the identifiers in the AST will be associated with
+ * the elements that they refer to and every expression in the AST will have a
+ * type associated with it.
+ */
+library analyzer.dart.ast.ast;
+
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/element.dart' show AuxiliaryElements;
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * Two or more string literals that are implicitly concatenated because of being
+ * adjacent (separated only by whitespace).
+ *
+ * While the grammar only allows adjacent strings when all of the strings are of
+ * the same kind (single line or multi-line), this class doesn't enforce that
+ * restriction.
+ *
+ *    adjacentStrings ::=
+ *        [StringLiteral] [StringLiteral]+
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AdjacentStrings extends StringLiteral {
+  /**
+   * Initialize a newly created list of adjacent strings. To be syntactically
+   * valid, the list of [strings] must contain at least two elements.
+   */
+  factory AdjacentStrings(List<StringLiteral> strings) = AdjacentStringsImpl;
+
+  /**
+   * Return the strings that are implicitly concatenated.
+   */
+  NodeList<StringLiteral> get strings;
+}
+
+/**
+ * An AST node that can be annotated with both a documentation comment and a
+ * list of annotations.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AnnotatedNode extends AstNode {
+  /**
+   * Return the documentation comment associated with this node, or `null` if
+   * this node does not have a documentation comment associated with it.
+   */
+  Comment get documentationComment;
+
+  /**
+   * Set the documentation comment associated with this node to the given
+   * [comment].
+   */
+  void set documentationComment(Comment comment);
+
+  /**
+   * Return the first token following the comment and metadata.
+   */
+  Token get firstTokenAfterCommentAndMetadata;
+
+  /**
+   * Return the annotations associated with this node.
+   */
+  NodeList<Annotation> get metadata;
+
+  /**
+   * Return a list containing the comment and annotations associated with this
+   * node, sorted in lexical order.
+   */
+  List<AstNode> get sortedCommentAndAnnotations;
+}
+
+/**
+ * An annotation that can be associated with an AST node.
+ *
+ *    metadata ::=
+ *        annotation*
+ *
+ *    annotation ::=
+ *        '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Annotation extends AstNode {
+  /**
+   * Initialize a newly created annotation. Both the [period] and the
+   * [constructorName] can be `null` if the annotation is not referencing a
+   * named constructor. The [arguments] can be `null` if the annotation is not
+   * referencing a constructor.
+   */
+  factory Annotation(
+      Token atSign,
+      Identifier name,
+      Token period,
+      SimpleIdentifier constructorName,
+      ArgumentList arguments) = AnnotationImpl;
+
+  /**
+   * Return the arguments to the constructor being invoked, or `null` if this
+   * annotation is not the invocation of a constructor.
+   */
+  ArgumentList get arguments;
+
+  /**
+   * Set the arguments to the constructor being invoked to the given [arguments].
+   */
+  void set arguments(ArgumentList arguments);
+
+  /**
+   * Return the at sign that introduced the annotation.
+   */
+  Token get atSign;
+
+  /**
+   * Set the at sign that introduced the annotation to the given [token].
+   */
+  void set atSign(Token token);
+
+  /**
+   * Return the name of the constructor being invoked, or `null` if this
+   * annotation is not the invocation of a named constructor.
+   */
+  SimpleIdentifier get constructorName;
+
+  /**
+   * Set the name of the constructor being invoked to the given [name].
+   */
+  void set constructorName(SimpleIdentifier name);
+
+  /**
+   * Return the element associated with this annotation, or `null` if the AST
+   * structure has not been resolved or if this annotation could not be
+   * resolved.
+   */
+  Element get element;
+
+  /**
+   * Set the element associated with this annotation to the given [element].
+   */
+  void set element(Element element);
+
+  /**
+   * Return the element annotation representing this annotation in the element model.
+   */
+  ElementAnnotation get elementAnnotation;
+
+  /**
+   * Set the element annotation representing this annotation in the element
+   * model to the given [annotation].
+   */
+  void set elementAnnotation(ElementAnnotation annotation);
+
+  /**
+   * Return the name of the class defining the constructor that is being invoked
+   * or the name of the field that is being referenced.
+   */
+  Identifier get name;
+
+  /**
+   * Set the name of the class defining the constructor that is being invoked or
+   * the name of the field that is being referenced to the given [name].
+   */
+  void set name(Identifier name);
+
+  /**
+   * Return the period before the constructor name, or `null` if this annotation
+   * is not the invocation of a named constructor.
+   */
+  Token get period;
+
+  /**
+   * Set the period before the constructor name to the given [token].
+   */
+  void set period(Token token);
+}
+
+/**
+ * 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])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ArgumentList extends AstNode {
+  /**
+   * Initialize a newly created list of arguments. The list of [arguments] can
+   * be `null` if there are no arguments.
+   */
+  factory ArgumentList(Token leftParenthesis, List<Expression> arguments,
+      Token rightParenthesis) = ArgumentListImpl;
+
+  /**
+   * Return the expressions producing the values of the arguments. Although the
+   * language requires that positional arguments appear before named arguments,
+   * this class allows them to be intermixed.
+   */
+  NodeList<Expression> get arguments;
+
+  /**
+   * Set the parameter elements corresponding to each of the arguments in this
+   * list to the given list of [parameters]. The list of parameters must be the
+   * same length as the number of arguments, but can contain `null` entries if a
+   * given argument does not correspond to a formal parameter.
+   */
+  void set correspondingPropagatedParameters(List<ParameterElement> parameters);
+
+  /**
+   * Set the parameter elements corresponding to each of the arguments in this
+   * list to the given list of [parameters]. The list of parameters must be the
+   * same length as the number of arguments, but can contain `null` entries if a
+   * given argument does not correspond to a formal parameter.
+   */
+  void set correspondingStaticParameters(List<ParameterElement> parameters);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+}
+
+/**
+ * An as expression.
+ *
+ *    asExpression ::=
+ *        [Expression] 'as' [TypeName]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AsExpression extends Expression {
+  /**
+   * Initialize a newly created as expression.
+   */
+  factory AsExpression(Expression expression, Token asOperator, TypeName type) =
+      AsExpressionImpl;
+
+  /**
+   * Return the 'as' operator.
+   */
+  Token get asOperator;
+
+  /**
+   * Set the 'as' operator to the given [token].
+   */
+  void set asOperator(Token token);
+
+  /**
+   * Return the expression used to compute the value being cast.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression used to compute the value being cast to the given
+   * [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the name of the type being cast to.
+   */
+  TypeName get type;
+
+  /**
+   * Set the name of the type being cast to to the given [name].
+   */
+  void set type(TypeName name);
+}
+
+/**
+ * An assert statement.
+ *
+ *    assertStatement ::=
+ *        'assert' '(' [Expression] ')' ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AssertStatement extends Statement {
+  /**
+   * Initialize a newly created assert statement. The [comma] and [message] can
+   * be `null` if there is no message.
+   */
+  factory AssertStatement(
+      Token assertKeyword,
+      Token leftParenthesis,
+      Expression condition,
+      Token comma,
+      Expression message,
+      Token rightParenthesis,
+      Token semicolon) = AssertStatementImpl;
+
+  /**
+   * Return the token representing the 'assert' keyword.
+   */
+  Token get assertKeyword;
+
+  /**
+   * Set the token representing the 'assert' keyword to the given [token].
+   */
+  void set assertKeyword(Token token);
+
+  /**
+   * Return the comma between the [condition] and the [message], or `null` if no
+   * message was supplied.
+   */
+  Token get comma;
+
+  /**
+   * Set the comma between the [condition] and the [message] to the given [token].
+   */
+  void set comma(Token token);
+
+  /**
+   * Return the condition that is being asserted to be `true`.
+   */
+  Expression get condition;
+
+  /**
+   * Set the condition that is being asserted to be `true` to the given
+   * [expression].
+   */
+  void set condition(Expression condition);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the message to report if the assertion fails, or `null` if no
+   * message was supplied.
+   */
+  Expression get message;
+
+  /**
+   * Set the message to report if the assertion fails to the given
+   * [expression].
+   */
+  void set message(Expression expression);
+
+  /**
+   *  Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   *  Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+
+  /**
+   * Return the semicolon terminating the statement.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * An assignment expression.
+ *
+ *    assignmentExpression ::=
+ *        [Expression] operator [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AssignmentExpression extends Expression {
+  /**
+   * Initialize a newly created assignment expression.
+   */
+  factory AssignmentExpression(
+          Expression leftHandSide, Token operator, Expression rightHandSide) =
+      AssignmentExpressionImpl;
+
+  /**
+   * Return the best element available for this operator. If resolution was able
+   * to find a better element based on type propagation, that element will be
+   * returned. Otherwise, the element found using the result of static analysis
+   * will be returned. If resolution has not been performed, then `null` will be
+   * returned.
+   */
+  MethodElement get bestElement;
+
+  /**
+   * Return the expression used to compute the left hand side.
+   */
+  Expression get leftHandSide;
+
+  /**
+   * Return the expression used to compute the left hand side.
+   */
+  void set leftHandSide(Expression expression);
+
+  /**
+   * Return the assignment operator being applied.
+   */
+  Token get operator;
+
+  /**
+   * Set the assignment operator being applied to the given [token].
+   */
+  void set operator(Token token);
+
+  /**
+   * Return the element associated with the operator based on the propagated
+   * type of the left-hand-side, or `null` if the AST structure has not been
+   * resolved, if the operator is not a compound operator, or if the operator
+   * could not be resolved.
+   */
+  MethodElement get propagatedElement;
+
+  /**
+   * Set the element associated with the operator based on the propagated
+   * type of the left-hand-side to the given [element].
+   */
+  void set propagatedElement(MethodElement element);
+
+  /**
+   * Return the expression used to compute the right hand side.
+   */
+  Expression get rightHandSide;
+
+  /**
+   * Set the expression used to compute the left hand side to the given
+   * [expression].
+   */
+  void set rightHandSide(Expression expression);
+
+  /**
+   * Return the element associated with the operator based on the static type of
+   * the left-hand-side, or `null` if the AST structure has not been resolved,
+   * if the operator is not a compound operator, or if the operator could not be
+   * resolved.
+   */
+  MethodElement get staticElement;
+
+  /**
+   * Set the element associated with the operator based on the static type of
+   * the left-hand-side to the given [element].
+   */
+  void set staticElement(MethodElement element);
+}
+
+/**
+ * A node in the AST structure for a Dart program.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AstNode {
+  /**
+   * An empty list of AST nodes.
+   */
+  static const List<AstNode> EMPTY_LIST = const <AstNode>[];
+
+  /**
+   * A comparator that can be used to sort AST nodes in lexical order. In other
+   * words, `compare` will return a negative value if the offset of the first
+   * node is less than the offset of the second node, zero (0) if the nodes have
+   * the same offset, and a positive value if the offset of the first node is
+   * greater than the offset of the second node.
+   */
+  static Comparator<AstNode> LEXICAL_ORDER =
+      (AstNode first, AstNode second) => first.offset - second.offset;
+
+  /**
+   * Return the first token included in this node's source range.
+   */
+  Token get beginToken;
+
+  /**
+   * Return an iterator that can be used to iterate through all the entities
+   * (either AST nodes or tokens) that make up the contents of this node,
+   * including doc comments but excluding other comments.
+   */
+  Iterable/*<AstNode | Token>*/ get childEntities;
+
+  /**
+   * Return the offset of the character immediately following the last character
+   * of this node's source range. This is equivalent to
+   * `node.getOffset() + node.getLength()`. For a compilation unit this will be
+   * equal to the length of the unit's source. For synthetic nodes this will be
+   * equivalent to the node's offset (because the length is zero (0) by
+   * definition).
+   */
+  int get end;
+
+  /**
+   * Return the last token included in this node's source range.
+   */
+  Token get endToken;
+
+  /**
+   * Return `true` if this node is a synthetic node. A synthetic node is a node
+   * that was introduced by the parser in order to recover from an error in the
+   * code. Synthetic nodes always have a length of zero (`0`).
+   */
+  bool get isSynthetic;
+
+  /**
+   * Return the number of characters in the node's source range.
+   */
+  int get length;
+
+  /**
+   * Return the offset from the beginning of the file to the first character in
+   * the node's source range.
+   */
+  int get offset;
+
+  /**
+   * Return this node's parent node, or `null` if this node is the root of an
+   * AST structure.
+   *
+   * Note that the relationship between an AST node and its parent node may
+   * change over the lifetime of a node.
+   */
+  AstNode get parent;
+
+  /**
+   * Return the node at the root of this node's AST structure. Note that this
+   * method's performance is linear with respect to the depth of the node in the
+   * AST structure (O(depth)).
+   */
+  AstNode get root;
+
+  /**
+   * Use the given [visitor] to visit this node. Return the value returned by
+   * the visitor as a result of visiting this node.
+   */
+  dynamic /* =E */ accept/*<E>*/(AstVisitor/*<E>*/ visitor);
+
+  /**
+   * Return the most immediate ancestor of this node for which the [predicate]
+   * returns `true`, or `null` if there is no such ancestor. Note that this node
+   * will never be returned.
+   */
+  AstNode getAncestor(Predicate<AstNode> predicate);
+
+  /**
+   * Return the value of the property with the given [name], or `null` if this
+   * node does not have a property with the given name.
+   */
+  Object getProperty(String name);
+
+  /**
+   * Set the value of the property with the given [name] to the given [value].
+   * If the value is `null`, the property will effectively be removed.
+   */
+  void setProperty(String name, Object value);
+
+  /**
+   * Return a textual description of this node in a form approximating valid
+   * source. The returned string will not be valid source primarily in the case
+   * where the node itself is not well-formed.
+   */
+  String toSource();
+
+  /**
+   * Use the given [visitor] to visit all of the children of this node. The
+   * children will be visited in lexical order.
+   */
+  void visitChildren(AstVisitor visitor);
+}
+
+/**
+ * An object that can be used to visit an AST structure.
+ *
+ * Clients may extend or implement this class.
+ */
+abstract class AstVisitor<R> {
+  R visitAdjacentStrings(AdjacentStrings node);
+
+  R visitAnnotation(Annotation node);
+
+  R visitArgumentList(ArgumentList node);
+
+  R visitAsExpression(AsExpression node);
+
+  R visitAssertStatement(AssertStatement assertStatement);
+
+  R visitAssignmentExpression(AssignmentExpression node);
+
+  R visitAwaitExpression(AwaitExpression node);
+
+  R visitBinaryExpression(BinaryExpression node);
+
+  R visitBlock(Block node);
+
+  R visitBlockFunctionBody(BlockFunctionBody node);
+
+  R visitBooleanLiteral(BooleanLiteral node);
+
+  R visitBreakStatement(BreakStatement node);
+
+  R visitCascadeExpression(CascadeExpression node);
+
+  R visitCatchClause(CatchClause node);
+
+  R visitClassDeclaration(ClassDeclaration node);
+
+  R visitClassTypeAlias(ClassTypeAlias node);
+
+  R visitComment(Comment node);
+
+  R visitCommentReference(CommentReference node);
+
+  R visitCompilationUnit(CompilationUnit node);
+
+  R visitConditionalExpression(ConditionalExpression node);
+
+  R visitConfiguration(Configuration node);
+
+  R visitConstructorDeclaration(ConstructorDeclaration node);
+
+  R visitConstructorFieldInitializer(ConstructorFieldInitializer node);
+
+  R visitConstructorName(ConstructorName node);
+
+  R visitContinueStatement(ContinueStatement node);
+
+  R visitDeclaredIdentifier(DeclaredIdentifier node);
+
+  R visitDefaultFormalParameter(DefaultFormalParameter node);
+
+  R visitDoStatement(DoStatement node);
+
+  R visitDottedName(DottedName node);
+
+  R visitDoubleLiteral(DoubleLiteral node);
+
+  R visitEmptyFunctionBody(EmptyFunctionBody node);
+
+  R visitEmptyStatement(EmptyStatement node);
+
+  R visitEnumConstantDeclaration(EnumConstantDeclaration node);
+
+  R visitEnumDeclaration(EnumDeclaration node);
+
+  R visitExportDirective(ExportDirective node);
+
+  R visitExpressionFunctionBody(ExpressionFunctionBody node);
+
+  R visitExpressionStatement(ExpressionStatement node);
+
+  R visitExtendsClause(ExtendsClause node);
+
+  R visitFieldDeclaration(FieldDeclaration node);
+
+  R visitFieldFormalParameter(FieldFormalParameter node);
+
+  R visitForEachStatement(ForEachStatement node);
+
+  R visitFormalParameterList(FormalParameterList node);
+
+  R visitForStatement(ForStatement node);
+
+  R visitFunctionDeclaration(FunctionDeclaration node);
+
+  R visitFunctionDeclarationStatement(FunctionDeclarationStatement node);
+
+  R visitFunctionExpression(FunctionExpression node);
+
+  R visitFunctionExpressionInvocation(FunctionExpressionInvocation node);
+
+  R visitFunctionTypeAlias(FunctionTypeAlias functionTypeAlias);
+
+  R visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node);
+
+  R visitHideCombinator(HideCombinator node);
+
+  R visitIfStatement(IfStatement node);
+
+  R visitImplementsClause(ImplementsClause node);
+
+  R visitImportDirective(ImportDirective node);
+
+  R visitIndexExpression(IndexExpression node);
+
+  R visitInstanceCreationExpression(InstanceCreationExpression node);
+
+  R visitIntegerLiteral(IntegerLiteral node);
+
+  R visitInterpolationExpression(InterpolationExpression node);
+
+  R visitInterpolationString(InterpolationString node);
+
+  R visitIsExpression(IsExpression node);
+
+  R visitLabel(Label node);
+
+  R visitLabeledStatement(LabeledStatement node);
+
+  R visitLibraryDirective(LibraryDirective node);
+
+  R visitLibraryIdentifier(LibraryIdentifier node);
+
+  R visitListLiteral(ListLiteral node);
+
+  R visitMapLiteral(MapLiteral node);
+
+  R visitMapLiteralEntry(MapLiteralEntry node);
+
+  R visitMethodDeclaration(MethodDeclaration node);
+
+  R visitMethodInvocation(MethodInvocation node);
+
+  R visitNamedExpression(NamedExpression node);
+
+  R visitNativeClause(NativeClause node);
+
+  R visitNativeFunctionBody(NativeFunctionBody node);
+
+  R visitNullLiteral(NullLiteral node);
+
+  R visitParenthesizedExpression(ParenthesizedExpression node);
+
+  R visitPartDirective(PartDirective node);
+
+  R visitPartOfDirective(PartOfDirective node);
+
+  R visitPostfixExpression(PostfixExpression node);
+
+  R visitPrefixedIdentifier(PrefixedIdentifier node);
+
+  R visitPrefixExpression(PrefixExpression node);
+
+  R visitPropertyAccess(PropertyAccess node);
+
+  R visitRedirectingConstructorInvocation(
+      RedirectingConstructorInvocation node);
+
+  R visitRethrowExpression(RethrowExpression node);
+
+  R visitReturnStatement(ReturnStatement node);
+
+  R visitScriptTag(ScriptTag node);
+
+  R visitShowCombinator(ShowCombinator node);
+
+  R visitSimpleFormalParameter(SimpleFormalParameter node);
+
+  R visitSimpleIdentifier(SimpleIdentifier node);
+
+  R visitSimpleStringLiteral(SimpleStringLiteral node);
+
+  R visitStringInterpolation(StringInterpolation node);
+
+  R visitSuperConstructorInvocation(SuperConstructorInvocation node);
+
+  R visitSuperExpression(SuperExpression node);
+
+  R visitSwitchCase(SwitchCase node);
+
+  R visitSwitchDefault(SwitchDefault node);
+
+  R visitSwitchStatement(SwitchStatement node);
+
+  R visitSymbolLiteral(SymbolLiteral node);
+
+  R visitThisExpression(ThisExpression node);
+
+  R visitThrowExpression(ThrowExpression node);
+
+  R visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node);
+
+  R visitTryStatement(TryStatement node);
+
+  R visitTypeArgumentList(TypeArgumentList node);
+
+  R visitTypeName(TypeName node);
+
+  R visitTypeParameter(TypeParameter node);
+
+  R visitTypeParameterList(TypeParameterList node);
+
+  R visitVariableDeclaration(VariableDeclaration node);
+
+  R visitVariableDeclarationList(VariableDeclarationList node);
+
+  R visitVariableDeclarationStatement(VariableDeclarationStatement node);
+
+  R visitWhileStatement(WhileStatement node);
+
+  R visitWithClause(WithClause node);
+
+  R visitYieldStatement(YieldStatement node);
+}
+
+/**
+ * An await expression.
+ *
+ *    awaitExpression ::=
+ *        'await' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AwaitExpression extends Expression {
+  /**
+   * Initialize a newly created await expression.
+   */
+  factory AwaitExpression(Token awaitKeyword, Expression expression) =
+      AwaitExpressionImpl;
+
+  /**
+   * Return the 'await' keyword.
+   */
+  Token get awaitKeyword;
+
+  /**
+   * Set the 'await' keyword to the given [token].
+   */
+  void set awaitKeyword(Token token);
+
+  /**
+   * Return the expression whose value is being waited on.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression whose value is being waited on to the given [expression].
+   */
+  void set expression(Expression expression);
+}
+
+/**
+ * A binary (infix) expression.
+ *
+ *    binaryExpression ::=
+ *        [Expression] [Token] [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class BinaryExpression extends Expression {
+  /**
+   * Initialize a newly created binary expression.
+   */
+  factory BinaryExpression(
+          Expression leftOperand, Token operator, Expression rightOperand) =
+      BinaryExpressionImpl;
+
+  /**
+   * Return the best element available for this operator. If resolution was able
+   * to find a better element based on type propagation, that element will be
+   * returned. Otherwise, the element found using the result of static analysis
+   * will be returned. If resolution has not been performed, then `null` will be
+   * returned.
+   */
+  MethodElement get bestElement;
+
+  /**
+   * Return the expression used to compute the left operand.
+   */
+  Expression get leftOperand;
+
+  /**
+   * Set the expression used to compute the left operand to the given
+   * [expression].
+   */
+  void set leftOperand(Expression expression);
+
+  /**
+   * Return the binary operator being applied.
+   */
+  Token get operator;
+
+  /**
+   * Set the binary operator being applied to the given [token].
+   */
+  void set operator(Token token);
+
+  /**
+   * Return the element associated with the operator based on the propagated
+   * type of the 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.
+   */
+  MethodElement get propagatedElement;
+
+  /**
+   * Set the element associated with the operator based on the propagated
+   * type of the left operand to the given [element].
+   */
+  void set propagatedElement(MethodElement element);
+
+  /**
+   * Return the expression used to compute the right operand.
+   */
+  Expression get rightOperand;
+
+  /**
+   * Set the expression used to compute the right operand to the given
+   * [expression].
+   */
+  void set rightOperand(Expression expression);
+
+  /**
+   * Return the element associated with the operator based on the static type of
+   * the 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.
+   */
+  MethodElement get staticElement;
+
+  /**
+   * Set the element associated with the operator based on the static type of
+   * the left operand to the given [element].
+   */
+  void set staticElement(MethodElement element);
+}
+
+/**
+ * A sequence of statements.
+ *
+ *    block ::=
+ *        '{' statement* '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Block extends Statement {
+  /**
+   * Initialize a newly created block of code.
+   */
+  factory Block(
+          Token leftBracket, List<Statement> statements, Token rightBracket) =
+      BlockImpl;
+
+  /**
+   * Return the left curly bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the left curly bracket to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the right curly bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Set the right curly bracket to the given [token].
+   */
+  void set rightBracket(Token token);
+
+  /**
+   * Return the statements contained in the block.
+   */
+  NodeList<Statement> get statements;
+}
+
+/**
+ * A function body that consists of a block of statements.
+ *
+ *    blockFunctionBody ::=
+ *        ('async' | 'async' '*' | 'sync' '*')? [Block]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class BlockFunctionBody extends FunctionBody {
+  /**
+   * Initialize a newly created function body consisting of a block of
+   * statements. The [keyword] can be `null` if there is no keyword specified
+   * for the block. The [star] can be `null` if there is no star following the
+   * keyword (and must be `null` if there is no keyword).
+   */
+  factory BlockFunctionBody(Token keyword, Token star, Block block) =
+      BlockFunctionBodyImpl;
+
+  /**
+   * Return the block representing the body of the function.
+   */
+  Block get block;
+
+  /**
+   * Set the block representing the body of the function to the given [block].
+   */
+  void set block(Block block);
+
+  /**
+   * Set token representing the 'async' or 'sync' keyword to the given [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Set the star following the 'async' or 'sync' keyword to the given [token].
+   */
+  void set star(Token token);
+}
+
+/**
+ * A boolean literal expression.
+ *
+ *    booleanLiteral ::=
+ *        'false' | 'true'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class BooleanLiteral extends Literal {
+  /**
+   * Initialize a newly created boolean literal.
+   */
+  factory BooleanLiteral(Token literal, bool value) = BooleanLiteralImpl;
+
+  /**
+   * Return the token representing the literal.
+   */
+  Token get literal;
+
+  /**
+   * Set the token representing the literal to the given [token].
+   */
+  void set literal(Token token);
+
+  /**
+   * Return the value of the literal.
+   */
+  bool get value;
+}
+
+/**
+ * A break statement.
+ *
+ *    breakStatement ::=
+ *        'break' [SimpleIdentifier]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class BreakStatement extends Statement {
+  /**
+   * Initialize a newly created break statement. The [label] can be `null` if
+   * there is no label associated with the statement.
+   */
+  factory BreakStatement(
+          Token breakKeyword, SimpleIdentifier label, Token semicolon) =
+      BreakStatementImpl;
+
+  /**
+   * Return the token representing the 'break' keyword.
+   */
+  Token get breakKeyword;
+
+  /**
+   * Set the token representing the 'break' keyword to the given [token].
+   */
+  void set breakKeyword(Token token);
+
+  /**
+   * Return the label associated with the statement, or `null` if there is no
+   * label.
+   */
+  SimpleIdentifier get label;
+
+  /**
+   * Set the label associated with the statement to the given [identifier].
+   */
+  void set label(SimpleIdentifier identifier);
+
+  /**
+   * Return the semicolon terminating the statement.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the node from which this break statement is breaking. This will be
+   * either a [Statement] (in the case of breaking out of a loop), a
+   * [SwitchMember] (in the case of a labeled break statement whose label
+   * matches a label on a switch case in an enclosing switch statement), or
+   * `null` if the AST has not yet been resolved or if the target could not be
+   * resolved. Note that if the source code has errors, the target might be
+   * invalid (e.g. trying to break to a switch case).
+   */
+  AstNode get target;
+
+  /**
+   * Set the node from which this break statement is breaking to the given
+   * [node].
+   */
+  void set target(AstNode node);
+}
+
+/**
+ * A sequence of cascaded expressions: expressions that share a common target.
+ * 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
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CascadeExpression extends Expression {
+  /**
+   * Initialize a newly created cascade expression. The list of
+   * [cascadeSections] must contain at least one element.
+   */
+  factory CascadeExpression(
+          Expression target, List<Expression> cascadeSections) =
+      CascadeExpressionImpl;
+
+  /**
+   * Return the cascade sections sharing the common target.
+   */
+  NodeList<Expression> get cascadeSections;
+
+  /**
+   * Return the target of the cascade sections.
+   */
+  Expression get target;
+
+  /**
+   * Set the target of the cascade sections to the given [expression].
+   */
+  void set target(Expression target);
+}
+
+/**
+ * A catch clause within a try statement.
+ *
+ *    onPart ::=
+ *        catchPart [Block]
+ *      | 'on' type catchPart? [Block]
+ *
+ *    catchPart ::=
+ *        'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CatchClause extends AstNode {
+  /**
+   * Initialize a newly created catch clause. The [onKeyword] and
+   * [exceptionType] can be `null` if the clause will catch all exceptions. The
+   * [comma] and [stackTraceParameter] can be `null` if the stack trace
+   * parameter is not defined.
+   */
+  factory CatchClause(
+      Token onKeyword,
+      TypeName exceptionType,
+      Token catchKeyword,
+      Token leftParenthesis,
+      SimpleIdentifier exceptionParameter,
+      Token comma,
+      SimpleIdentifier stackTraceParameter,
+      Token rightParenthesis,
+      Block body) = CatchClauseImpl;
+
+  /**
+   * Return the body of the catch block.
+   */
+  Block get body;
+
+  /**
+   * Set the body of the catch block to the given [block].
+   */
+  void set body(Block block);
+
+  /**
+   * Return the token representing the 'catch' keyword, or `null` if there is no
+   * 'catch' keyword.
+   */
+  Token get catchKeyword;
+
+  /**
+   * Set the token representing the 'catch' keyword to the given [token].
+   */
+  void set catchKeyword(Token token);
+
+  /**
+   * Return the comma separating the exception parameter from the stack trace
+   * parameter, or `null` if there is no stack trace parameter.
+   */
+  Token get comma;
+
+  /**
+   * Set the comma separating the exception parameter from the stack trace
+   * parameter to the given [token].
+   */
+  void set comma(Token token);
+
+  /**
+   * Return the parameter whose value will be the exception that was thrown, or
+   * `null` if there is no 'catch' keyword.
+   */
+  SimpleIdentifier get exceptionParameter;
+
+  /**
+   * Set the parameter whose value will be the exception that was thrown to the
+   * given [parameter].
+   */
+  void set exceptionParameter(SimpleIdentifier parameter);
+
+  /**
+   * Return the type of exceptions caught by this catch clause, or `null` if
+   * this catch clause catches every type of exception.
+   */
+  TypeName get exceptionType;
+
+  /**
+   * Set the type of exceptions caught by this catch clause to the given
+   * [exceptionType].
+   */
+  void set exceptionType(TypeName exceptionType);
+
+  /**
+   * Return the left parenthesis, or `null` if there is no 'catch' keyword.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the token representing the 'on' keyword, or `null` if there is no 'on'
+   * keyword.
+   */
+  Token get onKeyword;
+
+  /**
+   * Set the token representing the 'on' keyword to the given [token].
+   */
+  void set onKeyword(Token token);
+
+  /**
+   * Return the right parenthesis, or `null` if there is no 'catch' keyword.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+
+  /**
+   * Return the parameter whose value will be the stack trace associated with
+   * the exception, or `null` if there is no stack trace parameter.
+   */
+  SimpleIdentifier get stackTraceParameter;
+
+  /**
+   * Set the parameter whose value will be the stack trace associated with the
+   * exception to the given [parameter].
+   */
+  void set stackTraceParameter(SimpleIdentifier parameter);
+}
+
+/**
+ * The declaration of a class.
+ *
+ *    classDeclaration ::=
+ *        'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
+ *        ([ExtendsClause] [WithClause]?)?
+ *        [ImplementsClause]?
+ *        '{' [ClassMember]* '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ClassDeclaration extends NamedCompilationUnitMember {
+  /**
+   * Initialize a newly created class declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the class does not have the
+   * corresponding attribute. The [abstractKeyword] can be `null` if the class
+   * is not abstract. The [typeParameters] can be `null` if the class does not
+   * have any type parameters. Any or all of the [extendsClause], [withClause],
+   * and [implementsClause] can be `null` if the class does not have the
+   * corresponding clause. The list of [members] can be `null` if the class does
+   * not have any members.
+   */
+  factory ClassDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      Token abstractKeyword,
+      Token classKeyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      ExtendsClause extendsClause,
+      WithClause withClause,
+      ImplementsClause implementsClause,
+      Token leftBracket,
+      List<ClassMember> members,
+      Token rightBracket) = ClassDeclarationImpl;
+
+  /**
+   * Return the 'abstract' keyword, or `null` if the keyword was absent.
+   */
+  Token get abstractKeyword;
+
+  /**
+   * Set the 'abstract' keyword to the given [token].
+   */
+  void set abstractKeyword(Token token);
+
+  /**
+   * Return the token representing the 'class' keyword to the given [token].
+   */
+  Token get classKeyword;
+
+  /**
+   * Set the token representing the 'class' keyword.
+   */
+  void set classKeyword(Token token);
+
+  @override
+  ClassElement get element;
+
+  /**
+   * Return the extends clause for this class, or `null` if the class does not
+   * extend any other class.
+   */
+  ExtendsClause get extendsClause;
+
+  /**
+   * Set the extends clause for this class to the given [extendsClause].
+   */
+  void set extendsClause(ExtendsClause extendsClause);
+
+  /**
+   * Return the implements clause for the class, or `null` if the class does not
+   * implement any interfaces.
+   */
+  ImplementsClause get implementsClause;
+
+  /**
+   * Set the implements clause for the class to the given [implementsClause].
+   */
+  void set implementsClause(ImplementsClause implementsClause);
+
+  /**
+   * Return `true` if this class is declared to be an abstract class.
+   */
+  bool get isAbstract;
+
+  /**
+   * Return the left curly bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the left curly bracket to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the members defined by the class.
+   */
+  NodeList<ClassMember> get members;
+
+  /**
+   * Return the native clause for this class, or `null` if the class does not
+   * have a native clause.
+   */
+  NativeClause get nativeClause;
+
+  /**
+   * Set the native clause for this class to the given [nativeClause].
+   */
+  void set nativeClause(NativeClause nativeClause);
+
+  /**
+   * Return the right curly bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Set the right curly bracket to the given [token].
+   */
+  void set rightBracket(Token token);
+
+  /**
+   * Return the type parameters for the class, or `null` if the class does not
+   * have any type parameters.
+   */
+  TypeParameterList get typeParameters;
+
+  /**
+   * Set the type parameters for the class to the given list of [typeParameters].
+   */
+  void set typeParameters(TypeParameterList typeParameters);
+
+  /**
+   * Return the with clause for the class, or `null` if the class does not have
+   * a with clause.
+   */
+  WithClause get withClause;
+
+  /**
+   * Set the with clause for the class to the given [withClause].
+   */
+  void set withClause(WithClause withClause);
+
+  /**
+   * Return the constructor declared in the class with the given [name], or
+   * `null` if there is no such constructor. If the [name] is `null` then the
+   * default constructor will be searched for.
+   */
+  ConstructorDeclaration getConstructor(String name);
+
+  /**
+   * Return the field declared in the class with the given [name], or `null` if
+   * there is no such field.
+   */
+  VariableDeclaration getField(String name);
+
+  /**
+   * Return the method declared in the class with the given [name], or `null` if
+   * there is no such method.
+   */
+  MethodDeclaration getMethod(String name);
+}
+
+/**
+ * A node that declares a name within the scope of a class.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ClassMember extends Declaration {}
+
+/**
+ * A class type alias.
+ *
+ *    classTypeAlias ::=
+ *        [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+ *
+ *    mixinApplication ::=
+ *        [TypeName] [WithClause] [ImplementsClause]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ClassTypeAlias extends TypeAlias {
+  /**
+   * Initialize a newly created class type alias. Either or both of the
+   * [comment] and [metadata] can be `null` if the class type alias does not
+   * have the corresponding attribute. The [typeParameters] can be `null` if the
+   * class does not have any type parameters. The [abstractKeyword] can be
+   * `null` if the class is not abstract. The [implementsClause] can be `null`
+   * if the class does not implement any interfaces.
+   */
+  factory ClassTypeAlias(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      Token equals,
+      Token abstractKeyword,
+      TypeName superclass,
+      WithClause withClause,
+      ImplementsClause implementsClause,
+      Token semicolon) = ClassTypeAliasImpl;
+
+  /**
+   * Return the token for the 'abstract' keyword, or `null` if this is not
+   * defining an abstract class.
+   */
+  Token get abstractKeyword;
+
+  /**
+   * Set the token for the 'abstract' keyword to the given [token].
+   */
+  void set abstractKeyword(Token token);
+
+  /**
+   * Return the token for the '=' separating the name from the definition.
+   */
+  Token get equals;
+
+  /**
+   * Set the token for the '=' separating the name from the definition to the
+   * given [token].
+   */
+  void set equals(Token token);
+
+  /**
+   * Return the implements clause for this class, or `null` if there is no
+   * implements clause.
+   */
+  ImplementsClause get implementsClause;
+
+  /**
+   * Set the implements clause for this class to the given [implementsClause].
+   */
+  void set implementsClause(ImplementsClause implementsClause);
+
+  /**
+   * Return `true` if this class is declared to be an abstract class.
+   */
+  bool get isAbstract;
+
+  /**
+   * Return the name of the superclass of the class being declared.
+   */
+  TypeName get superclass;
+
+  /**
+   * Set the name of the superclass of the class being declared to the given
+   * [superclass] name.
+   */
+  void set superclass(TypeName superclass);
+
+  /**
+   * Return the type parameters for the class, or `null` if the class does not
+   * have any type parameters.
+   */
+  TypeParameterList get typeParameters;
+
+  /**
+   * Set the type parameters for the class to the given list of [typeParameters].
+   */
+  void set typeParameters(TypeParameterList typeParameters);
+
+  /**
+   * Return the with clause for this class.
+   */
+  WithClause get withClause;
+
+  /**
+   * Set the with clause for this class to the given with [withClause].
+   */
+  void set withClause(WithClause withClause);
+}
+
+/**
+ * A combinator associated with an import or export directive.
+ *
+ *    combinator ::=
+ *        [HideCombinator]
+ *      | [ShowCombinator]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Combinator extends AstNode {
+  /**
+   * Return the 'hide' or 'show' keyword specifying what kind of processing is
+   * to be done on the names.
+   */
+  Token get keyword;
+
+  /**
+   * Set the 'hide' or 'show' keyword specifying what kind of processing is
+   * to be done on the names to the given [token].
+   */
+  void set keyword(Token token);
+}
+
+/**
+ * A comment within the source code.
+ *
+ *    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.
+ */
+abstract class Comment extends AstNode {
+  /**
+   * Initialize a newly created comment. The list of [tokens] must contain at
+   * least one token. The [type] is the type of the comment. The list of
+   * [references] can be empty if the comment does not contain any embedded
+   * references.
+   */
+  factory Comment(List<Token> tokens, CommentType type,
+      List<CommentReference> references) = CommentImpl;
+
+  /**
+   * Return `true` if this is a block comment.
+   */
+  bool get isBlock;
+
+  /**
+   * Return `true` if this is a documentation comment.
+   */
+  bool get isDocumentation;
+
+  /**
+   * Return `true` if this is an end-of-line comment.
+   */
+  bool get isEndOfLine;
+
+  /**
+   * Return the references embedded within the documentation comment.
+   */
+  NodeList<CommentReference> get references;
+
+  /**
+   * Return the tokens representing the comment.
+   */
+  List<Token> get tokens;
+
+  /**
+   * Create a block comment consisting of the given [tokens].
+   */
+  static Comment createBlockComment(List<Token> tokens) =>
+      CommentImpl.createBlockComment(tokens);
+
+  /**
+   * Create a documentation comment consisting of the given [tokens].
+   */
+  static Comment createDocumentationComment(List<Token> tokens) =>
+      CommentImpl.createDocumentationComment(tokens);
+
+  /**
+   * Create a documentation comment consisting of the given [tokens] and having
+   * the given [references] embedded within it.
+   */
+  static Comment createDocumentationCommentWithReferences(
+          List<Token> tokens, List<CommentReference> references) =>
+      CommentImpl.createDocumentationCommentWithReferences(tokens, references);
+
+  /**
+   * Create an end-of-line comment consisting of the given [tokens].
+   */
+  static Comment createEndOfLineComment(List<Token> tokens) =>
+      CommentImpl.createEndOfLineComment(tokens);
+}
+
+/**
+ * A reference to a Dart element that is found within a documentation comment.
+ *
+ *    commentReference ::=
+ *        '[' 'new'? [Identifier] ']'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CommentReference extends AstNode {
+  /**
+   * Initialize a newly created reference to a Dart element. The [newKeyword]
+   * can be `null` if the reference is not to a constructor.
+   */
+  factory CommentReference(Token newKeyword, Identifier identifier) =
+      CommentReferenceImpl;
+
+  /**
+   * Return the identifier being referenced.
+   */
+  Identifier get identifier;
+
+  /**
+   * Set the identifier being referenced to the given [identifier].
+   */
+  void set identifier(Identifier identifier);
+
+  /**
+   * Return the token representing the 'new' keyword, or `null` if there was no
+   * 'new' keyword.
+   */
+  Token get newKeyword;
+
+  /**
+   * Set the token representing the 'new' keyword to the given [token].
+   */
+  void set newKeyword(Token token);
+}
+
+/**
+ * A compilation unit.
+ *
+ * While the grammar restricts the order of the directives and declarations
+ * within a compilation unit, this class does not enforce those restrictions.
+ * In particular, the children of a compilation unit will be visited in lexical
+ * 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]*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CompilationUnit extends AstNode {
+  /**
+   * Initialize a newly created compilation unit to have the given directives
+   * and declarations. The [scriptTag] can be `null` if there is no script tag
+   * in the compilation unit. The list of [directives] can be `null` if there
+   * are no directives in the compilation unit. The list of [declarations] can
+   * be `null` if there are no declarations in the compilation unit.
+   */
+  factory CompilationUnit(
+      Token beginToken,
+      ScriptTag scriptTag,
+      List<Directive> directives,
+      List<CompilationUnitMember> declarations,
+      Token endToken) = CompilationUnitImpl;
+
+  /**
+   * Set the first token included in this node's source range to the given
+   * [token].
+   */
+  void set beginToken(Token token);
+
+  /**
+   * Return the declarations contained in this compilation unit.
+   */
+  NodeList<CompilationUnitMember> get declarations;
+
+  /**
+   * Return the directives contained in this compilation unit.
+   */
+  NodeList<Directive> get directives;
+
+  /**
+   * Return the element associated with this compilation unit, or `null` if the
+   * AST structure has not been resolved.
+   */
+  CompilationUnitElement get element;
+
+  /**
+   * Set the element associated with this compilation unit to the given
+   * [element].
+   */
+  void set element(CompilationUnitElement element);
+
+  /**
+   * Set the last token included in this node's source range to the given
+   * [token].
+   */
+  void set endToken(Token token);
+
+  /**
+   * Return the line information for this compilation unit.
+   */
+  LineInfo get lineInfo;
+
+  /**
+   * Set the line information for this compilation unit to the given [info].
+   */
+  void set lineInfo(LineInfo info);
+
+  /**
+   * Return the script tag at the beginning of the compilation unit, or `null`
+   * if there is no script tag in this compilation unit.
+   */
+  ScriptTag get scriptTag;
+
+  /**
+   * Set the script tag at the beginning of the compilation unit to the given
+   * [scriptTag].
+   */
+  void set scriptTag(ScriptTag scriptTag);
+
+  /**
+   * Return a list containing all of the directives and declarations in this
+   * compilation unit, sorted in lexical order.
+   */
+  List<AstNode> get sortedDirectivesAndDeclarations;
+}
+
+/**
+ * A node that declares one or more names within the scope of a compilation
+ * unit.
+ *
+ *    compilationUnitMember ::=
+ *        [ClassDeclaration]
+ *      | [TypeAlias]
+ *      | [FunctionDeclaration]
+ *      | [MethodDeclaration]
+ *      | [VariableDeclaration]
+ *      | [VariableDeclaration]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CompilationUnitMember extends Declaration {}
+
+/**
+ * A conditional expression.
+ *
+ *    conditionalExpression ::=
+ *        [Expression] '?' [Expression] ':' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConditionalExpression extends Expression {
+  /**
+   * Initialize a newly created conditional expression.
+   */
+  factory ConditionalExpression(
+      Expression condition,
+      Token question,
+      Expression thenExpression,
+      Token colon,
+      Expression elseExpression) = ConditionalExpressionImpl;
+
+  /**
+   * Return the token used to separate the then expression from the else
+   * expression.
+   */
+  Token get colon;
+
+  /**
+   * Set the token used to separate the then expression from the else expression
+   * to the given [token].
+   */
+  void set colon(Token token);
+
+  /**
+   * Return the condition used to determine which of the expressions is executed
+   * next.
+   */
+  Expression get condition;
+
+  /**
+   * Set the condition used to determine which of the expressions is executed
+   * next to the given [expression].
+   */
+  void set condition(Expression expression);
+
+  /**
+   * Return the expression that is executed if the condition evaluates to
+   * `false`.
+   */
+  Expression get elseExpression;
+
+  /**
+   * Set the expression that is executed if the condition evaluates to `false`
+   * to the given [expression].
+   */
+  void set elseExpression(Expression expression);
+
+  /**
+   * Return the token used to separate the condition from the then expression.
+   */
+  Token get question;
+
+  /**
+   * Set the token used to separate the condition from the then expression to
+   * the given [token].
+   */
+  void set question(Token token);
+
+  /**
+   * Return the expression that is executed if the condition evaluates to
+   * `true`.
+   */
+  Expression get thenExpression;
+
+  /**
+   * Set the expression that is executed if the condition evaluates to `true` to
+   * the given [expression].
+   */
+  void set thenExpression(Expression expression);
+}
+
+/**
+ * A configuration in either an import or export directive.
+ *
+ *    configuration ::=
+ *        'if' '(' test ')' uri
+ *
+ *    test ::=
+ *        dottedName ('==' stringLiteral)?
+ *
+ *    dottedName ::=
+ *        identifier ('.' identifier)*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Configuration extends AstNode {
+  /**
+   * Initialize a newly created configuration.
+   */
+  factory Configuration(
+      Token ifKeyword,
+      Token leftParenthesis,
+      DottedName name,
+      Token equalToken,
+      StringLiteral value,
+      Token rightParenthesis,
+      StringLiteral libraryUri) = ConfigurationImpl;
+
+  /**
+   * Return the token for the equal operator, or `null` if the condition does
+   * not include an equality test.
+   */
+  Token get equalToken;
+
+  /**
+   * Set the token for the equal operator to the given [token].
+   */
+  void set equalToken(Token token);
+
+  /**
+   * Return the token for the 'if' keyword.
+   */
+  Token get ifKeyword;
+
+  /**
+   * Set the token for the 'if' keyword to the given [token].
+   */
+  void set ifKeyword(Token token);
+
+  /**
+   * Return the token for the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the token for the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the URI of the implementation library to be used if the condition is
+   * true.
+   */
+  StringLiteral get libraryUri;
+
+  /**
+   * Set the URI of the implementation library to be used if the condition is
+   * true to the given [uri].
+   */
+  void set libraryUri(StringLiteral uri);
+
+  /**
+   * Return the name of the declared variable whose value is being used in the
+   * condition.
+   */
+  DottedName get name;
+
+  /**
+   * Set the name of the declared variable whose value is being used in the
+   * condition to the given [name].
+   */
+  void set name(DottedName name);
+
+  /**
+   * Return the token for the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the token for the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+
+  /**
+   * Return the value to which the value of the declared variable will be
+   * compared, or `null` if the condition does not include an equality test.
+   */
+  StringLiteral get value;
+
+  /**
+   * Set the value to which the value of the declared variable will be
+   * compared to the given [value].
+   */
+  void set value(StringLiteral value);
+}
+
+/**
+ * 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])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConstructorDeclaration extends ClassMember {
+  /**
+   * Initialize a newly created constructor declaration. The [externalKeyword]
+   * can be `null` if the constructor is not external. Either or both of the
+   * [comment] and [metadata] can be `null` if the constructor does not have the
+   * corresponding attribute. The [constKeyword] can be `null` if the
+   * constructor cannot be used to create a constant. The [factoryKeyword] can
+   * be `null` if the constructor is not a factory. The [period] and [name] can
+   * both be `null` if the constructor is not a named constructor. The
+   * [separator] can be `null` if the constructor does not have any initializers
+   * and does not redirect to a different constructor. The list of
+   * [initializers] can be `null` if the constructor does not have any
+   * initializers. The [redirectedConstructor] can be `null` if the constructor
+   * does not redirect to a different constructor. The [body] can be `null` if
+   * the constructor does not have a body.
+   */
+  factory ConstructorDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      Token externalKeyword,
+      Token constKeyword,
+      Token factoryKeyword,
+      Identifier returnType,
+      Token period,
+      SimpleIdentifier name,
+      FormalParameterList parameters,
+      Token separator,
+      List<ConstructorInitializer> initializers,
+      ConstructorName redirectedConstructor,
+      FunctionBody body) = ConstructorDeclarationImpl;
+
+  /**
+   * Return the body of the constructor, or `null` if the constructor does not
+   * have a body.
+   */
+  FunctionBody get body;
+
+  /**
+   * Set the body of the constructor to the given [functionBody].
+   */
+  void set body(FunctionBody functionBody);
+
+  /**
+   * Return the token for the 'const' keyword, or `null` if the constructor is
+   * not a const constructor.
+   */
+  Token get constKeyword;
+
+  /**
+   * Set the token for the 'const' keyword to the given [token].
+   */
+  void set constKeyword(Token token);
+
+  @override
+  ConstructorElement get element;
+
+  /**
+   * Set the element associated with this constructor to the given [element].
+   */
+  void set element(ConstructorElement element);
+
+  /**
+   * Return the token for the 'external' keyword to the given [token].
+   */
+  Token get externalKeyword;
+
+  /**
+   * Set the token for the 'external' keyword, or `null` if the constructor
+   * is not external.
+   */
+  void set externalKeyword(Token token);
+
+  /**
+   * Return the token for the 'factory' keyword, or `null` if the constructor is
+   * not a factory constructor.
+   */
+  Token get factoryKeyword;
+
+  /**
+   * Set the token for the 'factory' keyword to the given [token].
+   */
+  void set factoryKeyword(Token token);
+
+  /**
+   * Return the initializers associated with the constructor.
+   */
+  NodeList<ConstructorInitializer> get initializers;
+
+  /**
+   * Return the name of the constructor, or `null` if the constructor being
+   * declared is unnamed.
+   */
+  SimpleIdentifier get name;
+
+  /**
+   * Set the name of the constructor to the given [identifier].
+   */
+  void set name(SimpleIdentifier identifier);
+
+  /**
+   * Return the parameters associated with the constructor.
+   */
+  FormalParameterList get parameters;
+
+  /**
+   * Set the parameters associated with the constructor to the given list of
+   * [parameters].
+   */
+  void set parameters(FormalParameterList parameters);
+
+  /**
+   * Return the token for the period before the constructor name, or `null` if
+   * the constructor being declared is unnamed.
+   */
+  Token get period;
+
+  /**
+   * Set the token for the period before the constructor name to the given
+   * [token].
+   */
+  void set period(Token token);
+
+  /**
+   * Return the name of the constructor to which this constructor will be
+   * redirected, or `null` if this is not a redirecting factory constructor.
+   */
+  ConstructorName get redirectedConstructor;
+
+  /**
+   * Set the name of the constructor to which this constructor will be
+   * redirected to the given [redirectedConstructor] name.
+   */
+  void set redirectedConstructor(ConstructorName redirectedConstructor);
+
+  /**
+   * Return the type of object being created. This can be different than the
+   * type in which the constructor is being declared if the constructor is the
+   * implementation of a factory constructor.
+   */
+  Identifier get returnType;
+
+  /**
+   * Set the type of object being created to the given [typeName].
+   */
+  void set returnType(Identifier typeName);
+
+  /**
+   * Return the token for the separator (colon or equals) before the initializer
+   * list or redirection, or `null` if there are no initializers.
+   */
+  Token get separator;
+
+  /**
+   * Set the token for the separator (colon or equals) before the initializer
+   * list or redirection to the given [token].
+   */
+  void set separator(Token token);
+}
+
+/**
+ * The initialization of a field within a constructor's initialization list.
+ *
+ *    fieldInitializer ::=
+ *        ('this' '.')? [SimpleIdentifier] '=' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConstructorFieldInitializer extends ConstructorInitializer {
+  /**
+   * Initialize a newly created field initializer to initialize the field with
+   * the given name to the value of the given expression. The [thisKeyword] and
+   * [period] can be `null` if the 'this' keyword was not specified.
+   */
+  factory ConstructorFieldInitializer(
+      Token thisKeyword,
+      Token period,
+      SimpleIdentifier fieldName,
+      Token equals,
+      Expression expression) = ConstructorFieldInitializerImpl;
+
+  /**
+   * Return the token for the equal sign between the field name and the
+   * expression.
+   */
+  Token get equals;
+
+  /**
+   * Set the token for the equal sign between the field name and the
+   * expression to the given [token].
+   */
+  void set equals(Token token);
+
+  /**
+   * Return the expression computing the value to which the field will be
+   * initialized.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression computing the value to which the field will be
+   * initialized to the given [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the name of the field being initialized.
+   */
+  SimpleIdentifier get fieldName;
+
+  /**
+   * Set the name of the field being initialized to the given [identifier].
+   */
+  void set fieldName(SimpleIdentifier identifier);
+
+  /**
+   * Return the token for the period after the 'this' keyword, or `null` if
+   * there is no 'this' keyword.
+   */
+  Token get period;
+
+  /**
+   * Set the token for the period after the 'this' keyword to the given [token].
+   */
+  void set period(Token token);
+
+  /**
+   * Return the token for the 'this' keyword, or `null` if there is no 'this'
+   * keyword.
+   */
+  Token get thisKeyword;
+
+  /**
+   * Set the token for the 'this' keyword to the given [token].
+   */
+  void set thisKeyword(Token token);
+}
+
+/**
+ * A node that can occur in the initializer list of a constructor declaration.
+ *
+ *    constructorInitializer ::=
+ *        [SuperConstructorInvocation]
+ *      | [ConstructorFieldInitializer]
+ *      | [RedirectingConstructorInvocation]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConstructorInitializer extends AstNode {}
+
+/**
+ * The name of a constructor.
+ *
+ *    constructorName ::=
+ *        type ('.' identifier)?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ConstructorName extends AstNode {
+  /**
+   * Initialize a newly created constructor name. The [period] and [name] can be
+   * `null` if the constructor being named is the unnamed constructor.
+   */
+  factory ConstructorName(TypeName type, Token period, SimpleIdentifier name) =
+      ConstructorNameImpl;
+
+  /**
+   * Return the name of the constructor, or `null` if the specified constructor
+   * is the unnamed constructor.
+   */
+  SimpleIdentifier get name;
+
+  /**
+   * Set the name of the constructor to the given [name].
+   */
+  void set name(SimpleIdentifier name);
+
+  /**
+   * Return the token for the period before the constructor name, or `null` if
+   * the specified constructor is the unnamed constructor.
+   */
+  Token get period;
+
+  /**
+   * Set the token for the period before the constructor name to the given
+   * [token].
+   */
+  void set period(Token token);
+
+  /**
+   * Return the element associated with this constructor name based on static
+   * type information, or `null` if the AST structure has not been resolved or
+   * if this constructor name could not be resolved.
+   */
+  ConstructorElement get staticElement;
+
+  /**
+   * Set the element associated with this constructor name based on static type
+   * information to the given [element].
+   */
+  void set staticElement(ConstructorElement element);
+
+  /**
+   * Return the name of the type defining the constructor.
+   */
+  TypeName get type;
+
+  /**
+   * Set the name of the type defining the constructor to the given [type] name.
+   */
+  void set type(TypeName type);
+}
+
+/**
+ * A continue statement.
+ *
+ *    continueStatement ::=
+ *        'continue' [SimpleIdentifier]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ContinueStatement extends Statement {
+  /**
+   * Initialize a newly created continue statement. The [label] can be `null` if
+   * there is no label associated with the statement.
+   */
+  factory ContinueStatement(
+          Token continueKeyword, SimpleIdentifier label, Token semicolon) =
+      ContinueStatementImpl;
+
+  /**
+   * Return the token representing the 'continue' keyword.
+   */
+  Token get continueKeyword;
+
+  /**
+   * Set the token representing the 'continue' keyword to the given [token].
+   */
+  void set continueKeyword(Token token);
+
+  /**
+   * Return the label associated with the statement, or `null` if there is no
+   * label.
+   */
+  SimpleIdentifier get label;
+
+  /**
+   * Set the label associated with the statement to the given [identifier].
+   */
+  void set label(SimpleIdentifier identifier);
+
+  /**
+   * Return the semicolon terminating the statement.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the node to which this continue statement is continuing. This will
+   * be either a [Statement] (in the case of continuing a loop), a
+   * [SwitchMember] (in the case of continuing from one switch case to another),
+   * or `null` if the AST has not yet been resolved or if the target could not
+   * be resolved. Note that if the source code has errors, the target might be
+   * invalid (e.g. the target may be in an enclosing function).
+   */
+  AstNode get target;
+
+  /**
+   * Set the node to which this continue statement is continuing to the given
+   * [node].
+   */
+  void set target(AstNode node);
+}
+
+/**
+ * A node that represents the declaration of one or more names. Each declared
+ * name is visible within a name scope.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Declaration extends AnnotatedNode {
+  /**
+   * Return the element associated with this declaration, or `null` if either
+   * this node corresponds to a list of declarations or if the AST structure has
+   * not been resolved.
+   */
+  Element get element;
+}
+
+/**
+ * The declaration of a single identifier.
+ *
+ *    declaredIdentifier ::=
+ *        [Annotation] finalConstVarOrType [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DeclaredIdentifier extends Declaration {
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the declaration does not have the
+   * corresponding attribute. The [keyword] can be `null` if a type name is
+   * given. The [type] must be `null` if the keyword is 'var'.
+   */
+  factory DeclaredIdentifier(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      TypeName type,
+      SimpleIdentifier identifier) = DeclaredIdentifierImpl;
+
+  @override
+  LocalVariableElement get element;
+
+  /**
+   * Return the name of the variable being declared.
+   */
+  SimpleIdentifier get identifier;
+
+  /**
+   * Set the name of the variable being declared to the given [identifier].
+   */
+  void set identifier(SimpleIdentifier identifier);
+
+  /**
+   * Return `true` if this variable was declared with the 'const' modifier.
+   */
+  bool get isConst;
+
+  /**
+   * Return `true` if this variable was declared with the 'final' modifier.
+   * Variables that are declared with the 'const' modifier will return `false`
+   * even though they are implicitly final.
+   */
+  bool get isFinal;
+
+  /**
+   * Return the token representing either the 'final', 'const' or 'var' keyword,
+   * or `null` if no keyword was used.
+   */
+  Token get keyword;
+
+  /**
+   * Set the token representing either the 'final', 'const' or 'var' keyword to
+   * the given [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Return the name of the declared type of the parameter, or `null` if the
+   * parameter does not have a declared type.
+   */
+  TypeName get type;
+
+  /**
+   * Set the name of the declared type of the parameter to the given [typeName].
+   */
+  void set type(TypeName typeName);
+}
+
+/**
+ * A formal parameter with a default value. There are two kinds of parameters
+ * that are both represented by this class: named formal parameters and
+ * positional formal parameters.
+ *
+ *    defaultFormalParameter ::=
+ *        [NormalFormalParameter] ('=' [Expression])?
+ *
+ *    defaultNamedParameter ::=
+ *        [NormalFormalParameter] (':' [Expression])?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DefaultFormalParameter extends FormalParameter {
+  /**
+   * Initialize a newly created default formal parameter. The [separator] and
+   * [defaultValue] can be `null` if there is no default value.
+   */
+  factory DefaultFormalParameter(
+      NormalFormalParameter parameter,
+      ParameterKind kind,
+      Token separator,
+      Expression defaultValue) = DefaultFormalParameterImpl;
+
+  /**
+   * Return the expression computing the default value for the parameter, or
+   * `null` if there is no default value.
+   */
+  Expression get defaultValue;
+
+  /**
+   * Set the expression computing the default value for the parameter to the
+   * given [expression].
+   */
+  void set defaultValue(Expression expression);
+
+  /**
+   * Set the kind of this parameter to the given [kind].
+   */
+  void set kind(ParameterKind kind);
+
+  /**
+   * Return the formal parameter with which the default value is associated.
+   */
+  NormalFormalParameter get parameter;
+
+  /**
+   * Set the formal parameter with which the default value is associated to the
+   * given [formalParameter].
+   */
+  void set parameter(NormalFormalParameter formalParameter);
+
+  /**
+   * Return the token separating the parameter from the default value, or `null`
+   * if there is no default value.
+   */
+  Token get separator;
+
+  /**
+   * Set the token separating the parameter from the default value to the given
+   * [token].
+   */
+  void set separator(Token token);
+}
+
+/**
+ * A node that represents a directive.
+ *
+ *    directive ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ *      | [LibraryDirective]
+ *      | [PartDirective]
+ *      | [PartOfDirective]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Directive extends AnnotatedNode {
+  /**
+   * Return the element associated with this directive, or `null` if the AST
+   * structure has not been resolved or if this directive could not be resolved.
+   */
+  Element get element;
+
+  /**
+   * Set the element associated with this directive to the given [element].
+   */
+  void set element(Element element);
+
+  /**
+   * Return the token representing the keyword that introduces this directive
+   * ('import', 'export', 'library' or 'part').
+   */
+  Token get keyword;
+}
+
+/**
+ * A do statement.
+ *
+ *    doStatement ::=
+ *        'do' [Statement] 'while' '(' [Expression] ')' ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DoStatement extends Statement {
+  /**
+   * Initialize a newly created do loop.
+   */
+  factory DoStatement(
+      Token doKeyword,
+      Statement body,
+      Token whileKeyword,
+      Token leftParenthesis,
+      Expression condition,
+      Token rightParenthesis,
+      Token semicolon) = DoStatementImpl;
+
+  /**
+   * Return the body of the loop.
+   */
+  Statement get body;
+
+  /**
+   * Set the body of the loop to the given [statement].
+   */
+  void set body(Statement statement);
+
+  /**
+   * Return the condition that determines when the loop will terminate.
+   */
+  Expression get condition;
+
+  /**
+   * Set the condition that determines when the loop will terminate to the given
+   * [expression].
+   */
+  void set condition(Expression expression);
+
+  /**
+   * Return the token representing the 'do' keyword.
+   */
+  Token get doKeyword;
+
+  /**
+   * Set the token representing the 'do' keyword to the given [token].
+   */
+  void set doKeyword(Token token);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+
+  /**
+   * Return the semicolon terminating the statement.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the token representing the 'while' keyword.
+   */
+  Token get whileKeyword;
+
+  /**
+   * Set the token representing the 'while' keyword to the given [token].
+   */
+  void set whileKeyword(Token token);
+}
+
+/**
+ * A dotted name, used in a configuration within an import or export directive.
+ *
+ *    dottedName ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DottedName extends AstNode {
+  /**
+   * Initialize a newly created dotted name.
+   */
+  factory DottedName(List<SimpleIdentifier> components) = DottedNameImpl;
+
+  /**
+   * Return the components of the identifier.
+   */
+  NodeList<SimpleIdentifier> get components;
+}
+
+/**
+ * A floating point literal expression.
+ *
+ *    doubleLiteral ::=
+ *        decimalDigit+ ('.' decimalDigit*)? exponent?
+ *      | '.' decimalDigit+ exponent?
+ *
+ *    exponent ::=
+ *        ('e' | 'E') ('+' | '-')? decimalDigit+
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DoubleLiteral extends Literal {
+  /**
+   * Initialize a newly created floating point literal.
+   */
+  factory DoubleLiteral(Token literal, double value) = DoubleLiteralImpl;
+
+  /**
+   * Return the token representing the literal.
+   */
+  Token get literal;
+
+  /**
+   * Set the token representing the literal to the given [token].
+   */
+  void set literal(Token token);
+
+  /**
+   * Return the value of the literal.
+   */
+  double get value;
+
+  /**
+   * Set the value of the literal to the given [value].
+   */
+  void set value(double value);
+}
+
+/**
+ * An empty function body, which can only appear in constructors or abstract
+ * methods.
+ *
+ *    emptyFunctionBody ::=
+ *        ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class EmptyFunctionBody extends FunctionBody {
+  /**
+   * Initialize a newly created function body.
+   */
+  factory EmptyFunctionBody(Token semicolon) = EmptyFunctionBodyImpl;
+
+  /**
+   * Return the token representing the semicolon that marks the end of the
+   * function body.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the token representing the semicolon that marks the end of the
+   * function body to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * An empty statement.
+ *
+ *    emptyStatement ::=
+ *        ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class EmptyStatement extends Statement {
+  /**
+   * Initialize a newly created empty statement.
+   */
+  factory EmptyStatement(Token semicolon) = EmptyStatementImpl;
+
+  /**
+   * Return the semicolon terminating the statement.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * The declaration of an enum constant.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class EnumConstantDeclaration extends Declaration {
+  /**
+   * Initialize a newly created enum constant declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the constant does not have the
+   * corresponding attribute. (Technically, enum constants cannot have metadata,
+   * but we allow it for consistency.)
+   */
+  factory EnumConstantDeclaration(
+          Comment comment, List<Annotation> metadata, SimpleIdentifier name) =
+      EnumConstantDeclarationImpl;
+
+  /**
+   * Return the name of the constant.
+   */
+  SimpleIdentifier get name;
+
+  /**
+   * Set the name of the constant to the given [name].
+   */
+  void set name(SimpleIdentifier name);
+}
+
+/**
+ * The declaration of an enumeration.
+ *
+ *    enumType ::=
+ *        metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class EnumDeclaration extends NamedCompilationUnitMember {
+  /**
+   * Initialize a newly created enumeration declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the declaration does not have the
+   * corresponding attribute. The list of [constants] must contain at least one
+   * value.
+   */
+  factory EnumDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      Token enumKeyword,
+      SimpleIdentifier name,
+      Token leftBracket,
+      List<EnumConstantDeclaration> constants,
+      Token rightBracket) = EnumDeclarationImpl;
+
+  /**
+   * Return the enumeration constants being declared.
+   */
+  NodeList<EnumConstantDeclaration> get constants;
+
+  @override
+  ClassElement get element;
+
+  /**
+   * Return the 'enum' keyword.
+   */
+  Token get enumKeyword;
+
+  /**
+   * Set the 'enum' keyword to the given [token].
+   */
+  void set enumKeyword(Token token);
+
+  /**
+   * Return the left curly bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the left curly bracket to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the right curly bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Set the right curly bracket to the given [token].
+   */
+  void set rightBracket(Token token);
+}
+
+/**
+ * An export directive.
+ *
+ *    exportDirective ::=
+ *        [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ExportDirective extends NamespaceDirective {
+  /**
+   * Initialize a newly created export directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute. The list of [combinators] can be `null` if there
+   * are no combinators.
+   */
+  factory ExportDirective(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      StringLiteral libraryUri,
+      List<Configuration> configurations,
+      List<Combinator> combinators,
+      Token semicolon) = ExportDirectiveImpl;
+}
+
+/**
+ * A node that represents an expression.
+ *
+ *    expression ::=
+ *        [AssignmentExpression]
+ *      | [ConditionalExpression] cascadeSection*
+ *      | [ThrowExpression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Expression extends AstNode {
+  /**
+   * An empty list of expressions.
+   */
+  static const List<Expression> EMPTY_LIST = const <Expression>[];
+
+  /**
+   * Return the best parameter element information available for this
+   * expression. If type propagation was able to find a better parameter element
+   * than static analysis, that type will be returned. Otherwise, the result of
+   * static analysis will be returned.
+   */
+  ParameterElement get bestParameterElement;
+
+  /**
+   * Return the best type information available for this expression. If type
+   * propagation was able to find a better type than static analysis, that type
+   * will be returned. Otherwise, the result of static analysis will be
+   * returned. If no type analysis has been performed, then the type 'dynamic'
+   * will be returned.
+   */
+  DartType get bestType;
+
+  /**
+   * Return `true` if this expression is syntactically valid for the LHS of an
+   * [AssignmentExpression].
+   */
+  bool get isAssignable;
+
+  /**
+   * Return the precedence of this expression. The precedence is a positive
+   * integer value that defines how the source code is parsed into an AST. For
+   * example `a * b + c` is parsed as `(a * b) + c` because the precedence of
+   * `*` is greater than the precedence of `+`.
+   *
+   * Clients should not assume that returned values will stay the same, they
+   * might change as result of specification change. Only relative order should
+   * be used.
+   */
+  int get precedence;
+
+  /**
+   * If this expression is an argument to an invocation, and the AST structure
+   * has been resolved, and the function being invoked is known based on
+   * propagated type information, and this expression corresponds to one of the
+   * parameters of the function being invoked, then return the parameter element
+   * representing the parameter to which the value of this expression will be
+   * bound. Otherwise, return `null`.
+   */
+  ParameterElement get propagatedParameterElement;
+
+  /**
+   * Return the propagated type of this expression, or `null` if type
+   * propagation has not been performed on the AST structure.
+   */
+  DartType get propagatedType;
+
+  /**
+   * Set the propagated type of this expression to the given [type].
+   */
+  void set propagatedType(DartType type);
+
+  /**
+   * If this expression is an argument to an invocation, and the AST structure
+   * has been resolved, and the function being invoked is known based on static
+   * type information, and this expression corresponds to one of the parameters
+   * of the function being invoked, then return the parameter element
+   * representing the parameter to which the value of this expression will be
+   * bound. Otherwise, return `null`.
+   */
+  ParameterElement get staticParameterElement;
+
+  /**
+   * Return the static type of this expression, or `null` if the AST structure
+   * has not been resolved.
+   */
+  DartType get staticType;
+
+  /**
+   * Set the static type of this expression to the given [type].
+   */
+  void set staticType(DartType type);
+}
+
+/**
+ * A function body consisting of a single expression.
+ *
+ *    expressionFunctionBody ::=
+ *        'async'? '=>' [Expression] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ExpressionFunctionBody extends FunctionBody {
+  /**
+   * Initialize a newly created function body consisting of a block of
+   * statements. The [keyword] can be `null` if the function body is not an
+   * async function body.
+   */
+  factory ExpressionFunctionBody(Token keyword, Token functionDefinition,
+      Expression expression, Token semicolon) = ExpressionFunctionBodyImpl;
+
+  /**
+   * Return the expression representing the body of the function.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression representing the body of the function to the given
+   * [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the token introducing the expression that represents the body of the
+   * function.
+   */
+  Token get functionDefinition;
+
+  /**
+   * Set the token introducing the expression that represents the body of the
+   * function to the given [token].
+   */
+  void set functionDefinition(Token token);
+
+  /**
+   * Set token representing the 'async' or 'sync' keyword to the given [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Return the semicolon terminating the statement.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * An expression used as a statement.
+ *
+ *    expressionStatement ::=
+ *        [Expression]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ExpressionStatement extends Statement {
+  /**
+   * Initialize a newly created expression statement.
+   */
+  factory ExpressionStatement(Expression expression, Token semicolon) =
+      ExpressionStatementImpl;
+
+  /**
+   * Return the expression that comprises the statement.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression that comprises the statement to the given [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the semicolon terminating the statement, or `null` if the expression is a
+   * function expression and therefore isn't followed by a semicolon.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * The "extends" clause in a class declaration.
+ *
+ *    extendsClause ::=
+ *        'extends' [TypeName]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ExtendsClause extends AstNode {
+  /**
+   * Initialize a newly created extends clause.
+   */
+  factory ExtendsClause(Token extendsKeyword, TypeName superclass) =
+      ExtendsClauseImpl;
+
+  /**
+   * Return the token representing the 'extends' keyword.
+   */
+  Token get extendsKeyword;
+
+  /**
+   * Set the token representing the 'extends' keyword to the given [token].
+   */
+  void set extendsKeyword(Token token);
+
+  /**
+   * Return the name of the class that is being extended.
+   */
+  TypeName get superclass;
+
+  /**
+   * Set the name of the class that is being extended to the given [name].
+   */
+  void set superclass(TypeName name);
+}
+
+/**
+ * The declaration of one or more fields of the same type.
+ *
+ *    fieldDeclaration ::=
+ *        'static'? [VariableDeclarationList] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FieldDeclaration extends ClassMember {
+  /**
+   * Initialize a newly created field declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the declaration does not have the
+   * corresponding attribute. The [staticKeyword] can be `null` if the field is
+   * not a static field.
+   */
+  factory FieldDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      Token staticKeyword,
+      VariableDeclarationList fieldList,
+      Token semicolon) = FieldDeclarationImpl;
+
+  /**
+   * Return the fields being declared.
+   */
+  VariableDeclarationList get fields;
+
+  /**
+   * Set the fields being declared to the given list of [fields].
+   */
+  void set fields(VariableDeclarationList fields);
+
+  /**
+   * Return `true` if the fields are declared to be static.
+   */
+  bool get isStatic;
+
+  /**
+   * Return the semicolon terminating the declaration.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the declaration to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the token representing the 'static' keyword, or `null` if the fields
+   * are not static.
+   */
+  Token get staticKeyword;
+
+  /**
+   * Set the token representing the 'static' keyword to the given [token].
+   */
+  void set staticKeyword(Token token);
+}
+
+/**
+ * A field formal parameter.
+ *
+ *    fieldFormalParameter ::=
+ *        ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+ *        'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FieldFormalParameter extends NormalFormalParameter {
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute. The [keyword] can be `null` if there is a type.
+   * The [type] must be `null` if the keyword is 'var'. The [thisKeyword] and
+   * [period] can be `null` if the keyword 'this' was not provided.  The
+   * [parameters] can be `null` if this is not a function-typed field formal
+   * parameter.
+   */
+  factory FieldFormalParameter(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      TypeName type,
+      Token thisKeyword,
+      Token period,
+      SimpleIdentifier identifier,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters) = FieldFormalParameterImpl;
+
+  /**
+   * Return the token representing either the 'final', 'const' or 'var' keyword,
+   * or `null` if no keyword was used.
+   */
+  Token get keyword;
+
+  /**
+   * Set the token representing either the 'final', 'const' or 'var' keyword to
+   * the given [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Return the parameters of the function-typed parameter, or `null` if this is
+   * not a function-typed field formal parameter.
+   */
+  FormalParameterList get parameters;
+
+  /**
+   * Set the parameters of the function-typed parameter to the given
+   * [parameters].
+   */
+  void set parameters(FormalParameterList parameters);
+
+  /**
+   * Return the token representing the period.
+   */
+  Token get period;
+
+  /**
+   * Set the token representing the period to the given [token].
+   */
+  void set period(Token token);
+
+  /**
+   * Return the token representing the 'this' keyword.
+   */
+  Token get thisKeyword;
+
+  /**
+   * Set the token representing the 'this' keyword to the given [token].
+   */
+  void set thisKeyword(Token token);
+
+  /**
+   * Return the name of the declared type of the parameter, or `null` if the
+   * parameter does not have a declared type. Note that if this is a
+   * function-typed field formal parameter this is the return type of the
+   * function.
+   */
+  TypeName get type;
+
+  /**
+   * Set the name of the declared type of the parameter to the given [typeName].
+   */
+  void set type(TypeName typeName);
+
+  /**
+   * Return the type parameters associated with this method, or `null` if this
+   * method is not a generic method.
+   */
+  TypeParameterList get typeParameters;
+
+  /**
+   * Set the type parameters associated with this method to the given
+   * [typeParameters].
+   */
+  void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * A for-each statement.
+ *
+ *    forEachStatement ::=
+ *        'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
+ *      | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ForEachStatement extends Statement {
+  /**
+   * Initialize a newly created for-each statement whose loop control variable
+   * is declared internally (in the for-loop part). The [awaitKeyword] can be
+   * `null` if this is not an asynchronous for loop.
+   */
+  factory ForEachStatement.withDeclaration(
+      Token awaitKeyword,
+      Token forKeyword,
+      Token leftParenthesis,
+      DeclaredIdentifier loopVariable,
+      Token inKeyword,
+      Expression iterator,
+      Token rightParenthesis,
+      Statement body) = ForEachStatementImpl.withDeclaration;
+
+  /**
+   * Initialize a newly created for-each statement whose loop control variable
+   * is declared outside the for loop. The [awaitKeyword] can be `null` if this
+   * is not an asynchronous for loop.
+   */
+  factory ForEachStatement.withReference(
+      Token awaitKeyword,
+      Token forKeyword,
+      Token leftParenthesis,
+      SimpleIdentifier identifier,
+      Token inKeyword,
+      Expression iterator,
+      Token rightParenthesis,
+      Statement body) = ForEachStatementImpl.withReference;
+
+  /**
+   * Return the token representing the 'await' keyword, or `null` if there is no
+   * 'await' keyword.
+   */
+  Token get awaitKeyword;
+
+  /**
+   * Set the token representing the 'await' keyword to the given [token].
+   */
+  void set awaitKeyword(Token token);
+
+  /**
+   * Return the body of the loop.
+   */
+  Statement get body;
+
+  /**
+   * Set the body of the loop to the given [statement].
+   */
+  void set body(Statement statement);
+
+  /**
+   * Return the token representing the 'for' keyword.
+   */
+  Token get forKeyword;
+
+  /**
+   * Set the token representing the 'for' keyword to the given [token].
+   */
+  void set forKeyword(Token token);
+
+  /**
+   * Return the loop variable, or `null` if the loop variable is declared in the
+   * 'for'.
+   */
+  SimpleIdentifier get identifier;
+
+  /**
+   * Set the loop variable to the given [identifier].
+   */
+  void set identifier(SimpleIdentifier identifier);
+
+  /**
+   * Return the token representing the 'in' keyword.
+   */
+  Token get inKeyword;
+
+  /**
+   * Set the token representing the 'in' keyword to the given [token].
+   */
+  void set inKeyword(Token token);
+
+  /**
+   * Return the expression evaluated to produce the iterator.
+   */
+  Expression get iterable;
+
+  /**
+   * Set the expression evaluated to produce the iterator to the given
+   * [expression].
+   */
+  void set iterable(Expression expression);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the declaration of the loop variable, or `null` if the loop variable
+   * is a simple identifier.
+   */
+  DeclaredIdentifier get loopVariable;
+
+  /**
+   * Set the declaration of the loop variable to the given [variable].
+   */
+  void set loopVariable(DeclaredIdentifier variable);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+}
+
+/**
+ * A node representing a parameter to a function.
+ *
+ *    formalParameter ::=
+ *        [NormalFormalParameter]
+ *      | [DefaultFormalParameter]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FormalParameter extends AstNode {
+  /**
+   * Return the element representing this parameter, or `null` if this parameter
+   * has not been resolved.
+   */
+  ParameterElement get element;
+
+  /**
+   * Return the name of the parameter being declared.
+   */
+  SimpleIdentifier get identifier;
+
+  /**
+   * Return `true` if this parameter was declared with the 'const' modifier.
+   */
+  bool get isConst;
+
+  /**
+   * Return `true` if this parameter was declared with the 'final' modifier.
+   * Parameters that are declared with the 'const' modifier will return `false`
+   * even though they are implicitly final.
+   */
+  bool get isFinal;
+
+  /**
+   * Return the kind of this parameter.
+   */
+  ParameterKind get kind;
+
+  /**
+   * Return the annotations associated with this parameter.
+   */
+  NodeList<Annotation> get metadata;
+}
+
+/**
+ * The formal parameter list of a method declaration, function declaration, or
+ * function type alias.
+ *
+ * While the grammar requires all optional formal parameters to follow all of
+ * the normal formal parameters and at most one grouping of optional formal
+ * parameters, this class does not enforce those constraints. All parameters are
+ * 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])* '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FormalParameterList extends AstNode {
+  /**
+   * Initialize a newly created parameter list. The list of [parameters] can be
+   * `null` if there are no parameters. The [leftDelimiter] and [rightDelimiter]
+   * can be `null` if there are no optional parameters.
+   */
+  factory FormalParameterList(
+      Token leftParenthesis,
+      List<FormalParameter> parameters,
+      Token leftDelimiter,
+      Token rightDelimiter,
+      Token rightParenthesis) = FormalParameterListImpl;
+
+  /**
+   * Return the left square bracket ('[') or left curly brace ('{') introducing
+   * the optional parameters, or `null` if there are no optional parameters.
+   */
+  Token get leftDelimiter;
+
+  /**
+   * Set the left square bracket ('[') or left curly brace ('{') introducing
+   * the optional parameters to the given [token].
+   */
+  void set leftDelimiter(Token token);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return a list containing the elements representing the parameters in this
+   * list. The list will contain `null`s if the parameters in this list have not
+   * been resolved.
+   */
+  List<ParameterElement> get parameterElements;
+
+  /**
+   * Return the parameters associated with the method.
+   */
+  NodeList<FormalParameter> get parameters;
+
+  /**
+   * Return the right square bracket (']') or right curly brace ('}') terminating the
+   * optional parameters, or `null` if there are no optional parameters.
+   */
+  Token get rightDelimiter;
+
+  /**
+   * Set the right square bracket (']') or right curly brace ('}') terminating the
+   * optional parameters to the given [token].
+   */
+  void set rightDelimiter(Token token);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+}
+
+/**
+ * A for statement.
+ *
+ *    forStatement ::=
+ *        'for' '(' forLoopParts ')' [Statement]
+ *
+ *    forLoopParts ::=
+ *        forInitializerStatement ';' [Expression]? ';' [Expression]?
+ *
+ *    forInitializerStatement ::=
+ *        [DefaultFormalParameter]
+ *      | [Expression]?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ForStatement extends Statement {
+  /**
+   * Initialize a newly created for statement. Either the [variableList] or the
+   * [initialization] must be `null`. Either the [condition] and the list of
+   * [updaters] can be `null` if the loop does not have the corresponding
+   * attribute.
+   */
+  factory ForStatement(
+      Token forKeyword,
+      Token leftParenthesis,
+      VariableDeclarationList variableList,
+      Expression initialization,
+      Token leftSeparator,
+      Expression condition,
+      Token rightSeparator,
+      List<Expression> updaters,
+      Token rightParenthesis,
+      Statement body) = ForStatementImpl;
+
+  /**
+   * Return the body of the loop.
+   */
+  Statement get body;
+
+  /**
+   * Set the body of the loop to the given [statement].
+   */
+  void set body(Statement statement);
+
+  /**
+   * Return the condition used to determine when to terminate the loop, or
+   * `null` if there is no condition.
+   */
+  Expression get condition;
+
+  /**
+   * Set the condition used to determine when to terminate the loop to the given
+   * [expression].
+   */
+  void set condition(Expression expression);
+
+  /**
+   * Return the token representing the 'for' keyword.
+   */
+  Token get forKeyword;
+
+  /**
+   * Set the token representing the 'for' keyword to the given [token].
+   */
+  void set forKeyword(Token token);
+
+  /**
+   * Return the initialization expression, or `null` if there is no
+   * initialization expression.
+   */
+  Expression get initialization;
+
+  /**
+   * Set the initialization expression to the given [expression].
+   */
+  void set initialization(Expression initialization);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the semicolon separating the initializer and the condition.
+   */
+  Token get leftSeparator;
+
+  /**
+   * Set the semicolon separating the initializer and the condition to the given
+   * [token].
+   */
+  void set leftSeparator(Token token);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+
+  /**
+   * Return the semicolon separating the condition and the updater.
+   */
+  Token get rightSeparator;
+
+  /**
+   * Set the semicolon separating the condition and the updater to the given
+   * [token].
+   */
+  void set rightSeparator(Token token);
+
+  /**
+   * Return the list of expressions run after each execution of the loop body.
+   */
+  NodeList<Expression> get updaters;
+
+  /**
+   * Return the declaration of the loop variables, or `null` if there are no
+   * variables.
+   */
+  VariableDeclarationList get variables;
+
+  /**
+   * Set the declaration of the loop variables to the given [variableList].
+   */
+  void set variables(VariableDeclarationList variableList);
+}
+
+/**
+ * A node representing the body of a function or method.
+ *
+ *    functionBody ::=
+ *        [BlockFunctionBody]
+ *      | [EmptyFunctionBody]
+ *      | [ExpressionFunctionBody]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionBody extends AstNode {
+  /**
+   * Return `true` if this function body is asynchronous.
+   */
+  bool get isAsynchronous;
+
+  /**
+   * Return `true` if this function body is a generator.
+   */
+  bool get isGenerator;
+
+  /**
+   * Return `true` if this function body is synchronous.
+   */
+  bool get isSynchronous;
+
+  /**
+   * Return the token representing the 'async' or 'sync' keyword, or `null` if
+   * there is no such keyword.
+   */
+  Token get keyword;
+
+  /**
+   * Return the star following the 'async' or 'sync' keyword, or `null` if there
+   * is no star.
+   */
+  Token get star;
+
+  /**
+   * If [variable] is a local variable or parameter declared anywhere within
+   * the top level function or method containing this [FunctionBody], return a
+   * boolean indicating whether [variable] is potentially mutated within a
+   * local function other than the function in which it is declared.
+   *
+   * If [variable] is not a local variable or parameter declared within the top
+   * level function or method containing this [FunctionBody], return `false`.
+   *
+   * Throws an exception if resolution has not yet been performed.
+   */
+  bool isPotentiallyMutatedInClosure(VariableElement variable);
+
+  /**
+   * If [variable] is a local variable or parameter declared anywhere within
+   * the top level function or method containing this [FunctionBody], return a
+   * boolean indicating whether [variable] is potentially mutated within the
+   * scope of its declaration.
+   *
+   * If [variable] is not a local variable or parameter declared within the top
+   * level function or method containing this [FunctionBody], return `false`.
+   *
+   * Throws an exception if resolution has not yet been performed.
+   */
+  bool isPotentiallyMutatedInScope(VariableElement variable);
+}
+
+/**
+ * A top-level declaration.
+ *
+ *    functionDeclaration ::=
+ *        'external' functionSignature
+ *      | functionSignature [FunctionBody]
+ *
+ *    functionSignature ::=
+ *        [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionDeclaration extends NamedCompilationUnitMember {
+  /**
+   * Initialize a newly created function declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the function does not have the
+   * corresponding attribute. The [externalKeyword] can be `null` if the
+   * function is not an external function. The [returnType] can be `null` if no
+   * return type was specified. The [propertyKeyword] can be `null` if the
+   * function is neither a getter or a setter.
+   */
+  factory FunctionDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      Token externalKeyword,
+      TypeName returnType,
+      Token propertyKeyword,
+      SimpleIdentifier name,
+      FunctionExpression functionExpression) = FunctionDeclarationImpl;
+
+  @override
+  ExecutableElement get element;
+
+  /**
+   * Return the token representing the 'external' keyword, or `null` if this is
+   * not an external function.
+   */
+  Token get externalKeyword;
+
+  /**
+   * Set the token representing the 'external' keyword to the given [token].
+   */
+  void set externalKeyword(Token token);
+
+  /**
+   * Return the function expression being wrapped.
+   */
+  FunctionExpression get functionExpression;
+
+  /**
+   * Set the function expression being wrapped to the given
+   * [functionExpression].
+   */
+  void set functionExpression(FunctionExpression functionExpression);
+
+  /**
+   * Return `true` if this function declares a getter.
+   */
+  bool get isGetter;
+
+  /**
+   * Return `true` if this function declares a setter.
+   */
+  bool get isSetter;
+
+  /**
+   * Return the token representing the 'get' or 'set' keyword, or `null` if this
+   * is a function declaration rather than a property declaration.
+   */
+  Token get propertyKeyword;
+
+  /**
+   * Set the token representing the 'get' or 'set' keyword to the given [token].
+   */
+  void set propertyKeyword(Token token);
+
+  /**
+   * Return the return type of the function, or `null` if no return type was
+   * declared.
+   */
+  TypeName get returnType;
+
+  /**
+   * Set the return type of the function to the given [returnType].
+   */
+  void set returnType(TypeName returnType);
+}
+
+/**
+ * A [FunctionDeclaration] used as a statement.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionDeclarationStatement extends Statement {
+  /**
+   * Initialize a newly created function declaration statement.
+   */
+  factory FunctionDeclarationStatement(
+          FunctionDeclaration functionDeclaration) =
+      FunctionDeclarationStatementImpl;
+
+  /**
+   * Return the function declaration being wrapped.
+   */
+  FunctionDeclaration get functionDeclaration;
+
+  /**
+   * Set the function declaration being wrapped to the given
+   * [functionDeclaration].
+   */
+  void set functionDeclaration(FunctionDeclaration functionDeclaration);
+}
+
+/**
+ * A function expression.
+ *
+ *    functionExpression ::=
+ *        [TypeParameterList]? [FormalParameterList] [FunctionBody]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionExpression extends Expression {
+  /**
+   * Initialize a newly created function declaration.
+   */
+  factory FunctionExpression(
+      TypeParameterList typeParameters,
+      FormalParameterList parameters,
+      FunctionBody body) = FunctionExpressionImpl;
+
+  /**
+   * Return the body of the function, or `null` if this is an external function.
+   */
+  FunctionBody get body;
+
+  /**
+   * Set the body of the function to the given [functionBody].
+   */
+  void set body(FunctionBody functionBody);
+
+  /**
+   * Return the element associated with the function, or `null` if the AST
+   * structure has not been resolved.
+   */
+  ExecutableElement get element;
+
+  /**
+   * Set the element associated with the function to the given [element].
+   */
+  void set element(ExecutableElement element);
+
+  /**
+   * Return the parameters associated with the function.
+   */
+  FormalParameterList get parameters;
+
+  /**
+   * Set the parameters associated with the function to the given list of
+   * [parameters].
+   */
+  void set parameters(FormalParameterList parameters);
+
+  /**
+   * Return the type parameters associated with this method, or `null` if this
+   * method is not a generic method.
+   */
+  TypeParameterList get typeParameters;
+
+  /**
+   * Set the type parameters associated with this method to the given
+   * [typeParameters].
+   */
+  void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * The invocation of a function resulting from evaluating an expression.
+ * Invocations of methods and other forms of functions are represented by
+ * [MethodInvocation] nodes. Invocations of getters and setters are represented
+ * by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+ *
+ *    functionExpressionInvocation ::=
+ *        [Expression] [TypeArgumentList]? [ArgumentList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionExpressionInvocation extends InvocationExpression {
+  /**
+   * Initialize a newly created function expression invocation.
+   */
+  factory FunctionExpressionInvocation(
+      Expression function,
+      TypeArgumentList typeArguments,
+      ArgumentList argumentList) = FunctionExpressionInvocationImpl;
+
+  /**
+   * Set the list of arguments to the method to the given [argumentList].
+   */
+  void set argumentList(ArgumentList argumentList);
+
+  /**
+   * Return the best element available for the function being invoked. If
+   * resolution was able to find a better element based on type propagation,
+   * that element will be returned. Otherwise, the element found using the
+   * result of static analysis will be returned. If resolution has not been
+   * performed, then `null` will be returned.
+   */
+  ExecutableElement get bestElement;
+
+  /**
+   * Return the expression producing the function being invoked.
+   */
+  @override
+  Expression get function;
+
+  /**
+   * Set the expression producing the function being invoked to the given
+   * [expression].
+   */
+  void set function(Expression expression);
+
+  /**
+   * Return the element associated with the function being invoked based on
+   * propagated type information, or `null` if the AST structure has not been
+   * resolved or the function could not be resolved.
+   */
+  ExecutableElement get propagatedElement;
+
+  /**
+   * Set the element associated with the function being invoked based on
+   * propagated type information to the given [element].
+   */
+  void set propagatedElement(ExecutableElement element);
+
+  /**
+   * Return the function type of the method invocation based on the propagated
+   * type information, or `null` if the AST structure has not been resolved, or
+   * if the invoke could not be resolved.
+   *
+   * This will usually be a [FunctionType], but it can also be an
+   * [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);
+
+  /**
+   * Return the element associated with the function being invoked based on
+   * static type information, or `null` if the AST structure has not been
+   * resolved or the function could not be resolved.
+   */
+  ExecutableElement get staticElement;
+
+  /**
+   * Set the element associated with the function being invoked based on static
+   * type information to the given [element].
+   */
+  void set staticElement(ExecutableElement element);
+
+  /**
+   * Return the function type of the method invocation based on the static type
+   * information, or `null` if the AST structure has not been resolved, or if
+   * the invoke could not be resolved.
+   *
+   * This will usually be a [FunctionType], but it can also be an
+   * [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);
+
+  /**
+   * Set the type arguments to be applied to the method being invoked to the
+   * given [typeArguments].
+   */
+  void set typeArguments(TypeArgumentList typeArguments);
+}
+
+/**
+ * A function type alias.
+ *
+ *    functionTypeAlias ::=
+ *        functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+ *
+ *    functionPrefix ::=
+ *        [TypeName]? [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionTypeAlias extends TypeAlias {
+  /**
+   * Initialize a newly created function type alias. Either or both of the
+   * [comment] and [metadata] can be `null` if the function does not have the
+   * corresponding attribute. The [returnType] can be `null` if no return type
+   * was specified. The [typeParameters] can be `null` if the function has no
+   * type parameters.
+   */
+  factory FunctionTypeAlias(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      TypeName returnType,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters,
+      Token semicolon) = FunctionTypeAliasImpl;
+
+  /**
+   * Return the parameters associated with the function type.
+   */
+  FormalParameterList get parameters;
+
+  /**
+   * Set the parameters associated with the function type to the given list of
+   * [parameters].
+   */
+  void set parameters(FormalParameterList parameters);
+
+  /**
+   * Return the name of the return type of the function type being defined, or
+   * `null` if no return type was given.
+   */
+  TypeName get returnType;
+
+  /**
+   * Set the name of the return type of the function type being defined to the
+   * given [typeName].
+   */
+  void set returnType(TypeName typeName);
+
+  /**
+   * Return the type parameters for the function type, or `null` if the function
+   * type does not have any type parameters.
+   */
+  TypeParameterList get typeParameters;
+
+  /**
+   * Set the type parameters for the function type to the given list of
+   * [typeParameters].
+   */
+  void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * A function-typed formal parameter.
+ *
+ *    functionSignature ::=
+ *        [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FunctionTypedFormalParameter extends NormalFormalParameter {
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute. The [returnType] can be `null` if no return type
+   * was specified.
+   */
+  factory FunctionTypedFormalParameter(
+      Comment comment,
+      List<Annotation> metadata,
+      TypeName returnType,
+      SimpleIdentifier identifier,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters) = FunctionTypedFormalParameterImpl;
+
+  /**
+   * Return the parameters of the function-typed parameter.
+   */
+  FormalParameterList get parameters;
+
+  /**
+   * Set the parameters of the function-typed parameter to the given
+   * [parameters].
+   */
+  void set parameters(FormalParameterList parameters);
+
+  /**
+   * Return the return type of the function, or `null` if the function does not
+   * have a return type.
+   */
+  TypeName get returnType;
+
+  /**
+   * Set the return type of the function to the given [type].
+   */
+  void set returnType(TypeName type);
+
+  /**
+   * Return the type parameters associated with this function, or `null` if
+   * this function is not a generic function.
+   */
+  TypeParameterList get typeParameters;
+
+  /**
+   * Set the type parameters associated with this method to the given
+   * [typeParameters].
+   */
+  void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * A combinator that restricts the names being imported to those that are not in
+ * a given list.
+ *
+ *    hideCombinator ::=
+ *        'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class HideCombinator extends Combinator {
+  /**
+   * Initialize a newly created import show combinator.
+   */
+  factory HideCombinator(Token keyword, List<SimpleIdentifier> hiddenNames) =
+      HideCombinatorImpl;
+
+  /**
+   * Return the list of names from the library that are hidden by this
+   * combinator.
+   */
+  NodeList<SimpleIdentifier> get hiddenNames;
+}
+
+/**
+ * A node that represents an identifier.
+ *
+ *    identifier ::=
+ *        [SimpleIdentifier]
+ *      | [PrefixedIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Identifier extends Expression {
+  /**
+   * Return the best element available for this operator. If resolution was able
+   * to find a better element based on type propagation, that element will be
+   * returned. Otherwise, the element found using the result of static analysis
+   * will be returned. If resolution has not been performed, then `null` will be
+   * returned.
+   */
+  Element get bestElement;
+
+  /**
+   * Return the lexical representation of the identifier.
+   */
+  String get name;
+
+  /**
+   * Return the element associated with this identifier based on propagated type
+   * information, or `null` if the AST structure has not been resolved or if
+   * this identifier could not be resolved. One example of the latter case is an
+   * identifier that is not defined within the scope in which it appears.
+   */
+  Element get propagatedElement;
+
+  /**
+   * Return the element associated with this identifier based on static type
+   * information, or `null` if the AST structure has not been resolved or if
+   * this identifier could not be resolved. One example of the latter case is an
+   * identifier that is not defined within the scope in which it appears
+   */
+  Element get staticElement;
+
+  /**
+   * Return `true` if the given [name] is visible only within the library in
+   * which it is declared.
+   */
+  static bool isPrivateName(String name) =>
+      StringUtilities.startsWithChar(name, 0x5F); // '_'
+}
+
+/**
+ * An if statement.
+ *
+ *    ifStatement ::=
+ *        'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class IfStatement extends Statement {
+  /**
+   * Initialize a newly created if statement. The [elseKeyword] and
+   * [elseStatement] can be `null` if there is no else clause.
+   */
+  factory IfStatement(
+      Token ifKeyword,
+      Token leftParenthesis,
+      Expression condition,
+      Token rightParenthesis,
+      Statement thenStatement,
+      Token elseKeyword,
+      Statement elseStatement) = IfStatementImpl;
+
+  /**
+   * Return the condition used to determine which of the statements is executed
+   * next.
+   */
+  Expression get condition;
+
+  /**
+   * Set the condition used to determine which of the statements is executed
+   * next to the given [expression].
+   */
+  void set condition(Expression expression);
+
+  /**
+   * Return the token representing the 'else' keyword, or `null` if there is no
+   * else statement.
+   */
+  Token get elseKeyword;
+
+  /**
+   * Set the token representing the 'else' keyword to the given [token].
+   */
+  void set elseKeyword(Token token);
+
+  /**
+   * Return the statement that is executed if the condition evaluates to
+   * `false`, or `null` if there is no else statement.
+   */
+  Statement get elseStatement;
+
+  /**
+   * Set the statement that is executed if the condition evaluates to `false`
+   * to the given [statement].
+   */
+  void set elseStatement(Statement statement);
+
+  /**
+   * Return the token representing the 'if' keyword.
+   */
+  Token get ifKeyword;
+
+  /**
+   * Set the token representing the 'if' keyword to the given [token].
+   */
+  void set ifKeyword(Token token);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+
+  /**
+   * Return the statement that is executed if the condition evaluates to `true`.
+   */
+  Statement get thenStatement;
+
+  /**
+   * Set the statement that is executed if the condition evaluates to `true` to
+   * the given [statement].
+   */
+  void set thenStatement(Statement statement);
+}
+
+/**
+ * The "implements" clause in an class declaration.
+ *
+ *    implementsClause ::=
+ *        'implements' [TypeName] (',' [TypeName])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ImplementsClause extends AstNode {
+  /**
+   * Initialize a newly created implements clause.
+   */
+  factory ImplementsClause(Token implementsKeyword, List<TypeName> interfaces) =
+      ImplementsClauseImpl;
+
+  /**
+   * Return the token representing the 'implements' keyword.
+   */
+  Token get implementsKeyword;
+
+  /**
+   * Set the token representing the 'implements' keyword to the given [token].
+   */
+  void set implementsKeyword(Token token);
+
+  /**
+   * Return the list of the interfaces that are being implemented.
+   */
+  NodeList<TypeName> get interfaces;
+}
+
+/**
+ * An import directive.
+ *
+ *    importDirective ::=
+ *        [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+ *      | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ImportDirective extends NamespaceDirective {
+  static Comparator<ImportDirective> COMPARATOR =
+      (ImportDirective import1, ImportDirective import2) {
+    //
+    // uri
+    //
+    StringLiteral uri1 = import1.uri;
+    StringLiteral uri2 = import2.uri;
+    String uriStr1 = uri1.stringValue;
+    String uriStr2 = uri2.stringValue;
+    if (uriStr1 != null || uriStr2 != null) {
+      if (uriStr1 == null) {
+        return -1;
+      } else if (uriStr2 == null) {
+        return 1;
+      } else {
+        int compare = uriStr1.compareTo(uriStr2);
+        if (compare != 0) {
+          return compare;
+        }
+      }
+    }
+    //
+    // as
+    //
+    SimpleIdentifier prefix1 = import1.prefix;
+    SimpleIdentifier prefix2 = import2.prefix;
+    String prefixStr1 = prefix1 != null ? prefix1.name : null;
+    String prefixStr2 = prefix2 != null ? prefix2.name : null;
+    if (prefixStr1 != null || prefixStr2 != null) {
+      if (prefixStr1 == null) {
+        return -1;
+      } else if (prefixStr2 == null) {
+        return 1;
+      } else {
+        int compare = prefixStr1.compareTo(prefixStr2);
+        if (compare != 0) {
+          return compare;
+        }
+      }
+    }
+    //
+    // hides and shows
+    //
+    NodeList<Combinator> combinators1 = import1.combinators;
+    List<String> allHides1 = new List<String>();
+    List<String> allShows1 = new List<String>();
+    for (Combinator combinator in combinators1) {
+      if (combinator is HideCombinator) {
+        NodeList<SimpleIdentifier> hides = combinator.hiddenNames;
+        for (SimpleIdentifier simpleIdentifier in hides) {
+          allHides1.add(simpleIdentifier.name);
+        }
+      } else {
+        NodeList<SimpleIdentifier> shows =
+            (combinator as ShowCombinator).shownNames;
+        for (SimpleIdentifier simpleIdentifier in shows) {
+          allShows1.add(simpleIdentifier.name);
+        }
+      }
+    }
+    NodeList<Combinator> combinators2 = import2.combinators;
+    List<String> allHides2 = new List<String>();
+    List<String> allShows2 = new List<String>();
+    for (Combinator combinator in combinators2) {
+      if (combinator is HideCombinator) {
+        NodeList<SimpleIdentifier> hides = combinator.hiddenNames;
+        for (SimpleIdentifier simpleIdentifier in hides) {
+          allHides2.add(simpleIdentifier.name);
+        }
+      } else {
+        NodeList<SimpleIdentifier> shows =
+            (combinator as ShowCombinator).shownNames;
+        for (SimpleIdentifier simpleIdentifier in shows) {
+          allShows2.add(simpleIdentifier.name);
+        }
+      }
+    }
+    // test lengths of combinator lists first
+    if (allHides1.length != allHides2.length) {
+      return allHides1.length - allHides2.length;
+    }
+    if (allShows1.length != allShows2.length) {
+      return allShows1.length - allShows2.length;
+    }
+    // next ensure that the lists are equivalent
+    if (!allHides1.toSet().containsAll(allHides2)) {
+      return -1;
+    }
+    if (!allShows1.toSet().containsAll(allShows2)) {
+      return -1;
+    }
+    return 0;
+  };
+
+  /**
+   * Initialize a newly created import directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the function does not have the
+   * corresponding attribute. The [deferredKeyword] can be `null` if the import
+   * is not deferred. The [asKeyword] and [prefix] can be `null` if the import
+   * does not specify a prefix. The list of [combinators] can be `null` if there
+   * are no combinators.
+   */
+  factory ImportDirective(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      StringLiteral libraryUri,
+      List<Configuration> configurations,
+      Token deferredKeyword,
+      Token asKeyword,
+      SimpleIdentifier prefix,
+      List<Combinator> combinators,
+      Token semicolon) = ImportDirectiveImpl;
+
+  /**
+   * Return the token representing the 'as' keyword, or `null` if the imported
+   * names are not prefixed.
+   */
+  Token get asKeyword;
+
+  /**
+   * Set the token representing the 'as' keyword to the given [token].
+   */
+  void set asKeyword(Token token);
+
+  /**
+   * Return the token representing the 'deferred' keyword, or `null` if the
+   * imported URI is not deferred.
+   */
+  Token get deferredKeyword;
+
+  /**
+   * Set the token representing the 'deferred' keyword to the given [token].
+   */
+  void set deferredKeyword(Token token);
+
+  /**
+   * Return the prefix to be used with the imported names, or `null` if the
+   * imported names are not prefixed.
+   */
+  SimpleIdentifier get prefix;
+
+  /**
+   * Set the prefix to be used with the imported names to the given [identifier].
+   */
+  void set prefix(SimpleIdentifier identifier);
+}
+
+/**
+ * An index expression.
+ *
+ *    indexExpression ::=
+ *        [Expression] '[' [Expression] ']'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class IndexExpression extends Expression {
+  /**
+   * Initialize a newly created index expression.
+   */
+  factory IndexExpression.forCascade(Token period, Token leftBracket,
+      Expression index, Token rightBracket) = IndexExpressionImpl.forCascade;
+
+  /**
+   * Initialize a newly created index expression.
+   */
+  factory IndexExpression.forTarget(Expression target, Token leftBracket,
+      Expression index, Token rightBracket) = IndexExpressionImpl.forTarget;
+
+  /**
+   * Return the auxiliary elements associated with this identifier, or `null` if
+   * this identifier is not in both a getter and setter context. The auxiliary
+   * elements hold the static and propagated elements associated with the getter
+   * context.
+   */
+  // TODO(brianwilkerson) Replace this API.
+  AuxiliaryElements get auxiliaryElements;
+
+  /**
+   * Set the auxiliary elements associated with this identifier to the given
+   * [elements].
+   */
+  // TODO(brianwilkerson) Replace this API.
+  void set auxiliaryElements(AuxiliaryElements elements);
+
+  /**
+   * Return the best element available for this operator. If resolution was able
+   * to find a better element based on type propagation, that element will be
+   * returned. Otherwise, the element found using the result of static analysis
+   * will be returned. If resolution has not been performed, then `null` will be
+   * returned.
+   */
+  MethodElement get bestElement;
+
+  /**
+   * Return the expression used to compute the index.
+   */
+  Expression get index;
+
+  /**
+   * Set the expression used to compute the index to the given [expression].
+   */
+  void set index(Expression expression);
+
+  /**
+   * Return `true` if this expression is cascaded. If it is, then the target of
+   * this expression is not stored locally but is stored in the nearest ancestor
+   * that is a [CascadeExpression].
+   */
+  bool get isCascaded;
+
+  /**
+   * Return the left square bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the left square bracket to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the period ("..") before a cascaded index expression, or `null` if
+   * this index expression is not part of a cascade expression.
+   */
+  Token get period;
+
+  /**
+   * Set the period ("..") before a cascaded index expression to the given
+   * [token].
+   */
+  void set period(Token token);
+
+  /**
+   * Return the element associated with the operator based on the propagated
+   * type of the target, or `null` if the AST structure has not been resolved or
+   * if the operator could not be resolved.
+   */
+  MethodElement get propagatedElement;
+
+  /**
+   * Set the element associated with the operator based on the propagated
+   * type of the target to the given [element].
+   */
+  void set propagatedElement(MethodElement element);
+
+  /**
+   * Return the expression used to compute the object being indexed. If this
+   * index expression is not part of a cascade expression, then this is the same
+   * as [target]. If this index expression is part of a cascade expression, then
+   * the target expression stored with the cascade expression is returned.
+   */
+  Expression get realTarget;
+
+  /**
+   * Return the right square bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Return the element associated with the operator based on the static type of
+   * the target, or `null` if the AST structure has not been resolved or if the
+   * operator could not be resolved.
+   */
+  MethodElement get staticElement;
+
+  /**
+   * Set the element associated with the operator based on the static type of
+   * the target to the given [element].
+   */
+  void set staticElement(MethodElement element);
+
+  /**
+   * Return the expression used to compute the object being indexed, or `null`
+   * if this index expression is part of a cascade expression.
+   *
+   * Use [realTarget] to get the target independent of whether this is part of a
+   * cascade expression.
+   */
+  Expression get target;
+
+  /**
+   * Set the expression used to compute the object being indexed to the given
+   * [expression].
+   */
+  void set target(Expression expression);
+
+  /**
+   * Return `true` if this expression is computing a right-hand value (that is,
+   * if this expression is in a context where the operator '[]' will be
+   * invoked).
+   *
+   * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
+   * are they mutually exclusive. In other words, it is possible for both
+   * methods to return `true` when invoked on the same node.
+   */
+  // TODO(brianwilkerson) Convert this to a getter.
+  bool inGetterContext();
+
+  /**
+   * Return `true` if this expression is computing a left-hand value (that is,
+   * if this expression is in a context where the operator '[]=' will be
+   * invoked).
+   *
+   * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
+   * are they mutually exclusive. In other words, it is possible for both
+   * methods to return `true` when invoked on the same node.
+   */
+  // TODO(brianwilkerson) Convert this to a getter.
+  bool inSetterContext();
+}
+
+/**
+ * An instance creation expression.
+ *
+ *    newExpression ::=
+ *        ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InstanceCreationExpression extends Expression {
+  /**
+   * Initialize a newly created instance creation expression.
+   */
+  factory InstanceCreationExpression(
+      Token keyword,
+      ConstructorName constructorName,
+      ArgumentList argumentList) = InstanceCreationExpressionImpl;
+
+  /**
+   * Return the list of arguments to the constructor.
+   */
+  ArgumentList get argumentList;
+
+  /**
+   * Set the list of arguments to the constructor to the given [argumentList].
+   */
+  void set argumentList(ArgumentList argumentList);
+
+  /**
+   * Return the name of the constructor to be invoked.
+   */
+  ConstructorName get constructorName;
+
+  /**
+   * Set the name of the constructor to be invoked to the given [name].
+   */
+  void set constructorName(ConstructorName name);
+
+  /**
+   * Return `true` if this creation expression is used to invoke a constant
+   * constructor.
+   */
+  bool get isConst;
+
+  /**
+   * Return the 'new' or 'const' keyword used to indicate how an object should
+   * be created.
+   */
+  Token get keyword;
+
+  /**
+   * Set the 'new' or 'const' keyword used to indicate how an object should be
+   * created to the given [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Return the element associated with the constructor based on static type
+   * information, or `null` if the AST structure has not been resolved or if the
+   * constructor could not be resolved.
+   */
+  ConstructorElement get staticElement;
+
+  /**
+   * Set the element associated with the constructor based on static type
+   * information to the given [element].
+   */
+  void set staticElement(ConstructorElement element);
+}
+
+/**
+ * An integer literal expression.
+ *
+ *    integerLiteral ::=
+ *        decimalIntegerLiteral
+ *      | hexadecimalIntegerLiteral
+ *
+ *    decimalIntegerLiteral ::=
+ *        decimalDigit+
+ *
+ *    hexadecimalIntegerLiteral ::=
+ *        '0x' hexadecimalDigit+
+ *      | '0X' hexadecimalDigit+
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class IntegerLiteral extends Literal {
+  /**
+   * Initialize a newly created integer literal.
+   */
+  factory IntegerLiteral(Token literal, int value) = IntegerLiteralImpl;
+
+  /**
+   * Return the token representing the literal.
+   */
+  Token get literal;
+
+  /**
+   * Set the token representing the literal to the given [token].
+   */
+  void set literal(Token token);
+
+  /**
+   * Return the value of the literal.
+   */
+  int get value;
+
+  /**
+   * Set the value of the literal to the given [value].
+   */
+  void set value(int value);
+}
+
+/**
+ * A node within a [StringInterpolation].
+ *
+ *    interpolationElement ::=
+ *        [InterpolationExpression]
+ *      | [InterpolationString]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InterpolationElement extends AstNode {}
+
+/**
+ * An expression embedded in a string interpolation.
+ *
+ *    interpolationExpression ::=
+ *        '$' [SimpleIdentifier]
+ *      | '$' '{' [Expression] '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InterpolationExpression extends InterpolationElement {
+  /**
+   * Initialize a newly created interpolation expression.
+   */
+  factory InterpolationExpression(
+          Token leftBracket, Expression expression, Token rightBracket) =
+      InterpolationExpressionImpl;
+
+  /**
+   * Return the expression to be evaluated for the value to be converted into a
+   * string.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression to be evaluated for the value to be converted into a
+   * string to the given [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the token used to introduce the interpolation expression; either '$'
+   * if the expression is a simple identifier or '${' if the expression is a
+   * full expression.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the token used to introduce the interpolation expression; either '$'
+   * if the expression is a simple identifier or '${' if the expression is a
+   * full expression to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the right curly bracket, or `null` if the expression is an
+   * identifier without brackets.
+   */
+  Token get rightBracket;
+
+  /**
+   * Set the right curly bracket to the given [token].
+   */
+  void set rightBracket(Token token);
+}
+
+/**
+ * A non-empty substring of an interpolated string.
+ *
+ *    interpolationString ::=
+ *        characters
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InterpolationString extends InterpolationElement {
+  /**
+   * Initialize a newly created string of characters that are part of a string
+   * interpolation.
+   */
+  factory InterpolationString(Token contents, String value) =
+      InterpolationStringImpl;
+
+  /**
+   * Return the characters that will be added to the string.
+   */
+  Token get contents;
+
+  /**
+   * Set the characters that will be added to the string to the given [token].
+   */
+  void set contents(Token token);
+
+  /**
+   * Return the offset of the after-last contents character.
+   */
+  int get contentsEnd;
+
+  /**
+   * Return the offset of the first contents character.
+   */
+  int get contentsOffset;
+
+  /**
+   * Return the value of the literal.
+   */
+  String get value;
+
+  /**
+   * Set the value of the literal to the given [value].
+   */
+  void set value(String value);
+}
+
+/**
+ * The invocation of a function or method; either a
+ * [FunctionExpressionInvocation] or a [MethodInvocation].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class InvocationExpression extends Expression {
+  /**
+   * Return the list of arguments to the method.
+   */
+  ArgumentList get argumentList;
+
+  /**
+   * The expression that identifies the function or method being invoked.
+   * For example:
+   *
+   *     (o.m)<TArgs>(args); // target will be `o.m`
+   *     o.m<TArgs>(args);   // target will be `m`
+   *
+   * In either case, the [function.staticType] will be the
+   * [staticInvokeType] before applying type arguments `TArgs`. Similarly,
+   * [function.propagatedType] will be the [propagatedInvokeType]
+   * before applying type arguments `TArgs`.
+   */
+  Expression get function;
+
+  /**
+   * Return the function type of the invocation based on the propagated type
+   * information, or `null` if the AST structure has not been resolved, or if
+   * the invoke could not be resolved.
+   *
+   * This will usually be a [FunctionType], but it can also be an
+   * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
+   * interface type that implements `Function`.
+   */
+  DartType get propagatedInvokeType;
+
+  /**
+   * Sets the function type of the invocation based on the propagated type
+   * information.
+   */
+  void set propagatedInvokeType(DartType value);
+
+  /**
+   * Return the function type of the invocation based on the static type
+   * information, or `null` if the AST structure has not been resolved, or if
+   * the invoke could not be resolved.
+   *
+   * This will usually be a [FunctionType], but it can also be an
+   * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
+   * interface type that implements `Function`.
+   */
+  DartType get staticInvokeType;
+
+  /**
+   * Sets the function type of the invocation based on the static type
+   * information.
+   */
+  void set staticInvokeType(DartType value);
+
+  /**
+   * Return the type arguments to be applied to the method being invoked, or
+   * `null` if no type arguments were provided.
+   */
+  TypeArgumentList get typeArguments;
+}
+
+/**
+ * An is expression.
+ *
+ *    isExpression ::=
+ *        [Expression] 'is' '!'? [TypeName]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class IsExpression extends Expression {
+  /**
+   * Initialize a newly created is expression. The [notOperator] can be `null`
+   * if the sense of the test is not negated.
+   */
+  factory IsExpression(Expression expression, Token isOperator,
+      Token notOperator, TypeName type) = IsExpressionImpl;
+
+  /**
+   * Return the expression used to compute the value whose type is being tested.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression used to compute the value whose type is being tested to
+   * the given [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the is operator.
+   */
+  Token get isOperator;
+
+  /**
+   * Set the is operator to the given [token].
+   */
+  void set isOperator(Token token);
+
+  /**
+   * Return the not operator, or `null` if the sense of the test is not negated.
+   */
+  Token get notOperator;
+
+  /**
+   * Set the not operator to the given [token].
+   */
+  void set notOperator(Token token);
+
+  /**
+   * Return the name of the type being tested for.
+   */
+  TypeName get type;
+
+  /**
+   * Set the name of the type being tested for to the given [name].
+   */
+  void set type(TypeName name);
+}
+
+/**
+ * A label on either a [LabeledStatement] or a [NamedExpression].
+ *
+ *    label ::=
+ *        [SimpleIdentifier] ':'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Label extends AstNode {
+  /**
+   * Initialize a newly created label.
+   */
+  factory Label(SimpleIdentifier label, Token colon) = LabelImpl;
+
+  /**
+   * Return the colon that separates the label from the statement.
+   */
+  Token get colon;
+
+  /**
+   * Set the colon that separates the label from the statement to the given
+   * [token].
+   */
+  void set colon(Token token);
+
+  /**
+   * Return the label being associated with the statement.
+   */
+  SimpleIdentifier get label;
+
+  /**
+   * Set the label being associated with the statement to the given [label].
+   */
+  void set label(SimpleIdentifier label);
+}
+
+/**
+ * A statement that has a label associated with them.
+ *
+ *    labeledStatement ::=
+ *       [Label]+ [Statement]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class LabeledStatement extends Statement {
+  /**
+   * Initialize a newly created labeled statement.
+   */
+  factory LabeledStatement(List<Label> labels, Statement statement) =
+      LabeledStatementImpl;
+
+  /**
+   * Return the labels being associated with the statement.
+   */
+  NodeList<Label> get labels;
+
+  /**
+   * Return the statement with which the labels are being associated.
+   */
+  Statement get statement;
+
+  /**
+   * Set the statement with which the labels are being associated to the given
+   * [statement].
+   */
+  void set statement(Statement statement);
+}
+
+/**
+ * A library directive.
+ *
+ *    libraryDirective ::=
+ *        [Annotation] 'library' [Identifier] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class LibraryDirective extends Directive {
+  /**
+   * Initialize a newly created library directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute.
+   */
+  factory LibraryDirective(
+      Comment comment,
+      List<Annotation> metadata,
+      Token libraryKeyword,
+      LibraryIdentifier name,
+      Token semicolon) = LibraryDirectiveImpl;
+
+  /**
+   * Return the token representing the 'library' keyword.
+   */
+  Token get libraryKeyword;
+
+  /**
+   * Set the token representing the 'library' keyword to the given [token].
+   */
+  void set libraryKeyword(Token token);
+
+  /**
+   * Return the name of the library being defined.
+   */
+  LibraryIdentifier get name;
+
+  /**
+   * Set the name of the library being defined to the given [name].
+   */
+  void set name(LibraryIdentifier name);
+
+  /**
+   * Return the semicolon terminating the directive.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the directive to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * The identifier for a library.
+ *
+ *    libraryIdentifier ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class LibraryIdentifier extends Identifier {
+  /**
+   * Initialize a newly created prefixed identifier.
+   */
+  factory LibraryIdentifier(List<SimpleIdentifier> components) =
+      LibraryIdentifierImpl;
+
+  /**
+   * Return the components of the identifier.
+   */
+  NodeList<SimpleIdentifier> get components;
+}
+
+/**
+ * A list literal.
+ *
+ *    listLiteral ::=
+ *        'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ListLiteral extends TypedLiteral {
+  /**
+   * Initialize a newly created list literal. The [constKeyword] can be `null`
+   * if the literal is not a constant. The [typeArguments] can be `null` if no
+   * type arguments were declared. The list of [elements] can be `null` if the
+   * list is empty.
+   */
+  factory ListLiteral(
+      Token constKeyword,
+      TypeArgumentList typeArguments,
+      Token leftBracket,
+      List<Expression> elements,
+      Token rightBracket) = ListLiteralImpl;
+
+  /**
+   * Return the expressions used to compute the elements of the list.
+   */
+  NodeList<Expression> get elements;
+
+  /**
+   * Return the left square bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the left square bracket to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the right square bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Set the right square bracket to the given [token].
+   */
+  void set rightBracket(Token token);
+}
+
+/**
+ * A node that represents a literal expression.
+ *
+ *    literal ::=
+ *        [BooleanLiteral]
+ *      | [DoubleLiteral]
+ *      | [IntegerLiteral]
+ *      | [ListLiteral]
+ *      | [MapLiteral]
+ *      | [NullLiteral]
+ *      | [StringLiteral]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Literal extends Expression {}
+
+/**
+ * A literal map.
+ *
+ *    mapLiteral ::=
+ *        'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+ *        '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class MapLiteral extends TypedLiteral {
+  /**
+   * Initialize a newly created map literal. The [constKeyword] can be `null` if
+   * the literal is not a constant. The [typeArguments] can be `null` if no type
+   * arguments were declared. The [entries] can be `null` if the map is empty.
+   */
+  factory MapLiteral(
+      Token constKeyword,
+      TypeArgumentList typeArguments,
+      Token leftBracket,
+      List<MapLiteralEntry> entries,
+      Token rightBracket) = MapLiteralImpl;
+
+  /**
+   * Return the entries in the map.
+   */
+  NodeList<MapLiteralEntry> get entries;
+
+  /**
+   * Return the left curly bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the left curly bracket to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the right curly bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Set the right curly bracket to the given [token].
+   */
+  void set rightBracket(Token token);
+}
+
+/**
+ * A single key/value pair in a map literal.
+ *
+ *    mapLiteralEntry ::=
+ *        [Expression] ':' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class MapLiteralEntry extends AstNode {
+  /**
+   * Initialize a newly created map literal entry.
+   */
+  factory MapLiteralEntry(Expression key, Token separator, Expression value) =
+      MapLiteralEntryImpl;
+
+  /**
+   * Return the expression computing the key with which the value will be
+   * associated.
+   */
+  Expression get key;
+
+  /**
+   * Set the expression computing the key with which the value will be
+   * associated to the given [string].
+   */
+  void set key(Expression string);
+
+  /**
+   * Return the colon that separates the key from the value.
+   */
+  Token get separator;
+
+  /**
+   * Set the colon that separates the key from the value to the given [token].
+   */
+  void set separator(Token token);
+
+  /**
+   * Return the expression computing the value that will be associated with the
+   * key.
+   */
+  Expression get value;
+
+  /**
+   * Set the expression computing the value that will be associated with the key
+   * to the given [expression].
+   */
+  void set value(Expression expression);
+}
+
+/**
+ * A method declaration.
+ *
+ *    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.
+ */
+abstract class MethodDeclaration extends ClassMember {
+  /**
+   * Initialize a newly created method declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the declaration does not have the
+   * corresponding attribute. The [externalKeyword] can be `null` if the method
+   * is not external. The [modifierKeyword] can be `null` if the method is
+   * neither abstract nor static. The [returnType] can be `null` if no return
+   * type was specified. The [propertyKeyword] can be `null` if the method is
+   * neither a getter or a setter. The [operatorKeyword] can be `null` if the
+   * method does not implement an operator. The [parameters] must be `null` if
+   * this method declares a getter.
+   */
+  factory MethodDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      Token externalKeyword,
+      Token modifierKeyword,
+      TypeName returnType,
+      Token propertyKeyword,
+      Token operatorKeyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters,
+      FunctionBody body) = MethodDeclarationImpl;
+
+  /**
+   * Return the body of the method.
+   */
+  FunctionBody get body;
+
+  /**
+   * Set the body of the method to the given [functionBody].
+   */
+  void set body(FunctionBody functionBody);
+
+  @override
+  ExecutableElement get element;
+
+  /**
+   * Return the token for the 'external' keyword, or `null` if the constructor
+   * is not external.
+   */
+  Token get externalKeyword;
+
+  /**
+   * Set the token for the 'external' keyword to the given [token].
+   */
+  void set externalKeyword(Token token);
+
+  /**
+   * Return `true` if this method is declared to be an abstract method.
+   */
+  bool get isAbstract;
+
+  /**
+   * Return `true` if this method declares a getter.
+   */
+  bool get isGetter;
+
+  /**
+   * Return `true` if this method declares an operator.
+   */
+  bool get isOperator;
+
+  /**
+   * Return `true` if this method declares a setter.
+   */
+  bool get isSetter;
+
+  /**
+   * Return `true` if this method is declared to be a static method.
+   */
+  bool get isStatic;
+
+  /**
+   * Return the token representing the 'abstract' or 'static' keyword, or `null`
+   * if neither modifier was specified.
+   */
+  Token get modifierKeyword;
+
+  /**
+   * Set the token representing the 'abstract' or 'static' keyword to the given
+   * [token].
+   */
+  void set modifierKeyword(Token token);
+
+  /**
+   * Return the name of the method.
+   */
+  SimpleIdentifier get name;
+
+  /**
+   * Set the name of the method to the given [identifier].
+   */
+  void set name(SimpleIdentifier identifier);
+
+  /**
+   * Return the token representing the 'operator' keyword, or `null` if this
+   * method does not declare an operator.
+   */
+  Token get operatorKeyword;
+
+  /**
+   * Set the token representing the 'operator' keyword to the given [token].
+   */
+  void set operatorKeyword(Token token);
+
+  /**
+   * Return the parameters associated with the method, or `null` if this method
+   * declares a getter.
+   */
+  FormalParameterList get parameters;
+
+  /**
+   * Set the parameters associated with the method to the given list of
+   * [parameters].
+   */
+  void set parameters(FormalParameterList parameters);
+
+  /**
+   * Return the token representing the 'get' or 'set' keyword, or `null` if this
+   * is a method declaration rather than a property declaration.
+   */
+  Token get propertyKeyword;
+
+  /**
+   * Set the token representing the 'get' or 'set' keyword to the given [token].
+   */
+  void set propertyKeyword(Token token);
+
+  /**
+   * Return the return type of the method, or `null` if no return type was
+   * declared.
+   */
+  TypeName get returnType;
+
+  /**
+   * Set the return type of the method to the given [typeName].
+   */
+  void set returnType(TypeName typeName);
+
+  /**
+   * Return the type parameters associated with this method, or `null` if this
+   * method is not a generic method.
+   */
+  TypeParameterList get typeParameters;
+
+  /**
+   * Set the type parameters associated with this method to the given
+   * [typeParameters].
+   */
+  void set typeParameters(TypeParameterList typeParameters);
+}
+
+/**
+ * The invocation of either a function or a method. Invocations of functions
+ * resulting from evaluating an expression are represented by
+ * [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
+ * represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+ *
+ *    methodInvocation ::=
+ *        ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class MethodInvocation extends InvocationExpression {
+  /**
+   * Initialize a newly created method invocation. The [target] and [operator]
+   * can be `null` if there is no target.
+   */
+  factory MethodInvocation(
+      Expression target,
+      Token operator,
+      SimpleIdentifier methodName,
+      TypeArgumentList typeArguments,
+      ArgumentList argumentList) = MethodInvocationImpl;
+
+  /**
+   * Set the list of arguments to the method to the given [argumentList].
+   */
+  void set argumentList(ArgumentList argumentList);
+
+  /**
+   * Return `true` if this expression is cascaded. If it is, then the target of
+   * this expression is not stored locally but is stored in the nearest ancestor
+   * that is a [CascadeExpression].
+   */
+  bool get isCascaded;
+
+  /**
+   * Return the name of the method being invoked.
+   */
+  SimpleIdentifier get methodName;
+
+  /**
+   * Set the name of the method being invoked to the given [identifier].
+   */
+  void set methodName(SimpleIdentifier identifier);
+
+  /**
+   * Return the operator that separates the target from the method name, or
+   * `null` if there is no target. In an ordinary method invocation this will be
+   *  * period ('.'). In a cascade section this will be the cascade operator
+   * ('..').
+   */
+  Token get operator;
+
+  /**
+   * Set the operator that separates the target from the method name to the
+   * given [token].
+   */
+  void set operator(Token token);
+
+  /**
+   * Return the function type of the method invocation based on the propagated
+   * type information, or `null` if the AST structure has not been resolved, or
+   * if the invoke could not be resolved.
+   *
+   * This will usually be a [FunctionType], but it can also be an
+   * [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);
+
+  /**
+   * Return the expression used to compute the receiver of the invocation. If
+   * this invocation is not part of a cascade expression, then this is the same
+   * as [target]. If this invocation is part of a cascade expression, then the
+   * target stored with the cascade expression is returned.
+   */
+  Expression get realTarget;
+
+  /**
+   * Return the function type of the method invocation based on the static type
+   * information, or `null` if the AST structure has not been resolved, or if
+   * the invoke could not be resolved.
+   *
+   * This will usually be a [FunctionType], but it can also be an
+   * [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);
+
+  /**
+   * Return the expression producing the object on which the method is defined,
+   * or `null` if there is no target (that is, the target is implicitly `this`)
+   * or if this method invocation is part of a cascade expression.
+   *
+   * Use [realTarget] to get the target independent of whether this is part of a
+   * cascade expression.
+   */
+  Expression get target;
+
+  /**
+   * Set the expression producing the object on which the method is defined to
+   * the given [expression].
+   */
+  void set target(Expression expression);
+
+  /**
+   * Set the type arguments to be applied to the method being invoked to the
+   * given [typeArguments].
+   */
+  void set typeArguments(TypeArgumentList typeArguments);
+}
+
+/**
+ * A node that declares a single name within the scope of a compilation unit.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NamedCompilationUnitMember extends CompilationUnitMember {
+  /**
+   * Return the name of the member being declared.
+   */
+  SimpleIdentifier get name;
+
+  /**
+   * Set the name of the member being declared to the given [identifier].
+   */
+  void set name(SimpleIdentifier identifier);
+}
+
+/**
+ * An expression that has a name associated with it. They are used in method
+ * invocations when there are named parameters.
+ *
+ *    namedExpression ::=
+ *        [Label] [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NamedExpression extends Expression {
+  /**
+   * Initialize a newly created named expression..
+   */
+  factory NamedExpression(Label name, Expression expression) =
+      NamedExpressionImpl;
+
+  /**
+   * Return the element representing the parameter being named by this
+   * expression, or `null` if the AST structure has not been resolved or if
+   * there is no parameter with the same name as this expression.
+   */
+  ParameterElement get element;
+
+  /**
+   * Return the expression with which the name is associated.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression with which the name is associated to the given
+   * [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the name associated with the expression.
+   */
+  Label get name;
+
+  /**
+   * Set the name associated with the expression to the given [identifier].
+   */
+  void set name(Label identifier);
+}
+
+/**
+ * A node that represents a directive that impacts the namespace of a library.
+ *
+ *    directive ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NamespaceDirective extends UriBasedDirective {
+  /**
+   * Return the combinators used to control how names are imported or exported.
+   */
+  NodeList<Combinator> get combinators;
+
+  /**
+   * Return the configurations used to control which library will actually be
+   * loaded at run-time.
+   */
+  NodeList<Configuration> get configurations;
+
+  /**
+   * Set the token representing the keyword that introduces this directive
+   * ('import', 'export', 'library' or 'part') to the given [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Return the semicolon terminating the directive.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the directive to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * The "native" clause in an class declaration.
+ *
+ *    nativeClause ::=
+ *        'native' [StringLiteral]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NativeClause extends AstNode {
+  /**
+   * Initialize a newly created native clause.
+   */
+  factory NativeClause(Token nativeKeyword, StringLiteral name) =
+      NativeClauseImpl;
+
+  /**
+   * Return the name of the native object that implements the class.
+   */
+  StringLiteral get name;
+
+  /**
+   * Set the name of the native object that implements the class to the given
+   * [name].
+   */
+  void set name(StringLiteral name);
+
+  /**
+   * Return the token representing the 'native' keyword.
+   */
+  Token get nativeKeyword;
+
+  /**
+   * Set the token representing the 'native' keyword to the given [token].
+   */
+  void set nativeKeyword(Token token);
+}
+
+/**
+ * A function body that consists of a native keyword followed by a string
+ * literal.
+ *
+ *    nativeFunctionBody ::=
+ *        'native' [SimpleStringLiteral] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NativeFunctionBody extends FunctionBody {
+  /**
+   * Initialize a newly created function body consisting of the 'native' token,
+   * a string literal, and a semicolon.
+   */
+  factory NativeFunctionBody(
+          Token nativeKeyword, StringLiteral stringLiteral, Token semicolon) =
+      NativeFunctionBodyImpl;
+
+  /**
+   * Return the token representing 'native' that marks the start of the function
+   * body.
+   */
+  Token get nativeKeyword;
+
+  /**
+   * Set the token representing 'native' that marks the start of the function
+   * body to the given [token].
+   */
+  void set nativeKeyword(Token token);
+
+  /**
+   * Return the token representing the semicolon that marks the end of the
+   * function body.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the token representing the semicolon that marks the end of the
+   * function body to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the string literal representing the string after the 'native' token.
+   */
+  StringLiteral get stringLiteral;
+
+  /**
+   * Set the string literal representing the string after the 'native' token to
+   * the given [stringLiteral].
+   */
+  void set stringLiteral(StringLiteral stringLiteral);
+}
+
+/**
+ * A list of AST nodes that have a common parent.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NodeList<E extends AstNode> implements List<E> {
+  /**
+   * Initialize a newly created list of nodes such that all of the nodes that
+   * are added to the list will have their parent set to the given [owner]. The
+   * list will initially be populated with the given [elements].
+   */
+  factory NodeList(AstNode owner, [List<E> elements]) = NodeListImpl;
+
+  /**
+   * Return the first token included in this node list's source range, or `null`
+   * if the list is empty.
+   */
+  Token get beginToken;
+
+  /**
+   * Return the last token included in this node list's source range, or `null`
+   * if the list is empty.
+   */
+  Token get endToken;
+
+  /**
+   * Return the node that is the parent of each of the elements in the list.
+   */
+  AstNode get owner;
+
+  /**
+   * Set the node that is the parent of each of the elements in the list to the
+   * given [node].
+   */
+  @deprecated // Never intended for public use.
+  void set owner(AstNode node);
+
+  /**
+   * 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);
+
+  /**
+   * Use the given [visitor] to visit each of the nodes in this list.
+   */
+  accept(AstVisitor visitor);
+}
+
+/**
+ * A formal parameter that is required (is not optional).
+ *
+ *    normalFormalParameter ::=
+ *        [FunctionTypedFormalParameter]
+ *      | [FieldFormalParameter]
+ *      | [SimpleFormalParameter]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NormalFormalParameter extends FormalParameter {
+  /**
+   * Return the documentation comment associated with this parameter, or `null`
+   * if this parameter does not have a documentation comment associated with it.
+   */
+  Comment get documentationComment;
+
+  /**
+   * Set the documentation comment associated with this parameter to the given
+   * [comment].
+   */
+  void set documentationComment(Comment comment);
+
+  /**
+   * Set the name of the parameter being declared to the given [identifier].
+   */
+  void set identifier(SimpleIdentifier identifier);
+
+  /**
+   * Set the metadata associated with this node to the given [metadata].
+   */
+  void set metadata(List<Annotation> metadata);
+
+  /**
+   * Return a list containing the comment and annotations associated with this
+   * parameter, sorted in lexical order.
+   */
+  List<AstNode> get sortedCommentAndAnnotations;
+}
+
+/**
+ * A null literal expression.
+ *
+ *    nullLiteral ::=
+ *        'null'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class NullLiteral extends Literal {
+  /**
+   * Initialize a newly created null literal.
+   */
+  factory NullLiteral(Token literal) = NullLiteralImpl;
+
+  /**
+   * Return the token representing the literal.
+   */
+  Token get literal;
+
+  /**
+   * Set the token representing the literal to the given [token].
+   */
+  void set literal(Token token);
+}
+
+/**
+ * A parenthesized expression.
+ *
+ *    parenthesizedExpression ::=
+ *        '(' [Expression] ')'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ParenthesizedExpression extends Expression {
+  /**
+   * Initialize a newly created parenthesized expression.
+   */
+  factory ParenthesizedExpression(Token leftParenthesis, Expression expression,
+      Token rightParenthesis) = ParenthesizedExpressionImpl;
+
+  /**
+   * Return the expression within the parentheses.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression within the parentheses to the given [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+}
+
+/**
+ * A part directive.
+ *
+ *    partDirective ::=
+ *        [Annotation] 'part' [StringLiteral] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PartDirective extends UriBasedDirective {
+  /**
+   * Initialize a newly created part directive. Either or both of the [comment]
+   * and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute.
+   */
+  factory PartDirective(
+      Comment comment,
+      List<Annotation> metadata,
+      Token partKeyword,
+      StringLiteral partUri,
+      Token semicolon) = PartDirectiveImpl;
+
+  /**
+   * Return the token representing the 'part' keyword.
+   */
+  Token get partKeyword;
+
+  /**
+   * Set the token representing the 'part' keyword to the given [token].
+   */
+  void set partKeyword(Token token);
+
+  /**
+   * Return the semicolon terminating the directive.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the directive to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * A part-of directive.
+ *
+ *    partOfDirective ::=
+ *        [Annotation] 'part' 'of' [Identifier] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PartOfDirective extends Directive {
+  /**
+   * Initialize a newly created part-of directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute.
+   */
+  factory PartOfDirective(
+      Comment comment,
+      List<Annotation> metadata,
+      Token partKeyword,
+      Token ofKeyword,
+      LibraryIdentifier libraryName,
+      Token semicolon) = PartOfDirectiveImpl;
+
+  /**
+   * Return the name of the library that the containing compilation unit is part
+   * of.
+   */
+  LibraryIdentifier get libraryName;
+
+  /**
+   * Set the name of the library that the containing compilation unit is part of
+   * to the given [libraryName].
+   */
+  void set libraryName(LibraryIdentifier libraryName);
+
+  /**
+   * Return the token representing the 'of' keyword.
+   */
+  Token get ofKeyword;
+
+  /**
+   * Set the token representing the 'of' keyword to the given [token].
+   */
+  void set ofKeyword(Token token);
+
+  /**
+   * Return the token representing the 'part' keyword.
+   */
+  Token get partKeyword;
+
+  /**
+   * Set the token representing the 'part' keyword to the given [token].
+   */
+  void set partKeyword(Token token);
+
+  /**
+   * Return the semicolon terminating the directive.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the directive to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * A postfix unary expression.
+ *
+ *    postfixExpression ::=
+ *        [Expression] [Token]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PostfixExpression extends Expression {
+  /**
+   * Initialize a newly created postfix expression.
+   */
+  factory PostfixExpression(Expression operand, Token operator) =
+      PostfixExpressionImpl;
+
+  /**
+   * Return the best element available for this operator. If resolution was able
+   * to find a better element based on type propagation, that element will be
+   * returned. Otherwise, the element found using the result of static analysis
+   * will be returned. If resolution has not been performed, then `null` will be
+   * returned.
+   */
+  MethodElement get bestElement;
+
+  /**
+   * Return the expression computing the operand for the operator.
+   */
+  Expression get operand;
+
+  /**
+   * Set the expression computing the operand for the operator to the given
+   * [expression].
+   */
+  void set operand(Expression expression);
+
+  /**
+   * Return the postfix operator being applied to the operand.
+   */
+  Token get operator;
+
+  /**
+   * Set the postfix operator being applied to the operand to the given [token].
+   */
+  void set operator(Token token);
+
+  /**
+   * Return the element associated with this the operator based on the
+   * propagated type of the 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.
+   */
+  MethodElement get propagatedElement;
+
+  /**
+   * Set the element associated with this the operator based on the propagated
+   * type of the operand to the given [element].
+   */
+  void set propagatedElement(MethodElement element);
+
+  /**
+   * Return the element associated with the operator based on the static type of
+   * the 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.
+   */
+  MethodElement get staticElement;
+
+  /**
+   * Set the element associated with the operator based on the static type of
+   * the operand to the given [element].
+   */
+  void set staticElement(MethodElement element);
+}
+
+/**
+ * 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]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PrefixedIdentifier extends Identifier {
+  /**
+   * Initialize a newly created prefixed identifier.
+   */
+  factory PrefixedIdentifier(
+          SimpleIdentifier prefix, Token period, SimpleIdentifier identifier) =
+      PrefixedIdentifierImpl;
+
+  /**
+   * Return the identifier being prefixed.
+   */
+  SimpleIdentifier get identifier;
+
+  /**
+   * Set the identifier being prefixed to the given [identifier].
+   */
+  void set identifier(SimpleIdentifier identifier);
+
+  /**
+   * Return `true` if this type is a deferred type. If the AST structure has not
+   * been resolved, then return `false`.
+   *
+   * 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
+   * </i>p.T</i> where <i>p</i> is a deferred prefix.
+   */
+  bool get isDeferred;
+
+  /**
+   * Return the period used to separate the prefix from the identifier.
+   */
+  Token get period;
+
+  /**
+   * Set the period used to separate the prefix from the identifier to the given
+   * [token].
+   */
+  void set period(Token token);
+
+  /**
+   * Return the prefix associated with the library in which the identifier is
+   * defined.
+   */
+  SimpleIdentifier get prefix;
+
+  /**
+   * Set the prefix associated with the library in which the identifier is
+   * defined to the given [identifier].
+   */
+  void set prefix(SimpleIdentifier identifier);
+}
+
+/**
+ * A prefix unary expression.
+ *
+ *    prefixExpression ::=
+ *        [Token] [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PrefixExpression extends Expression {
+  /**
+   * Initialize a newly created prefix expression.
+   */
+  factory PrefixExpression(Token operator, Expression operand) =
+      PrefixExpressionImpl;
+
+  /**
+   * Return the best element available for this operator. If resolution was able
+   * to find a better element based on type propagation, that element will be
+   * returned. Otherwise, the element found using the result of static analysis
+   * will be returned. If resolution has not been performed, then `null` will be
+   * returned.
+   */
+  MethodElement get bestElement;
+
+  /**
+   * Return the expression computing the operand for the operator.
+   */
+  Expression get operand;
+
+  /**
+   * Set the expression computing the operand for the operator to the given
+   * [expression].
+   */
+  void set operand(Expression expression);
+
+  /**
+   * Return the prefix operator being applied to the operand.
+   */
+  Token get operator;
+
+  /**
+   * Set the prefix operator being applied to the operand to the given [token].
+   */
+  void set operator(Token token);
+
+  /**
+   * Return the element associated with the operator based on the propagated
+   * type of the 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.
+   */
+  MethodElement get propagatedElement;
+
+  /**
+   * Set the element associated with the operator based on the propagated type
+   * of the operand to the given [element].
+   */
+  void set propagatedElement(MethodElement element);
+
+  /**
+   * Return the element associated with the operator based on the static type of
+   * the 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.
+   */
+  MethodElement get staticElement;
+
+  /**
+   * Set the element associated with the operator based on the static type of
+   * the operand to the given [element].
+   */
+  void set staticElement(MethodElement element);
+}
+
+/**
+ * The access of a property of an object.
+ *
+ * Note, however, that accesses to properties of objects can also be represented
+ * as [PrefixedIdentifier] nodes in cases where the target is also a simple
+ * identifier.
+ *
+ *    propertyAccess ::=
+ *        [Expression] '.' [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class PropertyAccess extends Expression {
+  /**
+   * Initialize a newly created property access expression.
+   */
+  factory PropertyAccess(
+          Expression target, Token operator, SimpleIdentifier propertyName) =
+      PropertyAccessImpl;
+
+  /**
+   * Return `true` if this expression is cascaded. If it is, then the target of
+   * this expression is not stored locally but is stored in the nearest ancestor
+   * that is a [CascadeExpression].
+   */
+  bool get isCascaded;
+
+  /**
+   * Return the property access operator.
+   */
+  Token get operator;
+
+  /**
+   * Set the property access operator to the given [token].
+   */
+  void set operator(Token token);
+
+  /**
+   * Return the name of the property being accessed.
+   */
+  SimpleIdentifier get propertyName;
+
+  /**
+   * Set the name of the property being accessed to the given [identifier].
+   */
+  void set propertyName(SimpleIdentifier identifier);
+
+  /**
+   * Return the expression used to compute the receiver of the invocation. If
+   * this invocation is not part of a cascade expression, then this is the same
+   * as [target]. If this invocation is part of a cascade expression, then the
+   * target stored with the cascade expression is returned.
+   */
+  Expression get realTarget;
+
+  /**
+   * Return the expression computing the object defining the property being
+   * accessed, or `null` if this property access is part of a cascade expression.
+   *
+   * Use [realTarget] to get the target independent of whether this is part of a
+   * cascade expression.
+   */
+  Expression get target;
+
+  /**
+   * Set the expression computing the object defining the property being
+   * accessed to the given [expression].
+   */
+  void set target(Expression expression);
+}
+
+/**
+ * The invocation of a constructor in the same class from within a constructor's
+ * initialization list.
+ *
+ *    redirectingConstructorInvocation ::=
+ *        'this' ('.' identifier)? arguments
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class RedirectingConstructorInvocation extends ConstructorInitializer {
+  /**
+   * Initialize a newly created redirecting invocation to invoke the constructor
+   * with the given name with the given arguments. The [constructorName] can be
+   * `null` if the constructor being invoked is the unnamed constructor.
+   */
+  factory RedirectingConstructorInvocation(
+      Token thisKeyword,
+      Token period,
+      SimpleIdentifier constructorName,
+      ArgumentList argumentList) = RedirectingConstructorInvocationImpl;
+
+  /**
+   * Return the list of arguments to the constructor.
+   */
+  ArgumentList get argumentList;
+
+  /**
+   * Set the list of arguments to the constructor to the given [argumentList].
+   */
+  void set argumentList(ArgumentList argumentList);
+
+  /**
+   * Return the name of the constructor that is being invoked, or `null` if the
+   * unnamed constructor is being invoked.
+   */
+  SimpleIdentifier get constructorName;
+
+  /**
+   * Set the name of the constructor that is being invoked to the given
+   * [identifier].
+   */
+  void set constructorName(SimpleIdentifier identifier);
+
+  /**
+   * Return the token for the period before the name of the constructor that is
+   * being invoked, or `null` if the unnamed constructor is being invoked.
+   */
+  Token get period;
+
+  /**
+   * Set the token for the period before the name of the constructor that is
+   * being invoked to the given [token].
+   */
+  void set period(Token token);
+
+  /**
+   * Return the element associated with the constructor based on static type
+   * information, or `null` if the AST structure has not been resolved or if the
+   * constructor could not be resolved.
+   */
+  ConstructorElement get staticElement;
+
+  /**
+   * Set the element associated with the constructor based on static type
+   * information to the given [element].
+   */
+  void set staticElement(ConstructorElement element);
+
+  /**
+   * Return the token for the 'this' keyword.
+   */
+  Token get thisKeyword;
+
+  /**
+   * Set the token for the 'this' keyword to the given [token].
+   */
+  void set thisKeyword(Token token);
+}
+
+/**
+ * A rethrow expression.
+ *
+ *    rethrowExpression ::=
+ *        'rethrow'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class RethrowExpression extends Expression {
+  /**
+   * Initialize a newly created rethrow expression.
+   */
+  factory RethrowExpression(Token rethrowKeyword) = RethrowExpressionImpl;
+
+  /**
+   * Return the token representing the 'rethrow' keyword.
+   */
+  Token get rethrowKeyword;
+
+  /**
+   * Set the token representing the 'rethrow' keyword to the given [token].
+   */
+  void set rethrowKeyword(Token token);
+}
+
+/**
+ * A return statement.
+ *
+ *    returnStatement ::=
+ *        'return' [Expression]? ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ReturnStatement extends Statement {
+  /**
+   * Initialize a newly created return statement. The [expression] can be `null`
+   * if no explicit value was provided.
+   */
+  factory ReturnStatement(
+          Token returnKeyword, Expression expression, Token semicolon) =
+      ReturnStatementImpl;
+
+  /**
+   * Return the expression computing the value to be returned, or `null` if no
+   * explicit value was provided.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression computing the value to be returned to the given
+   * [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the token representing the 'return' keyword.
+   */
+  Token get returnKeyword;
+
+  /**
+   * Set the token representing the 'return' keyword to the given [token].
+   */
+  void set returnKeyword(Token token);
+
+  /**
+   * Return the semicolon terminating the statement.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+}
+
+/**
+ * A script tag that can optionally occur at the beginning of a compilation unit.
+ *
+ *    scriptTag ::=
+ *        '#!' (~NEWLINE)* NEWLINE
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ScriptTag extends AstNode {
+  /**
+   * Initialize a newly created script tag.
+   */
+  factory ScriptTag(Token scriptTag) = ScriptTagImpl;
+
+  /**
+   * Return the token representing this script tag.
+   */
+  Token get scriptTag;
+
+  /**
+   * Set the token representing this script tag to the given [token].
+   */
+  void set scriptTag(Token token);
+}
+
+/**
+ * A combinator that restricts the names being imported to those in a given list.
+ *
+ *    showCombinator ::=
+ *        'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ShowCombinator extends Combinator {
+  /**
+   * Initialize a newly created import show combinator.
+   */
+  factory ShowCombinator(Token keyword, List<SimpleIdentifier> shownNames) =
+      ShowCombinatorImpl;
+
+  /**
+   * Return the list of names from the library that are made visible by this
+   * combinator.
+   */
+  NodeList<SimpleIdentifier> get shownNames;
+}
+
+/**
+ * A simple formal parameter.
+ *
+ *    simpleFormalParameter ::=
+ *        ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SimpleFormalParameter extends NormalFormalParameter {
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute. The [keyword] can be `null` if a type was
+   * specified. The [type] must be `null` if the keyword is 'var'.
+   */
+  factory SimpleFormalParameter(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      TypeName type,
+      SimpleIdentifier identifier) = SimpleFormalParameterImpl;
+
+  /**
+   * Return the token representing either the 'final', 'const' or 'var' keyword,
+   * or `null` if no keyword was used.
+   */
+  Token get keyword;
+
+  /**
+   * Set the token representing either the 'final', 'const' or 'var' keyword to
+   * the given [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Return the name of the declared type of the parameter, or `null` if the
+   * parameter does not have a declared type.
+   */
+  TypeName get type;
+
+  /**
+   * Set the name of the declared type of the parameter to the given [typeName].
+   */
+  void set type(TypeName typeName);
+}
+
+/**
+ * A simple identifier.
+ *
+ *    simpleIdentifier ::=
+ *        initialCharacter internalCharacter*
+ *
+ *    initialCharacter ::= '_' | '$' | letter
+ *
+ *    internalCharacter ::= '_' | '$' | letter | digit
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SimpleIdentifier extends Identifier {
+  /**
+   * Initialize a newly created identifier.
+   */
+  factory SimpleIdentifier(Token token) = SimpleIdentifierImpl;
+
+  /**
+   * Return the auxiliary elements associated with this identifier, or `null` if
+   * this identifier is not in both a getter and setter context. The auxiliary
+   * elements hold the static and propagated elements associated with the getter
+   * context.
+   */
+  // TODO(brianwilkerson) Replace this API.
+  AuxiliaryElements get auxiliaryElements;
+
+  /**
+   * Set the auxiliary elements associated with this identifier to the given
+   * [elements].
+   */
+  // TODO(brianwilkerson) Replace this API.
+  void set auxiliaryElements(AuxiliaryElements elements);
+
+  /**
+   * Return `true` if this identifier is the "name" part of a prefixed
+   * identifier or a method invocation.
+   */
+  bool get isQualified;
+
+  /**
+   * Set the element associated with this identifier based on propagated type
+   * information to the given [element].
+   */
+  void set propagatedElement(Element element);
+
+  /**
+   * Set the element associated with this identifier based on static type
+   * information to the given [element].
+   */
+  void set staticElement(Element element);
+
+  /**
+   * Return the token representing the identifier.
+   */
+  Token get token;
+
+  /**
+   * Set the token representing the identifier to the given [token].
+   */
+  void set token(Token token);
+
+  /**
+   * Return `true` if this identifier is the name being declared in a
+   * declaration.
+   */
+  // TODO(brianwilkerson) Convert this to a getter.
+  bool inDeclarationContext();
+
+  /**
+   * Return `true` if this expression is computing a right-hand value.
+   *
+   * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
+   * are they mutually exclusive. In other words, it is possible for both
+   * methods to return `true` when invoked on the same node.
+   */
+  // TODO(brianwilkerson) Convert this to a getter.
+  bool inGetterContext();
+
+  /**
+   * Return `true` if this expression is computing a left-hand value.
+   *
+   * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
+   * are they mutually exclusive. In other words, it is possible for both
+   * methods to return `true` when invoked on the same node.
+   */
+  // TODO(brianwilkerson) Convert this to a getter.
+  bool inSetterContext();
+}
+
+/**
+ * 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 '"'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SimpleStringLiteral extends SingleStringLiteral {
+  /**
+   * Initialize a newly created simple string literal.
+   */
+  factory SimpleStringLiteral(Token literal, String value) =
+      SimpleStringLiteralImpl;
+
+  /**
+   * Return the token representing the literal.
+   */
+  Token get literal;
+
+  /**
+   * Set the token representing the literal to the given [token].
+   */
+  void set literal(Token token);
+
+  /**
+   * Return the value of the literal.
+   */
+  String get value;
+
+  /**
+   * Set the value of the literal to the given [string].
+   */
+  void set value(String string);
+}
+
+/**
+ * A single string literal expression.
+ *
+ *    singleStringLiteral ::=
+ *        [SimpleStringLiteral]
+ *      | [StringInterpolation]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SingleStringLiteral extends StringLiteral {
+  /**
+   * Return the offset of the after-last contents character.
+   */
+  int get contentsEnd;
+
+  /**
+   * Return the offset of the first contents character.
+   * If the string is multiline, then leading whitespaces are skipped.
+   */
+  int get contentsOffset;
+
+  /**
+   * Return `true` if this string literal is a multi-line string.
+   */
+  bool get isMultiline;
+
+  /**
+   * Return `true` if this string literal is a raw string.
+   */
+  bool get isRaw;
+
+  /**
+   * Return `true` if this string literal uses single quotes (' or ''').
+   * Return `false` if this string literal uses double quotes (" or """).
+   */
+  bool get isSingleQuoted;
+}
+
+/**
+ * A node that represents a statement.
+ *
+ *    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.
+ */
+abstract class Statement extends AstNode {
+  /**
+   * If this is a labeled statement, return the unlabeled portion of the
+   * statement, otherwise return the statement itself.
+   */
+  Statement get unlabeled;
+}
+
+/**
+ * A string interpolation literal.
+ *
+ *    stringInterpolation ::=
+ *        ''' [InterpolationElement]* '''
+ *      | '"' [InterpolationElement]* '"'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class StringInterpolation extends SingleStringLiteral {
+  /**
+   * Initialize a newly created string interpolation expression.
+   */
+  factory StringInterpolation(List<InterpolationElement> elements) =
+      StringInterpolationImpl;
+
+  /**
+   * Return the elements that will be composed to produce the resulting string.
+   */
+  NodeList<InterpolationElement> get elements;
+}
+
+/**
+ * A string literal expression.
+ *
+ *    stringLiteral ::=
+ *        [SimpleStringLiteral]
+ *      | [AdjacentStrings]
+ *      | [StringInterpolation]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class StringLiteral extends Literal {
+  /**
+   * Return the value of the string literal, or `null` if the string is not a
+   * constant string without any string interpolation.
+   */
+  String get stringValue;
+}
+
+/**
+ * The invocation of a superclass' constructor from within a constructor's
+ * initialization list.
+ *
+ *    superInvocation ::=
+ *        'super' ('.' [SimpleIdentifier])? [ArgumentList]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SuperConstructorInvocation extends ConstructorInitializer {
+  /**
+   * Initialize a newly created super invocation to invoke the inherited
+   * constructor with the given name with the given arguments. The [period] and
+   * [constructorName] can be `null` if the constructor being invoked is the
+   * unnamed constructor.
+   */
+  factory SuperConstructorInvocation(
+      Token superKeyword,
+      Token period,
+      SimpleIdentifier constructorName,
+      ArgumentList argumentList) = SuperConstructorInvocationImpl;
+
+  /**
+   * Return the list of arguments to the constructor.
+   */
+  ArgumentList get argumentList;
+
+  /**
+   * Set the list of arguments to the constructor to the given [argumentList].
+   */
+  void set argumentList(ArgumentList argumentList);
+
+  /**
+   * Return the name of the constructor that is being invoked, or `null` if the
+   * unnamed constructor is being invoked.
+   */
+  SimpleIdentifier get constructorName;
+
+  /**
+   * Set the name of the constructor that is being invoked to the given
+   * [identifier].
+   */
+  void set constructorName(SimpleIdentifier identifier);
+
+  /**
+   * Return the token for the period before the name of the constructor that is
+   * being invoked, or `null` if the unnamed constructor is being invoked.
+   */
+  Token get period;
+
+  /**
+   * Set the token for the period before the name of the constructor that is
+   * being invoked to the given [token].
+   */
+  void set period(Token token);
+
+  /**
+   * Return the element associated with the constructor based on static type
+   * information, or `null` if the AST structure has not been resolved or if the
+   * constructor could not be resolved.
+   */
+  ConstructorElement get staticElement;
+
+  /**
+   * Set the element associated with the constructor based on static type
+   * information to the given [element].
+   */
+  void set staticElement(ConstructorElement element);
+
+  /**
+   * Return the token for the 'super' keyword.
+   */
+  Token get superKeyword;
+
+  /**
+   * Set the token for the 'super' keyword to the given [token].
+   */
+  void set superKeyword(Token token);
+}
+
+/**
+ * A super expression.
+ *
+ *    superExpression ::=
+ *        'super'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SuperExpression extends Expression {
+  /**
+   * Initialize a newly created super expression.
+   */
+  factory SuperExpression(Token superKeyword) = SuperExpressionImpl;
+
+  /**
+   * Return the token representing the 'super' keyword.
+   */
+  Token get superKeyword;
+
+  /**
+   * Set the token representing the 'super' keyword to the given [token].
+   */
+  void set superKeyword(Token token);
+}
+
+/**
+ * A case in a switch statement.
+ *
+ *    switchCase ::=
+ *        [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SwitchCase extends SwitchMember {
+  /**
+   * Initialize a newly created switch case. The list of [labels] can be `null`
+   * if there are no labels.
+   */
+  factory SwitchCase(List<Label> labels, Token keyword, Expression expression,
+      Token colon, List<Statement> statements) = SwitchCaseImpl;
+
+  /**
+   * Return the expression controlling whether the statements will be executed.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression controlling whether the statements will be executed to
+   * the given [expression].
+   */
+  void set expression(Expression expression);
+}
+
+/**
+ * The default case in a switch statement.
+ *
+ *    switchDefault ::=
+ *        [SimpleIdentifier]* 'default' ':' [Statement]*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SwitchDefault extends SwitchMember {
+  /**
+   * Initialize a newly created switch default. The list of [labels] can be
+   * `null` if there are no labels.
+   */
+  factory SwitchDefault(List<Label> labels, Token keyword, Token colon,
+      List<Statement> statements) = SwitchDefaultImpl;
+}
+
+/**
+ * An element within a switch statement.
+ *
+ *    switchMember ::=
+ *        switchCase
+ *      | switchDefault
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SwitchMember extends AstNode {
+  /**
+   * Return the colon separating the keyword or the expression from the
+   * statements.
+   */
+  Token get colon;
+
+  /**
+   * Set the colon separating the keyword or the expression from the
+   * statements to the given [token].
+   */
+  void set colon(Token token);
+
+  /**
+   * Return the token representing the 'case' or 'default' keyword.
+   */
+  Token get keyword;
+
+  /**
+   * Set the token representing the 'case' or 'default' keyword to the given
+   * [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Return the labels associated with the switch member.
+   */
+  NodeList<Label> get labels;
+
+  /**
+   * Return the statements that will be executed if this switch member is
+   * selected.
+   */
+  NodeList<Statement> get statements;
+}
+
+/**
+ * A switch statement.
+ *
+ *    switchStatement ::=
+ *        'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SwitchStatement extends Statement {
+  /**
+   * Initialize a newly created switch statement. The list of [members] can be
+   * `null` if there are no switch members.
+   */
+  factory SwitchStatement(
+      Token switchKeyword,
+      Token leftParenthesis,
+      Expression expression,
+      Token rightParenthesis,
+      Token leftBracket,
+      List<SwitchMember> members,
+      Token rightBracket) = SwitchStatementImpl;
+
+  /**
+   * Return the expression used to determine which of the switch members will be
+   * selected.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression used to determine which of the switch members will be
+   * selected to the given [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the left curly bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the left curly bracket to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the switch members that can be selected by the expression.
+   */
+  NodeList<SwitchMember> get members;
+
+  /**
+   * Return the right curly bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Set the right curly bracket to the given [token].
+   */
+  void set rightBracket(Token token);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+
+  /**
+   * Return the token representing the 'switch' keyword.
+   */
+  Token get switchKeyword;
+
+  /**
+   * Set the token representing the 'switch' keyword to the given [token].
+   */
+  void set switchKeyword(Token token);
+}
+
+/**
+ * A symbol literal expression.
+ *
+ *    symbolLiteral ::=
+ *        '#' (operator | (identifier ('.' identifier)*))
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class SymbolLiteral extends Literal {
+  /**
+   * Initialize a newly created symbol literal.
+   */
+  factory SymbolLiteral(Token poundSign, List<Token> components) =
+      SymbolLiteralImpl;
+
+  /**
+   * Return the components of the literal.
+   */
+  List<Token> get components;
+
+  /**
+   * Return the token introducing the literal.
+   */
+  Token get poundSign;
+
+  /**
+   * Set the token introducing the literal to the given [token].
+   */
+  void set poundSign(Token token);
+}
+
+/**
+ * A this expression.
+ *
+ *    thisExpression ::=
+ *        'this'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ThisExpression extends Expression {
+  /**
+   * Initialize a newly created this expression.
+   */
+  factory ThisExpression(Token thisKeyword) = ThisExpressionImpl;
+
+  /**
+   * Return the token representing the 'this' keyword.
+   */
+  Token get thisKeyword;
+
+  /**
+   * Set the token representing the 'this' keyword to the given [token].
+   */
+  void set thisKeyword(Token token);
+}
+
+/**
+ * A throw expression.
+ *
+ *    throwExpression ::=
+ *        'throw' [Expression]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class ThrowExpression extends Expression {
+  /**
+   * Initialize a newly created throw expression.
+   */
+  factory ThrowExpression(Token throwKeyword, Expression expression) =
+      ThrowExpressionImpl;
+
+  /**
+   * Return the expression computing the exception to be thrown.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression computing the exception to be thrown to the given
+   * [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the token representing the 'throw' keyword.
+   */
+  Token get throwKeyword;
+
+  /**
+   * Set the token representing the 'throw' keyword to the given [token].
+   */
+  void set throwKeyword(Token token);
+}
+
+/**
+ * The declaration of one or more top-level variables of the same type.
+ *
+ *    topLevelVariableDeclaration ::=
+ *        ('final' | 'const') type? staticFinalDeclarationList ';'
+ *      | variableDeclaration ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TopLevelVariableDeclaration extends CompilationUnitMember {
+  /**
+   * Initialize a newly created top-level variable declaration. Either or both
+   * of the [comment] and [metadata] can be `null` if the variable does not have
+   * the corresponding attribute.
+   */
+  factory TopLevelVariableDeclaration(
+      Comment comment,
+      List<Annotation> metadata,
+      VariableDeclarationList variableList,
+      Token semicolon) = TopLevelVariableDeclarationImpl;
+
+  /**
+   * Return the semicolon terminating the declaration.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the declaration to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the top-level variables being declared.
+   */
+  VariableDeclarationList get variables;
+
+  /**
+   * Set the top-level variables being declared to the given list of
+   * [variables].
+   */
+  void set variables(VariableDeclarationList variables);
+}
+
+/**
+ * A try statement.
+ *
+ *    tryStatement ::=
+ *        'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+ *
+ *    finallyClause ::=
+ *        'finally' [Block]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TryStatement extends Statement {
+  /**
+   * Initialize a newly created try statement. The list of [catchClauses] can be
+   * `null` if there are no catch clauses. The [finallyKeyword] and
+   * [finallyBlock] can be `null` if there is no finally clause.
+   */
+  factory TryStatement(
+      Token tryKeyword,
+      Block body,
+      List<CatchClause> catchClauses,
+      Token finallyKeyword,
+      Block finallyBlock) = TryStatementImpl;
+
+  /**
+   * Return the body of the statement.
+   */
+  Block get body;
+
+  /**
+   * Set the body of the statement to the given [block].
+   */
+  void set body(Block block);
+
+  /**
+   * Return the catch clauses contained in the try statement.
+   */
+  NodeList<CatchClause> get catchClauses;
+
+  /**
+   * Return the finally block contained in the try statement, or `null` if the
+   * statement does not contain a finally clause.
+   */
+  Block get finallyBlock;
+
+  /**
+   * Set the finally block contained in the try statement to the given [block].
+   */
+  void set finallyBlock(Block block);
+
+  /**
+   * Return the token representing the 'finally' keyword, or `null` if the
+   * statement does not contain a finally clause.
+   */
+  Token get finallyKeyword;
+
+  /**
+   * Set the token representing the 'finally' keyword to the given [token].
+   */
+  void set finallyKeyword(Token token);
+
+  /**
+   * Return the token representing the 'try' keyword.
+   */
+  Token get tryKeyword;
+
+  /**
+   * Set the token representing the 'try' keyword to the given [token].
+   */
+  void set tryKeyword(Token token);
+}
+
+/**
+ * The declaration of a type alias.
+ *
+ *    typeAlias ::=
+ *        'typedef' typeAliasBody
+ *
+ *    typeAliasBody ::=
+ *        classTypeAlias
+ *      | functionTypeAlias
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeAlias extends NamedCompilationUnitMember {
+  /**
+   * Return the semicolon terminating the declaration.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the declaration to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the token representing the 'typedef' keyword.
+   */
+  Token get typedefKeyword;
+
+  /**
+   * Set the token representing the 'typedef' keyword to the given [token].
+   */
+  void set typedefKeyword(Token token);
+}
+
+/**
+ * A list of type arguments.
+ *
+ *    typeArguments ::=
+ *        '<' typeName (',' typeName)* '>'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeArgumentList extends AstNode {
+  /**
+   * Initialize a newly created list of type arguments.
+   */
+  factory TypeArgumentList(
+          Token leftBracket, List<TypeName> arguments, Token rightBracket) =
+      TypeArgumentListImpl;
+
+  /**
+   * Return the type arguments associated with the type.
+   */
+  NodeList<TypeName> get arguments;
+
+  /**
+   * Return the left bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Set the left bracket to the given [token].
+   */
+  void set leftBracket(Token token);
+
+  /**
+   * Return the right bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Set the right bracket to the given [token].
+   */
+  void set rightBracket(Token token);
+}
+
+/**
+ * A literal that has a type associated with it.
+ *
+ *    typedLiteral ::=
+ *        [ListLiteral]
+ *      | [MapLiteral]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypedLiteral extends Literal {
+  /**
+   * Return the token representing the 'const' keyword, or `null` if the literal
+   * is not a constant.
+   */
+  Token get constKeyword;
+
+  /**
+   * Set the token representing the 'const' keyword to the given [token].
+   */
+  void set constKeyword(Token token);
+
+  /**
+   * Return the type argument associated with this literal, or `null` if no type
+   * arguments were declared.
+   */
+  TypeArgumentList get typeArguments;
+
+  /**
+   * Set the type argument associated with this literal to the given
+   * [typeArguments].
+   */
+  void set typeArguments(TypeArgumentList typeArguments);
+}
+
+/**
+ * The name of a type, which can optionally include type arguments.
+ *
+ *    typeName ::=
+ *        [Identifier] typeArguments?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeName extends AstNode {
+  /**
+   * Initialize a newly created type name. The [typeArguments] can be `null` if
+   * there are no type arguments.
+   */
+  factory TypeName(Identifier name, TypeArgumentList typeArguments) =
+      TypeNameImpl;
+
+  /**
+   * Return `true` if this type is a deferred type.
+   *
+   * 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
+   * </i>p.T</i> where <i>p</i> is a deferred prefix.
+   */
+  bool get isDeferred;
+
+  /**
+   * Return the name of the type.
+   */
+  Identifier get name;
+
+  /**
+   * Set the name of the type to the given [identifier].
+   */
+  void set name(Identifier identifier);
+
+  /**
+   * Return the type being named, or `null` if the AST structure has not been
+   * resolved.
+   */
+  DartType get type;
+
+  /**
+   * Set the type being named to the given [type].
+   */
+  void set type(DartType type);
+
+  /**
+   * Return the type arguments associated with the type, or `null` if there are
+   * no type arguments.
+   */
+  TypeArgumentList get typeArguments;
+
+  /**
+   * Set the type arguments associated with the type to the given
+   * [typeArguments].
+   */
+  void set typeArguments(TypeArgumentList typeArguments);
+}
+
+/**
+ * A type parameter.
+ *
+ *    typeParameter ::=
+ *        [SimpleIdentifier] ('extends' [TypeName])?
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeParameter extends Declaration {
+  /**
+   * Initialize a newly created type parameter. Either or both of the [comment]
+   * and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute. The [extendsKeyword] and [bound] can be `null` if
+   * the parameter does not have an upper bound.
+   */
+  factory TypeParameter(
+      Comment comment,
+      List<Annotation> metadata,
+      SimpleIdentifier name,
+      Token extendsKeyword,
+      TypeName bound) = TypeParameterImpl;
+
+  /**
+   * Return the name of the upper bound for legal arguments, or `null` if there
+   * is no explicit upper bound.
+   */
+  TypeName get bound;
+
+  /**
+   * Set the name of the upper bound for legal arguments to the given
+   * [typeName].
+   */
+  void set bound(TypeName typeName);
+
+  /**
+   * Return the token representing the 'extends' keyword, or `null` if there is
+   * no explicit upper bound.
+   */
+  Token get extendsKeyword;
+
+  /**
+   * Set the token representing the 'extends' keyword to the given [token].
+   */
+  void set extendsKeyword(Token token);
+
+  /**
+   * Return the name of the type parameter.
+   */
+  SimpleIdentifier get name;
+
+  /**
+   * Set the name of the type parameter to the given [identifier].
+   */
+  void set name(SimpleIdentifier identifier);
+}
+
+/**
+ * Type parameters within a declaration.
+ *
+ *    typeParameterList ::=
+ *        '<' [TypeParameter] (',' [TypeParameter])* '>'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class TypeParameterList extends AstNode {
+  /**
+   * Initialize a newly created list of type parameters.
+   */
+  factory TypeParameterList(
+      Token leftBracket,
+      List<TypeParameter> typeParameters,
+      Token rightBracket) = TypeParameterListImpl;
+
+  /**
+   * Return the left angle bracket.
+   */
+  Token get leftBracket;
+
+  /**
+   * Return the right angle bracket.
+   */
+  Token get rightBracket;
+
+  /**
+   * Return the type parameters for the type.
+   */
+  NodeList<TypeParameter> get typeParameters;
+}
+
+/**
+ * A directive that references a URI.
+ *
+ *    uriBasedDirective ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ *      | [PartDirective]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class UriBasedDirective extends Directive {
+  /**
+   * Return the source to which the URI was resolved.
+   */
+  Source get source;
+
+  /**
+   * Set the source to which the URI was resolved to the given [source].
+   */
+  void set source(Source source);
+
+  /**
+   * Return the URI referenced by this directive.
+   */
+  StringLiteral get uri;
+
+  /**
+   * Set the URI referenced by this directive to the given [uri].
+   */
+  void set uri(StringLiteral uri);
+
+  /**
+   * Return the content of the URI.
+   */
+  String get uriContent;
+
+  /**
+   * Set the content of the URI to the given [content].
+   */
+  void set uriContent(String content);
+
+  /**
+   * Return the element associated with the URI of this directive, or `null` if
+   * the AST structure has not been resolved or if the URI could not be
+   * resolved. Examples of the latter case include a directive that contains an
+   * invalid URL or a URL that does not exist.
+   */
+  Element get uriElement;
+
+  /**
+   * Validate this directive, but do not check for existence. Return a code
+   * indicating the problem if there is one, or `null` no problem
+   */
+  UriValidationCode validate();
+}
+
+/**
+ * Validation codes returned by [UriBasedDirective.validate].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class UriValidationCode {
+  static const UriValidationCode INVALID_URI =
+      UriValidationCodeImpl.INVALID_URI;
+
+  static const UriValidationCode URI_WITH_INTERPOLATION =
+      UriValidationCodeImpl.URI_WITH_INTERPOLATION;
+
+  static const UriValidationCode URI_WITH_DART_EXT_SCHEME =
+      UriValidationCodeImpl.URI_WITH_DART_EXT_SCHEME;
+}
+
+/**
+ * An identifier that has an initial value associated with it. Instances of this
+ * class are always children of the class [VariableDeclarationList].
+ *
+ *    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.
+ * Consider changing the class hierarchy so that [VariableDeclaration] does not
+ * extend [Declaration].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class VariableDeclaration extends Declaration {
+  /**
+   * Initialize a newly created variable declaration. The [equals] and
+   * [initializer] can be `null` if there is no initializer.
+   */
+  factory VariableDeclaration(
+          SimpleIdentifier name, Token equals, Expression initializer) =
+      VariableDeclarationImpl;
+
+  @override
+  VariableElement get element;
+
+  /**
+   * Return the equal sign separating the variable name from the initial value,
+   * or `null` if the initial value was not specified.
+   */
+  Token get equals;
+
+  /**
+   * Set the equal sign separating the variable name from the initial value to
+   * the given [token].
+   */
+  void set equals(Token token);
+
+  /**
+   * Return the expression used to compute the initial value for the variable,
+   * or `null` if the initial value was not specified.
+   */
+  Expression get initializer;
+
+  /**
+   * Set the expression used to compute the initial value for the variable to
+   * the given [expression].
+   */
+  void set initializer(Expression expression);
+
+  /**
+   * Return `true` if this variable was declared with the 'const' modifier.
+   */
+  bool get isConst;
+
+  /**
+   * Return `true` if this variable was declared with the 'final' modifier.
+   * Variables that are declared with the 'const' modifier will return `false`
+   * even though they are implicitly final.
+   */
+  bool get isFinal;
+
+  /**
+   * Return the name of the variable being declared.
+   */
+  SimpleIdentifier get name;
+
+  /**
+   * Set the name of the variable being declared to the given [identifier].
+   */
+  void set name(SimpleIdentifier identifier);
+}
+
+/**
+ * The declaration of one or more variables of the same type.
+ *
+ *    variableDeclarationList ::=
+ *        finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+ *
+ *    finalConstVarOrType ::=
+ *      | 'final' [TypeName]?
+ *      | 'const' [TypeName]?
+ *      | 'var'
+ *      | [TypeName]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class VariableDeclarationList extends AnnotatedNode {
+  /**
+   * Initialize a newly created variable declaration list. Either or both of the
+   * [comment] and [metadata] can be `null` if the variable list does not have
+   * the corresponding attribute. The [keyword] can be `null` if a type was
+   * specified. The [type] must be `null` if the keyword is 'var'.
+   */
+  factory VariableDeclarationList(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      TypeName type,
+      List<VariableDeclaration> variables) = VariableDeclarationListImpl;
+
+  /**
+   * Return `true` if the variables in this list were declared with the 'const'
+   * modifier.
+   */
+  bool get isConst;
+
+  /**
+   * Return `true` if the variables in this list were declared with the 'final'
+   * modifier. Variables that are declared with the 'const' modifier will return
+   * `false` even though they are implicitly final. (In other words, this is a
+   * syntactic check rather than a semantic check.)
+   */
+  bool get isFinal;
+
+  /**
+   * Return the token representing the 'final', 'const' or 'var' keyword, or
+   * `null` if no keyword was included.
+   */
+  Token get keyword;
+
+  /**
+   * Set the token representing the 'final', 'const' or 'var' keyword to the
+   * given [token].
+   */
+  void set keyword(Token token);
+
+  /**
+   * Return the type of the variables being declared, or `null` if no type was
+   * provided.
+   */
+  TypeName get type;
+
+  /**
+   * Set the type of the variables being declared to the given [typeName].
+   */
+  void set type(TypeName typeName);
+
+  /**
+   * Return a list containing the individual variables being declared.
+   */
+  NodeList<VariableDeclaration> get variables;
+}
+
+/**
+ * A list of variables that are being declared in a context where a statement is
+ * required.
+ *
+ *    variableDeclarationStatement ::=
+ *        [VariableDeclarationList] ';'
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class VariableDeclarationStatement extends Statement {
+  /**
+   * Initialize a newly created variable declaration statement.
+   */
+  factory VariableDeclarationStatement(
+          VariableDeclarationList variableList, Token semicolon) =
+      VariableDeclarationStatementImpl;
+
+  /**
+   * Return the semicolon terminating the statement.
+   */
+  Token get semicolon;
+
+  /**
+   * Set the semicolon terminating the statement to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the variables being declared.
+   */
+  VariableDeclarationList get variables;
+
+  /**
+   * Set the variables being declared to the given list of [variables].
+   */
+  void set variables(VariableDeclarationList variables);
+}
+
+/**
+ * A while statement.
+ *
+ *    whileStatement ::=
+ *        'while' '(' [Expression] ')' [Statement]
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class WhileStatement extends Statement {
+  /**
+   * Initialize a newly created while statement.
+   */
+  factory WhileStatement(
+      Token whileKeyword,
+      Token leftParenthesis,
+      Expression condition,
+      Token rightParenthesis,
+      Statement body) = WhileStatementImpl;
+
+  /**
+   * Return the body of the loop.
+   */
+  Statement get body;
+
+  /**
+   * Set the body of the loop to the given [statement].
+   */
+  void set body(Statement statement);
+
+  /**
+   * Return the expression used to determine whether to execute the body of the
+   * loop.
+   */
+  Expression get condition;
+
+  /**
+   * Set the expression used to determine whether to execute the body of the
+   * loop to the given [expression].
+   */
+  void set condition(Expression expression);
+
+  /**
+   * Return the left parenthesis.
+   */
+  Token get leftParenthesis;
+
+  /**
+   * Set the left parenthesis to the given [token].
+   */
+  void set leftParenthesis(Token token);
+
+  /**
+   * Return the right parenthesis.
+   */
+  Token get rightParenthesis;
+
+  /**
+   * Set the right parenthesis to the given [token].
+   */
+  void set rightParenthesis(Token token);
+
+  /**
+   * Return the token representing the 'while' keyword.
+   */
+  Token get whileKeyword;
+
+  /**
+   * Set the token representing the 'while' keyword to the given [token].
+   */
+  void set whileKeyword(Token token);
+}
+
+/**
+ * The with clause in a class declaration.
+ *
+ *    withClause ::=
+ *        'with' [TypeName] (',' [TypeName])*
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class WithClause extends AstNode {
+  /**
+   * Initialize a newly created with clause.
+   */
+  factory WithClause(Token withKeyword, List<TypeName> mixinTypes) =
+      WithClauseImpl;
+
+  /**
+   * Return the names of the mixins that were specified.
+   */
+  NodeList<TypeName> get mixinTypes;
+
+  /**
+   * Return the token representing the 'with' keyword.
+   */
+  Token get withKeyword;
+
+  /**
+   * Set the token representing the 'with' keyword to the given [token].
+   */
+  void set withKeyword(Token token);
+}
+
+/**
+ * A yield statement.
+ *
+ *    yieldStatement ::=
+ *        'yield' '*'? [Expression] ‘;’
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class YieldStatement extends Statement {
+  /**
+   * Initialize a newly created yield expression. The [star] can be `null` if no
+   * star was provided.
+   */
+  factory YieldStatement(Token yieldKeyword, Token star, Expression expression,
+      Token semicolon) = YieldStatementImpl;
+
+  /**
+   * Return the expression whose value will be yielded.
+   */
+  Expression get expression;
+
+  /**
+   * Set the expression whose value will be yielded to the given [expression].
+   */
+  void set expression(Expression expression);
+
+  /**
+   * Return the semicolon following the expression.
+   */
+  Token get semicolon;
+
+  /**
+   * Return the semicolon following the expression to the given [token].
+   */
+  void set semicolon(Token token);
+
+  /**
+   * Return the star optionally following the 'yield' keyword.
+   */
+  Token get star;
+
+  /**
+   * Return the star optionally following the 'yield' keyword to the given [token].
+   */
+  void set star(Token token);
+
+  /**
+   * Return the 'yield' keyword.
+   */
+  Token get yieldKeyword;
+
+  /**
+   * Return the 'yield' keyword to the given [token].
+   */
+  void set yieldKeyword(Token token);
+}
diff --git a/pkg/analyzer/lib/dart/ast/token.dart b/pkg/analyzer/lib/dart/ast/token.dart
new file mode 100644
index 0000000..6560a8e
--- /dev/null
+++ b/pkg/analyzer/lib/dart/ast/token.dart
@@ -0,0 +1,738 @@
+// 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.
+
+/**
+ * Defines the tokens that are produced by the scanner, used by the parser, and
+ * referenced from the [AST structure](ast.dart).
+ */
+library analyzer.dart.ast.token;
+
+import 'dart:collection';
+
+import 'package:analyzer/src/dart/ast/token.dart' show SimpleToken, TokenClass;
+
+/**
+ * The keywords in the Dart programming language.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Keyword {
+  static const Keyword ABSTRACT = const Keyword._('ABSTRACT', "abstract", true);
+
+  static const Keyword AS = const Keyword._('AS', "as", true);
+
+  static const Keyword ASSERT = const Keyword._('ASSERT', "assert");
+
+  static const Keyword BREAK = const Keyword._('BREAK', "break");
+
+  static const Keyword CASE = const Keyword._('CASE', "case");
+
+  static const Keyword CATCH = const Keyword._('CATCH', "catch");
+
+  static const Keyword CLASS = const Keyword._('CLASS', "class");
+
+  static const Keyword CONST = const Keyword._('CONST', "const");
+
+  static const Keyword CONTINUE = const Keyword._('CONTINUE', "continue");
+
+  static const Keyword DEFAULT = const Keyword._('DEFAULT', "default");
+
+  static const Keyword DEFERRED = const Keyword._('DEFERRED', "deferred", true);
+
+  static const Keyword DO = const Keyword._('DO', "do");
+
+  static const Keyword DYNAMIC = const Keyword._('DYNAMIC', "dynamic", true);
+
+  static const Keyword ELSE = const Keyword._('ELSE', "else");
+
+  static const Keyword ENUM = const Keyword._('ENUM', "enum");
+
+  static const Keyword EXPORT = const Keyword._('EXPORT', "export", true);
+
+  static const Keyword EXTENDS = const Keyword._('EXTENDS', "extends");
+
+  static const Keyword EXTERNAL = const Keyword._('EXTERNAL', "external", true);
+
+  static const Keyword FACTORY = const Keyword._('FACTORY', "factory", true);
+
+  static const Keyword FALSE = const Keyword._('FALSE', "false");
+
+  static const Keyword FINAL = const Keyword._('FINAL', "final");
+
+  static const Keyword FINALLY = const Keyword._('FINALLY', "finally");
+
+  static const Keyword FOR = const Keyword._('FOR', "for");
+
+  static const Keyword GET = const Keyword._('GET', "get", true);
+
+  static const Keyword IF = const Keyword._('IF', "if");
+
+  static const Keyword IMPLEMENTS =
+      const Keyword._('IMPLEMENTS', "implements", true);
+
+  static const Keyword IMPORT = const Keyword._('IMPORT', "import", true);
+
+  static const Keyword IN = const Keyword._('IN', "in");
+
+  static const Keyword IS = const Keyword._('IS', "is");
+
+  static const Keyword LIBRARY = const Keyword._('LIBRARY', "library", true);
+
+  static const Keyword NEW = const Keyword._('NEW', "new");
+
+  static const Keyword NULL = const Keyword._('NULL', "null");
+
+  static const Keyword OPERATOR = const Keyword._('OPERATOR', "operator", true);
+
+  static const Keyword PART = const Keyword._('PART', "part", true);
+
+  static const Keyword RETHROW = const Keyword._('RETHROW', "rethrow");
+
+  static const Keyword RETURN = const Keyword._('RETURN', "return");
+
+  static const Keyword SET = const Keyword._('SET', "set", true);
+
+  static const Keyword STATIC = const Keyword._('STATIC', "static", true);
+
+  static const Keyword SUPER = const Keyword._('SUPER', "super");
+
+  static const Keyword SWITCH = const Keyword._('SWITCH', "switch");
+
+  static const Keyword THIS = const Keyword._('THIS', "this");
+
+  static const Keyword THROW = const Keyword._('THROW', "throw");
+
+  static const Keyword TRUE = const Keyword._('TRUE', "true");
+
+  static const Keyword TRY = const Keyword._('TRY', "try");
+
+  static const Keyword TYPEDEF = const Keyword._('TYPEDEF', "typedef", true);
+
+  static const Keyword VAR = const Keyword._('VAR', "var");
+
+  static const Keyword VOID = const Keyword._('VOID', "void");
+
+  static const Keyword WHILE = const Keyword._('WHILE', "while");
+
+  static const Keyword WITH = const Keyword._('WITH', "with");
+
+  static const List<Keyword> values = const <Keyword>[
+    ABSTRACT,
+    AS,
+    ASSERT,
+    BREAK,
+    CASE,
+    CATCH,
+    CLASS,
+    CONST,
+    CONTINUE,
+    DEFAULT,
+    DEFERRED,
+    DO,
+    DYNAMIC,
+    ELSE,
+    ENUM,
+    EXPORT,
+    EXTENDS,
+    EXTERNAL,
+    FACTORY,
+    FALSE,
+    FINAL,
+    FINALLY,
+    FOR,
+    GET,
+    IF,
+    IMPLEMENTS,
+    IMPORT,
+    IN,
+    IS,
+    LIBRARY,
+    NEW,
+    NULL,
+    OPERATOR,
+    PART,
+    RETHROW,
+    RETURN,
+    SET,
+    STATIC,
+    SUPER,
+    SWITCH,
+    THIS,
+    THROW,
+    TRUE,
+    TRY,
+    TYPEDEF,
+    VAR,
+    VOID,
+    WHILE,
+    WITH,
+  ];
+
+  /**
+   * A table mapping the lexemes of keywords to the corresponding keyword.
+   */
+  static final Map<String, Keyword> keywords = _createKeywordMap();
+
+  /**
+   * The name of the keyword type.
+   */
+  final String name;
+
+  /**
+   * The lexeme for the keyword.
+   */
+  final String syntax;
+
+  /**
+   * A flag indicating whether the keyword is a pseudo-keyword. Pseudo keywords
+   * can be used as identifiers.
+   */
+  final bool isPseudoKeyword;
+
+  /**
+   * Initialize a newly created keyword to have the given [name] and [syntax].
+   * The keyword is a pseudo-keyword if the [isPseudoKeyword] flag is `true`.
+   */
+  const Keyword._(this.name, this.syntax, [this.isPseudoKeyword = false]);
+
+  @override
+  String toString() => name;
+
+  /**
+   * Create a table mapping the lexemes of keywords to the corresponding keyword
+   * and return the table that was created.
+   */
+  static Map<String, Keyword> _createKeywordMap() {
+    LinkedHashMap<String, Keyword> result =
+        new LinkedHashMap<String, Keyword>();
+    for (Keyword keyword in values) {
+      result[keyword.syntax] = keyword;
+    }
+    return result;
+  }
+}
+
+/**
+ * A token that was scanned from the input. Each token knows which tokens
+ * precede and follow it, acting as a link in a doubly linked list of tokens.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class Token {
+  /**
+   * Initialize a newly created token to have the given [type] and [offset].
+   */
+  factory Token(TokenType type, int offset) = SimpleToken;
+
+  /**
+   * Return the offset from the beginning of the file to the character after the
+   * last character of the token.
+   */
+  int get end;
+
+  /**
+   * Return `true` if this token represents an operator.
+   */
+  bool get isOperator;
+
+  /**
+   * Return `true` if this token is a synthetic token. A synthetic token is a
+   * token that was introduced by the parser in order to recover from an error
+   * in the code.
+   */
+  bool get isSynthetic;
+
+  /**
+   * Return `true` if this token represents an operator that can be defined by
+   * users.
+   */
+  bool get isUserDefinableOperator;
+
+  /**
+   * Return the number of characters in the node's source range.
+   */
+  int get length;
+
+  /**
+   * Return the lexeme that represents this token.
+   */
+  String get lexeme;
+
+  /**
+   * Return the next token in the token stream.
+   */
+  Token get next;
+
+  /**
+   * Return the offset from the beginning of the file to the first character in
+   * the token.
+   */
+  int get offset;
+
+  /**
+   * Set the offset from the beginning of the file to the first character in
+   * the token to the given [offset].
+   */
+  void set offset(int offset);
+
+  /**
+   * Return the first comment in the list of comments that precede this token,
+   * or `null` if there are no comments preceding this token. Additional
+   * comments can be reached by following the token stream using [next] until
+   * `null` is returned.
+   *
+   * For example, if the original contents were `/* one */ /* two */ id`, then
+   * the first preceding comment token will have a lexeme of `/* one */` and
+   * the next comment token will have a lexeme of `/* two */`.
+   */
+  Token get precedingComments;
+
+  /**
+   * Return the previous token in the token stream.
+   */
+  Token get previous;
+
+  /**
+   * Set the previous token in the token stream to the given [token].
+   */
+  void set previous(Token token);
+
+  /**
+   * Return the type of the token.
+   */
+  TokenType get type;
+
+  /**
+   * Apply (add) the given [delta] to this token's offset.
+   */
+  void applyDelta(int delta);
+
+  /**
+   * Return a newly created token that is a copy of this token but that is not a
+   * part of any token stream.
+   */
+  Token copy();
+
+  /**
+   * Copy a linked list of comment tokens identical to the given comment tokens.
+   */
+  Token copyComments(Token token);
+
+  /**
+   * Return `true` if this token has any one of the given [types].
+   */
+  bool matchesAny(List<TokenType> types);
+
+  /**
+   * Set the next token in the token stream to the given [token]. This has the
+   * side-effect of setting this token to be the previous token for the given
+   * token. Return the token that was passed in.
+   */
+  Token setNext(Token token);
+
+  /**
+   * Set the next token in the token stream to the given token without changing
+   * which token is the previous token for the given token. Return the token
+   * that was passed in.
+   */
+  Token setNextWithoutSettingPrevious(Token token);
+
+  /**
+   * Return the value of this token. For keyword tokens, this is the keyword
+   * associated with the token, for other tokens it is the lexeme associated
+   * with the token.
+   */
+  Object value();
+
+  /**
+   * Compare the given [tokens] to find the token that appears first in the
+   * source being parsed. That is, return the left-most of all of the tokens.
+   * The list must be non-`null`, but the elements of the list are allowed to be
+   * `null`. Return the token with the smallest offset, or `null` if the list is
+   * empty or if all of the elements of the list are `null`.
+   */
+  static Token lexicallyFirst(List<Token> tokens) {
+    Token first = null;
+    int offset = -1;
+    for (Token token in tokens) {
+      if (token != null && (offset < 0 || token.offset < offset)) {
+        first = token;
+        offset = token.offset;
+      }
+    }
+    return first;
+  }
+}
+
+/**
+ * The types of tokens that can be returned by the scanner.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class TokenType {
+  /**
+   * The type of the token that marks the start or end of the input.
+   */
+  static const TokenType EOF = const _EndOfFileTokenType();
+
+  static const TokenType DOUBLE = const TokenType._('DOUBLE');
+
+  static const TokenType HEXADECIMAL = const TokenType._('HEXADECIMAL');
+
+  static const TokenType IDENTIFIER = const TokenType._('IDENTIFIER');
+
+  static const TokenType INT = const TokenType._('INT');
+
+  static const TokenType KEYWORD = const TokenType._('KEYWORD');
+
+  static const TokenType MULTI_LINE_COMMENT =
+      const TokenType._('MULTI_LINE_COMMENT');
+
+  static const TokenType SCRIPT_TAG = const TokenType._('SCRIPT_TAG');
+
+  static const TokenType SINGLE_LINE_COMMENT =
+      const TokenType._('SINGLE_LINE_COMMENT');
+
+  static const TokenType STRING = const TokenType._('STRING');
+
+  static const TokenType AMPERSAND =
+      const TokenType._('AMPERSAND', TokenClass.BITWISE_AND_OPERATOR, '&');
+
+  static const TokenType AMPERSAND_AMPERSAND = const TokenType._(
+      'AMPERSAND_AMPERSAND', TokenClass.LOGICAL_AND_OPERATOR, '&&');
+
+  static const TokenType AMPERSAND_EQ =
+      const TokenType._('AMPERSAND_EQ', TokenClass.ASSIGNMENT_OPERATOR, '&=');
+
+  static const TokenType AT = const TokenType._('AT', TokenClass.NO_CLASS, '@');
+
+  static const TokenType BANG =
+      const TokenType._('BANG', TokenClass.UNARY_PREFIX_OPERATOR, '!');
+
+  static const TokenType BANG_EQ =
+      const TokenType._('BANG_EQ', TokenClass.EQUALITY_OPERATOR, '!=');
+
+  static const TokenType BAR =
+      const TokenType._('BAR', TokenClass.BITWISE_OR_OPERATOR, '|');
+
+  static const TokenType BAR_BAR =
+      const TokenType._('BAR_BAR', TokenClass.LOGICAL_OR_OPERATOR, '||');
+
+  static const TokenType BAR_EQ =
+      const TokenType._('BAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, '|=');
+
+  static const TokenType COLON =
+      const TokenType._('COLON', TokenClass.NO_CLASS, ':');
+
+  static const TokenType COMMA =
+      const TokenType._('COMMA', TokenClass.NO_CLASS, ',');
+
+  static const TokenType CARET =
+      const TokenType._('CARET', TokenClass.BITWISE_XOR_OPERATOR, '^');
+
+  static const TokenType CARET_EQ =
+      const TokenType._('CARET_EQ', TokenClass.ASSIGNMENT_OPERATOR, '^=');
+
+  static const TokenType CLOSE_CURLY_BRACKET =
+      const TokenType._('CLOSE_CURLY_BRACKET', TokenClass.NO_CLASS, '}');
+
+  static const TokenType CLOSE_PAREN =
+      const TokenType._('CLOSE_PAREN', TokenClass.NO_CLASS, ')');
+
+  static const TokenType CLOSE_SQUARE_BRACKET =
+      const TokenType._('CLOSE_SQUARE_BRACKET', TokenClass.NO_CLASS, ']');
+
+  static const TokenType EQ =
+      const TokenType._('EQ', TokenClass.ASSIGNMENT_OPERATOR, '=');
+
+  static const TokenType EQ_EQ =
+      const TokenType._('EQ_EQ', TokenClass.EQUALITY_OPERATOR, '==');
+
+  static const TokenType FUNCTION =
+      const TokenType._('FUNCTION', TokenClass.NO_CLASS, '=>');
+
+  static const TokenType GT =
+      const TokenType._('GT', TokenClass.RELATIONAL_OPERATOR, '>');
+
+  static const TokenType GT_EQ =
+      const TokenType._('GT_EQ', TokenClass.RELATIONAL_OPERATOR, '>=');
+
+  static const TokenType GT_GT =
+      const TokenType._('GT_GT', TokenClass.SHIFT_OPERATOR, '>>');
+
+  static const TokenType GT_GT_EQ =
+      const TokenType._('GT_GT_EQ', TokenClass.ASSIGNMENT_OPERATOR, '>>=');
+
+  static const TokenType HASH =
+      const TokenType._('HASH', TokenClass.NO_CLASS, '#');
+
+  static const TokenType INDEX =
+      const TokenType._('INDEX', TokenClass.UNARY_POSTFIX_OPERATOR, '[]');
+
+  static const TokenType INDEX_EQ =
+      const TokenType._('INDEX_EQ', TokenClass.UNARY_POSTFIX_OPERATOR, '[]=');
+
+  static const TokenType IS =
+      const TokenType._('IS', TokenClass.RELATIONAL_OPERATOR, 'is');
+
+  static const TokenType LT =
+      const TokenType._('LT', TokenClass.RELATIONAL_OPERATOR, '<');
+
+  static const TokenType LT_EQ =
+      const TokenType._('LT_EQ', TokenClass.RELATIONAL_OPERATOR, '<=');
+
+  static const TokenType LT_LT =
+      const TokenType._('LT_LT', TokenClass.SHIFT_OPERATOR, '<<');
+
+  static const TokenType LT_LT_EQ =
+      const TokenType._('LT_LT_EQ', TokenClass.ASSIGNMENT_OPERATOR, '<<=');
+
+  static const TokenType MINUS =
+      const TokenType._('MINUS', TokenClass.ADDITIVE_OPERATOR, '-');
+
+  static const TokenType MINUS_EQ =
+      const TokenType._('MINUS_EQ', TokenClass.ASSIGNMENT_OPERATOR, '-=');
+
+  static const TokenType MINUS_MINUS =
+      const TokenType._('MINUS_MINUS', TokenClass.UNARY_PREFIX_OPERATOR, '--');
+
+  static const TokenType OPEN_CURLY_BRACKET =
+      const TokenType._('OPEN_CURLY_BRACKET', TokenClass.NO_CLASS, '{');
+
+  static const TokenType OPEN_PAREN =
+      const TokenType._('OPEN_PAREN', TokenClass.UNARY_POSTFIX_OPERATOR, '(');
+
+  static const TokenType OPEN_SQUARE_BRACKET = const TokenType._(
+      'OPEN_SQUARE_BRACKET', TokenClass.UNARY_POSTFIX_OPERATOR, '[');
+
+  static const TokenType PERCENT =
+      const TokenType._('PERCENT', TokenClass.MULTIPLICATIVE_OPERATOR, '%');
+
+  static const TokenType PERCENT_EQ =
+      const TokenType._('PERCENT_EQ', TokenClass.ASSIGNMENT_OPERATOR, '%=');
+
+  static const TokenType PERIOD =
+      const TokenType._('PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, '.');
+
+  static const TokenType PERIOD_PERIOD =
+      const TokenType._('PERIOD_PERIOD', TokenClass.CASCADE_OPERATOR, '..');
+
+  static const TokenType PLUS =
+      const TokenType._('PLUS', TokenClass.ADDITIVE_OPERATOR, '+');
+
+  static const TokenType PLUS_EQ =
+      const TokenType._('PLUS_EQ', TokenClass.ASSIGNMENT_OPERATOR, '+=');
+
+  static const TokenType PLUS_PLUS =
+      const TokenType._('PLUS_PLUS', TokenClass.UNARY_PREFIX_OPERATOR, '++');
+
+  static const TokenType QUESTION =
+      const TokenType._('QUESTION', TokenClass.CONDITIONAL_OPERATOR, '?');
+
+  static const TokenType QUESTION_PERIOD = const TokenType._(
+      'QUESTION_PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, '?.');
+
+  static const TokenType QUESTION_QUESTION =
+      const TokenType._('QUESTION_QUESTION', TokenClass.IF_NULL_OPERATOR, '??');
+
+  static const TokenType QUESTION_QUESTION_EQ = const TokenType._(
+      'QUESTION_QUESTION_EQ', TokenClass.ASSIGNMENT_OPERATOR, '??=');
+
+  static const TokenType SEMICOLON =
+      const TokenType._('SEMICOLON', TokenClass.NO_CLASS, ';');
+
+  static const TokenType SLASH =
+      const TokenType._('SLASH', TokenClass.MULTIPLICATIVE_OPERATOR, '/');
+
+  static const TokenType SLASH_EQ =
+      const TokenType._('SLASH_EQ', TokenClass.ASSIGNMENT_OPERATOR, '/=');
+
+  static const TokenType STAR =
+      const TokenType._('STAR', TokenClass.MULTIPLICATIVE_OPERATOR, '*');
+
+  static const TokenType STAR_EQ =
+      const TokenType._('STAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, "*=");
+
+  static const TokenType STRING_INTERPOLATION_EXPRESSION = const TokenType._(
+      'STRING_INTERPOLATION_EXPRESSION', TokenClass.NO_CLASS, '\${');
+
+  static const TokenType STRING_INTERPOLATION_IDENTIFIER = const TokenType._(
+      'STRING_INTERPOLATION_IDENTIFIER', TokenClass.NO_CLASS, '\$');
+
+  static const TokenType TILDE =
+      const TokenType._('TILDE', TokenClass.UNARY_PREFIX_OPERATOR, '~');
+
+  static const TokenType TILDE_SLASH = const TokenType._(
+      'TILDE_SLASH', TokenClass.MULTIPLICATIVE_OPERATOR, '~/');
+
+  static const TokenType TILDE_SLASH_EQ = const TokenType._(
+      'TILDE_SLASH_EQ', TokenClass.ASSIGNMENT_OPERATOR, '~/=');
+
+  static const TokenType BACKPING =
+      const TokenType._('BACKPING', TokenClass.NO_CLASS, '`');
+
+  static const TokenType BACKSLASH =
+      const TokenType._('BACKSLASH', TokenClass.NO_CLASS, '\\');
+
+  static const TokenType PERIOD_PERIOD_PERIOD =
+      const TokenType._('PERIOD_PERIOD_PERIOD', TokenClass.NO_CLASS, '...');
+
+  static const TokenType GENERIC_METHOD_TYPE_LIST =
+      const TokenType._('GENERIC_METHOD_TYPE_LIST');
+
+  static const TokenType GENERIC_METHOD_TYPE_ASSIGN =
+      const TokenType._('GENERIC_METHOD_TYPE_ASSIGN');
+
+  /**
+   * The class of the token.
+   */
+  final TokenClass _tokenClass;
+
+  /**
+   * The name of the token type.
+   */
+  final String name;
+
+  /**
+   * The lexeme that defines this type of token, or `null` if there is more than
+   * one possible lexeme for this type of token.
+   */
+  final String lexeme;
+
+  /**
+   * Initialize a newly created token type to have the given [name],
+   * [_tokenClass] and [lexeme].
+   */
+  const TokenType._(this.name,
+      [this._tokenClass = TokenClass.NO_CLASS, this.lexeme = null]);
+
+  /**
+   * Return `true` if this type of token represents an additive operator.
+   */
+  bool get isAdditiveOperator => _tokenClass == TokenClass.ADDITIVE_OPERATOR;
+
+  /**
+   * Return `true` if this type of token represents an assignment operator.
+   */
+  bool get isAssignmentOperator =>
+      _tokenClass == TokenClass.ASSIGNMENT_OPERATOR;
+
+  /**
+   * Return `true` if this type of token represents an associative operator. An
+   * associative operator is an operator for which the following equality is
+   * true: `(a * b) * c == a * (b * c)`. In other words, if the result of
+   * applying the operator to multiple operands does not depend on the order in
+   * which those applications occur.
+   *
+   * Note: This method considers the logical-and and logical-or operators to be
+   * associative, even though the order in which the application of those
+   * operators can have an effect because evaluation of the right-hand operand
+   * is conditional.
+   */
+  bool get isAssociativeOperator =>
+      this == AMPERSAND ||
+      this == AMPERSAND_AMPERSAND ||
+      this == BAR ||
+      this == BAR_BAR ||
+      this == CARET ||
+      this == PLUS ||
+      this == STAR;
+
+  /**
+   * Return `true` if this type of token represents an equality operator.
+   */
+  bool get isEqualityOperator => _tokenClass == TokenClass.EQUALITY_OPERATOR;
+
+  /**
+   * Return `true` if this type of token represents an increment operator.
+   */
+  bool get isIncrementOperator =>
+      identical(lexeme, '++') || identical(lexeme, '--');
+
+  /**
+   * Return `true` if this type of token represents a multiplicative operator.
+   */
+  bool get isMultiplicativeOperator =>
+      _tokenClass == TokenClass.MULTIPLICATIVE_OPERATOR;
+
+  /**
+   * Return `true` if this token type represents an operator.
+   */
+  bool get isOperator =>
+      _tokenClass != TokenClass.NO_CLASS &&
+      this != OPEN_PAREN &&
+      this != OPEN_SQUARE_BRACKET &&
+      this != PERIOD;
+
+  /**
+   * Return `true` if this type of token represents a relational operator.
+   */
+  bool get isRelationalOperator =>
+      _tokenClass == TokenClass.RELATIONAL_OPERATOR;
+
+  /**
+   * Return `true` if this type of token represents a shift operator.
+   */
+  bool get isShiftOperator => _tokenClass == TokenClass.SHIFT_OPERATOR;
+
+  /**
+   * Return `true` if this type of token represents a unary postfix operator.
+   */
+  bool get isUnaryPostfixOperator =>
+      _tokenClass == TokenClass.UNARY_POSTFIX_OPERATOR;
+
+  /**
+   * Return `true` if this type of token represents a unary prefix operator.
+   */
+  bool get isUnaryPrefixOperator =>
+      _tokenClass == TokenClass.UNARY_PREFIX_OPERATOR;
+
+  /**
+   * Return `true` if this token type represents an operator that can be defined
+   * by users.
+   */
+  bool get isUserDefinableOperator =>
+      identical(lexeme, '==') ||
+      identical(lexeme, '~') ||
+      identical(lexeme, '[]') ||
+      identical(lexeme, '[]=') ||
+      identical(lexeme, '*') ||
+      identical(lexeme, '/') ||
+      identical(lexeme, '%') ||
+      identical(lexeme, '~/') ||
+      identical(lexeme, '+') ||
+      identical(lexeme, '-') ||
+      identical(lexeme, '<<') ||
+      identical(lexeme, '>>') ||
+      identical(lexeme, '>=') ||
+      identical(lexeme, '>') ||
+      identical(lexeme, '<=') ||
+      identical(lexeme, '<') ||
+      identical(lexeme, '&') ||
+      identical(lexeme, '^') ||
+      identical(lexeme, '|');
+
+  /**
+   * Return the precedence of the token, or `0` if the token does not represent
+   * an operator.
+   */
+  int get precedence => _tokenClass.precedence;
+
+  @override
+  String toString() => name;
+}
+
+/**
+ * A token representing the end (either the head or the tail) of a stream of
+ * tokens.
+ */
+class _EndOfFileTokenType extends TokenType {
+  /**
+   * Initialize a newly created token.
+   */
+  const _EndOfFileTokenType() : super._('EOF', TokenClass.NO_CLASS, '');
+
+  @override
+  String toString() => '-eof-';
+}
diff --git a/pkg/analyzer/lib/dart/ast/visitor.dart b/pkg/analyzer/lib/dart/ast/visitor.dart
index c9b345a..f76fb1d 100644
--- a/pkg/analyzer/lib/dart/ast/visitor.dart
+++ b/pkg/analyzer/lib/dart/ast/visitor.dart
@@ -2,11 +2,30 @@
 // 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.
 
+/**
+ * Defines AST visitors that support useful patterns for visiting the nodes in
+ * an [AST structure](ast.dart).
+ *
+ * Dart is an evolving language, and the AST structure must evolved with it.
+ * When the AST structure changes, the visitor interface will sometimes change
+ * as well. If it is desirable to get a compilation error when the structure of
+ * the AST has been modified, then you should consider implementing the
+ * interface [AstVisitor] directly. Doing so will ensure that changes that
+ * introduce new classes of nodes will be flagged. (Of course, not all changes
+ * to the AST structure require the addition of a new class of node, and hence
+ * cannot be caught this way.)
+ *
+ * But if automatic detection of these kinds of changes is not necessary then
+ * you will probably want to extend one of the classes in this library because
+ * doing so will simplify the task of writing your visitor and guard against
+ * future changes to the AST structure. For example, the [RecursiveAstVisitor]
+ * automates the process of visiting all of the descendants of a node.
+ */
 library analyzer.dart.ast.visitor;
 
 import 'dart:collection';
 
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
 
 /**
  * An AST visitor that will recursively visit all of the nodes in an AST
@@ -74,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 ab468ed..e89eb22 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -2,10 +2,42 @@
 // 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.
 
+/**
+ * Defines the element model. The element model describes the semantic (as
+ * opposed to syntactic) structure of Dart code. The syntactic structure of the
+ * code is modeled by the [AST structure](../ast/ast.dart).
+ *
+ * The element model consists of two closely related kinds of objects: elements
+ * (instances of a subclass of [Element]) and types. This library defines the
+ * elements, the types are defined in [type.dart](type.dart).
+ *
+ * Generally speaking, an element represents something that is declared in the
+ * code, such as a class, method, or variable. Elements are organized in a tree
+ * structure in which the children of an element are the elements that are
+ * logically (and often syntactically) part of the declaration of the parent.
+ * For example, the elements representing the methods and fields in a class are
+ * children of the element representing the class.
+ *
+ * Every complete element structure is rooted by an instance of the class
+ * [LibraryElement]. A library element represents a single Dart library. Every
+ * library is defined by one or more compilation units (the library and all of
+ * its parts). The compilation units are represented by the class
+ * [CompilationUnitElement] and are children of the library that is defined by
+ * them. Each compilation unit can contain zero or more top-level declarations,
+ * such as classes, functions, and variables. Each of these is in turn
+ * represented as an element that is a child of the compilation unit. Classes
+ * contain methods and fields, methods can contain local variables, etc.
+ *
+ * The element model does not contain everything in the code, only those things
+ * that are declared by the code. For example, it does not include any
+ * representation of the statements in a method body, but if one of those
+ * statements declares a local variable then the local variable will be
+ * represented by an element.
+ */
 library analyzer.dart.element.element;
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/constant.dart' show DartObject;
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/java_core.dart';
@@ -603,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.
    */
@@ -744,7 +781,7 @@
  *
  * Clients may not extend, implement or mix-in this class.
  */
-abstract class ElementAnnotation {
+abstract class ElementAnnotation implements ConstantEvaluationTarget {
   /**
    * An empty list of annotations.
    */
@@ -776,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.
@@ -1281,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;
@@ -1347,6 +1397,11 @@
   bool get isBrowserApplication;
 
   /**
+   * Return `true` if this library is the dart:async library.
+   */
+  bool get isDartAsync;
+
+  /**
    * Return `true` if this library is the dart:core library.
    */
   bool get isDartCore;
@@ -1427,14 +1482,12 @@
    * which the name of this element is visible, or `null` if there is no single
    * range of characters within which the element name is visible.
    *
-   * * For a local variable, this includes everything from the end of the
-   *   variable's initializer to the end of the block that encloses the variable
-   *   declaration.
+   * * For a local variable, this is the source range of the block that
+   *   encloses the variable declaration.
    * * For a parameter, this includes the body of the method or function that
    *   declares the parameter.
-   * * For a local function, this includes everything from the beginning of the
-   *   function's body to the end of the block that encloses the function
-   *   declaration.
+   * * For a local function, this is the source range of the block that
+   *   encloses the variable declaration.
    * * For top-level functions, `null` will be returned because they are
    *   potentially visible in multiple sources.
    */
@@ -1470,154 +1523,6 @@
 }
 
 /**
- * The enumeration `Modifier` defines constants for all of the modifiers defined
- * by the Dart language and for a few additional flags that are useful.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-class Modifier extends Enum<Modifier> {
-  /**
-   * Indicates that the modifier 'abstract' was applied to the element.
-   */
-  static const Modifier ABSTRACT = const Modifier('ABSTRACT', 0);
-
-  /**
-   * Indicates that an executable element has a body marked as being
-   * asynchronous.
-   */
-  static const Modifier ASYNCHRONOUS = const Modifier('ASYNCHRONOUS', 1);
-
-  /**
-   * Indicates that the modifier 'const' was applied to the element.
-   */
-  static const Modifier CONST = const Modifier('CONST', 2);
-
-  /**
-   * Indicates that the import element represents a deferred library.
-   */
-  static const Modifier DEFERRED = const Modifier('DEFERRED', 3);
-
-  /**
-   * Indicates that a class element was defined by an enum declaration.
-   */
-  static const Modifier ENUM = const Modifier('ENUM', 4);
-
-  /**
-   * Indicates that a class element was defined by an enum declaration.
-   */
-  static const Modifier EXTERNAL = const Modifier('EXTERNAL', 5);
-
-  /**
-   * Indicates that the modifier 'factory' was applied to the element.
-   */
-  static const Modifier FACTORY = const Modifier('FACTORY', 6);
-
-  /**
-   * Indicates that the modifier 'final' was applied to the element.
-   */
-  static const Modifier FINAL = const Modifier('FINAL', 7);
-
-  /**
-   * Indicates that an executable element has a body marked as being a
-   * generator.
-   */
-  static const Modifier GENERATOR = const Modifier('GENERATOR', 8);
-
-  /**
-   * Indicates that the pseudo-modifier 'get' was applied to the element.
-   */
-  static const Modifier GETTER = const Modifier('GETTER', 9);
-
-  /**
-   * A flag used for libraries indicating that the defining compilation unit
-   * contains at least one import directive whose URI uses the "dart-ext"
-   * scheme.
-   */
-  static const Modifier HAS_EXT_URI = const Modifier('HAS_EXT_URI', 10);
-
-  /**
-   * Indicates that the associated element did not have an explicit type
-   * associated with it. If the element is an [ExecutableElement], then the
-   * type being referred to is the return type.
-   */
-  static const Modifier IMPLICIT_TYPE = const Modifier('IMPLICIT_TYPE', 11);
-
-  /**
-   * Indicates that a class can validly be used as a mixin.
-   */
-  static const Modifier MIXIN = const Modifier('MIXIN', 12);
-
-  /**
-   * Indicates that a class is a mixin application.
-   */
-  static const Modifier MIXIN_APPLICATION =
-      const Modifier('MIXIN_APPLICATION', 13);
-
-  /**
-   * Indicates that the value of a parameter or local variable might be mutated
-   * within the context.
-   */
-  static const Modifier POTENTIALLY_MUTATED_IN_CONTEXT =
-      const Modifier('POTENTIALLY_MUTATED_IN_CONTEXT', 14);
-
-  /**
-   * Indicates that the value of a parameter or local variable might be mutated
-   * within the scope.
-   */
-  static const Modifier POTENTIALLY_MUTATED_IN_SCOPE =
-      const Modifier('POTENTIALLY_MUTATED_IN_SCOPE', 15);
-
-  /**
-   * Indicates that a class contains an explicit reference to 'super'.
-   */
-  static const Modifier REFERENCES_SUPER =
-      const Modifier('REFERENCES_SUPER', 16);
-
-  /**
-   * Indicates that the pseudo-modifier 'set' was applied to the element.
-   */
-  static const Modifier SETTER = const Modifier('SETTER', 17);
-
-  /**
-   * Indicates that the modifier 'static' was applied to the element.
-   */
-  static const Modifier STATIC = const Modifier('STATIC', 18);
-
-  /**
-   * Indicates that the element does not appear in the source code but was
-   * implicitly created. For example, if a class does not define any
-   * constructors, an implicit zero-argument constructor will be created and it
-   * will be marked as being synthetic.
-   */
-  static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 19);
-
-  static const List<Modifier> values = const [
-    ABSTRACT,
-    ASYNCHRONOUS,
-    CONST,
-    DEFERRED,
-    ENUM,
-    EXTERNAL,
-    FACTORY,
-    FINAL,
-    GENERATOR,
-    GETTER,
-    HAS_EXT_URI,
-    IMPLICIT_TYPE,
-    MIXIN,
-    MIXIN_APPLICATION,
-    POTENTIALLY_MUTATED_IN_CONTEXT,
-    POTENTIALLY_MUTATED_IN_SCOPE,
-    REFERENCES_SUPER,
-    SETTER,
-    STATIC,
-    SYNTHETIC
-  ];
-
-  const Modifier(String name, int ordinal) : super(name, ordinal);
-}
-
-/**
  * A pseudo-element that represents multiple elements defined within a single
  * scope that have the same name. This situation is not allowed by the language,
  * so objects implementing this interface always represent an error. As a
@@ -1732,9 +1637,13 @@
   LibraryElement get enclosingElement;
 
   /**
-   * Return a list containing all of the libraries that are imported using this
-   * prefix.
+   * Return the empty list.
+   *
+   * Deprecated: this getter was intended to return a list containing all of
+   * the libraries that are imported using this prefix, but it was never
+   * implemented.  Due to lack of demand, it is being removed.
    */
+  @deprecated
   List<LibraryElement> get importedLibraries;
 }
 
@@ -2020,7 +1929,12 @@
    * closure. This information is only available for local variables (including
    * parameters) and only after the compilation unit containing the variable has
    * been resolved.
+   *
+   * This getter is deprecated--it now returns `true` for all local variables
+   * and parameters.  Please use [FunctionBody.isPotentiallyMutatedInClosure]
+   * instead.
    */
+  @deprecated
   bool get isPotentiallyMutatedInClosure;
 
   /**
@@ -2028,7 +1942,12 @@
    * scope. This information is only available for local variables (including
    * parameters) and only after the compilation unit containing the variable has
    * been resolved.
+   *
+   * This getter is deprecated--it now returns `true` for all local variables
+   * and parameters.  Please use [FunctionBody.isPotentiallyMutatedInClosure]
+   * instead.
    */
+  @deprecated
   bool get isPotentiallyMutatedInScope;
 
   /**
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 548dc1d..3ff2ce8 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -2,10 +2,29 @@
 // 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.
 
+/**
+ * Defines the type model. The type model is part of the
+ * [element model](element.dart) in that most types are defined by Dart code
+ * (the types `dynamic` and `void` being the notable exceptions). All types are
+ * represented by an instance of a subclass of [DartType].
+ *
+ * Other than `dynamic` and `void`, all of the types define either the interface
+ * defined by a class (an instance of [InterfaceType]) or the type of a function
+ * (an instance of [FunctionType]).
+ *
+ * We make a distinction between the declaration of a class (a [ClassElement])
+ * and the type defined by that class (an [InterfaceType]). The biggest reason
+ * for the distinction is to allow us to more cleanly represent the distinction
+ * between type parameters and type arguments. For example, if we define a class
+ * as `class Pair<K, V> {}`, the declarations of `K` and `V` represent type
+ * parameters. But if we declare a variable as `Pair<String, int> pair;` the
+ * references to `String` and `int` are type arguments.
+ */
 library analyzer.dart.element.type;
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart' show InterfaceTypeImpl;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystem;
 
 /**
  * The type associated with elements in the element model.
@@ -38,6 +57,12 @@
   bool get isBottom;
 
   /**
+   * Return `true` if this type represents the type 'Future' defined in the
+   * dart:async library.
+   */
+  bool get isDartAsyncFuture;
+
+  /**
    * Return `true` if this type represents the type 'Function' defined in the
    * dart:core library.
    */
@@ -70,6 +95,19 @@
   String get name;
 
   /**
+   * Implements the function "flatten" defined in the spec, where T is this
+   * type:
+   *
+   *     If T = Future<S> then flatten(T) = flatten(S).
+   *
+   *     Otherwise if T <: Future then let S be a type such that T << Future<S>
+   *     and for all R, if T << Future<R> then S << R.  Then flatten(T) = S.
+   *
+   *     In any other circumstance, flatten(T) = T.
+   */
+  DartType flattenFutures(TypeSystem typeSystem);
+
+  /**
    * Return `true` if this type is assignable to the given [type]. A type
    * <i>T</i> may be assigned to a type <i>S</i>, written <i>T</i> &hArr;
    * <i>S</i>, iff either <i>T</i> <: <i>S</i> or <i>S</i> <: <i>T</i>.
@@ -112,6 +150,15 @@
    */
   DartType substitute2(
       List<DartType> argumentTypes, List<DartType> parameterTypes);
+
+  /**
+   * If this type is a [TypeParameterType], returns its bound if it has one, or
+   * [objectType] otherwise.
+   *
+   * For any other type, returns `this`. Applies recursively -- if the bound is
+   * itself a type parameter, that is resolved too.
+   */
+  DartType resolveToBound(DartType objectType);
 }
 
 /**
@@ -137,16 +184,6 @@
   List<TypeParameterElement> get boundTypeParameters;
 
   /**
-   * The formal type parameters of this generic function.
-   * For example `<T> T -> T`.
-   *
-   * These are distinct from the [typeParameters] list, which contains type
-   * parameters from surrounding contexts, and thus are free type variables from
-   * the perspective of this function type.
-   */
-  List<TypeParameterElement> get typeFormals;
-
-  /**
    * Return a map from the names of named parameters to the types of the named
    * parameters of this type of function. The entries in the map will be
    * iterated in the same order as the order in which the named parameters were
@@ -156,6 +193,12 @@
   Map<String, DartType> get namedParameterTypes;
 
   /**
+   * The names of the required positional parameters of this type of function,
+   * in the order that the parameters appear.
+   */
+  List<String> get normalParameterNames;
+
+  /**
    * Return a list containing the types of the normal parameters of this type of
    * function. The parameter types are in the same order as they appear in the
    * declaration of the function.
@@ -163,6 +206,12 @@
   List<DartType> get normalParameterTypes;
 
   /**
+   * The names of the optional positional parameters of this type of function,
+   * in the order that the parameters appear.
+   */
+  List<String> get optionalParameterNames;
+
+  /**
    * Return a map from the names of optional (positional) parameters to the
    * types of the optional parameters of this type of function. The entries in
    * the map will be iterated in the same order as the order in which the
@@ -184,6 +233,16 @@
   DartType get returnType;
 
   /**
+   * The formal type parameters of this generic function.
+   * For example `<T> T -> T`.
+   *
+   * These are distinct from the [typeParameters] list, which contains type
+   * parameters from surrounding contexts, and thus are free type variables from
+   * the perspective of this function type.
+   */
+  List<TypeParameterElement> get typeFormals;
+
+  /**
    * Return the type resulting from instantiating (replacing) the given
    * [argumentTypes] for this function's bound type parameters.
    */
diff --git a/pkg/analyzer/lib/dart/element/visitor.dart b/pkg/analyzer/lib/dart/element/visitor.dart
index 4a5f393..185357d 100644
--- a/pkg/analyzer/lib/dart/element/visitor.dart
+++ b/pkg/analyzer/lib/dart/element/visitor.dart
@@ -2,6 +2,26 @@
 // 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.
 
+/**
+ * Defines element visitors that support useful patterns for visiting the
+ * elements in an [element model](element.dart).
+ *
+ * Dart is an evolving language, and the element model must evolved with it.
+ * When the element model changes, the visitor interface will sometimes change
+ * as well. If it is desirable to get a compilation error when the structure of
+ * the element model has been modified, then you should consider implementing
+ * the interface [ElementVisitor] directly. Doing so will ensure that changes
+ * that introduce new classes of elements will be flagged. (Of course, not all
+ * changes to the element model require the addition of a new class of element,
+ * and hence cannot be caught this way.)
+ *
+ * But if automatic detection of these kinds of changes is not necessary then
+ * you will probably want to extend one of the classes in this library because
+ * doing so will simplify the task of writing your visitor and guard against
+ * future changes to the element model. For example, the
+ * [RecursiveElementVisitor] automates the process of visiting all of the
+ * descendants of an element.
+ */
 library analyzer.dart.element.visitor;
 
 import 'package:analyzer/dart/element/element.dart';
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 dc676bb..fd26eb1 100644
--- a/pkg/analyzer/lib/file_system/memory_file_system.dart
+++ b/pkg/analyzer/lib/file_system/memory_file_system.dart
@@ -28,11 +28,16 @@
       new HashMap<String, List<StreamController<WatchEvent>>>();
   int nextStamp = 0;
 
-  final AbsolutePathContext absolutePathContext =
-      new AbsolutePathContext(false);
+  final Context _pathContext;
+  @override
+  final AbsolutePathContext absolutePathContext;
+
+  MemoryResourceProvider({bool isWindows: false})
+      : _pathContext = isWindows ? windows : posix,
+        absolutePathContext = new AbsolutePathContext(isWindows);
 
   @override
-  Context get pathContext => posix;
+  Context get pathContext => _pathContext;
 
   /**
    * Delete the file with the given path.
@@ -127,9 +132,8 @@
 
   Folder newFolder(String path) {
     path = pathContext.normalize(path);
-    if (!path.startsWith(pathContext.separator)) {
-      throw new ArgumentError(
-          "Path must start with '${pathContext.separator}' : $path");
+    if (!pathContext.isAbsolute(path)) {
+      throw new ArgumentError("Path must be absolute : $path");
     }
     _MemoryResource resource = _pathToResource[path];
     if (resource == null) {
@@ -208,6 +212,7 @@
   @override
   bool get exists => false;
 
+  @override
   int get modificationStamp {
     int stamp = _provider._pathToTimestamp[path];
     if (stamp == null) {
@@ -246,6 +251,7 @@
   @override
   bool get exists => _provider._pathToResource[path] is _MemoryFile;
 
+  @override
   int get modificationStamp {
     int stamp = _provider._pathToTimestamp[path];
     if (stamp == null) {
@@ -300,6 +306,7 @@
 
   final _MemoryFile file;
 
+  @override
   final Uri uri;
 
   /**
@@ -450,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/plugin/embedded_resolver_provider.dart b/pkg/analyzer/lib/plugin/embedded_resolver_provider.dart
new file mode 100644
index 0000000..b248e34
--- /dev/null
+++ b/pkg/analyzer/lib/plugin/embedded_resolver_provider.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.plugin.embedded_resolver_provider;
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/source/embedder.dart';
+
+/**
+ * A function that will return a [UriResolver] that can be used to resolve
+ * URI's for embedded libraries within a given folder, or `null` if we should
+ * fall back to the standard URI resolver.
+ */
+typedef EmbedderUriResolver EmbeddedResolverProvider(Folder folder);
diff --git a/pkg/analysis_server/lib/plugin/analysis/resolver_provider.dart b/pkg/analyzer/lib/plugin/resolver_provider.dart
similarity index 72%
rename from pkg/analysis_server/lib/plugin/analysis/resolver_provider.dart
rename to pkg/analyzer/lib/plugin/resolver_provider.dart
index ab6926c..1172372 100644
--- a/pkg/analysis_server/lib/plugin/analysis/resolver_provider.dart
+++ b/pkg/analyzer/lib/plugin/resolver_provider.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analysis_server.plugin.analysis.resolver_provider;
+library analyzer.plugin.resolver_provider;
 
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -10,7 +10,5 @@
 /**
  * A function that will return a [UriResolver] that can be used to resolve a
  * specific kind of URI within the analysis context rooted at the given folder.
- * This is currently being used to provide a package URI resolver that will be
- * used by the server (see [ServerStarter.packageResolverProvider]).
  */
 typedef UriResolver ResolverProvider(Folder folder);
diff --git a/pkg/analyzer/lib/source/embedder.dart b/pkg/analyzer/lib/source/embedder.dart
index c82e4f3..bbc6659 100644
--- a/pkg/analyzer/lib/source/embedder.dart
+++ b/pkg/analyzer/lib/source/embedder.dart
@@ -8,12 +8,217 @@
 import 'dart:core' hide Resource;
 
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/java_io.dart' show JavaFile;
+import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource;
-import 'package:path/path.dart' as pathos;
 import 'package:yaml/yaml.dart';
 
+const String _DART_COLON_PREFIX = 'dart:';
+const String _EMBEDDED_LIB_MAP_KEY = 'embedded_libs';
+
+/// Check if this map defines embedded libraries.
+bool definesEmbeddedLibs(Map map) => map[_EMBEDDED_LIB_MAP_KEY] != null;
+
+class EmbedderSdk implements DartSdk {
+  // TODO(danrubel) Refactor this with DirectoryBasedDartSdk
+
+  /// The resolver associated with this embedder sdk.
+  EmbedderUriResolver _resolver;
+
+  /// The [AnalysisContext] which is used for all of the sources in this sdk.
+  InternalAnalysisContext _analysisContext;
+
+  /// The library map that is populated by visiting the AST structure parsed from
+  /// the contents of the libraries file.
+  final LibraryMap _librariesMap = new LibraryMap();
+
+  @override
+  AnalysisContext get context {
+    if (_analysisContext == null) {
+      _analysisContext = new SdkAnalysisContext();
+      SourceFactory factory = new SourceFactory([_resolver]);
+      _analysisContext.sourceFactory = factory;
+      List<String> uris = this.uris;
+      ChangeSet changeSet = new ChangeSet();
+      for (String uri in uris) {
+        changeSet.addedSource(factory.forUri(uri));
+      }
+      _analysisContext.applyChanges(changeSet);
+    }
+    return _analysisContext;
+  }
+
+  @override
+  List<SdkLibrary> get sdkLibraries => _librariesMap.sdkLibraries;
+
+  // TODO(danrubel) Determine SDK version
+  @override
+  String get sdkVersion => '0';
+
+  @override
+  List<String> get uris => _librariesMap.uris;
+
+  @override
+  Source fromFileUri(Uri uri) {
+    JavaFile file = new JavaFile.fromUri(uri);
+    String filePath = file.getAbsolutePath();
+
+    String path;
+    for (SdkLibrary library in _librariesMap.sdkLibraries) {
+      String libraryPath = library.path.replaceAll('/', JavaFile.separator);
+      if (filePath == libraryPath) {
+        path = '$_DART_COLON_PREFIX${library.shortName}';
+        break;
+      }
+    }
+    if (path == null) {
+      for (SdkLibrary library in _librariesMap.sdkLibraries) {
+        String libraryPath = library.path.replaceAll('/', JavaFile.separator);
+        int index = libraryPath.lastIndexOf(JavaFile.separator);
+        if (index == -1) {
+          continue;
+        }
+        String prefix = libraryPath.substring(0, index + 1);
+        if (!filePath.startsWith(prefix)) {
+          continue;
+        }
+        var relPath = filePath
+            .substring(prefix.length)
+            .replaceAll(JavaFile.separator, '/');
+        path = '$_DART_COLON_PREFIX${library.shortName}/$relPath';
+        break;
+      }
+    }
+
+    if (path != null) {
+      try {
+        return new FileBasedSource(file, parseUriWithException(path));
+      } on URISyntaxException catch (exception, stackTrace) {
+        AnalysisEngine.instance.logger.logInformation(
+            "Failed to create URI: $path",
+            new CaughtException(exception, stackTrace));
+        return null;
+      }
+    }
+    return null;
+  }
+
+  @override
+  SdkLibrary getSdkLibrary(String dartUri) => _librariesMap.getLibrary(dartUri);
+
+  @override
+  Source mapDartUri(String dartUri) {
+    String libraryName;
+    String relativePath;
+    int index = dartUri.indexOf('/');
+    if (index >= 0) {
+      libraryName = dartUri.substring(0, index);
+      relativePath = dartUri.substring(index + 1);
+    } else {
+      libraryName = dartUri;
+      relativePath = "";
+    }
+    SdkLibrary library = getSdkLibrary(libraryName);
+    if (library == null) {
+      return null;
+    }
+    String srcPath;
+    if (relativePath.isEmpty) {
+      srcPath = library.path;
+    } else {
+      String libraryPath = library.path;
+      int index = libraryPath.lastIndexOf(JavaFile.separator);
+      if (index == -1) {
+        index = libraryPath.lastIndexOf('/');
+        if (index == -1) {
+          return null;
+        }
+      }
+      String prefix = libraryPath.substring(0, index + 1);
+      srcPath = '$prefix$relativePath';
+    }
+    String filePath = srcPath.replaceAll('/', JavaFile.separator);
+    try {
+      JavaFile file = new JavaFile(filePath);
+      return new FileBasedSource(file, parseUriWithException(dartUri));
+    } on URISyntaxException {
+      return null;
+    }
+  }
+}
+
+/// Given the [embedderYamls] from [EmbedderYamlLocator] check each one for the
+/// top level key 'embedded_libs'. Under the 'embedded_libs' key are key value
+/// pairs. Each key is a 'dart:' library uri and each value is a path
+/// (relative to the directory containing `_embedder.yaml`) to a dart script
+/// for the given library. For example:
+///
+/// embedded_libs:
+///   'dart:io': '../../sdk/io/io.dart'
+///
+/// If a key doesn't begin with `dart:` it is ignored.
+///
+class EmbedderUriResolver extends DartUriResolver {
+  final Map<String, String> _urlMappings = <String, String>{};
+
+  /// Construct a [EmbedderUriResolver] from a package map
+  /// (see [PackageMapProvider]).
+  EmbedderUriResolver(Map<Folder, YamlMap> embedderYamls)
+      : super(new EmbedderSdk()) {
+    (dartSdk as EmbedderSdk)._resolver = this;
+    if (embedderYamls == null) {
+      return;
+    }
+    embedderYamls.forEach(_processEmbedderYaml);
+  }
+
+  /// Number of embedded libraries.
+  int get length => _urlMappings.length;
+
+  @override
+  Uri restoreAbsolute(Source source) {
+    String path = source.fullName;
+    if (path.length > 3 && path[1] == ':' && path[2] == '\\') {
+      path = '/${path[0]}:${path.substring(2).replaceAll('\\', '/')}';
+    }
+    Source sdkSource = dartSdk.fromFileUri(Uri.parse('file://$path'));
+    return sdkSource?.uri;
+  }
+
+  /// Install the mapping from [name] to [libDir]/[file].
+  void _processEmbeddedLibs(String name, String file, Folder libDir) {
+    if (!name.startsWith(_DART_COLON_PREFIX)) {
+      // SDK libraries must begin with 'dart:'.
+      // TODO(pquitslund): Notify developer that something is wrong with the
+      // _embedder.yaml file in libDir.
+      return;
+    }
+    String libPath = libDir.canonicalizePath(file);
+    _urlMappings[name] = libPath;
+    String shortName = name.substring(_DART_COLON_PREFIX.length);
+    SdkLibraryImpl library = new SdkLibraryImpl(shortName);
+    library.path = libPath;
+    (dartSdk as EmbedderSdk)._librariesMap.setLibrary(name, library);
+  }
+
+  void _processEmbedderYaml(Folder libDir, YamlMap map) {
+    YamlNode embedded_libs = map[_EMBEDDED_LIB_MAP_KEY];
+    if (embedded_libs == null) {
+      return;
+    }
+    if (embedded_libs is! YamlMap) {
+      return;
+    }
+    (embedded_libs as YamlMap)
+        .forEach((k, v) => _processEmbeddedLibs(k, v, libDir));
+  }
+}
+
 /// Given a packageMap, check in each package's lib directory for the
 /// existence of an `_embedder.yaml` file. If the file contains a top level
 /// YamlMap, it will be added to the [embedderYamls] map.
@@ -30,6 +235,11 @@
     }
   }
 
+  /// Programatically add an _embedder.yaml mapping.
+  void addEmbedderYaml(Folder libDir, String embedderYaml) {
+    _processEmbedderYaml(libDir, embedderYaml);
+  }
+
   void refresh(Map<String, List<Folder>> packageMap) {
     // Clear existing.
     embedderYamls.clear();
@@ -39,22 +249,6 @@
     packageMap.forEach(_processPackage);
   }
 
-  /// Programatically add an _embedder.yaml mapping.
-  void addEmbedderYaml(Folder libDir, String embedderYaml) {
-    _processEmbedderYaml(libDir, embedderYaml);
-  }
-
-  /// Given a package [name] and a list of folders ([libDirs]),
-  /// add any found `_embedder.yaml` files.
-  void _processPackage(String name, List<Folder> libDirs) {
-    for (Folder libDir in libDirs) {
-      String embedderYaml = _readEmbedderYaml(libDir);
-      if (embedderYaml != null) {
-        _processEmbedderYaml(libDir, embedderYaml);
-      }
-    }
-  }
-
   /// Given the yaml for an embedder ([embedderYaml]) and a folder
   /// ([libDir]), setup the uri mapping.
   void _processEmbedderYaml(Folder libDir, String embedderYaml) {
@@ -79,6 +273,16 @@
     embedderYamls[libDir] = yaml;
   }
 
+  /// Given a package [name] and a list of folders ([libDirs]),
+  /// add any found `_embedder.yaml` files.
+  void _processPackage(String name, List<Folder> libDirs) {
+    for (Folder libDir in libDirs) {
+      String embedderYaml = _readEmbedderYaml(libDir);
+      if (embedderYaml != null) {
+        _processEmbedderYaml(libDir, embedderYaml);
+      }
+    }
+  }
 
   /// Read the contents of [libDir]/[EMBEDDER_FILE_NAME] as a string.
   /// Returns null if the file doesn't exist.
@@ -92,142 +296,3 @@
     }
   }
 }
-
-/// Given the [embedderYamls] from [EmbedderYamlLocator] check each one for the
-/// top level key 'embedder_libs'. Under the 'embedder_libs' key are key value
-/// pairs. Each key is a 'dart:' library uri and each value is a path
-/// (relative to the directory containing `_embedder.yaml`) to a dart script
-/// for the given library. For example:
-///
-/// embedder_libs:
-///   'dart:io': '../../sdk/io/io.dart'
-///
-/// If a key doesn't begin with `dart:` it is ignored.
-///
-class EmbedderUriResolver extends UriResolver {
-  static const String DART_COLON_PREFIX = 'dart:';
-
-  final Map<String, String> _urlMappings = <String, String>{};
-
-  /// Construct a [EmbedderUriResolver] from a package map
-  /// (see [PackageMapProvider]).
-  EmbedderUriResolver(Map<Folder, YamlMap> embedderYamls) {
-    if (embedderYamls == null) {
-      return;
-    }
-    embedderYamls.forEach(_processEmbedderYaml);
-  }
-
-  void _processEmbedderYaml(Folder libDir, YamlMap map) {
-    YamlNode embedder_libs = map['embedder_libs'];
-    if (embedder_libs == null) {
-      return;
-    }
-    if (embedder_libs is! YamlMap) {
-      return;
-    }
-    (embedder_libs as YamlMap).forEach((k, v) =>
-        _processEmbedderLibs(k, v, libDir));
-  }
-
-  /// Install the mapping from [name] to [libDir]/[file].
-  void _processEmbedderLibs(String name, String file, Folder libDir) {
-    if (!name.startsWith(DART_COLON_PREFIX)) {
-      // SDK libraries must begin with 'dart:'.
-      // TODO(pquitslund): Notify developer that something is wrong with the
-      // _embedder.yaml file in libDir.
-      return;
-    }
-    String key = name;
-    String value = libDir.canonicalizePath(file);
-    _urlMappings[key] = value;
-  }
-
-  /// Number of embedder libraries.
-  int get length => _urlMappings.length;
-
-  /// Return the path mapping for [libName] or null if there is none.
-  String operator [](String libName) => _urlMappings[libName];
-
-  @override
-  Source resolveAbsolute(Uri importUri, [Uri actualUri]) {
-    String libraryName = _libraryName(importUri);
-    String partPath = _partPath(importUri);
-    // Lookup library name in mappings.
-    String mapping = _urlMappings[libraryName];
-    if (mapping == null) {
-      // Not found.
-      return null;
-    }
-    // This mapping points to the main entry file of the dart: library.
-    Uri libraryEntry = new Uri.file(mapping);
-    if (!libraryEntry.isAbsolute) {
-      // We expect an absolute path.
-      return null;
-    }
-
-    if (partPath != null) {
-      return _resolvePart(libraryEntry, partPath, importUri);
-    } else {
-      return _resolveEntry(libraryEntry, importUri);
-    }
-  }
-
-  @override
-  Uri restoreAbsolute(Source source) {
-    String extensionName = _findExtensionNameFor(source.fullName);
-    if (extensionName != null) {
-      return Uri.parse(extensionName);
-    }
-    // TODO(johnmccutchan): Handle restoring parts.
-    return null;
-  }
-
-  /// Return the extension name for [fullName] or `null`.
-  String _findExtensionNameFor(String fullName) {
-    String result;
-    _urlMappings.forEach((extensionName, pathMapping) {
-      if (pathMapping == fullName) {
-        result = extensionName;
-      }
-    });
-    return result;
-  }
-
-  /// Return the library name of [importUri].
-  String _libraryName(Uri importUri) {
-    String uri = importUri.toString();
-    int index = uri.indexOf('/');
-    if (index >= 0) {
-      return uri.substring(0, index);
-    }
-    return uri;
-  }
-
-  /// Return the part path of [importUri].
-  String _partPath(Uri importUri) {
-    String uri = importUri.toString();
-    int index = uri.indexOf('/');
-    if (index >= 0) {
-      return uri.substring(index + 1);
-    }
-    return null;
-  }
-
-  /// Resolve an import of an sdk extension.
-  Source _resolveEntry(Uri libraryEntry, Uri importUri) {
-    // Library entry.
-    JavaFile javaFile = new JavaFile.fromUri(libraryEntry);
-    return new FileBasedSource(javaFile, importUri);
-  }
-
-  /// Resolve a 'part' statement inside an sdk extension.
-  Source _resolvePart(Uri libraryEntry, String partPath, Uri importUri) {
-    // Library part.
-    String directory = pathos.dirname(libraryEntry.path);
-    Uri partUri = new Uri.file(pathos.join(directory, partPath));
-    assert(partUri.isAbsolute);
-    JavaFile javaFile = new JavaFile.fromUri(partUri);
-    return new FileBasedSource(javaFile, importUri);
-  }
-}
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/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index afe0216..bbb0e69 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -7,6 +7,8 @@
 import 'dart:async';
 import 'dart:collection';
 
+import 'package:analyzer/src/dart/element/element.dart'
+    show ElementImpl, Modifier;
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -239,7 +241,11 @@
           AnalysisEngine.instance.logger
               .logInformation('Removed the cache entry for $target.');
         }
-        return partition.remove(target);
+        CacheEntry entry = partition.remove(target);
+        if (entry != null) {
+          entry.dispose();
+        }
+        return entry;
       }
     }
     return null;
@@ -307,7 +313,11 @@
   Map<ResultDescriptor, ResultData> _resultMap =
       new HashMap<ResultDescriptor, ResultData>();
 
-  CacheEntry(this.target);
+  CacheEntry(this.target) {
+    if (target is ElementImpl) {
+      (target as ElementImpl).setModifier(Modifier.CACHE_KEY, true);
+    }
+  }
 
   /**
    * The exception that caused one or more values to have a state of
@@ -350,6 +360,9 @@
       }
     });
     _resultMap.clear();
+    if (target is ElementImpl) {
+      (target as ElementImpl).setModifier(Modifier.CACHE_KEY, false);
+    }
   }
 
   /**
@@ -384,7 +397,7 @@
    * Return the value of the result represented by the given [descriptor], or
    * the default value for the result if this entry does not have a valid value.
    */
-  dynamic /*=V*/ getValue /*<V>*/ (ResultDescriptor /*<V>*/ descriptor) {
+  dynamic/*=V*/ getValue/*<V>*/(ResultDescriptor/*<V>*/ descriptor) {
     ResultData data = _resultMap[descriptor];
     if (data == null) {
       return descriptor.defaultValue;
@@ -482,8 +495,8 @@
    * Set the value of the result represented by the given [descriptor] to the
    * given [value].
    */
-  void setValue /*<V>*/ (ResultDescriptor /*<V>*/ descriptor,
-      dynamic /*=V*/ value, List<TargetedResult> dependedOn) {
+  void setValue/*<V>*/(ResultDescriptor/*<V>*/ descriptor, dynamic/*=V*/ value,
+      List<TargetedResult> dependedOn) {
 //    {
 //      String valueStr = '$value';
 //      if (valueStr.length > 20) {
@@ -581,7 +594,10 @@
     _invalidateDependentResults(id, thisData, delta, level + 1);
     // If empty and not explicitly added, remove the entry altogether.
     if (_resultMap.isEmpty && !explicitlyAdded) {
-      _partition.entryMap.remove(target);
+      CacheEntry entry = _partition.entryMap.remove(target);
+      if (entry != null) {
+        entry.dispose();
+      }
       _partition._removeIfSource(target);
     }
     // Notify controller.
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 4714557..def719f 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -7,14 +7,16 @@
 import 'dart:async';
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/plugin/task.dart';
 import 'package:analyzer/source/embedder.dart';
 import 'package:analyzer/src/cancelable_future.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -24,6 +26,7 @@
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/dart_work_manager.dart';
@@ -69,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;
 
   /**
@@ -126,6 +130,7 @@
   /**
    * A list of all [WorkManager]s used by this context.
    */
+  @override
   final List<WorkManager> workManagers = <WorkManager>[];
 
   /**
@@ -185,6 +190,9 @@
    */
   List<AnalysisListener> _listeners = new List<AnalysisListener>();
 
+  @override
+  ResultProvider resultProvider;
+
   /**
    * The most recently incrementally resolved source, or `null` when it was
    * already validated, or the most recent change was not incrementally resolved.
@@ -254,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) {
@@ -268,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;
@@ -459,13 +471,19 @@
     if (coreElement == null) {
       throw new AnalysisException("Could not create an element for dart:core");
     }
-    Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
-    if (asyncSource == null) {
-      throw new AnalysisException("Could not create a source for dart:async");
-    }
-    LibraryElement asyncElement = computeLibraryElement(asyncSource);
-    if (asyncElement == null) {
-      throw new AnalysisException("Could not create an element for dart:async");
+    LibraryElement asyncElement;
+    if (analysisOptions.enableAsync) {
+      Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
+      if (asyncSource == null) {
+        throw new AnalysisException("Could not create a source for dart:async");
+      }
+      asyncElement = computeLibraryElement(asyncSource);
+      if (asyncElement == null) {
+        throw new AnalysisException(
+            "Could not create an element for dart:async");
+      }
+    } else {
+      asyncElement = createMockAsyncLib(coreElement);
     }
     _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
     return _typeProvider;
@@ -474,6 +492,7 @@
   /**
    * Sets the [TypeProvider] for this context.
    */
+  @override
   void set typeProvider(TypeProvider typeProvider) {
     _typeProvider = typeProvider;
   }
@@ -489,26 +508,20 @@
   @override
   bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result) {
     return PerformanceStatistics.summary.makeCurrentWhile(() {
-      AnalysisTarget target = entry.target;
-      // TYPE_PROVIDER
-      if (target is AnalysisContextTarget && result == TYPE_PROVIDER) {
-        DartSdk dartSdk = sourceFactory.dartSdk;
-        if (dartSdk != null) {
-          AnalysisContext sdkContext = dartSdk.context;
-          if (!identical(sdkContext, this) &&
-              sdkContext is InternalAnalysisContext) {
-            return sdkContext.aboutToComputeResult(entry, result);
-          }
+      // Use this helper if it is set.
+      if (resultProvider != null && resultProvider.compute(entry, result)) {
+        return true;
+      }
+      // Ask the SDK.
+      DartSdk dartSdk = sourceFactory.dartSdk;
+      if (dartSdk != null) {
+        AnalysisContext sdkContext = dartSdk.context;
+        if (!identical(sdkContext, this) &&
+            sdkContext is InternalAnalysisContext) {
+          return sdkContext.aboutToComputeResult(entry, result);
         }
       }
-      // A result for a Source.
-      Source source = target.source;
-      if (source != null) {
-        InternalAnalysisContext context = _cache.getContextFor(source);
-        if (!identical(context, this)) {
-          return context.aboutToComputeResult(entry, result);
-        }
-      }
+      // Cannot provide the result.
       return false;
     });
   }
@@ -640,8 +653,8 @@
   }
 
   @override
-  Object /*=V*/ computeResult /*<V>*/ (
-      AnalysisTarget target, ResultDescriptor /*<V>*/ descriptor) {
+  Object/*=V*/ computeResult/*<V>*/(
+      AnalysisTarget target, ResultDescriptor/*<V>*/ descriptor) {
     // Make sure we are not trying to invoke the task model in a reentrant
     // fashion.
     assert(!driver.isTaskRunning);
@@ -675,6 +688,55 @@
     ]);
   }
 
+  /**
+   * Create a minimalistic mock dart:async library
+   * to stand in for a real one if one does not exist
+   * facilitating creation a type provider without dart:async.
+   */
+  LibraryElement createMockAsyncLib(LibraryElement coreLibrary) {
+    InterfaceType objType = coreLibrary.getType('Object').type;
+
+    ClassElement _classElement(String typeName, [List<String> parameterNames]) {
+      ClassElementImpl element =
+          new ClassElementImpl.forNode(AstFactory.identifier3(typeName));
+      element.supertype = objType;
+      InterfaceTypeImpl type = new InterfaceTypeImpl(element);
+      element.type = type;
+      if (parameterNames != null) {
+        int count = parameterNames.length;
+        if (count > 0) {
+          List<TypeParameterElementImpl> typeParameters =
+              new List<TypeParameterElementImpl>(count);
+          List<TypeParameterTypeImpl> typeArguments =
+              new List<TypeParameterTypeImpl>(count);
+          for (int i = 0; i < count; i++) {
+            TypeParameterElementImpl typeParameter =
+                new TypeParameterElementImpl.forNode(
+                    AstFactory.identifier3(parameterNames[i]));
+            typeParameters[i] = typeParameter;
+            typeArguments[i] = new TypeParameterTypeImpl(typeParameter);
+            typeParameter.type = typeArguments[i];
+          }
+          element.typeParameters = typeParameters;
+          type.typeArguments = typeArguments;
+        }
+      }
+      return element;
+    }
+
+    InterfaceType futureType = _classElement('Future', ['T']).type;
+    InterfaceType streamType = _classElement('Stream', ['T']).type;
+    CompilationUnitElementImpl asyncUnit =
+        new CompilationUnitElementImpl("mock_async.dart");
+    asyncUnit.types = <ClassElement>[futureType.element, streamType.element];
+    LibraryElementImpl mockLib = new LibraryElementImpl.forNode(
+        this, AstFactory.libraryIdentifier2(["dart.async"]));
+    mockLib.definingCompilationUnit = asyncUnit;
+    mockLib.publicNamespace =
+        new NamespaceBuilder().createPublicNamespaceForLibrary(mockLib);
+    return mockLib;
+  }
+
   @override
   void dispose() {
     _disposed = true;
@@ -962,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);
@@ -1443,6 +1507,31 @@
   }
 
   /**
+   * Return a [CompilationUnit] for the given library and unit sources, which
+   * can be incrementally resolved.
+   */
+  CompilationUnit _getIncrementallyResolvableUnit(
+      Source librarySource, Source unitSource) {
+    LibrarySpecificUnit target =
+        new LibrarySpecificUnit(librarySource, unitSource);
+    for (ResultDescriptor result in [
+      RESOLVED_UNIT,
+      RESOLVED_UNIT11,
+      RESOLVED_UNIT10,
+      RESOLVED_UNIT9,
+      RESOLVED_UNIT8,
+      RESOLVED_UNIT7,
+      RESOLVED_UNIT6
+    ]) {
+      CompilationUnit unit = getResult(target, result);
+      if (unit != null) {
+        return unit;
+      }
+    }
+    return null;
+  }
+
+  /**
    * Return a list containing all of the sources known to this context that have
    * the given [kind].
    */
@@ -1674,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;
@@ -1733,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) {
@@ -1789,7 +1887,7 @@
       incrementalResolutionValidation_lastUnitSource = null;
       incrementalResolutionValidation_lastLibrarySource = null;
       incrementalResolutionValidation_lastUnit = null;
-      // prepare the entry
+      // prepare the source entry
       CacheEntry sourceEntry = _cache.get(unitSource);
       if (sourceEntry == null) {
         return false;
@@ -1800,19 +1898,15 @@
         return false;
       }
       Source librarySource = librarySources[0];
+      // prepare the unit entry
       CacheEntry unitEntry =
           _cache.get(new LibrarySpecificUnit(librarySource, unitSource));
       if (unitEntry == null) {
         return false;
       }
-      // prepare the library element
-      LibraryElement libraryElement = getLibraryElement(librarySource);
-      if (libraryElement == null) {
-        return false;
-      }
       // prepare the existing unit
       CompilationUnit oldUnit =
-          getResolvedCompilationUnit2(unitSource, librarySource);
+          _getIncrementallyResolvableUnit(librarySource, unitSource);
       if (oldUnit == null) {
         return false;
       }
@@ -1821,6 +1915,7 @@
       PoorMansIncrementalResolver resolver = new PoorMansIncrementalResolver(
           typeProvider,
           unitSource,
+          _cache,
           sourceEntry,
           unitEntry,
           oldUnit,
@@ -2023,6 +2118,24 @@
 }
 
 /**
+ * Provider for analysis results.
+ */
+abstract class ResultProvider {
+  /**
+   * This method is invoked by an [InternalAnalysisContext] when the state of
+   * the [result] of the [entry] is [CacheState.INVALID], so it is about to be
+   * computed.
+   *
+   * If the provider knows how to provide the value, it sets the value into
+   * the [entry] with all required dependencies, and returns `true`.
+   *
+   * Otherwise, it returns `false` to indicate that the result should be
+   * computed as usually.
+   */
+  bool compute(CacheEntry entry, ResultDescriptor result);
+}
+
+/**
  * An [AnalysisContext] that only contains sources for a Dart SDK.
  */
 class SdkAnalysisContext extends AnalysisContextImpl {
diff --git a/pkg/analyzer/lib/src/context/source.dart b/pkg/analyzer/lib/src/context/source.dart
new file mode 100644
index 0000000..5d18886
--- /dev/null
+++ b/pkg/analyzer/lib/src/context/source.dart
@@ -0,0 +1,322 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.src.context.source;
+
+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/generated/engine.dart';
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
+import 'package:package_config/packages.dart';
+
+/**
+ * Instances of the class `SourceFactory` resolve possibly relative URI's
+ * against an existing [Source].
+ */
+class SourceFactoryImpl implements SourceFactory {
+  /**
+   * The analysis context that this source factory is associated with.
+   */
+  @override
+  AnalysisContext context;
+
+  /**
+   * URI processor used to find mappings for `package:` URIs found in a
+   * `.packages` config file.
+   */
+  final Packages _packages;
+
+  /**
+   * Resource provider used in working with package maps.
+   */
+  final ResourceProvider _resourceProvider;
+
+  /**
+   * The resolvers used to resolve absolute URI's.
+   */
+  final List<UriResolver> resolvers;
+
+  /**
+   * The predicate to determine is [Source] is local.
+   */
+  LocalSourcePredicate _localSourcePredicate = LocalSourcePredicate.NOT_SDK;
+
+  /**
+   * Initialize a newly created source factory with the given absolute URI
+   * [resolvers] and optional [packages] resolution helper.
+   */
+  SourceFactoryImpl(this.resolvers,
+      [this._packages, ResourceProvider resourceProvider])
+      : _resourceProvider = resourceProvider != null
+            ? resourceProvider
+            : PhysicalResourceProvider.INSTANCE;
+
+  /**
+   * Return the [DartSdk] associated with this [SourceFactory], or `null` if
+   * there is no such SDK.
+   *
+   * @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) {
+        DartUriResolver dartUriResolver = resolver;
+        return dartUriResolver.dartSdk;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Sets the [LocalSourcePredicate].
+   *
+   * @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) {
+      Map<String, List<Folder>> packageMap = <String, List<Folder>>{};
+      _packages.asMap().forEach((String name, Uri uri) {
+        if (uri.scheme == 'file' || uri.scheme == '' /* unspecified */) {
+          packageMap[name] = <Folder>[
+            _resourceProvider.getFolder(uri.toFilePath())
+          ];
+        }
+      });
+      return packageMap;
+    }
+
+    // Default to the PackageMapUriResolver.
+    PackageMapUriResolver resolver = resolvers
+        .firstWhere((r) => r is PackageMapUriResolver, orElse: () => null);
+    return resolver != null ? resolver.packageMap : null;
+  }
+
+  /**
+   * 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);
+    factory.localSourcePredicate = _localSourcePredicate;
+    return factory;
+  }
+
+  /**
+   * Return a source object representing the given absolute URI, or `null` if
+   * the URI is not a valid URI or if it is not an absolute URI.
+   *
+   * @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);
+      if (uri.isAbsolute) {
+        return _internalResolveUri(null, uri);
+      }
+    } catch (exception, stackTrace) {
+      AnalysisEngine.instance.logger.logError(
+          "Could not resolve URI: $absoluteUri",
+          new CaughtException(exception, stackTrace));
+    }
+    return null;
+  }
+
+  /**
+   * Return a source object representing the given absolute URI, or `null` if
+   * the URI is not an absolute URI.
+   *
+   * @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 {
+        return _internalResolveUri(null, absoluteUri);
+      } on AnalysisException catch (exception, stackTrace) {
+        AnalysisEngine.instance.logger.logError(
+            "Could not resolve URI: $absoluteUri",
+            new CaughtException(exception, stackTrace));
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Return a source object that is equal to the source object used to obtain
+   * the given encoding.
+   *
+   * @param encoding the encoding of a source object
+   * @return a source object that is described by the given encoding
+   * @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) {
+      throw new IllegalArgumentException(
+          "Invalid source encoding: '$encoding'");
+    }
+    return source;
+  }
+
+  /**
+   * Determines if the given [Source] is local.
+   *
+   * @param source the [Source] to analyze
+   * @return `true` if the given [Source] is local
+   */
+  @override
+  bool isLocalSource(Source source) => _localSourcePredicate.isLocal(source);
+
+  /**
+   * Return a source representing the URI that results from resolving the given
+   * (possibly relative) [containedUri] against the URI associated with the
+   * [containingSource], whether or not the resulting source exists, or `null`
+   * 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;
+    }
+    try {
+      // Force the creation of an escaped URI to deal with spaces, etc.
+      return _internalResolveUri(
+          containingSource, parseUriWithException(containedUri));
+    } on URISyntaxException {
+      return null;
+    } catch (exception, stackTrace) {
+      String containingFullName =
+          containingSource != null ? containingSource.fullName : '<null>';
+      AnalysisEngine.instance.logger.logInformation(
+          "Could not resolve URI ($containedUri) "
+          "relative to source ($containingFullName)",
+          new CaughtException(exception, stackTrace));
+      return null;
+    }
+  }
+
+  /**
+   * Return an absolute URI that represents the given source, or `null` if a
+   * valid URI cannot be computed.
+   *
+   * @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) {
+      Uri uri = resolver.restoreAbsolute(source);
+      if (uri != null) {
+        // Now see if there's a package mapping.
+        Uri packageMappedUri = _getPackageMapping(uri);
+        if (packageMappedUri != null) {
+          return packageMappedUri;
+        }
+        // Fall back to the resolver's computed URI.
+        return uri;
+      }
+    }
+
+    return null;
+  }
+
+  Uri _getPackageMapping(Uri sourceUri) {
+    if (_packages == null) {
+      return null;
+    }
+    if (sourceUri.scheme != 'file') {
+      //TODO(pquitslund): verify this works for non-file URIs.
+      return null;
+    }
+
+    Uri packageUri;
+    _packages.asMap().forEach((String name, Uri uri) {
+      if (packageUri == null) {
+        if (utils.startsWith(sourceUri, uri)) {
+          packageUri = Uri.parse(
+              'package:$name/${sourceUri.path.substring(uri.path.length)}');
+        }
+      }
+    });
+    return packageUri;
+  }
+
+  /**
+   * Return a source object representing the URI that results from resolving
+   * the given (possibly relative) contained URI against the URI associated
+   * with an existing source object, or `null` if the URI could not be resolved.
+   *
+   * @param containingSource the source containing the given URI
+   * @param containedUri the (possibly relative) URI to be resolved against the
+   *        containing source
+   * @return the source representing the contained URI
+   * @throws AnalysisException if either the contained URI is invalid or if it
+   *         cannot be resolved against the source object's URI
+   */
+  Source _internalResolveUri(Source containingSource, Uri containedUri) {
+    if (!containedUri.isAbsolute) {
+      if (containingSource == null) {
+        throw new AnalysisException(
+            "Cannot resolve a relative URI without a containing source: "
+            "$containedUri");
+      }
+      containedUri = containingSource.resolveRelativeUri(containedUri);
+    }
+
+    Uri actualUri = containedUri;
+
+    // Check .packages and update target and actual URIs as appropriate.
+    if (_packages != null && containedUri.scheme == 'package') {
+      Uri packageUri = null;
+      try {
+        packageUri =
+            _packages.resolve(containedUri, notFound: (Uri packageUri) => null);
+      } on ArgumentError {
+        // Fall through to try resolvers.
+      }
+
+      if (packageUri != null) {
+        // Ensure scheme is set.
+        if (packageUri.scheme == '') {
+          packageUri = packageUri.replace(scheme: 'file');
+        }
+        containedUri = packageUri;
+      }
+    }
+
+    for (UriResolver resolver in resolvers) {
+      Source result = resolver.resolveAbsolute(containedUri, actualUri);
+      if (result != null) {
+        return result;
+      }
+    }
+
+    return null;
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
new file mode 100644
index 0000000..d2e09de
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -0,0 +1,10985 @@
+// 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 analyzer.src.dart.ast.ast;
+
+import 'dart:collection';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
+import 'package:analyzer/src/generated/java_core.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * Two or more string literals that are implicitly concatenated because of being
+ * adjacent (separated only by whitespace).
+ *
+ * While the grammar only allows adjacent strings when all of the strings are of
+ * the same kind (single line or multi-line), this class doesn't enforce that
+ * restriction.
+ *
+ *    adjacentStrings ::=
+ *        [StringLiteral] [StringLiteral]+
+ */
+class AdjacentStringsImpl extends StringLiteralImpl implements AdjacentStrings {
+  /**
+   * The strings that are implicitly concatenated.
+   */
+  NodeList<StringLiteral> _strings;
+
+  /**
+   * Initialize a newly created list of adjacent strings. To be syntactically
+   * valid, the list of [strings] must contain at least two elements.
+   */
+  AdjacentStringsImpl(List<StringLiteral> strings) {
+    _strings = new NodeList<StringLiteral>(this, strings);
+  }
+
+  @override
+  Token get beginToken => _strings.beginToken;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..addAll(_strings);
+
+  @override
+  Token get endToken => _strings.endToken;
+
+  @override
+  NodeList<StringLiteral> get strings => _strings;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitAdjacentStrings(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _strings.accept(visitor);
+  }
+
+  @override
+  void _appendStringValue(StringBuffer buffer) {
+    for (StringLiteralImpl stringLiteral in strings) {
+      stringLiteral._appendStringValue(buffer);
+    }
+  }
+}
+
+/**
+ * An AST node that can be annotated with both a documentation comment and a
+ * list of annotations.
+ */
+abstract class AnnotatedNodeImpl extends AstNodeImpl implements AnnotatedNode {
+  /**
+   * The documentation comment associated with this node, or `null` if this node
+   * does not have a documentation comment associated with it.
+   */
+  Comment _comment;
+
+  /**
+   * The annotations associated with this node.
+   */
+  NodeList<Annotation> _metadata;
+
+  /**
+   * Initialize a newly created annotated node. Either or both of the [comment]
+   * and [metadata] can be `null` if the node does not have the corresponding
+   * attribute.
+   */
+  AnnotatedNodeImpl(Comment comment, List<Annotation> metadata) {
+    _comment = _becomeParentOf(comment);
+    _metadata = new NodeList<Annotation>(this, metadata);
+  }
+
+  @override
+  Token get beginToken {
+    if (_comment == null) {
+      if (_metadata.isEmpty) {
+        return firstTokenAfterCommentAndMetadata;
+      }
+      return _metadata.beginToken;
+    } else if (_metadata.isEmpty) {
+      return _comment.beginToken;
+    }
+    Token commentToken = _comment.beginToken;
+    Token metadataToken = _metadata.beginToken;
+    if (commentToken.offset < metadataToken.offset) {
+      return commentToken;
+    }
+    return metadataToken;
+  }
+
+  @override
+  Comment get documentationComment => _comment;
+
+  @override
+  void set documentationComment(Comment comment) {
+    _comment = _becomeParentOf(comment);
+  }
+
+  @override
+  NodeList<Annotation> get metadata => _metadata;
+
+  @override
+  List<AstNode> get sortedCommentAndAnnotations {
+    return <AstNode>[]
+      ..add(_comment)
+      ..addAll(_metadata)
+      ..sort(AstNode.LEXICAL_ORDER);
+  }
+
+  /**
+   * Return a holder of child entities that subclasses can add to.
+   */
+  ChildEntities get _childEntities {
+    ChildEntities result = new ChildEntities();
+    if (_commentIsBeforeAnnotations()) {
+      result
+        ..add(_comment)
+        ..addAll(_metadata);
+    } else {
+      result.addAll(sortedCommentAndAnnotations);
+    }
+    return result;
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    if (_commentIsBeforeAnnotations()) {
+      _safelyVisitChild(_comment, visitor);
+      _metadata.accept(visitor);
+    } else {
+      for (AstNode child in sortedCommentAndAnnotations) {
+        child.accept(visitor);
+      }
+    }
+  }
+
+  /**
+   * Return `true` if there are no annotations before the comment. Note that a
+   * result of `true` does not imply that there is a comment, nor that there are
+   * annotations associated with this node.
+   */
+  bool _commentIsBeforeAnnotations() {
+    if (_comment == null || _metadata.isEmpty) {
+      return true;
+    }
+    Annotation firstAnnotation = _metadata[0];
+    return _comment.offset < firstAnnotation.offset;
+  }
+}
+
+/**
+ * An annotation that can be associated with an AST node.
+ *
+ *    metadata ::=
+ *        annotation*
+ *
+ *    annotation ::=
+ *        '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
+ */
+class AnnotationImpl extends AstNodeImpl implements Annotation {
+  /**
+   * The at sign that introduced the annotation.
+   */
+  @override
+  Token atSign;
+
+  /**
+   * The name of the class defining the constructor that is being invoked or the
+   * name of the field that is being referenced.
+   */
+  Identifier _name;
+
+  /**
+   * The period before the constructor name, or `null` if this annotation is not
+   * the invocation of a named constructor.
+   */
+  @override
+  Token period;
+
+  /**
+   * The name of the constructor being invoked, or `null` if this annotation is
+   * not the invocation of a named constructor.
+   */
+  SimpleIdentifier _constructorName;
+
+  /**
+   * The arguments to the constructor being invoked, or `null` if this
+   * annotation is not the invocation of a constructor.
+   */
+  ArgumentList _arguments;
+
+  /**
+   * The element associated with this annotation, or `null` if the AST structure
+   * has not been resolved or if this annotation could not be resolved.
+   */
+  Element _element;
+
+  /**
+   * The element annotation representing this annotation in the element model.
+   */
+  @override
+  ElementAnnotation elementAnnotation;
+
+  /**
+   * Initialize a newly created annotation. Both the [period] and the
+   * [constructorName] can be `null` if the annotation is not referencing a
+   * named constructor. The [arguments] can be `null` if the annotation is not
+   * referencing a constructor.
+   */
+  AnnotationImpl(this.atSign, Identifier name, this.period,
+      SimpleIdentifier constructorName, ArgumentList arguments) {
+    _name = _becomeParentOf(name);
+    _constructorName = _becomeParentOf(constructorName);
+    _arguments = _becomeParentOf(arguments);
+  }
+
+  @override
+  ArgumentList get arguments => _arguments;
+
+  @override
+  void set arguments(ArgumentList arguments) {
+    _arguments = _becomeParentOf(arguments);
+  }
+
+  @override
+  Token get beginToken => atSign;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(atSign)
+    ..add(_name)
+    ..add(period)
+    ..add(_constructorName)
+    ..add(_arguments);
+
+  @override
+  SimpleIdentifier get constructorName => _constructorName;
+
+  @override
+  void set constructorName(SimpleIdentifier name) {
+    _constructorName = _becomeParentOf(name);
+  }
+
+  @override
+  Element get element {
+    if (_element != null) {
+      return _element;
+    } else if (_name != null) {
+      return _name.staticElement;
+    }
+    return null;
+  }
+
+  @override
+  void set element(Element element) {
+    _element = element;
+  }
+
+  @override
+  Token get endToken {
+    if (_arguments != null) {
+      return _arguments.endToken;
+    } else if (_constructorName != null) {
+      return _constructorName.endToken;
+    }
+    return _name.endToken;
+  }
+
+  @override
+  Identifier get name => _name;
+
+  @override
+  void set name(Identifier name) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitAnnotation(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_constructorName, visitor);
+    _safelyVisitChild(_arguments, visitor);
+  }
+}
+
+/**
+ * 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])*
+ */
+class ArgumentListImpl extends AstNodeImpl implements ArgumentList {
+  /**
+   * The left parenthesis.
+   */
+  @override
+  Token leftParenthesis;
+
+  /**
+   * The expressions producing the values of the arguments.
+   */
+  NodeList<Expression> _arguments;
+
+  /**
+   * The right parenthesis.
+   */
+  @override
+  Token rightParenthesis;
+
+  /**
+   * A list containing the elements representing the parameters corresponding to
+   * each of the arguments in this list, or `null` if the AST has not been
+   * resolved or if the function or method being invoked could not be determined
+   * based on static type information. The list must be the same length as the
+   * number of arguments, but can contain `null` entries if a given argument
+   * does not correspond to a formal parameter.
+   */
+  List<ParameterElement> _correspondingStaticParameters;
+
+  /**
+   * A list containing the elements representing the parameters corresponding to
+   * each of the arguments in this list, or `null` if the AST has not been
+   * resolved or if the function or method being invoked could not be determined
+   * based on propagated type information. The list must be the same length as
+   * the number of arguments, but can contain `null` entries if a given argument
+   * does not correspond to a formal parameter.
+   */
+  List<ParameterElement> _correspondingPropagatedParameters;
+
+  /**
+   * Initialize a newly created list of arguments. The list of [arguments] can
+   * be `null` if there are no arguments.
+   */
+  ArgumentListImpl(
+      this.leftParenthesis, List<Expression> arguments, this.rightParenthesis) {
+    _arguments = new NodeList<Expression>(this, arguments);
+  }
+
+  @override
+  NodeList<Expression> get arguments => _arguments;
+
+  @override
+  Token get beginToken => leftParenthesis;
+
+  @override
+  // TODO(paulberry): Add commas.
+  Iterable get childEntities => new ChildEntities()
+    ..add(leftParenthesis)
+    ..addAll(_arguments)
+    ..add(rightParenthesis);
+
+  @override
+  void set correspondingPropagatedParameters(
+      List<ParameterElement> parameters) {
+    if (parameters.length != _arguments.length) {
+      throw new IllegalArgumentException(
+          "Expected ${_arguments.length} parameters, not ${parameters.length}");
+    }
+    _correspondingPropagatedParameters = parameters;
+  }
+
+  @override
+  void set correspondingStaticParameters(List<ParameterElement> parameters) {
+    if (parameters.length != _arguments.length) {
+      throw new IllegalArgumentException(
+          "Expected ${_arguments.length} parameters, not ${parameters.length}");
+    }
+    _correspondingStaticParameters = parameters;
+  }
+
+  @override
+  Token get endToken => rightParenthesis;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitArgumentList(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _arguments.accept(visitor);
+  }
+
+  /**
+   * If
+   * * the given [expression] is a child of this list,
+   * * the AST structure has been resolved,
+   * * the function being invoked is known based on propagated type information,
+   *   and
+   * * the expression corresponds to one of the parameters of the function being
+   *   invoked,
+   * then return the parameter element representing the parameter to which the
+   * value of the given expression will be bound. Otherwise, return `null`.
+   */
+  ParameterElement _getPropagatedParameterElementFor(Expression expression) {
+    if (_correspondingPropagatedParameters == null ||
+        _correspondingPropagatedParameters.length != _arguments.length) {
+      // Either the AST structure has not been resolved, the invocation of which
+      // this list is a part could not be resolved, or the argument list was
+      // modified after the parameters were set.
+      return null;
+    }
+    int index = _arguments.indexOf(expression);
+    if (index < 0) {
+      // The expression isn't a child of this node.
+      return null;
+    }
+    return _correspondingPropagatedParameters[index];
+  }
+
+  /**
+   * If
+   * * the given [expression] is a child of this list,
+   * * the AST structure has been resolved,
+   * * the function being invoked is known based on static type information, and
+   * * the expression corresponds to one of the parameters of the function being
+   *   invoked,
+   * then return the parameter element representing the parameter to which the
+   * value of the given expression will be bound. Otherwise, return `null`.
+   */
+  ParameterElement _getStaticParameterElementFor(Expression expression) {
+    if (_correspondingStaticParameters == null ||
+        _correspondingStaticParameters.length != _arguments.length) {
+      // Either the AST structure has not been resolved, the invocation of which
+      // this list is a part could not be resolved, or the argument list was
+      // modified after the parameters were set.
+      return null;
+    }
+    int index = _arguments.indexOf(expression);
+    if (index < 0) {
+      // The expression isn't a child of this node.
+      return null;
+    }
+    return _correspondingStaticParameters[index];
+  }
+}
+
+/**
+ * An as expression.
+ *
+ *    asExpression ::=
+ *        [Expression] 'as' [TypeName]
+ */
+class AsExpressionImpl extends ExpressionImpl implements AsExpression {
+  /**
+   * The expression used to compute the value being cast.
+   */
+  Expression _expression;
+
+  /**
+   * The 'as' operator.
+   */
+  @override
+  Token asOperator;
+
+  /**
+   * The name of the type being cast to.
+   */
+  TypeName _type;
+
+  /**
+   * Initialize a newly created as expression.
+   */
+  AsExpressionImpl(Expression expression, this.asOperator, TypeName type) {
+    _expression = _becomeParentOf(expression);
+    _type = _becomeParentOf(type);
+  }
+
+  @override
+  Token get beginToken => _expression.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_expression)..add(asOperator)..add(_type);
+
+  @override
+  Token get endToken => _type.endToken;
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 7;
+
+  @override
+  TypeName get type => _type;
+
+  @override
+  void set type(TypeName name) {
+    _type = _becomeParentOf(name);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitAsExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+    _safelyVisitChild(_type, visitor);
+  }
+}
+
+/**
+ * An assert statement.
+ *
+ *    assertStatement ::=
+ *        'assert' '(' [Expression] ')' ';'
+ */
+class AssertStatementImpl extends StatementImpl implements AssertStatement {
+  /**
+   * The token representing the 'assert' keyword.
+   */
+  @override
+  Token assertKeyword;
+
+  /**
+   * The left parenthesis.
+   */
+  @override
+  Token leftParenthesis;
+
+  /**
+   * The condition that is being asserted to be `true`.
+   */
+  Expression _condition;
+
+  /**
+   * The comma, if a message expression was supplied.  Otherwise `null`.
+   */
+  @override
+  Token comma;
+
+  /**
+   * The message to report if the assertion fails.  `null` if no message was
+   * supplied.
+   */
+  Expression _message;
+
+  /**
+   * The right parenthesis.
+   */
+  @override
+  Token rightParenthesis;
+
+  /**
+   * The semicolon terminating the statement.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created assert statement.
+   */
+  AssertStatementImpl(
+      this.assertKeyword,
+      this.leftParenthesis,
+      Expression condition,
+      this.comma,
+      Expression message,
+      this.rightParenthesis,
+      this.semicolon) {
+    _condition = _becomeParentOf(condition);
+    _message = _becomeParentOf(message);
+  }
+
+  @override
+  Token get beginToken => assertKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(assertKeyword)
+    ..add(leftParenthesis)
+    ..add(_condition)
+    ..add(comma)
+    ..add(_message)
+    ..add(rightParenthesis)
+    ..add(semicolon);
+
+  @override
+  Expression get condition => _condition;
+
+  @override
+  void set condition(Expression condition) {
+    _condition = _becomeParentOf(condition);
+  }
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Expression get message => _message;
+
+  @override
+  void set message(Expression expression) {
+    _message = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitAssertStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_condition, visitor);
+    _safelyVisitChild(message, visitor);
+  }
+}
+
+/**
+ * An assignment expression.
+ *
+ *    assignmentExpression ::=
+ *        [Expression] operator [Expression]
+ */
+class AssignmentExpressionImpl extends ExpressionImpl
+    implements AssignmentExpression {
+  /**
+   * The expression used to compute the left hand side.
+   */
+  Expression _leftHandSide;
+
+  /**
+   * The assignment operator being applied.
+   */
+  @override
+  Token operator;
+
+  /**
+   * The expression used to compute the right hand side.
+   */
+  Expression _rightHandSide;
+
+  /**
+   * The element associated with the operator based on the static type of the
+   * left-hand-side, or `null` if the AST structure has not been resolved, if
+   * the operator is not a compound operator, or if the operator could not be
+   * resolved.
+   */
+  @override
+  MethodElement staticElement;
+
+  /**
+   * The element associated with the operator based on the propagated type of
+   * the left-hand-side, or `null` if the AST structure has not been resolved,
+   * if the operator is not a compound operator, or if the operator could not be
+   * resolved.
+   */
+  @override
+  MethodElement propagatedElement;
+
+  /**
+   * Initialize a newly created assignment expression.
+   */
+  AssignmentExpressionImpl(
+      Expression leftHandSide, this.operator, Expression rightHandSide) {
+    if (leftHandSide == null || rightHandSide == null) {
+      String message;
+      if (leftHandSide == null) {
+        if (rightHandSide == null) {
+          message = "Both the left-hand and right-hand sides are null";
+        } else {
+          message = "The left-hand size is null";
+        }
+      } else {
+        message = "The right-hand size is null";
+      }
+      AnalysisEngine.instance.logger.logError(
+          message, new CaughtException(new AnalysisException(message), null));
+    }
+    _leftHandSide = _becomeParentOf(leftHandSide);
+    _rightHandSide = _becomeParentOf(rightHandSide);
+  }
+
+  @override
+  Token get beginToken => _leftHandSide.beginToken;
+
+  @override
+  MethodElement get bestElement {
+    MethodElement element = propagatedElement;
+    if (element == null) {
+      element = staticElement;
+    }
+    return element;
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(_leftHandSide)
+    ..add(operator)
+    ..add(_rightHandSide);
+
+  @override
+  Token get endToken => _rightHandSide.endToken;
+
+  @override
+  Expression get leftHandSide => _leftHandSide;
+
+  @override
+  void set leftHandSide(Expression expression) {
+    _leftHandSide = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 1;
+
+  @override
+  Expression get rightHandSide => _rightHandSide;
+
+  @override
+  void set rightHandSide(Expression expression) {
+    _rightHandSide = _becomeParentOf(expression);
+  }
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on propagated type information, then return the parameter
+   * element representing the parameter to which the value of the right operand
+   * will be bound. Otherwise, return `null`.
+   */
+  ParameterElement get _propagatedParameterElementForRightHandSide {
+    ExecutableElement executableElement = null;
+    if (propagatedElement != null) {
+      executableElement = propagatedElement;
+    } else {
+      if (_leftHandSide is Identifier) {
+        Identifier identifier = _leftHandSide as Identifier;
+        Element leftElement = identifier.propagatedElement;
+        if (leftElement is ExecutableElement) {
+          executableElement = leftElement;
+        }
+      }
+      if (_leftHandSide is PropertyAccess) {
+        SimpleIdentifier identifier =
+            (_leftHandSide as PropertyAccess).propertyName;
+        Element leftElement = identifier.propagatedElement;
+        if (leftElement is ExecutableElement) {
+          executableElement = leftElement;
+        }
+      }
+    }
+    if (executableElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = executableElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on static type information, then return the parameter element
+   * representing the parameter to which the value of the right operand will be
+   * bound. Otherwise, return `null`.
+   */
+  ParameterElement get _staticParameterElementForRightHandSide {
+    ExecutableElement executableElement = null;
+    if (staticElement != null) {
+      executableElement = staticElement;
+    } else {
+      if (_leftHandSide is Identifier) {
+        Element leftElement = (_leftHandSide as Identifier).staticElement;
+        if (leftElement is ExecutableElement) {
+          executableElement = leftElement;
+        }
+      }
+      if (_leftHandSide is PropertyAccess) {
+        Element leftElement =
+            (_leftHandSide as PropertyAccess).propertyName.staticElement;
+        if (leftElement is ExecutableElement) {
+          executableElement = leftElement;
+        }
+      }
+    }
+    if (executableElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = executableElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitAssignmentExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_leftHandSide, visitor);
+    _safelyVisitChild(_rightHandSide, visitor);
+  }
+}
+
+/**
+ * A node in the AST structure for a Dart program.
+ */
+abstract class AstNodeImpl implements AstNode {
+  /**
+   * The parent of the node, or `null` if the node is the root of an AST
+   * structure.
+   */
+  AstNode _parent;
+
+  /**
+   * A table mapping the names of properties to their values, or `null` if this
+   * node does not have any properties associated with it.
+   */
+  Map<String, Object> _propertyMap;
+
+  @override
+  int get end => offset + length;
+
+  @override
+  bool get isSynthetic => false;
+
+  @override
+  int get length {
+    Token beginToken = this.beginToken;
+    Token endToken = this.endToken;
+    if (beginToken == null || endToken == null) {
+      return -1;
+    }
+    return endToken.offset + endToken.length - beginToken.offset;
+  }
+
+  @override
+  int get offset {
+    Token beginToken = this.beginToken;
+    if (beginToken == null) {
+      return -1;
+    }
+    return beginToken.offset;
+  }
+
+  @override
+  AstNode get parent => _parent;
+
+  @override
+  AstNode get root {
+    AstNode root = this;
+    AstNode parent = this.parent;
+    while (parent != null) {
+      root = parent;
+      parent = root.parent;
+    }
+    return root;
+  }
+
+  @override
+  AstNode getAncestor(Predicate<AstNode> predicate) {
+    // TODO(brianwilkerson) It is a bug that this method can return `this`.
+    AstNode node = this;
+    while (node != null && !predicate(node)) {
+      node = node.parent;
+    }
+    return node;
+  }
+
+  @override
+  Object getProperty(String name) {
+    if (_propertyMap == null) {
+      return null;
+    }
+    return _propertyMap[name];
+  }
+
+  @override
+  void setProperty(String name, Object value) {
+    if (value == null) {
+      if (_propertyMap != null) {
+        _propertyMap.remove(name);
+        if (_propertyMap.isEmpty) {
+          _propertyMap = null;
+        }
+      }
+    } else {
+      if (_propertyMap == null) {
+        _propertyMap = new HashMap<String, Object>();
+      }
+      _propertyMap[name] = value;
+    }
+  }
+
+  @override
+  String toSource() {
+    PrintStringWriter writer = new PrintStringWriter();
+    accept(new ToSourceVisitor(writer));
+    return writer.toString();
+  }
+
+  @override
+  String toString() => toSource();
+
+  /**
+   * Make this node the parent of the given [child] node. Return the child node.
+   */
+  AstNode _becomeParentOf(AstNode child) {
+    if (child != null) {
+      (child as AstNodeImpl)._parent = this;
+    }
+    return child;
+  }
+
+  /**
+   * If the given [child] is not `null`, use the given [visitor] to visit it.
+   */
+  void _safelyVisitChild(AstNode child, AstVisitor visitor) {
+    if (child != null) {
+      child.accept(visitor);
+    }
+  }
+}
+
+/**
+ * An await expression.
+ *
+ *    awaitExpression ::=
+ *        'await' [Expression]
+ */
+class AwaitExpressionImpl extends ExpressionImpl implements AwaitExpression {
+  /**
+   * The 'await' keyword.
+   */
+  @override
+  Token awaitKeyword;
+
+  /**
+   * The expression whose value is being waited on.
+   */
+  Expression _expression;
+
+  /**
+   * Initialize a newly created await expression.
+   */
+  AwaitExpressionImpl(this.awaitKeyword, Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken {
+    if (awaitKeyword != null) {
+      return awaitKeyword;
+    }
+    return _expression.beginToken;
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(awaitKeyword)..add(_expression);
+
+  @override
+  Token get endToken => _expression.endToken;
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 0;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitAwaitExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * A binary (infix) expression.
+ *
+ *    binaryExpression ::=
+ *        [Expression] [Token] [Expression]
+ */
+class BinaryExpressionImpl extends ExpressionImpl implements BinaryExpression {
+  /**
+   * The expression used to compute the left operand.
+   */
+  Expression _leftOperand;
+
+  /**
+   * The binary operator being applied.
+   */
+  @override
+  Token operator;
+
+  /**
+   * The expression used to compute the right operand.
+   */
+  Expression _rightOperand;
+
+  /**
+   * The element associated with the operator based on the static type of the
+   * 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;
+
+  /**
+   * The element associated with the operator based on the propagated type of
+   * the 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 propagatedElement;
+
+  /**
+   * Initialize a newly created binary expression.
+   */
+  BinaryExpressionImpl(
+      Expression leftOperand, this.operator, Expression rightOperand) {
+    _leftOperand = _becomeParentOf(leftOperand);
+    _rightOperand = _becomeParentOf(rightOperand);
+  }
+
+  @override
+  Token get beginToken => _leftOperand.beginToken;
+
+  @override
+  MethodElement get bestElement {
+    MethodElement element = propagatedElement;
+    if (element == null) {
+      element = staticElement;
+    }
+    return element;
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_leftOperand)..add(operator)..add(_rightOperand);
+
+  @override
+  Token get endToken => _rightOperand.endToken;
+
+  @override
+  Expression get leftOperand => _leftOperand;
+
+  @override
+  void set leftOperand(Expression expression) {
+    _leftOperand = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => operator.type.precedence;
+
+  @override
+  Expression get rightOperand => _rightOperand;
+
+  @override
+  void set rightOperand(Expression expression) {
+    _rightOperand = _becomeParentOf(expression);
+  }
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on propagated type information, then return the parameter
+   * element representing the parameter to which the value of the right operand
+   * will be bound. Otherwise, return `null`.
+   */
+  ParameterElement get _propagatedParameterElementForRightOperand {
+    if (propagatedElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = propagatedElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on static type information, then return the parameter element
+   * representing the parameter to which the value of the right operand will be
+   * bound. Otherwise, return `null`.
+   */
+  ParameterElement get _staticParameterElementForRightOperand {
+    if (staticElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = staticElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitBinaryExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_leftOperand, visitor);
+    _safelyVisitChild(_rightOperand, visitor);
+  }
+}
+
+/**
+ * A function body that consists of a block of statements.
+ *
+ *    blockFunctionBody ::=
+ *        ('async' | 'async' '*' | 'sync' '*')? [Block]
+ */
+class BlockFunctionBodyImpl extends FunctionBodyImpl
+    implements BlockFunctionBody {
+  /**
+   * 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;
+
+  /**
+   * The block representing the body of the function.
+   */
+  Block _block;
+
+  /**
+   * Initialize a newly created function body consisting of a block of
+   * statements. The [keyword] can be `null` if there is no keyword specified
+   * for the block. The [star] can be `null` if there is no star following the
+   * keyword (and must be `null` if there is no keyword).
+   */
+  BlockFunctionBodyImpl(this.keyword, this.star, Block block) {
+    _block = _becomeParentOf(block);
+  }
+
+  @override
+  Token get beginToken {
+    if (keyword != null) {
+      return keyword;
+    }
+    return _block.beginToken;
+  }
+
+  @override
+  Block get block => _block;
+
+  @override
+  void set block(Block block) {
+    _block = _becomeParentOf(block);
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(keyword)..add(star)..add(_block);
+
+  @override
+  Token get endToken => _block.endToken;
+
+  @override
+  bool get isAsynchronous => keyword != null && keyword.lexeme == Parser.ASYNC;
+
+  @override
+  bool get isGenerator => star != null;
+
+  @override
+  bool get isSynchronous => keyword == null || keyword.lexeme != Parser.ASYNC;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitBlockFunctionBody(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_block, visitor);
+  }
+}
+
+/**
+ * A sequence of statements.
+ *
+ *    block ::=
+ *        '{' statement* '}'
+ */
+class BlockImpl extends StatementImpl implements Block {
+  /**
+   * The left curly bracket.
+   */
+  @override
+  Token leftBracket;
+
+  /**
+   * The statements contained in the block.
+   */
+  NodeList<Statement> _statements;
+
+  /**
+   * The right curly bracket.
+   */
+  @override
+  Token rightBracket;
+
+  /**
+   * Initialize a newly created block of code.
+   */
+  BlockImpl(this.leftBracket, List<Statement> statements, this.rightBracket) {
+    _statements = new NodeList<Statement>(this, statements);
+  }
+
+  @override
+  Token get beginToken => leftBracket;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(leftBracket)
+    ..addAll(_statements)
+    ..add(rightBracket);
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  NodeList<Statement> get statements => _statements;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitBlock(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _statements.accept(visitor);
+  }
+}
+
+/**
+ * A boolean literal expression.
+ *
+ *    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;
+
+  /**
+   * Initialize a newly created boolean literal.
+   */
+  BooleanLiteralImpl(this.literal, this.value);
+
+  @override
+  Token get beginToken => literal;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(literal);
+
+  @override
+  Token get endToken => literal;
+
+  @override
+  bool get isSynthetic => literal.isSynthetic;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitBooleanLiteral(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * A break statement.
+ *
+ *    breakStatement ::=
+ *        'break' [SimpleIdentifier]? ';'
+ */
+class BreakStatementImpl extends StatementImpl implements BreakStatement {
+  /**
+   * The token representing the 'break' keyword.
+   */
+  @override
+  Token breakKeyword;
+
+  /**
+   * The label associated with the statement, or `null` if there is no label.
+   */
+  SimpleIdentifier _label;
+
+  /**
+   * The semicolon terminating the statement.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * The AstNode which this break statement is breaking from.  This will be
+   * either a [Statement] (in the case of breaking out of a loop), a
+   * [SwitchMember] (in the case of a labeled break statement whose label
+   * matches a label on a switch case in an enclosing switch statement), or
+   * `null` if the AST has not yet been resolved or if the target could not be
+   * 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;
+
+  /**
+   * Initialize a newly created break statement. The [label] can be `null` if
+   * there is no label associated with the statement.
+   */
+  BreakStatementImpl(
+      this.breakKeyword, SimpleIdentifier label, this.semicolon) {
+    _label = _becomeParentOf(label);
+  }
+
+  @override
+  Token get beginToken => breakKeyword;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(breakKeyword)..add(_label)..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  SimpleIdentifier get label => _label;
+
+  @override
+  void set label(SimpleIdentifier identifier) {
+    _label = _becomeParentOf(identifier);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitBreakStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_label, visitor);
+  }
+}
+
+/**
+ * A sequence of cascaded expressions: expressions that share a common target.
+ * 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
+ */
+class CascadeExpressionImpl extends ExpressionImpl
+    implements CascadeExpression {
+  /**
+   * The target of the cascade sections.
+   */
+  Expression _target;
+
+  /**
+   * The cascade sections sharing the common target.
+   */
+  NodeList<Expression> _cascadeSections;
+
+  /**
+   * Initialize a newly created cascade expression. The list of
+   * [cascadeSections] must contain at least one element.
+   */
+  CascadeExpressionImpl(Expression target, List<Expression> cascadeSections) {
+    _target = _becomeParentOf(target);
+    _cascadeSections = new NodeList<Expression>(this, cascadeSections);
+  }
+
+  @override
+  Token get beginToken => _target.beginToken;
+
+  @override
+  NodeList<Expression> get cascadeSections => _cascadeSections;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(_target)
+    ..addAll(_cascadeSections);
+
+  @override
+  Token get endToken => _cascadeSections.endToken;
+
+  @override
+  int get precedence => 2;
+
+  @override
+  Expression get target => _target;
+
+  @override
+  void set target(Expression target) {
+    _target = _becomeParentOf(target);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitCascadeExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_target, visitor);
+    _cascadeSections.accept(visitor);
+  }
+}
+
+/**
+ * A catch clause within a try statement.
+ *
+ *    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;
+
+  /**
+   * The type of exceptions caught by this catch clause, or `null` if this catch
+   * clause catches every type of exception.
+   */
+  TypeName _exceptionType;
+
+  /**
+   * 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;
+
+  /**
+   * The parameter whose value will be the exception that was thrown, or `null`
+   * if there is no 'catch' keyword.
+   */
+  SimpleIdentifier _exceptionParameter;
+
+  /**
+   * The comma separating the exception parameter from the stack trace
+   * parameter, or `null` if there is no stack trace parameter.
+   */
+  @override
+  Token comma;
+
+  /**
+   * The parameter whose value will be the stack trace associated with the
+   * exception, or `null` if there is no stack trace parameter.
+   */
+  SimpleIdentifier _stackTraceParameter;
+
+  /**
+   * The right parenthesis, or `null` if there is no 'catch' keyword.
+   */
+  @override
+  Token rightParenthesis;
+
+  /**
+   * The body of the catch block.
+   */
+  Block _body;
+
+  /**
+   * Initialize a newly created catch clause. The [onKeyword] and
+   * [exceptionType] can be `null` if the clause will catch all exceptions. The
+   * [comma] and [stackTraceParameter] can be `null` if the stack trace
+   * parameter is not defined.
+   */
+  CatchClauseImpl(
+      this.onKeyword,
+      TypeName exceptionType,
+      this.catchKeyword,
+      this.leftParenthesis,
+      SimpleIdentifier exceptionParameter,
+      this.comma,
+      SimpleIdentifier stackTraceParameter,
+      this.rightParenthesis,
+      Block body) {
+    _exceptionType = _becomeParentOf(exceptionType);
+    _exceptionParameter = _becomeParentOf(exceptionParameter);
+    _stackTraceParameter = _becomeParentOf(stackTraceParameter);
+    _body = _becomeParentOf(body);
+  }
+
+  @override
+  Token get beginToken {
+    if (onKeyword != null) {
+      return onKeyword;
+    }
+    return catchKeyword;
+  }
+
+  @override
+  Block get body => _body;
+
+  @override
+  void set body(Block block) {
+    _body = _becomeParentOf(block);
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(onKeyword)
+    ..add(_exceptionType)
+    ..add(catchKeyword)
+    ..add(leftParenthesis)
+    ..add(_exceptionParameter)
+    ..add(comma)
+    ..add(_stackTraceParameter)
+    ..add(rightParenthesis)
+    ..add(_body);
+
+  @override
+  Token get endToken => _body.endToken;
+
+  @override
+  SimpleIdentifier get exceptionParameter => _exceptionParameter;
+
+  @override
+  void set exceptionParameter(SimpleIdentifier parameter) {
+    _exceptionParameter = _becomeParentOf(parameter);
+  }
+
+  @override
+  TypeName get exceptionType => _exceptionType;
+
+  @override
+  void set exceptionType(TypeName exceptionType) {
+    _exceptionType = _becomeParentOf(exceptionType);
+  }
+
+  @override
+  SimpleIdentifier get stackTraceParameter => _stackTraceParameter;
+
+  @override
+  void set stackTraceParameter(SimpleIdentifier parameter) {
+    _stackTraceParameter = _becomeParentOf(parameter);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitCatchClause(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_exceptionType, visitor);
+    _safelyVisitChild(_exceptionParameter, visitor);
+    _safelyVisitChild(_stackTraceParameter, visitor);
+    _safelyVisitChild(_body, visitor);
+  }
+}
+
+/**
+ * Helper class to allow iteration of child entities of an AST node.
+ */
+class ChildEntities extends Object with IterableMixin implements Iterable {
+  /**
+   * The list of child entities to be iterated over.
+   */
+  List _entities = [];
+
+  @override
+  Iterator get iterator => _entities.iterator;
+
+  /**
+   * Add an AST node or token as the next child entity, if it is not null.
+   */
+  void add(entity) {
+    if (entity != null) {
+      assert(entity is Token || entity is AstNode);
+      _entities.add(entity);
+    }
+  }
+
+  /**
+   * Add the given items as the next child entities, if [items] is not null.
+   */
+  void addAll(Iterable items) {
+    if (items != null) {
+      _entities.addAll(items);
+    }
+  }
+}
+
+/**
+ * The declaration of a class.
+ *
+ *    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;
+
+  /**
+   * The type parameters for the class, or `null` if the class does not have any
+   * type parameters.
+   */
+  TypeParameterList _typeParameters;
+
+  /**
+   * The extends clause for the class, or `null` if the class does not extend
+   * any other class.
+   */
+  ExtendsClause _extendsClause;
+
+  /**
+   * The with clause for the class, or `null` if the class does not have a with
+   * clause.
+   */
+  WithClause _withClause;
+
+  /**
+   * The implements clause for the class, or `null` if the class does not
+   * implement any interfaces.
+   */
+  ImplementsClause _implementsClause;
+
+  /**
+   * The native clause for the class, or `null` if the class does not have a
+   * native clause.
+   */
+  NativeClause _nativeClause;
+
+  /**
+   * The left curly bracket.
+   */
+  @override
+  Token leftBracket;
+
+  /**
+   * The members defined by the class.
+   */
+  NodeList<ClassMember> _members;
+
+  /**
+   * The right curly bracket.
+   */
+  @override
+  Token rightBracket;
+
+  /**
+   * Initialize a newly created class declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the class does not have the
+   * corresponding attribute. The [abstractKeyword] can be `null` if the class
+   * is not abstract. The [typeParameters] can be `null` if the class does not
+   * have any type parameters. Any or all of the [extendsClause], [withClause],
+   * and [implementsClause] can be `null` if the class does not have the
+   * corresponding clause. The list of [members] can be `null` if the class does
+   * not have any members.
+   */
+  ClassDeclarationImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      this.abstractKeyword,
+      this.classKeyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      ExtendsClause extendsClause,
+      WithClause withClause,
+      ImplementsClause implementsClause,
+      this.leftBracket,
+      List<ClassMember> members,
+      this.rightBracket)
+      : super(comment, metadata, name) {
+    _typeParameters = _becomeParentOf(typeParameters);
+    _extendsClause = _becomeParentOf(extendsClause);
+    _withClause = _becomeParentOf(withClause);
+    _implementsClause = _becomeParentOf(implementsClause);
+    _members = new NodeList<ClassMember>(this, members);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(abstractKeyword)
+    ..add(classKeyword)
+    ..add(_name)
+    ..add(_typeParameters)
+    ..add(_extendsClause)
+    ..add(_withClause)
+    ..add(_implementsClause)
+    ..add(_nativeClause)
+    ..add(leftBracket)
+    ..addAll(members)
+    ..add(rightBracket);
+
+  @override
+  ClassElement get element =>
+      _name != null ? (_name.staticElement as ClassElement) : null;
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  ExtendsClause get extendsClause => _extendsClause;
+
+  @override
+  void set extendsClause(ExtendsClause extendsClause) {
+    _extendsClause = _becomeParentOf(extendsClause);
+  }
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata {
+    if (abstractKeyword != null) {
+      return abstractKeyword;
+    }
+    return classKeyword;
+  }
+
+  @override
+  ImplementsClause get implementsClause => _implementsClause;
+
+  @override
+  void set implementsClause(ImplementsClause implementsClause) {
+    _implementsClause = _becomeParentOf(implementsClause);
+  }
+
+  @override
+  bool get isAbstract => abstractKeyword != null;
+
+  @override
+  NodeList<ClassMember> get members => _members;
+
+  @override
+  NativeClause get nativeClause => _nativeClause;
+
+  @override
+  void set nativeClause(NativeClause nativeClause) {
+    _nativeClause = _becomeParentOf(nativeClause);
+  }
+
+  @override
+  TypeParameterList get typeParameters => _typeParameters;
+
+  @override
+  void set typeParameters(TypeParameterList typeParameters) {
+    _typeParameters = _becomeParentOf(typeParameters);
+  }
+
+  @override
+  WithClause get withClause => _withClause;
+
+  @override
+  void set withClause(WithClause withClause) {
+    _withClause = _becomeParentOf(withClause);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitClassDeclaration(this);
+
+  @override
+  ConstructorDeclaration getConstructor(String name) {
+    for (ClassMember classMember in _members) {
+      if (classMember is ConstructorDeclaration) {
+        ConstructorDeclaration constructor = classMember;
+        SimpleIdentifier constructorName = constructor.name;
+        if (name == null && constructorName == null) {
+          return constructor;
+        }
+        if (constructorName != null && constructorName.name == name) {
+          return constructor;
+        }
+      }
+    }
+    return null;
+  }
+
+  @override
+  VariableDeclaration getField(String name) {
+    for (ClassMember classMember in _members) {
+      if (classMember is FieldDeclaration) {
+        FieldDeclaration fieldDeclaration = classMember;
+        NodeList<VariableDeclaration> fields =
+            fieldDeclaration.fields.variables;
+        for (VariableDeclaration field in fields) {
+          SimpleIdentifier fieldName = field.name;
+          if (fieldName != null && name == fieldName.name) {
+            return field;
+          }
+        }
+      }
+    }
+    return null;
+  }
+
+  @override
+  MethodDeclaration getMethod(String name) {
+    for (ClassMember classMember in _members) {
+      if (classMember is MethodDeclaration) {
+        MethodDeclaration method = classMember;
+        SimpleIdentifier methodName = method.name;
+        if (methodName != null && name == methodName.name) {
+          return method;
+        }
+      }
+    }
+    return null;
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_typeParameters, visitor);
+    _safelyVisitChild(_extendsClause, visitor);
+    _safelyVisitChild(_withClause, visitor);
+    _safelyVisitChild(_implementsClause, visitor);
+    _safelyVisitChild(_nativeClause, visitor);
+    members.accept(visitor);
+  }
+}
+
+/**
+ * A node that declares a name within the scope of a class.
+ */
+abstract class ClassMemberImpl extends DeclarationImpl implements ClassMember {
+  /**
+   * Initialize a newly created member of a class. Either or both of the
+   * [comment] and [metadata] can be `null` if the member does not have the
+   * corresponding attribute.
+   */
+  ClassMemberImpl(Comment comment, List<Annotation> metadata)
+      : super(comment, metadata);
+}
+
+/**
+ * A class type alias.
+ *
+ *    classTypeAlias ::=
+ *        [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
+ *
+ *    mixinApplication ::=
+ *        [TypeName] [WithClause] [ImplementsClause]? ';'
+ */
+class ClassTypeAliasImpl extends TypeAliasImpl implements ClassTypeAlias {
+  /**
+   * The type parameters for the class, or `null` if the class does not have any
+   * type parameters.
+   */
+  TypeParameterList _typeParameters;
+
+  /**
+   * 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;
+
+  /**
+   * The name of the superclass of the class being declared.
+   */
+  TypeName _superclass;
+
+  /**
+   * The with clause for this class.
+   */
+  WithClause _withClause;
+
+  /**
+   * The implements clause for this class, or `null` if there is no implements
+   * clause.
+   */
+  ImplementsClause _implementsClause;
+
+  /**
+   * Initialize a newly created class type alias. Either or both of the
+   * [comment] and [metadata] can be `null` if the class type alias does not
+   * have the corresponding attribute. The [typeParameters] can be `null` if the
+   * class does not have any type parameters. The [abstractKeyword] can be
+   * `null` if the class is not abstract. The [implementsClause] can be `null`
+   * if the class does not implement any interfaces.
+   */
+  ClassTypeAliasImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      this.equals,
+      this.abstractKeyword,
+      TypeName superclass,
+      WithClause withClause,
+      ImplementsClause implementsClause,
+      Token semicolon)
+      : super(comment, metadata, keyword, name, semicolon) {
+    _typeParameters = _becomeParentOf(typeParameters);
+    _superclass = _becomeParentOf(superclass);
+    _withClause = _becomeParentOf(withClause);
+    _implementsClause = _becomeParentOf(implementsClause);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(typedefKeyword)
+    ..add(_name)
+    ..add(_typeParameters)
+    ..add(equals)
+    ..add(abstractKeyword)
+    ..add(_superclass)
+    ..add(_withClause)
+    ..add(_implementsClause)
+    ..add(semicolon);
+
+  @override
+  ClassElement get element =>
+      _name != null ? (_name.staticElement as ClassElement) : null;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata {
+    if (abstractKeyword != null) {
+      return abstractKeyword;
+    }
+    return typedefKeyword;
+  }
+
+  @override
+  ImplementsClause get implementsClause => _implementsClause;
+
+  @override
+  void set implementsClause(ImplementsClause implementsClause) {
+    _implementsClause = _becomeParentOf(implementsClause);
+  }
+
+  @override
+  bool get isAbstract => abstractKeyword != null;
+
+  @override
+  TypeName get superclass => _superclass;
+
+  @override
+  void set superclass(TypeName superclass) {
+    _superclass = _becomeParentOf(superclass);
+  }
+
+  @override
+  TypeParameterList get typeParameters => _typeParameters;
+
+  @override
+  void set typeParameters(TypeParameterList typeParameters) {
+    _typeParameters = _becomeParentOf(typeParameters);
+  }
+
+  @override
+  WithClause get withClause => _withClause;
+
+  @override
+  void set withClause(WithClause withClause) {
+    _withClause = _becomeParentOf(withClause);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitClassTypeAlias(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_typeParameters, visitor);
+    _safelyVisitChild(_superclass, visitor);
+    _safelyVisitChild(_withClause, visitor);
+    _safelyVisitChild(_implementsClause, visitor);
+  }
+}
+
+/**
+ * A combinator associated with an import or export directive.
+ *
+ *    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;
+
+  /**
+   * Initialize a newly created combinator.
+   */
+  CombinatorImpl(this.keyword);
+
+  @override
+  Token get beginToken => keyword;
+}
+
+/**
+ * A comment within the source code.
+ *
+ *    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;
+
+  /**
+   * The type of the comment.
+   */
+  final CommentType _type;
+
+  /**
+   * The references embedded within the documentation comment. This list will be
+   * empty unless this is a documentation comment that has references embedded
+   * within it.
+   */
+  NodeList<CommentReference> _references;
+
+  /**
+   * Initialize a newly created comment. The list of [tokens] must contain at
+   * least one token. The [type] is the type of the comment. The list of
+   * [references] can be empty if the comment does not contain any embedded
+   * references.
+   */
+  CommentImpl(this.tokens, this._type, List<CommentReference> references) {
+    _references = new NodeList<CommentReference>(this, references);
+  }
+
+  @override
+  Token get beginToken => tokens[0];
+
+  @override
+  Iterable get childEntities => new ChildEntities()..addAll(tokens);
+
+  @override
+  Token get endToken => tokens[tokens.length - 1];
+
+  @override
+  bool get isBlock => _type == CommentType.BLOCK;
+
+  @override
+  bool get isDocumentation => _type == CommentType.DOCUMENTATION;
+
+  @override
+  bool get isEndOfLine => _type == CommentType.END_OF_LINE;
+
+  @override
+  NodeList<CommentReference> get references => _references;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitComment(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _references.accept(visitor);
+  }
+
+  /**
+   * Create a block comment consisting of the given [tokens].
+   */
+  static Comment createBlockComment(List<Token> tokens) =>
+      new CommentImpl(tokens, CommentType.BLOCK, null);
+
+  /**
+   * Create a documentation comment consisting of the given [tokens].
+   */
+  static Comment createDocumentationComment(List<Token> tokens) =>
+      new CommentImpl(
+          tokens, CommentType.DOCUMENTATION, new List<CommentReference>());
+
+  /**
+   * Create a documentation comment consisting of the given [tokens] and having
+   * the given [references] embedded within it.
+   */
+  static Comment createDocumentationCommentWithReferences(
+          List<Token> tokens, List<CommentReference> references) =>
+      new CommentImpl(tokens, CommentType.DOCUMENTATION, references);
+
+  /**
+   * Create an end-of-line comment consisting of the given [tokens].
+   */
+  static Comment createEndOfLineComment(List<Token> tokens) =>
+      new CommentImpl(tokens, CommentType.END_OF_LINE, null);
+}
+
+/**
+ * A reference to a Dart element that is found within a documentation comment.
+ *
+ *    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;
+
+  /**
+   * The identifier being referenced.
+   */
+  Identifier _identifier;
+
+  /**
+   * Initialize a newly created reference to a Dart element. The [newKeyword]
+   * can be `null` if the reference is not to a constructor.
+   */
+  CommentReferenceImpl(this.newKeyword, Identifier identifier) {
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  Token get beginToken => _identifier.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(newKeyword)..add(_identifier);
+
+  @override
+  Token get endToken => _identifier.endToken;
+
+  @override
+  Identifier get identifier => _identifier;
+
+  @override
+  void set identifier(Identifier identifier) {
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitCommentReference(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_identifier, visitor);
+  }
+}
+
+/**
+ * The possible types of comments that are recognized by the parser.
+ */
+class CommentType {
+  /**
+   * A block comment.
+   */
+  static const CommentType BLOCK = const CommentType('BLOCK');
+
+  /**
+   * A documentation comment.
+   */
+  static const CommentType DOCUMENTATION = const CommentType('DOCUMENTATION');
+
+  /**
+   * An end-of-line comment.
+   */
+  static const CommentType END_OF_LINE = const CommentType('END_OF_LINE');
+
+  /**
+   * The name of the comment type.
+   */
+  final String name;
+
+  /**
+   * Initialize a newly created comment type to have the given [name].
+   */
+  const CommentType(this.name);
+
+  @override
+  String toString() => name;
+}
+
+/**
+ * A compilation unit.
+ *
+ * While the grammar restricts the order of the directives and declarations
+ * within a compilation unit, this class does not enforce those restrictions.
+ * In particular, the children of a compilation unit will be visited in lexical
+ * 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]*
+ */
+class CompilationUnitImpl extends AstNodeImpl implements CompilationUnit {
+  /**
+   * The first token in the token stream that was parsed to form this
+   * compilation unit.
+   */
+  @override
+  Token beginToken;
+
+  /**
+   * The script tag at the beginning of the compilation unit, or `null` if there
+   * is no script tag in this compilation unit.
+   */
+  ScriptTag _scriptTag;
+
+  /**
+   * The directives contained in this compilation unit.
+   */
+  NodeList<Directive> _directives;
+
+  /**
+   * The declarations contained in this compilation unit.
+   */
+  NodeList<CompilationUnitMember> _declarations;
+
+  /**
+   * 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;
+
+  /**
+   * Initialize a newly created compilation unit to have the given directives
+   * and declarations. The [scriptTag] can be `null` if there is no script tag
+   * in the compilation unit. The list of [directives] can be `null` if there
+   * are no directives in the compilation unit. The list of [declarations] can
+   * be `null` if there are no declarations in the compilation unit.
+   */
+  CompilationUnitImpl(
+      this.beginToken,
+      ScriptTag scriptTag,
+      List<Directive> directives,
+      List<CompilationUnitMember> declarations,
+      this.endToken) {
+    _scriptTag = _becomeParentOf(scriptTag);
+    _directives = new NodeList<Directive>(this, directives);
+    _declarations = new NodeList<CompilationUnitMember>(this, declarations);
+  }
+
+  @override
+  Iterable get childEntities {
+    ChildEntities result = new ChildEntities()..add(_scriptTag);
+    if (_directivesAreBeforeDeclarations) {
+      result..addAll(_directives)..addAll(_declarations);
+    } else {
+      result.addAll(sortedDirectivesAndDeclarations);
+    }
+    return result;
+  }
+
+  @override
+  NodeList<CompilationUnitMember> get declarations => _declarations;
+
+  @override
+  NodeList<Directive> get directives => _directives;
+
+  @override
+  int get length {
+    Token endToken = this.endToken;
+    if (endToken == null) {
+      return 0;
+    }
+    return endToken.offset + endToken.length;
+  }
+
+  @override
+  int get offset => 0;
+
+  @override
+  ScriptTag get scriptTag => _scriptTag;
+
+  @override
+  void set scriptTag(ScriptTag scriptTag) {
+    _scriptTag = _becomeParentOf(scriptTag);
+  }
+
+  @override
+  List<AstNode> get sortedDirectivesAndDeclarations {
+    return <AstNode>[]
+      ..addAll(_directives)
+      ..addAll(_declarations)
+      ..sort(AstNode.LEXICAL_ORDER);
+  }
+
+  /**
+   * Return `true` if all of the directives are lexically before any
+   * declarations.
+   */
+  bool get _directivesAreBeforeDeclarations {
+    if (_directives.isEmpty || _declarations.isEmpty) {
+      return true;
+    }
+    Directive lastDirective = _directives[_directives.length - 1];
+    CompilationUnitMember firstDeclaration = _declarations[0];
+    return lastDirective.offset < firstDeclaration.offset;
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitCompilationUnit(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_scriptTag, visitor);
+    if (_directivesAreBeforeDeclarations) {
+      _directives.accept(visitor);
+      _declarations.accept(visitor);
+    } else {
+      for (AstNode child in sortedDirectivesAndDeclarations) {
+        child.accept(visitor);
+      }
+    }
+  }
+}
+
+/**
+ * A node that declares one or more names within the scope of a compilation
+ * unit.
+ *
+ *    compilationUnitMember ::=
+ *        [ClassDeclaration]
+ *      | [TypeAlias]
+ *      | [FunctionDeclaration]
+ *      | [MethodDeclaration]
+ *      | [VariableDeclaration]
+ *      | [VariableDeclaration]
+ */
+abstract class CompilationUnitMemberImpl extends DeclarationImpl
+    implements CompilationUnitMember {
+  /**
+   * Initialize a newly created generic compilation unit member. Either or both
+   * of the [comment] and [metadata] can be `null` if the member does not have
+   * the corresponding attribute.
+   */
+  CompilationUnitMemberImpl(Comment comment, List<Annotation> metadata)
+      : super(comment, metadata);
+}
+
+/**
+ * A conditional expression.
+ *
+ *    conditionalExpression ::=
+ *        [Expression] '?' [Expression] ':' [Expression]
+ */
+class ConditionalExpressionImpl extends ExpressionImpl
+    implements ConditionalExpression {
+  /**
+   * The condition used to determine which of the expressions is executed next.
+   */
+  Expression _condition;
+
+  /**
+   * The token used to separate the condition from the then expression.
+   */
+  @override
+  Token question;
+
+  /**
+   * The expression that is executed if the condition evaluates to `true`.
+   */
+  Expression _thenExpression;
+
+  /**
+   * The token used to separate the then expression from the else expression.
+   */
+  @override
+  Token colon;
+
+  /**
+   * The expression that is executed if the condition evaluates to `false`.
+   */
+  Expression _elseExpression;
+
+  /**
+   * Initialize a newly created conditional expression.
+   */
+  ConditionalExpressionImpl(Expression condition, this.question,
+      Expression thenExpression, this.colon, Expression elseExpression) {
+    _condition = _becomeParentOf(condition);
+    _thenExpression = _becomeParentOf(thenExpression);
+    _elseExpression = _becomeParentOf(elseExpression);
+  }
+
+  @override
+  Token get beginToken => _condition.beginToken;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(_condition)
+    ..add(question)
+    ..add(_thenExpression)
+    ..add(colon)
+    ..add(_elseExpression);
+
+  @override
+  Expression get condition => _condition;
+
+  @override
+  void set condition(Expression expression) {
+    _condition = _becomeParentOf(expression);
+  }
+
+  @override
+  Expression get elseExpression => _elseExpression;
+
+  @override
+  void set elseExpression(Expression expression) {
+    _elseExpression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get endToken => _elseExpression.endToken;
+
+  @override
+  int get precedence => 3;
+
+  @override
+  Expression get thenExpression => _thenExpression;
+
+  @override
+  void set thenExpression(Expression expression) {
+    _thenExpression = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitConditionalExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_condition, visitor);
+    _safelyVisitChild(_thenExpression, visitor);
+    _safelyVisitChild(_elseExpression, visitor);
+  }
+}
+
+/**
+ * A configuration in either an import or export directive.
+ *
+ *     configuration ::=
+ *         'if' '(' test ')' uri
+ *
+ *     test ::=
+ *         dottedName ('==' stringLiteral)?
+ *
+ *     dottedName ::=
+ *         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;
+
+  ConfigurationImpl(
+      this.ifKeyword,
+      this.leftParenthesis,
+      DottedName name,
+      this.equalToken,
+      StringLiteral value,
+      this.rightParenthesis,
+      StringLiteral libraryUri) {
+    _name = _becomeParentOf(name);
+    _value = _becomeParentOf(value);
+    _libraryUri = _becomeParentOf(libraryUri);
+  }
+
+  @override
+  Token get beginToken => ifKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(ifKeyword)
+    ..add(leftParenthesis)
+    ..add(_name)
+    ..add(equalToken)
+    ..add(_value)
+    ..add(rightParenthesis)
+    ..add(_libraryUri);
+
+  @override
+  Token get endToken => _libraryUri.endToken;
+
+  @override
+  StringLiteral get libraryUri => _libraryUri;
+
+  @override
+  void set libraryUri(StringLiteral libraryUri) {
+    _libraryUri = _becomeParentOf(libraryUri);
+  }
+
+  @override
+  DottedName get name => _name;
+
+  @override
+  void set name(DottedName name) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  StringLiteral get value => _value;
+
+  @override
+  void set value(StringLiteral value) {
+    _value = _becomeParentOf(value);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitConfiguration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_value, visitor);
+    _safelyVisitChild(_libraryUri, visitor);
+  }
+}
+
+/**
+ * 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])*
+ */
+class ConstructorDeclarationImpl extends ClassMemberImpl
+    implements ConstructorDeclaration {
+  /**
+   * 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;
+
+  /**
+   * The type of object being created. This can be different than the type in
+   * which the constructor is being declared if the constructor is the
+   * implementation of a factory constructor.
+   */
+  Identifier _returnType;
+
+  /**
+   * The token for the period before the constructor name, or `null` if the
+   * constructor being declared is unnamed.
+   */
+  @override
+  Token period;
+
+  /**
+   * The name of the constructor, or `null` if the constructor being declared is
+   * unnamed.
+   */
+  SimpleIdentifier _name;
+
+  /**
+   * The parameters associated with the constructor.
+   */
+  FormalParameterList _parameters;
+
+  /**
+   * The token for the separator (colon or equals) before the initializer list
+   * or redirection, or `null` if there are no initializers.
+   */
+  @override
+  Token separator;
+
+  /**
+   * The initializers associated with the constructor.
+   */
+  NodeList<ConstructorInitializer> _initializers;
+
+  /**
+   * The name of the constructor to which this constructor will be redirected,
+   * or `null` if this is not a redirecting factory constructor.
+   */
+  ConstructorName _redirectedConstructor;
+
+  /**
+   * The body of the constructor, or `null` if the constructor does not have a
+   * body.
+   */
+  FunctionBody _body;
+
+  /**
+   * The element associated with this constructor, or `null` if the AST
+   * structure has not been resolved or if this constructor could not be
+   * resolved.
+   */
+  @override
+  ConstructorElement element;
+
+  /**
+   * Initialize a newly created constructor declaration. The [externalKeyword]
+   * can be `null` if the constructor is not external. Either or both of the
+   * [comment] and [metadata] can be `null` if the constructor does not have the
+   * corresponding attribute. The [constKeyword] can be `null` if the
+   * constructor cannot be used to create a constant. The [factoryKeyword] can
+   * be `null` if the constructor is not a factory. The [period] and [name] can
+   * both be `null` if the constructor is not a named constructor. The
+   * [separator] can be `null` if the constructor does not have any initializers
+   * and does not redirect to a different constructor. The list of
+   * [initializers] can be `null` if the constructor does not have any
+   * initializers. The [redirectedConstructor] can be `null` if the constructor
+   * does not redirect to a different constructor. The [body] can be `null` if
+   * the constructor does not have a body.
+   */
+  ConstructorDeclarationImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      this.externalKeyword,
+      this.constKeyword,
+      this.factoryKeyword,
+      Identifier returnType,
+      this.period,
+      SimpleIdentifier name,
+      FormalParameterList parameters,
+      this.separator,
+      List<ConstructorInitializer> initializers,
+      ConstructorName redirectedConstructor,
+      FunctionBody body)
+      : super(comment, metadata) {
+    _returnType = _becomeParentOf(returnType);
+    _name = _becomeParentOf(name);
+    _parameters = _becomeParentOf(parameters);
+    _initializers = new NodeList<ConstructorInitializer>(this, initializers);
+    _redirectedConstructor = _becomeParentOf(redirectedConstructor);
+    _body = _becomeParentOf(body);
+  }
+
+  @override
+  FunctionBody get body => _body;
+
+  @override
+  void set body(FunctionBody functionBody) {
+    _body = _becomeParentOf(functionBody);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(externalKeyword)
+    ..add(constKeyword)
+    ..add(factoryKeyword)
+    ..add(_returnType)
+    ..add(period)
+    ..add(_name)
+    ..add(_parameters)
+    ..add(separator)
+    ..addAll(initializers)
+    ..add(_redirectedConstructor)
+    ..add(_body);
+
+  @override
+  Token get endToken {
+    if (_body != null) {
+      return _body.endToken;
+    } else if (!_initializers.isEmpty) {
+      return _initializers.endToken;
+    }
+    return _parameters.endToken;
+  }
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata {
+    Token leftMost =
+        Token.lexicallyFirst([externalKeyword, constKeyword, factoryKeyword]);
+    if (leftMost != null) {
+      return leftMost;
+    }
+    return _returnType.beginToken;
+  }
+
+  @override
+  NodeList<ConstructorInitializer> get initializers => _initializers;
+
+  @override
+  SimpleIdentifier get name => _name;
+
+  @override
+  void set name(SimpleIdentifier identifier) {
+    _name = _becomeParentOf(identifier);
+  }
+
+  @override
+  FormalParameterList get parameters => _parameters;
+
+  @override
+  void set parameters(FormalParameterList parameters) {
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  ConstructorName get redirectedConstructor => _redirectedConstructor;
+
+  @override
+  void set redirectedConstructor(ConstructorName redirectedConstructor) {
+    _redirectedConstructor = _becomeParentOf(redirectedConstructor);
+  }
+
+  @override
+  Identifier get returnType => _returnType;
+
+  @override
+  void set returnType(Identifier typeName) {
+    _returnType = _becomeParentOf(typeName);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitConstructorDeclaration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_returnType, visitor);
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_parameters, visitor);
+    _initializers.accept(visitor);
+    _safelyVisitChild(_redirectedConstructor, visitor);
+    _safelyVisitChild(_body, visitor);
+  }
+}
+
+/**
+ * The initialization of a field within a constructor's initialization list.
+ *
+ *    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;
+
+  /**
+   * The name of the field being initialized.
+   */
+  SimpleIdentifier _fieldName;
+
+  /**
+   * The token for the equal sign between the field name and the expression.
+   */
+  @override
+  Token equals;
+
+  /**
+   * The expression computing the value to which the field will be initialized.
+   */
+  Expression _expression;
+
+  /**
+   * Initialize a newly created field initializer to initialize the field with
+   * the given name to the value of the given expression. The [thisKeyword] and
+   * [period] can be `null` if the 'this' keyword was not specified.
+   */
+  ConstructorFieldInitializerImpl(this.thisKeyword, this.period,
+      SimpleIdentifier fieldName, this.equals, Expression expression) {
+    _fieldName = _becomeParentOf(fieldName);
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken {
+    if (thisKeyword != null) {
+      return thisKeyword;
+    }
+    return _fieldName.beginToken;
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(thisKeyword)
+    ..add(period)
+    ..add(_fieldName)
+    ..add(equals)
+    ..add(_expression);
+
+  @override
+  Token get endToken => _expression.endToken;
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  SimpleIdentifier get fieldName => _fieldName;
+
+  @override
+  void set fieldName(SimpleIdentifier identifier) {
+    _fieldName = _becomeParentOf(identifier);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitConstructorFieldInitializer(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_fieldName, visitor);
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * A node that can occur in the initializer list of a constructor declaration.
+ *
+ *    constructorInitializer ::=
+ *        [SuperConstructorInvocation]
+ *      | [ConstructorFieldInitializer]
+ *      | [RedirectingConstructorInvocation]
+ */
+abstract class ConstructorInitializerImpl extends AstNodeImpl
+    implements ConstructorInitializer {}
+
+/**
+ * The name of the constructor.
+ *
+ *    constructorName ::=
+ *        type ('.' identifier)?
+ */
+class ConstructorNameImpl extends AstNodeImpl implements ConstructorName {
+  /**
+   * The name of the type defining the constructor.
+   */
+  TypeName _type;
+
+  /**
+   * The token for the period before the constructor name, or `null` if the
+   * specified constructor is the unnamed constructor.
+   */
+  @override
+  Token period;
+
+  /**
+   * The name of the constructor, or `null` if the specified constructor is the
+   * unnamed constructor.
+   */
+  SimpleIdentifier _name;
+
+  /**
+   * The element associated with this constructor name based on static type
+   * information, or `null` if the AST structure has not been resolved or if
+   * this constructor name could not be resolved.
+   */
+  @override
+  ConstructorElement staticElement;
+
+  /**
+   * Initialize a newly created constructor name. The [period] and [name] can be
+   * `null` if the constructor being named is the unnamed constructor.
+   */
+  ConstructorNameImpl(TypeName type, this.period, SimpleIdentifier name) {
+    _type = _becomeParentOf(type);
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  Token get beginToken => _type.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_type)..add(period)..add(_name);
+
+  @override
+  Token get endToken {
+    if (_name != null) {
+      return _name.endToken;
+    }
+    return _type.endToken;
+  }
+
+  @override
+  SimpleIdentifier get name => _name;
+
+  @override
+  void set name(SimpleIdentifier name) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  TypeName get type => _type;
+
+  @override
+  void set type(TypeName type) {
+    _type = _becomeParentOf(type);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitConstructorName(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_type, visitor);
+    _safelyVisitChild(_name, visitor);
+  }
+}
+
+/**
+ * A continue statement.
+ *
+ *    continueStatement ::=
+ *        'continue' [SimpleIdentifier]? ';'
+ */
+class ContinueStatementImpl extends StatementImpl implements ContinueStatement {
+  /**
+   * The token representing the 'continue' keyword.
+   */
+  @override
+  Token continueKeyword;
+
+  /**
+   * The label associated with the statement, or `null` if there is no label.
+   */
+  SimpleIdentifier _label;
+
+  /**
+   * The semicolon terminating the statement.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * The AstNode which this continue statement is continuing to.  This will be
+   * either a Statement (in the case of continuing a loop) or a SwitchMember
+   * (in the case of continuing from one switch case to another).  Null if the
+   * AST has not yet been resolved or if the target could not be resolved.
+   * Note that if the source code has errors, the target may be invalid (e.g.
+   * the target may be in an enclosing function).
+   */
+  AstNode target;
+
+  /**
+   * Initialize a newly created continue statement. The [label] can be `null` if
+   * there is no label associated with the statement.
+   */
+  ContinueStatementImpl(
+      this.continueKeyword, SimpleIdentifier label, this.semicolon) {
+    _label = _becomeParentOf(label);
+  }
+
+  @override
+  Token get beginToken => continueKeyword;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(continueKeyword)..add(_label)..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  SimpleIdentifier get label => _label;
+
+  @override
+  void set label(SimpleIdentifier identifier) {
+    _label = _becomeParentOf(identifier);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitContinueStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_label, visitor);
+  }
+}
+
+/**
+ * A node that represents the declaration of one or more names. Each declared
+ * name is visible within a name scope.
+ */
+abstract class DeclarationImpl extends AnnotatedNodeImpl
+    implements Declaration {
+  /**
+   * Initialize a newly created declaration. Either or both of the [comment] and
+   * [metadata] can be `null` if the declaration does not have the corresponding
+   * attribute.
+   */
+  DeclarationImpl(Comment comment, List<Annotation> metadata)
+      : super(comment, metadata);
+}
+
+/**
+ * The declaration of a single identifier.
+ *
+ *    declaredIdentifier ::=
+ *        [Annotation] finalConstVarOrType [SimpleIdentifier]
+ */
+class DeclaredIdentifierImpl extends DeclarationImpl
+    implements DeclaredIdentifier {
+  /**
+   * The token representing either the 'final', 'const' or 'var' keyword, or
+   * `null` if no keyword was used.
+   */
+  @override
+  Token keyword;
+
+  /**
+   * The name of the declared type of the parameter, or `null` if the parameter
+   * does not have a declared type.
+   */
+  TypeName _type;
+
+  /**
+   * The name of the variable being declared.
+   */
+  SimpleIdentifier _identifier;
+
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the declaration does not have the
+   * corresponding attribute. The [keyword] can be `null` if a type name is
+   * given. The [type] must be `null` if the keyword is 'var'.
+   */
+  DeclaredIdentifierImpl(Comment comment, List<Annotation> metadata,
+      this.keyword, TypeName type, SimpleIdentifier identifier)
+      : super(comment, metadata) {
+    _type = _becomeParentOf(type);
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(keyword)..add(_type)..add(_identifier);
+
+  @override
+  LocalVariableElement get element {
+    if (_identifier == null) {
+      return null;
+    }
+    return _identifier.staticElement as LocalVariableElement;
+  }
+
+  @override
+  Token get endToken => _identifier.endToken;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata {
+    if (keyword != null) {
+      return keyword;
+    } else if (_type != null) {
+      return _type.beginToken;
+    }
+    return _identifier.beginToken;
+  }
+
+  @override
+  SimpleIdentifier get identifier => _identifier;
+
+  @override
+  void set identifier(SimpleIdentifier identifier) {
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  bool get isConst =>
+      (keyword is KeywordToken) &&
+      (keyword as KeywordToken).keyword == Keyword.CONST;
+
+  @override
+  bool get isFinal =>
+      (keyword is KeywordToken) &&
+      (keyword as KeywordToken).keyword == Keyword.FINAL;
+
+  @override
+  TypeName get type => _type;
+
+  @override
+  void set type(TypeName typeName) {
+    _type = _becomeParentOf(typeName);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitDeclaredIdentifier(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_type, visitor);
+    _safelyVisitChild(_identifier, visitor);
+  }
+}
+
+/**
+ * A formal parameter with a default value. There are two kinds of parameters
+ * that are both represented by this class: named formal parameters and
+ * positional formal parameters.
+ *
+ *    defaultFormalParameter ::=
+ *        [NormalFormalParameter] ('=' [Expression])?
+ *
+ *    defaultNamedParameter ::=
+ *        [NormalFormalParameter] (':' [Expression])?
+ */
+class DefaultFormalParameterImpl extends FormalParameterImpl
+    implements DefaultFormalParameter {
+  /**
+   * The formal parameter with which the default value is associated.
+   */
+  NormalFormalParameter _parameter;
+
+  /**
+   * 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;
+
+  /**
+   * The expression computing the default value for the parameter, or `null` if
+   * there is no default value.
+   */
+  Expression _defaultValue;
+
+  /**
+   * Initialize a newly created default formal parameter. The [separator] and
+   * [defaultValue] can be `null` if there is no default value.
+   */
+  DefaultFormalParameterImpl(NormalFormalParameter parameter, this.kind,
+      this.separator, Expression defaultValue) {
+    _parameter = _becomeParentOf(parameter);
+    _defaultValue = _becomeParentOf(defaultValue);
+  }
+
+  @override
+  Token get beginToken => _parameter.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_parameter)..add(separator)..add(_defaultValue);
+
+  @override
+  Expression get defaultValue => _defaultValue;
+
+  @override
+  void set defaultValue(Expression expression) {
+    _defaultValue = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get endToken {
+    if (_defaultValue != null) {
+      return _defaultValue.endToken;
+    }
+    return _parameter.endToken;
+  }
+
+  @override
+  SimpleIdentifier get identifier => _parameter.identifier;
+
+  @override
+  bool get isConst => _parameter != null && _parameter.isConst;
+
+  @override
+  bool get isFinal => _parameter != null && _parameter.isFinal;
+
+  @override
+  NodeList<Annotation> get metadata => _parameter.metadata;
+
+  @override
+  NormalFormalParameter get parameter => _parameter;
+
+  @override
+  void set parameter(NormalFormalParameter formalParameter) {
+    _parameter = _becomeParentOf(formalParameter);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitDefaultFormalParameter(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_parameter, visitor);
+    _safelyVisitChild(_defaultValue, visitor);
+  }
+}
+
+/**
+ * A node that represents a directive.
+ *
+ *    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;
+
+  /**
+   * Initialize a newly create directive. Either or both of the [comment] and
+   * [metadata] can be `null` if the directive does not have the corresponding
+   * attribute.
+   */
+  DirectiveImpl(Comment comment, List<Annotation> metadata)
+      : super(comment, metadata);
+}
+
+/**
+ * A do statement.
+ *
+ *    doStatement ::=
+ *        'do' [Statement] 'while' '(' [Expression] ')' ';'
+ */
+class DoStatementImpl extends StatementImpl implements DoStatement {
+  /**
+   * The token representing the 'do' keyword.
+   */
+  @override
+  Token doKeyword;
+
+  /**
+   * The body of the loop.
+   */
+  Statement _body;
+
+  /**
+   * The token representing the 'while' keyword.
+   */
+  @override
+  Token whileKeyword;
+
+  /**
+   * The left parenthesis.
+   */
+  Token leftParenthesis;
+
+  /**
+   * The condition that determines when the loop will terminate.
+   */
+  Expression _condition;
+
+  /**
+   * The right parenthesis.
+   */
+  @override
+  Token rightParenthesis;
+
+  /**
+   * The semicolon terminating the statement.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created do loop.
+   */
+  DoStatementImpl(
+      this.doKeyword,
+      Statement body,
+      this.whileKeyword,
+      this.leftParenthesis,
+      Expression condition,
+      this.rightParenthesis,
+      this.semicolon) {
+    _body = _becomeParentOf(body);
+    _condition = _becomeParentOf(condition);
+  }
+
+  @override
+  Token get beginToken => doKeyword;
+
+  @override
+  Statement get body => _body;
+
+  @override
+  void set body(Statement statement) {
+    _body = _becomeParentOf(statement);
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(doKeyword)
+    ..add(_body)
+    ..add(whileKeyword)
+    ..add(leftParenthesis)
+    ..add(_condition)
+    ..add(rightParenthesis)
+    ..add(semicolon);
+
+  @override
+  Expression get condition => _condition;
+
+  @override
+  void set condition(Expression expression) {
+    _condition = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitDoStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_body, visitor);
+    _safelyVisitChild(_condition, visitor);
+  }
+}
+
+/**
+ * A dotted name, used in a configuration within an import or export directive.
+ *
+ *    dottedName ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ */
+class DottedNameImpl extends AstNodeImpl implements DottedName {
+  /**
+   * The components of the identifier.
+   */
+  NodeList<SimpleIdentifier> _components;
+
+  /**
+   * Initialize a newly created dotted name.
+   */
+  DottedNameImpl(List<SimpleIdentifier> components) {
+    _components = new NodeList<SimpleIdentifier>(this, components);
+  }
+
+  @override
+  Token get beginToken => _components.beginToken;
+
+  @override
+  // TODO(paulberry): add "." tokens.
+  Iterable get childEntities => new ChildEntities()..addAll(_components);
+
+  @override
+  NodeList<SimpleIdentifier> get components => _components;
+
+  @override
+  Token get endToken => _components.endToken;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitDottedName(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _components.accept(visitor);
+  }
+}
+
+/**
+ * A floating point literal expression.
+ *
+ *    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;
+
+  /**
+   * Initialize a newly created floating point literal.
+   */
+  DoubleLiteralImpl(this.literal, this.value);
+
+  @override
+  Token get beginToken => literal;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(literal);
+
+  @override
+  Token get endToken => literal;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitDoubleLiteral(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * An empty function body, which can only appear in constructors or abstract
+ * methods.
+ *
+ *    emptyFunctionBody ::=
+ *        ';'
+ */
+class EmptyFunctionBodyImpl extends FunctionBodyImpl
+    implements EmptyFunctionBody {
+  /**
+   * The token representing the semicolon that marks the end of the function
+   * body.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created function body.
+   */
+  EmptyFunctionBodyImpl(this.semicolon);
+
+  @override
+  Token get beginToken => semicolon;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitEmptyFunctionBody(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // Empty function bodies have no children.
+  }
+}
+
+/**
+ * An empty statement.
+ *
+ *    emptyStatement ::=
+ *        ';'
+ */
+class EmptyStatementImpl extends StatementImpl implements EmptyStatement {
+  /**
+   * The semicolon terminating the statement.
+   */
+  Token semicolon;
+
+  /**
+   * Initialize a newly created empty statement.
+   */
+  EmptyStatementImpl(this.semicolon);
+
+  @override
+  Token get beginToken => semicolon;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitEmptyStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * The declaration of an enum constant.
+ */
+class EnumConstantDeclarationImpl extends DeclarationImpl
+    implements EnumConstantDeclaration {
+  /**
+   * The name of the constant.
+   */
+  SimpleIdentifier _name;
+
+  /**
+   * Initialize a newly created enum constant declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the constant does not have the
+   * corresponding attribute. (Technically, enum constants cannot have metadata,
+   * but we allow it for consistency.)
+   */
+  EnumConstantDeclarationImpl(
+      Comment comment, List<Annotation> metadata, SimpleIdentifier name)
+      : super(comment, metadata) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities..add(_name);
+
+  @override
+  FieldElement get element =>
+      _name == null ? null : (_name.staticElement as FieldElement);
+
+  @override
+  Token get endToken => _name.endToken;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
+
+  @override
+  SimpleIdentifier get name => _name;
+
+  @override
+  void set name(SimpleIdentifier name) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitEnumConstantDeclaration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_name, visitor);
+  }
+}
+
+/**
+ * The declaration of an enumeration.
+ *
+ *    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;
+
+  /**
+   * The enumeration constants being declared.
+   */
+  NodeList<EnumConstantDeclaration> _constants;
+
+  /**
+   * The right curly bracket.
+   */
+  @override
+  Token rightBracket;
+
+  /**
+   * Initialize a newly created enumeration declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the declaration does not have the
+   * corresponding attribute. The list of [constants] must contain at least one
+   * value.
+   */
+  EnumDeclarationImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      this.enumKeyword,
+      SimpleIdentifier name,
+      this.leftBracket,
+      List<EnumConstantDeclaration> constants,
+      this.rightBracket)
+      : super(comment, metadata, name) {
+    _constants = new NodeList<EnumConstantDeclaration>(this, constants);
+  }
+
+  @override
+  // TODO(brianwilkerson) Add commas?
+  Iterable get childEntities => super._childEntities
+    ..add(enumKeyword)
+    ..add(_name)
+    ..add(leftBracket)
+    ..addAll(_constants)
+    ..add(rightBracket);
+
+  @override
+  NodeList<EnumConstantDeclaration> get constants => _constants;
+
+  @override
+  ClassElement get element =>
+      _name != null ? (_name.staticElement as ClassElement) : null;
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => enumKeyword;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitEnumDeclaration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_name, visitor);
+    _constants.accept(visitor);
+  }
+}
+
+/**
+ * Ephemeral identifiers are created as needed to mimic the presence of an empty
+ * identifier.
+ */
+class EphemeralIdentifier extends SimpleIdentifierImpl {
+  EphemeralIdentifier(AstNode parent, int location)
+      : super(new StringToken(TokenType.IDENTIFIER, "", location)) {
+    (parent as AstNodeImpl)._becomeParentOf(this);
+  }
+}
+
+/**
+ * An export directive.
+ *
+ *    exportDirective ::=
+ *        [Annotation] 'export' [StringLiteral] [Combinator]* ';'
+ */
+class ExportDirectiveImpl extends NamespaceDirectiveImpl
+    implements ExportDirective {
+  /**
+   * Initialize a newly created export directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute. The list of [combinators] can be `null` if there
+   * are no combinators.
+   */
+  ExportDirectiveImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      StringLiteral libraryUri,
+      List<Configuration> configurations,
+      List<Combinator> combinators,
+      Token semicolon)
+      : super(comment, metadata, keyword, libraryUri, configurations,
+            combinators, semicolon);
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(_uri)
+    ..addAll(combinators)
+    ..add(semicolon);
+
+  @override
+  ExportElement get element => super.element as ExportElement;
+
+  @override
+  LibraryElement get uriElement {
+    if (element != null) {
+      return element.exportedLibrary;
+    }
+    return null;
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitExportDirective(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    combinators.accept(visitor);
+  }
+}
+
+/**
+ * A function body consisting of a single expression.
+ *
+ *    expressionFunctionBody ::=
+ *        'async'? '=>' [Expression] ';'
+ */
+class ExpressionFunctionBodyImpl extends FunctionBodyImpl
+    implements ExpressionFunctionBody {
+  /**
+   * 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;
+
+  /**
+   * The expression representing the body of the function.
+   */
+  Expression _expression;
+
+  /**
+   * The semicolon terminating the statement.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created function body consisting of a block of
+   * statements. The [keyword] can be `null` if the function body is not an
+   * async function body.
+   */
+  ExpressionFunctionBodyImpl(this.keyword, this.functionDefinition,
+      Expression expression, this.semicolon) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken {
+    if (keyword != null) {
+      return keyword;
+    }
+    return functionDefinition;
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(keyword)
+    ..add(functionDefinition)
+    ..add(_expression)
+    ..add(semicolon);
+
+  @override
+  Token get endToken {
+    if (semicolon != null) {
+      return semicolon;
+    }
+    return _expression.endToken;
+  }
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  bool get isAsynchronous => keyword != null;
+
+  @override
+  bool get isSynchronous => keyword == null;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitExpressionFunctionBody(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * A node that represents an expression.
+ *
+ *    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;
+
+  /**
+   * Return the best parameter element information available for this
+   * expression. If type propagation was able to find a better parameter element
+   * than static analysis, that type will be returned. Otherwise, the result of
+   * static analysis will be returned.
+   */
+  ParameterElement get bestParameterElement {
+    ParameterElement propagatedElement = propagatedParameterElement;
+    if (propagatedElement != null) {
+      return propagatedElement;
+    }
+    return staticParameterElement;
+  }
+
+  @override
+  DartType get bestType {
+    if (propagatedType != null) {
+      return propagatedType;
+    } else if (staticType != null) {
+      return staticType;
+    }
+    return DynamicTypeImpl.instance;
+  }
+
+  @override
+  bool get isAssignable => false;
+
+  @override
+  ParameterElement get propagatedParameterElement {
+    AstNode parent = this.parent;
+    if (parent is ArgumentListImpl) {
+      return parent._getPropagatedParameterElementFor(this);
+    } else if (parent is IndexExpressionImpl) {
+      if (identical(parent.index, this)) {
+        return parent._propagatedParameterElementForIndex;
+      }
+    } else if (parent is BinaryExpressionImpl) {
+      if (identical(parent.rightOperand, this)) {
+        return parent._propagatedParameterElementForRightOperand;
+      }
+    } else if (parent is AssignmentExpressionImpl) {
+      if (identical(parent.rightHandSide, this)) {
+        return parent._propagatedParameterElementForRightHandSide;
+      }
+    } else if (parent is PrefixExpressionImpl) {
+      return parent._propagatedParameterElementForOperand;
+    } else if (parent is PostfixExpressionImpl) {
+      return parent._propagatedParameterElementForOperand;
+    }
+    return null;
+  }
+
+  @override
+  ParameterElement get staticParameterElement {
+    AstNode parent = this.parent;
+    if (parent is ArgumentListImpl) {
+      return parent._getStaticParameterElementFor(this);
+    } else if (parent is IndexExpressionImpl) {
+      if (identical(parent.index, this)) {
+        return parent._staticParameterElementForIndex;
+      }
+    } else if (parent is BinaryExpressionImpl) {
+      if (identical(parent.rightOperand, this)) {
+        return parent._staticParameterElementForRightOperand;
+      }
+    } else if (parent is AssignmentExpressionImpl) {
+      if (identical(parent.rightHandSide, this)) {
+        return parent._staticParameterElementForRightHandSide;
+      }
+    } else if (parent is PrefixExpressionImpl) {
+      return parent._staticParameterElementForOperand;
+    } else if (parent is PostfixExpressionImpl) {
+      return parent._staticParameterElementForOperand;
+    }
+    return null;
+  }
+}
+
+/**
+ * An expression used as a statement.
+ *
+ *    expressionStatement ::=
+ *        [Expression]? ';'
+ */
+class ExpressionStatementImpl extends StatementImpl
+    implements ExpressionStatement {
+  /**
+   * The expression that comprises the statement.
+   */
+  Expression _expression;
+
+  /**
+   * 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;
+
+  /**
+   * Initialize a newly created expression statement.
+   */
+  ExpressionStatementImpl(Expression expression, this.semicolon) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken => _expression.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_expression)..add(semicolon);
+
+  @override
+  Token get endToken {
+    if (semicolon != null) {
+      return semicolon;
+    }
+    return _expression.endToken;
+  }
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  bool get isSynthetic => _expression.isSynthetic && semicolon.isSynthetic;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitExpressionStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * The "extends" clause in a class declaration.
+ *
+ *    extendsClause ::=
+ *        'extends' [TypeName]
+ */
+class ExtendsClauseImpl extends AstNodeImpl implements ExtendsClause {
+  /**
+   * The token representing the 'extends' keyword.
+   */
+  @override
+  Token extendsKeyword;
+
+  /**
+   * The name of the class that is being extended.
+   */
+  TypeName _superclass;
+
+  /**
+   * Initialize a newly created extends clause.
+   */
+  ExtendsClauseImpl(this.extendsKeyword, TypeName superclass) {
+    _superclass = _becomeParentOf(superclass);
+  }
+
+  @override
+  Token get beginToken => extendsKeyword;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(extendsKeyword)..add(_superclass);
+
+  @override
+  Token get endToken => _superclass.endToken;
+
+  @override
+  TypeName get superclass => _superclass;
+
+  @override
+  void set superclass(TypeName name) {
+    _superclass = _becomeParentOf(name);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitExtendsClause(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_superclass, visitor);
+  }
+}
+
+/**
+ * The declaration of one or more fields of the same type.
+ *
+ *    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;
+
+  /**
+   * The fields being declared.
+   */
+  VariableDeclarationList _fieldList;
+
+  /**
+   * The semicolon terminating the declaration.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created field declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the declaration does not have the
+   * corresponding attribute. The [staticKeyword] can be `null` if the field is
+   * not a static field.
+   */
+  FieldDeclarationImpl(Comment comment, List<Annotation> metadata,
+      this.staticKeyword, VariableDeclarationList fieldList, this.semicolon)
+      : super(comment, metadata) {
+    _fieldList = _becomeParentOf(fieldList);
+  }
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(staticKeyword)..add(_fieldList)..add(semicolon);
+
+  @override
+  Element get element => null;
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  VariableDeclarationList get fields => _fieldList;
+
+  @override
+  void set fields(VariableDeclarationList fields) {
+    _fieldList = _becomeParentOf(fields);
+  }
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata {
+    if (staticKeyword != null) {
+      return staticKeyword;
+    }
+    return _fieldList.beginToken;
+  }
+
+  @override
+  bool get isStatic => staticKeyword != null;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFieldDeclaration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_fieldList, visitor);
+  }
+}
+
+/**
+ * A field formal parameter.
+ *
+ *    fieldFormalParameter ::=
+ *        ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
+ *        'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
+ */
+class FieldFormalParameterImpl extends NormalFormalParameterImpl
+    implements FieldFormalParameter {
+  /**
+   * The token representing either the 'final', 'const' or 'var' keyword, or
+   * `null` if no keyword was used.
+   */
+  @override
+  Token keyword;
+
+  /**
+   * The name of the declared type of the parameter, or `null` if the parameter
+   * does not have a declared type.
+   */
+  TypeName _type;
+
+  /**
+   * The token representing the 'this' keyword.
+   */
+  @override
+  Token thisKeyword;
+
+  /**
+   * The token representing the period.
+   */
+  @override
+  Token period;
+
+  /**
+   * The type parameters associated with the method, or `null` if the method is
+   * not a generic method.
+   */
+  TypeParameterList _typeParameters;
+
+  /**
+   * The parameters of the function-typed parameter, or `null` if this is not a
+   * function-typed field formal parameter.
+   */
+  FormalParameterList _parameters;
+
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute. The [keyword] can be `null` if there is a type.
+   * The [type] must be `null` if the keyword is 'var'. The [thisKeyword] and
+   * [period] can be `null` if the keyword 'this' was not provided.  The
+   * [parameters] can be `null` if this is not a function-typed field formal
+   * parameter.
+   */
+  FieldFormalParameterImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      this.keyword,
+      TypeName type,
+      this.thisKeyword,
+      this.period,
+      SimpleIdentifier identifier,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters)
+      : super(comment, metadata, identifier) {
+    _type = _becomeParentOf(type);
+    _typeParameters = _becomeParentOf(typeParameters);
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  Token get beginToken {
+    if (keyword != null) {
+      return keyword;
+    } else if (_type != null) {
+      return _type.beginToken;
+    }
+    return thisKeyword;
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(keyword)
+    ..add(_type)
+    ..add(thisKeyword)
+    ..add(period)
+    ..add(identifier)
+    ..add(_parameters);
+
+  @override
+  Token get endToken {
+    if (_parameters != null) {
+      return _parameters.endToken;
+    }
+    return identifier.endToken;
+  }
+
+  @override
+  bool get isConst =>
+      (keyword is KeywordToken) &&
+      (keyword as KeywordToken).keyword == Keyword.CONST;
+
+  @override
+  bool get isFinal =>
+      (keyword is KeywordToken) &&
+      (keyword as KeywordToken).keyword == Keyword.FINAL;
+
+  @override
+  FormalParameterList get parameters => _parameters;
+
+  @override
+  void set parameters(FormalParameterList parameters) {
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  TypeName get type => _type;
+
+  @override
+  void set type(TypeName typeName) {
+    _type = _becomeParentOf(typeName);
+  }
+
+  @override
+  TypeParameterList get typeParameters => _typeParameters;
+
+  @override
+  void set typeParameters(TypeParameterList typeParameters) {
+    _typeParameters = _becomeParentOf(typeParameters);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFieldFormalParameter(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_type, visitor);
+    _safelyVisitChild(identifier, visitor);
+    _safelyVisitChild(_typeParameters, visitor);
+    _safelyVisitChild(_parameters, visitor);
+  }
+}
+
+/**
+ * A for-each statement.
+ *
+ *    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;
+
+  /**
+   * The declaration of the loop variable, or `null` if the loop variable is a
+   * simple identifier.
+   */
+  DeclaredIdentifier _loopVariable;
+
+  /**
+   * The loop variable, or `null` if the loop variable is declared in the 'for'.
+   */
+  SimpleIdentifier _identifier;
+
+  /**
+   * The token representing the 'in' keyword.
+   */
+  @override
+  Token inKeyword;
+
+  /**
+   * The expression evaluated to produce the iterator.
+   */
+  Expression _iterable;
+
+  /**
+   * The right parenthesis.
+   */
+  @override
+  Token rightParenthesis;
+
+  /**
+   * The body of the loop.
+   */
+  Statement _body;
+
+  /**
+   * Initialize a newly created for-each statement whose loop control variable
+   * is declared internally (in the for-loop part). The [awaitKeyword] can be
+   * `null` if this is not an asynchronous for loop.
+   */
+  ForEachStatementImpl.withDeclaration(
+      this.awaitKeyword,
+      this.forKeyword,
+      this.leftParenthesis,
+      DeclaredIdentifier loopVariable,
+      this.inKeyword,
+      Expression iterator,
+      this.rightParenthesis,
+      Statement body) {
+    _loopVariable = _becomeParentOf(loopVariable);
+    _iterable = _becomeParentOf(iterator);
+    _body = _becomeParentOf(body);
+  }
+
+  /**
+   * Initialize a newly created for-each statement whose loop control variable
+   * is declared outside the for loop. The [awaitKeyword] can be `null` if this
+   * is not an asynchronous for loop.
+   */
+  ForEachStatementImpl.withReference(
+      this.awaitKeyword,
+      this.forKeyword,
+      this.leftParenthesis,
+      SimpleIdentifier identifier,
+      this.inKeyword,
+      Expression iterator,
+      this.rightParenthesis,
+      Statement body) {
+    _identifier = _becomeParentOf(identifier);
+    _iterable = _becomeParentOf(iterator);
+    _body = _becomeParentOf(body);
+  }
+
+  @override
+  Token get beginToken => forKeyword;
+
+  @override
+  Statement get body => _body;
+
+  @override
+  void set body(Statement statement) {
+    _body = _becomeParentOf(statement);
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(awaitKeyword)
+    ..add(forKeyword)
+    ..add(leftParenthesis)
+    ..add(_loopVariable)
+    ..add(_identifier)
+    ..add(inKeyword)
+    ..add(_iterable)
+    ..add(rightParenthesis)
+    ..add(_body);
+
+  @override
+  Token get endToken => _body.endToken;
+
+  @override
+  SimpleIdentifier get identifier => _identifier;
+
+  @override
+  void set identifier(SimpleIdentifier identifier) {
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  Expression get iterable => _iterable;
+
+  @override
+  void set iterable(Expression expression) {
+    _iterable = _becomeParentOf(expression);
+  }
+
+  @override
+  DeclaredIdentifier get loopVariable => _loopVariable;
+
+  @override
+  void set loopVariable(DeclaredIdentifier variable) {
+    _loopVariable = _becomeParentOf(variable);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitForEachStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_loopVariable, visitor);
+    _safelyVisitChild(_identifier, visitor);
+    _safelyVisitChild(_iterable, visitor);
+    _safelyVisitChild(_body, visitor);
+  }
+}
+
+/**
+ * A node representing a parameter to a function.
+ *
+ *    formalParameter ::=
+ *        [NormalFormalParameter]
+ *      | [DefaultFormalParameter]
+ */
+abstract class FormalParameterImpl extends AstNodeImpl
+    implements FormalParameter {
+  @override
+  ParameterElement get element {
+    SimpleIdentifier identifier = this.identifier;
+    if (identifier == null) {
+      return null;
+    }
+    return identifier.staticElement as ParameterElement;
+  }
+}
+
+/**
+ * The formal parameter list of a method declaration, function declaration, or
+ * function type alias.
+ *
+ * While the grammar requires all optional formal parameters to follow all of
+ * the normal formal parameters and at most one grouping of optional formal
+ * parameters, this class does not enforce those constraints. All parameters are
+ * 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])* '}'
+ */
+class FormalParameterListImpl extends AstNodeImpl
+    implements FormalParameterList {
+  /**
+   * The left parenthesis.
+   */
+  @override
+  Token leftParenthesis;
+
+  /**
+   * The parameters associated with the method.
+   */
+  NodeList<FormalParameter> _parameters;
+
+  /**
+   * 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;
+
+  /**
+   * Initialize a newly created parameter list. The list of [parameters] can be
+   * `null` if there are no parameters. The [leftDelimiter] and [rightDelimiter]
+   * can be `null` if there are no optional parameters.
+   */
+  FormalParameterListImpl(
+      this.leftParenthesis,
+      List<FormalParameter> parameters,
+      this.leftDelimiter,
+      this.rightDelimiter,
+      this.rightParenthesis) {
+    _parameters = new NodeList<FormalParameter>(this, parameters);
+  }
+
+  @override
+  Token get beginToken => leftParenthesis;
+
+  @override
+  Iterable get childEntities {
+    // TODO(paulberry): include commas.
+    ChildEntities result = new ChildEntities()..add(leftParenthesis);
+    bool leftDelimiterNeeded = leftDelimiter != null;
+    for (FormalParameter parameter in _parameters) {
+      if (leftDelimiterNeeded && leftDelimiter.offset < parameter.offset) {
+        result.add(leftDelimiter);
+        leftDelimiterNeeded = false;
+      }
+      result.add(parameter);
+    }
+    return result..add(rightDelimiter)..add(rightParenthesis);
+  }
+
+  @override
+  Token get endToken => rightParenthesis;
+
+  @override
+  List<ParameterElement> get parameterElements {
+    int count = _parameters.length;
+    List<ParameterElement> types = new List<ParameterElement>(count);
+    for (int i = 0; i < count; i++) {
+      types[i] = _parameters[i].element;
+    }
+    return types;
+  }
+
+  @override
+  NodeList<FormalParameter> get parameters => _parameters;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFormalParameterList(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _parameters.accept(visitor);
+  }
+}
+
+/**
+ * A for statement.
+ *
+ *    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;
+
+  /**
+   * The declaration of the loop variables, or `null` if there are no variables.
+   * Note that a for statement cannot have both a variable list and an
+   * initialization expression, but can validly have neither.
+   */
+  VariableDeclarationList _variableList;
+
+  /**
+   * The initialization expression, or `null` if there is no initialization
+   * expression. Note that a for statement cannot have both a variable list and
+   * an initialization expression, but can validly have neither.
+   */
+  Expression _initialization;
+
+  /**
+   * The semicolon separating the initializer and the condition.
+   */
+  @override
+  Token leftSeparator;
+
+  /**
+   * The condition used to determine when to terminate the loop, or `null` if
+   * there is no condition.
+   */
+  Expression _condition;
+
+  /**
+   * The semicolon separating the condition and the updater.
+   */
+  @override
+  Token rightSeparator;
+
+  /**
+   * The list of expressions run after each execution of the loop body.
+   */
+  NodeList<Expression> _updaters;
+
+  /**
+   * The right parenthesis.
+   */
+  @override
+  Token rightParenthesis;
+
+  /**
+   * The body of the loop.
+   */
+  Statement _body;
+
+  /**
+   * Initialize a newly created for statement. Either the [variableList] or the
+   * [initialization] must be `null`. Either the [condition] and the list of
+   * [updaters] can be `null` if the loop does not have the corresponding
+   * attribute.
+   */
+  ForStatementImpl(
+      this.forKeyword,
+      this.leftParenthesis,
+      VariableDeclarationList variableList,
+      Expression initialization,
+      this.leftSeparator,
+      Expression condition,
+      this.rightSeparator,
+      List<Expression> updaters,
+      this.rightParenthesis,
+      Statement body) {
+    _variableList = _becomeParentOf(variableList);
+    _initialization = _becomeParentOf(initialization);
+    _condition = _becomeParentOf(condition);
+    _updaters = new NodeList<Expression>(this, updaters);
+    _body = _becomeParentOf(body);
+  }
+
+  @override
+  Token get beginToken => forKeyword;
+
+  @override
+  Statement get body => _body;
+
+  @override
+  void set body(Statement statement) {
+    _body = _becomeParentOf(statement);
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(forKeyword)
+    ..add(leftParenthesis)
+    ..add(_variableList)
+    ..add(_initialization)
+    ..add(leftSeparator)
+    ..add(_condition)
+    ..add(rightSeparator)
+    ..addAll(_updaters)
+    ..add(rightParenthesis)
+    ..add(_body);
+
+  @override
+  Expression get condition => _condition;
+
+  @override
+  void set condition(Expression expression) {
+    _condition = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get endToken => _body.endToken;
+
+  @override
+  Expression get initialization => _initialization;
+
+  @override
+  void set initialization(Expression initialization) {
+    _initialization = _becomeParentOf(initialization);
+  }
+
+  @override
+  NodeList<Expression> get updaters => _updaters;
+
+  @override
+  VariableDeclarationList get variables => _variableList;
+
+  @override
+  void set variables(VariableDeclarationList variableList) {
+    _variableList = _becomeParentOf(variableList);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitForStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_variableList, visitor);
+    _safelyVisitChild(_initialization, visitor);
+    _safelyVisitChild(_condition, visitor);
+    _updaters.accept(visitor);
+    _safelyVisitChild(_body, visitor);
+  }
+}
+
+/**
+ * A node representing the body of a function or method.
+ *
+ *    functionBody ::=
+ *        [BlockFunctionBody]
+ *      | [EmptyFunctionBody]
+ *      | [ExpressionFunctionBody]
+ */
+abstract class FunctionBodyImpl extends AstNodeImpl implements FunctionBody {
+  /**
+   * Additional information about local variables and parameters that are
+   * declared within this function body or any enclosing function body.  `null`
+   * if resolution has not yet been performed.
+   */
+  LocalVariableInfo localVariableInfo;
+
+  /**
+   * 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
+  bool isPotentiallyMutatedInClosure(VariableElement variable) {
+    if (localVariableInfo == null) {
+      throw new StateError('Resolution has not yet been performed');
+    }
+    return localVariableInfo.potentiallyMutatedInClosure.contains(variable);
+  }
+
+  @override
+  bool isPotentiallyMutatedInScope(VariableElement variable) {
+    if (localVariableInfo == null) {
+      throw new StateError('Resolution has not yet been performed');
+    }
+    return localVariableInfo.potentiallyMutatedInScope.contains(variable);
+  }
+}
+
+/**
+ * A top-level declaration.
+ *
+ *    functionDeclaration ::=
+ *        'external' functionSignature
+ *      | functionSignature [FunctionBody]
+ *
+ *    functionSignature ::=
+ *        [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
+ */
+class FunctionDeclarationImpl extends NamedCompilationUnitMemberImpl
+    implements FunctionDeclaration {
+  /**
+   * The token representing the 'external' keyword, or `null` if this is not an
+   * external function.
+   */
+  @override
+  Token externalKeyword;
+
+  /**
+   * The return type of the function, or `null` if no return type was declared.
+   */
+  TypeName _returnType;
+
+  /**
+   * The token representing the 'get' or 'set' keyword, or `null` if this is a
+   * function declaration rather than a property declaration.
+   */
+  @override
+  Token propertyKeyword;
+
+  /**
+   * The function expression being wrapped.
+   */
+  FunctionExpression _functionExpression;
+
+  /**
+   * Initialize a newly created function declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the function does not have the
+   * corresponding attribute. The [externalKeyword] can be `null` if the
+   * function is not an external function. The [returnType] can be `null` if no
+   * return type was specified. The [propertyKeyword] can be `null` if the
+   * function is neither a getter or a setter.
+   */
+  FunctionDeclarationImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      this.externalKeyword,
+      TypeName returnType,
+      this.propertyKeyword,
+      SimpleIdentifier name,
+      FunctionExpression functionExpression)
+      : super(comment, metadata, name) {
+    _returnType = _becomeParentOf(returnType);
+    _functionExpression = _becomeParentOf(functionExpression);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(externalKeyword)
+    ..add(_returnType)
+    ..add(propertyKeyword)
+    ..add(_name)
+    ..add(_functionExpression);
+
+  @override
+  ExecutableElement get element =>
+      _name != null ? (_name.staticElement as ExecutableElement) : null;
+
+  @override
+  Token get endToken => _functionExpression.endToken;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata {
+    if (externalKeyword != null) {
+      return externalKeyword;
+    } else if (_returnType != null) {
+      return _returnType.beginToken;
+    } else if (propertyKeyword != null) {
+      return propertyKeyword;
+    } else if (_name != null) {
+      return _name.beginToken;
+    }
+    return _functionExpression.beginToken;
+  }
+
+  @override
+  FunctionExpression get functionExpression => _functionExpression;
+
+  @override
+  void set functionExpression(FunctionExpression functionExpression) {
+    _functionExpression = _becomeParentOf(functionExpression);
+  }
+
+  @override
+  bool get isGetter =>
+      propertyKeyword != null &&
+      (propertyKeyword as KeywordToken).keyword == Keyword.GET;
+
+  @override
+  bool get isSetter =>
+      propertyKeyword != null &&
+      (propertyKeyword as KeywordToken).keyword == Keyword.SET;
+
+  @override
+  TypeName get returnType => _returnType;
+
+  @override
+  void set returnType(TypeName returnType) {
+    _returnType = _becomeParentOf(returnType);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFunctionDeclaration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_returnType, visitor);
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_functionExpression, visitor);
+  }
+}
+
+/**
+ * A [FunctionDeclaration] used as a statement.
+ */
+class FunctionDeclarationStatementImpl extends StatementImpl
+    implements FunctionDeclarationStatement {
+  /**
+   * The function declaration being wrapped.
+   */
+  FunctionDeclaration _functionDeclaration;
+
+  /**
+   * Initialize a newly created function declaration statement.
+   */
+  FunctionDeclarationStatementImpl(FunctionDeclaration functionDeclaration) {
+    _functionDeclaration = _becomeParentOf(functionDeclaration);
+  }
+
+  @override
+  Token get beginToken => _functionDeclaration.beginToken;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(_functionDeclaration);
+
+  @override
+  Token get endToken => _functionDeclaration.endToken;
+
+  @override
+  FunctionDeclaration get functionDeclaration => _functionDeclaration;
+
+  @override
+  void set functionDeclaration(FunctionDeclaration functionDeclaration) {
+    _functionDeclaration = _becomeParentOf(functionDeclaration);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFunctionDeclarationStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_functionDeclaration, visitor);
+  }
+}
+
+/**
+ * A function expression.
+ *
+ *    functionExpression ::=
+ *        [TypeParameterList]? [FormalParameterList] [FunctionBody]
+ */
+class FunctionExpressionImpl extends ExpressionImpl
+    implements FunctionExpression {
+  /**
+   * The type parameters associated with the method, or `null` if the method is
+   * not a generic method.
+   */
+  TypeParameterList _typeParameters;
+
+  /**
+   * The parameters associated with the function.
+   */
+  FormalParameterList _parameters;
+
+  /**
+   * The body of the function, or `null` if this is an external function.
+   */
+  FunctionBody _body;
+
+  /**
+   * The element associated with the function, or `null` if the AST structure
+   * has not been resolved.
+   */
+  @override
+  ExecutableElement element;
+
+  /**
+   * Initialize a newly created function declaration.
+   */
+  FunctionExpressionImpl(TypeParameterList typeParameters,
+      FormalParameterList parameters, FunctionBody body) {
+    _typeParameters = _becomeParentOf(typeParameters);
+    _parameters = _becomeParentOf(parameters);
+    _body = _becomeParentOf(body);
+  }
+
+  @override
+  Token get beginToken {
+    if (_typeParameters != null) {
+      return _typeParameters.beginToken;
+    } else if (_parameters != null) {
+      return _parameters.beginToken;
+    } else if (_body != null) {
+      return _body.beginToken;
+    }
+    // This should never be reached because external functions must be named,
+    // hence either the body or the name should be non-null.
+    throw new IllegalStateException("Non-external functions must have a body");
+  }
+
+  @override
+  FunctionBody get body => _body;
+
+  @override
+  void set body(FunctionBody functionBody) {
+    _body = _becomeParentOf(functionBody);
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_parameters)..add(_body);
+
+  @override
+  Token get endToken {
+    if (_body != null) {
+      return _body.endToken;
+    } else if (_parameters != null) {
+      return _parameters.endToken;
+    }
+    // This should never be reached because external functions must be named,
+    // hence either the body or the name should be non-null.
+    throw new IllegalStateException("Non-external functions must have a body");
+  }
+
+  @override
+  FormalParameterList get parameters => _parameters;
+
+  @override
+  void set parameters(FormalParameterList parameters) {
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  int get precedence => 16;
+
+  @override
+  TypeParameterList get typeParameters => _typeParameters;
+
+  @override
+  void set typeParameters(TypeParameterList typeParameters) {
+    _typeParameters = _becomeParentOf(typeParameters);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFunctionExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_typeParameters, visitor);
+    _safelyVisitChild(_parameters, visitor);
+    _safelyVisitChild(_body, visitor);
+  }
+}
+
+/**
+ * The invocation of a function resulting from evaluating an expression.
+ * Invocations of methods and other forms of functions are represented by
+ * [MethodInvocation] nodes. Invocations of getters and setters are represented
+ * by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+ *
+ *    functionExpressionInvocation ::=
+ *        [Expression] [TypeArgumentList]? [ArgumentList]
+ */
+class FunctionExpressionInvocationImpl extends InvocationExpressionImpl
+    implements FunctionExpressionInvocation {
+  /**
+   * The expression producing the function being invoked.
+   */
+  Expression _function;
+
+  /**
+   * The element associated with the function being invoked based on static type
+   * information, or `null` if the AST structure has not been resolved or the
+   * function could not be resolved.
+   */
+  @override
+  ExecutableElement staticElement;
+
+  /**
+   * The element associated with the function being invoked based on propagated
+   * type information, or `null` if the AST structure has not been resolved or
+   * the function could not be resolved.
+   */
+  @override
+  ExecutableElement propagatedElement;
+
+  /**
+   * Initialize a newly created function expression invocation.
+   */
+  FunctionExpressionInvocationImpl(Expression function,
+      TypeArgumentList typeArguments, ArgumentList argumentList)
+      : super(typeArguments, argumentList) {
+    _function = _becomeParentOf(function);
+  }
+
+  @override
+  Token get beginToken => _function.beginToken;
+
+  @override
+  ExecutableElement get bestElement {
+    ExecutableElement element = propagatedElement;
+    if (element == null) {
+      element = staticElement;
+    }
+    return element;
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_function)..add(_argumentList);
+
+  @override
+  Token get endToken => _argumentList.endToken;
+
+  @override
+  Expression get function => _function;
+
+  @override
+  void set function(Expression expression) {
+    _function = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 15;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFunctionExpressionInvocation(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_function, visitor);
+    _safelyVisitChild(_typeArguments, visitor);
+    _safelyVisitChild(_argumentList, visitor);
+  }
+}
+
+/**
+ * A function type alias.
+ *
+ *    functionTypeAlias ::=
+ *        functionPrefix [TypeParameterList]? [FormalParameterList] ';'
+ *
+ *    functionPrefix ::=
+ *        [TypeName]? [SimpleIdentifier]
+ */
+class FunctionTypeAliasImpl extends TypeAliasImpl implements FunctionTypeAlias {
+  /**
+   * The name of the return type of the function type being defined, or `null`
+   * if no return type was given.
+   */
+  TypeName _returnType;
+
+  /**
+   * The type parameters for the function type, or `null` if the function type
+   * does not have any type parameters.
+   */
+  TypeParameterList _typeParameters;
+
+  /**
+   * The parameters associated with the function type.
+   */
+  FormalParameterList _parameters;
+
+  /**
+   * Initialize a newly created function type alias. Either or both of the
+   * [comment] and [metadata] can be `null` if the function does not have the
+   * corresponding attribute. The [returnType] can be `null` if no return type
+   * was specified. The [typeParameters] can be `null` if the function has no
+   * type parameters.
+   */
+  FunctionTypeAliasImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      TypeName returnType,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters,
+      Token semicolon)
+      : super(comment, metadata, keyword, name, semicolon) {
+    _returnType = _becomeParentOf(returnType);
+    _typeParameters = _becomeParentOf(typeParameters);
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(typedefKeyword)
+    ..add(_returnType)
+    ..add(_name)
+    ..add(_typeParameters)
+    ..add(_parameters)
+    ..add(semicolon);
+
+  @override
+  FunctionTypeAliasElement get element =>
+      _name != null ? (_name.staticElement as FunctionTypeAliasElement) : null;
+
+  @override
+  FormalParameterList get parameters => _parameters;
+
+  @override
+  void set parameters(FormalParameterList parameters) {
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  TypeName get returnType => _returnType;
+
+  @override
+  void set returnType(TypeName typeName) {
+    _returnType = _becomeParentOf(typeName);
+  }
+
+  @override
+  TypeParameterList get typeParameters => _typeParameters;
+
+  @override
+  void set typeParameters(TypeParameterList typeParameters) {
+    _typeParameters = _becomeParentOf(typeParameters);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFunctionTypeAlias(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_returnType, visitor);
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_typeParameters, visitor);
+    _safelyVisitChild(_parameters, visitor);
+  }
+}
+
+/**
+ * A function-typed formal parameter.
+ *
+ *    functionSignature ::=
+ *        [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
+ */
+class FunctionTypedFormalParameterImpl extends NormalFormalParameterImpl
+    implements FunctionTypedFormalParameter {
+  /**
+   * The return type of the function, or `null` if the function does not have a
+   * return type.
+   */
+  TypeName _returnType;
+
+  /**
+   * The type parameters associated with the function, or `null` if the function
+   * is not a generic function.
+   */
+  TypeParameterList _typeParameters;
+
+  /**
+   * The parameters of the function-typed parameter.
+   */
+  FormalParameterList _parameters;
+
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute. The [returnType] can be `null` if no return type
+   * was specified.
+   */
+  FunctionTypedFormalParameterImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      TypeName returnType,
+      SimpleIdentifier identifier,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters)
+      : super(comment, metadata, identifier) {
+    _returnType = _becomeParentOf(returnType);
+    _typeParameters = _becomeParentOf(typeParameters);
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  Token get beginToken {
+    if (_returnType != null) {
+      return _returnType.beginToken;
+    }
+    return identifier.beginToken;
+  }
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(_returnType)..add(identifier)..add(parameters);
+
+  @override
+  Token get endToken => _parameters.endToken;
+
+  @override
+  bool get isConst => false;
+
+  @override
+  bool get isFinal => false;
+
+  @override
+  FormalParameterList get parameters => _parameters;
+
+  @override
+  void set parameters(FormalParameterList parameters) {
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  TypeName get returnType => _returnType;
+
+  @override
+  void set returnType(TypeName type) {
+    _returnType = _becomeParentOf(type);
+  }
+
+  @override
+  TypeParameterList get typeParameters => _typeParameters;
+
+  @override
+  void set typeParameters(TypeParameterList typeParameters) {
+    _typeParameters = _becomeParentOf(typeParameters);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitFunctionTypedFormalParameter(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_returnType, visitor);
+    _safelyVisitChild(identifier, visitor);
+    _safelyVisitChild(_typeParameters, visitor);
+    _safelyVisitChild(_parameters, visitor);
+  }
+}
+
+/**
+ * A combinator that restricts the names being imported to those that are not in
+ * a given list.
+ *
+ *    hideCombinator ::=
+ *        'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ */
+class HideCombinatorImpl extends CombinatorImpl implements HideCombinator {
+  /**
+   * The list of names from the library that are hidden by this combinator.
+   */
+  NodeList<SimpleIdentifier> _hiddenNames;
+
+  /**
+   * Initialize a newly created import show combinator.
+   */
+  HideCombinatorImpl(Token keyword, List<SimpleIdentifier> hiddenNames)
+      : super(keyword) {
+    _hiddenNames = new NodeList<SimpleIdentifier>(this, hiddenNames);
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(keyword)
+    ..addAll(_hiddenNames);
+
+  @override
+  Token get endToken => _hiddenNames.endToken;
+
+  @override
+  NodeList<SimpleIdentifier> get hiddenNames => _hiddenNames;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitHideCombinator(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _hiddenNames.accept(visitor);
+  }
+}
+
+/**
+ * A node that represents an identifier.
+ *
+ *    identifier ::=
+ *        [SimpleIdentifier]
+ *      | [PrefixedIdentifier]
+ */
+abstract class IdentifierImpl extends ExpressionImpl implements Identifier {
+  /**
+   * Return the best element available for this operator. If resolution was able
+   * to find a better element based on type propagation, that element will be
+   * returned. Otherwise, the element found using the result of static analysis
+   * will be returned. If resolution has not been performed, then `null` will be
+   * returned.
+   */
+  Element get bestElement;
+
+  @override
+  bool get isAssignable => true;
+}
+
+/**
+ * An if 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;
+
+  /**
+   * The condition used to determine which of the statements is executed next.
+   */
+  Expression _condition;
+
+  /**
+   * The right parenthesis.
+   */
+  @override
+  Token rightParenthesis;
+
+  /**
+   * The statement that is executed if the condition evaluates to `true`.
+   */
+  Statement _thenStatement;
+
+  /**
+   * The token representing the 'else' keyword, or `null` if there is no else
+   * statement.
+   */
+  @override
+  Token elseKeyword;
+
+  /**
+   * The statement that is executed if the condition evaluates to `false`, or
+   * `null` if there is no else statement.
+   */
+  Statement _elseStatement;
+
+  /**
+   * Initialize a newly created if statement. The [elseKeyword] and
+   * [elseStatement] can be `null` if there is no else clause.
+   */
+  IfStatementImpl(
+      this.ifKeyword,
+      this.leftParenthesis,
+      Expression condition,
+      this.rightParenthesis,
+      Statement thenStatement,
+      this.elseKeyword,
+      Statement elseStatement) {
+    _condition = _becomeParentOf(condition);
+    _thenStatement = _becomeParentOf(thenStatement);
+    _elseStatement = _becomeParentOf(elseStatement);
+  }
+
+  @override
+  Token get beginToken => ifKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(ifKeyword)
+    ..add(leftParenthesis)
+    ..add(_condition)
+    ..add(rightParenthesis)
+    ..add(_thenStatement)
+    ..add(elseKeyword)
+    ..add(_elseStatement);
+
+  @override
+  Expression get condition => _condition;
+
+  @override
+  void set condition(Expression expression) {
+    _condition = _becomeParentOf(expression);
+  }
+
+  @override
+  Statement get elseStatement => _elseStatement;
+
+  @override
+  void set elseStatement(Statement statement) {
+    _elseStatement = _becomeParentOf(statement);
+  }
+
+  @override
+  Token get endToken {
+    if (_elseStatement != null) {
+      return _elseStatement.endToken;
+    }
+    return _thenStatement.endToken;
+  }
+
+  @override
+  Statement get thenStatement => _thenStatement;
+
+  @override
+  void set thenStatement(Statement statement) {
+    _thenStatement = _becomeParentOf(statement);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitIfStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_condition, visitor);
+    _safelyVisitChild(_thenStatement, visitor);
+    _safelyVisitChild(_elseStatement, visitor);
+  }
+}
+
+/**
+ * The "implements" clause in an class declaration.
+ *
+ *    implementsClause ::=
+ *        'implements' [TypeName] (',' [TypeName])*
+ */
+class ImplementsClauseImpl extends AstNodeImpl implements ImplementsClause {
+  /**
+   * The token representing the 'implements' keyword.
+   */
+  @override
+  Token implementsKeyword;
+
+  /**
+   * The interfaces that are being implemented.
+   */
+  NodeList<TypeName> _interfaces;
+
+  /**
+   * Initialize a newly created implements clause.
+   */
+  ImplementsClauseImpl(this.implementsKeyword, List<TypeName> interfaces) {
+    _interfaces = new NodeList<TypeName>(this, interfaces);
+  }
+
+  @override
+  Token get beginToken => implementsKeyword;
+
+  @override
+  // TODO(paulberry): add commas.
+  Iterable get childEntities => new ChildEntities()
+    ..add(implementsKeyword)
+    ..addAll(interfaces);
+
+  @override
+  Token get endToken => _interfaces.endToken;
+
+  @override
+  NodeList<TypeName> get interfaces => _interfaces;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitImplementsClause(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _interfaces.accept(visitor);
+  }
+}
+
+/**
+ * An import directive.
+ *
+ *    importDirective ::=
+ *        [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
+ *      | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
+ */
+class ImportDirectiveImpl extends NamespaceDirectiveImpl
+    implements ImportDirective {
+  /**
+   * The token representing the 'deferred' keyword, or `null` if the imported is
+   * not deferred.
+   */
+  Token deferredKeyword;
+
+  /**
+   * The token representing the 'as' keyword, or `null` if the imported names are
+   * not prefixed.
+   */
+  @override
+  Token asKeyword;
+
+  /**
+   * The prefix to be used with the imported names, or `null` if the imported
+   * names are not prefixed.
+   */
+  SimpleIdentifier _prefix;
+
+  /**
+   * Initialize a newly created import directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the function does not have the
+   * corresponding attribute. The [deferredKeyword] can be `null` if the import
+   * is not deferred. The [asKeyword] and [prefix] can be `null` if the import
+   * does not specify a prefix. The list of [combinators] can be `null` if there
+   * are no combinators.
+   */
+  ImportDirectiveImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      Token keyword,
+      StringLiteral libraryUri,
+      List<Configuration> configurations,
+      this.deferredKeyword,
+      this.asKeyword,
+      SimpleIdentifier prefix,
+      List<Combinator> combinators,
+      Token semicolon)
+      : super(comment, metadata, keyword, libraryUri, configurations,
+            combinators, semicolon) {
+    _prefix = _becomeParentOf(prefix);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(_uri)
+    ..add(deferredKeyword)
+    ..add(asKeyword)
+    ..add(_prefix)
+    ..addAll(combinators)
+    ..add(semicolon);
+
+  @override
+  ImportElement get element => super.element as ImportElement;
+
+  @override
+  SimpleIdentifier get prefix => _prefix;
+
+  @override
+  void set prefix(SimpleIdentifier identifier) {
+    _prefix = _becomeParentOf(identifier);
+  }
+
+  @override
+  LibraryElement get uriElement {
+    ImportElement element = this.element;
+    if (element == null) {
+      return null;
+    }
+    return element.importedLibrary;
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitImportDirective(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_prefix, visitor);
+    combinators.accept(visitor);
+  }
+}
+
+/**
+ * An index expression.
+ *
+ *    indexExpression ::=
+ *        [Expression] '[' [Expression] ']'
+ */
+class IndexExpressionImpl extends ExpressionImpl implements IndexExpression {
+  /**
+   * The expression used to compute the object being indexed, or `null` if this
+   * index expression is part of a cascade expression.
+   */
+  Expression _target;
+
+  /**
+   * 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;
+
+  /**
+   * The expression used to compute the index.
+   */
+  Expression _index;
+
+  /**
+   * The right square bracket.
+   */
+  @override
+  Token rightBracket;
+
+  /**
+   * The element associated with the operator based on the static type of the
+   * target, or `null` if the AST structure has not been resolved or if the
+   * operator could not be resolved.
+   */
+  @override
+  MethodElement staticElement;
+
+  /**
+   * The element associated with the operator based on the propagated type of
+   * the target, or `null` if the AST structure has not been resolved or if the
+   * operator could not be resolved.
+   */
+
+  @override
+  MethodElement propagatedElement;
+
+  /**
+   * If this expression is both in a getter and setter context, the
+   * [AuxiliaryElements] will be set to hold onto the static and propagated
+   * information. The auxiliary element will hold onto the elements from the
+   * getter context.
+   */
+  AuxiliaryElements auxiliaryElements = null;
+
+  /**
+   * Initialize a newly created index expression.
+   */
+  IndexExpressionImpl.forCascade(
+      this.period, this.leftBracket, Expression index, this.rightBracket) {
+    _index = _becomeParentOf(index);
+  }
+
+  /**
+   * Initialize a newly created index expression.
+   */
+  IndexExpressionImpl.forTarget(Expression target, this.leftBracket,
+      Expression index, this.rightBracket) {
+    _target = _becomeParentOf(target);
+    _index = _becomeParentOf(index);
+  }
+
+  @override
+  Token get beginToken {
+    if (_target != null) {
+      return _target.beginToken;
+    }
+    return period;
+  }
+
+  @override
+  MethodElement get bestElement {
+    MethodElement element = propagatedElement;
+    if (element == null) {
+      element = staticElement;
+    }
+    return element;
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(_target)
+    ..add(period)
+    ..add(leftBracket)
+    ..add(_index)
+    ..add(rightBracket);
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  Expression get index => _index;
+
+  @override
+  void set index(Expression expression) {
+    _index = _becomeParentOf(expression);
+  }
+
+  @override
+  bool get isAssignable => true;
+
+  @override
+  bool get isCascaded => period != null;
+
+  @override
+  int get precedence => 15;
+
+  @override
+  Expression get realTarget {
+    if (isCascaded) {
+      AstNode ancestor = parent;
+      while (ancestor is! CascadeExpression) {
+        if (ancestor == null) {
+          return _target;
+        }
+        ancestor = ancestor.parent;
+      }
+      return (ancestor as CascadeExpression).target;
+    }
+    return _target;
+  }
+
+  @override
+  Expression get target => _target;
+
+  @override
+  void set target(Expression expression) {
+    _target = _becomeParentOf(expression);
+  }
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on propagated type information, then return the parameter
+   * element representing the parameter to which the value of the index
+   * expression will be bound. Otherwise, return `null`.
+   */
+  ParameterElement get _propagatedParameterElementForIndex {
+    if (propagatedElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = propagatedElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on static type information, then return the parameter element
+   * representing the parameter to which the value of the index expression will
+   * be bound. Otherwise, return `null`.
+   */
+  ParameterElement get _staticParameterElementForIndex {
+    if (staticElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = staticElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitIndexExpression(this);
+
+  @override
+  bool inGetterContext() {
+    // TODO(brianwilkerson) Convert this to a getter.
+    AstNode parent = this.parent;
+    if (parent is AssignmentExpression) {
+      AssignmentExpression assignment = parent;
+      if (identical(assignment.leftHandSide, this) &&
+          assignment.operator.type == TokenType.EQ) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @override
+  bool inSetterContext() {
+    // TODO(brianwilkerson) Convert this to a getter.
+    AstNode parent = this.parent;
+    if (parent is PrefixExpression) {
+      return parent.operator.type.isIncrementOperator;
+    } else if (parent is PostfixExpression) {
+      return true;
+    } else if (parent is AssignmentExpression) {
+      return identical(parent.leftHandSide, this);
+    }
+    return false;
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_target, visitor);
+    _safelyVisitChild(_index, visitor);
+  }
+}
+
+/**
+ * An instance creation expression.
+ *
+ *    newExpression ::=
+ *        ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
+ */
+class InstanceCreationExpressionImpl extends ExpressionImpl
+    implements InstanceCreationExpression {
+  /**
+   * The 'new' or 'const' keyword used to indicate how an object should be
+   * created.
+   */
+  @override
+  Token keyword;
+
+  /**
+   * The name of the constructor to be invoked.
+   */
+  ConstructorName _constructorName;
+
+  /**
+   * The list of arguments to the constructor.
+   */
+  ArgumentList _argumentList;
+
+  /**
+   * The element associated with the constructor based on static type
+   * information, or `null` if the AST structure has not been resolved or if the
+   * constructor could not be resolved.
+   */
+  @override
+  ConstructorElement staticElement;
+
+  /**
+   * Initialize a newly created instance creation expression.
+   */
+  InstanceCreationExpressionImpl(this.keyword, ConstructorName constructorName,
+      ArgumentList argumentList) {
+    _constructorName = _becomeParentOf(constructorName);
+    _argumentList = _becomeParentOf(argumentList);
+  }
+
+  @override
+  ArgumentList get argumentList => _argumentList;
+
+  @override
+  void set argumentList(ArgumentList argumentList) {
+    _argumentList = _becomeParentOf(argumentList);
+  }
+
+  @override
+  Token get beginToken => keyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(keyword)
+    ..add(_constructorName)
+    ..add(_argumentList);
+
+  @override
+  ConstructorName get constructorName => _constructorName;
+
+  @override
+  void set constructorName(ConstructorName name) {
+    _constructorName = _becomeParentOf(name);
+  }
+
+  @override
+  Token get endToken => _argumentList.endToken;
+
+  @override
+  bool get isConst =>
+      keyword is KeywordToken &&
+      (keyword as KeywordToken).keyword == Keyword.CONST;
+
+  @override
+  int get precedence => 16;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitInstanceCreationExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_constructorName, visitor);
+    _safelyVisitChild(_argumentList, visitor);
+  }
+}
+
+/**
+ * An integer literal expression.
+ *
+ *    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;
+
+  /**
+   * Initialize a newly created integer literal.
+   */
+  IntegerLiteralImpl(this.literal, this.value);
+
+  @override
+  Token get beginToken => literal;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(literal);
+
+  @override
+  Token get endToken => literal;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitIntegerLiteral(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * A node within a [StringInterpolation].
+ *
+ *    interpolationElement ::=
+ *        [InterpolationExpression]
+ *      | [InterpolationString]
+ */
+abstract class InterpolationElementImpl extends AstNodeImpl
+    implements InterpolationElement {}
+
+/**
+ * An expression embedded in a string interpolation.
+ *
+ *    interpolationExpression ::=
+ *        '$' [SimpleIdentifier]
+ *      | '$' '{' [Expression] '}'
+ */
+class InterpolationExpressionImpl extends InterpolationElementImpl
+    implements InterpolationExpression {
+  /**
+   * The token used to introduce the interpolation expression; either '$' if the
+   * expression is a simple identifier or '${' if the expression is a full
+   * expression.
+   */
+  @override
+  Token leftBracket;
+
+  /**
+   * The expression to be evaluated for the value to be converted into a string.
+   */
+  Expression _expression;
+
+  /**
+   * The right curly bracket, or `null` if the expression is an identifier
+   * without brackets.
+   */
+  @override
+  Token rightBracket;
+
+  /**
+   * Initialize a newly created interpolation expression.
+   */
+  InterpolationExpressionImpl(
+      this.leftBracket, Expression expression, this.rightBracket) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken => leftBracket;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(leftBracket)
+    ..add(_expression)
+    ..add(rightBracket);
+
+  @override
+  Token get endToken {
+    if (rightBracket != null) {
+      return rightBracket;
+    }
+    return _expression.endToken;
+  }
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitInterpolationExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * A non-empty substring of an interpolated string.
+ *
+ *    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;
+
+  /**
+   * Initialize a newly created string of characters that are part of a string
+   * interpolation.
+   */
+  InterpolationStringImpl(this.contents, this.value);
+
+  @override
+  Token get beginToken => contents;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(contents);
+
+  @override
+  int get contentsEnd {
+    String lexeme = contents.lexeme;
+    return offset + new StringLexemeHelper(lexeme, true, true).end;
+  }
+
+  @override
+  int get contentsOffset {
+    int offset = contents.offset;
+    String lexeme = contents.lexeme;
+    return offset + new StringLexemeHelper(lexeme, true, true).start;
+  }
+
+  @override
+  Token get endToken => contents;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitInterpolationString(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {}
+}
+
+/**
+ * Common base class for [FunctionExpressionInvocationImpl] and
+ * [MethodInvocationImpl].
+ */
+abstract class InvocationExpressionImpl extends ExpressionImpl
+    implements InvocationExpression {
+  /**
+   * The list of arguments to the function.
+   */
+  ArgumentList _argumentList;
+
+  /**
+   * The type arguments to be applied to the method being invoked, or `null` if
+   * no type arguments were provided.
+   */
+  TypeArgumentList _typeArguments;
+
+  @override
+  DartType propagatedInvokeType;
+
+  @override
+  DartType staticInvokeType;
+
+  /**
+   * Initialize a newly created invocation.
+   */
+  InvocationExpressionImpl(
+      TypeArgumentList typeArguments, ArgumentList argumentList) {
+    _typeArguments = _becomeParentOf(typeArguments);
+    _argumentList = _becomeParentOf(argumentList);
+  }
+
+  @override
+  ArgumentList get argumentList => _argumentList;
+
+  void set argumentList(ArgumentList argumentList) {
+    _argumentList = _becomeParentOf(argumentList);
+  }
+
+  @override
+  TypeArgumentList get typeArguments => _typeArguments;
+
+  void set typeArguments(TypeArgumentList typeArguments) {
+    _typeArguments = _becomeParentOf(typeArguments);
+  }
+}
+
+/**
+ * An is expression.
+ *
+ *    isExpression ::=
+ *        [Expression] 'is' '!'? [TypeName]
+ */
+class IsExpressionImpl extends ExpressionImpl implements IsExpression {
+  /**
+   * The expression used to compute the value whose type is being tested.
+   */
+  Expression _expression;
+
+  /**
+   * The is operator.
+   */
+  @override
+  Token isOperator;
+
+  /**
+   * The not operator, or `null` if the sense of the test is not negated.
+   */
+  @override
+  Token notOperator;
+
+  /**
+   * The name of the type being tested for.
+   */
+  TypeName _type;
+
+  /**
+   * Initialize a newly created is expression. The [notOperator] can be `null`
+   * if the sense of the test is not negated.
+   */
+  IsExpressionImpl(
+      Expression expression, this.isOperator, this.notOperator, TypeName type) {
+    _expression = _becomeParentOf(expression);
+    _type = _becomeParentOf(type);
+  }
+
+  @override
+  Token get beginToken => _expression.beginToken;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(_expression)
+    ..add(isOperator)
+    ..add(notOperator)
+    ..add(_type);
+
+  @override
+  Token get endToken => _type.endToken;
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 7;
+
+  @override
+  TypeName get type => _type;
+
+  @override
+  void set type(TypeName name) {
+    _type = _becomeParentOf(name);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitIsExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+    _safelyVisitChild(_type, visitor);
+  }
+}
+
+/**
+ * A statement that has a label associated with them.
+ *
+ *    labeledStatement ::=
+ *       [Label]+ [Statement]
+ */
+class LabeledStatementImpl extends StatementImpl implements LabeledStatement {
+  /**
+   * The labels being associated with the statement.
+   */
+  NodeList<Label> _labels;
+
+  /**
+   * The statement with which the labels are being associated.
+   */
+  Statement _statement;
+
+  /**
+   * Initialize a newly created labeled statement.
+   */
+  LabeledStatementImpl(List<Label> labels, Statement statement) {
+    _labels = new NodeList<Label>(this, labels);
+    _statement = _becomeParentOf(statement);
+  }
+
+  @override
+  Token get beginToken {
+    if (!_labels.isEmpty) {
+      return _labels.beginToken;
+    }
+    return _statement.beginToken;
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..addAll(_labels)
+    ..add(_statement);
+
+  @override
+  Token get endToken => _statement.endToken;
+
+  @override
+  NodeList<Label> get labels => _labels;
+
+  @override
+  Statement get statement => _statement;
+
+  @override
+  void set statement(Statement statement) {
+    _statement = _becomeParentOf(statement);
+  }
+
+  @override
+  Statement get unlabeled => _statement.unlabeled;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitLabeledStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _labels.accept(visitor);
+    _safelyVisitChild(_statement, visitor);
+  }
+}
+
+/**
+ * A label on either a [LabeledStatement] or a [NamedExpression].
+ *
+ *    label ::=
+ *        [SimpleIdentifier] ':'
+ */
+class LabelImpl extends AstNodeImpl implements Label {
+  /**
+   * The label being associated with the statement.
+   */
+  SimpleIdentifier _label;
+
+  /**
+   * The colon that separates the label from the statement.
+   */
+  @override
+  Token colon;
+
+  /**
+   * Initialize a newly created label.
+   */
+  LabelImpl(SimpleIdentifier label, this.colon) {
+    _label = _becomeParentOf(label);
+  }
+
+  @override
+  Token get beginToken => _label.beginToken;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(_label)..add(colon);
+
+  @override
+  Token get endToken => colon;
+
+  @override
+  SimpleIdentifier get label => _label;
+
+  @override
+  void set label(SimpleIdentifier label) {
+    _label = _becomeParentOf(label);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitLabel(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_label, visitor);
+  }
+}
+
+/**
+ * A library directive.
+ *
+ *    libraryDirective ::=
+ *        [Annotation] 'library' [Identifier] ';'
+ */
+class LibraryDirectiveImpl extends DirectiveImpl implements LibraryDirective {
+  /**
+   * The token representing the 'library' keyword.
+   */
+  @override
+  Token libraryKeyword;
+
+  /**
+   * The name of the library being defined.
+   */
+  LibraryIdentifier _name;
+
+  /**
+   * The semicolon terminating the directive.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created library directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute.
+   */
+  LibraryDirectiveImpl(Comment comment, List<Annotation> metadata,
+      this.libraryKeyword, LibraryIdentifier name, this.semicolon)
+      : super(comment, metadata) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(libraryKeyword)..add(_name)..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
+
+  @override
+  Token get keyword => libraryKeyword;
+
+  @override
+  LibraryIdentifier get name => _name;
+
+  @override
+  void set name(LibraryIdentifier name) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitLibraryDirective(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_name, visitor);
+  }
+}
+
+/**
+ * The identifier for a library.
+ *
+ *    libraryIdentifier ::=
+ *        [SimpleIdentifier] ('.' [SimpleIdentifier])*
+ */
+class LibraryIdentifierImpl extends IdentifierImpl
+    implements LibraryIdentifier {
+  /**
+   * The components of the identifier.
+   */
+  NodeList<SimpleIdentifier> _components;
+
+  /**
+   * Initialize a newly created prefixed identifier.
+   */
+  LibraryIdentifierImpl(List<SimpleIdentifier> components) {
+    _components = new NodeList<SimpleIdentifier>(this, components);
+  }
+
+  @override
+  Token get beginToken => _components.beginToken;
+
+  @override
+  Element get bestElement => staticElement;
+
+  @override
+  // TODO(paulberry): add "." tokens.
+  Iterable get childEntities => new ChildEntities()..addAll(_components);
+
+  @override
+  NodeList<SimpleIdentifier> get components => _components;
+
+  @override
+  Token get endToken => _components.endToken;
+
+  @override
+  String get name {
+    StringBuffer buffer = new StringBuffer();
+    bool needsPeriod = false;
+    for (SimpleIdentifier identifier in _components) {
+      if (needsPeriod) {
+        buffer.write(".");
+      } else {
+        needsPeriod = true;
+      }
+      buffer.write(identifier.name);
+    }
+    return buffer.toString();
+  }
+
+  @override
+  int get precedence => 15;
+
+  @override
+  Element get propagatedElement => null;
+
+  @override
+  Element get staticElement => null;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitLibraryIdentifier(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _components.accept(visitor);
+  }
+}
+
+/**
+ * A list literal.
+ *
+ *    listLiteral ::=
+ *        'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
+ */
+class ListLiteralImpl extends TypedLiteralImpl implements ListLiteral {
+  /**
+   * The left square bracket.
+   */
+  @override
+  Token leftBracket;
+
+  /**
+   * The expressions used to compute the elements of the list.
+   */
+  NodeList<Expression> _elements;
+
+  /**
+   * The right square bracket.
+   */
+  @override
+  Token rightBracket;
+
+  /**
+   * Initialize a newly created list literal. The [constKeyword] can be `null`
+   * if the literal is not a constant. The [typeArguments] can be `null` if no
+   * type arguments were declared. The list of [elements] can be `null` if the
+   * list is empty.
+   */
+  ListLiteralImpl(Token constKeyword, TypeArgumentList typeArguments,
+      this.leftBracket, List<Expression> elements, this.rightBracket)
+      : super(constKeyword, typeArguments) {
+    _elements = new NodeList<Expression>(this, elements);
+  }
+
+  @override
+  Token get beginToken {
+    if (constKeyword != null) {
+      return constKeyword;
+    }
+    TypeArgumentList typeArguments = this.typeArguments;
+    if (typeArguments != null) {
+      return typeArguments.beginToken;
+    }
+    return leftBracket;
+  }
+
+  @override
+  // TODO(paulberry): add commas.
+  Iterable get childEntities => super._childEntities
+    ..add(leftBracket)
+    ..addAll(_elements)
+    ..add(rightBracket);
+
+  @override
+  NodeList<Expression> get elements => _elements;
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitListLiteral(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _elements.accept(visitor);
+  }
+}
+
+/**
+ * A node that represents a literal expression.
+ *
+ *    literal ::=
+ *        [BooleanLiteral]
+ *      | [DoubleLiteral]
+ *      | [IntegerLiteral]
+ *      | [ListLiteral]
+ *      | [MapLiteral]
+ *      | [NullLiteral]
+ *      | [StringLiteral]
+ */
+abstract class LiteralImpl extends ExpressionImpl implements Literal {
+  @override
+  int get precedence => 16;
+}
+
+/**
+ * Additional information about local variables within a function or method
+ * produced at resolution time.
+ */
+class LocalVariableInfo {
+  /**
+   * The set of local variables and parameters that are potentially mutated
+   * within a local function other than the function in which they are declared.
+   */
+  final Set<VariableElement> potentiallyMutatedInClosure =
+      new Set<VariableElement>();
+
+  /**
+   * The set of local variables and parameters that are potentiall mutated
+   * within the scope of their declarations.
+   */
+  final Set<VariableElement> potentiallyMutatedInScope =
+      new Set<VariableElement>();
+}
+
+/**
+ * A single key/value pair in a map literal.
+ *
+ *    mapLiteralEntry ::=
+ *        [Expression] ':' [Expression]
+ */
+class MapLiteralEntryImpl extends AstNodeImpl implements MapLiteralEntry {
+  /**
+   * The expression computing the key with which the value will be associated.
+   */
+  Expression _key;
+
+  /**
+   * The colon that separates the key from the value.
+   */
+  @override
+  Token separator;
+
+  /**
+   * The expression computing the value that will be associated with the key.
+   */
+  Expression _value;
+
+  /**
+   * Initialize a newly created map literal entry.
+   */
+  MapLiteralEntryImpl(Expression key, this.separator, Expression value) {
+    _key = _becomeParentOf(key);
+    _value = _becomeParentOf(value);
+  }
+
+  @override
+  Token get beginToken => _key.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_key)..add(separator)..add(_value);
+
+  @override
+  Token get endToken => _value.endToken;
+
+  @override
+  Expression get key => _key;
+
+  @override
+  void set key(Expression string) {
+    _key = _becomeParentOf(string);
+  }
+
+  @override
+  Expression get value => _value;
+
+  @override
+  void set value(Expression expression) {
+    _value = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitMapLiteralEntry(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_key, visitor);
+    _safelyVisitChild(_value, visitor);
+  }
+}
+
+/**
+ * A literal map.
+ *
+ *    mapLiteral ::=
+ *        'const'? ('<' [TypeName] (',' [TypeName])* '>')?
+ *        '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
+ */
+class MapLiteralImpl extends TypedLiteralImpl implements MapLiteral {
+  /**
+   * The left curly bracket.
+   */
+  @override
+  Token leftBracket;
+
+  /**
+   * The entries in the map.
+   */
+  NodeList<MapLiteralEntry> _entries;
+
+  /**
+   * The right curly bracket.
+   */
+  @override
+  Token rightBracket;
+
+  /**
+   * Initialize a newly created map literal. The [constKeyword] can be `null` if
+   * the literal is not a constant. The [typeArguments] can be `null` if no type
+   * arguments were declared. The [entries] can be `null` if the map is empty.
+   */
+  MapLiteralImpl(Token constKeyword, TypeArgumentList typeArguments,
+      this.leftBracket, List<MapLiteralEntry> entries, this.rightBracket)
+      : super(constKeyword, typeArguments) {
+    _entries = new NodeList<MapLiteralEntry>(this, entries);
+  }
+
+  @override
+  Token get beginToken {
+    if (constKeyword != null) {
+      return constKeyword;
+    }
+    TypeArgumentList typeArguments = this.typeArguments;
+    if (typeArguments != null) {
+      return typeArguments.beginToken;
+    }
+    return leftBracket;
+  }
+
+  @override
+  // TODO(paulberry): add commas.
+  Iterable get childEntities => super._childEntities
+    ..add(leftBracket)
+    ..addAll(entries)
+    ..add(rightBracket);
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  NodeList<MapLiteralEntry> get entries => _entries;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitMapLiteral(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _entries.accept(visitor);
+  }
+}
+
+/**
+ * A method declaration.
+ *
+ *    methodDeclaration ::=
+ *        methodSignature [FunctionBody]
+ *
+ *    methodSignature ::=
+ *        'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
+ *        methodName [TypeParameterList] [FormalParameterList]
+ *
+ *    methodName ::=
+ *        [SimpleIdentifier]
+ *      | 'operator' [SimpleIdentifier]
+ */
+class MethodDeclarationImpl extends ClassMemberImpl
+    implements MethodDeclaration {
+  /**
+   * 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;
+
+  /**
+   * The return type of the method, or `null` if no return type was declared.
+   */
+  TypeName _returnType;
+
+  /**
+   * 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;
+
+  /**
+   * The name of the method.
+   */
+  SimpleIdentifier _name;
+
+  /**
+   * The type parameters associated with the method, or `null` if the method is
+   * not a generic method.
+   */
+  TypeParameterList _typeParameters;
+
+  /**
+   * The parameters associated with the method, or `null` if this method
+   * declares a getter.
+   */
+  FormalParameterList _parameters;
+
+  /**
+   * The body of the method.
+   */
+  FunctionBody _body;
+
+  /**
+   * Initialize a newly created method declaration. Either or both of the
+   * [comment] and [metadata] can be `null` if the declaration does not have the
+   * corresponding attribute. The [externalKeyword] can be `null` if the method
+   * is not external. The [modifierKeyword] can be `null` if the method is
+   * neither abstract nor static. The [returnType] can be `null` if no return
+   * type was specified. The [propertyKeyword] can be `null` if the method is
+   * neither a getter or a setter. The [operatorKeyword] can be `null` if the
+   * method does not implement an operator. The [parameters] must be `null` if
+   * this method declares a getter.
+   */
+  MethodDeclarationImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      this.externalKeyword,
+      this.modifierKeyword,
+      TypeName returnType,
+      this.propertyKeyword,
+      this.operatorKeyword,
+      SimpleIdentifier name,
+      TypeParameterList typeParameters,
+      FormalParameterList parameters,
+      FunctionBody body)
+      : super(comment, metadata) {
+    _returnType = _becomeParentOf(returnType);
+    _name = _becomeParentOf(name);
+    _typeParameters = _becomeParentOf(typeParameters);
+    _parameters = _becomeParentOf(parameters);
+    _body = _becomeParentOf(body);
+  }
+
+  @override
+  FunctionBody get body => _body;
+
+  @override
+  void set body(FunctionBody functionBody) {
+    _body = _becomeParentOf(functionBody);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(externalKeyword)
+    ..add(modifierKeyword)
+    ..add(_returnType)
+    ..add(propertyKeyword)
+    ..add(operatorKeyword)
+    ..add(_name)
+    ..add(_parameters)
+    ..add(_body);
+
+  /**
+   * Return the element associated with this method, or `null` if the AST
+   * structure has not been resolved. The element can either be a
+   * [MethodElement], if this represents the declaration of a normal method, or
+   * a [PropertyAccessorElement] if this represents the declaration of either a
+   * getter or a setter.
+   */
+  @override
+  ExecutableElement get element =>
+      _name != null ? (_name.staticElement as ExecutableElement) : null;
+
+  @override
+  Token get endToken => _body.endToken;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata {
+    if (modifierKeyword != null) {
+      return modifierKeyword;
+    } else if (_returnType != null) {
+      return _returnType.beginToken;
+    } else if (propertyKeyword != null) {
+      return propertyKeyword;
+    } else if (operatorKeyword != null) {
+      return operatorKeyword;
+    }
+    return _name.beginToken;
+  }
+
+  @override
+  bool get isAbstract {
+    FunctionBody body = _body;
+    return externalKeyword == null &&
+        (body is EmptyFunctionBody && !body.semicolon.isSynthetic);
+  }
+
+  @override
+  bool get isGetter =>
+      propertyKeyword != null &&
+      (propertyKeyword as KeywordToken).keyword == Keyword.GET;
+
+  @override
+  bool get isOperator => operatorKeyword != null;
+
+  @override
+  bool get isSetter =>
+      propertyKeyword != null &&
+      (propertyKeyword as KeywordToken).keyword == Keyword.SET;
+
+  @override
+  bool get isStatic =>
+      modifierKeyword != null &&
+      (modifierKeyword as KeywordToken).keyword == Keyword.STATIC;
+
+  @override
+  SimpleIdentifier get name => _name;
+
+  @override
+  void set name(SimpleIdentifier identifier) {
+    _name = _becomeParentOf(identifier);
+  }
+
+  @override
+  FormalParameterList get parameters => _parameters;
+
+  @override
+  void set parameters(FormalParameterList parameters) {
+    _parameters = _becomeParentOf(parameters);
+  }
+
+  @override
+  TypeName get returnType => _returnType;
+
+  @override
+  void set returnType(TypeName typeName) {
+    _returnType = _becomeParentOf(typeName);
+  }
+
+  @override
+  TypeParameterList get typeParameters => _typeParameters;
+
+  @override
+  void set typeParameters(TypeParameterList typeParameters) {
+    _typeParameters = _becomeParentOf(typeParameters);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitMethodDeclaration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_returnType, visitor);
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_typeParameters, visitor);
+    _safelyVisitChild(_parameters, visitor);
+    _safelyVisitChild(_body, visitor);
+  }
+}
+
+/**
+ * The invocation of either a function or a method. Invocations of functions
+ * resulting from evaluating an expression are represented by
+ * [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
+ * represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
+ *
+ *    methodInvocation ::=
+ *        ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
+ */
+class MethodInvocationImpl extends InvocationExpressionImpl
+    implements MethodInvocation {
+  /**
+   * The expression producing the object on which the method is defined, or
+   * `null` if there is no target (that is, the target is implicitly `this`).
+   */
+  Expression _target;
+
+  /**
+   * The operator that separates the target from the method name, or `null`
+   * if there is no target. In an ordinary method invocation this will be a
+   * period ('.'). In a cascade section this will be the cascade operator
+   * ('..').
+   */
+  @override
+  Token operator;
+
+  /**
+   * The name of the method being invoked.
+   */
+  SimpleIdentifier _methodName;
+
+  /**
+   * Initialize a newly created method invocation. The [target] and [operator]
+   * can be `null` if there is no target.
+   */
+  MethodInvocationImpl(
+      Expression target,
+      this.operator,
+      SimpleIdentifier methodName,
+      TypeArgumentList typeArguments,
+      ArgumentList argumentList)
+      : super(typeArguments, argumentList) {
+    _target = _becomeParentOf(target);
+    _methodName = _becomeParentOf(methodName);
+  }
+
+  @override
+  Token get beginToken {
+    if (_target != null) {
+      return _target.beginToken;
+    } else if (operator != null) {
+      return operator;
+    }
+    return _methodName.beginToken;
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(_target)
+    ..add(operator)
+    ..add(_methodName)
+    ..add(_argumentList);
+
+  @override
+  Token get endToken => _argumentList.endToken;
+
+  @override
+  Expression get function => methodName;
+
+  @override
+  bool get isCascaded =>
+      operator != null && operator.type == TokenType.PERIOD_PERIOD;
+
+  @override
+  SimpleIdentifier get methodName => _methodName;
+
+  @override
+  void set methodName(SimpleIdentifier identifier) {
+    _methodName = _becomeParentOf(identifier);
+  }
+
+  @override
+  int get precedence => 15;
+
+  @override
+  Expression get realTarget {
+    if (isCascaded) {
+      AstNode ancestor = parent;
+      while (ancestor is! CascadeExpression) {
+        if (ancestor == null) {
+          return _target;
+        }
+        ancestor = ancestor.parent;
+      }
+      return (ancestor as CascadeExpression).target;
+    }
+    return _target;
+  }
+
+  @override
+  Expression get target => _target;
+
+  @override
+  void set target(Expression expression) {
+    _target = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitMethodInvocation(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_target, visitor);
+    _safelyVisitChild(_methodName, visitor);
+    _safelyVisitChild(_typeArguments, visitor);
+    _safelyVisitChild(_argumentList, visitor);
+  }
+}
+
+/**
+ * A node that declares a single name within the scope of a compilation unit.
+ */
+abstract class NamedCompilationUnitMemberImpl extends CompilationUnitMemberImpl
+    implements NamedCompilationUnitMember {
+  /**
+   * The name of the member being declared.
+   */
+  SimpleIdentifier _name;
+
+  /**
+   * Initialize a newly created compilation unit member with the given [name].
+   * Either or both of the [comment] and [metadata] can be `null` if the member
+   * does not have the corresponding attribute.
+   */
+  NamedCompilationUnitMemberImpl(
+      Comment comment, List<Annotation> metadata, SimpleIdentifier name)
+      : super(comment, metadata) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  SimpleIdentifier get name => _name;
+
+  @override
+  void set name(SimpleIdentifier identifier) {
+    _name = _becomeParentOf(identifier);
+  }
+}
+
+/**
+ * An expression that has a name associated with it. They are used in method
+ * invocations when there are named parameters.
+ *
+ *    namedExpression ::=
+ *        [Label] [Expression]
+ */
+class NamedExpressionImpl extends ExpressionImpl implements NamedExpression {
+  /**
+   * The name associated with the expression.
+   */
+  Label _name;
+
+  /**
+   * The expression with which the name is associated.
+   */
+  Expression _expression;
+
+  /**
+   * Initialize a newly created named expression..
+   */
+  NamedExpressionImpl(Label name, Expression expression) {
+    _name = _becomeParentOf(name);
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken => _name.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_name)..add(_expression);
+
+  @override
+  ParameterElement get element {
+    Element element = _name.label.staticElement;
+    if (element is ParameterElement) {
+      return element;
+    }
+    return null;
+  }
+
+  @override
+  Token get endToken => _expression.endToken;
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Label get name => _name;
+
+  @override
+  void set name(Label identifier) {
+    _name = _becomeParentOf(identifier);
+  }
+
+  @override
+  int get precedence => 0;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitNamedExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * A node that represents a directive that impacts the namespace of a library.
+ *
+ *    directive ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ */
+abstract class NamespaceDirectiveImpl extends UriBasedDirectiveImpl
+    implements NamespaceDirective {
+  /**
+   * The token representing the 'import' or 'export' keyword.
+   */
+  @override
+  Token keyword;
+
+  /**
+   * The configurations used to control which library will actually be loaded at
+   * run-time.
+   */
+  NodeList<Configuration> _configurations;
+
+  /**
+   * The combinators used to control which names are imported or exported.
+   */
+  NodeList<Combinator> _combinators;
+
+  /**
+   * The semicolon terminating the directive.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created namespace directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute. The list of [combinators] can be `null` if there
+   * are no combinators.
+   */
+  NamespaceDirectiveImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      this.keyword,
+      StringLiteral libraryUri,
+      List<Configuration> configurations,
+      List<Combinator> combinators,
+      this.semicolon)
+      : super(comment, metadata, libraryUri) {
+    _configurations = new NodeList<Configuration>(this, configurations);
+    _combinators = new NodeList<Combinator>(this, combinators);
+  }
+
+  @override
+  NodeList<Combinator> get combinators => _combinators;
+
+  @override
+  NodeList<Configuration> get configurations => _configurations;
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => keyword;
+
+  @override
+  LibraryElement get uriElement;
+}
+
+/**
+ * The "native" clause in an class declaration.
+ *
+ *    nativeClause ::=
+ *        'native' [StringLiteral]
+ */
+class NativeClauseImpl extends AstNodeImpl implements NativeClause {
+  /**
+   * The token representing the 'native' keyword.
+   */
+  @override
+  Token nativeKeyword;
+
+  /**
+   * The name of the native object that implements the class.
+   */
+  StringLiteral _name;
+
+  /**
+   * Initialize a newly created native clause.
+   */
+  NativeClauseImpl(this.nativeKeyword, StringLiteral name) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  Token get beginToken => nativeKeyword;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(nativeKeyword)..add(_name);
+
+  @override
+  Token get endToken => _name.endToken;
+
+  @override
+  StringLiteral get name => _name;
+
+  @override
+  void set name(StringLiteral name) {
+    _name = _becomeParentOf(name);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitNativeClause(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_name, visitor);
+  }
+}
+
+/**
+ * A function body that consists of a native keyword followed by a string
+ * literal.
+ *
+ *    nativeFunctionBody ::=
+ *        'native' [SimpleStringLiteral] ';'
+ */
+class NativeFunctionBodyImpl extends FunctionBodyImpl
+    implements NativeFunctionBody {
+  /**
+   * The token representing 'native' that marks the start of the function body.
+   */
+  @override
+  Token nativeKeyword;
+
+  /**
+   * The string literal, after the 'native' token.
+   */
+  StringLiteral _stringLiteral;
+
+  /**
+   * The token representing the semicolon that marks the end of the function
+   * body.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created function body consisting of the 'native' token,
+   * a string literal, and a semicolon.
+   */
+  NativeFunctionBodyImpl(
+      this.nativeKeyword, StringLiteral stringLiteral, this.semicolon) {
+    _stringLiteral = _becomeParentOf(stringLiteral);
+  }
+
+  @override
+  Token get beginToken => nativeKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(nativeKeyword)
+    ..add(_stringLiteral)
+    ..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  StringLiteral get stringLiteral => _stringLiteral;
+
+  @override
+  void set stringLiteral(StringLiteral stringLiteral) {
+    _stringLiteral = _becomeParentOf(stringLiteral);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitNativeFunctionBody(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_stringLiteral, visitor);
+  }
+}
+
+/**
+ * A list of AST nodes that have a common parent.
+ */
+class NodeListImpl<E extends AstNode> extends Object
+    with ListMixin<E>
+    implements NodeList<E> {
+  /**
+   * The node that is the parent of each of the elements in the list.
+   */
+  @override
+  AstNodeImpl owner;
+
+  /**
+   * The elements contained in the list.
+   */
+  List<E> _elements = <E>[];
+
+  /**
+   * Initialize a newly created list of nodes such that all of the nodes that
+   * are added to the list will have their parent set to the given [owner]. The
+   * list will initially be populated with the given [elements].
+   */
+  NodeListImpl(this.owner, [List<E> elements]) {
+    addAll(elements);
+  }
+
+  @override
+  Token get beginToken {
+    if (_elements.length == 0) {
+      return null;
+    }
+    return _elements[0].beginToken;
+  }
+
+  @override
+  Token get endToken {
+    int length = _elements.length;
+    if (length == 0) {
+      return null;
+    }
+    return _elements[length - 1].endToken;
+  }
+
+  int get length => _elements.length;
+
+  @deprecated // Never intended for public use.
+  @override
+  void set length(int newLength) {
+    throw new UnsupportedError("Cannot resize NodeList.");
+  }
+
+  E operator [](int index) {
+    if (index < 0 || index >= _elements.length) {
+      throw new RangeError("Index: $index, Size: ${_elements.length}");
+    }
+    return _elements[index];
+  }
+
+  void operator []=(int index, E node) {
+    if (index < 0 || index >= _elements.length) {
+      throw new RangeError("Index: $index, Size: ${_elements.length}");
+    }
+    owner._becomeParentOf(node);
+    _elements[index] = node;
+  }
+
+  @override
+  accept(AstVisitor visitor) {
+    int length = _elements.length;
+    for (var i = 0; i < length; i++) {
+      _elements[i].accept(visitor);
+    }
+  }
+
+  @override
+  void add(E node) {
+    insert(length, node);
+  }
+
+  @override
+  bool addAll(Iterable<E> nodes) {
+    if (nodes != null && !nodes.isEmpty) {
+      _elements.addAll(nodes);
+      for (E node in nodes) {
+        owner._becomeParentOf(node);
+      }
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  void clear() {
+    _elements = <E>[];
+  }
+
+  @override
+  void insert(int index, E node) {
+    int length = _elements.length;
+    if (index < 0 || index > length) {
+      throw new RangeError("Index: $index, Size: ${_elements.length}");
+    }
+    owner._becomeParentOf(node);
+    if (length == 0) {
+      _elements.add(node);
+    } else {
+      _elements.insert(index, node);
+    }
+  }
+
+  @override
+  E removeAt(int index) {
+    if (index < 0 || index >= _elements.length) {
+      throw new RangeError("Index: $index, Size: ${_elements.length}");
+    }
+    E removedNode = _elements[index];
+    _elements.removeAt(index);
+    return removedNode;
+  }
+}
+
+/**
+ * A formal parameter that is required (is not optional).
+ *
+ *    normalFormalParameter ::=
+ *        [FunctionTypedFormalParameter]
+ *      | [FieldFormalParameter]
+ *      | [SimpleFormalParameter]
+ */
+abstract class NormalFormalParameterImpl extends FormalParameterImpl
+    implements NormalFormalParameter {
+  /**
+   * The documentation comment associated with this parameter, or `null` if this
+   * parameter does not have a documentation comment associated with it.
+   */
+  Comment _comment;
+
+  /**
+   * The annotations associated with this parameter.
+   */
+  NodeList<Annotation> _metadata;
+
+  /**
+   * The name of the parameter being declared.
+   */
+  SimpleIdentifier _identifier;
+
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute.
+   */
+  NormalFormalParameterImpl(
+      Comment comment, List<Annotation> metadata, SimpleIdentifier identifier) {
+    _comment = _becomeParentOf(comment);
+    _metadata = new NodeList<Annotation>(this, metadata);
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  Comment get documentationComment => _comment;
+
+  @override
+  void set documentationComment(Comment comment) {
+    _comment = _becomeParentOf(comment);
+  }
+
+  @override
+  SimpleIdentifier get identifier => _identifier;
+
+  @override
+  void set identifier(SimpleIdentifier identifier) {
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  ParameterKind get kind {
+    AstNode parent = this.parent;
+    if (parent is DefaultFormalParameter) {
+      return parent.kind;
+    }
+    return ParameterKind.REQUIRED;
+  }
+
+  @override
+  NodeList<Annotation> get metadata => _metadata;
+
+  @override
+  void set metadata(List<Annotation> metadata) {
+    _metadata.clear();
+    _metadata.addAll(metadata);
+  }
+
+  @override
+  List<AstNode> get sortedCommentAndAnnotations {
+    return <AstNode>[]
+      ..add(_comment)
+      ..addAll(_metadata)
+      ..sort(AstNode.LEXICAL_ORDER);
+  }
+
+  ChildEntities get _childEntities {
+    ChildEntities result = new ChildEntities();
+    if (_commentIsBeforeAnnotations()) {
+      result
+        ..add(_comment)
+        ..addAll(_metadata);
+    } else {
+      result.addAll(sortedCommentAndAnnotations);
+    }
+    return result;
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    //
+    // Note that subclasses are responsible for visiting the identifier because
+    // they often need to visit other nodes before visiting the identifier.
+    //
+    if (_commentIsBeforeAnnotations()) {
+      _safelyVisitChild(_comment, visitor);
+      _metadata.accept(visitor);
+    } else {
+      for (AstNode child in sortedCommentAndAnnotations) {
+        child.accept(visitor);
+      }
+    }
+  }
+
+  /**
+   * Return `true` if the comment is lexically before any annotations.
+   */
+  bool _commentIsBeforeAnnotations() {
+    if (_comment == null || _metadata.isEmpty) {
+      return true;
+    }
+    Annotation firstAnnotation = _metadata[0];
+    return _comment.offset < firstAnnotation.offset;
+  }
+}
+
+/**
+ * A null literal expression.
+ *
+ *    nullLiteral ::=
+ *        'null'
+ */
+class NullLiteralImpl extends LiteralImpl implements NullLiteral {
+  /**
+   * The token representing the literal.
+   */
+  Token literal;
+
+  /**
+   * Initialize a newly created null literal.
+   */
+  NullLiteralImpl(this.literal);
+
+  @override
+  Token get beginToken => literal;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(literal);
+
+  @override
+  Token get endToken => literal;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitNullLiteral(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * A parenthesized expression.
+ *
+ *    parenthesizedExpression ::=
+ *        '(' [Expression] ')'
+ */
+class ParenthesizedExpressionImpl extends ExpressionImpl
+    implements ParenthesizedExpression {
+  /**
+   * The left parenthesis.
+   */
+  Token leftParenthesis;
+
+  /**
+   * The expression within the parentheses.
+   */
+  Expression _expression;
+
+  /**
+   * The right parenthesis.
+   */
+  Token rightParenthesis;
+
+  /**
+   * Initialize a newly created parenthesized expression.
+   */
+  ParenthesizedExpressionImpl(
+      this.leftParenthesis, Expression expression, this.rightParenthesis) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken => leftParenthesis;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(leftParenthesis)
+    ..add(_expression)
+    ..add(rightParenthesis);
+
+  @override
+  Token get endToken => rightParenthesis;
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 15;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitParenthesizedExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * A part directive.
+ *
+ *    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;
+
+  /**
+   * Initialize a newly created part directive. Either or both of the [comment]
+   * and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute.
+   */
+  PartDirectiveImpl(Comment comment, List<Annotation> metadata,
+      this.partKeyword, StringLiteral partUri, this.semicolon)
+      : super(comment, metadata, partUri);
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(partKeyword)..add(_uri)..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => partKeyword;
+
+  @override
+  Token get keyword => partKeyword;
+
+  @override
+  CompilationUnitElement get uriElement => element as CompilationUnitElement;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitPartDirective(this);
+}
+
+/**
+ * A part-of directive.
+ *
+ *    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;
+
+  /**
+   * The name of the library that the containing compilation unit is part of.
+   */
+  LibraryIdentifier _libraryName;
+
+  /**
+   * The semicolon terminating the directive.
+   */
+  @override
+  Token semicolon;
+
+  /**
+   * Initialize a newly created part-of directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute.
+   */
+  PartOfDirectiveImpl(
+      Comment comment,
+      List<Annotation> metadata,
+      this.partKeyword,
+      this.ofKeyword,
+      LibraryIdentifier libraryName,
+      this.semicolon)
+      : super(comment, metadata) {
+    _libraryName = _becomeParentOf(libraryName);
+  }
+
+  @override
+  Iterable get childEntities => super._childEntities
+    ..add(partKeyword)
+    ..add(ofKeyword)
+    ..add(_libraryName)
+    ..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => partKeyword;
+
+  @override
+  Token get keyword => partKeyword;
+
+  @override
+  LibraryIdentifier get libraryName => _libraryName;
+
+  @override
+  void set libraryName(LibraryIdentifier libraryName) {
+    _libraryName = _becomeParentOf(libraryName);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitPartOfDirective(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_libraryName, visitor);
+  }
+}
+
+/**
+ * A postfix unary expression.
+ *
+ *    postfixExpression ::=
+ *        [Expression] [Token]
+ */
+class PostfixExpressionImpl extends ExpressionImpl
+    implements PostfixExpression {
+  /**
+   * The expression computing the operand for the operator.
+   */
+  Expression _operand;
+
+  /**
+   * The postfix operator being applied to the operand.
+   */
+  @override
+  Token operator;
+
+  /**
+   * The element associated with this the operator based on the propagated type
+   * of the 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 propagatedElement;
+
+  /**
+   * The element associated with the operator based on the static type of the
+   * 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;
+
+  /**
+   * Initialize a newly created postfix expression.
+   */
+  PostfixExpressionImpl(Expression operand, this.operator) {
+    _operand = _becomeParentOf(operand);
+  }
+
+  @override
+  Token get beginToken => _operand.beginToken;
+
+  @override
+  MethodElement get bestElement {
+    MethodElement element = propagatedElement;
+    if (element == null) {
+      element = staticElement;
+    }
+    return element;
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_operand)..add(operator);
+
+  @override
+  Token get endToken => operator;
+
+  @override
+  Expression get operand => _operand;
+
+  @override
+  void set operand(Expression expression) {
+    _operand = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 15;
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on propagated type information, then return the parameter
+   * element representing the parameter to which the value of the operand will
+   * be bound. Otherwise, return `null`.
+   */
+  ParameterElement get _propagatedParameterElementForOperand {
+    if (propagatedElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = propagatedElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on static type information, then return the parameter element
+   * representing the parameter to which the value of the operand will be bound.
+   * Otherwise, return `null`.
+   */
+  ParameterElement get _staticParameterElementForOperand {
+    if (staticElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = staticElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitPostfixExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_operand, visitor);
+  }
+}
+
+/**
+ * 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]
+ */
+class PrefixedIdentifierImpl extends IdentifierImpl
+    implements PrefixedIdentifier {
+  /**
+   * The prefix associated with the library in which the identifier is defined.
+   */
+  SimpleIdentifier _prefix;
+
+  /**
+   * The period used to separate the prefix from the identifier.
+   */
+  Token period;
+
+  /**
+   * The identifier being prefixed.
+   */
+  SimpleIdentifier _identifier;
+
+  /**
+   * Initialize a newly created prefixed identifier.
+   */
+  PrefixedIdentifierImpl(
+      SimpleIdentifier prefix, this.period, SimpleIdentifier identifier) {
+    _prefix = _becomeParentOf(prefix);
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  Token get beginToken => _prefix.beginToken;
+
+  @override
+  Element get bestElement {
+    if (_identifier == null) {
+      return null;
+    }
+    return _identifier.bestElement;
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_prefix)..add(period)..add(_identifier);
+
+  @override
+  Token get endToken => _identifier.endToken;
+
+  @override
+  SimpleIdentifier get identifier => _identifier;
+
+  @override
+  void set identifier(SimpleIdentifier identifier) {
+    _identifier = _becomeParentOf(identifier);
+  }
+
+  @override
+  bool get isDeferred {
+    Element element = _prefix.staticElement;
+    if (element is! PrefixElement) {
+      return false;
+    }
+    PrefixElement prefixElement = element as PrefixElement;
+    List<ImportElement> imports =
+        prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
+    if (imports.length != 1) {
+      return false;
+    }
+    return imports[0].isDeferred;
+  }
+
+  @override
+  String get name => "${_prefix.name}.${_identifier.name}";
+
+  @override
+  int get precedence => 15;
+
+  @override
+  SimpleIdentifier get prefix => _prefix;
+
+  @override
+  void set prefix(SimpleIdentifier identifier) {
+    _prefix = _becomeParentOf(identifier);
+  }
+
+  @override
+  Element get propagatedElement {
+    if (_identifier == null) {
+      return null;
+    }
+    return _identifier.propagatedElement;
+  }
+
+  @override
+  Element get staticElement {
+    if (_identifier == null) {
+      return null;
+    }
+    return _identifier.staticElement;
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitPrefixedIdentifier(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_prefix, visitor);
+    _safelyVisitChild(_identifier, visitor);
+  }
+}
+
+/**
+ * A prefix unary expression.
+ *
+ *    prefixExpression ::=
+ *        [Token] [Expression]
+ */
+class PrefixExpressionImpl extends ExpressionImpl implements PrefixExpression {
+  /**
+   * The prefix operator being applied to the operand.
+   */
+  Token operator;
+
+  /**
+   * The expression computing the operand for the operator.
+   */
+  Expression _operand;
+
+  /**
+   * The element associated with the operator based on the static type of the
+   * 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.
+   */
+  MethodElement staticElement;
+
+  /**
+   * The element associated with the operator based on the propagated type of
+   * the 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.
+   */
+  MethodElement propagatedElement;
+
+  /**
+   * Initialize a newly created prefix expression.
+   */
+  PrefixExpressionImpl(this.operator, Expression operand) {
+    _operand = _becomeParentOf(operand);
+  }
+
+  @override
+  Token get beginToken => operator;
+
+  @override
+  MethodElement get bestElement {
+    MethodElement element = propagatedElement;
+    if (element == null) {
+      element = staticElement;
+    }
+    return element;
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(operator)..add(_operand);
+
+  @override
+  Token get endToken => _operand.endToken;
+
+  @override
+  Expression get operand => _operand;
+
+  @override
+  void set operand(Expression expression) {
+    _operand = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 14;
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on propagated type information, then return the parameter
+   * element representing the parameter to which the value of the operand will
+   * be bound. Otherwise, return `null`.
+   */
+  ParameterElement get _propagatedParameterElementForOperand {
+    if (propagatedElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = propagatedElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  /**
+   * If the AST structure has been resolved, and the function being invoked is
+   * known based on static type information, then return the parameter element
+   * representing the parameter to which the value of the operand will be bound.
+   * Otherwise, return `null`.
+   */
+  ParameterElement get _staticParameterElementForOperand {
+    if (staticElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = staticElement.parameters;
+    if (parameters.length < 1) {
+      return null;
+    }
+    return parameters[0];
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitPrefixExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_operand, visitor);
+  }
+}
+
+/**
+ * The access of a property of an object.
+ *
+ * Note, however, that accesses to properties of objects can also be represented
+ * as [PrefixedIdentifier] nodes in cases where the target is also a simple
+ * identifier.
+ *
+ *    propertyAccess ::=
+ *        [Expression] '.' [SimpleIdentifier]
+ */
+class PropertyAccessImpl extends ExpressionImpl implements PropertyAccess {
+  /**
+   * The expression computing the object defining the property being accessed.
+   */
+  Expression _target;
+
+  /**
+   * The property access operator.
+   */
+  Token operator;
+
+  /**
+   * The name of the property being accessed.
+   */
+  SimpleIdentifier _propertyName;
+
+  /**
+   * Initialize a newly created property access expression.
+   */
+  PropertyAccessImpl(
+      Expression target, this.operator, SimpleIdentifier propertyName) {
+    _target = _becomeParentOf(target);
+    _propertyName = _becomeParentOf(propertyName);
+  }
+
+  @override
+  Token get beginToken {
+    if (_target != null) {
+      return _target.beginToken;
+    }
+    return operator;
+  }
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_target)..add(operator)..add(_propertyName);
+
+  @override
+  Token get endToken => _propertyName.endToken;
+
+  @override
+  bool get isAssignable => true;
+
+  @override
+  bool get isCascaded =>
+      operator != null && operator.type == TokenType.PERIOD_PERIOD;
+
+  @override
+  int get precedence => 15;
+
+  @override
+  SimpleIdentifier get propertyName => _propertyName;
+
+  @override
+  void set propertyName(SimpleIdentifier identifier) {
+    _propertyName = _becomeParentOf(identifier);
+  }
+
+  @override
+  Expression get realTarget {
+    if (isCascaded) {
+      AstNode ancestor = parent;
+      while (ancestor is! CascadeExpression) {
+        if (ancestor == null) {
+          return _target;
+        }
+        ancestor = ancestor.parent;
+      }
+      return (ancestor as CascadeExpression).target;
+    }
+    return _target;
+  }
+
+  @override
+  Expression get target => _target;
+
+  @override
+  void set target(Expression expression) {
+    _target = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitPropertyAccess(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_target, visitor);
+    _safelyVisitChild(_propertyName, visitor);
+  }
+}
+
+/**
+ * The invocation of a constructor in the same class from within a constructor's
+ * initialization list.
+ *
+ *    redirectingConstructorInvocation ::=
+ *        'this' ('.' identifier)? arguments
+ */
+class RedirectingConstructorInvocationImpl extends ConstructorInitializerImpl
+    implements RedirectingConstructorInvocation {
+  /**
+   * The token for the 'this' keyword.
+   */
+  Token thisKeyword;
+
+  /**
+   * The token for the period before the name of the constructor that is being
+   * invoked, or `null` if the unnamed constructor is being invoked.
+   */
+  Token period;
+
+  /**
+   * The name of the constructor that is being invoked, or `null` if the unnamed
+   * constructor is being invoked.
+   */
+  SimpleIdentifier _constructorName;
+
+  /**
+   * The list of arguments to the constructor.
+   */
+  ArgumentList _argumentList;
+
+  /**
+   * The element associated with the constructor based on static type
+   * information, or `null` if the AST structure has not been resolved or if the
+   * constructor could not be resolved.
+   */
+  ConstructorElement staticElement;
+
+  /**
+   * Initialize a newly created redirecting invocation to invoke the constructor
+   * with the given name with the given arguments. The [constructorName] can be
+   * `null` if the constructor being invoked is the unnamed constructor.
+   */
+  RedirectingConstructorInvocationImpl(this.thisKeyword, this.period,
+      SimpleIdentifier constructorName, ArgumentList argumentList) {
+    _constructorName = _becomeParentOf(constructorName);
+    _argumentList = _becomeParentOf(argumentList);
+  }
+
+  @override
+  ArgumentList get argumentList => _argumentList;
+
+  @override
+  void set argumentList(ArgumentList argumentList) {
+    _argumentList = _becomeParentOf(argumentList);
+  }
+
+  @override
+  Token get beginToken => thisKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(thisKeyword)
+    ..add(period)
+    ..add(_constructorName)
+    ..add(_argumentList);
+
+  @override
+  SimpleIdentifier get constructorName => _constructorName;
+
+  @override
+  void set constructorName(SimpleIdentifier identifier) {
+    _constructorName = _becomeParentOf(identifier);
+  }
+
+  @override
+  Token get endToken => _argumentList.endToken;
+
+  @override
+  accept(AstVisitor visitor) =>
+      visitor.visitRedirectingConstructorInvocation(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_constructorName, visitor);
+    _safelyVisitChild(_argumentList, visitor);
+  }
+}
+
+/**
+ * A rethrow expression.
+ *
+ *    rethrowExpression ::=
+ *        'rethrow'
+ */
+class RethrowExpressionImpl extends ExpressionImpl
+    implements RethrowExpression {
+  /**
+   * The token representing the 'rethrow' keyword.
+   */
+  Token rethrowKeyword;
+
+  /**
+   * Initialize a newly created rethrow expression.
+   */
+  RethrowExpressionImpl(this.rethrowKeyword);
+
+  @override
+  Token get beginToken => rethrowKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(rethrowKeyword);
+
+  @override
+  Token get endToken => rethrowKeyword;
+
+  @override
+  int get precedence => 0;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitRethrowExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * A return statement.
+ *
+ *    returnStatement ::=
+ *        'return' [Expression]? ';'
+ */
+class ReturnStatementImpl extends StatementImpl implements ReturnStatement {
+  /**
+   * The token representing the 'return' keyword.
+   */
+  Token returnKeyword;
+
+  /**
+   * The expression computing the value to be returned, or `null` if no explicit
+   * value was provided.
+   */
+  Expression _expression;
+
+  /**
+   * The semicolon terminating the statement.
+   */
+  Token semicolon;
+
+  /**
+   * Initialize a newly created return statement. The [expression] can be `null`
+   * if no explicit value was provided.
+   */
+  ReturnStatementImpl(
+      this.returnKeyword, Expression expression, this.semicolon) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken => returnKeyword;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(returnKeyword)..add(_expression)..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitReturnStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * A script tag that can optionally occur at the beginning of a compilation unit.
+ *
+ *    scriptTag ::=
+ *        '#!' (~NEWLINE)* NEWLINE
+ */
+class ScriptTagImpl extends AstNodeImpl implements ScriptTag {
+  /**
+   * The token representing this script tag.
+   */
+  Token scriptTag;
+
+  /**
+   * Initialize a newly created script tag.
+   */
+  ScriptTagImpl(this.scriptTag);
+
+  @override
+  Token get beginToken => scriptTag;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(scriptTag);
+
+  @override
+  Token get endToken => scriptTag;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitScriptTag(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * A combinator that restricts the names being imported to those in a given list.
+ *
+ *    showCombinator ::=
+ *        'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
+ */
+class ShowCombinatorImpl extends CombinatorImpl implements ShowCombinator {
+  /**
+   * The list of names from the library that are made visible by this combinator.
+   */
+  NodeList<SimpleIdentifier> _shownNames;
+
+  /**
+   * Initialize a newly created import show combinator.
+   */
+  ShowCombinatorImpl(Token keyword, List<SimpleIdentifier> shownNames)
+      : super(keyword) {
+    _shownNames = new NodeList<SimpleIdentifier>(this, shownNames);
+  }
+
+  @override
+  // TODO(paulberry): add commas.
+  Iterable get childEntities => new ChildEntities()
+    ..add(keyword)
+    ..addAll(_shownNames);
+
+  @override
+  Token get endToken => _shownNames.endToken;
+
+  @override
+  NodeList<SimpleIdentifier> get shownNames => _shownNames;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitShowCombinator(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _shownNames.accept(visitor);
+  }
+}
+
+/**
+ * A simple formal parameter.
+ *
+ *    simpleFormalParameter ::=
+ *        ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
+ */
+class SimpleFormalParameterImpl extends NormalFormalParameterImpl
+    implements SimpleFormalParameter {
+  /**
+   * The token representing either the 'final', 'const' or 'var' keyword, or
+   * `null` if no keyword was used.
+   */
+  Token keyword;
+
+  /**
+   * The name of the declared type of the parameter, or `null` if the parameter
+   * does not have a declared type.
+   */
+  TypeName _type;
+
+  /**
+   * Initialize a newly created formal parameter. Either or both of the
+   * [comment] and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute. The [keyword] can be `null` if a type was
+   * specified. The [type] must be `null` if the keyword is 'var'.
+   */
+  SimpleFormalParameterImpl(Comment comment, List<Annotation> metadata,
+      this.keyword, TypeName type, SimpleIdentifier identifier)
+      : super(comment, metadata, identifier) {
+    _type = _becomeParentOf(type);
+  }
+
+  @override
+  Token get beginToken {
+    NodeList<Annotation> metadata = this.metadata;
+    if (!metadata.isEmpty) {
+      return metadata.beginToken;
+    } else if (keyword != null) {
+      return keyword;
+    } else if (_type != null) {
+      return _type.beginToken;
+    }
+    return identifier.beginToken;
+  }
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(keyword)..add(_type)..add(identifier);
+
+  @override
+  Token get endToken => identifier.endToken;
+
+  @override
+  bool get isConst =>
+      (keyword is KeywordToken) &&
+      (keyword as KeywordToken).keyword == Keyword.CONST;
+
+  @override
+  bool get isFinal =>
+      (keyword is KeywordToken) &&
+      (keyword as KeywordToken).keyword == Keyword.FINAL;
+
+  @override
+  TypeName get type => _type;
+
+  @override
+  void set type(TypeName typeName) {
+    _type = _becomeParentOf(typeName);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSimpleFormalParameter(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_type, visitor);
+    _safelyVisitChild(identifier, visitor);
+  }
+}
+
+/**
+ * A simple identifier.
+ *
+ *    simpleIdentifier ::=
+ *        initialCharacter internalCharacter*
+ *
+ *    initialCharacter ::= '_' | '$' | letter
+ *
+ *    internalCharacter ::= '_' | '$' | letter | digit
+ */
+class SimpleIdentifierImpl extends IdentifierImpl implements SimpleIdentifier {
+  /**
+   * The token representing the identifier.
+   */
+  Token token;
+
+  /**
+   * The element associated with this identifier based on static type
+   * information, or `null` if the AST structure has not been resolved or if
+   * this identifier could not be resolved.
+   */
+  Element _staticElement;
+
+  /**
+   * The element associated with this identifier based on propagated type
+   * information, or `null` if the AST structure has not been resolved or if
+   * this identifier could not be resolved.
+   */
+  Element _propagatedElement;
+
+  /**
+   * If this expression is both in a getter and setter context, the
+   * [AuxiliaryElements] will be set to hold onto the static and propagated
+   * information. The auxiliary element will hold onto the elements from the
+   * getter context.
+   */
+  AuxiliaryElements auxiliaryElements = null;
+
+  /**
+   * Initialize a newly created identifier.
+   */
+  SimpleIdentifierImpl(this.token);
+
+  @override
+  Token get beginToken => token;
+
+  @override
+  Element get bestElement {
+    if (_propagatedElement == null) {
+      return _staticElement;
+    }
+    return _propagatedElement;
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(token);
+
+  @override
+  Token get endToken => token;
+
+  @override
+  bool get isQualified {
+    AstNode parent = this.parent;
+    if (parent is PrefixedIdentifier) {
+      return identical(parent.identifier, this);
+    }
+    if (parent is PropertyAccess) {
+      return identical(parent.propertyName, this);
+    }
+    if (parent is MethodInvocation) {
+      MethodInvocation invocation = parent;
+      return identical(invocation.methodName, this) &&
+          invocation.realTarget != null;
+    }
+    return false;
+  }
+
+  @override
+  bool get isSynthetic => token.isSynthetic;
+
+  @override
+  String get name => token.lexeme;
+
+  @override
+  int get precedence => 16;
+
+  @override
+  Element get propagatedElement => _propagatedElement;
+
+  @override
+  void set propagatedElement(Element element) {
+    _propagatedElement = _validateElement(element);
+  }
+
+  @override
+  Element get staticElement => _staticElement;
+
+  @override
+  void set staticElement(Element element) {
+    _staticElement = _validateElement(element);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSimpleIdentifier(this);
+
+  @override
+  bool inDeclarationContext() {
+    // TODO(brianwilkerson) Convert this to a getter.
+    AstNode parent = this.parent;
+    if (parent is CatchClause) {
+      CatchClause clause = parent;
+      return identical(this, clause.exceptionParameter) ||
+          identical(this, clause.stackTraceParameter);
+    } else if (parent is ClassDeclaration) {
+      return identical(this, parent.name);
+    } else if (parent is ClassTypeAlias) {
+      return identical(this, parent.name);
+    } else if (parent is ConstructorDeclaration) {
+      return identical(this, parent.name);
+    } else if (parent is DeclaredIdentifier) {
+      return identical(this, parent.identifier);
+    } else if (parent is EnumDeclaration) {
+      return identical(this, parent.name);
+    } else if (parent is EnumConstantDeclaration) {
+      return identical(this, parent.name);
+    } else if (parent is FunctionDeclaration) {
+      return identical(this, parent.name);
+    } else if (parent is FunctionTypeAlias) {
+      return identical(this, parent.name);
+    } else if (parent is ImportDirective) {
+      return identical(this, parent.prefix);
+    } else if (parent is Label) {
+      return identical(this, parent.label) &&
+          (parent.parent is LabeledStatement);
+    } else if (parent is MethodDeclaration) {
+      return identical(this, parent.name);
+    } else if (parent is FunctionTypedFormalParameter ||
+        parent is SimpleFormalParameter) {
+      return identical(this, (parent as NormalFormalParameter).identifier);
+    } else if (parent is TypeParameter) {
+      return identical(this, parent.name);
+    } else if (parent is VariableDeclaration) {
+      return identical(this, parent.name);
+    }
+    return false;
+  }
+
+  @override
+  bool inGetterContext() {
+    // TODO(brianwilkerson) Convert this to a getter.
+    AstNode parent = this.parent;
+    AstNode target = this;
+    // skip prefix
+    if (parent is PrefixedIdentifier) {
+      PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
+      if (identical(prefixed.prefix, this)) {
+        return true;
+      }
+      parent = prefixed.parent;
+      target = prefixed;
+    } else if (parent is PropertyAccess) {
+      PropertyAccess access = parent as PropertyAccess;
+      if (identical(access.target, this)) {
+        return true;
+      }
+      parent = access.parent;
+      target = access;
+    }
+    // skip label
+    if (parent is Label) {
+      return false;
+    }
+    // analyze usage
+    if (parent is AssignmentExpression) {
+      if (identical(parent.leftHandSide, target) &&
+          parent.operator.type == TokenType.EQ) {
+        return false;
+      }
+    }
+    if (parent is ForEachStatement) {
+      if (identical(parent.identifier, target)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @override
+  bool inSetterContext() {
+    // TODO(brianwilkerson) Convert this to a getter.
+    AstNode parent = this.parent;
+    AstNode target = this;
+    // skip prefix
+    if (parent is PrefixedIdentifier) {
+      PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
+      // if this is the prefix, then return false
+      if (identical(prefixed.prefix, this)) {
+        return false;
+      }
+      parent = prefixed.parent;
+      target = prefixed;
+    } else if (parent is PropertyAccess) {
+      PropertyAccess access = parent as PropertyAccess;
+      if (identical(access.target, this)) {
+        return false;
+      }
+      parent = access.parent;
+      target = access;
+    }
+    // analyze usage
+    if (parent is PrefixExpression) {
+      return parent.operator.type.isIncrementOperator;
+    } else if (parent is PostfixExpression) {
+      return true;
+    } else if (parent is AssignmentExpression) {
+      return identical(parent.leftHandSide, target);
+    } else if (parent is ForEachStatement) {
+      return identical(parent.identifier, target);
+    }
+    return false;
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+
+  /**
+   * Return the given element if it is valid, or report the problem and return
+   * `null` if it is not appropriate.
+   *
+   * The [parent] is the parent of the element, used for reporting when there is
+   * a problem.
+   * The [isValid] is `true` if the element is appropriate.
+   * The [element] is the element to be associated with this identifier.
+   */
+  Element _returnOrReportElement(
+      AstNode parent, bool isValid, Element element) {
+    if (!isValid) {
+      AnalysisEngine.instance.logger.logInformation(
+          "Internal error: attempting to set the name of a ${parent.runtimeType} to a ${element.runtimeType}",
+          new CaughtException(new AnalysisException(), null));
+      return null;
+    }
+    return element;
+  }
+
+  /**
+   * Return the given [element] if it is an appropriate element based on the
+   * parent of this identifier, or `null` if it is not appropriate.
+   */
+  Element _validateElement(Element element) {
+    if (element == null) {
+      return null;
+    }
+    AstNode parent = this.parent;
+    if (parent is ClassDeclaration && identical(parent.name, this)) {
+      return _returnOrReportElement(parent, element is ClassElement, element);
+    } else if (parent is ClassTypeAlias && identical(parent.name, this)) {
+      return _returnOrReportElement(parent, element is ClassElement, element);
+    } else if (parent is DeclaredIdentifier &&
+        identical(parent.identifier, this)) {
+      return _returnOrReportElement(
+          parent, element is LocalVariableElement, element);
+    } else if (parent is FormalParameter &&
+        identical(parent.identifier, this)) {
+      return _returnOrReportElement(
+          parent, element is ParameterElement, element);
+    } else if (parent is FunctionDeclaration && identical(parent.name, this)) {
+      return _returnOrReportElement(
+          parent, element is ExecutableElement, element);
+    } else if (parent is FunctionTypeAlias && identical(parent.name, this)) {
+      return _returnOrReportElement(
+          parent, element is FunctionTypeAliasElement, element);
+    } else if (parent is MethodDeclaration && identical(parent.name, this)) {
+      return _returnOrReportElement(
+          parent, element is ExecutableElement, element);
+    } else if (parent is TypeParameter && identical(parent.name, this)) {
+      return _returnOrReportElement(
+          parent, element is TypeParameterElement, element);
+    } else if (parent is VariableDeclaration && identical(parent.name, this)) {
+      return _returnOrReportElement(
+          parent, element is VariableElement, element);
+    }
+    return element;
+  }
+}
+
+/**
+ * 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 '"'
+ */
+class SimpleStringLiteralImpl extends SingleStringLiteralImpl
+    implements SimpleStringLiteral {
+  /**
+   * The token representing the literal.
+   */
+  Token literal;
+
+  /**
+   * The value of the literal.
+   */
+  String _value;
+
+  /**
+   * Initialize a newly created simple string literal.
+   */
+  SimpleStringLiteralImpl(this.literal, String value) {
+    _value = StringUtilities.intern(value);
+  }
+
+  @override
+  Token get beginToken => literal;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(literal);
+
+  @override
+  int get contentsEnd => offset + _helper.end;
+
+  @override
+  int get contentsOffset => offset + _helper.start;
+
+  @override
+  Token get endToken => literal;
+
+  @override
+  bool get isMultiline => _helper.isMultiline;
+
+  @override
+  bool get isRaw => _helper.isRaw;
+
+  @override
+  bool get isSingleQuoted => _helper.isSingleQuoted;
+
+  @override
+  bool get isSynthetic => literal.isSynthetic;
+
+  @override
+  String get value => _value;
+
+  @override
+  void set value(String string) {
+    _value = StringUtilities.intern(_value);
+  }
+
+  StringLexemeHelper get _helper {
+    return new StringLexemeHelper(literal.lexeme, true, true);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSimpleStringLiteral(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+
+  @override
+  void _appendStringValue(StringBuffer buffer) {
+    buffer.write(value);
+  }
+}
+
+/**
+ * A single string literal expression.
+ *
+ *    singleStringLiteral ::=
+ *        [SimpleStringLiteral]
+ *      | [StringInterpolation]
+ */
+abstract class SingleStringLiteralImpl extends StringLiteralImpl
+    implements SingleStringLiteral {}
+
+/**
+ * A node that represents a statement.
+ *
+ *    statement ::=
+ *        [Block]
+ *      | [VariableDeclarationStatement]
+ *      | [ForStatement]
+ *      | [ForEachStatement]
+ *      | [WhileStatement]
+ *      | [DoStatement]
+ *      | [SwitchStatement]
+ *      | [IfStatement]
+ *      | [TryStatement]
+ *      | [BreakStatement]
+ *      | [ContinueStatement]
+ *      | [ReturnStatement]
+ *      | [ExpressionStatement]
+ *      | [FunctionDeclarationStatement]
+ */
+abstract class StatementImpl extends AstNodeImpl implements Statement {
+  @override
+  Statement get unlabeled => this;
+}
+
+/**
+ * A string interpolation literal.
+ *
+ *    stringInterpolation ::=
+ *        ''' [InterpolationElement]* '''
+ *      | '"' [InterpolationElement]* '"'
+ */
+class StringInterpolationImpl extends SingleStringLiteralImpl
+    implements StringInterpolation {
+  /**
+   * The elements that will be composed to produce the resulting string.
+   */
+  NodeList<InterpolationElement> _elements;
+
+  /**
+   * Initialize a newly created string interpolation expression.
+   */
+  StringInterpolationImpl(List<InterpolationElement> elements) {
+    _elements = new NodeList<InterpolationElement>(this, elements);
+  }
+
+  @override
+  Token get beginToken => _elements.beginToken;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..addAll(_elements);
+
+  @override
+  int get contentsEnd {
+    InterpolationString element = _elements.last;
+    return element.contentsEnd;
+  }
+
+  @override
+  int get contentsOffset {
+    InterpolationString element = _elements.first;
+    return element.contentsOffset;
+  }
+
+  /**
+   * Return the elements that will be composed to produce the resulting string.
+   */
+  NodeList<InterpolationElement> get elements => _elements;
+
+  @override
+  Token get endToken => _elements.endToken;
+
+  @override
+  bool get isMultiline => _firstHelper.isMultiline;
+
+  @override
+  bool get isRaw => false;
+
+  @override
+  bool get isSingleQuoted => _firstHelper.isSingleQuoted;
+
+  StringLexemeHelper get _firstHelper {
+    InterpolationString lastString = _elements.first;
+    String lexeme = lastString.contents.lexeme;
+    return new StringLexemeHelper(lexeme, true, false);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitStringInterpolation(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _elements.accept(visitor);
+  }
+
+  @override
+  void _appendStringValue(StringBuffer buffer) {
+    throw new IllegalArgumentException();
+  }
+}
+
+/**
+ * A helper for analyzing string lexemes.
+ */
+class StringLexemeHelper {
+  final String lexeme;
+  final bool isFirst;
+  final bool isLast;
+
+  bool isRaw = false;
+  bool isSingleQuoted = false;
+  bool isMultiline = false;
+  int start = 0;
+  int end;
+
+  StringLexemeHelper(this.lexeme, this.isFirst, this.isLast) {
+    if (isFirst) {
+      isRaw = StringUtilities.startsWithChar(lexeme, 0x72);
+      if (isRaw) {
+        start++;
+      }
+      if (StringUtilities.startsWith3(lexeme, start, 0x27, 0x27, 0x27)) {
+        isSingleQuoted = true;
+        isMultiline = true;
+        start += 3;
+        start = _trimInitialWhitespace(start);
+      } else if (StringUtilities.startsWith3(lexeme, start, 0x22, 0x22, 0x22)) {
+        isSingleQuoted = false;
+        isMultiline = true;
+        start += 3;
+        start = _trimInitialWhitespace(start);
+      } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x27) {
+        isSingleQuoted = true;
+        isMultiline = false;
+        start++;
+      } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x22) {
+        isSingleQuoted = false;
+        isMultiline = false;
+        start++;
+      }
+    }
+    end = lexeme.length;
+    if (isLast) {
+      if (start + 3 <= end &&
+          (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) ||
+              StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27))) {
+        end -= 3;
+      } else if (start + 1 <= end &&
+          (StringUtilities.endsWithChar(lexeme, 0x22) ||
+              StringUtilities.endsWithChar(lexeme, 0x27))) {
+        end -= 1;
+      }
+    }
+  }
+
+  /**
+   * Given the [lexeme] for a multi-line string whose content begins at the
+   * given [start] index, return the index of the first character that is
+   * included in the value of the string. According to the specification:
+   *
+   * If the first line of a multiline string consists solely of the whitespace
+   * characters defined by the production WHITESPACE 20.1), possibly prefixed
+   * by \, then that line is ignored, including the new line at its end.
+   */
+  int _trimInitialWhitespace(int start) {
+    int length = lexeme.length;
+    int index = start;
+    while (index < length) {
+      int currentChar = lexeme.codeUnitAt(index);
+      if (currentChar == 0x0D) {
+        if (index + 1 < length && lexeme.codeUnitAt(index + 1) == 0x0A) {
+          return index + 2;
+        }
+        return index + 1;
+      } else if (currentChar == 0x0A) {
+        return index + 1;
+      } else if (currentChar == 0x5C) {
+        if (index + 1 >= length) {
+          return start;
+        }
+        currentChar = lexeme.codeUnitAt(index + 1);
+        if (currentChar != 0x0D &&
+            currentChar != 0x0A &&
+            currentChar != 0x09 &&
+            currentChar != 0x20) {
+          return start;
+        }
+      } else if (currentChar != 0x09 && currentChar != 0x20) {
+        return start;
+      }
+      index++;
+    }
+    return start;
+  }
+}
+
+/**
+ * A string literal expression.
+ *
+ *    stringLiteral ::=
+ *        [SimpleStringLiteral]
+ *      | [AdjacentStrings]
+ *      | [StringInterpolation]
+ */
+abstract class StringLiteralImpl extends LiteralImpl implements StringLiteral {
+  @override
+  String get stringValue {
+    StringBuffer buffer = new StringBuffer();
+    try {
+      _appendStringValue(buffer);
+    } on IllegalArgumentException {
+      return null;
+    }
+    return buffer.toString();
+  }
+
+  /**
+   * Append the value of this string literal to the given [buffer]. Throw an
+   * [IllegalArgumentException] if the string is not a constant string without
+   * any string interpolation.
+   */
+  void _appendStringValue(StringBuffer buffer);
+}
+
+/**
+ * The invocation of a superclass' constructor from within a constructor's
+ * initialization list.
+ *
+ *    superInvocation ::=
+ *        'super' ('.' [SimpleIdentifier])? [ArgumentList]
+ */
+class SuperConstructorInvocationImpl extends ConstructorInitializerImpl
+    implements SuperConstructorInvocation {
+  /**
+   * The token for the 'super' keyword.
+   */
+  Token superKeyword;
+
+  /**
+   * The token for the period before the name of the constructor that is being
+   * invoked, or `null` if the unnamed constructor is being invoked.
+   */
+  Token period;
+
+  /**
+   * The name of the constructor that is being invoked, or `null` if the unnamed
+   * constructor is being invoked.
+   */
+  SimpleIdentifier _constructorName;
+
+  /**
+   * The list of arguments to the constructor.
+   */
+  ArgumentList _argumentList;
+
+  /**
+   * The element associated with the constructor based on static type
+   * information, or `null` if the AST structure has not been resolved or if the
+   * constructor could not be resolved.
+   */
+  ConstructorElement staticElement;
+
+  /**
+   * Initialize a newly created super invocation to invoke the inherited
+   * constructor with the given name with the given arguments. The [period] and
+   * [constructorName] can be `null` if the constructor being invoked is the
+   * unnamed constructor.
+   */
+  SuperConstructorInvocationImpl(this.superKeyword, this.period,
+      SimpleIdentifier constructorName, ArgumentList argumentList) {
+    _constructorName = _becomeParentOf(constructorName);
+    _argumentList = _becomeParentOf(argumentList);
+  }
+
+  @override
+  ArgumentList get argumentList => _argumentList;
+
+  @override
+  void set argumentList(ArgumentList argumentList) {
+    _argumentList = _becomeParentOf(argumentList);
+  }
+
+  @override
+  Token get beginToken => superKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(superKeyword)
+    ..add(period)
+    ..add(_constructorName)
+    ..add(_argumentList);
+
+  @override
+  SimpleIdentifier get constructorName => _constructorName;
+
+  @override
+  void set constructorName(SimpleIdentifier identifier) {
+    _constructorName = _becomeParentOf(identifier);
+  }
+
+  @override
+  Token get endToken => _argumentList.endToken;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSuperConstructorInvocation(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_constructorName, visitor);
+    _safelyVisitChild(_argumentList, visitor);
+  }
+}
+
+/**
+ * A super expression.
+ *
+ *    superExpression ::=
+ *        'super'
+ */
+class SuperExpressionImpl extends ExpressionImpl implements SuperExpression {
+  /**
+   * The token representing the 'super' keyword.
+   */
+  Token superKeyword;
+
+  /**
+   * Initialize a newly created super expression.
+   */
+  SuperExpressionImpl(this.superKeyword);
+
+  @override
+  Token get beginToken => superKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(superKeyword);
+
+  @override
+  Token get endToken => superKeyword;
+
+  @override
+  int get precedence => 16;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSuperExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * A case in a switch statement.
+ *
+ *    switchCase ::=
+ *        [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
+ */
+class SwitchCaseImpl extends SwitchMemberImpl implements SwitchCase {
+  /**
+   * The expression controlling whether the statements will be executed.
+   */
+  Expression _expression;
+
+  /**
+   * Initialize a newly created switch case. The list of [labels] can be `null`
+   * if there are no labels.
+   */
+  SwitchCaseImpl(List<Label> labels, Token keyword, Expression expression,
+      Token colon, List<Statement> statements)
+      : super(labels, keyword, colon, statements) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..addAll(labels)
+    ..add(keyword)
+    ..add(_expression)
+    ..add(colon)
+    ..addAll(statements);
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSwitchCase(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    labels.accept(visitor);
+    _safelyVisitChild(_expression, visitor);
+    statements.accept(visitor);
+  }
+}
+
+/**
+ * The default case in a switch statement.
+ *
+ *    switchDefault ::=
+ *        [SimpleIdentifier]* 'default' ':' [Statement]*
+ */
+class SwitchDefaultImpl extends SwitchMemberImpl implements SwitchDefault {
+  /**
+   * Initialize a newly created switch default. The list of [labels] can be
+   * `null` if there are no labels.
+   */
+  SwitchDefaultImpl(List<Label> labels, Token keyword, Token colon,
+      List<Statement> statements)
+      : super(labels, keyword, colon, statements);
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..addAll(labels)
+    ..add(keyword)
+    ..add(colon)
+    ..addAll(statements);
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSwitchDefault(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    labels.accept(visitor);
+    statements.accept(visitor);
+  }
+}
+
+/**
+ * An element within a switch statement.
+ *
+ *    switchMember ::=
+ *        switchCase
+ *      | switchDefault
+ */
+abstract class SwitchMemberImpl extends AstNodeImpl implements SwitchMember {
+  /**
+   * The labels associated with the switch member.
+   */
+  NodeList<Label> _labels;
+
+  /**
+   * The token representing the 'case' or 'default' keyword.
+   */
+  Token keyword;
+
+  /**
+   * The colon separating the keyword or the expression from the statements.
+   */
+  Token colon;
+
+  /**
+   * The statements that will be executed if this switch member is selected.
+   */
+  NodeList<Statement> _statements;
+
+  /**
+   * Initialize a newly created switch member. The list of [labels] can be
+   * `null` if there are no labels.
+   */
+  SwitchMemberImpl(List<Label> labels, this.keyword, this.colon,
+      List<Statement> statements) {
+    _labels = new NodeList<Label>(this, labels);
+    _statements = new NodeList<Statement>(this, statements);
+  }
+
+  @override
+  Token get beginToken {
+    if (!_labels.isEmpty) {
+      return _labels.beginToken;
+    }
+    return keyword;
+  }
+
+  @override
+  Token get endToken {
+    if (!_statements.isEmpty) {
+      return _statements.endToken;
+    }
+    return colon;
+  }
+
+  @override
+  NodeList<Label> get labels => _labels;
+
+  @override
+  NodeList<Statement> get statements => _statements;
+}
+
+/**
+ * A switch statement.
+ *
+ *    switchStatement ::=
+ *        'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
+ */
+class SwitchStatementImpl extends StatementImpl implements SwitchStatement {
+  /**
+   * The token representing the 'switch' keyword.
+   */
+  Token switchKeyword;
+
+  /**
+   * The left parenthesis.
+   */
+  Token leftParenthesis;
+
+  /**
+   * The expression used to determine which of the switch members will be
+   * selected.
+   */
+  Expression _expression;
+
+  /**
+   * The right parenthesis.
+   */
+  Token rightParenthesis;
+
+  /**
+   * The left curly bracket.
+   */
+  Token leftBracket;
+
+  /**
+   * The switch members that can be selected by the expression.
+   */
+  NodeList<SwitchMember> _members;
+
+  /**
+   * The right curly bracket.
+   */
+  Token rightBracket;
+
+  /**
+   * Initialize a newly created switch statement. The list of [members] can be
+   * `null` if there are no switch members.
+   */
+  SwitchStatementImpl(
+      this.switchKeyword,
+      this.leftParenthesis,
+      Expression expression,
+      this.rightParenthesis,
+      this.leftBracket,
+      List<SwitchMember> members,
+      this.rightBracket) {
+    _expression = _becomeParentOf(expression);
+    _members = new NodeList<SwitchMember>(this, members);
+  }
+
+  @override
+  Token get beginToken => switchKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(switchKeyword)
+    ..add(leftParenthesis)
+    ..add(_expression)
+    ..add(rightParenthesis)
+    ..add(leftBracket)
+    ..addAll(_members)
+    ..add(rightBracket);
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  NodeList<SwitchMember> get members => _members;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSwitchStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+    _members.accept(visitor);
+  }
+}
+
+/**
+ * A symbol literal expression.
+ *
+ *    symbolLiteral ::=
+ *        '#' (operator | (identifier ('.' identifier)*))
+ */
+class SymbolLiteralImpl extends LiteralImpl implements SymbolLiteral {
+  /**
+   * The token introducing the literal.
+   */
+  Token poundSign;
+
+  /**
+   * The components of the literal.
+   */
+  final List<Token> components;
+
+  /**
+   * Initialize a newly created symbol literal.
+   */
+  SymbolLiteralImpl(this.poundSign, this.components);
+
+  @override
+  Token get beginToken => poundSign;
+
+  @override
+  // TODO(paulberry): add "." tokens.
+  Iterable get childEntities => new ChildEntities()
+    ..add(poundSign)
+    ..addAll(components);
+
+  @override
+  Token get endToken => components[components.length - 1];
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitSymbolLiteral(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * A this expression.
+ *
+ *    thisExpression ::=
+ *        'this'
+ */
+class ThisExpressionImpl extends ExpressionImpl implements ThisExpression {
+  /**
+   * The token representing the 'this' keyword.
+   */
+  Token thisKeyword;
+
+  /**
+   * Initialize a newly created this expression.
+   */
+  ThisExpressionImpl(this.thisKeyword);
+
+  @override
+  Token get beginToken => thisKeyword;
+
+  @override
+  Iterable get childEntities => new ChildEntities()..add(thisKeyword);
+
+  @override
+  Token get endToken => thisKeyword;
+
+  @override
+  int get precedence => 16;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitThisExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    // There are no children to visit.
+  }
+}
+
+/**
+ * A throw expression.
+ *
+ *    throwExpression ::=
+ *        'throw' [Expression]
+ */
+class ThrowExpressionImpl extends ExpressionImpl implements ThrowExpression {
+  /**
+   * The token representing the 'throw' keyword.
+   */
+  Token throwKeyword;
+
+  /**
+   * The expression computing the exception to be thrown.
+   */
+  Expression _expression;
+
+  /**
+   * Initialize a newly created throw expression.
+   */
+  ThrowExpressionImpl(this.throwKeyword, Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken => throwKeyword;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(throwKeyword)..add(_expression);
+
+  @override
+  Token get endToken {
+    if (_expression != null) {
+      return _expression.endToken;
+    }
+    return throwKeyword;
+  }
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  int get precedence => 0;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitThrowExpression(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+  }
+}
+
+/**
+ * The declaration of one or more top-level variables of the same type.
+ *
+ *    topLevelVariableDeclaration ::=
+ *        ('final' | 'const') type? staticFinalDeclarationList ';'
+ *      | variableDeclaration ';'
+ */
+class TopLevelVariableDeclarationImpl extends CompilationUnitMemberImpl
+    implements TopLevelVariableDeclaration {
+  /**
+   * The top-level variables being declared.
+   */
+  VariableDeclarationList _variableList;
+
+  /**
+   * The semicolon terminating the declaration.
+   */
+  Token semicolon;
+
+  /**
+   * Initialize a newly created top-level variable declaration. Either or both
+   * of the [comment] and [metadata] can be `null` if the variable does not have
+   * the corresponding attribute.
+   */
+  TopLevelVariableDeclarationImpl(Comment comment, List<Annotation> metadata,
+      VariableDeclarationList variableList, this.semicolon)
+      : super(comment, metadata) {
+    _variableList = _becomeParentOf(variableList);
+  }
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(_variableList)..add(semicolon);
+
+  @override
+  Element get element => null;
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => _variableList.beginToken;
+
+  @override
+  VariableDeclarationList get variables => _variableList;
+
+  @override
+  void set variables(VariableDeclarationList variables) {
+    _variableList = _becomeParentOf(variables);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitTopLevelVariableDeclaration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_variableList, visitor);
+  }
+}
+
+/**
+ * A try statement.
+ *
+ *    tryStatement ::=
+ *        'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
+ *
+ *    finallyClause ::=
+ *        'finally' [Block]
+ */
+class TryStatementImpl extends StatementImpl implements TryStatement {
+  /**
+   * The token representing the 'try' keyword.
+   */
+  Token tryKeyword;
+
+  /**
+   * The body of the statement.
+   */
+  Block _body;
+
+  /**
+   * The catch clauses contained in the try statement.
+   */
+  NodeList<CatchClause> _catchClauses;
+
+  /**
+   * The token representing the 'finally' keyword, or `null` if the statement
+   * does not contain a finally clause.
+   */
+  Token finallyKeyword;
+
+  /**
+   * The finally block contained in the try statement, or `null` if the
+   * statement does not contain a finally clause.
+   */
+  Block _finallyBlock;
+
+  /**
+   * Initialize a newly created try statement. The list of [catchClauses] can be
+   * `null` if there are no catch clauses. The [finallyKeyword] and
+   * [finallyBlock] can be `null` if there is no finally clause.
+   */
+  TryStatementImpl(this.tryKeyword, Block body, List<CatchClause> catchClauses,
+      this.finallyKeyword, Block finallyBlock) {
+    _body = _becomeParentOf(body);
+    _catchClauses = new NodeList<CatchClause>(this, catchClauses);
+    _finallyBlock = _becomeParentOf(finallyBlock);
+  }
+
+  @override
+  Token get beginToken => tryKeyword;
+
+  @override
+  Block get body => _body;
+
+  @override
+  void set body(Block block) {
+    _body = _becomeParentOf(block);
+  }
+
+  @override
+  NodeList<CatchClause> get catchClauses => _catchClauses;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(tryKeyword)
+    ..add(_body)
+    ..addAll(_catchClauses)
+    ..add(finallyKeyword)
+    ..add(_finallyBlock);
+
+  @override
+  Token get endToken {
+    if (_finallyBlock != null) {
+      return _finallyBlock.endToken;
+    } else if (finallyKeyword != null) {
+      return finallyKeyword;
+    } else if (!_catchClauses.isEmpty) {
+      return _catchClauses.endToken;
+    }
+    return _body.endToken;
+  }
+
+  @override
+  Block get finallyBlock => _finallyBlock;
+
+  @override
+  void set finallyBlock(Block block) {
+    _finallyBlock = _becomeParentOf(block);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitTryStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_body, visitor);
+    _catchClauses.accept(visitor);
+    _safelyVisitChild(_finallyBlock, visitor);
+  }
+}
+
+/**
+ * The declaration of a type alias.
+ *
+ *    typeAlias ::=
+ *        'typedef' typeAliasBody
+ *
+ *    typeAliasBody ::=
+ *        classTypeAlias
+ *      | functionTypeAlias
+ */
+abstract class TypeAliasImpl extends NamedCompilationUnitMemberImpl
+    implements TypeAlias {
+  /**
+   * The token representing the 'typedef' keyword.
+   */
+  Token typedefKeyword;
+
+  /**
+   * The semicolon terminating the declaration.
+   */
+  Token semicolon;
+
+  /**
+   * Initialize a newly created type alias. Either or both of the [comment] and
+   * [metadata] can be `null` if the declaration does not have the corresponding
+   * attribute.
+   */
+  TypeAliasImpl(Comment comment, List<Annotation> metadata, this.typedefKeyword,
+      SimpleIdentifier name, this.semicolon)
+      : super(comment, metadata, name);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => typedefKeyword;
+}
+
+/**
+ * A list of type arguments.
+ *
+ *    typeArguments ::=
+ *        '<' typeName (',' typeName)* '>'
+ */
+class TypeArgumentListImpl extends AstNodeImpl implements TypeArgumentList {
+  /**
+   * The left bracket.
+   */
+  Token leftBracket;
+
+  /**
+   * The type arguments associated with the type.
+   */
+  NodeList<TypeName> _arguments;
+
+  /**
+   * The right bracket.
+   */
+  Token rightBracket;
+
+  /**
+   * Initialize a newly created list of type arguments.
+   */
+  TypeArgumentListImpl(
+      this.leftBracket, List<TypeName> arguments, this.rightBracket) {
+    _arguments = new NodeList<TypeName>(this, arguments);
+  }
+
+  @override
+  NodeList<TypeName> get arguments => _arguments;
+
+  @override
+  Token get beginToken => leftBracket;
+
+  @override
+  // TODO(paulberry): Add commas.
+  Iterable get childEntities => new ChildEntities()
+    ..add(leftBracket)
+    ..addAll(_arguments)
+    ..add(rightBracket);
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitTypeArgumentList(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _arguments.accept(visitor);
+  }
+}
+
+/**
+ * A literal that has a type associated with it.
+ *
+ *    typedLiteral ::=
+ *        [ListLiteral]
+ *      | [MapLiteral]
+ */
+abstract class TypedLiteralImpl extends LiteralImpl implements TypedLiteral {
+  /**
+   * The token representing the 'const' keyword, or `null` if the literal is not
+   * a constant.
+   */
+  Token constKeyword;
+
+  /**
+   * The type argument associated with this literal, or `null` if no type
+   * arguments were declared.
+   */
+  TypeArgumentList _typeArguments;
+
+  /**
+   * Initialize a newly created typed literal. The [constKeyword] can be `null`\
+   * if the literal is not a constant. The [typeArguments] can be `null` if no
+   * type arguments were declared.
+   */
+  TypedLiteralImpl(this.constKeyword, TypeArgumentList typeArguments) {
+    _typeArguments = _becomeParentOf(typeArguments);
+  }
+
+  @override
+  TypeArgumentList get typeArguments => _typeArguments;
+
+  @override
+  void set typeArguments(TypeArgumentList typeArguments) {
+    _typeArguments = _becomeParentOf(typeArguments);
+  }
+
+  ChildEntities get _childEntities =>
+      new ChildEntities()..add(constKeyword)..add(_typeArguments);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_typeArguments, visitor);
+  }
+}
+
+/**
+ * The name of a type, which can optionally include type arguments.
+ *
+ *    typeName ::=
+ *        [Identifier] typeArguments?
+ */
+class TypeNameImpl extends AstNodeImpl implements TypeName {
+  /**
+   * The name of the type.
+   */
+  Identifier _name;
+
+  /**
+   * The type arguments associated with the type, or `null` if there are no type
+   * arguments.
+   */
+  TypeArgumentList _typeArguments;
+
+  /**
+   * The type being named, or `null` if the AST structure has not been resolved.
+   */
+  DartType type;
+
+  /**
+   * Initialize a newly created type name. The [typeArguments] can be `null` if
+   * there are no type arguments.
+   */
+  TypeNameImpl(Identifier name, TypeArgumentList typeArguments) {
+    _name = _becomeParentOf(name);
+    _typeArguments = _becomeParentOf(typeArguments);
+  }
+
+  @override
+  Token get beginToken => _name.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_name)..add(_typeArguments);
+
+  @override
+  Token get endToken {
+    if (_typeArguments != null) {
+      return _typeArguments.endToken;
+    }
+    return _name.endToken;
+  }
+
+  @override
+  bool get isDeferred {
+    Identifier identifier = name;
+    if (identifier is! PrefixedIdentifier) {
+      return false;
+    }
+    return (identifier as PrefixedIdentifier).isDeferred;
+  }
+
+  @override
+  bool get isSynthetic => _name.isSynthetic && _typeArguments == null;
+
+  @override
+  Identifier get name => _name;
+
+  @override
+  void set name(Identifier identifier) {
+    _name = _becomeParentOf(identifier);
+  }
+
+  @override
+  TypeArgumentList get typeArguments => _typeArguments;
+
+  @override
+  void set typeArguments(TypeArgumentList typeArguments) {
+    _typeArguments = _becomeParentOf(typeArguments);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitTypeName(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_typeArguments, visitor);
+  }
+}
+
+/**
+ * A type parameter.
+ *
+ *    typeParameter ::=
+ *        [SimpleIdentifier] ('extends' [TypeName])?
+ */
+class TypeParameterImpl extends DeclarationImpl implements TypeParameter {
+  /**
+   * The name of the type parameter.
+   */
+  SimpleIdentifier _name;
+
+  /**
+   * The token representing the 'extends' keyword, or `null` if there is no
+   * explicit upper bound.
+   */
+  Token extendsKeyword;
+
+  /**
+   * The name of the upper bound for legal arguments, or `null` if there is no
+   * explicit upper bound.
+   */
+  TypeName _bound;
+
+  /**
+   * Initialize a newly created type parameter. Either or both of the [comment]
+   * and [metadata] can be `null` if the parameter does not have the
+   * corresponding attribute. The [extendsKeyword] and [bound] can be `null` if
+   * the parameter does not have an upper bound.
+   */
+  TypeParameterImpl(Comment comment, List<Annotation> metadata,
+      SimpleIdentifier name, this.extendsKeyword, TypeName bound)
+      : super(comment, metadata) {
+    _name = _becomeParentOf(name);
+    _bound = _becomeParentOf(bound);
+  }
+
+  @override
+  TypeName get bound => _bound;
+
+  @override
+  void set bound(TypeName typeName) {
+    _bound = _becomeParentOf(typeName);
+  }
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(_name)..add(extendsKeyword)..add(_bound);
+
+  @override
+  TypeParameterElement get element =>
+      _name != null ? (_name.staticElement as TypeParameterElement) : null;
+
+  @override
+  Token get endToken {
+    if (_bound == null) {
+      return _name.endToken;
+    }
+    return _bound.endToken;
+  }
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
+
+  @override
+  SimpleIdentifier get name => _name;
+
+  @override
+  void set name(SimpleIdentifier identifier) {
+    _name = _becomeParentOf(identifier);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitTypeParameter(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_bound, visitor);
+  }
+}
+
+/**
+ * Type parameters within a declaration.
+ *
+ *    typeParameterList ::=
+ *        '<' [TypeParameter] (',' [TypeParameter])* '>'
+ */
+class TypeParameterListImpl extends AstNodeImpl implements TypeParameterList {
+  /**
+   * The left angle bracket.
+   */
+  final Token leftBracket;
+
+  /**
+   * The type parameters in the list.
+   */
+  NodeList<TypeParameter> _typeParameters;
+
+  /**
+   * The right angle bracket.
+   */
+  final Token rightBracket;
+
+  /**
+   * Initialize a newly created list of type parameters.
+   */
+  TypeParameterListImpl(
+      this.leftBracket, List<TypeParameter> typeParameters, this.rightBracket) {
+    _typeParameters = new NodeList<TypeParameter>(this, typeParameters);
+  }
+
+  @override
+  Token get beginToken => leftBracket;
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(leftBracket)
+    ..addAll(_typeParameters)
+    ..add(rightBracket);
+
+  @override
+  Token get endToken => rightBracket;
+
+  @override
+  NodeList<TypeParameter> get typeParameters => _typeParameters;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitTypeParameterList(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _typeParameters.accept(visitor);
+  }
+}
+
+/**
+ * A directive that references a URI.
+ *
+ *    uriBasedDirective ::=
+ *        [ExportDirective]
+ *      | [ImportDirective]
+ *      | [PartDirective]
+ */
+abstract class UriBasedDirectiveImpl extends DirectiveImpl
+    implements UriBasedDirective {
+  /**
+   * The prefix of a URI using the `dart-ext` scheme to reference a native code
+   * library.
+   */
+  static String _DART_EXT_SCHEME = "dart-ext:";
+
+  /**
+   * The URI referenced by this directive.
+   */
+  StringLiteral _uri;
+
+  /**
+   * The content of the URI.
+   */
+  String uriContent;
+
+  /**
+   * The source to which the URI was resolved.
+   */
+  Source source;
+
+  /**
+   * Initialize a newly create URI-based directive. Either or both of the
+   * [comment] and [metadata] can be `null` if the directive does not have the
+   * corresponding attribute.
+   */
+  UriBasedDirectiveImpl(
+      Comment comment, List<Annotation> metadata, StringLiteral uri)
+      : super(comment, metadata) {
+    _uri = _becomeParentOf(uri);
+  }
+
+  @override
+  StringLiteral get uri => _uri;
+
+  @override
+  void set uri(StringLiteral uri) {
+    _uri = _becomeParentOf(uri);
+  }
+
+  @override
+  UriValidationCode validate() {
+    StringLiteral uriLiteral = uri;
+    if (uriLiteral is StringInterpolation) {
+      return UriValidationCode.URI_WITH_INTERPOLATION;
+    }
+    String uriContent = this.uriContent;
+    if (uriContent == null) {
+      return UriValidationCode.INVALID_URI;
+    }
+    if (this is ImportDirective && uriContent.startsWith(_DART_EXT_SCHEME)) {
+      return UriValidationCode.URI_WITH_DART_EXT_SCHEME;
+    }
+    try {
+      parseUriWithException(Uri.encodeFull(uriContent));
+    } on URISyntaxException {
+      return UriValidationCode.INVALID_URI;
+    }
+    return null;
+  }
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_uri, visitor);
+  }
+}
+
+/**
+ * Validation codes returned by [UriBasedDirective.validate].
+ */
+class UriValidationCodeImpl implements UriValidationCode {
+  static const UriValidationCode INVALID_URI =
+      const UriValidationCodeImpl('INVALID_URI');
+
+  static const UriValidationCode URI_WITH_INTERPOLATION =
+      const UriValidationCodeImpl('URI_WITH_INTERPOLATION');
+
+  static const UriValidationCode URI_WITH_DART_EXT_SCHEME =
+      const UriValidationCodeImpl('URI_WITH_DART_EXT_SCHEME');
+
+  /**
+   * The name of the validation code.
+   */
+  final String name;
+
+  /**
+   * Initialize a newly created validation code to have the given [name].
+   */
+  const UriValidationCodeImpl(this.name);
+
+  @override
+  String toString() => name;
+}
+
+/**
+ * An identifier that has an initial value associated with it. Instances of this
+ * class are always children of the class [VariableDeclarationList].
+ *
+ *    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.
+ * Consider changing the class hierarchy so that [VariableDeclaration] does not
+ * extend [Declaration].
+ */
+class VariableDeclarationImpl extends DeclarationImpl
+    implements VariableDeclaration {
+  /**
+   * The name of the variable being declared.
+   */
+  SimpleIdentifier _name;
+
+  /**
+   * The equal sign separating the variable name from the initial value, or
+   * `null` if the initial value was not specified.
+   */
+  Token equals;
+
+  /**
+   * The expression used to compute the initial value for the variable, or
+   * `null` if the initial value was not specified.
+   */
+  Expression _initializer;
+
+  /**
+   * Initialize a newly created variable declaration. The [equals] and
+   * [initializer] can be `null` if there is no initializer.
+   */
+  VariableDeclarationImpl(
+      SimpleIdentifier name, this.equals, Expression initializer)
+      : super(null, null) {
+    _name = _becomeParentOf(name);
+    _initializer = _becomeParentOf(initializer);
+  }
+
+  @override
+  Iterable get childEntities =>
+      super._childEntities..add(_name)..add(equals)..add(_initializer);
+
+  /**
+   * This overridden implementation of getDocumentationComment() looks in the
+   * grandparent node for Dartdoc comments if no documentation is specifically
+   * available on the node.
+   */
+  @override
+  Comment get documentationComment {
+    Comment comment = super.documentationComment;
+    if (comment == null) {
+      if (parent != null && parent.parent != null) {
+        AstNode node = parent.parent;
+        if (node is AnnotatedNode) {
+          return node.documentationComment;
+        }
+      }
+    }
+    return comment;
+  }
+
+  @override
+  VariableElement get element =>
+      _name != null ? (_name.staticElement as VariableElement) : null;
+
+  @override
+  Token get endToken {
+    if (_initializer != null) {
+      return _initializer.endToken;
+    }
+    return _name.endToken;
+  }
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
+
+  @override
+  Expression get initializer => _initializer;
+
+  @override
+  void set initializer(Expression expression) {
+    _initializer = _becomeParentOf(expression);
+  }
+
+  @override
+  bool get isConst {
+    AstNode parent = this.parent;
+    return parent is VariableDeclarationList && parent.isConst;
+  }
+
+  @override
+  bool get isFinal {
+    AstNode parent = this.parent;
+    return parent is VariableDeclarationList && parent.isFinal;
+  }
+
+  @override
+  SimpleIdentifier get name => _name;
+
+  @override
+  void set name(SimpleIdentifier identifier) {
+    _name = _becomeParentOf(identifier);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitVariableDeclaration(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_name, visitor);
+    _safelyVisitChild(_initializer, visitor);
+  }
+}
+
+/**
+ * The declaration of one or more variables of the same type.
+ *
+ *    variableDeclarationList ::=
+ *        finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
+ *
+ *    finalConstVarOrType ::=
+ *      | 'final' [TypeName]?
+ *      | 'const' [TypeName]?
+ *      | 'var'
+ *      | [TypeName]
+ */
+class VariableDeclarationListImpl extends AnnotatedNodeImpl
+    implements VariableDeclarationList {
+  /**
+   * The token representing the 'final', 'const' or 'var' keyword, or `null` if
+   * no keyword was included.
+   */
+  Token keyword;
+
+  /**
+   * The type of the variables being declared, or `null` if no type was provided.
+   */
+  TypeName _type;
+
+  /**
+   * A list containing the individual variables being declared.
+   */
+  NodeList<VariableDeclaration> _variables;
+
+  /**
+   * Initialize a newly created variable declaration list. Either or both of the
+   * [comment] and [metadata] can be `null` if the variable list does not have
+   * the corresponding attribute. The [keyword] can be `null` if a type was
+   * specified. The [type] must be `null` if the keyword is 'var'.
+   */
+  VariableDeclarationListImpl(Comment comment, List<Annotation> metadata,
+      this.keyword, TypeName type, List<VariableDeclaration> variables)
+      : super(comment, metadata) {
+    _type = _becomeParentOf(type);
+    _variables = new NodeList<VariableDeclaration>(this, variables);
+  }
+
+  @override
+  // TODO(paulberry): include commas.
+  Iterable get childEntities => super._childEntities
+    ..add(keyword)
+    ..add(_type)
+    ..addAll(_variables);
+
+  @override
+  Token get endToken => _variables.endToken;
+
+  @override
+  Token get firstTokenAfterCommentAndMetadata {
+    if (keyword != null) {
+      return keyword;
+    } else if (_type != null) {
+      return _type.beginToken;
+    }
+    return _variables.beginToken;
+  }
+
+  @override
+  bool get isConst =>
+      keyword is KeywordToken &&
+      (keyword as KeywordToken).keyword == Keyword.CONST;
+
+  @override
+  bool get isFinal =>
+      keyword is KeywordToken &&
+      (keyword as KeywordToken).keyword == Keyword.FINAL;
+
+  @override
+  TypeName get type => _type;
+
+  @override
+  void set type(TypeName typeName) {
+    _type = _becomeParentOf(typeName);
+  }
+
+  @override
+  NodeList<VariableDeclaration> get variables => _variables;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitVariableDeclarationList(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    super.visitChildren(visitor);
+    _safelyVisitChild(_type, visitor);
+    _variables.accept(visitor);
+  }
+}
+
+/**
+ * A list of variables that are being declared in a context where a statement is
+ * required.
+ *
+ *    variableDeclarationStatement ::=
+ *        [VariableDeclarationList] ';'
+ */
+class VariableDeclarationStatementImpl extends StatementImpl
+    implements VariableDeclarationStatement {
+  /**
+   * The variables being declared.
+   */
+  VariableDeclarationList _variableList;
+
+  /**
+   * The semicolon terminating the statement.
+   */
+  Token semicolon;
+
+  /**
+   * Initialize a newly created variable declaration statement.
+   */
+  VariableDeclarationStatementImpl(
+      VariableDeclarationList variableList, this.semicolon) {
+    _variableList = _becomeParentOf(variableList);
+  }
+
+  @override
+  Token get beginToken => _variableList.beginToken;
+
+  @override
+  Iterable get childEntities =>
+      new ChildEntities()..add(_variableList)..add(semicolon);
+
+  @override
+  Token get endToken => semicolon;
+
+  @override
+  VariableDeclarationList get variables => _variableList;
+
+  @override
+  void set variables(VariableDeclarationList variables) {
+    _variableList = _becomeParentOf(variables);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitVariableDeclarationStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_variableList, visitor);
+  }
+}
+
+/**
+ * A while statement.
+ *
+ *    whileStatement ::=
+ *        'while' '(' [Expression] ')' [Statement]
+ */
+class WhileStatementImpl extends StatementImpl implements WhileStatement {
+  /**
+   * The token representing the 'while' keyword.
+   */
+  Token whileKeyword;
+
+  /**
+   * The left parenthesis.
+   */
+  Token leftParenthesis;
+
+  /**
+   * The expression used to determine whether to execute the body of the loop.
+   */
+  Expression _condition;
+
+  /**
+   * The right parenthesis.
+   */
+  Token rightParenthesis;
+
+  /**
+   * The body of the loop.
+   */
+  Statement _body;
+
+  /**
+   * Initialize a newly created while statement.
+   */
+  WhileStatementImpl(this.whileKeyword, this.leftParenthesis,
+      Expression condition, this.rightParenthesis, Statement body) {
+    _condition = _becomeParentOf(condition);
+    _body = _becomeParentOf(body);
+  }
+
+  @override
+  Token get beginToken => whileKeyword;
+
+  @override
+  Statement get body => _body;
+
+  @override
+  void set body(Statement statement) {
+    _body = _becomeParentOf(statement);
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(whileKeyword)
+    ..add(leftParenthesis)
+    ..add(_condition)
+    ..add(rightParenthesis)
+    ..add(_body);
+
+  @override
+  Expression get condition => _condition;
+
+  @override
+  void set condition(Expression expression) {
+    _condition = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get endToken => _body.endToken;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitWhileStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_condition, visitor);
+    _safelyVisitChild(_body, visitor);
+  }
+}
+
+/**
+ * The with clause in a class declaration.
+ *
+ *    withClause ::=
+ *        'with' [TypeName] (',' [TypeName])*
+ */
+class WithClauseImpl extends AstNodeImpl implements WithClause {
+  /**
+   * The token representing the 'with' keyword.
+   */
+  Token withKeyword;
+
+  /**
+   * The names of the mixins that were specified.
+   */
+  NodeList<TypeName> _mixinTypes;
+
+  /**
+   * Initialize a newly created with clause.
+   */
+  WithClauseImpl(this.withKeyword, List<TypeName> mixinTypes) {
+    _mixinTypes = new NodeList<TypeName>(this, mixinTypes);
+  }
+
+  @override
+  Token get beginToken => withKeyword;
+
+  @override
+  // TODO(paulberry): add commas.
+  Iterable get childEntities => new ChildEntities()
+    ..add(withKeyword)
+    ..addAll(_mixinTypes);
+
+  @override
+  Token get endToken => _mixinTypes.endToken;
+
+  @override
+  NodeList<TypeName> get mixinTypes => _mixinTypes;
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitWithClause(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _mixinTypes.accept(visitor);
+  }
+}
+
+/**
+ * A yield statement.
+ *
+ *    yieldStatement ::=
+ *        'yield' '*'? [Expression] ‘;’
+ */
+class YieldStatementImpl extends StatementImpl implements YieldStatement {
+  /**
+   * The 'yield' keyword.
+   */
+  Token yieldKeyword;
+
+  /**
+   * The star optionally following the 'yield' keyword.
+   */
+  Token star;
+
+  /**
+   * The expression whose value will be yielded.
+   */
+  Expression _expression;
+
+  /**
+   * The semicolon following the expression.
+   */
+  Token semicolon;
+
+  /**
+   * Initialize a newly created yield expression. The [star] can be `null` if no
+   * star was provided.
+   */
+  YieldStatementImpl(
+      this.yieldKeyword, this.star, Expression expression, this.semicolon) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  Token get beginToken {
+    if (yieldKeyword != null) {
+      return yieldKeyword;
+    }
+    return _expression.beginToken;
+  }
+
+  @override
+  Iterable get childEntities => new ChildEntities()
+    ..add(yieldKeyword)
+    ..add(star)
+    ..add(_expression)
+    ..add(semicolon);
+
+  @override
+  Token get endToken {
+    if (semicolon != null) {
+      return semicolon;
+    }
+    return _expression.endToken;
+  }
+
+  @override
+  Expression get expression => _expression;
+
+  @override
+  void set expression(Expression expression) {
+    _expression = _becomeParentOf(expression);
+  }
+
+  @override
+  accept(AstVisitor visitor) => visitor.visitYieldStatement(this);
+
+  @override
+  void visitChildren(AstVisitor visitor) {
+    _safelyVisitChild(_expression, visitor);
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/ast/token.dart b/pkg/analyzer/lib/src/dart/ast/token.dart
new file mode 100644
index 0000000..1791990
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/ast/token.dart
@@ -0,0 +1,572 @@
+// 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 analyzer.src.dart.ast.token;
+
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+
+/**
+ * The opening half of a grouping pair of tokens. This is used for curly
+ * brackets ('{'), parentheses ('('), and square brackets ('[').
+ */
+class BeginToken extends SimpleToken {
+  /**
+   * The token that corresponds to this token.
+   */
+  Token endToken;
+
+  /**
+   * Initialize a newly created token to have the given [type] at the given
+   * [offset].
+   */
+  BeginToken(TokenType type, int offset) : super(type, offset) {
+    assert(type == TokenType.OPEN_CURLY_BRACKET ||
+        type == TokenType.OPEN_PAREN ||
+        type == TokenType.OPEN_SQUARE_BRACKET ||
+        type == TokenType.STRING_INTERPOLATION_EXPRESSION);
+  }
+
+  @override
+  Token copy() => new BeginToken(type, offset);
+}
+
+/**
+ * A begin token that is preceded by comments.
+ */
+class BeginTokenWithComment extends BeginToken implements TokenWithComment {
+  /**
+   * The first comment in the list of comments that precede this token.
+   */
+  @override
+  CommentToken _precedingComment;
+
+  /**
+   * Initialize a newly created token to have the given [type] at the given
+   * [offset] and to be preceded by the comments reachable from the given
+   * [comment].
+   */
+  BeginTokenWithComment(TokenType type, int offset, this._precedingComment)
+      : super(type, offset) {
+    _setCommentParent(_precedingComment);
+  }
+
+  @override
+  CommentToken get precedingComments => _precedingComment;
+
+  @override
+  void set precedingComments(CommentToken comment) {
+    _precedingComment = comment;
+    _setCommentParent(_precedingComment);
+  }
+
+  @override
+  void applyDelta(int delta) {
+    super.applyDelta(delta);
+    Token token = precedingComments;
+    while (token != null) {
+      token.applyDelta(delta);
+      token = token.next;
+    }
+  }
+
+  @override
+  Token copy() =>
+      new BeginTokenWithComment(type, offset, copyComments(precedingComments));
+}
+
+/**
+ * A token representing a comment.
+ */
+class CommentToken extends StringToken {
+  /**
+   * The token that contains this comment.
+   */
+  TokenWithComment parent;
+
+  /**
+   * Initialize a newly created token to represent a token of the given [type]
+   * with the given [value] at the given [offset].
+   */
+  CommentToken(TokenType type, String value, int offset)
+      : super(type, value, offset);
+
+  @override
+  CommentToken copy() => new CommentToken(type, _value, offset);
+
+  /**
+   * Remove this comment token from the list.
+   *
+   * This is used when we decide to interpret the comment as syntax.
+   */
+  void remove() {
+    if (previous != null) {
+      previous.setNextWithoutSettingPrevious(next);
+      next?.previous = previous;
+    } else {
+      assert(parent.precedingComments == this);
+      parent.precedingComments = next;
+    }
+  }
+}
+
+/**
+ * A documentation comment token.
+ */
+class DocumentationCommentToken extends CommentToken {
+  /**
+   * The references embedded within the documentation comment.
+   * This list will be empty unless this is a documentation comment that has
+   * references embedded within it.
+   */
+  final List<Token> references = <Token>[];
+
+  /**
+   * Initialize a newly created token to represent a token of the given [type]
+   * with the given [value] at the given [offset].
+   */
+  DocumentationCommentToken(TokenType type, String value, int offset)
+      : super(type, value, offset);
+
+  @override
+  CommentToken copy() {
+    DocumentationCommentToken copy =
+        new DocumentationCommentToken(type, _value, offset);
+    references.forEach((ref) => copy.references.add(ref.copy()));
+    return copy;
+  }
+}
+
+/**
+ * A token representing a keyword in the language.
+ */
+class KeywordToken extends SimpleToken {
+  /**
+   * The keyword being represented by this token.
+   */
+  final Keyword keyword;
+
+  /**
+   * Initialize a newly created token to represent the given [keyword] at the
+   * given [offset].
+   */
+  KeywordToken(this.keyword, int offset) : super(TokenType.KEYWORD, offset);
+
+  @override
+  String get lexeme => keyword.syntax;
+
+  @override
+  Token copy() => new KeywordToken(keyword, offset);
+
+  @override
+  Keyword value() => keyword;
+}
+
+/**
+ * A keyword token that is preceded by comments.
+ */
+class KeywordTokenWithComment extends KeywordToken implements TokenWithComment {
+  /**
+   * The first comment in the list of comments that precede this token.
+   */
+  @override
+  CommentToken _precedingComment;
+
+  /**
+   * Initialize a newly created token to to represent the given [keyword] at the
+   * given [offset] and to be preceded by the comments reachable from the given
+   * [comment].
+   */
+  KeywordTokenWithComment(Keyword keyword, int offset, this._precedingComment)
+      : super(keyword, offset) {
+    _setCommentParent(_precedingComment);
+  }
+
+  @override
+  CommentToken get precedingComments => _precedingComment;
+
+  void set precedingComments(CommentToken comment) {
+    _precedingComment = comment;
+    _setCommentParent(_precedingComment);
+  }
+
+  @override
+  void applyDelta(int delta) {
+    super.applyDelta(delta);
+    Token token = precedingComments;
+    while (token != null) {
+      token.applyDelta(delta);
+      token = token.next;
+    }
+  }
+
+  @override
+  Token copy() => new KeywordTokenWithComment(
+      keyword, offset, copyComments(precedingComments));
+}
+
+/**
+ * A token that was scanned from the input. Each token knows which tokens
+ * precede and follow it, acting as a link in a doubly linked list of tokens.
+ */
+class SimpleToken implements Token {
+  /**
+   * The type of the token.
+   */
+  @override
+  final TokenType type;
+
+  /**
+   * The offset from the beginning of the file to the first character in the
+   * token.
+   */
+  @override
+  int offset = 0;
+
+  /**
+   * The previous token in the token stream.
+   */
+  @override
+  Token previous;
+
+  /**
+   * The next token in the token stream.
+   */
+  Token _next;
+
+  /**
+   * Initialize a newly created token to have the given [type] and [offset].
+   */
+  SimpleToken(this.type, this.offset);
+
+  @override
+  int get end => offset + length;
+
+  @override
+  bool get isOperator => type.isOperator;
+
+  @override
+  bool get isSynthetic => length == 0;
+
+  @override
+  bool get isUserDefinableOperator => type.isUserDefinableOperator;
+
+  @override
+  int get length => lexeme.length;
+
+  @override
+  String get lexeme => type.lexeme;
+
+  @override
+  Token get next => _next;
+
+  @override
+  CommentToken get precedingComments => null;
+
+  @override
+  void applyDelta(int delta) {
+    offset += delta;
+  }
+
+  @override
+  Token copy() => new Token(type, offset);
+
+  @override
+  Token copyComments(Token token) {
+    if (token == null) {
+      return null;
+    }
+    Token head = token.copy();
+    Token tail = head;
+    token = token.next;
+    while (token != null) {
+      tail = tail.setNext(token.copy());
+      token = token.next;
+    }
+    return head;
+  }
+
+  @override
+  bool matchesAny(List<TokenType> types) {
+    for (TokenType type in types) {
+      if (this.type == type) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @override
+  Token setNext(Token token) {
+    _next = token;
+    token.previous = this;
+    return token;
+  }
+
+  @override
+  Token setNextWithoutSettingPrevious(Token token) {
+    _next = token;
+    return token;
+  }
+
+  @override
+  String toString() => lexeme;
+
+  @override
+  Object value() => type.lexeme;
+
+  /**
+   * Sets the `parent` property to `this` for the given [comment] and all the
+   * next tokens.
+   */
+  void _setCommentParent(CommentToken comment) {
+    while (comment != null) {
+      comment.parent = this;
+      comment = comment.next;
+    }
+  }
+}
+
+/**
+ * A token whose value is independent of it's type.
+ */
+class StringToken extends SimpleToken {
+  /**
+   * The lexeme represented by this token.
+   */
+  String _value;
+
+  /**
+   * Initialize a newly created token to represent a token of the given [type]
+   * with the given [value] at the given [offset].
+   */
+  StringToken(TokenType type, String value, int offset) : super(type, offset) {
+    this._value = StringUtilities.intern(value);
+  }
+
+  @override
+  String get lexeme => _value;
+
+  @override
+  Token copy() => new StringToken(type, _value, offset);
+
+  @override
+  String value() => _value;
+}
+
+/**
+ * A string token that is preceded by comments.
+ */
+class StringTokenWithComment extends StringToken implements TokenWithComment {
+  /**
+   * The first comment in the list of comments that precede this token.
+   */
+  CommentToken _precedingComment;
+
+  /**
+   * Initialize a newly created token to have the given [type] at the given
+   * [offset] and to be preceded by the comments reachable from the given
+   * [comment].
+   */
+  StringTokenWithComment(
+      TokenType type, String value, int offset, this._precedingComment)
+      : super(type, value, offset) {
+    _setCommentParent(_precedingComment);
+  }
+
+  @override
+  CommentToken get precedingComments => _precedingComment;
+
+  void set precedingComments(CommentToken comment) {
+    _precedingComment = comment;
+    _setCommentParent(_precedingComment);
+  }
+
+  @override
+  void applyDelta(int delta) {
+    super.applyDelta(delta);
+    Token token = precedingComments;
+    while (token != null) {
+      token.applyDelta(delta);
+      token = token.next;
+    }
+  }
+
+  @override
+  Token copy() => new StringTokenWithComment(
+      type, lexeme, offset, copyComments(precedingComments));
+}
+
+/**
+ * A token whose value is independent of it's type.
+ */
+class SyntheticStringToken extends StringToken {
+  /**
+   * Initialize a newly created token to represent a token of the given [type]
+   * with the given [value] at the given [offset].
+   */
+  SyntheticStringToken(TokenType type, String value, int offset)
+      : super(type, value, offset);
+
+  @override
+  bool get isSynthetic => true;
+}
+
+/**
+ * The classes (or groups) of tokens with a similar use.
+ */
+class TokenClass {
+  /**
+   * A value used to indicate that the token type is not part of any specific
+   * class of token.
+   */
+  static const TokenClass NO_CLASS = const TokenClass('NO_CLASS');
+
+  /**
+   * A value used to indicate that the token type is an additive operator.
+   */
+  static const TokenClass ADDITIVE_OPERATOR =
+      const TokenClass('ADDITIVE_OPERATOR', 13);
+
+  /**
+   * A value used to indicate that the token type is an assignment operator.
+   */
+  static const TokenClass ASSIGNMENT_OPERATOR =
+      const TokenClass('ASSIGNMENT_OPERATOR', 1);
+
+  /**
+   * A value used to indicate that the token type is a bitwise-and operator.
+   */
+  static const TokenClass BITWISE_AND_OPERATOR =
+      const TokenClass('BITWISE_AND_OPERATOR', 11);
+
+  /**
+   * A value used to indicate that the token type is a bitwise-or operator.
+   */
+  static const TokenClass BITWISE_OR_OPERATOR =
+      const TokenClass('BITWISE_OR_OPERATOR', 9);
+
+  /**
+   * A value used to indicate that the token type is a bitwise-xor operator.
+   */
+  static const TokenClass BITWISE_XOR_OPERATOR =
+      const TokenClass('BITWISE_XOR_OPERATOR', 10);
+
+  /**
+   * A value used to indicate that the token type is a cascade operator.
+   */
+  static const TokenClass CASCADE_OPERATOR =
+      const TokenClass('CASCADE_OPERATOR', 2);
+
+  /**
+   * A value used to indicate that the token type is a conditional operator.
+   */
+  static const TokenClass CONDITIONAL_OPERATOR =
+      const TokenClass('CONDITIONAL_OPERATOR', 3);
+
+  /**
+   * A value used to indicate that the token type is an equality operator.
+   */
+  static const TokenClass EQUALITY_OPERATOR =
+      const TokenClass('EQUALITY_OPERATOR', 7);
+
+  /**
+   * A value used to indicate that the token type is an if-null operator.
+   */
+  static const TokenClass IF_NULL_OPERATOR =
+      const TokenClass('IF_NULL_OPERATOR', 4);
+
+  /**
+   * A value used to indicate that the token type is a logical-and operator.
+   */
+  static const TokenClass LOGICAL_AND_OPERATOR =
+      const TokenClass('LOGICAL_AND_OPERATOR', 6);
+
+  /**
+   * A value used to indicate that the token type is a logical-or operator.
+   */
+  static const TokenClass LOGICAL_OR_OPERATOR =
+      const TokenClass('LOGICAL_OR_OPERATOR', 5);
+
+  /**
+   * A value used to indicate that the token type is a multiplicative operator.
+   */
+  static const TokenClass MULTIPLICATIVE_OPERATOR =
+      const TokenClass('MULTIPLICATIVE_OPERATOR', 14);
+
+  /**
+   * A value used to indicate that the token type is a relational operator.
+   */
+  static const TokenClass RELATIONAL_OPERATOR =
+      const TokenClass('RELATIONAL_OPERATOR', 8);
+
+  /**
+   * A value used to indicate that the token type is a shift operator.
+   */
+  static const TokenClass SHIFT_OPERATOR =
+      const TokenClass('SHIFT_OPERATOR', 12);
+
+  /**
+   * A value used to indicate that the token type is a unary operator.
+   */
+  static const TokenClass UNARY_POSTFIX_OPERATOR =
+      const TokenClass('UNARY_POSTFIX_OPERATOR', 16);
+
+  /**
+   * A value used to indicate that the token type is a unary operator.
+   */
+  static const TokenClass UNARY_PREFIX_OPERATOR =
+      const TokenClass('UNARY_PREFIX_OPERATOR', 15);
+
+  /**
+   * The name of the token class.
+   */
+  final String name;
+
+  /**
+   * The precedence of tokens of this class, or `0` if the such tokens do not
+   * represent an operator.
+   */
+  final int precedence;
+
+  /**
+   * Initialize a newly created class of tokens to have the given [name] and
+   * [precedence].
+   */
+  const TokenClass(this.name, [this.precedence = 0]);
+
+  @override
+  String toString() => name;
+}
+
+/**
+ * A normal token that is preceded by comments.
+ */
+class TokenWithComment extends SimpleToken {
+  /**
+   * The first comment in the list of comments that precede this token.
+   */
+  CommentToken _precedingComment;
+
+  /**
+   * Initialize a newly created token to have the given [type] at the given
+   * [offset] and to be preceded by the comments reachable from the given
+   * [comment].
+   */
+  TokenWithComment(TokenType type, int offset, this._precedingComment)
+      : super(type, offset) {
+    _setCommentParent(_precedingComment);
+  }
+
+  @override
+  CommentToken get precedingComments => _precedingComment;
+
+  void set precedingComments(CommentToken comment) {
+    _precedingComment = comment;
+    _setCommentParent(_precedingComment);
+  }
+
+  @override
+  Token copy() => new TokenWithComment(type, offset, precedingComments);
+}
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index f0435eb..dbbba10 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -2,17 +2,18 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analyzer.src.generated.ast;
+library analyzer.src.dart.ast.utilities;
 
 import 'dart:collection';
 
+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/generated/ast.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart' show TokenMap;
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
@@ -29,12 +30,32 @@
   final bool cloneTokens;
 
   /**
+   * Mapping from original tokes to cloned.
+   */
+  final Map<Token, Token> _clonedTokens = new Map<Token, Token>.identity();
+
+  /**
+   * The next original token to clone.
+   */
+  Token _nextToClone;
+
+  /**
+   * The last cloned token.
+   */
+  Token _lastCloned;
+
+  /**
+   * The offset of the last cloned token.
+   */
+  int _lastClonedOffset = -1;
+
+  /**
    * Initialize a newly created AST cloner to optionally clone tokens while
    * cloning AST nodes if [cloneTokens] is `true`.
+   *
+   * TODO(brianwilkerson) Change this to be a named parameter.
    */
-  AstCloner(
-      [this.cloneTokens =
-          false]); // TODO(brianwilkerson) Change this to be a named parameter.
+  AstCloner([this.cloneTokens = false]);
 
   /**
    * Return a clone of the given [node].
@@ -64,7 +85,15 @@
    */
   Token cloneToken(Token token) {
     if (cloneTokens) {
-      return (token == null ? null : token.copy());
+      if (token == null) {
+        return null;
+      }
+      if (_lastClonedOffset <= token.offset) {
+        _cloneTokens(_nextToClone ?? token, token.offset);
+      }
+      Token clone = _clonedTokens[token];
+      assert(clone != null);
+      return clone;
     } else {
       return token;
     }
@@ -75,7 +104,7 @@
    */
   List<Token> cloneTokenList(List<Token> tokens) {
     if (cloneTokens) {
-      return tokens.map((Token token) => token.copy()).toList();
+      return tokens.map(cloneToken).toList();
     }
     return tokens;
   }
@@ -185,18 +214,21 @@
   }
 
   @override
-  ClassTypeAlias visitClassTypeAlias(ClassTypeAlias node) => new ClassTypeAlias(
-      cloneNode(node.documentationComment),
-      cloneNodeList(node.metadata),
-      cloneToken(node.typedefKeyword),
-      cloneNode(node.name),
-      cloneNode(node.typeParameters),
-      cloneToken(node.equals),
-      cloneToken(node.abstractKeyword),
-      cloneNode(node.superclass),
-      cloneNode(node.withClause),
-      cloneNode(node.implementsClause),
-      cloneToken(node.semicolon));
+  ClassTypeAlias visitClassTypeAlias(ClassTypeAlias node) {
+    cloneToken(node.abstractKeyword);
+    return new ClassTypeAlias(
+        cloneNode(node.documentationComment),
+        cloneNodeList(node.metadata),
+        cloneToken(node.typedefKeyword),
+        cloneNode(node.name),
+        cloneNode(node.typeParameters),
+        cloneToken(node.equals),
+        cloneToken(node.abstractKeyword),
+        cloneNode(node.superclass),
+        cloneNode(node.withClause),
+        cloneNode(node.implementsClause),
+        cloneToken(node.semicolon));
+  }
 
   @override
   Comment visitComment(Comment node) {
@@ -887,6 +919,58 @@
       cloneToken(node.semicolon));
 
   /**
+   * Clone all token starting from the given [token] up to a token that has
+   * offset greater then [stopAfter], and put mapping from originals to clones
+   * into [_clonedTokens].
+   *
+   * We cannot clone tokens as we visit nodes because not every token is a part
+   * of a node, E.g. commas in argument lists are not represented in AST. But
+   * we need to the sequence of tokens that is identical to the original one.
+   */
+  void _cloneTokens(Token token, int stopAfter) {
+    if (token == null) {
+      return;
+    }
+    if (token is CommentToken) {
+      token = (token as CommentToken).parent;
+    }
+    if (_lastCloned == null) {
+      _lastCloned = new Token(TokenType.EOF, -1);
+      _lastCloned.setNext(_lastCloned);
+    }
+    while (token != null) {
+      Token clone = token.copy();
+      {
+        CommentToken c1 = token.precedingComments;
+        CommentToken c2 = clone.precedingComments;
+        while (c1 != null && c2 != null) {
+          _clonedTokens[c1] = c2;
+          if (c1 is DocumentationCommentToken &&
+              c2 is DocumentationCommentToken) {
+            for (int i = 0; i < c1.references.length; i++) {
+              _clonedTokens[c1.references[i]] = c2.references[i];
+            }
+          }
+          c1 = c1.next;
+          c2 = c2.next;
+        }
+      }
+      _clonedTokens[token] = clone;
+      _lastCloned.setNext(clone);
+      _lastCloned = clone;
+      if (token.type == TokenType.EOF) {
+        break;
+      }
+      if (token.offset > stopAfter) {
+        _nextToClone = token.next;
+        _lastClonedOffset = token.offset;
+        break;
+      }
+      token = token.next;
+    }
+  }
+
+  /**
    * Return a clone of the given [node].
    */
   static AstNode clone(AstNode node) {
@@ -4866,7 +4950,7 @@
     } else if (_replaceInList(node.variables)) {
       return true;
     }
-    return visitNode(node);
+    return visitAnnotatedNode(node);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
new file mode 100644
index 0000000..23869ee
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -0,0 +1,1463 @@
+// 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 analyzer.src.dart.element.builder;
+
+import 'dart:collection';
+
+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/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * A `CompilationUnitBuilder` builds an element model for a single compilation
+ * unit.
+ */
+class CompilationUnitBuilder {
+  /**
+   * Build the compilation unit element for the given [source] based on the
+   * compilation [unit] associated with the source. Throw an AnalysisException
+   * if the element could not be built.  [librarySource] is the source for the
+   * containing library.
+   */
+  CompilationUnitElementImpl buildCompilationUnit(
+      Source source, CompilationUnit unit, Source librarySource) {
+    return PerformanceStatistics.resolve.makeCurrentWhile(() {
+      if (unit == null) {
+        return null;
+      }
+      ElementHolder holder = new ElementHolder();
+      CompilationUnitElementImpl element =
+          new CompilationUnitElementImpl(source.shortName);
+      ElementBuilder builder = new ElementBuilder(holder, element);
+      unit.accept(builder);
+      element.accessors = holder.accessors;
+      element.enums = holder.enums;
+      element.functions = holder.functions;
+      element.source = source;
+      element.librarySource = librarySource;
+      element.typeAliases = holder.typeAliases;
+      element.types = holder.types;
+      element.topLevelVariables = holder.topLevelVariables;
+      unit.element = element;
+      holder.validate();
+      return element;
+    });
+  }
+}
+
+/**
+ * Instances of the class `DirectiveElementBuilder` build elements for top
+ * level library directives.
+ */
+class DirectiveElementBuilder extends SimpleAstVisitor<Object> {
+  /**
+   * The analysis context within which directive elements are being built.
+   */
+  final AnalysisContext context;
+
+  /**
+   * The library element for which directive elements are being built.
+   */
+  final LibraryElementImpl libraryElement;
+
+  /**
+   * Map from sources imported by this library to their corresponding library
+   * elements.
+   */
+  final Map<Source, LibraryElement> importLibraryMap;
+
+  /**
+   * Map from sources imported by this library to their corresponding source
+   * kinds.
+   */
+  final Map<Source, SourceKind> importSourceKindMap;
+
+  /**
+   * Map from sources exported by this library to their corresponding library
+   * elements.
+   */
+  final Map<Source, LibraryElement> exportLibraryMap;
+
+  /**
+   * Map from sources exported by this library to their corresponding source
+   * kinds.
+   */
+  final Map<Source, SourceKind> exportSourceKindMap;
+
+  /**
+   * The [ImportElement]s created so far.
+   */
+  final List<ImportElement> imports = <ImportElement>[];
+
+  /**
+   * The [ExportElement]s created so far.
+   */
+  final List<ExportElement> exports = <ExportElement>[];
+
+  /**
+   * The errors found while building directive elements.
+   */
+  final List<AnalysisError> errors = <AnalysisError>[];
+
+  /**
+   * Map from prefix names to their corresponding elements.
+   */
+  final HashMap<String, PrefixElementImpl> nameToPrefixMap =
+      new HashMap<String, PrefixElementImpl>();
+
+  /**
+   * Indicates whether an explicit import of `dart:core` has been found.
+   */
+  bool explicitlyImportsCore = false;
+
+  DirectiveElementBuilder(
+      this.context,
+      this.libraryElement,
+      this.importLibraryMap,
+      this.importSourceKindMap,
+      this.exportLibraryMap,
+      this.exportSourceKindMap);
+
+  @override
+  Object visitCompilationUnit(CompilationUnit node) {
+    //
+    // Resolve directives.
+    //
+    for (Directive directive in node.directives) {
+      directive.accept(this);
+    }
+    //
+    // Ensure "dart:core" import.
+    //
+    Source librarySource = libraryElement.source;
+    Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE);
+    if (!explicitlyImportsCore && coreLibrarySource != librarySource) {
+      ImportElementImpl importElement = new ImportElementImpl(-1);
+      importElement.importedLibrary = importLibraryMap[coreLibrarySource];
+      importElement.synthetic = true;
+      imports.add(importElement);
+    }
+    //
+    // Populate the library element.
+    //
+    libraryElement.imports = imports;
+    libraryElement.exports = exports;
+    return null;
+  }
+
+  @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
+      // directive was invalid.
+      LibraryElement exportedLibrary = exportLibraryMap[exportedSource];
+      if (exportedLibrary != null) {
+        ExportElementImpl exportElement = new ExportElementImpl(node.offset);
+        exportElement.metadata = _getElementAnnotations(node.metadata);
+        StringLiteral uriLiteral = node.uri;
+        if (uriLiteral != null) {
+          exportElement.uriOffset = uriLiteral.offset;
+          exportElement.uriEnd = uriLiteral.end;
+        }
+        exportElement.uri = node.uriContent;
+        exportElement.combinators = _buildCombinators(node);
+        exportElement.exportedLibrary = exportedLibrary;
+        setElementDocumentationComment(exportElement, node);
+        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(
+              libraryElement.source,
+              offset,
+              length,
+              CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
+              [uriLiteral.toSource()]));
+        }
+      }
+    }
+    return null;
+  }
+
+  @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;
+    }
+    Source importedSource = node.source;
+    if (importedSource != null && context.exists(importedSource)) {
+      // The imported source will be null if the URI in the import
+      // directive was invalid.
+      LibraryElement importedLibrary = importLibraryMap[importedSource];
+      if (importedLibrary != null) {
+        if (importedLibrary.isDartCore) {
+          explicitlyImportsCore = true;
+        }
+        ImportElementImpl importElement = new ImportElementImpl(node.offset);
+        importElement.metadata = _getElementAnnotations(node.metadata);
+        StringLiteral uriLiteral = node.uri;
+        if (uriLiteral != null) {
+          importElement.uriOffset = uriLiteral.offset;
+          importElement.uriEnd = uriLiteral.end;
+        }
+        importElement.uri = uriContent;
+        importElement.deferred = node.deferredKeyword != null;
+        importElement.combinators = _buildCombinators(node);
+        importElement.importedLibrary = importedLibrary;
+        setElementDocumentationComment(importElement, node);
+        SimpleIdentifier prefixNode = node.prefix;
+        if (prefixNode != null) {
+          importElement.prefixOffset = prefixNode.offset;
+          String prefixName = prefixNode.name;
+          PrefixElementImpl prefix = nameToPrefixMap[prefixName];
+          if (prefix == null) {
+            prefix = new PrefixElementImpl.forNode(prefixNode);
+            nameToPrefixMap[prefixName] = prefix;
+          }
+          importElement.prefix = prefix;
+          prefixNode.staticElement = prefix;
+        }
+        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(libraryElement.source, offset, length,
+              errorCode, [uriLiteral.toSource()]));
+        }
+      }
+    }
+    return null;
+  }
+
+  @override
+  Object visitLibraryDirective(LibraryDirective node) {
+    (node.element as LibraryElementImpl)?.metadata =
+        _getElementAnnotations(node.metadata);
+    return null;
+  }
+
+  @override
+  Object visitPartDirective(PartDirective node) {
+    (node.element as CompilationUnitElementImpl)?.metadata =
+        _getElementAnnotations(node.metadata);
+    return null;
+  }
+
+  /**
+   * Gather a list of the [ElementAnnotation]s referred to by the [Annotation]s
+   * in [metadata].
+   */
+  List<ElementAnnotation> _getElementAnnotations(
+      NodeList<Annotation> metadata) {
+    if (metadata.isEmpty) {
+      return ElementAnnotation.EMPTY_LIST;
+    }
+    return metadata.map((Annotation a) => a.elementAnnotation).toList();
+  }
+
+  /**
+   * Build the element model representing the combinators declared by
+   * the given [directive].
+   */
+  static List<NamespaceCombinator> _buildCombinators(
+      NamespaceDirective directive) {
+    _NamespaceCombinatorBuilder namespaceCombinatorBuilder =
+        new _NamespaceCombinatorBuilder();
+    for (Combinator combinator in directive.combinators) {
+      combinator.accept(namespaceCombinatorBuilder);
+    }
+    return namespaceCombinatorBuilder.combinators;
+  }
+}
+
+/**
+ * Instances of the class `ElementBuilder` traverse an AST structure and build the element
+ * model representing the AST structure.
+ */
+class ElementBuilder extends RecursiveAstVisitor<Object> {
+  /**
+   * The compilation unit element into which the elements being built will be
+   * stored.
+   */
+  final CompilationUnitElement compilationUnitElement;
+
+  /**
+   * The element holder associated with the element that is currently being built.
+   */
+  ElementHolder _currentHolder;
+
+  /**
+   * A flag indicating whether a variable declaration is within the body of a method or function.
+   */
+  bool _inFunction = false;
+
+  /**
+   * A collection holding the elements defined in a class that need to have
+   * their function type fixed to take into account type parameters of the
+   * enclosing class, or `null` if we are not currently processing nodes within
+   * a class.
+   */
+  List<ExecutableElementImpl> _functionTypesToFix = null;
+
+  /**
+   * A table mapping field names to field elements for the fields defined in the current class, or
+   * `null` if we are not in the scope of a class.
+   */
+  HashMap<String, FieldElement> _fieldMap;
+
+  /**
+   * Initialize a newly created element builder to build the elements for a compilation unit.
+   *
+   * @param initialHolder the element holder associated with the compilation unit being built
+   */
+  ElementBuilder(ElementHolder initialHolder, this.compilationUnitElement) {
+    _currentHolder = initialHolder;
+  }
+
+  @override
+  Object visitAnnotation(Annotation node) {
+    // Although it isn't valid to do so because closures are not constant
+    // expressions, it's possible for one of the arguments to the constructor to
+    // contain a closure. Wrapping the processing of the annotation this way
+    // prevents these closures from being added to the list of functions in the
+    // annotated declaration.
+    ElementHolder holder = new ElementHolder();
+    ElementHolder previousHolder = _currentHolder;
+    _currentHolder = holder;
+    try {
+      super.visitAnnotation(node);
+    } finally {
+      _currentHolder = previousHolder;
+    }
+    return null;
+  }
+
+  @override
+  Object visitCatchClause(CatchClause node) {
+    SimpleIdentifier exceptionParameter = node.exceptionParameter;
+    if (exceptionParameter != null) {
+      // exception
+      LocalVariableElementImpl exception =
+          new LocalVariableElementImpl.forNode(exceptionParameter);
+      if (node.exceptionType == null) {
+        exception.hasImplicitType = true;
+      }
+      _currentHolder.addLocalVariable(exception);
+      exceptionParameter.staticElement = exception;
+      // stack trace
+      SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
+      if (stackTraceParameter != null) {
+        LocalVariableElementImpl stackTrace =
+            new LocalVariableElementImpl.forNode(stackTraceParameter);
+        _setCodeRange(stackTrace, stackTraceParameter);
+        _currentHolder.addLocalVariable(stackTrace);
+        stackTraceParameter.staticElement = stackTrace;
+      }
+    }
+    return super.visitCatchClause(node);
+  }
+
+  @override
+  Object visitClassDeclaration(ClassDeclaration node) {
+    ElementHolder holder = new ElementHolder();
+    _functionTypesToFix = new List<ExecutableElementImpl>();
+    //
+    // Process field declarations before constructors and methods so that field
+    // formal parameters can be correctly resolved to their fields.
+    //
+    ElementHolder previousHolder = _currentHolder;
+    _currentHolder = holder;
+    try {
+      List<ClassMember> nonFields = new List<ClassMember>();
+      node.visitChildren(
+          new _ElementBuilder_visitClassDeclaration(this, nonFields));
+      _buildFieldMap(holder.fieldsWithoutFlushing);
+      int count = nonFields.length;
+      for (int i = 0; i < count; i++) {
+        nonFields[i].accept(this);
+      }
+    } finally {
+      _currentHolder = previousHolder;
+    }
+    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);
+    InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
+    interfaceType.typeArguments = typeArguments;
+    element.type = interfaceType;
+    element.typeParameters = typeParameters;
+    setElementDocumentationComment(element, node);
+    element.abstract = node.isAbstract;
+    element.accessors = holder.accessors;
+    List<ConstructorElement> constructors = holder.constructors;
+    if (constructors.isEmpty) {
+      constructors = _createDefaultConstructors(element);
+    }
+    element.constructors = constructors;
+    element.fields = holder.fields;
+    element.methods = holder.methods;
+    // Function types must be initialized after the enclosing element has been
+    // set, for them to pick up the type parameters.
+    for (ExecutableElementImpl e in _functionTypesToFix) {
+      e.type = new FunctionTypeImpl(e);
+    }
+    _functionTypesToFix = null;
+    _currentHolder.addType(element);
+    className.staticElement = element;
+    _fieldMap = null;
+    holder.validate();
+    return null;
+  }
+
+  /**
+   * Implementation of this method should be synchronized with
+   * [visitClassDeclaration].
+   */
+  void visitClassDeclarationIncrementally(ClassDeclaration node) {
+    //
+    // Process field declarations before constructors and methods so that field
+    // formal parameters can be correctly resolved to their fields.
+    //
+    ClassElement classElement = node.element;
+    _buildFieldMap(classElement.fields);
+  }
+
+  @override
+  Object visitClassTypeAlias(ClassTypeAlias node) {
+    ElementHolder holder = new ElementHolder();
+    _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;
+    List<TypeParameterElement> typeParameters = holder.typeParameters;
+    element.typeParameters = typeParameters;
+    List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
+    InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
+    interfaceType.typeArguments = typeArguments;
+    element.type = interfaceType;
+    setElementDocumentationComment(element, node);
+    _currentHolder.addType(element);
+    className.staticElement = element;
+    holder.validate();
+    return null;
+  }
+
+  @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;
+    _inFunction = true;
+    try {
+      _visitChildren(holder, node);
+    } finally {
+      _inFunction = wasInFunction;
+    }
+    FunctionBody body = node.body;
+    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) {
+      element.external = true;
+    }
+    if (node.factoryKeyword != null) {
+      element.factory = true;
+    }
+    element.functions = holder.functions;
+    element.labels = holder.labels;
+    element.localVariables = holder.localVariables;
+    element.parameters = holder.parameters;
+    element.const2 = node.constKeyword != null;
+    if (body.isAsynchronous) {
+      element.asynchronous = true;
+    }
+    if (body.isGenerator) {
+      element.generator = true;
+    }
+    _currentHolder.addConstructor(element);
+    node.element = element;
+    if (constructorName == null) {
+      Identifier returnType = node.returnType;
+      if (returnType != null) {
+        element.nameOffset = returnType.offset;
+        element.nameEnd = returnType.end;
+      }
+    } else {
+      constructorName.staticElement = element;
+      element.periodOffset = node.period.offset;
+      element.nameEnd = constructorName.end;
+    }
+    holder.validate();
+    return null;
+  }
+
+  @override
+  Object visitDeclaredIdentifier(DeclaredIdentifier node) {
+    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;
+    int statementEnd = statement.offset + statement.length;
+    element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1);
+    element.const3 = node.isConst;
+    element.final2 = node.isFinal;
+    if (node.type == null) {
+      element.hasImplicitType = true;
+    }
+    _currentHolder.addLocalVariable(element);
+    variableName.staticElement = element;
+    return super.visitDeclaredIdentifier(node);
+  }
+
+  @override
+  Object visitDefaultFormalParameter(DefaultFormalParameter node) {
+    ElementHolder holder = new ElementHolder();
+    NormalFormalParameter normalParameter = node.parameter;
+    SimpleIdentifier parameterName = normalParameter.identifier;
+    ParameterElementImpl parameter;
+    if (normalParameter is FieldFormalParameter) {
+      parameter =
+          new DefaultFieldFormalParameterElementImpl.forNode(parameterName);
+      FieldElement field =
+          _fieldMap == null ? null : _fieldMap[parameterName.name];
+      if (field != null) {
+        (parameter as DefaultFieldFormalParameterElementImpl).field = field;
+      }
+    } else {
+      parameter = new DefaultParameterElementImpl.forNode(parameterName);
+    }
+    _setCodeRange(parameter, node);
+    parameter.const3 = node.isConst;
+    parameter.final2 = node.isFinal;
+    parameter.parameterKind = node.kind;
+    // set initializer, default value range
+    Expression defaultValue = node.defaultValue;
+    if (defaultValue != null) {
+      _visit(holder, defaultValue);
+      FunctionElementImpl initializer =
+          new FunctionElementImpl.forOffset(defaultValue.beginToken.offset);
+      initializer.hasImplicitReturnType = true;
+      initializer.functions = holder.functions;
+      initializer.labels = holder.labels;
+      initializer.localVariables = holder.localVariables;
+      initializer.parameters = holder.parameters;
+      initializer.synthetic = true;
+      initializer.type = new FunctionTypeImpl(initializer);
+      parameter.initializer = initializer;
+      parameter.defaultValueCode = defaultValue.toSource();
+    }
+    // visible range
+    _setParameterVisibleRange(node, parameter);
+    if (normalParameter is SimpleFormalParameter &&
+        normalParameter.type == null) {
+      parameter.hasImplicitType = true;
+    }
+    _currentHolder.addParameter(parameter);
+    parameterName.staticElement = parameter;
+    normalParameter.accept(this);
+    holder.validate();
+    return null;
+  }
+
+  @override
+  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);
+    InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
+    enumElement.type = enumType;
+    // The equivalent code for enums in the spec shows a single constructor,
+    // but that constructor is not callable (since it is a compile-time error
+    // to subclass, mix-in, implement, or explicitly instantiate an enum).  So
+    // we represent this as having no constructors.
+    enumElement.constructors = ConstructorElement.EMPTY_LIST;
+    _currentHolder.addEnum(enumElement);
+    enumName.staticElement = enumElement;
+    return super.visitEnumDeclaration(node);
+  }
+
+  @override
+  Object visitExportDirective(ExportDirective node) {
+    _createElementAnnotations(node.metadata);
+    return super.visitExportDirective(node);
+  }
+
+  @override
+  Object visitFieldFormalParameter(FieldFormalParameter node) {
+    if (node.parent is! DefaultFormalParameter) {
+      SimpleIdentifier parameterName = node.identifier;
+      FieldElement field =
+          _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;
+      if (field != null) {
+        parameter.field = field;
+      }
+      _currentHolder.addParameter(parameter);
+      parameterName.staticElement = parameter;
+    }
+    //
+    // The children of this parameter include any parameters defined on the type
+    // of this parameter.
+    //
+    ElementHolder holder = new ElementHolder();
+    _visitChildren(holder, node);
+    ParameterElementImpl element = node.element;
+    element.metadata = _createElementAnnotations(node.metadata);
+    element.parameters = holder.parameters;
+    element.typeParameters = holder.typeParameters;
+    holder.validate();
+    return null;
+  }
+
+  @override
+  Object visitFunctionDeclaration(FunctionDeclaration node) {
+    FunctionExpression expression = node.functionExpression;
+    if (expression != null) {
+      ElementHolder holder = new ElementHolder();
+      bool wasInFunction = _inFunction;
+      _inFunction = true;
+      try {
+        _visitChildren(holder, node);
+      } finally {
+        _inFunction = wasInFunction;
+      }
+      FunctionBody body = expression.body;
+      Token property = node.propertyKeyword;
+      if (property == null || _inFunction) {
+        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) {
+          element.external = true;
+        }
+        element.functions = holder.functions;
+        element.labels = holder.labels;
+        element.localVariables = holder.localVariables;
+        element.parameters = holder.parameters;
+        element.typeParameters = holder.typeParameters;
+        if (body.isAsynchronous) {
+          element.asynchronous = true;
+        }
+        if (body.isGenerator) {
+          element.generator = true;
+        }
+        if (_inFunction) {
+          Block enclosingBlock = node.getAncestor((node) => node is Block);
+          if (enclosingBlock != null) {
+            element.setVisibleRange(
+                enclosingBlock.offset, enclosingBlock.length);
+          }
+        }
+        if (node.returnType == null) {
+          element.hasImplicitReturnType = true;
+        }
+        _currentHolder.addFunction(element);
+        expression.element = element;
+        functionName.staticElement = element;
+      } else {
+        SimpleIdentifier propertyNameNode = node.name;
+        if (propertyNameNode == null) {
+          // TODO(brianwilkerson) Report this internal error.
+          return null;
+        }
+        String propertyName = propertyNameNode.name;
+        TopLevelVariableElementImpl variable = _currentHolder
+            .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl;
+        if (variable == null) {
+          variable = new TopLevelVariableElementImpl(node.name.name, -1);
+          variable.final2 = true;
+          variable.synthetic = true;
+          _currentHolder.addTopLevelVariable(variable);
+        }
+        if (node.isGetter) {
+          PropertyAccessorElementImpl getter =
+              new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setCodeRange(getter, node);
+          getter.metadata = _createElementAnnotations(node.metadata);
+          setElementDocumentationComment(getter, node);
+          if (node.externalKeyword != null) {
+            getter.external = true;
+          }
+          getter.functions = holder.functions;
+          getter.labels = holder.labels;
+          getter.localVariables = holder.localVariables;
+          if (body.isAsynchronous) {
+            getter.asynchronous = true;
+          }
+          if (body.isGenerator) {
+            getter.generator = true;
+          }
+          getter.variable = variable;
+          getter.getter = true;
+          getter.static = true;
+          variable.getter = getter;
+          if (node.returnType == null) {
+            getter.hasImplicitReturnType = true;
+          }
+          _currentHolder.addAccessor(getter);
+          expression.element = getter;
+          propertyNameNode.staticElement = getter;
+        } else {
+          PropertyAccessorElementImpl setter =
+              new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setCodeRange(setter, node);
+          setter.metadata = _createElementAnnotations(node.metadata);
+          setElementDocumentationComment(setter, node);
+          if (node.externalKeyword != null) {
+            setter.external = true;
+          }
+          setter.functions = holder.functions;
+          setter.labels = holder.labels;
+          setter.localVariables = holder.localVariables;
+          setter.parameters = holder.parameters;
+          if (body.isAsynchronous) {
+            setter.asynchronous = true;
+          }
+          if (body.isGenerator) {
+            setter.generator = true;
+          }
+          setter.variable = variable;
+          setter.setter = true;
+          setter.static = true;
+          if (node.returnType == null) {
+            setter.hasImplicitReturnType = true;
+          }
+          variable.setter = setter;
+          variable.final2 = false;
+          _currentHolder.addAccessor(setter);
+          expression.element = setter;
+          propertyNameNode.staticElement = setter;
+        }
+      }
+      holder.validate();
+    }
+    return null;
+  }
+
+  @override
+  Object visitFunctionExpression(FunctionExpression node) {
+    if (node.parent is FunctionDeclaration) {
+      // visitFunctionDeclaration has already created the element for the
+      // declaration.  We just need to visit children.
+      return super.visitFunctionExpression(node);
+    }
+    ElementHolder holder = new ElementHolder();
+    bool wasInFunction = _inFunction;
+    _inFunction = true;
+    try {
+      _visitChildren(holder, node);
+    } finally {
+      _inFunction = wasInFunction;
+    }
+    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;
+    element.parameters = holder.parameters;
+    element.typeParameters = holder.typeParameters;
+    if (body.isAsynchronous) {
+      element.asynchronous = true;
+    }
+    if (body.isGenerator) {
+      element.generator = true;
+    }
+    if (_inFunction) {
+      Block enclosingBlock = node.getAncestor((node) => node is Block);
+      if (enclosingBlock != null) {
+        element.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
+      }
+    }
+    if (_functionTypesToFix != null) {
+      _functionTypesToFix.add(element);
+    } else {
+      element.type = new FunctionTypeImpl(element);
+    }
+    element.hasImplicitReturnType = true;
+    _currentHolder.addFunction(element);
+    node.element = element;
+    holder.validate();
+    return null;
+  }
+
+  @override
+  Object visitFunctionTypeAlias(FunctionTypeAlias node) {
+    ElementHolder holder = new ElementHolder();
+    _visitChildren(holder, node);
+    SimpleIdentifier aliasName = node.name;
+    List<ParameterElement> parameters = holder.parameters;
+    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;
+    element.typeParameters = typeParameters;
+    _createTypeParameterTypes(typeParameters);
+    element.type = new FunctionTypeImpl.forTypedef(element);
+    _currentHolder.addTypeAlias(element);
+    aliasName.staticElement = element;
+    holder.validate();
+    return null;
+  }
+
+  @override
+  Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+    if (node.parent is! DefaultFormalParameter) {
+      SimpleIdentifier parameterName = node.identifier;
+      ParameterElementImpl parameter =
+          new ParameterElementImpl.forNode(parameterName);
+      _setCodeRange(parameter, node);
+      parameter.parameterKind = node.kind;
+      _setParameterVisibleRange(node, parameter);
+      _currentHolder.addParameter(parameter);
+      parameterName.staticElement = parameter;
+    }
+    //
+    // The children of this parameter include any parameters defined on the type
+    //of this parameter.
+    //
+    ElementHolder holder = new ElementHolder();
+    _visitChildren(holder, node);
+    ParameterElementImpl element = node.element;
+    element.metadata = _createElementAnnotations(node.metadata);
+    element.parameters = holder.parameters;
+    element.typeParameters = holder.typeParameters;
+    holder.validate();
+    return null;
+  }
+
+  @override
+  Object visitImportDirective(ImportDirective node) {
+    _createElementAnnotations(node.metadata);
+    return super.visitImportDirective(node);
+  }
+
+  @override
+  Object visitLabeledStatement(LabeledStatement node) {
+    bool onSwitchStatement = node.statement is SwitchStatement;
+    for (Label label in node.labels) {
+      SimpleIdentifier labelName = label.label;
+      LabelElementImpl element =
+          new LabelElementImpl.forNode(labelName, onSwitchStatement, false);
+      _setCodeRange(element, node);
+      _currentHolder.addLabel(element);
+      labelName.staticElement = element;
+    }
+    return super.visitLabeledStatement(node);
+  }
+
+  @override
+  Object visitLibraryDirective(LibraryDirective node) {
+    _createElementAnnotations(node.metadata);
+    return super.visitLibraryDirective(node);
+  }
+
+  @override
+  Object visitMethodDeclaration(MethodDeclaration node) {
+    try {
+      ElementHolder holder = new ElementHolder();
+      bool wasInFunction = _inFunction;
+      _inFunction = true;
+      try {
+        _visitChildren(holder, node);
+      } finally {
+        _inFunction = wasInFunction;
+      }
+      bool isStatic = node.isStatic;
+      Token property = node.propertyKeyword;
+      FunctionBody body = node.body;
+      if (property == null) {
+        SimpleIdentifier methodName = node.name;
+        String nameOfMethod = methodName.name;
+        if (nameOfMethod == TokenType.MINUS.lexeme &&
+            node.parameters.parameters.length == 0) {
+          nameOfMethod = "unary-";
+        }
+        MethodElementImpl element =
+            new MethodElementImpl(nameOfMethod, methodName.offset);
+        _setCodeRange(element, node);
+        element.metadata = _createElementAnnotations(node.metadata);
+        setElementDocumentationComment(element, node);
+        element.abstract = node.isAbstract;
+        if (node.externalKeyword != null) {
+          element.external = true;
+        }
+        element.functions = holder.functions;
+        element.labels = holder.labels;
+        element.localVariables = holder.localVariables;
+        element.parameters = holder.parameters;
+        element.static = isStatic;
+        element.typeParameters = holder.typeParameters;
+        if (body.isAsynchronous) {
+          element.asynchronous = true;
+        }
+        if (body.isGenerator) {
+          element.generator = true;
+        }
+        if (node.returnType == null) {
+          element.hasImplicitReturnType = true;
+        }
+        _currentHolder.addMethod(element);
+        methodName.staticElement = element;
+      } else {
+        SimpleIdentifier propertyNameNode = node.name;
+        String propertyName = propertyNameNode.name;
+        FieldElementImpl field =
+            _currentHolder.getField(propertyName) as FieldElementImpl;
+        if (field == null) {
+          field = new FieldElementImpl(node.name.name, -1);
+          field.final2 = true;
+          field.static = isStatic;
+          field.synthetic = true;
+          _currentHolder.addField(field);
+        }
+        if (node.isGetter) {
+          PropertyAccessorElementImpl getter =
+              new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setCodeRange(getter, node);
+          getter.metadata = _createElementAnnotations(node.metadata);
+          setElementDocumentationComment(getter, node);
+          if (node.externalKeyword != null) {
+            getter.external = true;
+          }
+          getter.functions = holder.functions;
+          getter.labels = holder.labels;
+          getter.localVariables = holder.localVariables;
+          if (body.isAsynchronous) {
+            getter.asynchronous = true;
+          }
+          if (body.isGenerator) {
+            getter.generator = true;
+          }
+          getter.variable = field;
+          getter.abstract = node.isAbstract;
+          getter.getter = true;
+          getter.static = isStatic;
+          field.getter = getter;
+          if (node.returnType == null) {
+            getter.hasImplicitReturnType = true;
+          }
+          _currentHolder.addAccessor(getter);
+          propertyNameNode.staticElement = getter;
+        } else {
+          PropertyAccessorElementImpl setter =
+              new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setCodeRange(setter, node);
+          setter.metadata = _createElementAnnotations(node.metadata);
+          setElementDocumentationComment(setter, node);
+          if (node.externalKeyword != null) {
+            setter.external = true;
+          }
+          setter.functions = holder.functions;
+          setter.labels = holder.labels;
+          setter.localVariables = holder.localVariables;
+          setter.parameters = holder.parameters;
+          if (body.isAsynchronous) {
+            setter.asynchronous = true;
+          }
+          if (body.isGenerator) {
+            setter.generator = true;
+          }
+          setter.variable = field;
+          setter.abstract = node.isAbstract;
+          setter.setter = true;
+          setter.static = isStatic;
+          if (node.returnType == null) {
+            setter.hasImplicitReturnType = true;
+          }
+          field.setter = setter;
+          field.final2 = false;
+          _currentHolder.addAccessor(setter);
+          propertyNameNode.staticElement = setter;
+        }
+      }
+      holder.validate();
+    } catch (exception, stackTrace) {
+      if (node.name.staticElement == null) {
+        ClassDeclaration classNode =
+            node.getAncestor((node) => node is ClassDeclaration);
+        StringBuffer buffer = new StringBuffer();
+        buffer.write("The element for the method ");
+        buffer.write(node.name);
+        buffer.write(" in ");
+        buffer.write(classNode.name);
+        buffer.write(" was not set while trying to build the element model.");
+        AnalysisEngine.instance.logger.logError(
+            buffer.toString(), new CaughtException(exception, stackTrace));
+      } else {
+        String message =
+            "Exception caught in ElementBuilder.visitMethodDeclaration()";
+        AnalysisEngine.instance.logger
+            .logError(message, new CaughtException(exception, stackTrace));
+      }
+    } finally {
+      if (node.name.staticElement == null) {
+        ClassDeclaration classNode =
+            node.getAncestor((node) => node is ClassDeclaration);
+        StringBuffer buffer = new StringBuffer();
+        buffer.write("The element for the method ");
+        buffer.write(node.name);
+        buffer.write(" in ");
+        buffer.write(classNode.name);
+        buffer.write(" was not set while trying to resolve types.");
+        AnalysisEngine.instance.logger.logError(
+            buffer.toString(),
+            new CaughtException(
+                new AnalysisException(buffer.toString()), null));
+      }
+    }
+    return null;
+  }
+
+  @override
+  Object visitPartDirective(PartDirective node) {
+    _createElementAnnotations(node.metadata);
+    return super.visitPartDirective(node);
+  }
+
+  @override
+  Object visitSimpleFormalParameter(SimpleFormalParameter node) {
+    if (node.parent is! DefaultFormalParameter) {
+      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;
+      _setParameterVisibleRange(node, parameter);
+      if (node.type == null) {
+        parameter.hasImplicitType = true;
+      }
+      _currentHolder.addParameter(parameter);
+      parameterName.staticElement = parameter;
+    }
+    super.visitSimpleFormalParameter(node);
+    (node.element as ElementImpl).metadata =
+        _createElementAnnotations(node.metadata);
+    return null;
+  }
+
+  @override
+  Object visitSwitchCase(SwitchCase node) {
+    for (Label label in node.labels) {
+      SimpleIdentifier labelName = label.label;
+      LabelElementImpl element =
+          new LabelElementImpl.forNode(labelName, false, true);
+      _currentHolder.addLabel(element);
+      labelName.staticElement = element;
+    }
+    return super.visitSwitchCase(node);
+  }
+
+  @override
+  Object visitSwitchDefault(SwitchDefault node) {
+    for (Label label in node.labels) {
+      SimpleIdentifier labelName = label.label;
+      LabelElementImpl element =
+          new LabelElementImpl.forNode(labelName, false, true);
+      _currentHolder.addLabel(element);
+      labelName.staticElement = element;
+    }
+    return super.visitSwitchDefault(node);
+  }
+
+  @override
+  Object visitTypeParameter(TypeParameter node) {
+    SimpleIdentifier parameterName = node.name;
+    TypeParameterElementImpl typeParameter =
+        new TypeParameterElementImpl.forNode(parameterName);
+    _setCodeRange(typeParameter, node);
+    typeParameter.metadata = _createElementAnnotations(node.metadata);
+    TypeParameterTypeImpl typeParameterType =
+        new TypeParameterTypeImpl(typeParameter);
+    typeParameter.type = typeParameterType;
+    _currentHolder.addTypeParameter(typeParameter);
+    parameterName.staticElement = typeParameter;
+    return super.visitTypeParameter(node);
+  }
+
+  @override
+  Object visitVariableDeclaration(VariableDeclaration node) {
+    bool isConst = node.isConst;
+    bool isFinal = node.isFinal;
+    bool hasInitializer = node.initializer != null;
+    VariableDeclarationList varList = node.parent;
+    FieldDeclaration fieldNode =
+        varList.parent is FieldDeclaration ? varList.parent : null;
+    VariableElementImpl element;
+    if (fieldNode != null) {
+      SimpleIdentifier fieldName = node.name;
+      FieldElementImpl field;
+      if ((isConst || isFinal && !fieldNode.isStatic) && hasInitializer) {
+        field = new ConstFieldElementImpl.forNode(fieldName);
+      } else {
+        field = new FieldElementImpl.forNode(fieldName);
+      }
+      element = field;
+      field.static = fieldNode.isStatic;
+      _setCodeRange(element, node);
+      setElementDocumentationComment(element, fieldNode);
+      field.hasImplicitType = varList.type == null;
+      _currentHolder.addField(field);
+      fieldName.staticElement = field;
+    } else if (_inFunction) {
+      SimpleIdentifier variableName = node.name;
+      LocalVariableElementImpl variable;
+      if (isConst && hasInitializer) {
+        variable = new ConstLocalVariableElementImpl.forNode(variableName);
+      } else {
+        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.
+      variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
+      variable.hasImplicitType = varList.type == null;
+      _currentHolder.addLocalVariable(variable);
+      variableName.staticElement = element;
+    } else {
+      SimpleIdentifier variableName = node.name;
+      TopLevelVariableElementImpl variable;
+      if (isConst && hasInitializer) {
+        variable = new ConstTopLevelVariableElementImpl.forNode(variableName);
+      } else {
+        variable = new TopLevelVariableElementImpl.forNode(variableName);
+      }
+      element = variable;
+      _setCodeRange(element, node);
+      if (varList.parent is TopLevelVariableDeclaration) {
+        setElementDocumentationComment(element, varList.parent);
+      }
+      variable.hasImplicitType = varList.type == null;
+      _currentHolder.addTopLevelVariable(variable);
+      variableName.staticElement = element;
+    }
+    element.const3 = isConst;
+    element.final2 = isFinal;
+    if (hasInitializer) {
+      ElementHolder holder = new ElementHolder();
+      _visit(holder, node.initializer);
+      FunctionElementImpl initializer =
+          new FunctionElementImpl.forOffset(node.initializer.beginToken.offset);
+      initializer.hasImplicitReturnType = true;
+      initializer.functions = holder.functions;
+      initializer.labels = holder.labels;
+      initializer.localVariables = holder.localVariables;
+      initializer.synthetic = true;
+      initializer.type = new FunctionTypeImpl(initializer);
+      element.initializer = initializer;
+      holder.validate();
+    }
+    if (element is PropertyInducingElementImpl) {
+      PropertyAccessorElementImpl getter =
+          new PropertyAccessorElementImpl.forVariable(element);
+      getter.getter = true;
+      if (element.hasImplicitType) {
+        getter.hasImplicitReturnType = true;
+      }
+      _currentHolder.addAccessor(getter);
+      element.getter = getter;
+      if (!isConst && !isFinal) {
+        PropertyAccessorElementImpl setter =
+            new PropertyAccessorElementImpl.forVariable(element);
+        setter.setter = true;
+        ParameterElementImpl parameter =
+            new ParameterElementImpl("_${element.name}", element.nameOffset);
+        parameter.synthetic = true;
+        parameter.parameterKind = ParameterKind.REQUIRED;
+        setter.parameters = <ParameterElement>[parameter];
+        _currentHolder.addAccessor(setter);
+        element.setter = setter;
+      }
+    }
+    return null;
+  }
+
+  @override
+  Object visitVariableDeclarationList(VariableDeclarationList node) {
+    super.visitVariableDeclarationList(node);
+    AstNode parent = node.parent;
+    List<ElementAnnotation> elementAnnotations;
+    if (parent is FieldDeclaration) {
+      elementAnnotations = _createElementAnnotations(parent.metadata);
+    } else if (parent is TopLevelVariableDeclaration) {
+      elementAnnotations = _createElementAnnotations(parent.metadata);
+    } else {
+      // Local variable declaration
+      elementAnnotations = _createElementAnnotations(node.metadata);
+    }
+    for (VariableDeclaration variableDeclaration in node.variables) {
+      ElementImpl element = variableDeclaration.element as ElementImpl;
+      _setCodeRange(element, node.parent);
+      element.metadata = elementAnnotations;
+    }
+    return null;
+  }
+
+  /**
+   * Build the table mapping field names to field elements for the fields defined in the current
+   * class.
+   *
+   * @param fields the field elements defined in the current class
+   */
+  void _buildFieldMap(List<FieldElement> fields) {
+    _fieldMap = new HashMap<String, FieldElement>();
+    int count = fields.length;
+    for (int i = 0; i < count; i++) {
+      FieldElement field = fields[i];
+      _fieldMap[field.name] = field;
+    }
+  }
+
+  /**
+   * Creates the [ConstructorElement]s array with the single default constructor element.
+   *
+   * @param interfaceType the interface type for which to create a default constructor
+   * @return the [ConstructorElement]s array with the single default constructor element
+   */
+  List<ConstructorElement> _createDefaultConstructors(
+      ClassElementImpl definingClass) {
+    ConstructorElementImpl constructor =
+        new ConstructorElementImpl.forNode(null);
+    constructor.synthetic = true;
+    constructor.returnType = definingClass.type;
+    constructor.enclosingElement = definingClass;
+    constructor.type = new FunctionTypeImpl(constructor);
+    return <ConstructorElement>[constructor];
+  }
+
+  /**
+   * For each [Annotation] found in [annotations], create a new
+   * [ElementAnnotation] object and set the [Annotation] to point to it.
+   */
+  List<ElementAnnotation> _createElementAnnotations(
+      NodeList<Annotation> annotations) {
+    if (annotations.isEmpty) {
+      return ElementAnnotation.EMPTY_LIST;
+    }
+    return annotations.map((Annotation a) {
+      ElementAnnotationImpl elementAnnotation =
+          new ElementAnnotationImpl(compilationUnitElement);
+      a.elementAnnotation = elementAnnotation;
+      return elementAnnotation;
+    }).toList();
+  }
+
+  /**
+   * Create the types associated with the given type parameters, setting the type of each type
+   * parameter, and return an array of types corresponding to the given parameters.
+   *
+   * @param typeParameters the type parameters for which types are to be created
+   * @return an array of types corresponding to the given parameters
+   */
+  List<DartType> _createTypeParameterTypes(
+      List<TypeParameterElement> typeParameters) {
+    int typeParameterCount = typeParameters.length;
+    List<DartType> typeArguments = new List<DartType>(typeParameterCount);
+    for (int i = 0; i < typeParameterCount; i++) {
+      TypeParameterElementImpl typeParameter =
+          typeParameters[i] as TypeParameterElementImpl;
+      TypeParameterTypeImpl typeParameterType =
+          new TypeParameterTypeImpl(typeParameter);
+      typeParameter.type = typeParameterType;
+      typeArguments[i] = typeParameterType;
+    }
+    return typeArguments;
+  }
+
+  /**
+   * Return the body of the function that contains the given [parameter], or
+   * `null` if no function body could be found.
+   */
+  FunctionBody _getFunctionBody(FormalParameter parameter) {
+    AstNode parent = parameter?.parent?.parent;
+    if (parent is ConstructorDeclaration) {
+      return parent.body;
+    } else if (parent is FunctionExpression) {
+      return parent.body;
+    } else if (parent is MethodDeclaration) {
+      return parent.body;
+    }
+    return null;
+  }
+
+  void _setCodeRange(ElementImpl element, AstNode node) {
+    element.setCodeRange(node.offset, node.length);
+  }
+
+  /**
+   * Sets the visible source range for formal parameter.
+   */
+  void _setParameterVisibleRange(
+      FormalParameter node, ParameterElementImpl element) {
+    FunctionBody body = _getFunctionBody(node);
+    if (body is BlockFunctionBody || body is ExpressionFunctionBody) {
+      element.setVisibleRange(body.offset, body.length);
+    }
+  }
+
+  /**
+   * Make the given holder be the current holder while visiting the given node.
+   *
+   * @param holder the holder that will gather elements that are built while visiting the children
+   * @param node the node to be visited
+   */
+  void _visit(ElementHolder holder, AstNode node) {
+    if (node != null) {
+      ElementHolder previousHolder = _currentHolder;
+      _currentHolder = holder;
+      try {
+        node.accept(this);
+      } finally {
+        _currentHolder = previousHolder;
+      }
+    }
+  }
+
+  /**
+   * Make the given holder be the current holder while visiting the children of the given node.
+   *
+   * @param holder the holder that will gather elements that are built while visiting the children
+   * @param node the node whose children are to be visited
+   */
+  void _visitChildren(ElementHolder holder, AstNode node) {
+    if (node != null) {
+      ElementHolder previousHolder = _currentHolder;
+      _currentHolder = holder;
+      try {
+        node.visitChildren(this);
+      } finally {
+        _currentHolder = previousHolder;
+      }
+    }
+  }
+}
+
+class _ElementBuilder_visitClassDeclaration extends UnifyingAstVisitor<Object> {
+  final ElementBuilder builder;
+
+  List<ClassMember> nonFields;
+
+  _ElementBuilder_visitClassDeclaration(this.builder, this.nonFields) : super();
+
+  @override
+  Object visitConstructorDeclaration(ConstructorDeclaration node) {
+    nonFields.add(node);
+    return null;
+  }
+
+  @override
+  Object visitMethodDeclaration(MethodDeclaration node) {
+    nonFields.add(node);
+    return null;
+  }
+
+  @override
+  Object visitNode(AstNode node) => node.accept(builder);
+}
+
+/**
+ * Instances of the class [_NamespaceCombinatorBuilder] can be used to visit
+ * [Combinator] AST nodes and generate [NamespaceCombinator] elements.
+ */
+class _NamespaceCombinatorBuilder extends SimpleAstVisitor<Object> {
+  /**
+   * Elements generated so far.
+   */
+  final List<NamespaceCombinator> combinators = <NamespaceCombinator>[];
+
+  @override
+  Object visitHideCombinator(HideCombinator node) {
+    HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
+    hide.hiddenNames = _getIdentifiers(node.hiddenNames);
+    combinators.add(hide);
+    return null;
+  }
+
+  @override
+  Object visitShowCombinator(ShowCombinator node) {
+    ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
+    show.offset = node.offset;
+    show.end = node.end;
+    show.shownNames = _getIdentifiers(node.shownNames);
+    combinators.add(show);
+    return null;
+  }
+
+  /**
+   * Return the lexical identifiers associated with the given [identifiers].
+   */
+  static List<String> _getIdentifiers(NodeList<SimpleIdentifier> identifiers) {
+    return identifiers.map((identifier) => identifier.name).toList();
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 71030e7..e3f4dfe 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -7,19 +7,21 @@
 import 'dart:collection';
 import 'dart:math' show min;
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.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, AnalysisException;
+    show AnalysisContext, AnalysisEngine;
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart' show Keyword;
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart';
@@ -84,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;
 
   /**
@@ -100,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;
 
   /**
@@ -113,11 +119,6 @@
   List<TypeParameterElement> _typeParameters = TypeParameterElement.EMPTY_LIST;
 
   /**
-   * The [SourceRange] of the `with` clause, `null` if there is no one.
-   */
-  SourceRange withClauseRange;
-
-  /**
    * A flag indicating whether the types associated with the instance members of
    * this class have been inferred.
    */
@@ -335,7 +336,22 @@
   }
 
   @override
-  bool get isValidMixin => hasModifier(Modifier.MIXIN);
+  bool get isValidMixin {
+    if (!context.analysisOptions.enableSuperMixins) {
+      if (hasReferenceToSuper) {
+        return false;
+      }
+      if (!supertype.isObject) {
+        return false;
+      }
+    }
+    for (ConstructorElement constructor in constructors) {
+      if (!constructor.isSynthetic && !constructor.isFactory) {
+        return false;
+      }
+    }
+    return true;
+  }
 
   @override
   ElementKind get kind => ElementKind.CLASS;
@@ -385,13 +401,6 @@
     return null;
   }
 
-  /**
-   * Set whether this class is a valid mixin.
-   */
-  void set validMixin(bool isValidMixin) {
-    setModifier(Modifier.MIXIN, isValidMixin);
-  }
-
   @override
   accept(ElementVisitor visitor) => visitor.visitClassElement(this);
 
@@ -701,7 +710,6 @@
           new ConstructorElementImpl(superclassConstructor.name, -1);
       implicitConstructor.synthetic = true;
       implicitConstructor.redirectedConstructor = superclassConstructor;
-      implicitConstructor.const2 = superclassConstructor.isConst;
       implicitConstructor.returnType = type;
       List<ParameterElement> superParameters = superclassConstructor.parameters;
       int count = superParameters.length;
@@ -907,6 +915,7 @@
   /**
    * The source that corresponds to this compilation unit.
    */
+  @override
   Source source;
 
   /**
@@ -1212,7 +1221,7 @@
   ConstFieldElementImpl.forNode(Identifier name) : super.forNode(name);
 
   @override
-  DartObject get constantValue => _result.value;
+  DartObject get constantValue => _result?.value;
 
   @override
   EvaluationResultImpl get evaluationResult => _result;
@@ -1246,7 +1255,7 @@
   ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
 
   @override
-  DartObject get constantValue => _result.value;
+  DartObject get constantValue => _result?.value;
 
   @override
   EvaluationResultImpl get evaluationResult => _result;
@@ -1391,13 +1400,21 @@
   EvaluationResultImpl _result;
 
   /**
+   * Initialize a newly created synthetic top-level variable element to have the
+   * given [name] and [offset].
+   */
+  ConstTopLevelVariableElementImpl(String name, int offset)
+      : super(name, offset);
+
+  /**
    * Initialize a newly created top-level variable element to have the given
    * [name].
    */
-  ConstTopLevelVariableElementImpl(Identifier name) : super.forNode(name);
+  ConstTopLevelVariableElementImpl.forNode(Identifier name)
+      : super.forNode(name);
 
   @override
-  DartObject get constantValue => _result.value;
+  DartObject get constantValue => _result?.value;
 
   @override
   EvaluationResultImpl get evaluationResult => _result;
@@ -1443,12 +1460,20 @@
   EvaluationResultImpl _result;
 
   /**
+   * Initialize a newly created parameter element to have the given [name] and
+   * [nameOffset].
+   */
+  DefaultFieldFormalParameterElementImpl(String name, int nameOffset)
+      : super(name, nameOffset);
+
+  /**
    * Initialize a newly created parameter element to have the given [name].
    */
-  DefaultFieldFormalParameterElementImpl(Identifier name) : super(name);
+  DefaultFieldFormalParameterElementImpl.forNode(Identifier name)
+      : super.forNode(name);
 
   @override
-  DartObject get constantValue => _result.value;
+  DartObject get constantValue => _result?.value;
 
   @override
   EvaluationResultImpl get evaluationResult => _result;
@@ -1470,12 +1495,19 @@
   EvaluationResultImpl _result;
 
   /**
+   * Initialize a newly created parameter element to have the given [name] and
+   * [nameOffset].
+   */
+  DefaultParameterElementImpl(String name, int nameOffset)
+      : super(name, nameOffset);
+
+  /**
    * Initialize a newly created parameter element to have the given [name].
    */
-  DefaultParameterElementImpl(Identifier name) : super.forNode(name);
+  DefaultParameterElementImpl.forNode(Identifier name) : super.forNode(name);
 
   @override
-  DartObject get constantValue => _result.value;
+  DartObject get constantValue => _result?.value;
 
   @override
   EvaluationResultImpl get evaluationResult => _result;
@@ -1536,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.
    */
@@ -1551,7 +1594,18 @@
    * The element representing the field, variable, or constructor being used as
    * an annotation.
    */
-  final Element element;
+  Element element;
+
+  /**
+   * The compilation unit in which this annotation appears.
+   */
+  final CompilationUnitElementImpl compilationUnit;
+
+  /**
+   * The AST of the annotation itself, cloned from the resolved AST for the
+   * source code.
+   */
+  Annotation annotationAst;
 
   /**
    * The result of evaluating this annotation as a compile-time constant
@@ -1561,62 +1615,54 @@
   EvaluationResultImpl evaluationResult;
 
   /**
-   * Initialize a newly created annotation. The given [element] is the element
-   * representing the field, variable, or constructor being used as an
-   * annotation.
+   * Initialize a newly created annotation. The given [compilationUnit] is the
+   * compilation unit in which the annotation appears.
    */
-  ElementAnnotationImpl(this.element);
+  ElementAnnotationImpl(this.compilationUnit);
 
   @override
-  DartObject get constantValue => evaluationResult.value;
+  DartObject get constantValue => evaluationResult?.value;
+
+  @override
+  AnalysisContext get context => compilationUnit.library.context;
 
   @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.
+   */
+  Source get librarySource => compilationUnit.librarySource;
+
+  @override
+  Source get source => compilationUnit.source;
 
   @override
   String toString() => '@$element';
@@ -1689,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].
    */
@@ -1702,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) {
@@ -1736,11 +1804,12 @@
 
   /**
    * Set the enclosing element of this element to the given [element].
+   *
+   * Throws [FrozenHashCodeException] if the hashCode can't be changed.
    */
   void set enclosingElement(Element element) {
     _enclosingElement = element as ElementImpl;
-    _cachedLocation = null;
-    _cachedHashCode = null;
+    _updateCaches();
   }
 
   @override
@@ -1748,13 +1817,7 @@
     // TODO: We might want to re-visit this optimization in the future.
     // We cache the hash code value as this is a very frequently called method.
     if (_cachedHashCode == null) {
-      int hashIdentifier = identifier.hashCode;
-      Element enclosing = enclosingElement;
-      if (enclosing != null) {
-        _cachedHashCode = hashIdentifier + enclosing.hashCode;
-      } else {
-        _cachedHashCode = hashIdentifier;
-      }
+      _cachedHashCode = location.hashCode;
     }
     return _cachedHashCode;
   }
@@ -1795,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
@@ -1818,10 +1891,14 @@
   @override
   String get name => _name;
 
+  /**
+   * Changes the name of this element.
+   *
+   * Throws [FrozenHashCodeException] if the hashCode can't be changed.
+   */
   void set name(String name) {
     this._name = name;
-    _cachedLocation = null;
-    _cachedHashCode = null;
+    _updateCaches();
   }
 
   @override
@@ -1833,11 +1910,12 @@
   /**
    * Sets the offset of the name of this element in the file that contains the
    * declaration of this element.
+   *
+   * Throws [FrozenHashCodeException] if the hashCode can't be changed.
    */
   void set nameOffset(int offset) {
     _nameOffset = offset;
-    _cachedHashCode = null;
-    _cachedLocation = null;
+    _updateCaches();
   }
 
   @override
@@ -1972,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) {
@@ -1998,6 +2084,35 @@
   void visitChildren(ElementVisitor visitor) {
     // There are no children to visit
   }
+
+  /**
+   *  Updates cached values after an input changed.
+   *
+   *  Throws [FrozenHashCodeException] if not allowed.
+   */
+  void _updateCaches() {
+    if (!hasModifier(Modifier.CACHE_KEY)) {
+      // Fast path.
+      _cachedLocation = null;
+      _cachedHashCode = null;
+      return;
+    }
+
+    // Save originals.
+    ElementLocation oldLocation = _cachedLocation;
+    int oldHashCode = _cachedHashCode;
+
+    _cachedLocation = null;
+    _cachedHashCode = null;
+
+    if (oldHashCode != hashCode) {
+      // Prevent cache corruption by restoring originals.
+      _cachedLocation = oldLocation;
+      _cachedHashCode = oldHashCode;
+      throw new FrozenHashCodeException(
+          "can't update hashCode for a cache key: $this ($runtimeType)");
+    }
+  }
 }
 
 /**
@@ -2507,9 +2622,17 @@
   FieldElement field;
 
   /**
+   * Initialize a newly created parameter element to have the given [name] and
+   * [nameOffset].
+   */
+  FieldFormalParameterElementImpl(String name, int nameOffset)
+      : super(name, nameOffset);
+
+  /**
    * Initialize a newly created parameter element to have the given [name].
    */
-  FieldFormalParameterElementImpl(Identifier name) : super.forNode(name);
+  FieldFormalParameterElementImpl.forNode(Identifier name)
+      : super.forNode(name);
 
   @override
   bool get isInitializingFormal => true;
@@ -2520,6 +2643,18 @@
 }
 
 /**
+ * Indicates that an ElementImpl's hashCode cannot currently be changed.
+ */
+class FrozenHashCodeException implements Exception {
+  final String _message;
+
+  FrozenHashCodeException(this._message);
+
+  @override
+  String toString() => "FrozenHashCodeException($_message)";
+}
+
+/**
  * A concrete implementation of a [FunctionElement].
  */
 class FunctionElementImpl extends ExecutableElementImpl
@@ -2880,7 +3015,17 @@
    * `switch` statement and [onSwitchMember] should be `true` if this label is
    * associated with a `switch` member.
    */
-  LabelElementImpl(
+  LabelElementImpl(String name, int nameOffset, this._onSwitchStatement,
+      this._onSwitchMember)
+      : super(name, nameOffset);
+
+  /**
+   * Initialize a newly created label element to have the given [name].
+   * [onSwitchStatement] should be `true` if this label is associated with a
+   * `switch` statement and [onSwitchMember] should be `true` if this label is
+   * associated with a `switch` member.
+   */
+  LabelElementImpl.forNode(
       Identifier name, this._onSwitchStatement, this._onSwitchMember)
       : super.forNode(name);
 
@@ -2992,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;
 
@@ -3042,9 +3205,6 @@
   }
 
   @override
-  int get hashCode => _definingCompilationUnit.hashCode;
-
-  @override
   bool get hasLoadLibraryFunction {
     if (_definingCompilationUnit.hasLoadLibraryFunction) {
       return true;
@@ -3095,6 +3255,9 @@
       entryPoint != null && isOrImportsBrowserLibrary;
 
   @override
+  bool get isDartAsync => name == "dart.async";
+
+  @override
   bool get isDartCore => name == "dart.core";
 
   @override
@@ -3135,6 +3298,7 @@
   @override
   LibraryElement get library => this;
 
+  @override
   List<LibraryElement> get libraryCycle {
     if (_libraryCycle != null) {
       return _libraryCycle;
@@ -3156,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,
@@ -3173,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);
 
@@ -3256,11 +3433,6 @@
   }
 
   @override
-  bool operator ==(Object object) =>
-      object is LibraryElementImpl &&
-      _definingCompilationUnit == object.definingCompilationUnit;
-
-  @override
   accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
 
   /**
@@ -3499,12 +3671,10 @@
   }
 
   @override
-  bool get isPotentiallyMutatedInClosure =>
-      hasModifier(Modifier.POTENTIALLY_MUTATED_IN_CONTEXT);
+  bool get isPotentiallyMutatedInClosure => true;
 
   @override
-  bool get isPotentiallyMutatedInScope =>
-      hasModifier(Modifier.POTENTIALLY_MUTATED_IN_SCOPE);
+  bool get isPotentiallyMutatedInScope => true;
 
   @override
   ElementKind get kind => ElementKind.LOCAL_VARIABLE;
@@ -3532,20 +3702,6 @@
       getNodeMatching((node) => node is VariableDeclaration);
 
   /**
-   * Specifies that this variable is potentially mutated somewhere in closure.
-   */
-  void markPotentiallyMutatedInClosure() {
-    setModifier(Modifier.POTENTIALLY_MUTATED_IN_CONTEXT, true);
-  }
-
-  /**
-   * Specifies that this variable is potentially mutated somewhere in its scope.
-   */
-  void markPotentiallyMutatedInScope() {
-    setModifier(Modifier.POTENTIALLY_MUTATED_IN_SCOPE, true);
-  }
-
-  /**
    * Set the visible range for this element to the range starting at the given
    * [offset] with the given [length].
    */
@@ -3641,6 +3797,142 @@
 }
 
 /**
+ * The enumeration `Modifier` defines constants for all of the modifiers defined
+ * by the Dart language and for a few additional flags that are useful.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class Modifier extends Enum<Modifier> {
+  /**
+   * Indicates that the modifier 'abstract' was applied to the element.
+   */
+  static const Modifier ABSTRACT = const Modifier('ABSTRACT', 0);
+
+  /**
+   * Indicates that an executable element has a body marked as being
+   * asynchronous.
+   */
+  static const Modifier ASYNCHRONOUS = const Modifier('ASYNCHRONOUS', 1);
+
+  /**
+   * Indicates that the modifier 'const' was applied to the element.
+   */
+  static const Modifier CONST = const Modifier('CONST', 2);
+
+  /**
+   * Indicates that the import element represents a deferred library.
+   */
+  static const Modifier DEFERRED = const Modifier('DEFERRED', 3);
+
+  /**
+   * Indicates that a class element was defined by an enum declaration.
+   */
+  static const Modifier ENUM = const Modifier('ENUM', 4);
+
+  /**
+   * Indicates that a class element was defined by an enum declaration.
+   */
+  static const Modifier EXTERNAL = const Modifier('EXTERNAL', 5);
+
+  /**
+   * Indicates that the modifier 'factory' was applied to the element.
+   */
+  static const Modifier FACTORY = const Modifier('FACTORY', 6);
+
+  /**
+   * Indicates that the modifier 'final' was applied to the element.
+   */
+  static const Modifier FINAL = const Modifier('FINAL', 7);
+
+  /**
+   * Indicates that an executable element has a body marked as being a
+   * generator.
+   */
+  static const Modifier GENERATOR = const Modifier('GENERATOR', 8);
+
+  /**
+   * Indicates that the pseudo-modifier 'get' was applied to the element.
+   */
+  static const Modifier GETTER = const Modifier('GETTER', 9);
+
+  /**
+   * A flag used for libraries indicating that the defining compilation unit
+   * contains at least one import directive whose URI uses the "dart-ext"
+   * scheme.
+   */
+  static const Modifier HAS_EXT_URI = const Modifier('HAS_EXT_URI', 10);
+
+  /**
+   * Indicates that the associated element did not have an explicit type
+   * associated with it. If the element is an [ExecutableElement], then the
+   * type being referred to is the return type.
+   */
+  static const Modifier IMPLICIT_TYPE = const Modifier('IMPLICIT_TYPE', 11);
+
+  /**
+   * Indicates that a class is a mixin application.
+   */
+  static const Modifier MIXIN_APPLICATION =
+      const Modifier('MIXIN_APPLICATION', 12);
+
+  /**
+   * Indicates that a class contains an explicit reference to 'super'.
+   */
+  static const Modifier REFERENCES_SUPER =
+      const Modifier('REFERENCES_SUPER', 13);
+
+  /**
+   * Indicates that the pseudo-modifier 'set' was applied to the element.
+   */
+  static const Modifier SETTER = const Modifier('SETTER', 14);
+
+  /**
+   * Indicates that the modifier 'static' was applied to the element.
+   */
+  static const Modifier STATIC = const Modifier('STATIC', 15);
+
+  /**
+   * Indicates that the element does not appear in the source code but was
+   * implicitly created. For example, if a class does not define any
+   * constructors, an implicit zero-argument constructor will be created and it
+   * will be marked as being synthetic.
+   */
+  static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 16);
+
+  /**
+   * Indicates that this element is being used as an analyzer cache key.
+   */
+  static const Modifier CACHE_KEY = const Modifier('CACHE_KEY', 17);
+
+  static const List<Modifier> persistedValues = const [
+    ABSTRACT,
+    ASYNCHRONOUS,
+    CONST,
+    DEFERRED,
+    ENUM,
+    EXTERNAL,
+    FACTORY,
+    FINAL,
+    GENERATOR,
+    GETTER,
+    HAS_EXT_URI,
+    IMPLICIT_TYPE,
+    MIXIN_APPLICATION,
+    REFERENCES_SUPER,
+    SETTER,
+    STATIC,
+    SYNTHETIC
+  ];
+
+  static const List<Modifier> transientValues = const [CACHE_KEY];
+
+  static final values = new List.unmodifiable(
+      []..addAll(persistedValues)..addAll(transientValues));
+
+  const Modifier(String name, int ordinal) : super(name, ordinal);
+}
+
+/**
  * A concrete implementation of a [MultiplyDefinedElement].
  */
 class MultiplyDefinedElementImpl implements MultiplyDefinedElement {
@@ -3700,6 +3992,9 @@
   }
 
   @override
+  bool get isProtected => false;
+
+  @override
   bool get isPublic => !isPrivate;
 
   @override
@@ -3926,7 +4221,7 @@
 
   /**
    * Initialize a newly created parameter element to have the given [name] and
-   * [offset].
+   * [nameOffset].
    */
   ParameterElementImpl(String name, int nameOffset) : super(name, nameOffset);
 
@@ -3935,6 +4230,18 @@
    */
   ParameterElementImpl.forNode(Identifier name) : super.forNode(name);
 
+  /**
+   * Creates a synthetic parameter with [name], [type] and [kind].
+   */
+  factory ParameterElementImpl.synthetic(
+      String name, DartType type, ParameterKind kind) {
+    ParameterElementImpl element = new ParameterElementImpl(name, -1);
+    element.type = type;
+    element.synthetic = true;
+    element.parameterKind = kind;
+    return element;
+  }
+
   @override
   String get defaultValueCode => _defaultValueCode;
 
@@ -3949,12 +4256,10 @@
   bool get isInitializingFormal => false;
 
   @override
-  bool get isPotentiallyMutatedInClosure =>
-      hasModifier(Modifier.POTENTIALLY_MUTATED_IN_CONTEXT);
+  bool get isPotentiallyMutatedInClosure => true;
 
   @override
-  bool get isPotentiallyMutatedInScope =>
-      hasModifier(Modifier.POTENTIALLY_MUTATED_IN_SCOPE);
+  bool get isPotentiallyMutatedInScope => true;
 
   @override
   ElementKind get kind => ElementKind.PARAMETER;
@@ -4032,20 +4337,6 @@
   }
 
   /**
-   * Specifies that this variable is potentially mutated somewhere in closure.
-   */
-  void markPotentiallyMutatedInClosure() {
-    setModifier(Modifier.POTENTIALLY_MUTATED_IN_CONTEXT, true);
-  }
-
-  /**
-   * Specifies that this variable is potentially mutated somewhere in its scope.
-   */
-  void markPotentiallyMutatedInScope() {
-    setModifier(Modifier.POTENTIALLY_MUTATED_IN_SCOPE, true);
-  }
-
-  /**
    * Set the visible range for this element to the range starting at the given
    * [offset] with the given [length].
    */
@@ -4088,11 +4379,6 @@
  */
 class PrefixElementImpl extends ElementImpl implements PrefixElement {
   /**
-   * A list containing all of the libraries that are imported using this prefix.
-   */
-  List<LibraryElement> _importedLibraries = LibraryElement.EMPTY_LIST;
-
-  /**
    * Initialize a newly created method element to have the given [name] and
    * [offset].
    */
@@ -4111,18 +4397,7 @@
   String get identifier => "_${super.identifier}";
 
   @override
-  List<LibraryElement> get importedLibraries => _importedLibraries;
-
-  /**
-   * Set the libraries that are imported using this prefix to the given
-   * [libraries].
-   */
-  void set importedLibraries(List<LibraryElement> libraries) {
-    for (LibraryElement library in libraries) {
-      (library as LibraryElementImpl).enclosingElement = this;
-    }
-    _importedLibraries = libraries;
-  }
+  List<LibraryElement> get importedLibraries => LibraryElement.EMPTY_LIST;
 
   @override
   ElementKind get kind => ElementKind.PREFIX;
@@ -4408,6 +4683,14 @@
    */
   TypeParameterElementImpl.forNode(Identifier name) : super.forNode(name);
 
+  /**
+   * Initialize a newly created synthetic type parameter element to have the
+   * given [name], and with [synthetic] set to true.
+   */
+  TypeParameterElementImpl.synthetic(String name) : super(name, -1) {
+    synthetic = true;
+  }
+
   @override
   ElementKind get kind => ElementKind.TYPE_PARAMETER;
 
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 75dcee6..28bce1e 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -4,15 +4,15 @@
 
 library analyzer.src.dart.element.member;
 
+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/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/constant.dart'
     show DartObject, EvaluationResultImpl;
 import 'package:analyzer/src/generated/engine.dart'
-    show AnalysisContext, AnalysisEngine, AnalysisException;
+    show AnalysisContext, AnalysisEngine;
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -128,8 +128,7 @@
  * type parameters are known.
  */
 abstract class ExecutableMember extends Member implements ExecutableElement {
-  @override
-  final FunctionType type;
+  FunctionType _type;
 
   /**
    * Initialize a newly created element to represent a callable element (like a
@@ -139,9 +138,7 @@
    */
   ExecutableMember(ExecutableElement baseElement, InterfaceType definingType,
       [FunctionType type])
-      : type = type ??
-            baseElement.type.substitute2(definingType.typeArguments,
-                TypeParameterTypeImpl.getTypes(definingType.typeParameters)),
+      : _type = type,
         super(baseElement, definingType);
 
   @override
@@ -201,6 +198,12 @@
   DartType get returnType => type.returnType;
 
   @override
+  FunctionType get type {
+    return _type ??= baseElement.type.substitute2(definingType.typeArguments,
+        TypeParameterTypeImpl.getTypes(definingType.typeParameters));
+  }
+
+  @override
   List<TypeParameterElement> get typeParameters => baseElement.typeParameters;
 
   @override
@@ -452,6 +455,7 @@
   @override
   String get documentationComment => _baseElement.documentationComment;
 
+  @override
   int get id => _baseElement.id;
 
   @override
@@ -464,6 +468,9 @@
   bool get isPrivate => _baseElement.isPrivate;
 
   @override
+  bool get isProtected => _baseElement.isProtected;
+
+  @override
   bool get isPublic => _baseElement.isPublic;
 
   @override
@@ -898,6 +905,68 @@
 }
 
 /**
+ * A type parameter defined inside of another parameterized type, where the
+ * values of the enclosing type parameters are known.
+ *
+ * For example:
+ *
+ *     class C<T> {
+ *       S m<S extends T>(S s);
+ *     }
+ *
+ * If we have `C<num>.m` and we ask for the type parameter "S", we should get
+ * `<S extends num>` instead of `<S extends T>`. This is how the parameter
+ * and return types work, see: [FunctionType.parameters],
+ * [FunctionType.returnType], and [ParameterMember].
+ */
+class TypeParameterMember extends Member implements TypeParameterElement {
+  @override
+  final DartType bound;
+
+  TypeParameterMember(
+      TypeParameterElement baseElement, DartType definingType, this.bound)
+      : super(baseElement, definingType);
+
+  @override
+  TypeParameterElement get baseElement =>
+      super.baseElement as TypeParameterElement;
+
+  @override
+  Element get enclosingElement => baseElement.enclosingElement;
+
+  @override
+  TypeParameterType get type => baseElement.type;
+
+  @override
+  accept(ElementVisitor visitor) => visitor.visitTypeParameterElement(this);
+
+  /**
+   * If the given [parameter]'s type is different when any type parameters from
+   * the defining type's declaration are replaced with the actual type
+   * arguments from the [definingType], create a parameter member representing
+   * the given parameter. Return the member that was created, or the base
+   * parameter if no member was created.
+   */
+  static TypeParameterElement from(
+      TypeParameterElement parameter, ParameterizedType definingType) {
+    if (parameter?.bound == null || definingType.typeArguments.isEmpty) {
+      return parameter;
+    }
+
+    DartType bound = parameter.bound;
+    List<DartType> argumentTypes = definingType.typeArguments;
+    List<DartType> parameterTypes =
+        TypeParameterTypeImpl.getTypes(definingType.typeParameters);
+    DartType substitutedBound =
+        bound.substitute2(argumentTypes, parameterTypes);
+    if (bound == substitutedBound) {
+      return parameter;
+    }
+    return new TypeParameterMember(parameter, definingType, substitutedBound);
+  }
+}
+
+/**
  * A variable element defined in a parameterized type where the values of the
  * type parameters are known.
  */
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index b804339..29658fb 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -6,29 +6,31 @@
 
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/token.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/src/dart/element/member.dart';
 import 'package:analyzer/src/generated/engine.dart'
-    show AnalysisContext, AnalysisEngine, AnalysisException;
+    show AnalysisContext, AnalysisEngine;
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/scanner.dart' show Keyword;
+import 'package:analyzer/src/generated/type_system.dart';
+import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
 /**
+ * Type of callbacks used by [DeferredFunctionTypeImpl].
+ */
+typedef FunctionTypedElement FunctionTypedElementComputer();
+
+/**
  * A [Type] that represents the type 'bottom'.
  */
 class BottomTypeImpl extends TypeImpl {
   /**
    * The unique instance of this class.
    */
-  static BottomTypeImpl _INSTANCE = new BottomTypeImpl._();
-
-  /**
-   * Return the unique instance of this class.
-   */
-  static BottomTypeImpl get instance => _INSTANCE;
+  static final BottomTypeImpl instance = new BottomTypeImpl._();
 
   /**
    * Prevent the creation of instances of this class.
@@ -89,18 +91,48 @@
 }
 
 /**
+ * The type of a function, method, constructor, getter, or setter that has been
+ * resynthesized from a summary.  The actual underlying element won't be
+ * constructed until it's needed.
+ */
+class DeferredFunctionTypeImpl extends FunctionTypeImpl {
+  /**
+   * Callback which should be invoked when the element associated with this
+   * function type is needed.
+   *
+   * Once the callback has been invoked, it is set to `null` to reduce GC
+   * pressure.
+   */
+  FunctionTypedElementComputer _computeElement;
+
+  /**
+   * If [_computeElement] has been called, the value it returned.  Otherwise
+   * `null`.
+   */
+  FunctionTypedElement _computedElement;
+
+  DeferredFunctionTypeImpl(this._computeElement, String name,
+      List<DartType> typeArguments, bool isInstantiated)
+      : super._(null, name, null, typeArguments, isInstantiated);
+
+  @override
+  FunctionTypedElement get element {
+    if (_computeElement != null) {
+      _computedElement = _computeElement();
+      _computeElement = null;
+    }
+    return _computedElement;
+  }
+}
+
+/**
  * The [Type] representing the type `dynamic`.
  */
 class DynamicTypeImpl extends TypeImpl {
   /**
    * The unique instance of this class.
    */
-  static DynamicTypeImpl _INSTANCE = new DynamicTypeImpl._();
-
-  /**
-   * Return the unique instance of this class.
-   */
-  static DynamicTypeImpl get instance => _INSTANCE;
+  static final DynamicTypeImpl instance = new DynamicTypeImpl._();
 
   /**
    * Prevent the creation of instances of this class.
@@ -113,8 +145,7 @@
   /**
    * Constructor used by [CircularTypeImpl].
    */
-  DynamicTypeImpl._circular()
-      : super(_INSTANCE.element, Keyword.DYNAMIC.syntax);
+  DynamicTypeImpl._circular() : super(instance.element, Keyword.DYNAMIC.syntax);
 
   @override
   int get hashCode => 1;
@@ -234,15 +265,6 @@
   List<TypeParameterElement> get boundTypeParameters => typeFormals;
 
   @override
-  List<TypeParameterElement> get typeFormals {
-    if (_isInstantiated) {
-      return TypeParameterElement.EMPTY_LIST;
-    } else {
-      return element?.typeParameters ?? TypeParameterElement.EMPTY_LIST;
-    }
-  }
-
-  @override
   String get displayName {
     String name = this.name;
     if (name == null || name.length == 0) {
@@ -346,28 +368,11 @@
 
   @override
   Map<String, DartType> get namedParameterTypes {
-    LinkedHashMap<String, DartType> namedParameterTypes =
-        new LinkedHashMap<String, DartType>();
-    List<ParameterElement> parameters = baseParameters;
-    if (parameters.length == 0) {
-      return namedParameterTypes;
-    }
-    List<DartType> typeParameters =
-        TypeParameterTypeImpl.getTypes(this.typeParameters);
-    for (ParameterElement parameter in parameters) {
-      if (parameter.parameterKind == ParameterKind.NAMED) {
-        DartType type = parameter.type;
-        if (typeArguments.length != 0 &&
-            typeArguments.length == typeParameters.length) {
-          type = (type as TypeImpl)
-              .substitute2(typeArguments, typeParameters, newPrune);
-        } else {
-          type = (type as TypeImpl).pruned(newPrune);
-        }
-        namedParameterTypes[parameter.name] = type;
-      }
-    }
-    return namedParameterTypes;
+    Map<String, DartType> types = <String, DartType>{};
+    _forEachParameterType(ParameterKind.NAMED, (name, type) {
+      types[name] = type;
+    });
+    return types;
   }
 
   /**
@@ -392,52 +397,37 @@
   }
 
   @override
+  List<String> get normalParameterNames {
+    return baseParameters
+        .where((parameter) => parameter.parameterKind == ParameterKind.REQUIRED)
+        .map((parameter) => parameter.name)
+        .toList();
+  }
+
+  @override
   List<DartType> get normalParameterTypes {
-    List<ParameterElement> parameters = baseParameters;
-    if (parameters.length == 0) {
-      return DartType.EMPTY_LIST;
-    }
-    List<DartType> typeParameters =
-        TypeParameterTypeImpl.getTypes(this.typeParameters);
-    List<DartType> types = new List<DartType>();
-    for (ParameterElement parameter in parameters) {
-      if (parameter.parameterKind == ParameterKind.REQUIRED) {
-        DartType type = parameter.type;
-        if (typeArguments.length != 0 &&
-            typeArguments.length == typeParameters.length) {
-          type = (type as TypeImpl)
-              .substitute2(typeArguments, typeParameters, newPrune);
-        } else {
-          type = (type as TypeImpl).pruned(newPrune);
-        }
-        types.add(type);
-      }
-    }
+    List<DartType> types = <DartType>[];
+    _forEachParameterType(ParameterKind.REQUIRED, (name, type) {
+      types.add(type);
+    });
     return types;
   }
 
   @override
+  List<String> get optionalParameterNames {
+    return baseParameters
+        .where(
+            (parameter) => parameter.parameterKind == ParameterKind.POSITIONAL)
+        .map((parameter) => parameter.name)
+        .toList();
+  }
+
+  @override
   List<DartType> get optionalParameterTypes {
-    List<ParameterElement> parameters = baseParameters;
-    if (parameters.length == 0) {
-      return DartType.EMPTY_LIST;
-    }
-    List<DartType> typeParameters =
-        TypeParameterTypeImpl.getTypes(this.typeParameters);
-    List<DartType> types = new List<DartType>();
-    for (ParameterElement parameter in parameters) {
-      if (parameter.parameterKind == ParameterKind.POSITIONAL) {
-        DartType type = parameter.type;
-        if (typeArguments.length != 0 &&
-            typeArguments.length == typeParameters.length) {
-          type = (type as TypeImpl)
-              .substitute2(typeArguments, typeParameters, newPrune);
-        } else {
-          type = (type as TypeImpl).pruned(newPrune);
-        }
-        types.add(type);
-      }
-    }
+    List<DartType> types = <DartType>[];
+    _forEachParameterType(ParameterKind.POSITIONAL, (name, type) {
+      types.add(type);
+    });
     return types;
   }
 
@@ -496,19 +486,47 @@
   }
 
   @override
+  List<TypeParameterElement> get typeFormals {
+    if (_isInstantiated || element == null) {
+      return TypeParameterElement.EMPTY_LIST;
+    }
+    List<TypeParameterElement> baseTypeFormals = element.typeParameters;
+    int formalCount = baseTypeFormals.length;
+    if (formalCount == 0) {
+      return TypeParameterElement.EMPTY_LIST;
+    }
+
+    // Create type formals with specialized bounds.
+    // For example `<U extends T>` where T comes from an outer scope.
+    List<TypeParameterElement> result =
+        new List<TypeParameterElement>(formalCount);
+
+    for (int i = 0; i < formalCount; i++) {
+      result[i] = TypeParameterMember.from(baseTypeFormals[i], this);
+    }
+    return result;
+  }
+
+  @override
   List<TypeParameterElement> get typeParameters {
     if (_typeParameters == null) {
       // Combine the generic type variables from all enclosing contexts, except
       // for this generic function's type variables. Those variables are
       // tracked in [boundTypeParameters].
       _typeParameters = <TypeParameterElement>[];
-      Element e = element?.enclosingElement;
+
+      Element e = element;
       while (e != null) {
+        // If a static method, skip the enclosing class type parameters.
+        if (e is MethodElement && e.isStatic) {
+          e = e.enclosingElement;
+        }
+        e = e.enclosingElement;
         if (e is TypeParameterizedElement) {
           _typeParameters.addAll(e.typeParameters);
         }
-        e = e.enclosingElement;
       }
+
       if (_isInstantiated) {
         // Once the type has been instantiated, type parameters defined at the
         // site of the declaration of the method are no longer considered part
@@ -535,28 +553,13 @@
     // To test this, we instantiate both types with the same (unique) type
     // variables, and see if the result is equal.
     if (typeFormals.isNotEmpty) {
-      List<DartType> instantiateTypeArgs = new List<DartType>();
-      List<DartType> variablesThis = new List<DartType>();
-      List<DartType> variablesOther = new List<DartType>();
-      for (int i = 0; i < typeFormals.length; i++) {
-        TypeParameterElement pThis = typeFormals[i];
-        TypeParameterElement pOther = otherType.typeFormals[i];
-        TypeParameterTypeImpl pFresh = new TypeParameterTypeImpl(
-            new TypeParameterElementImpl(pThis.name, -1));
-        instantiateTypeArgs.add(pFresh);
-        variablesThis.add(pThis.type);
-        variablesOther.add(pOther.type);
-        // Check that the bounds are equal after equating the previous
-        // bound variables.
-        if (pThis.bound?.substitute2(instantiateTypeArgs, variablesThis) !=
-            pOther.bound?.substitute2(instantiateTypeArgs, variablesOther)) {
-          return false;
-        }
+      List<DartType> freshVariables =
+          relateTypeFormals(this, otherType, (t, s) => t == s);
+      if (freshVariables == null) {
+        return false;
       }
-      // After instantiation, they will no longer have typeFormals,
-      // so we will continue below.
-      return this.instantiate(instantiateTypeArgs) ==
-          otherType.instantiate(instantiateTypeArgs);
+      return instantiate(freshVariables) ==
+          otherType.instantiate(freshVariables);
     }
 
     return returnType == otherType.returnType &&
@@ -582,8 +585,8 @@
         }
       }
 
-      List<DartType> instantiateTypeArgs = new List<DartType>();
-      List<DartType> variables = new List<DartType>();
+      List<DartType> instantiateTypeArgs = <DartType>[];
+      List<DartType> variables = <DartType>[];
       buffer.write("<");
       for (TypeParameterElement e in typeFormals) {
         if (e != typeFormals[0]) {
@@ -718,225 +721,21 @@
       [bool withDynamic = false, Set<Element> visitedElements]) {
     // Note: visitedElements is only used for breaking recursion in the type
     // hierarchy; we don't use it when recursing into the function type.
-
-    // trivial base cases
-    if (type == null) {
-      return false;
-    } else if (identical(this, type) ||
-        type.isDynamic ||
-        type.isDartCoreFunction ||
-        type.isObject) {
-      return true;
-    } else if (type is! FunctionType) {
-      return false;
-    } else if (this == type) {
-      return true;
-    }
-    FunctionType t = this;
-    FunctionType s = type as FunctionType;
-    List<DartType> tTypes = t.normalParameterTypes;
-    List<DartType> tOpTypes = t.optionalParameterTypes;
-    List<DartType> sTypes = s.normalParameterTypes;
-    List<DartType> sOpTypes = s.optionalParameterTypes;
-    // If one function has positional and the other has named parameters,
-    // return false.
-    if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
-        (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
-      return false;
-    }
-    // named parameters case
-    if (t.namedParameterTypes.length > 0) {
-      // check that the number of required parameters are equal, and check that
-      // every t_i is more specific than every s_i
-      if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
-        return false;
-      } else if (t.normalParameterTypes.length > 0) {
-        for (int i = 0; i < tTypes.length; i++) {
-          if (!(tTypes[i] as TypeImpl)
-              .isMoreSpecificThan(sTypes[i], withDynamic)) {
-            return false;
-          }
-        }
-      }
-      Map<String, DartType> namedTypesT = t.namedParameterTypes;
-      Map<String, DartType> namedTypesS = s.namedParameterTypes;
-      // if k >= m is false, return false: the passed function type has more
-      // named parameter types than this
-      if (namedTypesT.length < namedTypesS.length) {
-        return false;
-      }
-      // Loop through each element in S verifying that T has a matching
-      // parameter name and that the corresponding type is more specific then
-      // the type in S.
-      for (String keyS in namedTypesS.keys) {
-        DartType typeT = namedTypesT[keyS];
-        if (typeT == null) {
-          return false;
-        }
-        if (!(typeT as TypeImpl)
-            .isMoreSpecificThan(namedTypesS[keyS], withDynamic)) {
-          return false;
-        }
-      }
-    } else if (s.namedParameterTypes.length > 0) {
-      return false;
-    } else {
-      // positional parameter case
-      int tArgLength = tTypes.length + tOpTypes.length;
-      int sArgLength = sTypes.length + sOpTypes.length;
-      // Check that the total number of parameters in t is greater than or equal
-      // to the number of parameters in s and that the number of required
-      // parameters in s is greater than or equal to the number of required
-      // parameters in t.
-      if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
-        return false;
-      }
-      if (tOpTypes.length == 0 && sOpTypes.length == 0) {
-        // No positional arguments, don't copy contents to new array
-        for (int i = 0; i < sTypes.length; i++) {
-          if (!(tTypes[i] as TypeImpl)
-              .isMoreSpecificThan(sTypes[i], withDynamic)) {
-            return false;
-          }
-        }
-      } else {
-        // Else, we do have positional parameters, copy required and positional
-        // parameter types into arrays to do the compare (for loop below).
-        List<DartType> tAllTypes = new List<DartType>(sArgLength);
-        for (int i = 0; i < tTypes.length; i++) {
-          tAllTypes[i] = tTypes[i];
-        }
-        for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
-          tAllTypes[i] = tOpTypes[j];
-        }
-        List<DartType> sAllTypes = new List<DartType>(sArgLength);
-        for (int i = 0; i < sTypes.length; i++) {
-          sAllTypes[i] = sTypes[i];
-        }
-        for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
-          sAllTypes[i] = sOpTypes[j];
-        }
-        for (int i = 0; i < sAllTypes.length; i++) {
-          if (!(tAllTypes[i] as TypeImpl)
-              .isMoreSpecificThan(sAllTypes[i], withDynamic)) {
-            return false;
-          }
-        }
-      }
-    }
-    DartType tRetType = t.returnType;
-    DartType sRetType = s.returnType;
-    return sRetType.isVoid ||
-        (tRetType as TypeImpl).isMoreSpecificThan(sRetType, withDynamic);
+    return relate(
+        this,
+        type,
+        (DartType t, DartType s) =>
+            (t as TypeImpl).isMoreSpecificThan(s, withDynamic),
+        new TypeSystemImpl().instantiateToBounds);
   }
 
   @override
   bool isSubtypeOf(DartType type) {
-    // trivial base cases
-    if (type == null) {
-      return false;
-    } else if (identical(this, type) ||
-        type.isDynamic ||
-        type.isDartCoreFunction ||
-        type.isObject) {
-      return true;
-    } else if (type is! FunctionType) {
-      return false;
-    } else if (this == type) {
-      return true;
-    }
-    FunctionType t = this;
-    FunctionType s = type as FunctionType;
-    List<DartType> tTypes = t.normalParameterTypes;
-    List<DartType> tOpTypes = t.optionalParameterTypes;
-    List<DartType> sTypes = s.normalParameterTypes;
-    List<DartType> sOpTypes = s.optionalParameterTypes;
-    // If one function has positional and the other has named parameters,
-    // return false.
-    if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) ||
-        (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) {
-      return false;
-    }
-    // named parameters case
-    if (t.namedParameterTypes.length > 0) {
-      // check that the number of required parameters are equal,
-      // and check that every t_i is assignable to every s_i
-      if (t.normalParameterTypes.length != s.normalParameterTypes.length) {
-        return false;
-      } else if (t.normalParameterTypes.length > 0) {
-        for (int i = 0; i < tTypes.length; i++) {
-          if (!(tTypes[i] as TypeImpl).isAssignableTo(sTypes[i])) {
-            return false;
-          }
-        }
-      }
-      Map<String, DartType> namedTypesT = t.namedParameterTypes;
-      Map<String, DartType> namedTypesS = s.namedParameterTypes;
-      // if k >= m is false, return false: the passed function type has more
-      // named parameter types than this
-      if (namedTypesT.length < namedTypesS.length) {
-        return false;
-      }
-      // Loop through each element in S verifying that T has a matching
-      // parameter name and that the corresponding type is assignable to the
-      // type in S.
-      for (String keyS in namedTypesS.keys) {
-        DartType typeT = namedTypesT[keyS];
-        if (typeT == null) {
-          return false;
-        }
-        if (!(typeT as TypeImpl).isAssignableTo(namedTypesS[keyS])) {
-          return false;
-        }
-      }
-    } else if (s.namedParameterTypes.length > 0) {
-      return false;
-    } else {
-      // positional parameter case
-      int tArgLength = tTypes.length + tOpTypes.length;
-      int sArgLength = sTypes.length + sOpTypes.length;
-      // Check that the total number of parameters in t is greater than or
-      // equal to the number of parameters in s and that the number of
-      // required parameters in s is greater than or equal to the number of
-      // required parameters in t.
-      if (tArgLength < sArgLength || sTypes.length < tTypes.length) {
-        return false;
-      }
-      if (tOpTypes.length == 0 && sOpTypes.length == 0) {
-        // No positional arguments, don't copy contents to new array
-        for (int i = 0; i < sTypes.length; i++) {
-          if (!(tTypes[i] as TypeImpl).isAssignableTo(sTypes[i])) {
-            return false;
-          }
-        }
-      } else {
-        // Else, we do have positional parameters, copy required and
-        // positional parameter types into arrays to do the compare (for loop
-        // below).
-        List<DartType> tAllTypes = new List<DartType>(sArgLength);
-        for (int i = 0; i < tTypes.length; i++) {
-          tAllTypes[i] = tTypes[i];
-        }
-        for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) {
-          tAllTypes[i] = tOpTypes[j];
-        }
-        List<DartType> sAllTypes = new List<DartType>(sArgLength);
-        for (int i = 0; i < sTypes.length; i++) {
-          sAllTypes[i] = sTypes[i];
-        }
-        for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) {
-          sAllTypes[i] = sOpTypes[j];
-        }
-        for (int i = 0; i < sAllTypes.length; i++) {
-          if (!(tAllTypes[i] as TypeImpl).isAssignableTo(sAllTypes[i])) {
-            return false;
-          }
-        }
-      }
-    }
-    DartType tRetType = t.returnType;
-    DartType sRetType = s.returnType;
-    return sRetType.isVoid || (tRetType as TypeImpl).isAssignableTo(sRetType);
+    return relate(
+        this,
+        type,
+        (DartType t, DartType s) => t.isAssignableTo(s),
+        new TypeSystemImpl().instantiateToBounds);
   }
 
   @override
@@ -990,6 +789,33 @@
   FunctionTypeImpl substitute3(List<DartType> argumentTypes) =>
       substitute2(argumentTypes, typeArguments);
 
+  /**
+   * Invokes [callback] for each parameter of [kind] with the parameter's [name]
+   * and [type] after any type parameters have been applied.
+   */
+  void _forEachParameterType(
+      ParameterKind kind, callback(String name, DartType type)) {
+    if (baseParameters.isEmpty) {
+      return;
+    }
+
+    List<DartType> typeParameters =
+        TypeParameterTypeImpl.getTypes(this.typeParameters);
+    for (ParameterElement parameter in baseParameters) {
+      if (parameter.parameterKind == kind) {
+        TypeImpl type = parameter.type;
+        if (typeArguments.length != 0 &&
+            typeArguments.length == typeParameters.length) {
+          type = type.substitute2(typeArguments, typeParameters, newPrune);
+        } else {
+          type = type.pruned(newPrune);
+        }
+
+        callback(parameter.name, type);
+      }
+    }
+  }
+
   void _freeVariablesInFunctionType(
       FunctionType type, Set<TypeParameterType> free) {
     // Make some fresh variables to avoid capture.
@@ -1028,16 +854,173 @@
   }
 
   /**
-   * Compute the least upper bound of types [f] and [g], both of which are
-   * known to be function types.
+   * Given two functions [f1] and [f2] where f1 and f2 are known to be
+   * generic function types (both have type formals), this checks that they
+   * have the same number of formals, and that those formals have bounds
+   * (e.g. `<T extends LowerBound>`) that satisfy [relation].
    *
-   * In the event that f and g have different numbers of required parameters,
-   * `null` is returned, in which case the least upper bound is the interface
-   * type `Function`.
+   * The return value will be a new list of fresh type variables, that can be
+   * used to instantiate both function types, allowing further comparison.
+   * For example, given `<T>T -> T` and `<U>U -> U` we can instantiate them with
+   * `F` to get `F -> F` and `F -> F`, which we can see are equal.
    */
-  static FunctionType computeLeastUpperBound(FunctionType f, FunctionType g) {
-    // TODO(paulberry): implement this.
-    return null;
+  static List<DartType> relateTypeFormals(
+      FunctionType f1, FunctionType f2, bool relation(DartType t, DartType s)) {
+    List<TypeParameterElement> params1 = f1.typeFormals;
+    List<TypeParameterElement> params2 = f2.typeFormals;
+    int count = params1.length;
+    if (params2.length != count) {
+      return null;
+    }
+    // We build up a substitution matching up the type parameters
+    // from the two types, {variablesFresh/variables1} and
+    // {variablesFresh/variables2}
+    List<DartType> variables1 = <DartType>[];
+    List<DartType> variables2 = <DartType>[];
+    List<DartType> variablesFresh = <DartType>[];
+    for (int i = 0; i < count; i++) {
+      TypeParameterElement p1 = params1[i];
+      TypeParameterElement p2 = params2[i];
+      TypeParameterElementImpl pFresh =
+          new TypeParameterElementImpl.synthetic(p2.name);
+
+      DartType variable1 = p1.type;
+      DartType variable2 = p2.type;
+      DartType variableFresh = new TypeParameterTypeImpl(pFresh);
+
+      variables1.add(variable1);
+      variables2.add(variable2);
+      variablesFresh.add(variableFresh);
+      DartType bound1 = p1.bound ?? DynamicTypeImpl.instance;
+      DartType bound2 = p2.bound ?? DynamicTypeImpl.instance;
+      bound1 = bound1.substitute2(variablesFresh, variables1);
+      bound2 = bound2.substitute2(variablesFresh, variables2);
+      pFresh.bound = bound2;
+      if (!relation(bound2, bound1)) {
+        return null;
+      }
+    }
+    return variablesFresh;
+  }
+
+  /**
+   * Compares two function types [t] and [s] to see if their corresponding
+   * parameter types match [parameterRelation] and their return types match
+   * [returnRelation].
+   *
+   * Used for the various relations on function types which have the same
+   * structural rules for handling optional parameters and arity, but use their
+   * own relation for comparing corresponding paramaters or return types.
+   *
+   * If [returnRelation] is omitted, uses [parameterRelation] for both.
+   */
+  static bool relate(
+      FunctionType t,
+      DartType other,
+      bool parameterRelation(DartType t, DartType s),
+      FunctionType instantiateToBounds(FunctionType t),
+      {bool returnRelation(DartType t, DartType s)}) {
+
+    returnRelation ??= parameterRelation;
+
+    // Trivial base cases.
+    if (other == null) {
+      return false;
+    } else if (identical(t, other) ||
+        other.isDynamic ||
+        other.isDartCoreFunction ||
+        other.isObject) {
+      return true;
+    } else if (other is! FunctionType) {
+      return false;
+    }
+
+    // This type cast is safe, because we checked it above.
+    FunctionType s = other as FunctionType;
+    if (t.typeFormals.isNotEmpty) {
+      if (s.typeFormals.isEmpty) {
+        t = instantiateToBounds(t);
+      } else {
+        List<DartType> freshVariables = relateTypeFormals(t, s, returnRelation);
+        if (freshVariables == null) {
+          return false;
+        }
+        t = t.instantiate(freshVariables);
+        s = s.instantiate(freshVariables);
+      }
+    } else if (s.typeFormals.isNotEmpty) {
+      return false;
+    }
+
+    // Test the return types.
+    DartType sRetType = s.returnType;
+    if (!sRetType.isVoid && !returnRelation(t.returnType, sRetType)) {
+      return false;
+    }
+
+    // Test the parameter types.
+    List<DartType> tRequired = t.normalParameterTypes;
+    List<DartType> sRequired = s.normalParameterTypes;
+    List<DartType> tOptional = t.optionalParameterTypes;
+    List<DartType> sOptional = s.optionalParameterTypes;
+    Map<String, DartType> tNamed = t.namedParameterTypes;
+    Map<String, DartType> sNamed = s.namedParameterTypes;
+
+    // If one function has positional and the other has named parameters,
+    // they don't relate.
+    if (sOptional.isNotEmpty && tNamed.isNotEmpty ||
+        tOptional.isNotEmpty && sNamed.isNotEmpty) {
+      return false;
+    }
+
+    // If the passed function includes more named parameters than we do, we
+    // don't relate.
+    if (tNamed.length < sNamed.length) {
+      return false;
+    }
+
+    // For each named parameter in s, make sure we have a corresponding one
+    // that relates.
+    for (String key in sNamed.keys) {
+      var tParamType = tNamed[key];
+      if (tParamType == null) {
+        return false;
+      }
+      if (!parameterRelation(tParamType, sNamed[key])) {
+        return false;
+      }
+    }
+
+    // Make sure all of the positional parameters (both required and optional)
+    // relate to each other.
+    List<DartType> tPositional = tRequired;
+    List<DartType> sPositional = sRequired;
+
+    if (tOptional.isNotEmpty) {
+      tPositional = tPositional.toList()..addAll(tOptional);
+    }
+
+    if (sOptional.isNotEmpty) {
+      sPositional = sPositional.toList()..addAll(sOptional);
+    }
+
+    // Check that s has enough required parameters.
+    if (sRequired.length < tRequired.length) {
+      return false;
+    }
+
+    // Check that s does not include more positional parameters than we do.
+    if (tPositional.length < sPositional.length) {
+      return false;
+    }
+
+    for (int i = 0; i < sPositional.length; i++) {
+      if (!parameterRelation(tPositional[i], sPositional[i])) {
+        return false;
+      }
+    }
+
+    return true;
   }
 
   /**
@@ -1089,7 +1072,7 @@
 
   /**
    * Initialize a newly created type to be declared by the given [element],
-   * with the given [name] and [typeArguents].
+   * with the given [name] and [typeArguments].
    */
   InterfaceTypeImpl.elementWithNameAndArgs(
       ClassElement element, String name, List<DartType> typeArguments)
@@ -1194,6 +1177,15 @@
   }
 
   @override
+  bool get isDartAsyncFuture {
+    ClassElement element = this.element;
+    if (element == null) {
+      return false;
+    }
+    return element.name == "Future" && element.library.isDartAsync;
+  }
+
+  @override
   bool get isDartCoreFunction {
     ClassElement element = this.element;
     if (element == null) {
@@ -1280,6 +1272,35 @@
   }
 
   @override
+  DartType flattenFutures(TypeSystem typeSystem) {
+    // Implement the case: "If T = Future<S> then flatten(T) = flatten(S)."
+    if (isDartAsyncFuture && typeArguments.isNotEmpty) {
+      return typeArguments[0].flattenFutures(typeSystem);
+    }
+
+    // Implement the case: "Otherwise if T <: Future then let S be a type
+    // such that T << Future<S> and for all R, if T << Future<R> then S << R.
+    // Then flatten(T) = S."
+    //
+    // 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 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);
+    if (flattenResult != null) {
+      return flattenResult;
+    }
+
+    // Implement the case: "In any other circumstance, flatten(T) = T."
+    return this;
+  }
+
+  @override
   PropertyAccessorElement getGetter(String getterName) =>
       PropertyAccessorMember.from(element.getGetter(getterName), this);
 
@@ -1675,9 +1696,37 @@
     }
     List<DartType> newTypeArguments = TypeImpl.substitute(
         typeArguments, argumentTypes, parameterTypes, prune);
-    if (JavaArrays.equals(newTypeArguments, typeArguments)) {
+    if (listsEqual(newTypeArguments, typeArguments)) {
       return this;
     }
+
+    if (isDartAsyncFuture && newTypeArguments.isNotEmpty) {
+      //
+      // In strong mode interpret Future< T > as Future< flatten(T) >
+      //
+      // For example, Future<Future<T>> will flatten to Future<T>.
+      //
+      // In the Dart 3rd edition spec, this flatten operation is used for
+      // `async` and `await`. In strong mode, we extend it to all Future<T>
+      // instantiations. This allows typing of Future-related operations
+      // in dart:async in a way that matches their runtime behavior and provides
+      // precise return types for users of these APIs.
+      //
+      // For example:
+      //
+      //     abstract class Future<T> {
+      //       Future<S> then<S>(S onValue(T value), ...);
+      //     }
+      //
+      // Given a call where S <: Future<R> for some R, we will need to flatten
+      // the return type so it is Future< flatten(S) >, yielding Future<R>.
+      //
+      if (element.library.context.analysisOptions.strongMode) {
+        TypeImpl t = newTypeArguments[0];
+        newTypeArguments[0] = t.flattenFutures(new StrongTypeSystemImpl());
+      }
+    }
+
     InterfaceTypeImpl newType = new InterfaceTypeImpl(element, prune);
     newType.typeArguments = newTypeArguments;
     return newType;
@@ -1688,6 +1737,31 @@
       substitute2(argumentTypes, typeArguments);
 
   /**
+   * Starting from this type, search its class hierarchy for types of the form
+   * Future<R>, and return a list of the resulting R's.
+   */
+  List<DartType> _searchTypeHierarchyForFutureTypeParameters() {
+    List<DartType> result = <DartType>[];
+    HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
+    void recurse(InterfaceTypeImpl type) {
+      if (type.isDartAsyncFuture && type.typeArguments.isNotEmpty) {
+        result.add(type.typeArguments[0]);
+      }
+      if (visitedClasses.add(type.element)) {
+        if (type.superclass != null) {
+          recurse(type.superclass);
+        }
+        for (InterfaceType interface in type.interfaces) {
+          recurse(interface);
+        }
+        visitedClasses.remove(type.element);
+      }
+    }
+    recurse(this);
+    return result;
+  }
+
+  /**
    * Compute the least upper bound of types [i] and [j], both of which are
    * known to be interface types.
    *
@@ -1846,6 +1920,62 @@
   }
 
   /**
+   * 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(
+      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
+    // specific types seen so far such that no type in the bucket is more
+    // specific than any other type in the bucket.
+    List<DartType> bucket = <DartType>[];
+
+    // Then we consider each type in turn.
+    for (DartType type in types) {
+      // If any existing type in the bucket is more specific than this type,
+      // then we can ignore this type.
+      if (bucket.any((DartType t) => typeSystem.isMoreSpecificThan(t, type))) {
+        continue;
+      }
+      // Otherwise, we need to add this type to the bucket and remove any types
+      // that are less specific than it.
+      bool added = false;
+      int i = 0;
+      while (i < bucket.length) {
+        if (typeSystem.isMoreSpecificThan(type, bucket[i])) {
+          if (added) {
+            if (i < bucket.length - 1) {
+              bucket[i] = bucket.removeLast();
+            } else {
+              bucket.removeLast();
+            }
+          } else {
+            bucket[i] = type;
+            i++;
+            added = true;
+          }
+        } else {
+          i++;
+        }
+      }
+      if (!added) {
+        bucket.add(type);
+      }
+    }
+
+    // Now that we are finished, if there is exactly one type left in the
+    // bucket, it is the most specific type.
+    if (bucket.length == 1) {
+      return bucket[0];
+    }
+
+    // Otherwise, there is no single type that is more specific than the
+    // others.
+    return null;
+  }
+
+  /**
    * Return the intersection of the [first] and [second] sets of types, where
    * intersection is based on the equality of the types themselves.
    */
@@ -1986,6 +2116,9 @@
   bool get isBottom => false;
 
   @override
+  bool get isDartAsyncFuture => false;
+
+  @override
   bool get isDartCoreFunction => false;
 
   @override
@@ -2012,6 +2145,9 @@
     }
   }
 
+  @override
+  DartType flattenFutures(TypeSystem typeSystem) => this;
+
   /**
    * Return `true` if this type is assignable to the given [type] (written in
    * the spec as "T <=> S", where T=[this] and S=[type]).
@@ -2096,6 +2232,9 @@
       [List<FunctionTypeAliasElement> prune]);
 
   @override
+  DartType resolveToBound(DartType objectType) => this;
+
+  @override
   String toString() {
     StringBuffer buffer = new StringBuffer();
     appendTo(buffer);
@@ -2261,6 +2400,15 @@
     }
     return types;
   }
+
+  @override
+  DartType resolveToBound(DartType objectType) {
+    if (element.bound == null) {
+      return objectType;
+    }
+
+    return element.bound.resolveToBound(objectType);
+  }
 }
 
 /**
@@ -2274,12 +2422,7 @@
   /**
    * The unique instance of this class.
    */
-  static UndefinedTypeImpl _INSTANCE = new UndefinedTypeImpl._();
-
-  /**
-   * Return the unique instance of this class.
-   */
-  static UndefinedTypeImpl get instance => _INSTANCE;
+  static final UndefinedTypeImpl instance = new UndefinedTypeImpl._();
 
   /**
    * Prevent the creation of instances of this class.
@@ -2349,17 +2492,12 @@
   /**
    * The unique instance of this class.
    */
-  static VoidTypeImpl _INSTANCE = new VoidTypeImpl();
-
-  /**
-   * Return the unique instance of this class.
-   */
-  static VoidTypeImpl get instance => _INSTANCE;
+  static final VoidTypeImpl instance = new VoidTypeImpl._();
 
   /**
    * Prevent the creation of instances of this class.
    */
-  VoidTypeImpl() : super(null, Keyword.VOID.syntax);
+  VoidTypeImpl._() : super(null, Keyword.VOID.syntax);
 
   @override
   int get hashCode => 2;
diff --git a/pkg/analyzer/lib/src/dart/element/utilities.dart b/pkg/analyzer/lib/src/dart/element/utilities.dart
new file mode 100644
index 0000000..7c5aa4c
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/element/utilities.dart
@@ -0,0 +1,34 @@
+// 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 analyzer.src.dart.element.utilities;
+
+import 'dart:collection';
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+
+/**
+ * A visitor that can be used to collect all of the non-synthetic elements in an
+ * element model.
+ */
+class ElementGatherer extends GeneralizingElementVisitor {
+  /**
+   * The set in which the elements are collected.
+   */
+  final Set<Element> elements = new HashSet<Element>();
+
+  /**
+   * Initialize the visitor.
+   */
+  ElementGatherer();
+
+  @override
+  void visitElement(Element element) {
+    if (!element.isSynthetic) {
+      elements.add(element);
+    }
+    super.visitElement(element);
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/scanner/reader.dart b/pkg/analyzer/lib/src/dart/scanner/reader.dart
new file mode 100644
index 0000000..1f5d87d
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/scanner/reader.dart
@@ -0,0 +1,187 @@
+// 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 analyzer.src.dart.scanner.reader;
+
+/**
+ * A [CharacterReader] that reads a range of characters from another character
+ * reader.
+ */
+class CharacterRangeReader extends CharacterReader {
+  /**
+   * The reader from which the characters are actually being read.
+   */
+  final CharacterReader baseReader;
+
+  /**
+   * The last character to be read.
+   */
+  final int endIndex;
+
+  /**
+   * Initialize a newly created reader to read the characters from the given
+   * [baseReader] between the [startIndex] inclusive to [endIndex] exclusive.
+   */
+  CharacterRangeReader(this.baseReader, int startIndex, this.endIndex) {
+    baseReader.offset = startIndex - 1;
+  }
+
+  @override
+  int get offset => baseReader.offset;
+
+  @override
+  void set offset(int offset) {
+    baseReader.offset = offset;
+  }
+
+  @override
+  int advance() {
+    if (baseReader.offset + 1 >= endIndex) {
+      return -1;
+    }
+    return baseReader.advance();
+  }
+
+  @override
+  String getString(int start, int endDelta) =>
+      baseReader.getString(start, endDelta);
+
+  @override
+  int peek() {
+    if (baseReader.offset + 1 >= endIndex) {
+      return -1;
+    }
+    return baseReader.peek();
+  }
+}
+
+/**
+ * An object used by the scanner to read the characters to be scanned.
+ */
+abstract class CharacterReader {
+  /**
+   * The current offset relative to the beginning of the source. Return the
+   * initial offset if the scanner has not yet scanned the source code, and one
+   * (1) past the end of the source code if the entire source code has been
+   * scanned.
+   */
+  int get offset;
+
+  /**
+   * Set the current offset relative to the beginning of the source to the given
+   * [offset]. The new offset must be between the initial offset and one (1)
+   * past the end of the source code.
+   */
+  void set offset(int offset);
+
+  /**
+   * Advance the current position and return the character at the new current
+   * position.
+   */
+  int advance();
+
+  /**
+   * Return the substring of the source code between the [start] offset and the
+   * modified current position. The current position is modified by adding the
+   * [endDelta], which is the number of characters after the current location to
+   * be included in the string, or the number of characters before the current
+   * location to be excluded if the offset is negative.
+   */
+  String getString(int start, int endDelta);
+
+  /**
+   * Return the character at the current position without changing the current
+   * position.
+   */
+  int peek();
+}
+
+/**
+ * A [CharacterReader] that reads characters from a character sequence.
+ */
+class CharSequenceReader implements CharacterReader {
+  /**
+   * The sequence from which characters will be read.
+   */
+  final String _sequence;
+
+  /**
+   * The number of characters in the string.
+   */
+  int _stringLength = 0;
+
+  /**
+   * The index, relative to the string, of the last character that was read.
+   */
+  int _charOffset = 0;
+
+  /**
+   * Initialize a newly created reader to read the characters in the given
+   * [_sequence].
+   */
+  CharSequenceReader(this._sequence) {
+    this._stringLength = _sequence.length;
+    this._charOffset = -1;
+  }
+
+  @override
+  int get offset => _charOffset;
+
+  @override
+  void set offset(int offset) {
+    _charOffset = offset;
+  }
+
+  @override
+  int advance() {
+    if (_charOffset + 1 >= _stringLength) {
+      return -1;
+    }
+    return _sequence.codeUnitAt(++_charOffset);
+  }
+
+  @override
+  String getString(int start, int endDelta) =>
+      _sequence.substring(start, _charOffset + 1 + endDelta).toString();
+
+  @override
+  int peek() {
+    if (_charOffset + 1 >= _stringLength) {
+      return -1;
+    }
+    return _sequence.codeUnitAt(_charOffset + 1);
+  }
+}
+
+/**
+ * A [CharacterReader] that reads characters from a character sequence, but adds
+ * a delta when reporting the current character offset so that the character
+ * sequence can be a subsequence from a larger sequence.
+ */
+class SubSequenceReader extends CharSequenceReader {
+  /**
+   * The offset from the beginning of the file to the beginning of the source
+   * being scanned.
+   */
+  final int _offsetDelta;
+
+  /**
+   * Initialize a newly created reader to read the characters in the given
+   * [sequence]. The [_offsetDelta] is the offset from the beginning of the file
+   * to the beginning of the source being scanned
+   */
+  SubSequenceReader(String sequence, this._offsetDelta) : super(sequence);
+
+  @override
+  int get offset => _offsetDelta + super.offset;
+
+  @override
+  void set offset(int offset) {
+    super.offset = offset - _offsetDelta;
+  }
+
+  @override
+  String getString(int start, int endDelta) =>
+      super.getString(start - _offsetDelta, endDelta);
+}
diff --git a/pkg/analyzer/lib/src/dart/scanner/scanner.dart b/pkg/analyzer/lib/src/dart/scanner/scanner.dart
new file mode 100644
index 0000000..7814eb7
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/scanner/scanner.dart
@@ -0,0 +1,1375 @@
+// 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 analyzer.src.dart.scanner.scanner;
+
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A state in a state machine used to scan keywords.
+ */
+class KeywordState {
+  /**
+   * An empty transition table used by leaf states.
+   */
+  static List<KeywordState> _EMPTY_TABLE = new List<KeywordState>(26);
+
+  /**
+   * The initial state in the state machine.
+   */
+  static final KeywordState KEYWORD_STATE = _createKeywordStateTable();
+
+  /**
+   * A table mapping characters to the states to which those characters will
+   * transition. (The index into the array is the offset from the character
+   * `'a'` to the transitioning character.)
+   */
+  final List<KeywordState> _table;
+
+  /**
+   * The keyword that is recognized by this state, or `null` if this state is
+   * not a terminal state.
+   */
+  Keyword _keyword;
+
+  /**
+   * Initialize a newly created state to have the given transitions and to
+   * recognize the keyword with the given [syntax].
+   */
+  KeywordState(this._table, String syntax) {
+    this._keyword = (syntax == null) ? null : Keyword.keywords[syntax];
+  }
+
+  /**
+   * Return the keyword that was recognized by this state, or `null` if this
+   * state does not recognized a keyword.
+   */
+  Keyword keyword() => _keyword;
+
+  /**
+   * Return the state that follows this state on a transition of the given
+   * [character], or `null` if there is no valid state reachable from this state
+   * with such a transition.
+   */
+  KeywordState next(int character) => _table[character - 0x61];
+
+  /**
+   * Create the next state in the state machine where we have already recognized
+   * the subset of strings in the given array of [strings] starting at the given
+   * [offset] and having the given [length]. All of these strings have a common
+   * prefix and the next character is at the given [start] index.
+   */
+  static KeywordState _computeKeywordStateTable(
+      int start, List<String> strings, int offset, int length) {
+    List<KeywordState> result = new List<KeywordState>(26);
+    assert(length != 0);
+    int chunk = 0x0;
+    int chunkStart = -1;
+    bool isLeaf = false;
+    for (int i = offset; i < offset + length; i++) {
+      if (strings[i].length == start) {
+        isLeaf = true;
+      }
+      if (strings[i].length > start) {
+        int c = strings[i].codeUnitAt(start);
+        if (chunk != c) {
+          if (chunkStart != -1) {
+            result[chunk - 0x61] = _computeKeywordStateTable(
+                start + 1, strings, chunkStart, i - chunkStart);
+          }
+          chunkStart = i;
+          chunk = c;
+        }
+      }
+    }
+    if (chunkStart != -1) {
+      assert(result[chunk - 0x61] == null);
+      result[chunk - 0x61] = _computeKeywordStateTable(
+          start + 1, strings, chunkStart, offset + length - chunkStart);
+    } else {
+      assert(length == 1);
+      return new KeywordState(_EMPTY_TABLE, strings[offset]);
+    }
+    if (isLeaf) {
+      return new KeywordState(result, strings[offset]);
+    } else {
+      return new KeywordState(result, null);
+    }
+  }
+
+  /**
+   * Create and return the initial state in the state machine.
+   */
+  static KeywordState _createKeywordStateTable() {
+    List<Keyword> values = Keyword.values;
+    List<String> strings = new List<String>(values.length);
+    for (int i = 0; i < values.length; i++) {
+      strings[i] = values[i].syntax;
+    }
+    strings.sort();
+    return _computeKeywordStateTable(0, strings, 0, strings.length);
+  }
+}
+
+/**
+ * The class `Scanner` implements a scanner for Dart code.
+ *
+ * The lexical structure of Dart is ambiguous without knowledge of the context
+ * in which a token is being scanned. For example, without context we cannot
+ * determine whether source of the form "<<" should be scanned as a single
+ * left-shift operator or as two left angle brackets. This scanner does not have
+ * any context, so it always resolves such conflicts by scanning the longest
+ * possible token.
+ */
+class Scanner {
+  /**
+   * The source being scanned.
+   */
+  final Source source;
+
+  /**
+   * The reader used to access the characters in the source.
+   */
+  final CharacterReader _reader;
+
+  /**
+   * The error listener that will be informed of any errors that are found
+   * during the scan.
+   */
+  final AnalysisErrorListener _errorListener;
+
+  /**
+   * The flag specifying whether documentation comments should be parsed.
+   */
+  bool _preserveComments = true;
+
+  /**
+   * The token pointing to the head of the linked list of tokens.
+   */
+  Token _tokens;
+
+  /**
+   * The last token that was scanned.
+   */
+  Token _tail;
+
+  /**
+   * The first token in the list of comment tokens found since the last
+   * non-comment token.
+   */
+  Token _firstComment;
+
+  /**
+   * The last token in the list of comment tokens found since the last
+   * non-comment token.
+   */
+  Token _lastComment;
+
+  /**
+   * The index of the first character of the current token.
+   */
+  int _tokenStart = 0;
+
+  /**
+   * A list containing the offsets of the first character of each line in the
+   * source code.
+   */
+  List<int> _lineStarts = new List<int>();
+
+  /**
+   * A list, treated something like a stack, of tokens representing the
+   * beginning of a matched pair. It is used to pair the end tokens with the
+   * begin tokens.
+   */
+  List<BeginToken> _groupingStack = new List<BeginToken>();
+
+  /**
+   * The index of the last item in the [_groupingStack], or `-1` if the stack is
+   * empty.
+   */
+  int _stackEnd = -1;
+
+  /**
+   * A flag indicating whether any unmatched groups were found during the parse.
+   */
+  bool _hasUnmatchedGroups = false;
+
+  /**
+   * A flag indicating whether to parse generic method comments, of the form
+   * `/*=T*/` and `/*<T>*/`.
+   */
+  bool scanGenericMethodComments = false;
+
+  /**
+   * Initialize a newly created scanner to scan characters from the given
+   * [source]. The given character [_reader] will be used to read the characters
+   * in the source. The given [_errorListener] will be informed of any errors
+   * that are found.
+   */
+  Scanner(this.source, this._reader, this._errorListener) {
+    _tokens = new Token(TokenType.EOF, -1);
+    _tokens.setNext(_tokens);
+    _tail = _tokens;
+    _tokenStart = -1;
+    _lineStarts.add(0);
+  }
+
+  /**
+   * Return the first token in the token stream that was scanned.
+   */
+  Token get firstToken => _tokens.next;
+
+  /**
+   * Return `true` if any unmatched groups were found during the parse.
+   */
+  bool get hasUnmatchedGroups => _hasUnmatchedGroups;
+
+  /**
+   * Return an array containing the offsets of the first character of each line
+   * in the source code.
+   */
+  List<int> get lineStarts => _lineStarts;
+
+  /**
+   * Set whether documentation tokens should be preserved.
+   */
+  void set preserveComments(bool preserveComments) {
+    this._preserveComments = preserveComments;
+  }
+
+  /**
+   * Return the last token that was scanned.
+   */
+  Token get tail => _tail;
+
+  /**
+   * Append the given [token] to the end of the token stream being scanned. This
+   * method is intended to be used by subclasses that copy existing tokens and
+   * should not normally be used because it will fail to correctly associate any
+   * comments with the token being passed in.
+   */
+  void appendToken(Token token) {
+    _tail = _tail.setNext(token);
+  }
+
+  int bigSwitch(int next) {
+    _beginToken();
+    if (next == 0xD) {
+      // '\r'
+      next = _reader.advance();
+      if (next == 0xA) {
+        // '\n'
+        next = _reader.advance();
+      }
+      recordStartOfLine();
+      return next;
+    } else if (next == 0xA) {
+      // '\n'
+      next = _reader.advance();
+      recordStartOfLine();
+      return next;
+    } else if (next == 0x9 || next == 0x20) {
+      // '\t' || ' '
+      return _reader.advance();
+    }
+    if (next == 0x72) {
+      // 'r'
+      int peek = _reader.peek();
+      if (peek == 0x22 || peek == 0x27) {
+        // '"' || "'"
+        int start = _reader.offset;
+        return _tokenizeString(_reader.advance(), start, true);
+      }
+    }
+    if (0x61 <= next && next <= 0x7A) {
+      // 'a'-'z'
+      return _tokenizeKeywordOrIdentifier(next, true);
+    }
+    if ((0x41 <= next && next <= 0x5A) || next == 0x5F || next == 0x24) {
+      // 'A'-'Z' || '_' || '$'
+      return _tokenizeIdentifier(next, _reader.offset, true);
+    }
+    if (next == 0x3C) {
+      // '<'
+      return _tokenizeLessThan(next);
+    }
+    if (next == 0x3E) {
+      // '>'
+      return _tokenizeGreaterThan(next);
+    }
+    if (next == 0x3D) {
+      // '='
+      return _tokenizeEquals(next);
+    }
+    if (next == 0x21) {
+      // '!'
+      return _tokenizeExclamation(next);
+    }
+    if (next == 0x2B) {
+      // '+'
+      return _tokenizePlus(next);
+    }
+    if (next == 0x2D) {
+      // '-'
+      return _tokenizeMinus(next);
+    }
+    if (next == 0x2A) {
+      // '*'
+      return _tokenizeMultiply(next);
+    }
+    if (next == 0x25) {
+      // '%'
+      return _tokenizePercent(next);
+    }
+    if (next == 0x26) {
+      // '&'
+      return _tokenizeAmpersand(next);
+    }
+    if (next == 0x7C) {
+      // '|'
+      return _tokenizeBar(next);
+    }
+    if (next == 0x5E) {
+      // '^'
+      return _tokenizeCaret(next);
+    }
+    if (next == 0x5B) {
+      // '['
+      return _tokenizeOpenSquareBracket(next);
+    }
+    if (next == 0x7E) {
+      // '~'
+      return _tokenizeTilde(next);
+    }
+    if (next == 0x5C) {
+      // '\\'
+      _appendTokenOfType(TokenType.BACKSLASH);
+      return _reader.advance();
+    }
+    if (next == 0x23) {
+      // '#'
+      return _tokenizeTag(next);
+    }
+    if (next == 0x28) {
+      // '('
+      _appendBeginToken(TokenType.OPEN_PAREN);
+      return _reader.advance();
+    }
+    if (next == 0x29) {
+      // ')'
+      _appendEndToken(TokenType.CLOSE_PAREN, TokenType.OPEN_PAREN);
+      return _reader.advance();
+    }
+    if (next == 0x2C) {
+      // ','
+      _appendTokenOfType(TokenType.COMMA);
+      return _reader.advance();
+    }
+    if (next == 0x3A) {
+      // ':'
+      _appendTokenOfType(TokenType.COLON);
+      return _reader.advance();
+    }
+    if (next == 0x3B) {
+      // ';'
+      _appendTokenOfType(TokenType.SEMICOLON);
+      return _reader.advance();
+    }
+    if (next == 0x3F) {
+      // '?'
+      return _tokenizeQuestion();
+    }
+    if (next == 0x5D) {
+      // ']'
+      _appendEndToken(
+          TokenType.CLOSE_SQUARE_BRACKET, TokenType.OPEN_SQUARE_BRACKET);
+      return _reader.advance();
+    }
+    if (next == 0x60) {
+      // '`'
+      _appendTokenOfType(TokenType.BACKPING);
+      return _reader.advance();
+    }
+    if (next == 0x7B) {
+      // '{'
+      _appendBeginToken(TokenType.OPEN_CURLY_BRACKET);
+      return _reader.advance();
+    }
+    if (next == 0x7D) {
+      // '}'
+      _appendEndToken(
+          TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET);
+      return _reader.advance();
+    }
+    if (next == 0x2F) {
+      // '/'
+      return _tokenizeSlashOrComment(next);
+    }
+    if (next == 0x40) {
+      // '@'
+      _appendTokenOfType(TokenType.AT);
+      return _reader.advance();
+    }
+    if (next == 0x22 || next == 0x27) {
+      // '"' || "'"
+      return _tokenizeString(next, _reader.offset, false);
+    }
+    if (next == 0x2E) {
+      // '.'
+      return _tokenizeDotOrNumber(next);
+    }
+    if (next == 0x30) {
+      // '0'
+      return _tokenizeHexOrNumber(next);
+    }
+    if (0x31 <= next && next <= 0x39) {
+      // '1'-'9'
+      return _tokenizeNumber(next);
+    }
+    if (next == -1) {
+      // EOF
+      return -1;
+    }
+    _reportError(ScannerErrorCode.ILLEGAL_CHARACTER, [next]);
+    return _reader.advance();
+  }
+
+  /**
+   * Record the fact that we are at the beginning of a new line in the source.
+   */
+  void recordStartOfLine() {
+    _lineStarts.add(_reader.offset);
+  }
+
+  /**
+   * Record that the source begins on the given [line] and [column] at the
+   * current offset as given by the reader. Both the line and the column are
+   * one-based indexes. The line starts for lines before the given line will not
+   * be correct.
+   *
+   * This method must be invoked at most one time and must be invoked before
+   * scanning begins. The values provided must be sensible. The results are
+   * undefined if these conditions are violated.
+   */
+  void setSourceStart(int line, int column) {
+    int offset = _reader.offset;
+    if (line < 1 || column < 1 || offset < 0 || (line + column - 2) >= offset) {
+      return;
+    }
+    for (int i = 2; i < line; i++) {
+      _lineStarts.add(1);
+    }
+    _lineStarts.add(offset - column + 1);
+  }
+
+  /**
+   * Scan the source code to produce a list of tokens representing the source,
+   * and return the first token in the list of tokens that were produced.
+   */
+  Token tokenize() {
+    int next = _reader.advance();
+    while (next != -1) {
+      next = bigSwitch(next);
+    }
+    _appendEofToken();
+    return firstToken;
+  }
+
+  void _appendBeginToken(TokenType type) {
+    BeginToken token;
+    if (_firstComment == null) {
+      token = new BeginToken(type, _tokenStart);
+    } else {
+      token = new BeginTokenWithComment(type, _tokenStart, _firstComment);
+      _firstComment = null;
+      _lastComment = null;
+    }
+    _tail = _tail.setNext(token);
+    _groupingStack.add(token);
+    _stackEnd++;
+  }
+
+  void _appendCommentToken(TokenType type, String value) {
+    CommentToken token = null;
+    TokenType genericComment = _matchGenericMethodCommentType(value);
+    if (genericComment != null) {
+      token = new CommentToken(genericComment, value, _tokenStart);
+    } else if (!_preserveComments) {
+      // Ignore comment tokens if client specified that it doesn't need them.
+      return;
+    } else {
+      // OK, remember comment tokens.
+      if (_isDocumentationComment(value)) {
+        token = new DocumentationCommentToken(type, value, _tokenStart);
+      } else {
+        token = new CommentToken(type, value, _tokenStart);
+      }
+    }
+    if (_firstComment == null) {
+      _firstComment = token;
+      _lastComment = _firstComment;
+    } else {
+      _lastComment = _lastComment.setNext(token);
+    }
+  }
+
+  void _appendEndToken(TokenType type, TokenType beginType) {
+    Token token;
+    if (_firstComment == null) {
+      token = new Token(type, _tokenStart);
+    } else {
+      token = new TokenWithComment(type, _tokenStart, _firstComment);
+      _firstComment = null;
+      _lastComment = null;
+    }
+    _tail = _tail.setNext(token);
+    if (_stackEnd >= 0) {
+      BeginToken begin = _groupingStack[_stackEnd];
+      if (begin.type == beginType) {
+        begin.endToken = token;
+        _groupingStack.removeAt(_stackEnd--);
+      }
+    }
+  }
+
+  void _appendEofToken() {
+    Token eofToken;
+    if (_firstComment == null) {
+      eofToken = new Token(TokenType.EOF, _reader.offset + 1);
+    } else {
+      eofToken = new TokenWithComment(
+          TokenType.EOF, _reader.offset + 1, _firstComment);
+      _firstComment = null;
+      _lastComment = null;
+    }
+    // The EOF token points to itself so that there is always infinite
+    // look-ahead.
+    eofToken.setNext(eofToken);
+    _tail = _tail.setNext(eofToken);
+    if (_stackEnd >= 0) {
+      _hasUnmatchedGroups = true;
+      // TODO(brianwilkerson) Fix the ungrouped tokens?
+    }
+  }
+
+  void _appendKeywordToken(Keyword keyword) {
+    if (_firstComment == null) {
+      _tail = _tail.setNext(new KeywordToken(keyword, _tokenStart));
+    } else {
+      _tail = _tail.setNext(
+          new KeywordTokenWithComment(keyword, _tokenStart, _firstComment));
+      _firstComment = null;
+      _lastComment = null;
+    }
+  }
+
+  void _appendStringToken(TokenType type, String value) {
+    if (_firstComment == null) {
+      _tail = _tail.setNext(new StringToken(type, value, _tokenStart));
+    } else {
+      _tail = _tail.setNext(
+          new StringTokenWithComment(type, value, _tokenStart, _firstComment));
+      _firstComment = null;
+      _lastComment = null;
+    }
+  }
+
+  void _appendStringTokenWithOffset(TokenType type, String value, int offset) {
+    if (_firstComment == null) {
+      _tail = _tail.setNext(new StringToken(type, value, _tokenStart + offset));
+    } else {
+      _tail = _tail.setNext(new StringTokenWithComment(
+          type, value, _tokenStart + offset, _firstComment));
+      _firstComment = null;
+      _lastComment = null;
+    }
+  }
+
+  void _appendTokenOfType(TokenType type) {
+    if (_firstComment == null) {
+      _tail = _tail.setNext(new Token(type, _tokenStart));
+    } else {
+      _tail =
+          _tail.setNext(new TokenWithComment(type, _tokenStart, _firstComment));
+      _firstComment = null;
+      _lastComment = null;
+    }
+  }
+
+  void _appendTokenOfTypeWithOffset(TokenType type, int offset) {
+    if (_firstComment == null) {
+      _tail = _tail.setNext(new Token(type, offset));
+    } else {
+      _tail = _tail.setNext(new TokenWithComment(type, offset, _firstComment));
+      _firstComment = null;
+      _lastComment = null;
+    }
+  }
+
+  void _beginToken() {
+    _tokenStart = _reader.offset;
+  }
+
+  /**
+   * Return the beginning token corresponding to a closing brace that was found
+   * while scanning inside a string interpolation expression. Tokens that cannot
+   * be matched with the closing brace will be dropped from the stack.
+   */
+  BeginToken _findTokenMatchingClosingBraceInInterpolationExpression() {
+    while (_stackEnd >= 0) {
+      BeginToken begin = _groupingStack[_stackEnd];
+      if (begin.type == TokenType.OPEN_CURLY_BRACKET ||
+          begin.type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
+        return begin;
+      }
+      _hasUnmatchedGroups = true;
+      _groupingStack.removeAt(_stackEnd--);
+    }
+    //
+    // We should never get to this point because we wouldn't be inside a string
+    // interpolation expression unless we had previously found the start of the
+    // expression.
+    //
+    return null;
+  }
+
+  /**
+   * Checks if [value] is the start of a generic method type annotation comment.
+   *
+   * This can either be of the form `/*<T>*/` or `/*=T*/`. The token type is
+   * returned, or null if it was not a generic method comment.
+   */
+  TokenType _matchGenericMethodCommentType(String value) {
+    if (scanGenericMethodComments) {
+      // Match /*< and >*/
+      if (StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x3C) &&
+          StringUtilities.endsWith3(value, 0x3E, 0x2A, 0x2F)) {
+        return TokenType.GENERIC_METHOD_TYPE_LIST;
+      }
+      // Match /*=
+      if (StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x3D)) {
+        return TokenType.GENERIC_METHOD_TYPE_ASSIGN;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Report an error at the current offset. The [errorCode] is the error code
+   * indicating the nature of the error. The [arguments] are any arguments
+   * needed to complete the error message
+   */
+  void _reportError(ScannerErrorCode errorCode, [List<Object> arguments]) {
+    _errorListener.onError(
+        new AnalysisError(source, _reader.offset, 1, errorCode, arguments));
+  }
+
+  int _select(int choice, TokenType yesType, TokenType noType) {
+    int next = _reader.advance();
+    if (next == choice) {
+      _appendTokenOfType(yesType);
+      return _reader.advance();
+    } else {
+      _appendTokenOfType(noType);
+      return next;
+    }
+  }
+
+  int _selectWithOffset(
+      int choice, TokenType yesType, TokenType noType, int offset) {
+    int next = _reader.advance();
+    if (next == choice) {
+      _appendTokenOfTypeWithOffset(yesType, offset);
+      return _reader.advance();
+    } else {
+      _appendTokenOfTypeWithOffset(noType, offset);
+      return next;
+    }
+  }
+
+  int _tokenizeAmpersand(int next) {
+    // && &= &
+    next = _reader.advance();
+    if (next == 0x26) {
+      _appendTokenOfType(TokenType.AMPERSAND_AMPERSAND);
+      return _reader.advance();
+    } else if (next == 0x3D) {
+      _appendTokenOfType(TokenType.AMPERSAND_EQ);
+      return _reader.advance();
+    } else {
+      _appendTokenOfType(TokenType.AMPERSAND);
+      return next;
+    }
+  }
+
+  int _tokenizeBar(int next) {
+    // | || |=
+    next = _reader.advance();
+    if (next == 0x7C) {
+      _appendTokenOfType(TokenType.BAR_BAR);
+      return _reader.advance();
+    } else if (next == 0x3D) {
+      _appendTokenOfType(TokenType.BAR_EQ);
+      return _reader.advance();
+    } else {
+      _appendTokenOfType(TokenType.BAR);
+      return next;
+    }
+  }
+
+  int _tokenizeCaret(int next) =>
+      _select(0x3D, TokenType.CARET_EQ, TokenType.CARET);
+
+  int _tokenizeDotOrNumber(int next) {
+    int start = _reader.offset;
+    next = _reader.advance();
+    if (0x30 <= next && next <= 0x39) {
+      return _tokenizeFractionPart(next, start);
+    } else if (0x2E == next) {
+      return _select(
+          0x2E, TokenType.PERIOD_PERIOD_PERIOD, TokenType.PERIOD_PERIOD);
+    } else {
+      _appendTokenOfType(TokenType.PERIOD);
+      return next;
+    }
+  }
+
+  int _tokenizeEquals(int next) {
+    // = == =>
+    next = _reader.advance();
+    if (next == 0x3D) {
+      _appendTokenOfType(TokenType.EQ_EQ);
+      return _reader.advance();
+    } else if (next == 0x3E) {
+      _appendTokenOfType(TokenType.FUNCTION);
+      return _reader.advance();
+    }
+    _appendTokenOfType(TokenType.EQ);
+    return next;
+  }
+
+  int _tokenizeExclamation(int next) {
+    // ! !=
+    next = _reader.advance();
+    if (next == 0x3D) {
+      _appendTokenOfType(TokenType.BANG_EQ);
+      return _reader.advance();
+    }
+    _appendTokenOfType(TokenType.BANG);
+    return next;
+  }
+
+  int _tokenizeExponent(int next) {
+    if (next == 0x2B || next == 0x2D) {
+      next = _reader.advance();
+    }
+    bool hasDigits = false;
+    while (true) {
+      if (0x30 <= next && next <= 0x39) {
+        hasDigits = true;
+      } else {
+        if (!hasDigits) {
+          _reportError(ScannerErrorCode.MISSING_DIGIT);
+        }
+        return next;
+      }
+      next = _reader.advance();
+    }
+  }
+
+  int _tokenizeFractionPart(int next, int start) {
+    bool done = false;
+    bool hasDigit = false;
+    LOOP: while (!done) {
+      if (0x30 <= next && next <= 0x39) {
+        hasDigit = true;
+      } else if (0x65 == next || 0x45 == next) {
+        hasDigit = true;
+        next = _tokenizeExponent(_reader.advance());
+        done = true;
+        continue LOOP;
+      } else {
+        done = true;
+        continue LOOP;
+      }
+      next = _reader.advance();
+    }
+    if (!hasDigit) {
+      _appendStringToken(TokenType.INT, _reader.getString(start, -2));
+      if (0x2E == next) {
+        return _selectWithOffset(0x2E, TokenType.PERIOD_PERIOD_PERIOD,
+            TokenType.PERIOD_PERIOD, _reader.offset - 1);
+      }
+      _appendTokenOfTypeWithOffset(TokenType.PERIOD, _reader.offset - 1);
+      return bigSwitch(next);
+    }
+    _appendStringToken(
+        TokenType.DOUBLE, _reader.getString(start, next < 0 ? 0 : -1));
+    return next;
+  }
+
+  int _tokenizeGreaterThan(int next) {
+    // > >= >> >>=
+    next = _reader.advance();
+    if (0x3D == next) {
+      _appendTokenOfType(TokenType.GT_EQ);
+      return _reader.advance();
+    } else if (0x3E == next) {
+      next = _reader.advance();
+      if (0x3D == next) {
+        _appendTokenOfType(TokenType.GT_GT_EQ);
+        return _reader.advance();
+      } else {
+        _appendTokenOfType(TokenType.GT_GT);
+        return next;
+      }
+    } else {
+      _appendTokenOfType(TokenType.GT);
+      return next;
+    }
+  }
+
+  int _tokenizeHex(int next) {
+    int start = _reader.offset - 1;
+    bool hasDigits = false;
+    while (true) {
+      next = _reader.advance();
+      if ((0x30 <= next && next <= 0x39) ||
+          (0x41 <= next && next <= 0x46) ||
+          (0x61 <= next && next <= 0x66)) {
+        hasDigits = true;
+      } else {
+        if (!hasDigits) {
+          _reportError(ScannerErrorCode.MISSING_HEX_DIGIT);
+        }
+        _appendStringToken(
+            TokenType.HEXADECIMAL, _reader.getString(start, next < 0 ? 0 : -1));
+        return next;
+      }
+    }
+  }
+
+  int _tokenizeHexOrNumber(int next) {
+    int x = _reader.peek();
+    if (x == 0x78 || x == 0x58) {
+      _reader.advance();
+      return _tokenizeHex(x);
+    }
+    return _tokenizeNumber(next);
+  }
+
+  int _tokenizeIdentifier(int next, int start, bool allowDollar) {
+    while ((0x61 <= next && next <= 0x7A) ||
+        (0x41 <= next && next <= 0x5A) ||
+        (0x30 <= next && next <= 0x39) ||
+        next == 0x5F ||
+        (next == 0x24 && allowDollar)) {
+      next = _reader.advance();
+    }
+    _appendStringToken(
+        TokenType.IDENTIFIER, _reader.getString(start, next < 0 ? 0 : -1));
+    return next;
+  }
+
+  int _tokenizeInterpolatedExpression(int next, int start) {
+    _appendBeginToken(TokenType.STRING_INTERPOLATION_EXPRESSION);
+    next = _reader.advance();
+    while (next != -1) {
+      if (next == 0x7D) {
+        BeginToken begin =
+            _findTokenMatchingClosingBraceInInterpolationExpression();
+        if (begin == null) {
+          _beginToken();
+          _appendTokenOfType(TokenType.CLOSE_CURLY_BRACKET);
+          next = _reader.advance();
+          _beginToken();
+          return next;
+        } else if (begin.type == TokenType.OPEN_CURLY_BRACKET) {
+          _beginToken();
+          _appendEndToken(
+              TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET);
+          next = _reader.advance();
+          _beginToken();
+        } else if (begin.type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
+          _beginToken();
+          _appendEndToken(TokenType.CLOSE_CURLY_BRACKET,
+              TokenType.STRING_INTERPOLATION_EXPRESSION);
+          next = _reader.advance();
+          _beginToken();
+          return next;
+        }
+      } else {
+        next = bigSwitch(next);
+      }
+    }
+    return next;
+  }
+
+  int _tokenizeInterpolatedIdentifier(int next, int start) {
+    _appendStringTokenWithOffset(
+        TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 0);
+    if ((0x41 <= next && next <= 0x5A) ||
+        (0x61 <= next && next <= 0x7A) ||
+        next == 0x5F) {
+      _beginToken();
+      next = _tokenizeKeywordOrIdentifier(next, false);
+    }
+    _beginToken();
+    return next;
+  }
+
+  int _tokenizeKeywordOrIdentifier(int next, bool allowDollar) {
+    KeywordState state = KeywordState.KEYWORD_STATE;
+    int start = _reader.offset;
+    while (state != null && 0x61 <= next && next <= 0x7A) {
+      state = state.next(next);
+      next = _reader.advance();
+    }
+    if (state == null || state.keyword() == null) {
+      return _tokenizeIdentifier(next, start, allowDollar);
+    }
+    if ((0x41 <= next && next <= 0x5A) ||
+        (0x30 <= next && next <= 0x39) ||
+        next == 0x5F ||
+        next == 0x24) {
+      return _tokenizeIdentifier(next, start, allowDollar);
+    } else if (next < 128) {
+      _appendKeywordToken(state.keyword());
+      return next;
+    } else {
+      return _tokenizeIdentifier(next, start, allowDollar);
+    }
+  }
+
+  int _tokenizeLessThan(int next) {
+    // < <= << <<=
+    next = _reader.advance();
+    if (0x3D == next) {
+      _appendTokenOfType(TokenType.LT_EQ);
+      return _reader.advance();
+    } else if (0x3C == next) {
+      return _select(0x3D, TokenType.LT_LT_EQ, TokenType.LT_LT);
+    } else {
+      _appendTokenOfType(TokenType.LT);
+      return next;
+    }
+  }
+
+  int _tokenizeMinus(int next) {
+    // - -- -=
+    next = _reader.advance();
+    if (next == 0x2D) {
+      _appendTokenOfType(TokenType.MINUS_MINUS);
+      return _reader.advance();
+    } else if (next == 0x3D) {
+      _appendTokenOfType(TokenType.MINUS_EQ);
+      return _reader.advance();
+    } else {
+      _appendTokenOfType(TokenType.MINUS);
+      return next;
+    }
+  }
+
+  int _tokenizeMultiLineComment(int next) {
+    int nesting = 1;
+    next = _reader.advance();
+    while (true) {
+      if (-1 == next) {
+        _reportError(ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT);
+        _appendCommentToken(
+            TokenType.MULTI_LINE_COMMENT, _reader.getString(_tokenStart, 0));
+        return next;
+      } else if (0x2A == next) {
+        next = _reader.advance();
+        if (0x2F == next) {
+          --nesting;
+          if (0 == nesting) {
+            _appendCommentToken(TokenType.MULTI_LINE_COMMENT,
+                _reader.getString(_tokenStart, 0));
+            return _reader.advance();
+          } else {
+            next = _reader.advance();
+          }
+        }
+      } else if (0x2F == next) {
+        next = _reader.advance();
+        if (0x2A == next) {
+          next = _reader.advance();
+          ++nesting;
+        }
+      } else if (next == 0xD) {
+        next = _reader.advance();
+        if (next == 0xA) {
+          next = _reader.advance();
+        }
+        recordStartOfLine();
+      } else if (next == 0xA) {
+        next = _reader.advance();
+        recordStartOfLine();
+      } else {
+        next = _reader.advance();
+      }
+    }
+  }
+
+  int _tokenizeMultiLineRawString(int quoteChar, int start) {
+    int next = _reader.advance();
+    outer: while (next != -1) {
+      while (next != quoteChar) {
+        if (next == -1) {
+          break outer;
+        } else if (next == 0xD) {
+          next = _reader.advance();
+          if (next == 0xA) {
+            next = _reader.advance();
+          }
+          recordStartOfLine();
+        } else if (next == 0xA) {
+          next = _reader.advance();
+          recordStartOfLine();
+        } else {
+          next = _reader.advance();
+        }
+      }
+      next = _reader.advance();
+      if (next == quoteChar) {
+        next = _reader.advance();
+        if (next == quoteChar) {
+          _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
+          return _reader.advance();
+        }
+      }
+    }
+    _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
+    _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
+    return _reader.advance();
+  }
+
+  int _tokenizeMultiLineString(int quoteChar, int start, bool raw) {
+    if (raw) {
+      return _tokenizeMultiLineRawString(quoteChar, start);
+    }
+    int next = _reader.advance();
+    while (next != -1) {
+      if (next == 0x24) {
+        _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
+        next = _tokenizeStringInterpolation(start);
+        _beginToken();
+        start = _reader.offset;
+        continue;
+      }
+      if (next == quoteChar) {
+        next = _reader.advance();
+        if (next == quoteChar) {
+          next = _reader.advance();
+          if (next == quoteChar) {
+            _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
+            return _reader.advance();
+          }
+        }
+        continue;
+      }
+      if (next == 0x5C) {
+        next = _reader.advance();
+        if (next == -1) {
+          break;
+        }
+        if (next == 0xD) {
+          next = _reader.advance();
+          if (next == 0xA) {
+            next = _reader.advance();
+          }
+          recordStartOfLine();
+        } else if (next == 0xA) {
+          recordStartOfLine();
+          next = _reader.advance();
+        } else {
+          next = _reader.advance();
+        }
+      } else if (next == 0xD) {
+        next = _reader.advance();
+        if (next == 0xA) {
+          next = _reader.advance();
+        }
+        recordStartOfLine();
+      } else if (next == 0xA) {
+        recordStartOfLine();
+        next = _reader.advance();
+      } else {
+        next = _reader.advance();
+      }
+    }
+    _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
+    if (start == _reader.offset) {
+      _appendStringTokenWithOffset(TokenType.STRING, "", 1);
+    } else {
+      _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
+    }
+    return _reader.advance();
+  }
+
+  int _tokenizeMultiply(int next) =>
+      _select(0x3D, TokenType.STAR_EQ, TokenType.STAR);
+
+  int _tokenizeNumber(int next) {
+    int start = _reader.offset;
+    while (true) {
+      next = _reader.advance();
+      if (0x30 <= next && next <= 0x39) {
+        continue;
+      } else if (next == 0x2E) {
+        return _tokenizeFractionPart(_reader.advance(), start);
+      } else if (next == 0x65 || next == 0x45) {
+        return _tokenizeFractionPart(next, start);
+      } else {
+        _appendStringToken(
+            TokenType.INT, _reader.getString(start, next < 0 ? 0 : -1));
+        return next;
+      }
+    }
+  }
+
+  int _tokenizeOpenSquareBracket(int next) {
+    // [ []  []=
+    next = _reader.advance();
+    if (next == 0x5D) {
+      return _select(0x3D, TokenType.INDEX_EQ, TokenType.INDEX);
+    } else {
+      _appendBeginToken(TokenType.OPEN_SQUARE_BRACKET);
+      return next;
+    }
+  }
+
+  int _tokenizePercent(int next) =>
+      _select(0x3D, TokenType.PERCENT_EQ, TokenType.PERCENT);
+
+  int _tokenizePlus(int next) {
+    // + ++ +=
+    next = _reader.advance();
+    if (0x2B == next) {
+      _appendTokenOfType(TokenType.PLUS_PLUS);
+      return _reader.advance();
+    } else if (0x3D == next) {
+      _appendTokenOfType(TokenType.PLUS_EQ);
+      return _reader.advance();
+    } else {
+      _appendTokenOfType(TokenType.PLUS);
+      return next;
+    }
+  }
+
+  int _tokenizeQuestion() {
+    // ? ?. ?? ??=
+    int next = _reader.advance();
+    if (next == 0x2E) {
+      // '.'
+      _appendTokenOfType(TokenType.QUESTION_PERIOD);
+      return _reader.advance();
+    } else if (next == 0x3F) {
+      // '?'
+      next = _reader.advance();
+      if (next == 0x3D) {
+        // '='
+        _appendTokenOfType(TokenType.QUESTION_QUESTION_EQ);
+        return _reader.advance();
+      } else {
+        _appendTokenOfType(TokenType.QUESTION_QUESTION);
+        return next;
+      }
+    } else {
+      _appendTokenOfType(TokenType.QUESTION);
+      return next;
+    }
+  }
+
+  int _tokenizeSingleLineComment(int next) {
+    while (true) {
+      next = _reader.advance();
+      if (-1 == next) {
+        _appendCommentToken(
+            TokenType.SINGLE_LINE_COMMENT, _reader.getString(_tokenStart, 0));
+        return next;
+      } else if (0xA == next || 0xD == next) {
+        _appendCommentToken(
+            TokenType.SINGLE_LINE_COMMENT, _reader.getString(_tokenStart, -1));
+        return next;
+      }
+    }
+  }
+
+  int _tokenizeSingleLineRawString(int next, int quoteChar, int start) {
+    next = _reader.advance();
+    while (next != -1) {
+      if (next == quoteChar) {
+        _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
+        return _reader.advance();
+      } else if (next == 0xD || next == 0xA) {
+        _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
+        _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
+        return _reader.advance();
+      }
+      next = _reader.advance();
+    }
+    _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
+    _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
+    return _reader.advance();
+  }
+
+  int _tokenizeSingleLineString(int next, int quoteChar, int start) {
+    while (next != quoteChar) {
+      if (next == 0x5C) {
+        next = _reader.advance();
+      } else if (next == 0x24) {
+        _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
+        next = _tokenizeStringInterpolation(start);
+        _beginToken();
+        start = _reader.offset;
+        continue;
+      }
+      if (next <= 0xD && (next == 0xA || next == 0xD || next == -1)) {
+        _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
+        if (start == _reader.offset) {
+          _appendStringTokenWithOffset(TokenType.STRING, "", 1);
+        } else if (next == -1) {
+          _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
+        } else {
+          _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
+        }
+        return _reader.advance();
+      }
+      next = _reader.advance();
+    }
+    _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
+    return _reader.advance();
+  }
+
+  int _tokenizeSlashOrComment(int next) {
+    next = _reader.advance();
+    if (0x2A == next) {
+      return _tokenizeMultiLineComment(next);
+    } else if (0x2F == next) {
+      return _tokenizeSingleLineComment(next);
+    } else if (0x3D == next) {
+      _appendTokenOfType(TokenType.SLASH_EQ);
+      return _reader.advance();
+    } else {
+      _appendTokenOfType(TokenType.SLASH);
+      return next;
+    }
+  }
+
+  int _tokenizeString(int next, int start, bool raw) {
+    int quoteChar = next;
+    next = _reader.advance();
+    if (quoteChar == next) {
+      next = _reader.advance();
+      if (quoteChar == next) {
+        // Multiline string.
+        return _tokenizeMultiLineString(quoteChar, start, raw);
+      } else {
+        // Empty string.
+        _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
+        return next;
+      }
+    }
+    if (raw) {
+      return _tokenizeSingleLineRawString(next, quoteChar, start);
+    } else {
+      return _tokenizeSingleLineString(next, quoteChar, start);
+    }
+  }
+
+  int _tokenizeStringInterpolation(int start) {
+    _beginToken();
+    int next = _reader.advance();
+    if (next == 0x7B) {
+      return _tokenizeInterpolatedExpression(next, start);
+    } else {
+      return _tokenizeInterpolatedIdentifier(next, start);
+    }
+  }
+
+  int _tokenizeTag(int next) {
+    // # or #!.*[\n\r]
+    if (_reader.offset == 0) {
+      if (_reader.peek() == 0x21) {
+        do {
+          next = _reader.advance();
+        } while (next != 0xA && next != 0xD && next > 0);
+        _appendStringToken(
+            TokenType.SCRIPT_TAG, _reader.getString(_tokenStart, 0));
+        return next;
+      }
+    }
+    _appendTokenOfType(TokenType.HASH);
+    return _reader.advance();
+  }
+
+  int _tokenizeTilde(int next) {
+    // ~ ~/ ~/=
+    next = _reader.advance();
+    if (next == 0x2F) {
+      return _select(0x3D, TokenType.TILDE_SLASH_EQ, TokenType.TILDE_SLASH);
+    } else {
+      _appendTokenOfType(TokenType.TILDE);
+      return next;
+    }
+  }
+
+  /**
+   * Checks if [value] is a single-line or multi-line comment.
+   */
+  static bool _isDocumentationComment(String value) {
+    return StringUtilities.startsWith3(value, 0, 0x2F, 0x2F, 0x2F) ||
+        StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x2A);
+  }
+}
+
+/**
+ * The error codes used for errors detected by the scanner.
+ */
+class ScannerErrorCode extends ErrorCode {
+  static const ScannerErrorCode ILLEGAL_CHARACTER =
+      const ScannerErrorCode('ILLEGAL_CHARACTER', "Illegal character {0}");
+
+  static const ScannerErrorCode MISSING_DIGIT =
+      const ScannerErrorCode('MISSING_DIGIT', "Decimal digit expected");
+
+  static const ScannerErrorCode MISSING_HEX_DIGIT =
+      const ScannerErrorCode('MISSING_HEX_DIGIT', "Hexidecimal digit expected");
+
+  static const ScannerErrorCode MISSING_QUOTE =
+      const ScannerErrorCode('MISSING_QUOTE', "Expected quote (' or \")");
+
+  static const ScannerErrorCode UNABLE_GET_CONTENT = const ScannerErrorCode(
+      'UNABLE_GET_CONTENT', "Unable to get content: {0}");
+
+  static const ScannerErrorCode UNTERMINATED_MULTI_LINE_COMMENT =
+      const ScannerErrorCode(
+          'UNTERMINATED_MULTI_LINE_COMMENT', "Unterminated multi-line comment");
+
+  static const ScannerErrorCode UNTERMINATED_STRING_LITERAL =
+      const ScannerErrorCode(
+          'UNTERMINATED_STRING_LITERAL', "Unterminated string literal");
+
+  /**
+   * Initialize a newly created error code to have the given [name]. The message
+   * associated with the error will be created from the given [message]
+   * template. The correction associated with the error will be created from the
+   * given [correction] template.
+   */
+  const ScannerErrorCode(String name, String message, [String correction])
+      : super(name, message, correction);
+
+  @override
+  ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
+
+  @override
+  ErrorType get type => ErrorType.SYNTACTIC_ERROR;
+}
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/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index 3daca75..18c14d8 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -2,12331 +2,18 @@
 // 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 library is deprecated. Please convert all references to this library to
+ * reference one of the following public libraries:
+ * * package:analyzer/dart/ast/ast.dart
+ * * package:analyzer/dart/ast/visitor.dart
+ *
+ * If your code is using APIs not available in these public libraries, please
+ * contact the analyzer team to either find an alternate API or have the API you
+ * depend on added to the public API.
+ */
 library analyzer.src.generated.ast;
 
-import 'dart:collection';
-
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/ast/utilities.dart';
-import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
-import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/source.dart' show LineInfo, Source;
-import 'package:analyzer/src/generated/utilities_dart.dart';
-
+export 'package:analyzer/dart/ast/ast.dart';
 export 'package:analyzer/dart/ast/visitor.dart';
 export 'package:analyzer/src/dart/ast/utilities.dart';
-
-/**
- * Two or more string literals that are implicitly concatenated because of being
- * adjacent (separated only by whitespace).
- *
- * While the grammar only allows adjacent strings when all of the strings are of
- * the same kind (single line or multi-line), this class doesn't enforce that
- * restriction.
- *
- * > adjacentStrings ::=
- * >     [StringLiteral] [StringLiteral]+
- */
-class AdjacentStrings extends StringLiteral {
-  /**
-   * The strings that are implicitly concatenated.
-   */
-  NodeList<StringLiteral> _strings;
-
-  /**
-   * Initialize a newly created list of adjacent strings. To be syntactically
-   * valid, the list of [strings] must contain at least two elements.
-   */
-  AdjacentStrings(List<StringLiteral> strings) {
-    _strings = new NodeList<StringLiteral>(this, strings);
-  }
-
-  @override
-  Token get beginToken => _strings.beginToken;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..addAll(_strings);
-
-  @override
-  Token get endToken => _strings.endToken;
-
-  /**
-   * Return the strings that are implicitly concatenated.
-   */
-  NodeList<StringLiteral> get strings => _strings;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitAdjacentStrings(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _strings.accept(visitor);
-  }
-
-  @override
-  void _appendStringValue(StringBuffer buffer) {
-    for (StringLiteral stringLiteral in strings) {
-      stringLiteral._appendStringValue(buffer);
-    }
-  }
-}
-
-/**
- * An AST node that can be annotated with both a documentation comment and a
- * list of annotations.
- */
-abstract class AnnotatedNode extends AstNode {
-  /**
-   * The documentation comment associated with this node, or `null` if this node
-   * does not have a documentation comment associated with it.
-   */
-  Comment _comment;
-
-  /**
-   * The annotations associated with this node.
-   */
-  NodeList<Annotation> _metadata;
-
-  /**
-   * Initialize a newly created annotated node. Either or both of the [comment]
-   * and [metadata] can be `null` if the node does not have the corresponding
-   * attribute.
-   */
-  AnnotatedNode(Comment comment, List<Annotation> metadata) {
-    _comment = _becomeParentOf(comment);
-    _metadata = new NodeList<Annotation>(this, metadata);
-  }
-
-  @override
-  Token get beginToken {
-    if (_comment == null) {
-      if (_metadata.isEmpty) {
-        return firstTokenAfterCommentAndMetadata;
-      }
-      return _metadata.beginToken;
-    } else if (_metadata.isEmpty) {
-      return _comment.beginToken;
-    }
-    Token commentToken = _comment.beginToken;
-    Token metadataToken = _metadata.beginToken;
-    if (commentToken.offset < metadataToken.offset) {
-      return commentToken;
-    }
-    return metadataToken;
-  }
-
-  /**
-   * Return the documentation comment associated with this node, or `null` if
-   * this node does not have a documentation comment associated with it.
-   */
-  Comment get documentationComment => _comment;
-
-  /**
-   * Set the documentation comment associated with this node to the given
-   * [comment].
-   */
-  void set documentationComment(Comment comment) {
-    _comment = _becomeParentOf(comment);
-  }
-
-  /**
-   * Return the first token following the comment and metadata.
-   */
-  Token get firstTokenAfterCommentAndMetadata;
-
-  /**
-   * Return the annotations associated with this node.
-   */
-  NodeList<Annotation> get metadata => _metadata;
-
-  /**
-   * Return a list containing the comment and annotations associated with this
-   * node, sorted in lexical order.
-   */
-  List<AstNode> get sortedCommentAndAnnotations {
-    return <AstNode>[]
-      ..add(_comment)
-      ..addAll(_metadata)
-      ..sort(AstNode.LEXICAL_ORDER);
-  }
-
-  /**
-   * Return a holder of child entities that subclasses can add to.
-   */
-  ChildEntities get _childEntities {
-    ChildEntities result = new ChildEntities();
-    if (_commentIsBeforeAnnotations()) {
-      result
-        ..add(_comment)
-        ..addAll(_metadata);
-    } else {
-      result.addAll(sortedCommentAndAnnotations);
-    }
-    return result;
-  }
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    if (_commentIsBeforeAnnotations()) {
-      _safelyVisitChild(_comment, visitor);
-      _metadata.accept(visitor);
-    } else {
-      for (AstNode child in sortedCommentAndAnnotations) {
-        child.accept(visitor);
-      }
-    }
-  }
-
-  /**
-   * Return `true` if there are no annotations before the comment. Note that a
-   * result of `true` does not imply that there is a comment, nor that there are
-   * annotations associated with this node.
-   */
-  bool _commentIsBeforeAnnotations() {
-    // TODO(brianwilkerson) Convert this to a getter.
-    if (_comment == null || _metadata.isEmpty) {
-      return true;
-    }
-    Annotation firstAnnotation = _metadata[0];
-    return _comment.offset < firstAnnotation.offset;
-  }
-}
-
-/**
- * An annotation that can be associated with an AST node.
- *
- * > metadata ::=
- * >     annotation*
- * >
- * > annotation ::=
- * >     '@' [Identifier] ('.' [SimpleIdentifier])? [ArgumentList]?
- */
-class Annotation extends AstNode {
-  /**
-   * The at sign that introduced the annotation.
-   */
-  Token atSign;
-
-  /**
-   * The name of the class defining the constructor that is being invoked or the
-   * name of the field that is being referenced.
-   */
-  Identifier _name;
-
-  /**
-   * The period before the constructor name, or `null` if this annotation is not
-   * the invocation of a named constructor.
-   */
-  Token period;
-
-  /**
-   * The name of the constructor being invoked, or `null` if this annotation is
-   * not the invocation of a named constructor.
-   */
-  SimpleIdentifier _constructorName;
-
-  /**
-   * The arguments to the constructor being invoked, or `null` if this
-   * annotation is not the invocation of a constructor.
-   */
-  ArgumentList _arguments;
-
-  /**
-   * The element associated with this annotation, or `null` if the AST structure
-   * has not been resolved or if this annotation could not be resolved.
-   */
-  Element _element;
-
-  /**
-   * The element annotation representing this annotation in the element model.
-   */
-  ElementAnnotation elementAnnotation;
-
-  /**
-   * Initialize a newly created annotation. Both the [period] and the
-   * [constructorName] can be `null` if the annotation is not referencing a
-   * named constructor. The [arguments] can be `null` if the annotation is not
-   * referencing a constructor.
-   */
-  Annotation(this.atSign, Identifier name, this.period,
-      SimpleIdentifier constructorName, ArgumentList arguments) {
-    _name = _becomeParentOf(name);
-    _constructorName = _becomeParentOf(constructorName);
-    _arguments = _becomeParentOf(arguments);
-  }
-
-  /**
-   * Return the arguments to the constructor being invoked, or `null` if this
-   * annotation is not the invocation of a constructor.
-   */
-  ArgumentList get arguments => _arguments;
-
-  /**
-   * Set the arguments to the constructor being invoked to the given arguments.
-   */
-  void set arguments(ArgumentList arguments) {
-    _arguments = _becomeParentOf(arguments);
-  }
-
-  @override
-  Token get beginToken => atSign;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(atSign)
-    ..add(_name)
-    ..add(period)
-    ..add(_constructorName)
-    ..add(_arguments);
-
-  /**
-   * Return the name of the constructor being invoked, or `null` if this
-   * annotation is not the invocation of a named constructor.
-   */
-  SimpleIdentifier get constructorName => _constructorName;
-
-  /**
-   * Set the name of the constructor being invoked to the given [name].
-   */
-  void set constructorName(SimpleIdentifier name) {
-    _constructorName = _becomeParentOf(name);
-  }
-
-  /**
-   * Return the element associated with this annotation, or `null` if the AST
-   * structure has not been resolved or if this annotation could not be
-   * resolved.
-   */
-  Element get element {
-    if (_element != null) {
-      return _element;
-    } else if (_name != null) {
-      return _name.staticElement;
-    }
-    return null;
-  }
-
-  /**
-   * Set the element associated with this annotation to the given [element].
-   */
-  void set element(Element element) {
-    _element = element;
-  }
-
-  @override
-  Token get endToken {
-    if (_arguments != null) {
-      return _arguments.endToken;
-    } else if (_constructorName != null) {
-      return _constructorName.endToken;
-    }
-    return _name.endToken;
-  }
-
-  /**
-   * Return the name of the class defining the constructor that is being invoked
-   * or the name of the field that is being referenced.
-   */
-  Identifier get name => _name;
-
-  /**
-   * Set the name of the class defining the constructor that is being invoked or
-   * the name of the field that is being referenced to the given [name].
-   */
-  void set name(Identifier name) {
-    _name = _becomeParentOf(name);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitAnnotation(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_constructorName, visitor);
-    _safelyVisitChild(_arguments, visitor);
-  }
-}
-
-/**
- * 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])*
- */
-class ArgumentList extends AstNode {
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The expressions producing the values of the arguments.
-   */
-  NodeList<Expression> _arguments;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * A list containing the elements representing the parameters corresponding to
-   * each of the arguments in this list, or `null` if the AST has not been
-   * resolved or if the function or method being invoked could not be determined
-   * based on static type information. The list must be the same length as the
-   * number of arguments, but can contain `null` entries if a given argument
-   * does not correspond to a formal parameter.
-   */
-  List<ParameterElement> _correspondingStaticParameters;
-
-  /**
-   * A list containing the elements representing the parameters corresponding to
-   * each of the arguments in this list, or `null` if the AST has not been
-   * resolved or if the function or method being invoked could not be determined
-   * based on propagated type information. The list must be the same length as
-   * the number of arguments, but can contain `null` entries if a given argument
-   * does not correspond to a formal parameter.
-   */
-  List<ParameterElement> _correspondingPropagatedParameters;
-
-  /**
-   * Initialize a newly created list of arguments. The list of [arguments] can
-   * be `null` if there are no arguments.
-   */
-  ArgumentList(
-      this.leftParenthesis, List<Expression> arguments, this.rightParenthesis) {
-    _arguments = new NodeList<Expression>(this, arguments);
-  }
-
-  /**
-   * Return the expressions producing the values of the arguments. Although the
-   * language requires that positional arguments appear before named arguments,
-   * this class allows them to be intermixed.
-   */
-  NodeList<Expression> get arguments => _arguments;
-
-  @override
-  Token get beginToken => leftParenthesis;
-
-  @override
-  // TODO(paulberry): Add commas.
-  Iterable get childEntities => new ChildEntities()
-    ..add(leftParenthesis)
-    ..addAll(_arguments)
-    ..add(rightParenthesis);
-
-  /**
-   * Set the parameter elements corresponding to each of the arguments in this
-   * list to the given list of [parameters]. The list of parameters must be the
-   * same length as the number of arguments, but can contain `null` entries if a
-   * given argument does not correspond to a formal parameter.
-   */
-  void set correspondingPropagatedParameters(
-      List<ParameterElement> parameters) {
-    if (parameters.length != _arguments.length) {
-      throw new IllegalArgumentException(
-          "Expected ${_arguments.length} parameters, not ${parameters.length}");
-    }
-    _correspondingPropagatedParameters = parameters;
-  }
-
-  /**
-   * Set the parameter elements corresponding to each of the arguments in this
-   * list to the given list of parameters. The list of parameters must be the
-   * same length as the number of arguments, but can contain `null` entries if a
-   * given argument does not correspond to a formal parameter.
-   */
-  void set correspondingStaticParameters(List<ParameterElement> parameters) {
-    if (parameters.length != _arguments.length) {
-      throw new IllegalArgumentException(
-          "Expected ${_arguments.length} parameters, not ${parameters.length}");
-    }
-    _correspondingStaticParameters = parameters;
-  }
-
-  @override
-  Token get endToken => rightParenthesis;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitArgumentList(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _arguments.accept(visitor);
-  }
-
-  /**
-   * If
-   * * the given [expression] is a child of this list,
-   * * the AST structure has been resolved,
-   * * the function being invoked is known based on propagated type information,
-   *   and
-   * * the expression corresponds to one of the parameters of the function being
-   *   invoked,
-   * then return the parameter element representing the parameter to which the
-   * value of the given expression will be bound. Otherwise, return `null`.
-   */
-  ParameterElement _getPropagatedParameterElementFor(Expression expression) {
-    if (_correspondingPropagatedParameters == null ||
-        _correspondingPropagatedParameters.length != _arguments.length) {
-      // Either the AST structure has not been resolved, the invocation of which
-      // this list is a part could not be resolved, or the argument list was
-      // modified after the parameters were set.
-      return null;
-    }
-    int index = _arguments.indexOf(expression);
-    if (index < 0) {
-      // The expression isn't a child of this node.
-      return null;
-    }
-    return _correspondingPropagatedParameters[index];
-  }
-
-  /**
-   * If
-   * * the given [expression] is a child of this list,
-   * * the AST structure has been resolved,
-   * * the function being invoked is known based on static type information, and
-   * * the expression corresponds to one of the parameters of the function being
-   *   invoked,
-   * then return the parameter element representing the parameter to which the
-   * value of the given expression will be bound. Otherwise, return `null`.
-   */
-  ParameterElement _getStaticParameterElementFor(Expression expression) {
-    if (_correspondingStaticParameters == null ||
-        _correspondingStaticParameters.length != _arguments.length) {
-      // Either the AST structure has not been resolved, the invocation of which
-      // this list is a part could not be resolved, or the argument list was
-      // modified after the parameters were set.
-      return null;
-    }
-    int index = _arguments.indexOf(expression);
-    if (index < 0) {
-      // The expression isn't a child of this node.
-      return null;
-    }
-    return _correspondingStaticParameters[index];
-  }
-}
-
-/**
- * An as expression.
- *
- * > asExpression ::=
- * >     [Expression] 'as' [TypeName]
- */
-class AsExpression extends Expression {
-  /**
-   * The expression used to compute the value being cast.
-   */
-  Expression _expression;
-
-  /**
-   * The 'as' operator.
-   */
-  Token asOperator;
-
-  /**
-   * The name of the type being cast to.
-   */
-  TypeName _type;
-
-  /**
-   * Initialize a newly created as expression.
-   */
-  AsExpression(Expression expression, this.asOperator, TypeName type) {
-    _expression = _becomeParentOf(expression);
-    _type = _becomeParentOf(type);
-  }
-
-  @override
-  Token get beginToken => _expression.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_expression)..add(asOperator)..add(_type);
-
-  @override
-  Token get endToken => _type.endToken;
-
-  /**
-   * Return the expression used to compute the value being cast.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression used to compute the value being cast to the given
-   * [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 7;
-
-  /**
-   * Return the name of the type being cast to.
-   */
-  TypeName get type => _type;
-
-  /**
-   * Set the name of the type being cast to to the given [name].
-   */
-  void set type(TypeName name) {
-    _type = _becomeParentOf(name);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitAsExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-    _safelyVisitChild(_type, visitor);
-  }
-}
-
-/**
- * An assert statement.
- *
- * > assertStatement ::=
- * >     'assert' '(' [Expression] ')' ';'
- */
-class AssertStatement extends Statement {
-  /**
-   * The token representing the 'assert' keyword.
-   */
-  Token assertKeyword;
-
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The condition that is being asserted to be `true`.
-   */
-  Expression _condition;
-
-  /**
-   * The comma, if a message expression was supplied.  Otherwise `null`.
-   */
-  Token comma;
-
-  /**
-   * The message to report if the assertion fails.  `null` if no message was
-   * supplied.
-   */
-  Expression _message;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * The semicolon terminating the statement.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created assert statement.
-   */
-  AssertStatement(
-      this.assertKeyword,
-      this.leftParenthesis,
-      Expression condition,
-      this.comma,
-      Expression message,
-      this.rightParenthesis,
-      this.semicolon) {
-    _condition = _becomeParentOf(condition);
-    _message = _becomeParentOf(message);
-  }
-
-  @override
-  Token get beginToken => assertKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(assertKeyword)
-    ..add(leftParenthesis)
-    ..add(_condition)
-    ..add(comma)
-    ..add(_message)
-    ..add(rightParenthesis)
-    ..add(semicolon);
-
-  /**
-   * Return the condition that is being asserted to be `true`.
-   */
-  Expression get condition => _condition;
-
-  /**
-   * Set the condition that is being asserted to be `true` to the given
-   * [expression].
-   */
-  void set condition(Expression condition) {
-    _condition = _becomeParentOf(condition);
-  }
-
-  @override
-  Token get endToken => semicolon;
-
-  /**
-   * Return the message to report if the assertion fails.
-   */
-  Expression get message => _message;
-
-  /**
-   * Set the message to report if the assertion fails to the given
-   * [expression].
-   */
-  void set message(Expression expression) {
-    _message = _becomeParentOf(expression);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitAssertStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_condition, visitor);
-    _safelyVisitChild(message, visitor);
-  }
-}
-
-/**
- * An assignment expression.
- *
- * > assignmentExpression ::=
- * >     [Expression] operator [Expression]
- */
-class AssignmentExpression extends Expression {
-  /**
-   * The expression used to compute the left hand side.
-   */
-  Expression _leftHandSide;
-
-  /**
-   * The assignment operator being applied.
-   */
-  Token operator;
-
-  /**
-   * The expression used to compute the right hand side.
-   */
-  Expression _rightHandSide;
-
-  /**
-   * The element associated with the operator based on the static type of the
-   * left-hand-side, or `null` if the AST structure has not been resolved, if
-   * the operator is not a compound operator, or if the operator could not be
-   * resolved.
-   */
-  MethodElement staticElement;
-
-  /**
-   * The element associated with the operator based on the propagated type of
-   * the left-hand-side, or `null` if the AST structure has not been resolved,
-   * if the operator is not a compound operator, or if the operator could not be
-   * resolved.
-   */
-  MethodElement propagatedElement;
-
-  /**
-   * Initialize a newly created assignment expression.
-   */
-  AssignmentExpression(
-      Expression leftHandSide, this.operator, Expression rightHandSide) {
-    if (leftHandSide == null || rightHandSide == null) {
-      String message;
-      if (leftHandSide == null) {
-        if (rightHandSide == null) {
-          message = "Both the left-hand and right-hand sides are null";
-        } else {
-          message = "The left-hand size is null";
-        }
-      } else {
-        message = "The right-hand size is null";
-      }
-      AnalysisEngine.instance.logger.logError(
-          message, new CaughtException(new AnalysisException(message), null));
-    }
-    _leftHandSide = _becomeParentOf(leftHandSide);
-    _rightHandSide = _becomeParentOf(rightHandSide);
-  }
-
-  @override
-  Token get beginToken => _leftHandSide.beginToken;
-
-  /**
-   * Return the best element available for this operator. If resolution was able
-   * to find a better element based on type propagation, that element will be
-   * returned. Otherwise, the element found using the result of static analysis
-   * will be returned. If resolution has not been performed, then `null` will be
-   * returned.
-   */
-  MethodElement get bestElement {
-    MethodElement element = propagatedElement;
-    if (element == null) {
-      element = staticElement;
-    }
-    return element;
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(_leftHandSide)
-    ..add(operator)
-    ..add(_rightHandSide);
-
-  @override
-  Token get endToken => _rightHandSide.endToken;
-
-  /**
-   * Set the expression used to compute the left hand side to the given
-   * [expression].
-   */
-  Expression get leftHandSide => _leftHandSide;
-
-  /**
-   * Return the expression used to compute the left hand side.
-   */
-  void set leftHandSide(Expression expression) {
-    _leftHandSide = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 1;
-
-  /**
-   * Return the expression used to compute the right hand side.
-   */
-  Expression get rightHandSide => _rightHandSide;
-
-  /**
-   * Set the expression used to compute the left hand side to the given
-   * [expression].
-   */
-  void set rightHandSide(Expression expression) {
-    _rightHandSide = _becomeParentOf(expression);
-  }
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on propagated type information, then return the parameter
-   * element representing the parameter to which the value of the right operand
-   * will be bound. Otherwise, return `null`.
-   */
-  ParameterElement get _propagatedParameterElementForRightHandSide {
-    ExecutableElement executableElement = null;
-    if (propagatedElement != null) {
-      executableElement = propagatedElement;
-    } else {
-      if (_leftHandSide is Identifier) {
-        Identifier identifier = _leftHandSide as Identifier;
-        Element leftElement = identifier.propagatedElement;
-        if (leftElement is ExecutableElement) {
-          executableElement = leftElement;
-        }
-      }
-      if (_leftHandSide is PropertyAccess) {
-        SimpleIdentifier identifier =
-            (_leftHandSide as PropertyAccess).propertyName;
-        Element leftElement = identifier.propagatedElement;
-        if (leftElement is ExecutableElement) {
-          executableElement = leftElement;
-        }
-      }
-    }
-    if (executableElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = executableElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on static type information, then return the parameter element
-   * representing the parameter to which the value of the right operand will be
-   * bound. Otherwise, return `null`.
-   */
-  ParameterElement get _staticParameterElementForRightHandSide {
-    ExecutableElement executableElement = null;
-    if (staticElement != null) {
-      executableElement = staticElement;
-    } else {
-      if (_leftHandSide is Identifier) {
-        Element leftElement = (_leftHandSide as Identifier).staticElement;
-        if (leftElement is ExecutableElement) {
-          executableElement = leftElement;
-        }
-      }
-      if (_leftHandSide is PropertyAccess) {
-        Element leftElement =
-            (_leftHandSide as PropertyAccess).propertyName.staticElement;
-        if (leftElement is ExecutableElement) {
-          executableElement = leftElement;
-        }
-      }
-    }
-    if (executableElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = executableElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitAssignmentExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_leftHandSide, visitor);
-    _safelyVisitChild(_rightHandSide, visitor);
-  }
-}
-
-/**
- * A node in the AST structure for a Dart program.
- */
-abstract class AstNode {
-  /**
-   * An empty list of AST nodes.
-   */
-  static const List<AstNode> EMPTY_LIST = const <AstNode>[];
-
-  /**
-   * A comparator that can be used to sort AST nodes in lexical order. In other
-   * words, `compare` will return a negative value if the offset of the first
-   * node is less than the offset of the second node, zero (0) if the nodes have
-   * the same offset, and a positive value if the offset of the first node is
-   * greater than the offset of the second node.
-   */
-  static Comparator<AstNode> LEXICAL_ORDER =
-      (AstNode first, AstNode second) => first.offset - second.offset;
-
-  /**
-   * The parent of the node, or `null` if the node is the root of an AST
-   * structure.
-   */
-  AstNode _parent;
-
-  /**
-   * A table mapping the names of properties to their values, or `null` if this
-   * node does not have any properties associated with it.
-   */
-  Map<String, Object> _propertyMap;
-
-  /**
-   * Return the first token included in this node's source range.
-   */
-  Token get beginToken;
-
-  /**
-   * Iterate through all the entities (either AST nodes or tokens) which make
-   * up the contents of this node, including doc comments but excluding other
-   * comments.
-   */
-  Iterable /*<AstNode | Token>*/ get childEntities;
-
-  /**
-   * Return the offset of the character immediately following the last character
-   * of this node's source range. This is equivalent to
-   * `node.getOffset() + node.getLength()`. For a compilation unit this will be
-   * equal to the length of the unit's source. For synthetic nodes this will be
-   * equivalent to the node's offset (because the length is zero (0) by
-   * definition).
-   */
-  int get end => offset + length;
-
-  /**
-   * Return the last token included in this node's source range.
-   */
-  Token get endToken;
-
-  /**
-   * Return `true` if this node is a synthetic node. A synthetic node is a node
-   * that was introduced by the parser in order to recover from an error in the
-   * code. Synthetic nodes always have a length of zero (`0`).
-   */
-  bool get isSynthetic => false;
-
-  /**
-   * Return the number of characters in the node's source range.
-   */
-  int get length {
-    Token beginToken = this.beginToken;
-    Token endToken = this.endToken;
-    if (beginToken == null || endToken == null) {
-      return -1;
-    }
-    return endToken.offset + endToken.length - beginToken.offset;
-  }
-
-  /**
-   * Return the offset from the beginning of the file to the first character in
-   * the node's source range.
-   */
-  int get offset {
-    Token beginToken = this.beginToken;
-    if (beginToken == null) {
-      return -1;
-    }
-    return beginToken.offset;
-  }
-
-  /**
-   * Return this node's parent node, or `null` if this node is the root of an
-   * AST structure.
-   *
-   * Note that the relationship between an AST node and its parent node may
-   * change over the lifetime of a node.
-   */
-  AstNode get parent => _parent;
-
-  /**
-   * Return the node at the root of this node's AST structure. Note that this
-   * method's performance is linear with respect to the depth of the node in the
-   * AST structure (O(depth)).
-   */
-  AstNode get root {
-    AstNode root = this;
-    AstNode parent = this.parent;
-    while (parent != null) {
-      root = parent;
-      parent = root.parent;
-    }
-    return root;
-  }
-
-  /**
-   * Use the given [visitor] to visit this node. Return the value returned by
-   * the visitor as a result of visiting this node.
-   */
-  dynamic /*=E*/ accept /*<E>*/ (AstVisitor /*<E>*/ visitor);
-
-  /**
-   * Return the most immediate ancestor of this node for which the [predicate]
-   * returns `true`, or `null` if there is no such ancestor. Note that this node
-   * will never be returned.
-   */
-  AstNode getAncestor(Predicate<AstNode> predicate) {
-    // TODO(brianwilkerson) It is a bug that this method can return `this`.
-    AstNode node = this;
-    while (node != null && !predicate(node)) {
-      node = node.parent;
-    }
-    return node;
-  }
-
-  /**
-   * Return the value of the property with the given [name], or `null` if this
-   * node does not have a property with the given name.
-   */
-  Object getProperty(String name) {
-    if (_propertyMap == null) {
-      return null;
-    }
-    return _propertyMap[name];
-  }
-
-  /**
-   * Set the value of the property with the given [name] to the given [value].
-   * If the value is `null`, the property will effectively be removed.
-   */
-  void setProperty(String name, Object value) {
-    if (value == null) {
-      if (_propertyMap != null) {
-        _propertyMap.remove(name);
-        if (_propertyMap.isEmpty) {
-          _propertyMap = null;
-        }
-      }
-    } else {
-      if (_propertyMap == null) {
-        _propertyMap = new HashMap<String, Object>();
-      }
-      _propertyMap[name] = value;
-    }
-  }
-
-  /**
-   * Return a textual description of this node in a form approximating valid
-   * source. The returned string will not be valid source primarily in the case
-   * where the node itself is not well-formed.
-   */
-  String toSource() {
-    PrintStringWriter writer = new PrintStringWriter();
-    accept(new ToSourceVisitor(writer));
-    return writer.toString();
-  }
-
-  @override
-  String toString() => toSource();
-
-  /**
-   * Use the given [visitor] to visit all of the children of this node. The
-   * children will be visited in lexical order.
-   */
-  void visitChildren(AstVisitor visitor);
-
-  /**
-   * Make this node the parent of the given [child] node. Return the child node.
-   */
-  AstNode _becomeParentOf(AstNode child) {
-    if (child != null) {
-      child._parent = this;
-    }
-    return child;
-  }
-
-  /**
-   * If the given [child] is not `null`, use the given [visitor] to visit it.
-   */
-  void _safelyVisitChild(AstNode child, AstVisitor visitor) {
-    if (child != null) {
-      child.accept(visitor);
-    }
-  }
-}
-
-/**
- * An object that can be used to visit an AST structure.
- */
-abstract class AstVisitor<R> {
-  R visitAdjacentStrings(AdjacentStrings node);
-
-  R visitAnnotation(Annotation node);
-
-  R visitArgumentList(ArgumentList node);
-
-  R visitAsExpression(AsExpression node);
-
-  R visitAssertStatement(AssertStatement assertStatement);
-
-  R visitAssignmentExpression(AssignmentExpression node);
-
-  R visitAwaitExpression(AwaitExpression node);
-
-  R visitBinaryExpression(BinaryExpression node);
-
-  R visitBlock(Block node);
-
-  R visitBlockFunctionBody(BlockFunctionBody node);
-
-  R visitBooleanLiteral(BooleanLiteral node);
-
-  R visitBreakStatement(BreakStatement node);
-
-  R visitCascadeExpression(CascadeExpression node);
-
-  R visitCatchClause(CatchClause node);
-
-  R visitClassDeclaration(ClassDeclaration node);
-
-  R visitClassTypeAlias(ClassTypeAlias node);
-
-  R visitComment(Comment node);
-
-  R visitCommentReference(CommentReference node);
-
-  R visitCompilationUnit(CompilationUnit node);
-
-  R visitConditionalExpression(ConditionalExpression node);
-
-  R visitConfiguration(Configuration node);
-
-  R visitConstructorDeclaration(ConstructorDeclaration node);
-
-  R visitConstructorFieldInitializer(ConstructorFieldInitializer node);
-
-  R visitConstructorName(ConstructorName node);
-
-  R visitContinueStatement(ContinueStatement node);
-
-  R visitDeclaredIdentifier(DeclaredIdentifier node);
-
-  R visitDefaultFormalParameter(DefaultFormalParameter node);
-
-  R visitDoStatement(DoStatement node);
-
-  R visitDottedName(DottedName node);
-
-  R visitDoubleLiteral(DoubleLiteral node);
-
-  R visitEmptyFunctionBody(EmptyFunctionBody node);
-
-  R visitEmptyStatement(EmptyStatement node);
-
-  R visitEnumConstantDeclaration(EnumConstantDeclaration node);
-
-  R visitEnumDeclaration(EnumDeclaration node);
-
-  R visitExportDirective(ExportDirective node);
-
-  R visitExpressionFunctionBody(ExpressionFunctionBody node);
-
-  R visitExpressionStatement(ExpressionStatement node);
-
-  R visitExtendsClause(ExtendsClause node);
-
-  R visitFieldDeclaration(FieldDeclaration node);
-
-  R visitFieldFormalParameter(FieldFormalParameter node);
-
-  R visitForEachStatement(ForEachStatement node);
-
-  R visitFormalParameterList(FormalParameterList node);
-
-  R visitForStatement(ForStatement node);
-
-  R visitFunctionDeclaration(FunctionDeclaration node);
-
-  R visitFunctionDeclarationStatement(FunctionDeclarationStatement node);
-
-  R visitFunctionExpression(FunctionExpression node);
-
-  R visitFunctionExpressionInvocation(FunctionExpressionInvocation node);
-
-  R visitFunctionTypeAlias(FunctionTypeAlias functionTypeAlias);
-
-  R visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node);
-
-  R visitHideCombinator(HideCombinator node);
-
-  R visitIfStatement(IfStatement node);
-
-  R visitImplementsClause(ImplementsClause node);
-
-  R visitImportDirective(ImportDirective node);
-
-  R visitIndexExpression(IndexExpression node);
-
-  R visitInstanceCreationExpression(InstanceCreationExpression node);
-
-  R visitIntegerLiteral(IntegerLiteral node);
-
-  R visitInterpolationExpression(InterpolationExpression node);
-
-  R visitInterpolationString(InterpolationString node);
-
-  R visitIsExpression(IsExpression node);
-
-  R visitLabel(Label node);
-
-  R visitLabeledStatement(LabeledStatement node);
-
-  R visitLibraryDirective(LibraryDirective node);
-
-  R visitLibraryIdentifier(LibraryIdentifier node);
-
-  R visitListLiteral(ListLiteral node);
-
-  R visitMapLiteral(MapLiteral node);
-
-  R visitMapLiteralEntry(MapLiteralEntry node);
-
-  R visitMethodDeclaration(MethodDeclaration node);
-
-  R visitMethodInvocation(MethodInvocation node);
-
-  R visitNamedExpression(NamedExpression node);
-
-  R visitNativeClause(NativeClause node);
-
-  R visitNativeFunctionBody(NativeFunctionBody node);
-
-  R visitNullLiteral(NullLiteral node);
-
-  R visitParenthesizedExpression(ParenthesizedExpression node);
-
-  R visitPartDirective(PartDirective node);
-
-  R visitPartOfDirective(PartOfDirective node);
-
-  R visitPostfixExpression(PostfixExpression node);
-
-  R visitPrefixedIdentifier(PrefixedIdentifier node);
-
-  R visitPrefixExpression(PrefixExpression node);
-
-  R visitPropertyAccess(PropertyAccess node);
-
-  R visitRedirectingConstructorInvocation(
-      RedirectingConstructorInvocation node);
-
-  R visitRethrowExpression(RethrowExpression node);
-
-  R visitReturnStatement(ReturnStatement node);
-
-  R visitScriptTag(ScriptTag node);
-
-  R visitShowCombinator(ShowCombinator node);
-
-  R visitSimpleFormalParameter(SimpleFormalParameter node);
-
-  R visitSimpleIdentifier(SimpleIdentifier node);
-
-  R visitSimpleStringLiteral(SimpleStringLiteral node);
-
-  R visitStringInterpolation(StringInterpolation node);
-
-  R visitSuperConstructorInvocation(SuperConstructorInvocation node);
-
-  R visitSuperExpression(SuperExpression node);
-
-  R visitSwitchCase(SwitchCase node);
-
-  R visitSwitchDefault(SwitchDefault node);
-
-  R visitSwitchStatement(SwitchStatement node);
-
-  R visitSymbolLiteral(SymbolLiteral node);
-
-  R visitThisExpression(ThisExpression node);
-
-  R visitThrowExpression(ThrowExpression node);
-
-  R visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node);
-
-  R visitTryStatement(TryStatement node);
-
-  R visitTypeArgumentList(TypeArgumentList node);
-
-  R visitTypeName(TypeName node);
-
-  R visitTypeParameter(TypeParameter node);
-
-  R visitTypeParameterList(TypeParameterList node);
-
-  R visitVariableDeclaration(VariableDeclaration node);
-
-  R visitVariableDeclarationList(VariableDeclarationList node);
-
-  R visitVariableDeclarationStatement(VariableDeclarationStatement node);
-
-  R visitWhileStatement(WhileStatement node);
-
-  R visitWithClause(WithClause node);
-
-  R visitYieldStatement(YieldStatement node);
-}
-
-/**
- * An await expression.
- *
- * > awaitExpression ::=
- * >     'await' [Expression]
- */
-class AwaitExpression extends Expression {
-  /**
-   * The 'await' keyword.
-   */
-  Token awaitKeyword;
-
-  /**
-   * The expression whose value is being waited on.
-   */
-  Expression _expression;
-
-  /**
-   * Initialize a newly created await expression.
-   */
-  AwaitExpression(this.awaitKeyword, Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken {
-    if (awaitKeyword != null) {
-      return awaitKeyword;
-    }
-    return _expression.beginToken;
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(awaitKeyword)..add(_expression);
-
-  @override
-  Token get endToken => _expression.endToken;
-
-  /**
-   * Return the expression whose value is being waited on.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression whose value is being waited on to the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 0;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitAwaitExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * A binary (infix) expression.
- *
- * > binaryExpression ::=
- * >     [Expression] [Token] [Expression]
- */
-class BinaryExpression extends Expression {
-  /**
-   * The expression used to compute the left operand.
-   */
-  Expression _leftOperand;
-
-  /**
-   * The binary operator being applied.
-   */
-  Token operator;
-
-  /**
-   * The expression used to compute the right operand.
-   */
-  Expression _rightOperand;
-
-  /**
-   * The element associated with the operator based on the static type of the
-   * 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.
-   */
-  MethodElement staticElement;
-
-  /**
-   * The element associated with the operator based on the propagated type of
-   * the 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.
-   */
-  MethodElement propagatedElement;
-
-  /**
-   * Initialize a newly created binary expression.
-   */
-  BinaryExpression(
-      Expression leftOperand, this.operator, Expression rightOperand) {
-    _leftOperand = _becomeParentOf(leftOperand);
-    _rightOperand = _becomeParentOf(rightOperand);
-  }
-
-  @override
-  Token get beginToken => _leftOperand.beginToken;
-
-  /**
-   * Return the best element available for this operator. If resolution was able
-   * to find a better element based on type propagation, that element will be
-   * returned. Otherwise, the element found using the result of static analysis
-   * will be returned. If resolution has not been performed, then `null` will be
-   * returned.
-   */
-  MethodElement get bestElement {
-    MethodElement element = propagatedElement;
-    if (element == null) {
-      element = staticElement;
-    }
-    return element;
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_leftOperand)..add(operator)..add(_rightOperand);
-
-  @override
-  Token get endToken => _rightOperand.endToken;
-
-  /**
-   * Return the expression used to compute the left operand.
-   */
-  Expression get leftOperand => _leftOperand;
-
-  /**
-   * Set the expression used to compute the left operand to the given
-   * [expression].
-   */
-  void set leftOperand(Expression expression) {
-    _leftOperand = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => operator.type.precedence;
-
-  /**
-   * Return the expression used to compute the right operand.
-   */
-  Expression get rightOperand => _rightOperand;
-
-  /**
-   * Set the expression used to compute the right operand to the given
-   * [expression].
-   */
-  void set rightOperand(Expression expression) {
-    _rightOperand = _becomeParentOf(expression);
-  }
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on propagated type information, then return the parameter
-   * element representing the parameter to which the value of the right operand
-   * will be bound. Otherwise, return `null`.
-   */
-  ParameterElement get _propagatedParameterElementForRightOperand {
-    if (propagatedElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = propagatedElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on static type information, then return the parameter element
-   * representing the parameter to which the value of the right operand will be
-   * bound. Otherwise, return `null`.
-   */
-  ParameterElement get _staticParameterElementForRightOperand {
-    if (staticElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = staticElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitBinaryExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_leftOperand, visitor);
-    _safelyVisitChild(_rightOperand, visitor);
-  }
-}
-
-/**
- * A sequence of statements.
- *
- * > block ::=
- * >     '{' statement* '}'
- */
-class Block extends Statement {
-  /**
-   * The left curly bracket.
-   */
-  Token leftBracket;
-
-  /**
-   * The statements contained in the block.
-   */
-  NodeList<Statement> _statements;
-
-  /**
-   * The right curly bracket.
-   */
-  Token rightBracket;
-
-  /**
-   * Initialize a newly created block of code.
-   */
-  Block(this.leftBracket, List<Statement> statements, this.rightBracket) {
-    _statements = new NodeList<Statement>(this, statements);
-  }
-
-  @override
-  Token get beginToken => leftBracket;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(leftBracket)
-    ..addAll(_statements)
-    ..add(rightBracket);
-
-  @override
-  Token get endToken => rightBracket;
-
-  /**
-   * Return the statements contained in the block.
-   */
-  NodeList<Statement> get statements => _statements;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitBlock(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _statements.accept(visitor);
-  }
-}
-
-/**
- * A function body that consists of a block of statements.
- *
- * > blockFunctionBody ::=
- * >     ('async' | 'async' '*' | 'sync' '*')? [Block]
- */
-class BlockFunctionBody extends FunctionBody {
-  /**
-   * The token representing the 'async' or 'sync' keyword, or `null` if there is
-   * no such keyword.
-   */
-  Token keyword;
-
-  /**
-   * The star optionally following the 'async' or 'sync' keyword, or `null` if
-   * there is wither no such keyword or no star.
-   */
-  Token star;
-
-  /**
-   * The block representing the body of the function.
-   */
-  Block _block;
-
-  /**
-   * Initialize a newly created function body consisting of a block of
-   * statements. The [keyword] can be `null` if there is no keyword specified
-   * for the block. The [star] can be `null` if there is no star following the
-   * keyword (and must be `null` if there is no keyword).
-   */
-  BlockFunctionBody(this.keyword, this.star, Block block) {
-    _block = _becomeParentOf(block);
-  }
-
-  @override
-  Token get beginToken {
-    if (keyword != null) {
-      return keyword;
-    }
-    return _block.beginToken;
-  }
-
-  /**
-   * Return the block representing the body of the function.
-   */
-  Block get block => _block;
-
-  /**
-   * Set the block representing the body of the function to the given [block].
-   */
-  void set block(Block block) {
-    _block = _becomeParentOf(block);
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(keyword)..add(star)..add(_block);
-
-  @override
-  Token get endToken => _block.endToken;
-
-  @override
-  bool get isAsynchronous => keyword != null && keyword.lexeme == Parser.ASYNC;
-
-  @override
-  bool get isGenerator => star != null;
-
-  @override
-  bool get isSynchronous => keyword == null || keyword.lexeme != Parser.ASYNC;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitBlockFunctionBody(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_block, visitor);
-  }
-}
-
-/**
- * A boolean literal expression.
- *
- * > booleanLiteral ::=
- * >     'false' | 'true'
- */
-class BooleanLiteral extends Literal {
-  /**
-   * The token representing the literal.
-   */
-  Token literal;
-
-  /**
-   * The value of the literal.
-   */
-  bool value = false;
-
-  /**
-   * Initialize a newly created boolean literal.
-   */
-  BooleanLiteral(this.literal, this.value);
-
-  @override
-  Token get beginToken => literal;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(literal);
-
-  @override
-  Token get endToken => literal;
-
-  @override
-  bool get isSynthetic => literal.isSynthetic;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitBooleanLiteral(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * A break statement.
- *
- * > breakStatement ::=
- * >     'break' [SimpleIdentifier]? ';'
- */
-class BreakStatement extends Statement {
-  /**
-   * The token representing the 'break' keyword.
-   */
-  Token breakKeyword;
-
-  /**
-   * The label associated with the statement, or `null` if there is no label.
-   */
-  SimpleIdentifier _label;
-
-  /**
-   * The semicolon terminating the statement.
-   */
-  Token semicolon;
-
-  /**
-   * The AstNode which this break statement is breaking from.  This will be
-   * either a [Statement] (in the case of breaking out of a loop), a
-   * [SwitchMember] (in the case of a labeled break statement whose label
-   * matches a label on a switch case in an enclosing switch statement), or
-   * `null` if the AST has not yet been resolved or if the target could not be
-   * resolved. Note that if the source code has errors, the target might be
-   * invalid (e.g. trying to break to a switch case).
-   */
-  AstNode target;
-
-  /**
-   * Initialize a newly created break statement. The [label] can be `null` if
-   * there is no label associated with the statement.
-   */
-  BreakStatement(this.breakKeyword, SimpleIdentifier label, this.semicolon) {
-    _label = _becomeParentOf(label);
-  }
-
-  @override
-  Token get beginToken => breakKeyword;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(breakKeyword)..add(_label)..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  /**
-   * Return the label associated with the statement, or `null` if there is no
-   * label.
-   */
-  SimpleIdentifier get label => _label;
-
-  /**
-   * Set the label associated with the statement to the given [identifier].
-   */
-  void set label(SimpleIdentifier identifier) {
-    _label = _becomeParentOf(identifier);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitBreakStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_label, visitor);
-  }
-}
-
-/**
- * A sequence of cascaded expressions: expressions that share a common target.
- * 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
- */
-class CascadeExpression extends Expression {
-  /**
-   * The target of the cascade sections.
-   */
-  Expression _target;
-
-  /**
-   * The cascade sections sharing the common target.
-   */
-  NodeList<Expression> _cascadeSections;
-
-  /**
-   * Initialize a newly created cascade expression. The list of
-   * [cascadeSections] must contain at least one element.
-   */
-  CascadeExpression(Expression target, List<Expression> cascadeSections) {
-    _target = _becomeParentOf(target);
-    _cascadeSections = new NodeList<Expression>(this, cascadeSections);
-  }
-
-  @override
-  Token get beginToken => _target.beginToken;
-
-  /**
-   * Return the cascade sections sharing the common target.
-   */
-  NodeList<Expression> get cascadeSections => _cascadeSections;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(_target)
-    ..addAll(_cascadeSections);
-
-  @override
-  Token get endToken => _cascadeSections.endToken;
-
-  @override
-  int get precedence => 2;
-
-  /**
-   * Return the target of the cascade sections.
-   */
-  Expression get target => _target;
-
-  /**
-   * Set the target of the cascade sections to the given [expression].
-   */
-  void set target(Expression target) {
-    _target = _becomeParentOf(target);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitCascadeExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_target, visitor);
-    _cascadeSections.accept(visitor);
-  }
-}
-
-/**
- * A catch clause within a try statement.
- *
- * > onPart ::=
- * >     catchPart [Block]
- * >   | 'on' type catchPart? [Block]
- * >
- * > catchPart ::=
- * >     'catch' '(' [SimpleIdentifier] (',' [SimpleIdentifier])? ')'
- */
-class CatchClause extends AstNode {
-  /**
-   * The token representing the 'on' keyword, or `null` if there is no 'on'
-   * keyword.
-   */
-  Token onKeyword;
-
-  /**
-   * The type of exceptions caught by this catch clause, or `null` if this catch
-   * clause catches every type of exception.
-   */
-  TypeName _exceptionType;
-
-  /**
-   * The token representing the 'catch' keyword, or `null` if there is no
-   * 'catch' keyword.
-   */
-  Token catchKeyword;
-
-  /**
-   * The left parenthesis, or `null` if there is no 'catch' keyword.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The parameter whose value will be the exception that was thrown, or `null`
-   * if there is no 'catch' keyword.
-   */
-  SimpleIdentifier _exceptionParameter;
-
-  /**
-   * The comma separating the exception parameter from the stack trace
-   * parameter, or `null` if there is no stack trace parameter.
-   */
-  Token comma;
-
-  /**
-   * The parameter whose value will be the stack trace associated with the
-   * exception, or `null` if there is no stack trace parameter.
-   */
-  SimpleIdentifier _stackTraceParameter;
-
-  /**
-   * The right parenthesis, or `null` if there is no 'catch' keyword.
-   */
-  Token rightParenthesis;
-
-  /**
-   * The body of the catch block.
-   */
-  Block _body;
-
-  /**
-   * Initialize a newly created catch clause. The [onKeyword] and
-   * [exceptionType] can be `null` if the clause will catch all exceptions. The
-   * [comma] and [stackTraceParameter] can be `null` if the stack trace is not
-   * referencable within the body.
-   */
-  CatchClause(
-      this.onKeyword,
-      TypeName exceptionType,
-      this.catchKeyword,
-      this.leftParenthesis,
-      SimpleIdentifier exceptionParameter,
-      this.comma,
-      SimpleIdentifier stackTraceParameter,
-      this.rightParenthesis,
-      Block body) {
-    _exceptionType = _becomeParentOf(exceptionType);
-    _exceptionParameter = _becomeParentOf(exceptionParameter);
-    _stackTraceParameter = _becomeParentOf(stackTraceParameter);
-    _body = _becomeParentOf(body);
-  }
-
-  @override
-  Token get beginToken {
-    if (onKeyword != null) {
-      return onKeyword;
-    }
-    return catchKeyword;
-  }
-
-  /**
-   * Return the body of the catch block.
-   */
-  Block get body => _body;
-
-  /**
-   * Set the body of the catch block to the given [block].
-   */
-  void set body(Block block) {
-    _body = _becomeParentOf(block);
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(onKeyword)
-    ..add(_exceptionType)
-    ..add(catchKeyword)
-    ..add(leftParenthesis)
-    ..add(_exceptionParameter)
-    ..add(comma)
-    ..add(_stackTraceParameter)
-    ..add(rightParenthesis)
-    ..add(_body);
-
-  @override
-  Token get endToken => _body.endToken;
-
-  /**
-   * Return the parameter whose value will be the exception that was thrown, or
-   * `null` if there is no 'catch' keyword.
-   */
-  SimpleIdentifier get exceptionParameter => _exceptionParameter;
-
-  /**
-   * Set the parameter whose value will be the exception that was thrown to the
-   * given [parameter].
-   */
-  void set exceptionParameter(SimpleIdentifier parameter) {
-    _exceptionParameter = _becomeParentOf(parameter);
-  }
-
-  /**
-   * Return the type of exceptions caught by this catch clause, or `null` if
-   * this catch clause catches every type of exception.
-   */
-  TypeName get exceptionType => _exceptionType;
-
-  /**
-   * Set the type of exceptions caught by this catch clause to the given
-   * [exceptionType].
-   */
-  void set exceptionType(TypeName exceptionType) {
-    _exceptionType = _becomeParentOf(exceptionType);
-  }
-
-  /**
-   * Return the parameter whose value will be the stack trace associated with
-   * the exception, or `null` if there is no stack trace parameter.
-   */
-  SimpleIdentifier get stackTraceParameter => _stackTraceParameter;
-
-  /**
-   * Set the parameter whose value will be the stack trace associated with the
-   * exception to the given [parameter].
-   */
-  void set stackTraceParameter(SimpleIdentifier parameter) {
-    _stackTraceParameter = _becomeParentOf(parameter);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitCatchClause(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_exceptionType, visitor);
-    _safelyVisitChild(_exceptionParameter, visitor);
-    _safelyVisitChild(_stackTraceParameter, visitor);
-    _safelyVisitChild(_body, visitor);
-  }
-}
-
-/**
- * Helper class to allow iteration of child entities of an AST node.
- */
-class ChildEntities extends Object with IterableMixin implements Iterable {
-  /**
-   * The list of child entities to be iterated over.
-   */
-  List _entities = [];
-
-  @override
-  Iterator get iterator => _entities.iterator;
-
-  /**
-   * Add an AST node or token as the next child entity, if it is not null.
-   */
-  void add(entity) {
-    if (entity != null) {
-      assert(entity is Token || entity is AstNode);
-      _entities.add(entity);
-    }
-  }
-
-  /**
-   * Add the given items as the next child entities, if [items] is not null.
-   */
-  void addAll(Iterable items) {
-    if (items != null) {
-      _entities.addAll(items);
-    }
-  }
-}
-
-/**
- * The declaration of a class.
- *
- * > classDeclaration ::=
- * >     'abstract'? 'class' [SimpleIdentifier] [TypeParameterList]?
- * >     ([ExtendsClause] [WithClause]?)?
- * >     [ImplementsClause]?
- * >     '{' [ClassMember]* '}'
- */
-class ClassDeclaration extends NamedCompilationUnitMember {
-  /**
-   * The 'abstract' keyword, or `null` if the keyword was absent.
-   */
-  Token abstractKeyword;
-
-  /**
-   * The token representing the 'class' keyword.
-   */
-  Token classKeyword;
-
-  /**
-   * The type parameters for the class, or `null` if the class does not have any
-   * type parameters.
-   */
-  TypeParameterList _typeParameters;
-
-  /**
-   * The extends clause for the class, or `null` if the class does not extend
-   * any other class.
-   */
-  ExtendsClause _extendsClause;
-
-  /**
-   * The with clause for the class, or `null` if the class does not have a with
-   * clause.
-   */
-  WithClause _withClause;
-
-  /**
-   * The implements clause for the class, or `null` if the class does not
-   * implement any interfaces.
-   */
-  ImplementsClause _implementsClause;
-
-  /**
-   * The native clause for the class, or `null` if the class does not have a
-   * native clause.
-   */
-  NativeClause _nativeClause;
-
-  /**
-   * The left curly bracket.
-   */
-  Token leftBracket;
-
-  /**
-   * The members defined by the class.
-   */
-  NodeList<ClassMember> _members;
-
-  /**
-   * The right curly bracket.
-   */
-  Token rightBracket;
-
-  /**
-   * Initialize a newly created class declaration. Either or both of the
-   * [comment] and [metadata] can be `null` if the class does not have the
-   * corresponding attribute. The [abstractKeyword] can be `null` if the class
-   * is not abstract. The [typeParameters] can be `null` if the class does not
-   * have any type parameters. Any or all of the [extendsClause], [withClause],
-   * and [implementsClause] can be `null` if the class does not have the
-   * corresponding clause. The list of [members] can be `null` if the class does
-   * not have any members.
-   */
-  ClassDeclaration(
-      Comment comment,
-      List<Annotation> metadata,
-      this.abstractKeyword,
-      this.classKeyword,
-      SimpleIdentifier name,
-      TypeParameterList typeParameters,
-      ExtendsClause extendsClause,
-      WithClause withClause,
-      ImplementsClause implementsClause,
-      this.leftBracket,
-      List<ClassMember> members,
-      this.rightBracket)
-      : super(comment, metadata, name) {
-    _typeParameters = _becomeParentOf(typeParameters);
-    _extendsClause = _becomeParentOf(extendsClause);
-    _withClause = _becomeParentOf(withClause);
-    _implementsClause = _becomeParentOf(implementsClause);
-    _members = new NodeList<ClassMember>(this, members);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(abstractKeyword)
-    ..add(classKeyword)
-    ..add(_name)
-    ..add(_typeParameters)
-    ..add(_extendsClause)
-    ..add(_withClause)
-    ..add(_implementsClause)
-    ..add(_nativeClause)
-    ..add(leftBracket)
-    ..addAll(members)
-    ..add(rightBracket);
-
-  @override
-  ClassElement get element =>
-      _name != null ? (_name.staticElement as ClassElement) : null;
-
-  @override
-  Token get endToken => rightBracket;
-
-  /**
-   * Return the extends clause for this class, or `null` if the class does not
-   * extend any other class.
-   */
-  ExtendsClause get extendsClause => _extendsClause;
-
-  /**
-   * Set the extends clause for this class to the given [extendsClause].
-   */
-  void set extendsClause(ExtendsClause extendsClause) {
-    _extendsClause = _becomeParentOf(extendsClause);
-  }
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata {
-    if (abstractKeyword != null) {
-      return abstractKeyword;
-    }
-    return classKeyword;
-  }
-
-  /**
-   * Return the implements clause for the class, or `null` if the class does not
-   * implement any interfaces.
-   */
-  ImplementsClause get implementsClause => _implementsClause;
-
-  /**
-   * Set the implements clause for the class to the given [implementsClause].
-   */
-  void set implementsClause(ImplementsClause implementsClause) {
-    _implementsClause = _becomeParentOf(implementsClause);
-  }
-
-  /**
-   * Return `true` if this class is declared to be an abstract class.
-   */
-  bool get isAbstract => abstractKeyword != null;
-
-  /**
-   * Return the members defined by the class.
-   */
-  NodeList<ClassMember> get members => _members;
-
-  /**
-   * Return the native clause for this class, or `null` if the class does not
-   * have a native clause.
-   */
-  NativeClause get nativeClause => _nativeClause;
-
-  /**
-   * Set the native clause for this class to the given [nativeClause].
-   */
-  void set nativeClause(NativeClause nativeClause) {
-    _nativeClause = _becomeParentOf(nativeClause);
-  }
-
-  /**
-   * Return the type parameters for the class, or `null` if the class does not
-   * have any type parameters.
-   */
-  TypeParameterList get typeParameters => _typeParameters;
-
-  /**
-   * Set the type parameters for the class to the given list of [typeParameters].
-   */
-  void set typeParameters(TypeParameterList typeParameters) {
-    _typeParameters = _becomeParentOf(typeParameters);
-  }
-
-  /**
-   * Return the with clause for the class, or `null` if the class does not have
-   * a with clause.
-   */
-  WithClause get withClause => _withClause;
-
-  /**
-   * Set the with clause for the class to the given [withClause].
-   */
-  void set withClause(WithClause withClause) {
-    _withClause = _becomeParentOf(withClause);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitClassDeclaration(this);
-
-  /**
-   * Return the constructor declared in the class with the given [name], or
-   * `null` if there is no such constructor. If the [name] is `null` then the
-   * default constructor will be searched for.
-   */
-  ConstructorDeclaration getConstructor(String name) {
-    for (ClassMember classMember in _members) {
-      if (classMember is ConstructorDeclaration) {
-        ConstructorDeclaration constructor = classMember;
-        SimpleIdentifier constructorName = constructor.name;
-        if (name == null && constructorName == null) {
-          return constructor;
-        }
-        if (constructorName != null && constructorName.name == name) {
-          return constructor;
-        }
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Return the field declared in the class with the given [name], or `null` if
-   * there is no such field.
-   */
-  VariableDeclaration getField(String name) {
-    for (ClassMember classMember in _members) {
-      if (classMember is FieldDeclaration) {
-        FieldDeclaration fieldDeclaration = classMember;
-        NodeList<VariableDeclaration> fields =
-            fieldDeclaration.fields.variables;
-        for (VariableDeclaration field in fields) {
-          SimpleIdentifier fieldName = field.name;
-          if (fieldName != null && name == fieldName.name) {
-            return field;
-          }
-        }
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Return the method declared in the class with the given [name], or `null` if
-   * there is no such method.
-   */
-  MethodDeclaration getMethod(String name) {
-    for (ClassMember classMember in _members) {
-      if (classMember is MethodDeclaration) {
-        MethodDeclaration method = classMember;
-        SimpleIdentifier methodName = method.name;
-        if (methodName != null && name == methodName.name) {
-          return method;
-        }
-      }
-    }
-    return null;
-  }
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_typeParameters, visitor);
-    _safelyVisitChild(_extendsClause, visitor);
-    _safelyVisitChild(_withClause, visitor);
-    _safelyVisitChild(_implementsClause, visitor);
-    _safelyVisitChild(_nativeClause, visitor);
-    members.accept(visitor);
-  }
-}
-
-/**
- * A node that declares a name within the scope of a class.
- */
-abstract class ClassMember extends Declaration {
-  /**
-   * Initialize a newly created member of a class. Either or both of the
-   * [comment] and [metadata] can be `null` if the member does not have the
-   * corresponding attribute.
-   */
-  ClassMember(Comment comment, List<Annotation> metadata)
-      : super(comment, metadata);
-}
-
-/**
- * A class type alias.
- *
- * > classTypeAlias ::=
- * >     [SimpleIdentifier] [TypeParameterList]? '=' 'abstract'? mixinApplication
- * >
- * > mixinApplication ::=
- * >     [TypeName] [WithClause] [ImplementsClause]? ';'
- */
-class ClassTypeAlias extends TypeAlias {
-  /**
-   * The type parameters for the class, or `null` if the class does not have any
-   * type parameters.
-   */
-  TypeParameterList _typeParameters;
-
-  /**
-   * The token for the '=' separating the name from the definition.
-   */
-  Token equals;
-
-  /**
-   * The token for the 'abstract' keyword, or `null` if this is not defining an
-   * abstract class.
-   */
-  Token abstractKeyword;
-
-  /**
-   * The name of the superclass of the class being declared.
-   */
-  TypeName _superclass;
-
-  /**
-   * The with clause for this class.
-   */
-  WithClause _withClause;
-
-  /**
-   * The implements clause for this class, or `null` if there is no implements
-   * clause.
-   */
-  ImplementsClause _implementsClause;
-
-  /**
-   * Initialize a newly created class type alias. Either or both of the
-   * [comment] and [metadata] can be `null` if the class type alias does not
-   * have the corresponding attribute. The [typeParameters] can be `null` if the
-   * class does not have any type parameters. The [abstractKeyword] can be
-   * `null` if the class is not abstract. The [implementsClause] can be `null`
-   * if the class does not implement any interfaces.
-   */
-  ClassTypeAlias(
-      Comment comment,
-      List<Annotation> metadata,
-      Token keyword,
-      SimpleIdentifier name,
-      TypeParameterList typeParameters,
-      this.equals,
-      this.abstractKeyword,
-      TypeName superclass,
-      WithClause withClause,
-      ImplementsClause implementsClause,
-      Token semicolon)
-      : super(comment, metadata, keyword, name, semicolon) {
-    _typeParameters = _becomeParentOf(typeParameters);
-    _superclass = _becomeParentOf(superclass);
-    _withClause = _becomeParentOf(withClause);
-    _implementsClause = _becomeParentOf(implementsClause);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(typedefKeyword)
-    ..add(_name)
-    ..add(_typeParameters)
-    ..add(equals)
-    ..add(abstractKeyword)
-    ..add(_superclass)
-    ..add(_withClause)
-    ..add(_implementsClause)
-    ..add(semicolon);
-
-  @override
-  ClassElement get element =>
-      _name != null ? (_name.staticElement as ClassElement) : null;
-
-  /**
-   * Return the implements clause for this class, or `null` if there is no
-   * implements clause.
-   */
-  ImplementsClause get implementsClause => _implementsClause;
-
-  /**
-   * Set the implements clause for this class to the given [implementsClause].
-   */
-  void set implementsClause(ImplementsClause implementsClause) {
-    _implementsClause = _becomeParentOf(implementsClause);
-  }
-
-  /**
-   * Return `true` if this class is declared to be an abstract class.
-   */
-  bool get isAbstract => abstractKeyword != null;
-
-  /**
-   * Return the name of the superclass of the class being declared.
-   */
-  TypeName get superclass => _superclass;
-
-  /**
-   * Set the name of the superclass of the class being declared to the given
-   * [superclass] name.
-   */
-  void set superclass(TypeName superclass) {
-    _superclass = _becomeParentOf(superclass);
-  }
-
-  /**
-   * Return the type parameters for the class, or `null` if the class does not
-   * have any type parameters.
-   */
-  TypeParameterList get typeParameters => _typeParameters;
-
-  /**
-   * Set the type parameters for the class to the given list of [typeParameters].
-   */
-  void set typeParameters(TypeParameterList typeParameters) {
-    _typeParameters = _becomeParentOf(typeParameters);
-  }
-
-  /**
-   * Return the with clause for this class.
-   */
-  WithClause get withClause => _withClause;
-
-  /**
-   * Set the with clause for this class to the given with [withClause].
-   */
-  void set withClause(WithClause withClause) {
-    _withClause = _becomeParentOf(withClause);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitClassTypeAlias(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_typeParameters, visitor);
-    _safelyVisitChild(_superclass, visitor);
-    _safelyVisitChild(_withClause, visitor);
-    _safelyVisitChild(_implementsClause, visitor);
-  }
-}
-
-/**
- * A combinator associated with an import or export directive.
- *
- * > combinator ::=
- * >     [HideCombinator]
- * >   | [ShowCombinator]
- */
-abstract class Combinator extends AstNode {
-  /**
-   * The 'hide' or 'show' keyword specifying what kind of processing is to be
-   * done on the names.
-   */
-  Token keyword;
-
-  /**
-   * Initialize a newly created combinator.
-   */
-  Combinator(this.keyword);
-
-  @override
-  Token get beginToken => keyword;
-}
-
-/**
- * A comment within the source code.
- *
- * > comment ::=
- * >     endOfLineComment
- * >   | blockComment
- * >   | documentationComment
- * >
- * > endOfLineComment ::=
- * >     '//' (CHARACTER - EOL)* EOL
- * >
- * > blockComment ::=
- * >     '/ *' CHARACTER* '&#42;/'
- * >
- * > documentationComment ::=
- * >     '/ **' (CHARACTER | [CommentReference])* '&#42;/'
- * >   | ('///' (CHARACTER - EOL)* EOL)+
- */
-class Comment extends AstNode {
-  /**
-   * The tokens representing the comment.
-   */
-  final List<Token> tokens;
-
-  /**
-   * The type of the comment.
-   */
-  final CommentType _type;
-
-  /**
-   * The references embedded within the documentation comment. This list will be
-   * empty unless this is a documentation comment that has references embedded
-   * within it.
-   */
-  NodeList<CommentReference> _references;
-
-  /**
-   * Initialize a newly created comment. The list of [tokens] must contain at
-   * least one token. The [type] is the type of the comment. The list of
-   * [references] can be empty if the comment does not contain any embedded
-   * references.
-   */
-  Comment(this.tokens, this._type, List<CommentReference> references) {
-    _references = new NodeList<CommentReference>(this, references);
-  }
-
-  @override
-  Token get beginToken => tokens[0];
-
-  @override
-  Iterable get childEntities => new ChildEntities()..addAll(tokens);
-
-  @override
-  Token get endToken => tokens[tokens.length - 1];
-
-  /**
-   * Return `true` if this is a block comment.
-   */
-  bool get isBlock => _type == CommentType.BLOCK;
-
-  /**
-   * Return `true` if this is a documentation comment.
-   */
-  bool get isDocumentation => _type == CommentType.DOCUMENTATION;
-
-  /**
-   * Return `true` if this is an end-of-line comment.
-   */
-  bool get isEndOfLine => _type == CommentType.END_OF_LINE;
-
-  /**
-   * Return the references embedded within the documentation comment.
-   */
-  NodeList<CommentReference> get references => _references;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitComment(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _references.accept(visitor);
-  }
-
-  /**
-   * Create a block comment consisting of the given [tokens].
-   */
-  static Comment createBlockComment(List<Token> tokens) =>
-      new Comment(tokens, CommentType.BLOCK, null);
-
-  /**
-   * Create a documentation comment consisting of the given [tokens].
-   */
-  static Comment createDocumentationComment(List<Token> tokens) => new Comment(
-      tokens, CommentType.DOCUMENTATION, new List<CommentReference>());
-
-  /**
-   * Create a documentation comment consisting of the given [tokens] and having
-   * the given [references] embedded within it.
-   */
-  static Comment createDocumentationCommentWithReferences(
-          List<Token> tokens, List<CommentReference> references) =>
-      new Comment(tokens, CommentType.DOCUMENTATION, references);
-
-  /**
-   * Create an end-of-line comment consisting of the given [tokens].
-   */
-  static Comment createEndOfLineComment(List<Token> tokens) =>
-      new Comment(tokens, CommentType.END_OF_LINE, null);
-}
-
-/**
- * A reference to a Dart element that is found within a documentation comment.
- *
- * > commentReference ::=
- * >     '[' 'new'? [Identifier] ']'
- */
-class CommentReference extends AstNode {
-  /**
-   * The token representing the 'new' keyword, or `null` if there was no 'new'
-   * keyword.
-   */
-  Token newKeyword;
-
-  /**
-   * The identifier being referenced.
-   */
-  Identifier _identifier;
-
-  /**
-   * Initialize a newly created reference to a Dart element. The [newKeyword]
-   * can be `null` if the reference is not to a constructor.
-   */
-  CommentReference(this.newKeyword, Identifier identifier) {
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  @override
-  Token get beginToken => _identifier.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(newKeyword)..add(_identifier);
-
-  @override
-  Token get endToken => _identifier.endToken;
-
-  /**
-   * Return the identifier being referenced.
-   */
-  Identifier get identifier => _identifier;
-
-  /**
-   * Set the identifier being referenced to the given [identifier].
-   */
-  void set identifier(Identifier identifier) {
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitCommentReference(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_identifier, visitor);
-  }
-}
-
-/**
- * The possible types of comments that are recognized by the parser.
- */
-class CommentType {
-  /**
-   * A block comment.
-   */
-  static const CommentType BLOCK = const CommentType('BLOCK');
-
-  /**
-   * A documentation comment.
-   */
-  static const CommentType DOCUMENTATION = const CommentType('DOCUMENTATION');
-
-  /**
-   * An end-of-line comment.
-   */
-  static const CommentType END_OF_LINE = const CommentType('END_OF_LINE');
-
-  /**
-   * The name of the comment type.
-   */
-  final String name;
-
-  /**
-   * Initialize a newly created comment type to have the given [name].
-   */
-  const CommentType(this.name);
-
-  @override
-  String toString() => name;
-}
-
-/**
- * A compilation unit.
- *
- * While the grammar restricts the order of the directives and declarations
- * within a compilation unit, this class does not enforce those restrictions.
- * In particular, the children of a compilation unit will be visited in lexical
- * 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]*
- */
-class CompilationUnit extends AstNode {
-  /**
-   * The first token in the token stream that was parsed to form this
-   * compilation unit.
-   */
-  Token beginToken;
-
-  /**
-   * The script tag at the beginning of the compilation unit, or `null` if there
-   * is no script tag in this compilation unit.
-   */
-  ScriptTag _scriptTag;
-
-  /**
-   * The directives contained in this compilation unit.
-   */
-  NodeList<Directive> _directives;
-
-  /**
-   * The declarations contained in this compilation unit.
-   */
-  NodeList<CompilationUnitMember> _declarations;
-
-  /**
-   * 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].
-   */
-  Token endToken;
-
-  /**
-   * The element associated with this compilation unit, or `null` if the AST
-   * structure has not been resolved.
-   */
-  CompilationUnitElement element;
-
-  /**
-   * The line information for this compilation unit.
-   */
-  LineInfo lineInfo;
-
-  /**
-   * Initialize a newly created compilation unit to have the given directives
-   * and declarations. The [scriptTag] can be `null` if there is no script tag
-   * in the compilation unit. The list of [directives] can be `null` if there
-   * are no directives in the compilation unit. The list of [declarations] can
-   * be `null` if there are no declarations in the compilation unit.
-   */
-  CompilationUnit(
-      this.beginToken,
-      ScriptTag scriptTag,
-      List<Directive> directives,
-      List<CompilationUnitMember> declarations,
-      this.endToken) {
-    _scriptTag = _becomeParentOf(scriptTag);
-    _directives = new NodeList<Directive>(this, directives);
-    _declarations = new NodeList<CompilationUnitMember>(this, declarations);
-  }
-
-  @override
-  Iterable get childEntities {
-    ChildEntities result = new ChildEntities()..add(_scriptTag);
-    if (_directivesAreBeforeDeclarations) {
-      result..addAll(_directives)..addAll(_declarations);
-    } else {
-      result.addAll(sortedDirectivesAndDeclarations);
-    }
-    return result;
-  }
-
-  /**
-   * Return the declarations contained in this compilation unit.
-   */
-  NodeList<CompilationUnitMember> get declarations => _declarations;
-
-  /**
-   * Return the directives contained in this compilation unit.
-   */
-  NodeList<Directive> get directives => _directives;
-
-  @override
-  int get length {
-    Token endToken = this.endToken;
-    if (endToken == null) {
-      return 0;
-    }
-    return endToken.offset + endToken.length;
-  }
-
-  @override
-  int get offset => 0;
-
-  /**
-   * Return the script tag at the beginning of the compilation unit, or `null`
-   * if there is no script tag in this compilation unit.
-   */
-  ScriptTag get scriptTag => _scriptTag;
-
-  /**
-   * Set the script tag at the beginning of the compilation unit to the given
-   * [scriptTag].
-   */
-  void set scriptTag(ScriptTag scriptTag) {
-    _scriptTag = _becomeParentOf(scriptTag);
-  }
-
-  /**
-   * Return a list containing all of the directives and declarations in this
-   * compilation unit, sorted in lexical order.
-   */
-  List<AstNode> get sortedDirectivesAndDeclarations {
-    return <AstNode>[]
-      ..addAll(_directives)
-      ..addAll(_declarations)
-      ..sort(AstNode.LEXICAL_ORDER);
-  }
-
-  /**
-   * Return `true` if all of the directives are lexically before any
-   * declarations.
-   */
-  bool get _directivesAreBeforeDeclarations {
-    if (_directives.isEmpty || _declarations.isEmpty) {
-      return true;
-    }
-    Directive lastDirective = _directives[_directives.length - 1];
-    CompilationUnitMember firstDeclaration = _declarations[0];
-    return lastDirective.offset < firstDeclaration.offset;
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitCompilationUnit(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_scriptTag, visitor);
-    if (_directivesAreBeforeDeclarations) {
-      _directives.accept(visitor);
-      _declarations.accept(visitor);
-    } else {
-      for (AstNode child in sortedDirectivesAndDeclarations) {
-        child.accept(visitor);
-      }
-    }
-  }
-}
-
-/**
- * A node that declares one or more names within the scope of a compilation
- * unit.
- *
- * > compilationUnitMember ::=
- * >     [ClassDeclaration]
- * >   | [TypeAlias]
- * >   | [FunctionDeclaration]
- * >   | [MethodDeclaration]
- * >   | [VariableDeclaration]
- * >   | [VariableDeclaration]
- */
-abstract class CompilationUnitMember extends Declaration {
-  /**
-   * Initialize a newly created generic compilation unit member. Either or both
-   * of the [comment] and [metadata] can be `null` if the member does not have
-   * the corresponding attribute.
-   */
-  CompilationUnitMember(Comment comment, List<Annotation> metadata)
-      : super(comment, metadata);
-}
-
-/**
- * A conditional expression.
- *
- * > conditionalExpression ::=
- * >     [Expression] '?' [Expression] ':' [Expression]
- */
-class ConditionalExpression extends Expression {
-  /**
-   * The condition used to determine which of the expressions is executed next.
-   */
-  Expression _condition;
-
-  /**
-   * The token used to separate the condition from the then expression.
-   */
-  Token question;
-
-  /**
-   * The expression that is executed if the condition evaluates to `true`.
-   */
-  Expression _thenExpression;
-
-  /**
-   * The token used to separate the then expression from the else expression.
-   */
-  Token colon;
-
-  /**
-   * The expression that is executed if the condition evaluates to `false`.
-   */
-  Expression _elseExpression;
-
-  /**
-   * Initialize a newly created conditional expression.
-   */
-  ConditionalExpression(Expression condition, this.question,
-      Expression thenExpression, this.colon, Expression elseExpression) {
-    _condition = _becomeParentOf(condition);
-    _thenExpression = _becomeParentOf(thenExpression);
-    _elseExpression = _becomeParentOf(elseExpression);
-  }
-
-  @override
-  Token get beginToken => _condition.beginToken;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(_condition)
-    ..add(question)
-    ..add(_thenExpression)
-    ..add(colon)
-    ..add(_elseExpression);
-
-  /**
-   * Return the condition used to determine which of the expressions is executed
-   * next.
-   */
-  Expression get condition => _condition;
-
-  /**
-   * Set the condition used to determine which of the expressions is executed
-   * next to the given [expression].
-   */
-  void set condition(Expression expression) {
-    _condition = _becomeParentOf(expression);
-  }
-
-  /**
-   * Return the expression that is executed if the condition evaluates to
-   * `false`.
-   */
-  Expression get elseExpression => _elseExpression;
-
-  /**
-   * Set the expression that is executed if the condition evaluates to `false`
-   * to the given [expression].
-   */
-  void set elseExpression(Expression expression) {
-    _elseExpression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get endToken => _elseExpression.endToken;
-
-  @override
-  int get precedence => 3;
-
-  /**
-   * Return the expression that is executed if the condition evaluates to
-   * `true`.
-   */
-  Expression get thenExpression => _thenExpression;
-
-  /**
-   * Set the expression that is executed if the condition evaluates to `true` to
-   * the given [expression].
-   */
-  void set thenExpression(Expression expression) {
-    _thenExpression = _becomeParentOf(expression);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitConditionalExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_condition, visitor);
-    _safelyVisitChild(_thenExpression, visitor);
-    _safelyVisitChild(_elseExpression, visitor);
-  }
-}
-
-/**
- * A configuration in either an import or export directive.
- *
- *     configuration ::=
- *         'if' '(' test ')' uri
- *
- *     test ::=
- *         dottedName ('==' stringLiteral)?
- *
- *     dottedName ::=
- *         identifier ('.' identifier)*
- */
-class Configuration extends AstNode {
-  Token ifKeyword;
-  Token leftParenthesis;
-  DottedName _name;
-  Token equalToken;
-  StringLiteral _value;
-  Token rightParenthesis;
-  StringLiteral _libraryUri;
-
-  Configuration(
-      this.ifKeyword,
-      this.leftParenthesis,
-      DottedName name,
-      this.equalToken,
-      StringLiteral value,
-      this.rightParenthesis,
-      StringLiteral libraryUri) {
-    _name = _becomeParentOf(name);
-    _value = _becomeParentOf(value);
-    _libraryUri = _becomeParentOf(libraryUri);
-  }
-
-  @override
-  Token get beginToken => ifKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(ifKeyword)
-    ..add(leftParenthesis)
-    ..add(_name)
-    ..add(equalToken)
-    ..add(_value)
-    ..add(rightParenthesis)
-    ..add(_libraryUri);
-
-  @override
-  Token get endToken => _libraryUri.endToken;
-
-  StringLiteral get libraryUri => _libraryUri;
-
-  void set libraryUri(StringLiteral libraryUri) {
-    _libraryUri = _becomeParentOf(libraryUri);
-  }
-
-  DottedName get name => _name;
-
-  void set name(DottedName name) {
-    _name = _becomeParentOf(name);
-  }
-
-  StringLiteral get value => _value;
-
-  void set value(StringLiteral value) {
-    _value = _becomeParentOf(value);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitConfiguration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_value, visitor);
-    _safelyVisitChild(_libraryUri, visitor);
-  }
-}
-
-/**
- * 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])*
- */
-class ConstructorDeclaration extends ClassMember {
-  /**
-   * The token for the 'external' keyword, or `null` if the constructor is not
-   * external.
-   */
-  Token externalKeyword;
-
-  /**
-   * The token for the 'const' keyword, or `null` if the constructor is not a
-   * const constructor.
-   */
-  Token constKeyword;
-
-  /**
-   * The token for the 'factory' keyword, or `null` if the constructor is not a
-   * factory constructor.
-   */
-  Token factoryKeyword;
-
-  /**
-   * The type of object being created. This can be different than the type in
-   * which the constructor is being declared if the constructor is the
-   * implementation of a factory constructor.
-   */
-  Identifier _returnType;
-
-  /**
-   * The token for the period before the constructor name, or `null` if the
-   * constructor being declared is unnamed.
-   */
-  Token period;
-
-  /**
-   * The name of the constructor, or `null` if the constructor being declared is
-   * unnamed.
-   */
-  SimpleIdentifier _name;
-
-  /**
-   * The parameters associated with the constructor.
-   */
-  FormalParameterList _parameters;
-
-  /**
-   * The token for the separator (colon or equals) before the initializer list
-   * or redirection, or `null` if there are no initializers.
-   */
-  Token separator;
-
-  /**
-   * The initializers associated with the constructor.
-   */
-  NodeList<ConstructorInitializer> _initializers;
-
-  /**
-   * The name of the constructor to which this constructor will be redirected,
-   * or `null` if this is not a redirecting factory constructor.
-   */
-  ConstructorName _redirectedConstructor;
-
-  /**
-   * The body of the constructor, or `null` if the constructor does not have a
-   * body.
-   */
-  FunctionBody _body;
-
-  /**
-   * The element associated with this constructor, or `null` if the AST
-   * structure has not been resolved or if this constructor could not be
-   * resolved.
-   */
-  ConstructorElement element;
-
-  /**
-   * Initialize a newly created constructor declaration. The [externalKeyword]
-   * can be `null` if the constructor is not external. Either or both of the
-   * [comment] and [metadata] can be `null` if the constructor does not have the
-   * corresponding attribute. The [constKeyword] can be `null` if the
-   * constructor cannot be used to create a constant. The [factoryKeyword] can
-   * be `null` if the constructor is not a factory. The [period] and [name] can
-   * both be `null` if the constructor is not a named constructor. The
-   * [separator] can be `null` if the constructor does not have any initializers
-   * and does not redirect to a different constructor. The list of
-   * [initializers] can be `null` if the constructor does not have any
-   * initializers. The [redirectedConstructor] can be `null` if the constructor
-   * does not redirect to a different constructor. The [body] can be `null` if
-   * the constructor does not have a body.
-   */
-  ConstructorDeclaration(
-      Comment comment,
-      List<Annotation> metadata,
-      this.externalKeyword,
-      this.constKeyword,
-      this.factoryKeyword,
-      Identifier returnType,
-      this.period,
-      SimpleIdentifier name,
-      FormalParameterList parameters,
-      this.separator,
-      List<ConstructorInitializer> initializers,
-      ConstructorName redirectedConstructor,
-      FunctionBody body)
-      : super(comment, metadata) {
-    _returnType = _becomeParentOf(returnType);
-    _name = _becomeParentOf(name);
-    _parameters = _becomeParentOf(parameters);
-    _initializers = new NodeList<ConstructorInitializer>(this, initializers);
-    _redirectedConstructor = _becomeParentOf(redirectedConstructor);
-    _body = _becomeParentOf(body);
-  }
-
-  /**
-   * Return the body of the constructor, or `null` if the constructor does not
-   * have a body.
-   */
-  FunctionBody get body => _body;
-
-  /**
-   * Set the body of the constructor to the given [functionBody].
-   */
-  void set body(FunctionBody functionBody) {
-    _body = _becomeParentOf(functionBody);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(externalKeyword)
-    ..add(constKeyword)
-    ..add(factoryKeyword)
-    ..add(_returnType)
-    ..add(period)
-    ..add(_name)
-    ..add(_parameters)
-    ..add(separator)
-    ..addAll(initializers)
-    ..add(_redirectedConstructor)
-    ..add(_body);
-
-  @override
-  Token get endToken {
-    if (_body != null) {
-      return _body.endToken;
-    } else if (!_initializers.isEmpty) {
-      return _initializers.endToken;
-    }
-    return _parameters.endToken;
-  }
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata {
-    Token leftMost =
-        Token.lexicallyFirst([externalKeyword, constKeyword, factoryKeyword]);
-    if (leftMost != null) {
-      return leftMost;
-    }
-    return _returnType.beginToken;
-  }
-
-  /**
-   * Return the initializers associated with the constructor.
-   */
-  NodeList<ConstructorInitializer> get initializers => _initializers;
-
-  /**
-   * Return the name of the constructor, or `null` if the constructor being
-   * declared is unnamed.
-   */
-  SimpleIdentifier get name => _name;
-
-  /**
-   * Set the name of the constructor to the given [identifier].
-   */
-  void set name(SimpleIdentifier identifier) {
-    _name = _becomeParentOf(identifier);
-  }
-
-  /**
-   * Return the parameters associated with the constructor.
-   */
-  FormalParameterList get parameters => _parameters;
-
-  /**
-   * Set the parameters associated with the constructor to the given list of
-   * [parameters].
-   */
-  void set parameters(FormalParameterList parameters) {
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  /**
-   * Return the name of the constructor to which this constructor will be
-   * redirected, or `null` if this is not a redirecting factory constructor.
-   */
-  ConstructorName get redirectedConstructor => _redirectedConstructor;
-
-  /**
-   * Set the name of the constructor to which this constructor will be
-   * redirected to the given [redirectedConstructor] name.
-   */
-  void set redirectedConstructor(ConstructorName redirectedConstructor) {
-    _redirectedConstructor = _becomeParentOf(redirectedConstructor);
-  }
-
-  /**
-   * Return the type of object being created. This can be different than the
-   * type in which the constructor is being declared if the constructor is the
-   * implementation of a factory constructor.
-   */
-  Identifier get returnType => _returnType;
-
-  /**
-   * Set the type of object being created to the given [typeName].
-   */
-  void set returnType(Identifier typeName) {
-    _returnType = _becomeParentOf(typeName);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitConstructorDeclaration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_returnType, visitor);
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_parameters, visitor);
-    _initializers.accept(visitor);
-    _safelyVisitChild(_redirectedConstructor, visitor);
-    _safelyVisitChild(_body, visitor);
-  }
-}
-
-/**
- * The initialization of a field within a constructor's initialization list.
- *
- * > fieldInitializer ::=
- * >     ('this' '.')? [SimpleIdentifier] '=' [Expression]
- */
-class ConstructorFieldInitializer extends ConstructorInitializer {
-  /**
-   * The token for the 'this' keyword, or `null` if there is no 'this' keyword.
-   */
-  Token thisKeyword;
-
-  /**
-   * The token for the period after the 'this' keyword, or `null` if there is no
-   * 'this' keyword.
-   */
-  Token period;
-
-  /**
-   * The name of the field being initialized.
-   */
-  SimpleIdentifier _fieldName;
-
-  /**
-   * The token for the equal sign between the field name and the expression.
-   */
-  Token equals;
-
-  /**
-   * The expression computing the value to which the field will be initialized.
-   */
-  Expression _expression;
-
-  /**
-   * Initialize a newly created field initializer to initialize the field with
-   * the given name to the value of the given expression. The [thisKeyword] and
-   * [period] can be `null` if the 'this' keyword was not specified.
-   */
-  ConstructorFieldInitializer(this.thisKeyword, this.period,
-      SimpleIdentifier fieldName, this.equals, Expression expression) {
-    _fieldName = _becomeParentOf(fieldName);
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken {
-    if (thisKeyword != null) {
-      return thisKeyword;
-    }
-    return _fieldName.beginToken;
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(thisKeyword)
-    ..add(period)
-    ..add(_fieldName)
-    ..add(equals)
-    ..add(_expression);
-
-  @override
-  Token get endToken => _expression.endToken;
-
-  /**
-   * Return the expression computing the value to which the field will be
-   * initialized.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression computing the value to which the field will be
-   * initialized to the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  /**
-   * Return the name of the field being initialized.
-   */
-  SimpleIdentifier get fieldName => _fieldName;
-
-  /**
-   * Set the name of the field being initialized to the given [identifier].
-   */
-  void set fieldName(SimpleIdentifier identifier) {
-    _fieldName = _becomeParentOf(identifier);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitConstructorFieldInitializer(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_fieldName, visitor);
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * A node that can occur in the initializer list of a constructor declaration.
- *
- * > constructorInitializer ::=
- * >     [SuperConstructorInvocation]
- * >   | [ConstructorFieldInitializer]
- * >   | [RedirectingConstructorInvocation]
- */
-abstract class ConstructorInitializer extends AstNode {}
-
-/**
- * The name of the constructor.
- *
- * > constructorName ::=
- * >     type ('.' identifier)?
- */
-class ConstructorName extends AstNode {
-  /**
-   * The name of the type defining the constructor.
-   */
-  TypeName _type;
-
-  /**
-   * The token for the period before the constructor name, or `null` if the
-   * specified constructor is the unnamed constructor.
-   */
-  Token period;
-
-  /**
-   * The name of the constructor, or `null` if the specified constructor is the
-   * unnamed constructor.
-   */
-  SimpleIdentifier _name;
-
-  /**
-   * The element associated with this constructor name based on static type
-   * information, or `null` if the AST structure has not been resolved or if
-   * this constructor name could not be resolved.
-   */
-  ConstructorElement staticElement;
-
-  /**
-   * Initialize a newly created constructor name. The [period] and [name] can be
-   * `null` if the constructor being named is the unnamed constructor.
-   */
-  ConstructorName(TypeName type, this.period, SimpleIdentifier name) {
-    _type = _becomeParentOf(type);
-    _name = _becomeParentOf(name);
-  }
-
-  @override
-  Token get beginToken => _type.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_type)..add(period)..add(_name);
-
-  @override
-  Token get endToken {
-    if (_name != null) {
-      return _name.endToken;
-    }
-    return _type.endToken;
-  }
-
-  /**
-   * Return the name of the constructor, or `null` if the specified constructor
-   * is the unnamed constructor.
-   */
-  SimpleIdentifier get name => _name;
-
-  /**
-   * Set the name of the constructor to the given [name].
-   */
-  void set name(SimpleIdentifier name) {
-    _name = _becomeParentOf(name);
-  }
-
-  /**
-   * Return the name of the type defining the constructor.
-   */
-  TypeName get type => _type;
-
-  /**
-   * Set the name of the type defining the constructor to the given [type] name.
-   */
-  void set type(TypeName type) {
-    _type = _becomeParentOf(type);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitConstructorName(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_type, visitor);
-    _safelyVisitChild(_name, visitor);
-  }
-}
-
-/**
- * A continue statement.
- *
- * > continueStatement ::=
- * >     'continue' [SimpleIdentifier]? ';'
- */
-class ContinueStatement extends Statement {
-  /**
-   * The token representing the 'continue' keyword.
-   */
-  Token continueKeyword;
-
-  /**
-   * The label associated with the statement, or `null` if there is no label.
-   */
-  SimpleIdentifier _label;
-
-  /**
-   * The semicolon terminating the statement.
-   */
-  Token semicolon;
-
-  /**
-   * The AstNode which this continue statement is continuing to.  This will be
-   * either a Statement (in the case of continuing a loop) or a SwitchMember
-   * (in the case of continuing from one switch case to another).  Null if the
-   * AST has not yet been resolved or if the target could not be resolved.
-   * Note that if the source code has errors, the target may be invalid (e.g.
-   * the target may be in an enclosing function).
-   */
-  AstNode target;
-
-  /**
-   * Initialize a newly created continue statement. The [label] can be `null` if
-   * there is no label associated with the statement.
-   */
-  ContinueStatement(
-      this.continueKeyword, SimpleIdentifier label, this.semicolon) {
-    _label = _becomeParentOf(label);
-  }
-
-  @override
-  Token get beginToken => continueKeyword;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(continueKeyword)..add(_label)..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  /**
-   * Return the label associated with the statement, or `null` if there is no
-   * label.
-   */
-  SimpleIdentifier get label => _label;
-
-  /**
-   * Set the label associated with the statement to the given [identifier].
-   */
-  void set label(SimpleIdentifier identifier) {
-    _label = _becomeParentOf(identifier);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitContinueStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_label, visitor);
-  }
-}
-
-/**
- * A node that represents the declaration of one or more names. Each declared
- * name is visible within a name scope.
- */
-abstract class Declaration extends AnnotatedNode {
-  /**
-   * Initialize a newly created declaration. Either or both of the [comment] and
-   * [metadata] can be `null` if the declaration does not have the corresponding
-   * attribute.
-   */
-  Declaration(Comment comment, List<Annotation> metadata)
-      : super(comment, metadata);
-
-  /**
-   * Return the element associated with this declaration, or `null` if either
-   * this node corresponds to a list of declarations or if the AST structure has
-   * not been resolved.
-   */
-  Element get element;
-}
-
-/**
- * The declaration of a single identifier.
- *
- * > declaredIdentifier ::=
- * >     [Annotation] finalConstVarOrType [SimpleIdentifier]
- */
-class DeclaredIdentifier extends Declaration {
-  /**
-   * The token representing either the 'final', 'const' or 'var' keyword, or
-   * `null` if no keyword was used.
-   */
-  Token keyword;
-
-  /**
-   * The name of the declared type of the parameter, or `null` if the parameter
-   * does not have a declared type.
-   */
-  TypeName _type;
-
-  /**
-   * The name of the variable being declared.
-   */
-  SimpleIdentifier _identifier;
-
-  /**
-   * Initialize a newly created formal parameter. Either or both of the
-   * [comment] and [metadata] can be `null` if the declaration does not have the
-   * corresponding attribute. The [keyword] can be `null` if a type name is
-   * given. The [type] must be `null` if the keyword is 'var'.
-   */
-  DeclaredIdentifier(Comment comment, List<Annotation> metadata, this.keyword,
-      TypeName type, SimpleIdentifier identifier)
-      : super(comment, metadata) {
-    _type = _becomeParentOf(type);
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(keyword)..add(_type)..add(_identifier);
-
-  @override
-  LocalVariableElement get element {
-    if (_identifier == null) {
-      return null;
-    }
-    return _identifier.staticElement as LocalVariableElement;
-  }
-
-  @override
-  Token get endToken => _identifier.endToken;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata {
-    if (keyword != null) {
-      return keyword;
-    } else if (_type != null) {
-      return _type.beginToken;
-    }
-    return _identifier.beginToken;
-  }
-
-  /**
-   * Return the name of the variable being declared.
-   */
-  SimpleIdentifier get identifier => _identifier;
-
-  /**
-   * Set the name of the variable being declared to the given [identifier].
-   */
-  void set identifier(SimpleIdentifier identifier) {
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  /**
-   * Return `true` if this variable was declared with the 'const' modifier.
-   */
-  bool get isConst =>
-      (keyword is KeywordToken) &&
-      (keyword as KeywordToken).keyword == Keyword.CONST;
-
-  /**
-   * Return `true` if this variable was declared with the 'final' modifier.
-   * Variables that are declared with the 'const' modifier will return `false`
-   * even though they are implicitly final.
-   */
-  bool get isFinal =>
-      (keyword is KeywordToken) &&
-      (keyword as KeywordToken).keyword == Keyword.FINAL;
-
-  /**
-   * Return the name of the declared type of the parameter, or `null` if the
-   * parameter does not have a declared type.
-   */
-  TypeName get type => _type;
-
-  /**
-   * Set the name of the declared type of the parameter to the given [typeName].
-   */
-  void set type(TypeName typeName) {
-    _type = _becomeParentOf(typeName);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitDeclaredIdentifier(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_type, visitor);
-    _safelyVisitChild(_identifier, visitor);
-  }
-}
-
-/**
- * A formal parameter with a default value. There are two kinds of parameters
- * that are both represented by this class: named formal parameters and
- * positional formal parameters.
- *
- * > defaultFormalParameter ::=
- * >     [NormalFormalParameter] ('=' [Expression])?
- * >
- * > defaultNamedParameter ::=
- * >     [NormalFormalParameter] (':' [Expression])?
- */
-class DefaultFormalParameter extends FormalParameter {
-  /**
-   * The formal parameter with which the default value is associated.
-   */
-  NormalFormalParameter _parameter;
-
-  /**
-   * The kind of this parameter.
-   */
-  ParameterKind kind;
-
-  /**
-   * The token separating the parameter from the default value, or `null` if
-   * there is no default value.
-   */
-  Token separator;
-
-  /**
-   * The expression computing the default value for the parameter, or `null` if
-   * there is no default value.
-   */
-  Expression _defaultValue;
-
-  /**
-   * Initialize a newly created default formal parameter. The [separator] and
-   * [defaultValue] can be `null` if there is no default value.
-   */
-  DefaultFormalParameter(NormalFormalParameter parameter, this.kind,
-      this.separator, Expression defaultValue) {
-    _parameter = _becomeParentOf(parameter);
-    _defaultValue = _becomeParentOf(defaultValue);
-  }
-
-  @override
-  Token get beginToken => _parameter.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_parameter)..add(separator)..add(_defaultValue);
-
-  /**
-   * Return the expression computing the default value for the parameter, or
-   * `null` if there is no default value.
-   */
-  Expression get defaultValue => _defaultValue;
-
-  /**
-   * Set the expression computing the default value for the parameter to the
-   * given [expression].
-   */
-  void set defaultValue(Expression expression) {
-    _defaultValue = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get endToken {
-    if (_defaultValue != null) {
-      return _defaultValue.endToken;
-    }
-    return _parameter.endToken;
-  }
-
-  @override
-  SimpleIdentifier get identifier => _parameter.identifier;
-
-  @override
-  bool get isConst => _parameter != null && _parameter.isConst;
-
-  @override
-  bool get isFinal => _parameter != null && _parameter.isFinal;
-
-  @override
-  NodeList<Annotation> get metadata => _parameter.metadata;
-
-  /**
-   * Return the formal parameter with which the default value is associated.
-   */
-  NormalFormalParameter get parameter => _parameter;
-
-  /**
-   * Set the formal parameter with which the default value is associated to the
-   * given [formalParameter].
-   */
-  void set parameter(NormalFormalParameter formalParameter) {
-    _parameter = _becomeParentOf(formalParameter);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitDefaultFormalParameter(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_parameter, visitor);
-    _safelyVisitChild(_defaultValue, visitor);
-  }
-}
-
-/**
- * A node that represents a directive.
- *
- * > directive ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
- * >   | [LibraryDirective]
- * >   | [PartDirective]
- * >   | [PartOfDirective]
- */
-abstract class Directive extends AnnotatedNode {
-  /**
-   * The element associated with this directive, or `null` if the AST structure
-   * has not been resolved or if this directive could not be resolved.
-   */
-  Element element;
-
-  /**
-   * Initialize a newly create directive. Either or both of the [comment] and
-   * [metadata] can be `null` if the directive does not have the corresponding
-   * attribute.
-   */
-  Directive(Comment comment, List<Annotation> metadata)
-      : super(comment, metadata);
-
-  /**
-   * Return the token representing the keyword that introduces this directive
-   * ('import', 'export', 'library' or 'part').
-   */
-  Token get keyword;
-}
-
-/**
- * A do statement.
- *
- * > doStatement ::=
- * >     'do' [Statement] 'while' '(' [Expression] ')' ';'
- */
-class DoStatement extends Statement {
-  /**
-   * The token representing the 'do' keyword.
-   */
-  Token doKeyword;
-
-  /**
-   * The body of the loop.
-   */
-  Statement _body;
-
-  /**
-   * The token representing the 'while' keyword.
-   */
-  Token whileKeyword;
-
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The condition that determines when the loop will terminate.
-   */
-  Expression _condition;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * The semicolon terminating the statement.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created do loop.
-   */
-  DoStatement(
-      this.doKeyword,
-      Statement body,
-      this.whileKeyword,
-      this.leftParenthesis,
-      Expression condition,
-      this.rightParenthesis,
-      this.semicolon) {
-    _body = _becomeParentOf(body);
-    _condition = _becomeParentOf(condition);
-  }
-
-  @override
-  Token get beginToken => doKeyword;
-
-  /**
-   * Return the body of the loop.
-   */
-  Statement get body => _body;
-
-  /**
-   * Set the body of the loop to the given [statement].
-   */
-  void set body(Statement statement) {
-    _body = _becomeParentOf(statement);
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(doKeyword)
-    ..add(_body)
-    ..add(whileKeyword)
-    ..add(leftParenthesis)
-    ..add(_condition)
-    ..add(rightParenthesis)
-    ..add(semicolon);
-
-  /**
-   * Return the condition that determines when the loop will terminate.
-   */
-  Expression get condition => _condition;
-
-  /**
-   * Set the condition that determines when the loop will terminate to the given
-   * [expression].
-   */
-  void set condition(Expression expression) {
-    _condition = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitDoStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_body, visitor);
-    _safelyVisitChild(_condition, visitor);
-  }
-}
-
-/**
- * A dotted name, used in a configuration within an import or export directive.
- *
- * > dottedName ::=
- * >     [SimpleIdentifier] ('.' [SimpleIdentifier])*
- */
-class DottedName extends AstNode {
-  /**
-   * The components of the identifier.
-   */
-  NodeList<SimpleIdentifier> _components;
-
-  /**
-   * Initialize a newly created dotted name.
-   */
-  DottedName(List<SimpleIdentifier> components) {
-    _components = new NodeList<SimpleIdentifier>(this, components);
-  }
-
-  @override
-  Token get beginToken => _components.beginToken;
-
-  @override
-  // TODO(paulberry): add "." tokens.
-  Iterable get childEntities => new ChildEntities()..addAll(_components);
-
-  /**
-   * Return the components of the identifier.
-   */
-  NodeList<SimpleIdentifier> get components => _components;
-
-  @override
-  Token get endToken => _components.endToken;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitDottedName(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _components.accept(visitor);
-  }
-}
-
-/**
- * A floating point literal expression.
- *
- * > doubleLiteral ::=
- * >     decimalDigit+ ('.' decimalDigit*)? exponent?
- * >   | '.' decimalDigit+ exponent?
- * >
- * > exponent ::=
- * >     ('e' | 'E') ('+' | '-')? decimalDigit+
- */
-class DoubleLiteral extends Literal {
-  /**
-   * The token representing the literal.
-   */
-  Token literal;
-
-  /**
-   * The value of the literal.
-   */
-  double value;
-
-  /**
-   * Initialize a newly created floating point literal.
-   */
-  DoubleLiteral(this.literal, this.value);
-
-  @override
-  Token get beginToken => literal;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(literal);
-
-  @override
-  Token get endToken => literal;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitDoubleLiteral(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * An empty function body, which can only appear in constructors or abstract
- * methods.
- *
- * > emptyFunctionBody ::=
- * >     ';'
- */
-class EmptyFunctionBody extends FunctionBody {
-  /**
-   * The token representing the semicolon that marks the end of the function
-   * body.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created function body.
-   */
-  EmptyFunctionBody(this.semicolon);
-
-  @override
-  Token get beginToken => semicolon;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitEmptyFunctionBody(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // Empty function bodies have no children.
-  }
-}
-
-/**
- * An empty statement.
- *
- * > emptyStatement ::=
- * >     ';'
- */
-class EmptyStatement extends Statement {
-  /**
-   * The semicolon terminating the statement.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created empty statement.
-   */
-  EmptyStatement(this.semicolon);
-
-  @override
-  Token get beginToken => semicolon;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitEmptyStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * The declaration of an enum constant.
- */
-class EnumConstantDeclaration extends Declaration {
-  /**
-   * The name of the constant.
-   */
-  SimpleIdentifier _name;
-
-  /**
-   * Initialize a newly created enum constant declaration. Either or both of the
-   * [comment] and [metadata] can be `null` if the constant does not have the
-   * corresponding attribute. (Technically, enum constants cannot have metadata,
-   * but we allow it for consistency.)
-   */
-  EnumConstantDeclaration(
-      Comment comment, List<Annotation> metadata, SimpleIdentifier name)
-      : super(comment, metadata) {
-    _name = _becomeParentOf(name);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities..add(_name);
-
-  @override
-  FieldElement get element =>
-      _name == null ? null : (_name.staticElement as FieldElement);
-
-  @override
-  Token get endToken => _name.endToken;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
-
-  /**
-   * Return the name of the constant.
-   */
-  SimpleIdentifier get name => _name;
-
-  /**
-   * Set the name of the constant to the given [name].
-   */
-  void set name(SimpleIdentifier name) {
-    _name = _becomeParentOf(name);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitEnumConstantDeclaration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_name, visitor);
-  }
-}
-
-/**
- * The declaration of an enumeration.
- *
- * > enumType ::=
- * >     metadata 'enum' [SimpleIdentifier] '{' [SimpleIdentifier] (',' [SimpleIdentifier])* (',')? '}'
- */
-class EnumDeclaration extends NamedCompilationUnitMember {
-  /**
-   * The 'enum' keyword.
-   */
-  Token enumKeyword;
-
-  /**
-   * The left curly bracket.
-   */
-  Token leftBracket;
-
-  /**
-   * The enumeration constants being declared.
-   */
-  NodeList<EnumConstantDeclaration> _constants;
-
-  /**
-   * The right curly bracket.
-   */
-  Token rightBracket;
-
-  /**
-   * Initialize a newly created enumeration declaration. Either or both of the
-   * [comment] and [metadata] can be `null` if the declaration does not have the
-   * corresponding attribute. The list of [constants] must contain at least one
-   * value.
-   */
-  EnumDeclaration(
-      Comment comment,
-      List<Annotation> metadata,
-      this.enumKeyword,
-      SimpleIdentifier name,
-      this.leftBracket,
-      List<EnumConstantDeclaration> constants,
-      this.rightBracket)
-      : super(comment, metadata, name) {
-    _constants = new NodeList<EnumConstantDeclaration>(this, constants);
-  }
-
-  @override
-  // TODO(brianwilkerson) Add commas?
-  Iterable get childEntities => super._childEntities
-    ..add(enumKeyword)
-    ..add(_name)
-    ..add(leftBracket)
-    ..addAll(_constants)
-    ..add(rightBracket);
-
-  /**
-   * Return the enumeration constants being declared.
-   */
-  NodeList<EnumConstantDeclaration> get constants => _constants;
-
-  @override
-  ClassElement get element =>
-      _name != null ? (_name.staticElement as ClassElement) : null;
-
-  @override
-  Token get endToken => rightBracket;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => enumKeyword;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitEnumDeclaration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_name, visitor);
-    _constants.accept(visitor);
-  }
-}
-
-/**
- * Ephemeral identifiers are created as needed to mimic the presence of an empty
- * identifier.
- */
-class EphemeralIdentifier extends SimpleIdentifier {
-  EphemeralIdentifier(AstNode parent, int location)
-      : super(new StringToken(TokenType.IDENTIFIER, "", location)) {
-    parent._becomeParentOf(this);
-  }
-}
-
-/**
- * An export directive.
- *
- * > exportDirective ::=
- * >     [Annotation] 'export' [StringLiteral] [Combinator]* ';'
- */
-class ExportDirective extends NamespaceDirective {
-  /**
-   * Initialize a newly created export directive. Either or both of the
-   * [comment] and [metadata] can be `null` if the directive does not have the
-   * corresponding attribute. The list of [combinators] can be `null` if there
-   * are no combinators.
-   */
-  ExportDirective(
-      Comment comment,
-      List<Annotation> metadata,
-      Token keyword,
-      StringLiteral libraryUri,
-      List<Configuration> configurations,
-      List<Combinator> combinators,
-      Token semicolon)
-      : super(comment, metadata, keyword, libraryUri, configurations,
-            combinators, semicolon);
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(_uri)
-    ..addAll(combinators)
-    ..add(semicolon);
-
-  @override
-  ExportElement get element => super.element as ExportElement;
-
-  @override
-  LibraryElement get uriElement {
-    if (element != null) {
-      return element.exportedLibrary;
-    }
-    return null;
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitExportDirective(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    combinators.accept(visitor);
-  }
-}
-
-/**
- * A node that represents an expression.
- *
- * > expression ::=
- * >     [AssignmentExpression]
- * >   | [ConditionalExpression] cascadeSection*
- * >   | [ThrowExpression]
- */
-abstract class Expression extends AstNode {
-  /**
-   * An empty list of expressions.
-   */
-  static const List<Expression> EMPTY_LIST = const <Expression>[];
-
-  /**
-   * The static type of this expression, or `null` if the AST structure has not
-   * been resolved.
-   */
-  DartType staticType;
-
-  /**
-   * The propagated type of this expression, or `null` if type propagation has
-   * not been performed on the AST structure.
-   */
-  DartType propagatedType;
-
-  /**
-   * Return the best parameter element information available for this
-   * expression. If type propagation was able to find a better parameter element
-   * than static analysis, that type will be returned. Otherwise, the result of
-   * static analysis will be returned.
-   */
-  ParameterElement get bestParameterElement {
-    ParameterElement propagatedElement = propagatedParameterElement;
-    if (propagatedElement != null) {
-      return propagatedElement;
-    }
-    return staticParameterElement;
-  }
-
-  /**
-   * Return the best type information available for this expression. If type
-   * propagation was able to find a better type than static analysis, that type
-   * will be returned. Otherwise, the result of static analysis will be
-   * returned. If no type analysis has been performed, then the type 'dynamic'
-   * will be returned.
-   */
-  DartType get bestType {
-    if (propagatedType != null) {
-      return propagatedType;
-    } else if (staticType != null) {
-      return staticType;
-    }
-    return DynamicTypeImpl.instance;
-  }
-
-  /**
-   * Return `true` if this expression is syntactically valid for the LHS of an
-   * [AssignmentExpression].
-   */
-  bool get isAssignable => false;
-
-  /**
-   * Return the precedence of this expression. The precedence is a positive
-   * integer value that defines how the source code is parsed into an AST. For
-   * example `a * b + c` is parsed as `(a * b) + c` because the precedence of
-   * `*` is greater than the precedence of `+`.
-   *
-   * Clients should not assume that returned values will stay the same, they
-   * might change as result of specification change. Only relative order should
-   * be used.
-   */
-  int get precedence;
-
-  /**
-   * If this expression is an argument to an invocation, and the AST structure
-   * has been resolved, and the function being invoked is known based on
-   * propagated type information, and this expression corresponds to one of the
-   * parameters of the function being invoked, then return the parameter element
-   * representing the parameter to which the value of this expression will be
-   * bound. Otherwise, return `null`.
-   */
-  ParameterElement get propagatedParameterElement {
-    AstNode parent = this.parent;
-    if (parent is ArgumentList) {
-      return parent._getPropagatedParameterElementFor(this);
-    } else if (parent is IndexExpression) {
-      IndexExpression indexExpression = parent;
-      if (identical(indexExpression.index, this)) {
-        return indexExpression._propagatedParameterElementForIndex;
-      }
-    } else if (parent is BinaryExpression) {
-      BinaryExpression binaryExpression = parent;
-      if (identical(binaryExpression.rightOperand, this)) {
-        return binaryExpression._propagatedParameterElementForRightOperand;
-      }
-    } else if (parent is AssignmentExpression) {
-      AssignmentExpression assignmentExpression = parent;
-      if (identical(assignmentExpression.rightHandSide, this)) {
-        return assignmentExpression._propagatedParameterElementForRightHandSide;
-      }
-    } else if (parent is PrefixExpression) {
-      return parent._propagatedParameterElementForOperand;
-    } else if (parent is PostfixExpression) {
-      return parent._propagatedParameterElementForOperand;
-    }
-    return null;
-  }
-
-  /**
-   * If this expression is an argument to an invocation, and the AST structure
-   * has been resolved, and the function being invoked is known based on static
-   * type information, and this expression corresponds to one of the parameters
-   * of the function being invoked, then return the parameter element
-   * representing the parameter to which the value of this expression will be
-   * bound. Otherwise, return `null`.
-   */
-  ParameterElement get staticParameterElement {
-    AstNode parent = this.parent;
-    if (parent is ArgumentList) {
-      return parent._getStaticParameterElementFor(this);
-    } else if (parent is IndexExpression) {
-      IndexExpression indexExpression = parent;
-      if (identical(indexExpression.index, this)) {
-        return indexExpression._staticParameterElementForIndex;
-      }
-    } else if (parent is BinaryExpression) {
-      BinaryExpression binaryExpression = parent;
-      if (identical(binaryExpression.rightOperand, this)) {
-        return binaryExpression._staticParameterElementForRightOperand;
-      }
-    } else if (parent is AssignmentExpression) {
-      AssignmentExpression assignmentExpression = parent;
-      if (identical(assignmentExpression.rightHandSide, this)) {
-        return assignmentExpression._staticParameterElementForRightHandSide;
-      }
-    } else if (parent is PrefixExpression) {
-      return parent._staticParameterElementForOperand;
-    } else if (parent is PostfixExpression) {
-      return parent._staticParameterElementForOperand;
-    }
-    return null;
-  }
-}
-
-/**
- * A function body consisting of a single expression.
- *
- * > expressionFunctionBody ::=
- * >     'async'? '=>' [Expression] ';'
- */
-class ExpressionFunctionBody extends FunctionBody {
-  /**
-   * The token representing the 'async' keyword, or `null` if there is no such
-   * keyword.
-   */
-  Token keyword;
-
-  /**
-   * The token introducing the expression that represents the body of the
-   * function.
-   */
-  Token functionDefinition;
-
-  /**
-   * The expression representing the body of the function.
-   */
-  Expression _expression;
-
-  /**
-   * The semicolon terminating the statement.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created function body consisting of a block of
-   * statements. The [keyword] can be `null` if the function body is not an
-   * async function body.
-   */
-  ExpressionFunctionBody(this.keyword, this.functionDefinition,
-      Expression expression, this.semicolon) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken {
-    if (keyword != null) {
-      return keyword;
-    }
-    return functionDefinition;
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(keyword)
-    ..add(functionDefinition)
-    ..add(_expression)
-    ..add(semicolon);
-
-  @override
-  Token get endToken {
-    if (semicolon != null) {
-      return semicolon;
-    }
-    return _expression.endToken;
-  }
-
-  /**
-   * Return the expression representing the body of the function.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression representing the body of the function to the given
-   * [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  bool get isAsynchronous => keyword != null;
-
-  @override
-  bool get isSynchronous => keyword == null;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitExpressionFunctionBody(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * An expression used as a statement.
- *
- * > expressionStatement ::=
- * >     [Expression]? ';'
- */
-class ExpressionStatement extends Statement {
-  /**
-   * The expression that comprises the statement.
-   */
-  Expression _expression;
-
-  /**
-   * The semicolon terminating the statement, or `null` if the expression is a
-   * function expression and therefore isn't followed by a semicolon.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created expression statement.
-   */
-  ExpressionStatement(Expression expression, this.semicolon) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken => _expression.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_expression)..add(semicolon);
-
-  @override
-  Token get endToken {
-    if (semicolon != null) {
-      return semicolon;
-    }
-    return _expression.endToken;
-  }
-
-  /**
-   * Return the expression that comprises the statement.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression that comprises the statement to the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  bool get isSynthetic => _expression.isSynthetic && semicolon.isSynthetic;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitExpressionStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * The "extends" clause in a class declaration.
- *
- * > extendsClause ::=
- * >     'extends' [TypeName]
- */
-class ExtendsClause extends AstNode {
-  /**
-   * The token representing the 'extends' keyword.
-   */
-  Token extendsKeyword;
-
-  /**
-   * The name of the class that is being extended.
-   */
-  TypeName _superclass;
-
-  /**
-   * Initialize a newly created extends clause.
-   */
-  ExtendsClause(this.extendsKeyword, TypeName superclass) {
-    _superclass = _becomeParentOf(superclass);
-  }
-
-  @override
-  Token get beginToken => extendsKeyword;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(extendsKeyword)..add(_superclass);
-
-  @override
-  Token get endToken => _superclass.endToken;
-
-  /**
-   * Return the name of the class that is being extended.
-   */
-  TypeName get superclass => _superclass;
-
-  /**
-   * Set the name of the class that is being extended to the given [name].
-   */
-  void set superclass(TypeName name) {
-    _superclass = _becomeParentOf(name);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitExtendsClause(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_superclass, visitor);
-  }
-}
-
-/**
- * The declaration of one or more fields of the same type.
- *
- * > fieldDeclaration ::=
- * >     'static'? [VariableDeclarationList] ';'
- */
-class FieldDeclaration extends ClassMember {
-  /**
-   * The token representing the 'static' keyword, or `null` if the fields are
-   * not static.
-   */
-  Token staticKeyword;
-
-  /**
-   * The fields being declared.
-   */
-  VariableDeclarationList _fieldList;
-
-  /**
-   * The semicolon terminating the declaration.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created field declaration. Either or both of the
-   * [comment] and [metadata] can be `null` if the declaration does not have the
-   * corresponding attribute. The [staticKeyword] can be `null` if the field is
-   * not a static field.
-   */
-  FieldDeclaration(Comment comment, List<Annotation> metadata,
-      this.staticKeyword, VariableDeclarationList fieldList, this.semicolon)
-      : super(comment, metadata) {
-    _fieldList = _becomeParentOf(fieldList);
-  }
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(staticKeyword)..add(_fieldList)..add(semicolon);
-
-  @override
-  Element get element => null;
-
-  @override
-  Token get endToken => semicolon;
-
-  /**
-   * Return the fields being declared.
-   */
-  VariableDeclarationList get fields => _fieldList;
-
-  /**
-   * Set the fields being declared to the given list of [fields].
-   */
-  void set fields(VariableDeclarationList fields) {
-    _fieldList = _becomeParentOf(fields);
-  }
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata {
-    if (staticKeyword != null) {
-      return staticKeyword;
-    }
-    return _fieldList.beginToken;
-  }
-
-  /**
-   * Return `true` if the fields are declared to be static.
-   */
-  bool get isStatic => staticKeyword != null;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFieldDeclaration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_fieldList, visitor);
-  }
-}
-
-/**
- * A field formal parameter.
- *
- * > fieldFormalParameter ::=
- * >     ('final' [TypeName] | 'const' [TypeName] | 'var' | [TypeName])?
- * >     'this' '.' [SimpleIdentifier] ([TypeParameterList]? [FormalParameterList])?
- */
-class FieldFormalParameter extends NormalFormalParameter {
-  /**
-   * The token representing either the 'final', 'const' or 'var' keyword, or
-   * `null` if no keyword was used.
-   */
-  Token keyword;
-
-  /**
-   * The name of the declared type of the parameter, or `null` if the parameter
-   * does not have a declared type.
-   */
-  TypeName _type;
-
-  /**
-   * The token representing the 'this' keyword.
-   */
-  Token thisKeyword;
-
-  /**
-   * The token representing the period.
-   */
-  Token period;
-
-  /**
-   * The type parameters associated with the method, or `null` if the method is
-   * not a generic method.
-   */
-  TypeParameterList _typeParameters;
-
-  /**
-   * The parameters of the function-typed parameter, or `null` if this is not a
-   * function-typed field formal parameter.
-   */
-  FormalParameterList _parameters;
-
-  /**
-   * Initialize a newly created formal parameter. Either or both of the
-   * [comment] and [metadata] can be `null` if the parameter does not have the
-   * corresponding attribute. The [keyword] can be `null` if there is a type.
-   * The [type] must be `null` if the keyword is 'var'. The [thisKeyword] and
-   * [period] can be `null` if the keyword 'this' was not provided.  The
-   * [parameters] can be `null` if this is not a function-typed field formal
-   * parameter.
-   */
-  FieldFormalParameter(
-      Comment comment,
-      List<Annotation> metadata,
-      this.keyword,
-      TypeName type,
-      this.thisKeyword,
-      this.period,
-      SimpleIdentifier identifier,
-      TypeParameterList typeParameters,
-      FormalParameterList parameters)
-      : super(comment, metadata, identifier) {
-    _type = _becomeParentOf(type);
-    _typeParameters = _becomeParentOf(typeParameters);
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  @override
-  Token get beginToken {
-    if (keyword != null) {
-      return keyword;
-    } else if (_type != null) {
-      return _type.beginToken;
-    }
-    return thisKeyword;
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(keyword)
-    ..add(_type)
-    ..add(thisKeyword)
-    ..add(period)
-    ..add(identifier)
-    ..add(_parameters);
-
-  @override
-  Token get endToken {
-    if (_parameters != null) {
-      return _parameters.endToken;
-    }
-    return identifier.endToken;
-  }
-
-  @override
-  bool get isConst =>
-      (keyword is KeywordToken) &&
-      (keyword as KeywordToken).keyword == Keyword.CONST;
-
-  @override
-  bool get isFinal =>
-      (keyword is KeywordToken) &&
-      (keyword as KeywordToken).keyword == Keyword.FINAL;
-
-  /**
-   * Return the parameters of the function-typed parameter, or `null` if this is
-   * not a function-typed field formal parameter.
-   */
-  FormalParameterList get parameters => _parameters;
-
-  /**
-   * Set the parameters of the function-typed parameter to the given
-   * [parameters].
-   */
-  void set parameters(FormalParameterList parameters) {
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  /**
-   * Return the name of the declared type of the parameter, or `null` if the
-   * parameter does not have a declared type. Note that if this is a
-   * function-typed field formal parameter this is the return type of the
-   * function.
-   */
-  TypeName get type => _type;
-
-  /**
-   * Set the name of the declared type of the parameter to the given [typeName].
-   */
-  void set type(TypeName typeName) {
-    _type = _becomeParentOf(typeName);
-  }
-
-  /**
-   * Return the type parameters associated with this method, or `null` if this
-   * method is not a generic method.
-   */
-  TypeParameterList get typeParameters => _typeParameters;
-
-  /**
-   * Set the type parameters associated with this method to the given
-   * [typeParameters].
-   */
-  void set typeParameters(TypeParameterList typeParameters) {
-    _typeParameters = _becomeParentOf(typeParameters);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFieldFormalParameter(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_type, visitor);
-    _safelyVisitChild(identifier, visitor);
-    _safelyVisitChild(_typeParameters, visitor);
-    _safelyVisitChild(_parameters, visitor);
-  }
-}
-
-/**
- * A for-each statement.
- *
- * > forEachStatement ::=
- * >     'await'? 'for' '(' [DeclaredIdentifier] 'in' [Expression] ')' [Block]
- * >   | 'await'? 'for' '(' [SimpleIdentifier] 'in' [Expression] ')' [Block]
- */
-class ForEachStatement extends Statement {
-  /**
-   * The token representing the 'await' keyword, or `null` if there is no
-   * 'await' keyword.
-   */
-  Token awaitKeyword;
-
-  /**
-   * The token representing the 'for' keyword.
-   */
-  Token forKeyword;
-
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The declaration of the loop variable, or `null` if the loop variable is a
-   * simple identifier.
-   */
-  DeclaredIdentifier _loopVariable;
-
-  /**
-   * The loop variable, or `null` if the loop variable is declared in the 'for'.
-   */
-  SimpleIdentifier _identifier;
-
-  /**
-   * The token representing the 'in' keyword.
-   */
-  Token inKeyword;
-
-  /**
-   * The expression evaluated to produce the iterator.
-   */
-  Expression _iterable;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * The body of the loop.
-   */
-  Statement _body;
-
-  /**
-   * Initialize a newly created for-each statement whose loop control variable
-   * is declared internally (in the for-loop part). The [awaitKeyword] can be
-   * `null` if this is not an asynchronous for loop.
-   */
-  ForEachStatement.withDeclaration(
-      this.awaitKeyword,
-      this.forKeyword,
-      this.leftParenthesis,
-      DeclaredIdentifier loopVariable,
-      this.inKeyword,
-      Expression iterator,
-      this.rightParenthesis,
-      Statement body) {
-    _loopVariable = _becomeParentOf(loopVariable);
-    _iterable = _becomeParentOf(iterator);
-    _body = _becomeParentOf(body);
-  }
-
-  /**
-   * Initialize a newly created for-each statement whose loop control variable
-   * is declared outside the for loop. The [awaitKeyword] can be `null` if this
-   * is not an asynchronous for loop.
-   */
-  ForEachStatement.withReference(
-      this.awaitKeyword,
-      this.forKeyword,
-      this.leftParenthesis,
-      SimpleIdentifier identifier,
-      this.inKeyword,
-      Expression iterator,
-      this.rightParenthesis,
-      Statement body) {
-    _identifier = _becomeParentOf(identifier);
-    _iterable = _becomeParentOf(iterator);
-    _body = _becomeParentOf(body);
-  }
-
-  @override
-  Token get beginToken => forKeyword;
-
-  /**
-   * Return the body of the loop.
-   */
-  Statement get body => _body;
-
-  /**
-   * Set the body of the loop to the given [statement].
-   */
-  void set body(Statement statement) {
-    _body = _becomeParentOf(statement);
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(awaitKeyword)
-    ..add(forKeyword)
-    ..add(leftParenthesis)
-    ..add(_loopVariable)
-    ..add(_identifier)
-    ..add(inKeyword)
-    ..add(_iterable)
-    ..add(rightParenthesis)
-    ..add(_body);
-
-  @override
-  Token get endToken => _body.endToken;
-
-  /**
-   * Return the loop variable, or `null` if the loop variable is declared in the
-   * 'for'.
-   */
-  SimpleIdentifier get identifier => _identifier;
-
-  /**
-   * Set the loop variable to the given [identifier].
-   */
-  void set identifier(SimpleIdentifier identifier) {
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  /**
-   * Return the expression evaluated to produce the iterator.
-   */
-  Expression get iterable => _iterable;
-
-  /**
-   * Set the expression evaluated to produce the iterator to the given
-   * [expression].
-   */
-  void set iterable(Expression expression) {
-    _iterable = _becomeParentOf(expression);
-  }
-
-  /**
-   * Return the declaration of the loop variable, or `null` if the loop variable
-   * is a simple identifier.
-   */
-  DeclaredIdentifier get loopVariable => _loopVariable;
-
-  /**
-   * Set the declaration of the loop variable to the given [variable].
-   */
-  void set loopVariable(DeclaredIdentifier variable) {
-    _loopVariable = _becomeParentOf(variable);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitForEachStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_loopVariable, visitor);
-    _safelyVisitChild(_identifier, visitor);
-    _safelyVisitChild(_iterable, visitor);
-    _safelyVisitChild(_body, visitor);
-  }
-}
-
-/**
- * A node representing a parameter to a function.
- *
- * > formalParameter ::=
- * >     [NormalFormalParameter]
- * >   | [DefaultFormalParameter]
- */
-abstract class FormalParameter extends AstNode {
-  /**
-   * Return the element representing this parameter, or `null` if this parameter
-   * has not been resolved.
-   */
-  ParameterElement get element {
-    SimpleIdentifier identifier = this.identifier;
-    if (identifier == null) {
-      return null;
-    }
-    return identifier.staticElement as ParameterElement;
-  }
-
-  /**
-   * Return the name of the parameter being declared.
-   */
-  SimpleIdentifier get identifier;
-
-  /**
-   * Return `true` if this parameter was declared with the 'const' modifier.
-   */
-  bool get isConst;
-
-  /**
-   * Return `true` if this parameter was declared with the 'final' modifier.
-   * Parameters that are declared with the 'const' modifier will return `false`
-   * even though they are implicitly final.
-   */
-  bool get isFinal;
-
-  /**
-   * Return the kind of this parameter.
-   */
-  ParameterKind get kind;
-
-  /**
-   * Return the annotations associated with this parameter.
-   */
-  NodeList<Annotation> get metadata;
-}
-
-/**
- * The formal parameter list of a method declaration, function declaration, or
- * function type alias.
- *
- * While the grammar requires all optional formal parameters to follow all of
- * the normal formal parameters and at most one grouping of optional formal
- * parameters, this class does not enforce those constraints. All parameters are
- * 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])* '}'
- */
-class FormalParameterList extends AstNode {
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The parameters associated with the method.
-   */
-  NodeList<FormalParameter> _parameters;
-
-  /**
-   * The left square bracket ('[') or left curly brace ('{') introducing the
-   * optional parameters, or `null` if there are no optional parameters.
-   */
-  Token leftDelimiter;
-
-  /**
-   * The right square bracket (']') or right curly brace ('}') terminating the
-   * optional parameters, or `null` if there are no optional parameters.
-   */
-  Token rightDelimiter;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * Initialize a newly created parameter list. The list of [parameters] can be
-   * `null` if there are no parameters. The [leftDelimiter] and [rightDelimiter]
-   * can be `null` if there are no optional parameters.
-   */
-  FormalParameterList(this.leftParenthesis, List<FormalParameter> parameters,
-      this.leftDelimiter, this.rightDelimiter, this.rightParenthesis) {
-    _parameters = new NodeList<FormalParameter>(this, parameters);
-  }
-
-  @override
-  Token get beginToken => leftParenthesis;
-
-  @override
-  Iterable get childEntities {
-    // TODO(paulberry): include commas.
-    ChildEntities result = new ChildEntities()..add(leftParenthesis);
-    bool leftDelimiterNeeded = leftDelimiter != null;
-    for (FormalParameter parameter in _parameters) {
-      if (leftDelimiterNeeded && leftDelimiter.offset < parameter.offset) {
-        result.add(leftDelimiter);
-        leftDelimiterNeeded = false;
-      }
-      result.add(parameter);
-    }
-    return result..add(rightDelimiter)..add(rightParenthesis);
-  }
-
-  @override
-  Token get endToken => rightParenthesis;
-
-  /**
-   * Return a list containing the elements representing the parameters in this
-   * list. The list will contain `null`s if the parameters in this list have not
-   * been resolved.
-   */
-  List<ParameterElement> get parameterElements {
-    int count = _parameters.length;
-    List<ParameterElement> types = new List<ParameterElement>(count);
-    for (int i = 0; i < count; i++) {
-      types[i] = _parameters[i].element;
-    }
-    return types;
-  }
-
-  /**
-   * Return the parameters associated with the method.
-   */
-  NodeList<FormalParameter> get parameters => _parameters;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFormalParameterList(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _parameters.accept(visitor);
-  }
-}
-
-/**
- * A for statement.
- *
- * > forStatement ::=
- * >     'for' '(' forLoopParts ')' [Statement]
- * >
- * > forLoopParts ::=
- * >     forInitializerStatement ';' [Expression]? ';' [Expression]?
- * >
- * > forInitializerStatement ::=
- * >     [DefaultFormalParameter]
- * >   | [Expression]?
- */
-class ForStatement extends Statement {
-  /**
-   * The token representing the 'for' keyword.
-   */
-  Token forKeyword;
-
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The declaration of the loop variables, or `null` if there are no variables.
-   * Note that a for statement cannot have both a variable list and an
-   * initialization expression, but can validly have neither.
-   */
-  VariableDeclarationList _variableList;
-
-  /**
-   * The initialization expression, or `null` if there is no initialization
-   * expression. Note that a for statement cannot have both a variable list and
-   * an initialization expression, but can validly have neither.
-   */
-  Expression _initialization;
-
-  /**
-   * The semicolon separating the initializer and the condition.
-   */
-  Token leftSeparator;
-
-  /**
-   * The condition used to determine when to terminate the loop, or `null` if
-   * there is no condition.
-   */
-  Expression _condition;
-
-  /**
-   * The semicolon separating the condition and the updater.
-   */
-  Token rightSeparator;
-
-  /**
-   * The list of expressions run after each execution of the loop body.
-   */
-  NodeList<Expression> _updaters;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * The body of the loop.
-   */
-  Statement _body;
-
-  /**
-   * Initialize a newly created for statement. Either the [variableList] or the
-   * [initialization] must be `null`. Either the [condition] and the list of
-   * [updaters] can be `null` if the loop does not have the corresponding
-   * attribute.
-   */
-  ForStatement(
-      this.forKeyword,
-      this.leftParenthesis,
-      VariableDeclarationList variableList,
-      Expression initialization,
-      this.leftSeparator,
-      Expression condition,
-      this.rightSeparator,
-      List<Expression> updaters,
-      this.rightParenthesis,
-      Statement body) {
-    _variableList = _becomeParentOf(variableList);
-    _initialization = _becomeParentOf(initialization);
-    _condition = _becomeParentOf(condition);
-    _updaters = new NodeList<Expression>(this, updaters);
-    _body = _becomeParentOf(body);
-  }
-
-  @override
-  Token get beginToken => forKeyword;
-
-  /**
-   * Return the body of the loop.
-   */
-  Statement get body => _body;
-
-  /**
-   * Set the body of the loop to the given [statement].
-   */
-  void set body(Statement statement) {
-    _body = _becomeParentOf(statement);
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(forKeyword)
-    ..add(leftParenthesis)
-    ..add(_variableList)
-    ..add(_initialization)
-    ..add(leftSeparator)
-    ..add(_condition)
-    ..add(rightSeparator)
-    ..addAll(_updaters)
-    ..add(rightParenthesis)
-    ..add(_body);
-
-  /**
-   * Return the condition used to determine when to terminate the loop, or
-   * `null` if there is no condition.
-   */
-  Expression get condition => _condition;
-
-  /**
-   * Set the condition used to determine when to terminate the loop to the given
-   * [expression].
-   */
-  void set condition(Expression expression) {
-    _condition = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get endToken => _body.endToken;
-
-  /**
-   * Return the initialization expression, or `null` if there is no
-   * initialization expression.
-   */
-  Expression get initialization => _initialization;
-
-  /**
-   * Set the initialization expression to the given [expression].
-   */
-  void set initialization(Expression initialization) {
-    _initialization = _becomeParentOf(initialization);
-  }
-
-  /**
-   * Return the list of expressions run after each execution of the loop body.
-   */
-  NodeList<Expression> get updaters => _updaters;
-
-  /**
-   * Return the declaration of the loop variables, or `null` if there are no
-   * variables.
-   */
-  VariableDeclarationList get variables => _variableList;
-
-  /**
-   * Set the declaration of the loop variables to the given [variableList].
-   */
-  void set variables(VariableDeclarationList variableList) {
-    _variableList = _becomeParentOf(variableList);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitForStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_variableList, visitor);
-    _safelyVisitChild(_initialization, visitor);
-    _safelyVisitChild(_condition, visitor);
-    _updaters.accept(visitor);
-    _safelyVisitChild(_body, visitor);
-  }
-}
-
-/**
- * A node representing the body of a function or method.
- *
- * > functionBody ::=
- * >     [BlockFunctionBody]
- * >   | [EmptyFunctionBody]
- * >   | [ExpressionFunctionBody]
- */
-abstract class FunctionBody extends AstNode {
-  /**
-   * Return `true` if this function body is asynchronous.
-   */
-  bool get isAsynchronous => false;
-
-  /**
-   * Return `true` if this function body is a generator.
-   */
-  bool get isGenerator => false;
-
-  /**
-   * Return `true` if this function body is synchronous.
-   */
-  bool get isSynchronous => true;
-
-  /**
-   * Return the token representing the 'async' or 'sync' keyword, or `null` if
-   * there is no such keyword.
-   */
-  Token get keyword => null;
-
-  /**
-   * Return the star following the 'async' or 'sync' keyword, or `null` if there
-   * is no star.
-   */
-  Token get star => null;
-}
-
-/**
- * A top-level declaration.
- *
- * > functionDeclaration ::=
- * >     'external' functionSignature
- * >   | functionSignature [FunctionBody]
- * >
- * > functionSignature ::=
- * >     [Type]? ('get' | 'set')? [SimpleIdentifier] [FormalParameterList]
- */
-class FunctionDeclaration extends NamedCompilationUnitMember {
-  /**
-   * The token representing the 'external' keyword, or `null` if this is not an
-   * external function.
-   */
-  Token externalKeyword;
-
-  /**
-   * The return type of the function, or `null` if no return type was declared.
-   */
-  TypeName _returnType;
-
-  /**
-   * The token representing the 'get' or 'set' keyword, or `null` if this is a
-   * function declaration rather than a property declaration.
-   */
-  Token propertyKeyword;
-
-  /**
-   * The function expression being wrapped.
-   */
-  FunctionExpression _functionExpression;
-
-  /**
-   * Initialize a newly created function declaration. Either or both of the
-   * [comment] and [metadata] can be `null` if the function does not have the
-   * corresponding attribute. The [externalKeyword] can be `null` if the
-   * function is not an external function. The [returnType] can be `null` if no
-   * return type was specified. The [propertyKeyword] can be `null` if the
-   * function is neither a getter or a setter.
-   */
-  FunctionDeclaration(
-      Comment comment,
-      List<Annotation> metadata,
-      this.externalKeyword,
-      TypeName returnType,
-      this.propertyKeyword,
-      SimpleIdentifier name,
-      FunctionExpression functionExpression)
-      : super(comment, metadata, name) {
-    _returnType = _becomeParentOf(returnType);
-    _functionExpression = _becomeParentOf(functionExpression);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(externalKeyword)
-    ..add(_returnType)
-    ..add(propertyKeyword)
-    ..add(_name)
-    ..add(_functionExpression);
-
-  @override
-  ExecutableElement get element =>
-      _name != null ? (_name.staticElement as ExecutableElement) : null;
-
-  @override
-  Token get endToken => _functionExpression.endToken;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata {
-    if (externalKeyword != null) {
-      return externalKeyword;
-    } else if (_returnType != null) {
-      return _returnType.beginToken;
-    } else if (propertyKeyword != null) {
-      return propertyKeyword;
-    } else if (_name != null) {
-      return _name.beginToken;
-    }
-    return _functionExpression.beginToken;
-  }
-
-  /**
-   * Return the function expression being wrapped.
-   */
-  FunctionExpression get functionExpression => _functionExpression;
-
-  /**
-   * Set the function expression being wrapped to the given
-   * [functionExpression].
-   */
-  void set functionExpression(FunctionExpression functionExpression) {
-    _functionExpression = _becomeParentOf(functionExpression);
-  }
-
-  /**
-   * Return `true` if this function declares a getter.
-   */
-  bool get isGetter =>
-      propertyKeyword != null &&
-      (propertyKeyword as KeywordToken).keyword == Keyword.GET;
-
-  /**
-   * Return `true` if this function declares a setter.
-   */
-  bool get isSetter =>
-      propertyKeyword != null &&
-      (propertyKeyword as KeywordToken).keyword == Keyword.SET;
-
-  /**
-   * Return the return type of the function, or `null` if no return type was
-   * declared.
-   */
-  TypeName get returnType => _returnType;
-
-  /**
-   * Set the return type of the function to the given [returnType].
-   */
-  void set returnType(TypeName returnType) {
-    _returnType = _becomeParentOf(returnType);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFunctionDeclaration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_returnType, visitor);
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_functionExpression, visitor);
-  }
-}
-
-/**
- * A [FunctionDeclaration] used as a statement.
- */
-class FunctionDeclarationStatement extends Statement {
-  /**
-   * The function declaration being wrapped.
-   */
-  FunctionDeclaration _functionDeclaration;
-
-  /**
-   * Initialize a newly created function declaration statement.
-   */
-  FunctionDeclarationStatement(FunctionDeclaration functionDeclaration) {
-    _functionDeclaration = _becomeParentOf(functionDeclaration);
-  }
-
-  @override
-  Token get beginToken => _functionDeclaration.beginToken;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(_functionDeclaration);
-
-  @override
-  Token get endToken => _functionDeclaration.endToken;
-
-  /**
-   * Return the function declaration being wrapped.
-   */
-  FunctionDeclaration get functionDeclaration => _functionDeclaration;
-
-  /**
-   * Set the function declaration being wrapped to the given
-   * [functionDeclaration].
-   */
-  void set functionDeclaration(FunctionDeclaration functionDeclaration) {
-    _functionDeclaration = _becomeParentOf(functionDeclaration);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFunctionDeclarationStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_functionDeclaration, visitor);
-  }
-}
-
-/**
- * A function expression.
- *
- * > functionExpression ::=
- * >     [TypeParameterList]? [FormalParameterList] [FunctionBody]
- */
-class FunctionExpression extends Expression {
-  /**
-   * The type parameters associated with the method, or `null` if the method is
-   * not a generic method.
-   */
-  TypeParameterList _typeParameters;
-
-  /**
-   * The parameters associated with the function.
-   */
-  FormalParameterList _parameters;
-
-  /**
-   * The body of the function, or `null` if this is an external function.
-   */
-  FunctionBody _body;
-
-  /**
-   * The element associated with the function, or `null` if the AST structure
-   * has not been resolved.
-   */
-  ExecutableElement element;
-
-  /**
-   * Initialize a newly created function declaration.
-   */
-  FunctionExpression(TypeParameterList typeParameters,
-      FormalParameterList parameters, FunctionBody body) {
-    _typeParameters = _becomeParentOf(typeParameters);
-    _parameters = _becomeParentOf(parameters);
-    _body = _becomeParentOf(body);
-  }
-
-  @override
-  Token get beginToken {
-    if (_typeParameters != null) {
-      return _typeParameters.beginToken;
-    } else if (_parameters != null) {
-      return _parameters.beginToken;
-    } else if (_body != null) {
-      return _body.beginToken;
-    }
-    // This should never be reached because external functions must be named,
-    // hence either the body or the name should be non-null.
-    throw new IllegalStateException("Non-external functions must have a body");
-  }
-
-  /**
-   * Return the body of the function, or `null` if this is an external function.
-   */
-  FunctionBody get body => _body;
-
-  /**
-   * Set the body of the function to the given [functionBody].
-   */
-  void set body(FunctionBody functionBody) {
-    _body = _becomeParentOf(functionBody);
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_parameters)..add(_body);
-
-  @override
-  Token get endToken {
-    if (_body != null) {
-      return _body.endToken;
-    } else if (_parameters != null) {
-      return _parameters.endToken;
-    }
-    // This should never be reached because external functions must be named,
-    // hence either the body or the name should be non-null.
-    throw new IllegalStateException("Non-external functions must have a body");
-  }
-
-  /**
-   * Return the parameters associated with the function.
-   */
-  FormalParameterList get parameters => _parameters;
-
-  /**
-   * Set the parameters associated with the function to the given list of
-   * [parameters].
-   */
-  void set parameters(FormalParameterList parameters) {
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  @override
-  int get precedence => 16;
-
-  /**
-   * Return the type parameters associated with this method, or `null` if this
-   * method is not a generic method.
-   */
-  TypeParameterList get typeParameters => _typeParameters;
-
-  /**
-   * Set the type parameters associated with this method to the given
-   * [typeParameters].
-   */
-  void set typeParameters(TypeParameterList typeParameters) {
-    _typeParameters = _becomeParentOf(typeParameters);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFunctionExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_typeParameters, visitor);
-    _safelyVisitChild(_parameters, visitor);
-    _safelyVisitChild(_body, visitor);
-  }
-}
-
-/**
- * The invocation of a function resulting from evaluating an expression.
- * Invocations of methods and other forms of functions are represented by
- * [MethodInvocation] nodes. Invocations of getters and setters are represented
- * by either [PrefixedIdentifier] or [PropertyAccess] nodes.
- *
- * > functionExpressionInvocation ::=
- * >     [Expression] [TypeArgumentList]? [ArgumentList]
- */
-class FunctionExpressionInvocation extends Expression {
-  /**
-   * The expression producing the function being invoked.
-   */
-  Expression _function;
-
-  /**
-   * The type arguments to be applied to the method being invoked, or `null` if
-   * no type arguments were provided.
-   */
-  TypeArgumentList _typeArguments;
-
-  /**
-   * The list of arguments to the function.
-   */
-  ArgumentList _argumentList;
-
-  /**
-   * The element associated with the function being invoked based on static type
-   * information, or `null` if the AST structure has not been resolved or the
-   * function could not be resolved.
-   */
-  ExecutableElement staticElement;
-
-  /**
-   * The function type of the method invocation, or `null` if the AST
-   * structure has not been resolved, or if the invoke could not be resolved.
-   *
-   * This will usually be a [FunctionType], but it can also be an
-   * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
-   * interface type that implements `Function`.
-   */
-  DartType staticInvokeType;
-
-  /**
-   * The element associated with the function being invoked based on propagated
-   * type information, or `null` if the AST structure has not been resolved or
-   * the function could not be resolved.
-   */
-  ExecutableElement propagatedElement;
-
-  /**
-   * Like [staticInvokeType], but reflects propagated type information.
-   */
-  DartType propagatedInvokeType;
-
-  /**
-   * Initialize a newly created function expression invocation.
-   */
-  FunctionExpressionInvocation(Expression function,
-      TypeArgumentList typeArguments, ArgumentList argumentList) {
-    _function = _becomeParentOf(function);
-    _typeArguments = _becomeParentOf(typeArguments);
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  /**
-   * Return the list of arguments to the method.
-   */
-  ArgumentList get argumentList => _argumentList;
-
-  /**
-   * Set the list of arguments to the method to the given [argumentList].
-   */
-  void set argumentList(ArgumentList argumentList) {
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  @override
-  Token get beginToken => _function.beginToken;
-
-  /**
-   * Return the best element available for the function being invoked. If
-   * resolution was able to find a better element based on type propagation,
-   * that element will be returned. Otherwise, the element found using the
-   * result of static analysis will be returned. If resolution has not been
-   * performed, then `null` will be returned.
-   */
-  ExecutableElement get bestElement {
-    ExecutableElement element = propagatedElement;
-    if (element == null) {
-      element = staticElement;
-    }
-    return element;
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_function)..add(_argumentList);
-
-  @override
-  Token get endToken => _argumentList.endToken;
-
-  /**
-   * Return the expression producing the function being invoked.
-   */
-  Expression get function => _function;
-
-  /**
-   * Set the expression producing the function being invoked to the given
-   * [expression].
-   */
-  void set function(Expression expression) {
-    _function = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 15;
-
-  /**
-   * Return the type arguments to be applied to the method being invoked, or
-   * `null` if no type arguments were provided.
-   */
-  TypeArgumentList get typeArguments => _typeArguments;
-
-  /**
-   * Set the type arguments to be applied to the method being invoked to the
-   * given [typeArguments].
-   */
-  void set typeArguments(TypeArgumentList typeArguments) {
-    _typeArguments = _becomeParentOf(typeArguments);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFunctionExpressionInvocation(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_function, visitor);
-    _safelyVisitChild(_typeArguments, visitor);
-    _safelyVisitChild(_argumentList, visitor);
-  }
-}
-
-/**
- * A function type alias.
- *
- * > functionTypeAlias ::=
- * >     functionPrefix [TypeParameterList]? [FormalParameterList] ';'
- * >
- * > functionPrefix ::=
- * >     [TypeName]? [SimpleIdentifier]
- */
-class FunctionTypeAlias extends TypeAlias {
-  /**
-   * The name of the return type of the function type being defined, or `null`
-   * if no return type was given.
-   */
-  TypeName _returnType;
-
-  /**
-   * The type parameters for the function type, or `null` if the function type
-   * does not have any type parameters.
-   */
-  TypeParameterList _typeParameters;
-
-  /**
-   * The parameters associated with the function type.
-   */
-  FormalParameterList _parameters;
-
-  /**
-   * Initialize a newly created function type alias. Either or both of the
-   * [comment] and [metadata] can be `null` if the function does not have the
-   * corresponding attribute. The [returnType] can be `null` if no return type
-   * was specified. The [typeParameters] can be `null` if the function has no
-   * type parameters.
-   */
-  FunctionTypeAlias(
-      Comment comment,
-      List<Annotation> metadata,
-      Token keyword,
-      TypeName returnType,
-      SimpleIdentifier name,
-      TypeParameterList typeParameters,
-      FormalParameterList parameters,
-      Token semicolon)
-      : super(comment, metadata, keyword, name, semicolon) {
-    _returnType = _becomeParentOf(returnType);
-    _typeParameters = _becomeParentOf(typeParameters);
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(typedefKeyword)
-    ..add(_returnType)
-    ..add(_name)
-    ..add(_typeParameters)
-    ..add(_parameters)
-    ..add(semicolon);
-
-  @override
-  FunctionTypeAliasElement get element =>
-      _name != null ? (_name.staticElement as FunctionTypeAliasElement) : null;
-
-  /**
-   * Return the parameters associated with the function type.
-   */
-  FormalParameterList get parameters => _parameters;
-
-  /**
-   * Set the parameters associated with the function type to the given list of
-   * [parameters].
-   */
-  void set parameters(FormalParameterList parameters) {
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  /**
-   * Return the name of the return type of the function type being defined, or
-   * `null` if no return type was given.
-   */
-  TypeName get returnType => _returnType;
-
-  /**
-   * Set the name of the return type of the function type being defined to the
-   * given [typeName].
-   */
-  void set returnType(TypeName typeName) {
-    _returnType = _becomeParentOf(typeName);
-  }
-
-  /**
-   * Return the type parameters for the function type, or `null` if the function
-   * type does not have any type parameters.
-   */
-  TypeParameterList get typeParameters => _typeParameters;
-
-  /**
-   * Set the type parameters for the function type to the given list of
-   * [typeParameters].
-   */
-  void set typeParameters(TypeParameterList typeParameters) {
-    _typeParameters = _becomeParentOf(typeParameters);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFunctionTypeAlias(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_returnType, visitor);
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_typeParameters, visitor);
-    _safelyVisitChild(_parameters, visitor);
-  }
-}
-
-/**
- * A function-typed formal parameter.
- *
- * > functionSignature ::=
- * >     [TypeName]? [SimpleIdentifier] [TypeParameterList]? [FormalParameterList]
- */
-class FunctionTypedFormalParameter extends NormalFormalParameter {
-  /**
-   * The return type of the function, or `null` if the function does not have a
-   * return type.
-   */
-  TypeName _returnType;
-
-  /**
-   * The type parameters associated with the function, or `null` if the function
-   * is not a generic function.
-   */
-  TypeParameterList _typeParameters;
-
-  /**
-   * The parameters of the function-typed parameter.
-   */
-  FormalParameterList _parameters;
-
-  /**
-   * Initialize a newly created formal parameter. Either or both of the
-   * [comment] and [metadata] can be `null` if the parameter does not have the
-   * corresponding attribute. The [returnType] can be `null` if no return type
-   * was specified.
-   */
-  FunctionTypedFormalParameter(
-      Comment comment,
-      List<Annotation> metadata,
-      TypeName returnType,
-      SimpleIdentifier identifier,
-      TypeParameterList typeParameters,
-      FormalParameterList parameters)
-      : super(comment, metadata, identifier) {
-    _returnType = _becomeParentOf(returnType);
-    _typeParameters = _becomeParentOf(typeParameters);
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  @override
-  Token get beginToken {
-    if (_returnType != null) {
-      return _returnType.beginToken;
-    }
-    return identifier.beginToken;
-  }
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(_returnType)..add(identifier)..add(parameters);
-
-  @override
-  Token get endToken => _parameters.endToken;
-
-  @override
-  bool get isConst => false;
-
-  @override
-  bool get isFinal => false;
-
-  /**
-   * Return the parameters of the function-typed parameter.
-   */
-  FormalParameterList get parameters => _parameters;
-
-  /**
-   * Set the parameters of the function-typed parameter to the given
-   * [parameters].
-   */
-  void set parameters(FormalParameterList parameters) {
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  /**
-   * Return the return type of the function, or `null` if the function does not
-   * have a return type.
-   */
-  TypeName get returnType => _returnType;
-
-  /**
-   * Set the return type of the function to the given [type].
-   */
-  void set returnType(TypeName type) {
-    _returnType = _becomeParentOf(type);
-  }
-
-  /**
-   * Return the type parameters associated with this function, or `null` if
-   * this function is not a generic function.
-   */
-  TypeParameterList get typeParameters => _typeParameters;
-
-  /**
-   * Set the type parameters associated with this method to the given
-   * [typeParameters].
-   */
-  void set typeParameters(TypeParameterList typeParameters) {
-    _typeParameters = _becomeParentOf(typeParameters);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitFunctionTypedFormalParameter(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_returnType, visitor);
-    _safelyVisitChild(identifier, visitor);
-    _safelyVisitChild(_typeParameters, visitor);
-    _safelyVisitChild(_parameters, visitor);
-  }
-}
-
-/**
- * A combinator that restricts the names being imported to those that are not in
- * a given list.
- *
- * > hideCombinator ::=
- * >     'hide' [SimpleIdentifier] (',' [SimpleIdentifier])*
- */
-class HideCombinator extends Combinator {
-  /**
-   * The list of names from the library that are hidden by this combinator.
-   */
-  NodeList<SimpleIdentifier> _hiddenNames;
-
-  /**
-   * Initialize a newly created import show combinator.
-   */
-  HideCombinator(Token keyword, List<SimpleIdentifier> hiddenNames)
-      : super(keyword) {
-    _hiddenNames = new NodeList<SimpleIdentifier>(this, hiddenNames);
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(keyword)
-    ..addAll(_hiddenNames);
-
-  @override
-  Token get endToken => _hiddenNames.endToken;
-
-  /**
-   * Return the list of names from the library that are hidden by this
-   * combinator.
-   */
-  NodeList<SimpleIdentifier> get hiddenNames => _hiddenNames;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitHideCombinator(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _hiddenNames.accept(visitor);
-  }
-}
-
-/**
- * A node that represents an identifier.
- *
- * > identifier ::=
- * >     [SimpleIdentifier]
- * >   | [PrefixedIdentifier]
- */
-abstract class Identifier extends Expression {
-  /**
-   * Return the best element available for this operator. If resolution was able
-   * to find a better element based on type propagation, that element will be
-   * returned. Otherwise, the element found using the result of static analysis
-   * will be returned. If resolution has not been performed, then `null` will be
-   * returned.
-   */
-  Element get bestElement;
-
-  @override
-  bool get isAssignable => true;
-
-  /**
-   * Return the lexical representation of the identifier.
-   */
-  String get name;
-
-  /**
-   * Return the element associated with this identifier based on propagated type
-   * information, or `null` if the AST structure has not been resolved or if
-   * this identifier could not be resolved. One example of the latter case is an
-   * identifier that is not defined within the scope in which it appears.
-   */
-  Element get propagatedElement;
-
-  /**
-   * Return the element associated with this identifier based on static type
-   * information, or `null` if the AST structure has not been resolved or if
-   * this identifier could not be resolved. One example of the latter case is an
-   * identifier that is not defined within the scope in which it appears
-   */
-  Element get staticElement;
-
-  /**
-   * Return `true` if the given [name] is visible only within the library in
-   * which it is declared.
-   */
-  static bool isPrivateName(String name) =>
-      StringUtilities.startsWithChar(name, 0x5F);
-}
-
-/**
- * An if statement.
- *
- * > ifStatement ::=
- * >     'if' '(' [Expression] ')' [Statement] ('else' [Statement])?
- */
-class IfStatement extends Statement {
-  /**
-   * The token representing the 'if' keyword.
-   */
-  Token ifKeyword;
-
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The condition used to determine which of the statements is executed next.
-   */
-  Expression _condition;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * The statement that is executed if the condition evaluates to `true`.
-   */
-  Statement _thenStatement;
-
-  /**
-   * The token representing the 'else' keyword, or `null` if there is no else
-   * statement.
-   */
-  Token elseKeyword;
-
-  /**
-   * The statement that is executed if the condition evaluates to `false`, or
-   * `null` if there is no else statement.
-   */
-  Statement _elseStatement;
-
-  /**
-   * Initialize a newly created if statement. The [elseKeyword] and
-   * [elseStatement] can be `null` if there is no else clause.
-   */
-  IfStatement(
-      this.ifKeyword,
-      this.leftParenthesis,
-      Expression condition,
-      this.rightParenthesis,
-      Statement thenStatement,
-      this.elseKeyword,
-      Statement elseStatement) {
-    _condition = _becomeParentOf(condition);
-    _thenStatement = _becomeParentOf(thenStatement);
-    _elseStatement = _becomeParentOf(elseStatement);
-  }
-
-  @override
-  Token get beginToken => ifKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(ifKeyword)
-    ..add(leftParenthesis)
-    ..add(_condition)
-    ..add(rightParenthesis)
-    ..add(_thenStatement)
-    ..add(elseKeyword)
-    ..add(_elseStatement);
-
-  /**
-   * Return the condition used to determine which of the statements is executed
-   * next.
-   */
-  Expression get condition => _condition;
-
-  /**
-   * Set the condition used to determine which of the statements is executed
-   * next to the given [expression].
-   */
-  void set condition(Expression expression) {
-    _condition = _becomeParentOf(expression);
-  }
-
-  /**
-   * Return the statement that is executed if the condition evaluates to
-   * `false`, or `null` if there is no else statement.
-   */
-  Statement get elseStatement => _elseStatement;
-
-  /**
-   * Set the statement that is executed if the condition evaluates to `false`
-   * to the given [statement].
-   */
-  void set elseStatement(Statement statement) {
-    _elseStatement = _becomeParentOf(statement);
-  }
-
-  @override
-  Token get endToken {
-    if (_elseStatement != null) {
-      return _elseStatement.endToken;
-    }
-    return _thenStatement.endToken;
-  }
-
-  /**
-   * Return the statement that is executed if the condition evaluates to `true`.
-   */
-  Statement get thenStatement => _thenStatement;
-
-  /**
-   * Set the statement that is executed if the condition evaluates to `true` to
-   * the given [statement].
-   */
-  void set thenStatement(Statement statement) {
-    _thenStatement = _becomeParentOf(statement);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitIfStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_condition, visitor);
-    _safelyVisitChild(_thenStatement, visitor);
-    _safelyVisitChild(_elseStatement, visitor);
-  }
-}
-
-/**
- * The "implements" clause in an class declaration.
- *
- * > implementsClause ::=
- * >     'implements' [TypeName] (',' [TypeName])*
- */
-class ImplementsClause extends AstNode {
-  /**
-   * The token representing the 'implements' keyword.
-   */
-  Token implementsKeyword;
-
-  /**
-   * The interfaces that are being implemented.
-   */
-  NodeList<TypeName> _interfaces;
-
-  /**
-   * Initialize a newly created implements clause.
-   */
-  ImplementsClause(this.implementsKeyword, List<TypeName> interfaces) {
-    _interfaces = new NodeList<TypeName>(this, interfaces);
-  }
-
-  @override
-  Token get beginToken => implementsKeyword;
-
-  @override
-  // TODO(paulberry): add commas.
-  Iterable get childEntities => new ChildEntities()
-    ..add(implementsKeyword)
-    ..addAll(interfaces);
-
-  @override
-  Token get endToken => _interfaces.endToken;
-
-  /**
-   * Return the list of the interfaces that are being implemented.
-   */
-  NodeList<TypeName> get interfaces => _interfaces;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitImplementsClause(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _interfaces.accept(visitor);
-  }
-}
-
-/**
- * An import directive.
- *
- * > importDirective ::=
- * >     [Annotation] 'import' [StringLiteral] ('as' identifier)? [Combinator]* ';'
- * >   | [Annotation] 'import' [StringLiteral] 'deferred' 'as' identifier [Combinator]* ';'
- */
-class ImportDirective extends NamespaceDirective {
-  static Comparator<ImportDirective> COMPARATOR =
-      (ImportDirective import1, ImportDirective import2) {
-    //
-    // uri
-    //
-    StringLiteral uri1 = import1.uri;
-    StringLiteral uri2 = import2.uri;
-    String uriStr1 = uri1.stringValue;
-    String uriStr2 = uri2.stringValue;
-    if (uriStr1 != null || uriStr2 != null) {
-      if (uriStr1 == null) {
-        return -1;
-      } else if (uriStr2 == null) {
-        return 1;
-      } else {
-        int compare = uriStr1.compareTo(uriStr2);
-        if (compare != 0) {
-          return compare;
-        }
-      }
-    }
-    //
-    // as
-    //
-    SimpleIdentifier prefix1 = import1.prefix;
-    SimpleIdentifier prefix2 = import2.prefix;
-    String prefixStr1 = prefix1 != null ? prefix1.name : null;
-    String prefixStr2 = prefix2 != null ? prefix2.name : null;
-    if (prefixStr1 != null || prefixStr2 != null) {
-      if (prefixStr1 == null) {
-        return -1;
-      } else if (prefixStr2 == null) {
-        return 1;
-      } else {
-        int compare = prefixStr1.compareTo(prefixStr2);
-        if (compare != 0) {
-          return compare;
-        }
-      }
-    }
-    //
-    // hides and shows
-    //
-    NodeList<Combinator> combinators1 = import1.combinators;
-    List<String> allHides1 = new List<String>();
-    List<String> allShows1 = new List<String>();
-    for (Combinator combinator in combinators1) {
-      if (combinator is HideCombinator) {
-        NodeList<SimpleIdentifier> hides = combinator.hiddenNames;
-        for (SimpleIdentifier simpleIdentifier in hides) {
-          allHides1.add(simpleIdentifier.name);
-        }
-      } else {
-        NodeList<SimpleIdentifier> shows =
-            (combinator as ShowCombinator).shownNames;
-        for (SimpleIdentifier simpleIdentifier in shows) {
-          allShows1.add(simpleIdentifier.name);
-        }
-      }
-    }
-    NodeList<Combinator> combinators2 = import2.combinators;
-    List<String> allHides2 = new List<String>();
-    List<String> allShows2 = new List<String>();
-    for (Combinator combinator in combinators2) {
-      if (combinator is HideCombinator) {
-        NodeList<SimpleIdentifier> hides = combinator.hiddenNames;
-        for (SimpleIdentifier simpleIdentifier in hides) {
-          allHides2.add(simpleIdentifier.name);
-        }
-      } else {
-        NodeList<SimpleIdentifier> shows =
-            (combinator as ShowCombinator).shownNames;
-        for (SimpleIdentifier simpleIdentifier in shows) {
-          allShows2.add(simpleIdentifier.name);
-        }
-      }
-    }
-    // test lengths of combinator lists first
-    if (allHides1.length != allHides2.length) {
-      return allHides1.length - allHides2.length;
-    }
-    if (allShows1.length != allShows2.length) {
-      return allShows1.length - allShows2.length;
-    }
-    // next ensure that the lists are equivalent
-    if (!javaCollectionContainsAll(allHides1, allHides2)) {
-      return -1;
-    }
-    if (!javaCollectionContainsAll(allShows1, allShows2)) {
-      return -1;
-    }
-    return 0;
-  };
-
-  /**
-   * The token representing the 'deferred' keyword, or `null` if the imported is
-   * not deferred.
-   */
-  Token deferredKeyword;
-
-  /**
-   * The token representing the 'as' keyword, or `null` if the imported names are
-   * not prefixed.
-   */
-  Token asKeyword;
-
-  /**
-   * The prefix to be used with the imported names, or `null` if the imported
-   * names are not prefixed.
-   */
-  SimpleIdentifier _prefix;
-
-  /**
-   * Initialize a newly created import directive. Either or both of the
-   * [comment] and [metadata] can be `null` if the function does not have the
-   * corresponding attribute. The [deferredKeyword] can be `null` if the import
-   * is not deferred. The [asKeyword] and [prefix] can be `null` if the import
-   * does not specify a prefix. The list of [combinators] can be `null` if there
-   * are no combinators.
-   */
-  ImportDirective(
-      Comment comment,
-      List<Annotation> metadata,
-      Token keyword,
-      StringLiteral libraryUri,
-      List<Configuration> configurations,
-      this.deferredKeyword,
-      this.asKeyword,
-      SimpleIdentifier prefix,
-      List<Combinator> combinators,
-      Token semicolon)
-      : super(comment, metadata, keyword, libraryUri, configurations,
-            combinators, semicolon) {
-    _prefix = _becomeParentOf(prefix);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(_uri)
-    ..add(deferredKeyword)
-    ..add(asKeyword)
-    ..add(_prefix)
-    ..addAll(combinators)
-    ..add(semicolon);
-
-  @override
-  ImportElement get element => super.element as ImportElement;
-
-  /**
-   * Return the prefix to be used with the imported names, or `null` if the
-   * imported names are not prefixed.
-   */
-  SimpleIdentifier get prefix => _prefix;
-
-  /**
-   * Set the prefix to be used with the imported names to the given [identifier].
-   */
-  void set prefix(SimpleIdentifier identifier) {
-    _prefix = _becomeParentOf(identifier);
-  }
-
-  @override
-  LibraryElement get uriElement {
-    ImportElement element = this.element;
-    if (element == null) {
-      return null;
-    }
-    return element.importedLibrary;
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitImportDirective(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_prefix, visitor);
-    combinators.accept(visitor);
-  }
-}
-
-/**
- * An index expression.
- *
- * > indexExpression ::=
- * >     [Expression] '[' [Expression] ']'
- */
-class IndexExpression extends Expression {
-  /**
-   * The expression used to compute the object being indexed, or `null` if this
-   * index expression is part of a cascade expression.
-   */
-  Expression _target;
-
-  /**
-   * The period ("..") before a cascaded index expression, or `null` if this
-   * index expression is not part of a cascade expression.
-   */
-  Token period;
-
-  /**
-   * The left square bracket.
-   */
-  Token leftBracket;
-
-  /**
-   * The expression used to compute the index.
-   */
-  Expression _index;
-
-  /**
-   * The right square bracket.
-   */
-  Token rightBracket;
-
-  /**
-   * The element associated with the operator based on the static type of the
-   * target, or `null` if the AST structure has not been resolved or if the
-   * operator could not be resolved.
-   */
-  MethodElement staticElement;
-
-  /**
-   * The element associated with the operator based on the propagated type of
-   * the target, or `null` if the AST structure has not been resolved or if the
-   * operator could not be resolved.
-   */
-  MethodElement propagatedElement;
-
-  /**
-   * If this expression is both in a getter and setter context, the
-   * [AuxiliaryElements] will be set to hold onto the static and propagated
-   * information. The auxiliary element will hold onto the elements from the
-   * getter context.
-   */
-  AuxiliaryElements auxiliaryElements = null;
-
-  /**
-   * Initialize a newly created index expression.
-   */
-  IndexExpression.forCascade(
-      this.period, this.leftBracket, Expression index, this.rightBracket) {
-    _index = _becomeParentOf(index);
-  }
-
-  /**
-   * Initialize a newly created index expression.
-   */
-  IndexExpression.forTarget(Expression target, this.leftBracket,
-      Expression index, this.rightBracket) {
-    _target = _becomeParentOf(target);
-    _index = _becomeParentOf(index);
-  }
-
-  @override
-  Token get beginToken {
-    if (_target != null) {
-      return _target.beginToken;
-    }
-    return period;
-  }
-
-  /**
-   * Return the best element available for this operator. If resolution was able
-   * to find a better element based on type propagation, that element will be
-   * returned. Otherwise, the element found using the result of static analysis
-   * will be returned. If resolution has not been performed, then `null` will be
-   * returned.
-   */
-  MethodElement get bestElement {
-    MethodElement element = propagatedElement;
-    if (element == null) {
-      element = staticElement;
-    }
-    return element;
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(_target)
-    ..add(period)
-    ..add(leftBracket)
-    ..add(_index)
-    ..add(rightBracket);
-
-  @override
-  Token get endToken => rightBracket;
-
-  /**
-   * Return the expression used to compute the index.
-   */
-  Expression get index => _index;
-
-  /**
-   * Set the expression used to compute the index to the given [expression].
-   */
-  void set index(Expression expression) {
-    _index = _becomeParentOf(expression);
-  }
-
-  @override
-  bool get isAssignable => true;
-
-  /**
-   * Return `true` if this expression is cascaded. If it is, then the target of
-   * this expression is not stored locally but is stored in the nearest ancestor
-   * that is a [CascadeExpression].
-   */
-  bool get isCascaded => period != null;
-
-  @override
-  int get precedence => 15;
-
-  /**
-   * Return the expression used to compute the object being indexed. If this
-   * index expression is not part of a cascade expression, then this is the same
-   * as [target]. If this index expression is part of a cascade expression, then
-   * the target expression stored with the cascade expression is returned.
-   */
-  Expression get realTarget {
-    if (isCascaded) {
-      AstNode ancestor = parent;
-      while (ancestor is! CascadeExpression) {
-        if (ancestor == null) {
-          return _target;
-        }
-        ancestor = ancestor.parent;
-      }
-      return (ancestor as CascadeExpression).target;
-    }
-    return _target;
-  }
-
-  /**
-   * Return the expression used to compute the object being indexed, or `null`
-   * if this index expression is part of a cascade expression.
-   *
-   * Use [realTarget] to get the target independent of whether this is part of a
-   * cascade expression.
-   */
-  Expression get target => _target;
-
-  /**
-   * Set the expression used to compute the object being indexed to the given
-   * [expression].
-   */
-  void set target(Expression expression) {
-    _target = _becomeParentOf(expression);
-  }
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on propagated type information, then return the parameter
-   * element representing the parameter to which the value of the index
-   * expression will be bound. Otherwise, return `null`.
-   */
-  ParameterElement get _propagatedParameterElementForIndex {
-    if (propagatedElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = propagatedElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on static type information, then return the parameter element
-   * representing the parameter to which the value of the index expression will
-   * be bound. Otherwise, return `null`.
-   */
-  ParameterElement get _staticParameterElementForIndex {
-    if (staticElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = staticElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitIndexExpression(this);
-
-  /**
-   * Return `true` if this expression is computing a right-hand value (that is,
-   * if this expression is in a context where the operator '[]' will be
-   * invoked).
-   *
-   * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
-   * are they mutually exclusive. In other words, it is possible for both
-   * methods to return `true` when invoked on the same node.
-   */
-  bool inGetterContext() {
-    // TODO(brianwilkerson) Convert this to a getter.
-    AstNode parent = this.parent;
-    if (parent is AssignmentExpression) {
-      AssignmentExpression assignment = parent;
-      if (identical(assignment.leftHandSide, this) &&
-          assignment.operator.type == TokenType.EQ) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Return `true` if this expression is computing a left-hand value (that is,
-   * if this expression is in a context where the operator '[]=' will be
-   * invoked).
-   *
-   * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
-   * are they mutually exclusive. In other words, it is possible for both
-   * methods to return `true` when invoked on the same node.
-   */
-  bool inSetterContext() {
-    // TODO(brianwilkerson) Convert this to a getter.
-    AstNode parent = this.parent;
-    if (parent is PrefixExpression) {
-      return parent.operator.type.isIncrementOperator;
-    } else if (parent is PostfixExpression) {
-      return true;
-    } else if (parent is AssignmentExpression) {
-      return identical(parent.leftHandSide, this);
-    }
-    return false;
-  }
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_target, visitor);
-    _safelyVisitChild(_index, visitor);
-  }
-}
-
-/**
- * An instance creation expression.
- *
- * > newExpression ::=
- * >     ('new' | 'const') [TypeName] ('.' [SimpleIdentifier])? [ArgumentList]
- */
-class InstanceCreationExpression extends Expression {
-  /**
-   * The 'new' or 'const' keyword used to indicate how an object should be
-   * created.
-   */
-  Token keyword;
-
-  /**
-   * The name of the constructor to be invoked.
-   */
-  ConstructorName _constructorName;
-
-  /**
-   * The list of arguments to the constructor.
-   */
-  ArgumentList _argumentList;
-
-  /**
-   * The element associated with the constructor based on static type
-   * information, or `null` if the AST structure has not been resolved or if the
-   * constructor could not be resolved.
-   */
-  ConstructorElement staticElement;
-
-  /**
-   * Initialize a newly created instance creation expression.
-   */
-  InstanceCreationExpression(this.keyword, ConstructorName constructorName,
-      ArgumentList argumentList) {
-    _constructorName = _becomeParentOf(constructorName);
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  /**
-   * Return the list of arguments to the constructor.
-   */
-  ArgumentList get argumentList => _argumentList;
-
-  /**
-   * Set the list of arguments to the constructor to the given [argumentList].
-   */
-  void set argumentList(ArgumentList argumentList) {
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  @override
-  Token get beginToken => keyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(keyword)
-    ..add(_constructorName)
-    ..add(_argumentList);
-
-  /**
-   * Return the name of the constructor to be invoked.
-   */
-  ConstructorName get constructorName => _constructorName;
-
-  /**
-   * Set the name of the constructor to be invoked to the given [name].
-   */
-  void set constructorName(ConstructorName name) {
-    _constructorName = _becomeParentOf(name);
-  }
-
-  @override
-  Token get endToken => _argumentList.endToken;
-
-  /**
-   * Return `true` if this creation expression is used to invoke a constant
-   * constructor.
-   */
-  bool get isConst =>
-      keyword is KeywordToken &&
-      (keyword as KeywordToken).keyword == Keyword.CONST;
-
-  @override
-  int get precedence => 16;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitInstanceCreationExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_constructorName, visitor);
-    _safelyVisitChild(_argumentList, visitor);
-  }
-}
-
-/**
- * An integer literal expression.
- *
- * > integerLiteral ::=
- * >     decimalIntegerLiteral
- * >   | hexadecimalIntegerLiteral
- * >
- * > decimalIntegerLiteral ::=
- * >     decimalDigit+
- * >
- * > hexadecimalIntegerLiteral ::=
- * >     '0x' hexadecimalDigit+
- * >   | '0X' hexadecimalDigit+
- */
-class IntegerLiteral extends Literal {
-  /**
-   * The token representing the literal.
-   */
-  Token literal;
-
-  /**
-   * The value of the literal.
-   */
-  int value = 0;
-
-  /**
-   * Initialize a newly created integer literal.
-   */
-  IntegerLiteral(this.literal, this.value);
-
-  @override
-  Token get beginToken => literal;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(literal);
-
-  @override
-  Token get endToken => literal;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitIntegerLiteral(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * A node within a [StringInterpolation].
- *
- * > interpolationElement ::=
- * >     [InterpolationExpression]
- * >   | [InterpolationString]
- */
-abstract class InterpolationElement extends AstNode {}
-
-/**
- * An expression embedded in a string interpolation.
- *
- * > interpolationExpression ::=
- * >     '$' [SimpleIdentifier]
- * >   | '$' '{' [Expression] '}'
- */
-class InterpolationExpression extends InterpolationElement {
-  /**
-   * The token used to introduce the interpolation expression; either '$' if the
-   * expression is a simple identifier or '${' if the expression is a full
-   * expression.
-   */
-  Token leftBracket;
-
-  /**
-   * The expression to be evaluated for the value to be converted into a string.
-   */
-  Expression _expression;
-
-  /**
-   * The right curly bracket, or `null` if the expression is an identifier
-   * without brackets.
-   */
-  Token rightBracket;
-
-  /**
-   * Initialize a newly created interpolation expression.
-   */
-  InterpolationExpression(
-      this.leftBracket, Expression expression, this.rightBracket) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken => leftBracket;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(leftBracket)
-    ..add(_expression)
-    ..add(rightBracket);
-
-  @override
-  Token get endToken {
-    if (rightBracket != null) {
-      return rightBracket;
-    }
-    return _expression.endToken;
-  }
-
-  /**
-   * Return the expression to be evaluated for the value to be converted into a
-   * string.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression to be evaluated for the value to be converted into a
-   * string to the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitInterpolationExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * A non-empty substring of an interpolated string.
- *
- * > interpolationString ::=
- * >     characters
- */
-class InterpolationString extends InterpolationElement {
-  /**
-   * The characters that will be added to the string.
-   */
-  Token contents;
-
-  /**
-   * The value of the literal.
-   */
-  String value;
-
-  /**
-   * Initialize a newly created string of characters that are part of a string
-   * interpolation.
-   */
-  InterpolationString(this.contents, this.value);
-
-  @override
-  Token get beginToken => contents;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(contents);
-
-  /**
-   * Return the offset of the after-last contents character.
-   */
-  int get contentsEnd {
-    String lexeme = contents.lexeme;
-    return offset + new StringLexemeHelper(lexeme, true, true).end;
-  }
-
-  /**
-   * Return the offset of the first contents character.
-   */
-  int get contentsOffset {
-    int offset = contents.offset;
-    String lexeme = contents.lexeme;
-    return offset + new StringLexemeHelper(lexeme, true, true).start;
-  }
-
-  @override
-  Token get endToken => contents;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitInterpolationString(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {}
-}
-
-/**
- * An is expression.
- *
- * > isExpression ::=
- * >     [Expression] 'is' '!'? [TypeName]
- */
-class IsExpression extends Expression {
-  /**
-   * The expression used to compute the value whose type is being tested.
-   */
-  Expression _expression;
-
-  /**
-   * The is operator.
-   */
-  Token isOperator;
-
-  /**
-   * The not operator, or `null` if the sense of the test is not negated.
-   */
-  Token notOperator;
-
-  /**
-   * The name of the type being tested for.
-   */
-  TypeName _type;
-
-  /**
-   * Initialize a newly created is expression. The [notOperator] can be `null`
-   * if the sense of the test is not negated.
-   */
-  IsExpression(
-      Expression expression, this.isOperator, this.notOperator, TypeName type) {
-    _expression = _becomeParentOf(expression);
-    _type = _becomeParentOf(type);
-  }
-
-  @override
-  Token get beginToken => _expression.beginToken;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(_expression)
-    ..add(isOperator)
-    ..add(notOperator)
-    ..add(_type);
-
-  @override
-  Token get endToken => _type.endToken;
-
-  /**
-   * Return the expression used to compute the value whose type is being tested.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression used to compute the value whose type is being tested to
-   * the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 7;
-
-  /**
-   * Return the name of the type being tested for.
-   */
-  TypeName get type => _type;
-
-  /**
-   * Set the name of the type being tested for to the given [name].
-   */
-  void set type(TypeName name) {
-    _type = _becomeParentOf(name);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitIsExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-    _safelyVisitChild(_type, visitor);
-  }
-}
-
-/**
- * A label on either a [LabeledStatement] or a [NamedExpression].
- *
- * > label ::=
- * >     [SimpleIdentifier] ':'
- */
-class Label extends AstNode {
-  /**
-   * The label being associated with the statement.
-   */
-  SimpleIdentifier _label;
-
-  /**
-   * The colon that separates the label from the statement.
-   */
-  Token colon;
-
-  /**
-   * Initialize a newly created label.
-   */
-  Label(SimpleIdentifier label, this.colon) {
-    _label = _becomeParentOf(label);
-  }
-
-  @override
-  Token get beginToken => _label.beginToken;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(_label)..add(colon);
-
-  @override
-  Token get endToken => colon;
-
-  /**
-   * Return the label being associated with the statement.
-   */
-  SimpleIdentifier get label => _label;
-
-  /**
-   * Set the label being associated with the statement to the given [label].
-   */
-  void set label(SimpleIdentifier label) {
-    _label = _becomeParentOf(label);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitLabel(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_label, visitor);
-  }
-}
-
-/**
- * A statement that has a label associated with them.
- *
- * > labeledStatement ::=
- * >    [Label]+ [Statement]
- */
-class LabeledStatement extends Statement {
-  /**
-   * The labels being associated with the statement.
-   */
-  NodeList<Label> _labels;
-
-  /**
-   * The statement with which the labels are being associated.
-   */
-  Statement _statement;
-
-  /**
-   * Initialize a newly created labeled statement.
-   */
-  LabeledStatement(List<Label> labels, Statement statement) {
-    _labels = new NodeList<Label>(this, labels);
-    _statement = _becomeParentOf(statement);
-  }
-
-  @override
-  Token get beginToken {
-    if (!_labels.isEmpty) {
-      return _labels.beginToken;
-    }
-    return _statement.beginToken;
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..addAll(_labels)
-    ..add(_statement);
-
-  @override
-  Token get endToken => _statement.endToken;
-
-  /**
-   * Return the labels being associated with the statement.
-   */
-  NodeList<Label> get labels => _labels;
-
-  /**
-   * Return the statement with which the labels are being associated.
-   */
-  Statement get statement => _statement;
-
-  /**
-   * Set the statement with which the labels are being associated to the given
-   * [statement].
-   */
-  void set statement(Statement statement) {
-    _statement = _becomeParentOf(statement);
-  }
-
-  @override
-  Statement get unlabeled => _statement.unlabeled;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitLabeledStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _labels.accept(visitor);
-    _safelyVisitChild(_statement, visitor);
-  }
-}
-
-/**
- * A library directive.
- *
- * > libraryDirective ::=
- * >     [Annotation] 'library' [Identifier] ';'
- */
-class LibraryDirective extends Directive {
-  /**
-   * The token representing the 'library' keyword.
-   */
-  Token libraryKeyword;
-
-  /**
-   * The name of the library being defined.
-   */
-  LibraryIdentifier _name;
-
-  /**
-   * The semicolon terminating the directive.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created library directive. Either or both of the
-   * [comment] and [metadata] can be `null` if the directive does not have the
-   * corresponding attribute.
-   */
-  LibraryDirective(Comment comment, List<Annotation> metadata,
-      this.libraryKeyword, LibraryIdentifier name, this.semicolon)
-      : super(comment, metadata) {
-    _name = _becomeParentOf(name);
-  }
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(libraryKeyword)..add(_name)..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => libraryKeyword;
-
-  @override
-  Token get keyword => libraryKeyword;
-
-  /**
-   * Return the name of the library being defined.
-   */
-  LibraryIdentifier get name => _name;
-
-  /**
-   * Set the name of the library being defined to the given [name].
-   */
-  void set name(LibraryIdentifier name) {
-    _name = _becomeParentOf(name);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitLibraryDirective(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_name, visitor);
-  }
-}
-
-/**
- * The identifier for a library.
- *
- * > libraryIdentifier ::=
- * >     [SimpleIdentifier] ('.' [SimpleIdentifier])*
- */
-class LibraryIdentifier extends Identifier {
-  /**
-   * The components of the identifier.
-   */
-  NodeList<SimpleIdentifier> _components;
-
-  /**
-   * Initialize a newly created prefixed identifier.
-   */
-  LibraryIdentifier(List<SimpleIdentifier> components) {
-    _components = new NodeList<SimpleIdentifier>(this, components);
-  }
-
-  @override
-  Token get beginToken => _components.beginToken;
-
-  @override
-  Element get bestElement => staticElement;
-
-  @override
-  // TODO(paulberry): add "." tokens.
-  Iterable get childEntities => new ChildEntities()..addAll(_components);
-
-  /**
-   * Return the components of the identifier.
-   */
-  NodeList<SimpleIdentifier> get components => _components;
-
-  @override
-  Token get endToken => _components.endToken;
-
-  @override
-  String get name {
-    StringBuffer buffer = new StringBuffer();
-    bool needsPeriod = false;
-    for (SimpleIdentifier identifier in _components) {
-      if (needsPeriod) {
-        buffer.write(".");
-      } else {
-        needsPeriod = true;
-      }
-      buffer.write(identifier.name);
-    }
-    return buffer.toString();
-  }
-
-  @override
-  int get precedence => 15;
-
-  @override
-  Element get propagatedElement => null;
-
-  @override
-  Element get staticElement => null;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitLibraryIdentifier(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _components.accept(visitor);
-  }
-}
-
-/**
- * A list literal.
- *
- * > listLiteral ::=
- * >     'const'? ('<' [TypeName] '>')? '[' ([Expression] ','?)? ']'
- */
-class ListLiteral extends TypedLiteral {
-  /**
-   * The left square bracket.
-   */
-  Token leftBracket;
-
-  /**
-   * The expressions used to compute the elements of the list.
-   */
-  NodeList<Expression> _elements;
-
-  /**
-   * The right square bracket.
-   */
-  Token rightBracket;
-
-  /**
-   * Initialize a newly created list literal. The [constKeyword] can be `null`
-   * if the literal is not a constant. The [typeArguments] can be `null` if no
-   * type arguments were declared. The list of [elements] can be `null` if the
-   * list is empty.
-   */
-  ListLiteral(Token constKeyword, TypeArgumentList typeArguments,
-      this.leftBracket, List<Expression> elements, this.rightBracket)
-      : super(constKeyword, typeArguments) {
-    _elements = new NodeList<Expression>(this, elements);
-  }
-
-  @override
-  Token get beginToken {
-    if (constKeyword != null) {
-      return constKeyword;
-    }
-    TypeArgumentList typeArguments = this.typeArguments;
-    if (typeArguments != null) {
-      return typeArguments.beginToken;
-    }
-    return leftBracket;
-  }
-
-  @override
-  // TODO(paulberry): add commas.
-  Iterable get childEntities => super._childEntities
-    ..add(leftBracket)
-    ..addAll(_elements)
-    ..add(rightBracket);
-
-  /**
-   * Return the expressions used to compute the elements of the list.
-   */
-  NodeList<Expression> get elements => _elements;
-
-  @override
-  Token get endToken => rightBracket;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitListLiteral(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _elements.accept(visitor);
-  }
-}
-
-/**
- * A node that represents a literal expression.
- *
- * > literal ::=
- * >     [BooleanLiteral]
- * >   | [DoubleLiteral]
- * >   | [IntegerLiteral]
- * >   | [ListLiteral]
- * >   | [MapLiteral]
- * >   | [NullLiteral]
- * >   | [StringLiteral]
- */
-abstract class Literal extends Expression {
-  @override
-  int get precedence => 16;
-}
-
-/**
- * A literal map.
- *
- * > mapLiteral ::=
- * >     'const'? ('<' [TypeName] (',' [TypeName])* '>')?
- * >     '{' ([MapLiteralEntry] (',' [MapLiteralEntry])* ','?)? '}'
- */
-class MapLiteral extends TypedLiteral {
-  /**
-   * The left curly bracket.
-   */
-  Token leftBracket;
-
-  /**
-   * The entries in the map.
-   */
-  NodeList<MapLiteralEntry> _entries;
-
-  /**
-   * The right curly bracket.
-   */
-  Token rightBracket;
-
-  /**
-   * Initialize a newly created map literal. The [constKeyword] can be `null` if
-   * the literal is not a constant. The [typeArguments] can be `null` if no type
-   * arguments were declared. The [entries] can be `null` if the map is empty.
-   */
-  MapLiteral(Token constKeyword, TypeArgumentList typeArguments,
-      this.leftBracket, List<MapLiteralEntry> entries, this.rightBracket)
-      : super(constKeyword, typeArguments) {
-    _entries = new NodeList<MapLiteralEntry>(this, entries);
-  }
-
-  @override
-  Token get beginToken {
-    if (constKeyword != null) {
-      return constKeyword;
-    }
-    TypeArgumentList typeArguments = this.typeArguments;
-    if (typeArguments != null) {
-      return typeArguments.beginToken;
-    }
-    return leftBracket;
-  }
-
-  @override
-  // TODO(paulberry): add commas.
-  Iterable get childEntities => super._childEntities
-    ..add(leftBracket)
-    ..addAll(entries)
-    ..add(rightBracket);
-
-  @override
-  Token get endToken => rightBracket;
-
-  /**
-   * Return the entries in the map.
-   */
-  NodeList<MapLiteralEntry> get entries => _entries;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitMapLiteral(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _entries.accept(visitor);
-  }
-}
-
-/**
- * A single key/value pair in a map literal.
- *
- * > mapLiteralEntry ::=
- * >     [Expression] ':' [Expression]
- */
-class MapLiteralEntry extends AstNode {
-  /**
-   * The expression computing the key with which the value will be associated.
-   */
-  Expression _key;
-
-  /**
-   * The colon that separates the key from the value.
-   */
-  Token separator;
-
-  /**
-   * The expression computing the value that will be associated with the key.
-   */
-  Expression _value;
-
-  /**
-   * Initialize a newly created map literal entry.
-   */
-  MapLiteralEntry(Expression key, this.separator, Expression value) {
-    _key = _becomeParentOf(key);
-    _value = _becomeParentOf(value);
-  }
-
-  @override
-  Token get beginToken => _key.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_key)..add(separator)..add(_value);
-
-  @override
-  Token get endToken => _value.endToken;
-
-  /**
-   * Return the expression computing the key with which the value will be
-   * associated.
-   */
-  Expression get key => _key;
-
-  /**
-   * Set the expression computing the key with which the value will be
-   * associated to the given [string].
-   */
-  void set key(Expression string) {
-    _key = _becomeParentOf(string);
-  }
-
-  /**
-   * Return the expression computing the value that will be associated with the
-   * key.
-   */
-  Expression get value => _value;
-
-  /**
-   * Set the expression computing the value that will be associated with the key
-   * to the given [expression].
-   */
-  void set value(Expression expression) {
-    _value = _becomeParentOf(expression);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitMapLiteralEntry(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_key, visitor);
-    _safelyVisitChild(_value, visitor);
-  }
-}
-
-/**
- * A method declaration.
- *
- * > methodDeclaration ::=
- * >     methodSignature [FunctionBody]
- * >
- * > methodSignature ::=
- * >     'external'? ('abstract' | 'static')? [Type]? ('get' | 'set')?
- * >     methodName [TypeParameterList] [FormalParameterList]
- * >
- * > methodName ::=
- * >     [SimpleIdentifier]
- * >   | 'operator' [SimpleIdentifier]
- */
-class MethodDeclaration extends ClassMember {
-  /**
-   * The token for the 'external' keyword, or `null` if the constructor is not
-   * external.
-   */
-  Token externalKeyword;
-
-  /**
-   * The token representing the 'abstract' or 'static' keyword, or `null` if
-   * neither modifier was specified.
-   */
-  Token modifierKeyword;
-
-  /**
-   * The return type of the method, or `null` if no return type was declared.
-   */
-  TypeName _returnType;
-
-  /**
-   * The token representing the 'get' or 'set' keyword, or `null` if this is a
-   * method declaration rather than a property declaration.
-   */
-  Token propertyKeyword;
-
-  /**
-   * The token representing the 'operator' keyword, or `null` if this method
-   * does not declare an operator.
-   */
-  Token operatorKeyword;
-
-  /**
-   * The name of the method.
-   */
-  SimpleIdentifier _name;
-
-  /**
-   * The type parameters associated with the method, or `null` if the method is
-   * not a generic method.
-   */
-  TypeParameterList _typeParameters;
-
-  /**
-   * The parameters associated with the method, or `null` if this method
-   * declares a getter.
-   */
-  FormalParameterList _parameters;
-
-  /**
-   * The body of the method.
-   */
-  FunctionBody _body;
-
-  /**
-   * Initialize a newly created method declaration. Either or both of the
-   * [comment] and [metadata] can be `null` if the declaration does not have the
-   * corresponding attribute. The [externalKeyword] can be `null` if the method
-   * is not external. The [modifierKeyword] can be `null` if the method is
-   * neither abstract nor static. The [returnType] can be `null` if no return
-   * type was specified. The [propertyKeyword] can be `null` if the method is
-   * neither a getter or a setter. The [operatorKeyword] can be `null` if the
-   * method does not implement an operator. The [parameters] must be `null` if
-   * this method declares a getter.
-   */
-  MethodDeclaration(
-      Comment comment,
-      List<Annotation> metadata,
-      this.externalKeyword,
-      this.modifierKeyword,
-      TypeName returnType,
-      this.propertyKeyword,
-      this.operatorKeyword,
-      SimpleIdentifier name,
-      TypeParameterList typeParameters,
-      FormalParameterList parameters,
-      FunctionBody body)
-      : super(comment, metadata) {
-    _returnType = _becomeParentOf(returnType);
-    _name = _becomeParentOf(name);
-    _typeParameters = _becomeParentOf(typeParameters);
-    _parameters = _becomeParentOf(parameters);
-    _body = _becomeParentOf(body);
-  }
-
-  /**
-   * Return the body of the method.
-   */
-  FunctionBody get body => _body;
-
-  /**
-   * Set the body of the method to the given [functionBody].
-   */
-  void set body(FunctionBody functionBody) {
-    _body = _becomeParentOf(functionBody);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(externalKeyword)
-    ..add(modifierKeyword)
-    ..add(_returnType)
-    ..add(propertyKeyword)
-    ..add(operatorKeyword)
-    ..add(_name)
-    ..add(_parameters)
-    ..add(_body);
-
-  /**
-   * Return the element associated with this method, or `null` if the AST
-   * structure has not been resolved. The element can either be a
-   * [MethodElement], if this represents the declaration of a normal method, or
-   * a [PropertyAccessorElement] if this represents the declaration of either a
-   * getter or a setter.
-   */
-  @override
-  ExecutableElement get element =>
-      _name != null ? (_name.staticElement as ExecutableElement) : null;
-
-  @override
-  Token get endToken => _body.endToken;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata {
-    if (modifierKeyword != null) {
-      return modifierKeyword;
-    } else if (_returnType != null) {
-      return _returnType.beginToken;
-    } else if (propertyKeyword != null) {
-      return propertyKeyword;
-    } else if (operatorKeyword != null) {
-      return operatorKeyword;
-    }
-    return _name.beginToken;
-  }
-
-  /**
-   * Return `true` if this method is declared to be an abstract method.
-   */
-  bool get isAbstract {
-    FunctionBody body = _body;
-    return externalKeyword == null &&
-        (body is EmptyFunctionBody && !body.semicolon.isSynthetic);
-  }
-
-  /**
-   * Return `true` if this method declares a getter.
-   */
-  bool get isGetter =>
-      propertyKeyword != null &&
-      (propertyKeyword as KeywordToken).keyword == Keyword.GET;
-
-  /**
-   * Return `true` if this method declares an operator.
-   */
-  bool get isOperator => operatorKeyword != null;
-
-  /**
-   * Return `true` if this method declares a setter.
-   */
-  bool get isSetter =>
-      propertyKeyword != null &&
-      (propertyKeyword as KeywordToken).keyword == Keyword.SET;
-
-  /**
-   * Return `true` if this method is declared to be a static method.
-   */
-  bool get isStatic =>
-      modifierKeyword != null &&
-      (modifierKeyword as KeywordToken).keyword == Keyword.STATIC;
-
-  /**
-   * Return the name of the method.
-   */
-  SimpleIdentifier get name => _name;
-
-  /**
-   * Set the name of the method to the given [identifier].
-   */
-  void set name(SimpleIdentifier identifier) {
-    _name = _becomeParentOf(identifier);
-  }
-
-  /**
-   * Return the parameters associated with the method, or `null` if this method
-   * declares a getter.
-   */
-  FormalParameterList get parameters => _parameters;
-
-  /**
-   * Set the parameters associated with the method to the given list of
-   * [parameters].
-   */
-  void set parameters(FormalParameterList parameters) {
-    _parameters = _becomeParentOf(parameters);
-  }
-
-  /**
-   * Return the return type of the method, or `null` if no return type was
-   * declared.
-   */
-  TypeName get returnType => _returnType;
-
-  /**
-   * Set the return type of the method to the given [typeName].
-   */
-  void set returnType(TypeName typeName) {
-    _returnType = _becomeParentOf(typeName);
-  }
-
-  /**
-   * Return the type parameters associated with this method, or `null` if this
-   * method is not a generic method.
-   */
-  TypeParameterList get typeParameters => _typeParameters;
-
-  /**
-   * Set the type parameters associated with this method to the given
-   * [typeParameters].
-   */
-  void set typeParameters(TypeParameterList typeParameters) {
-    _typeParameters = _becomeParentOf(typeParameters);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitMethodDeclaration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_returnType, visitor);
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_typeParameters, visitor);
-    _safelyVisitChild(_parameters, visitor);
-    _safelyVisitChild(_body, visitor);
-  }
-}
-
-/**
- * The invocation of either a function or a method. Invocations of functions
- * resulting from evaluating an expression are represented by
- * [FunctionExpressionInvocation] nodes. Invocations of getters and setters are
- * represented by either [PrefixedIdentifier] or [PropertyAccess] nodes.
- *
- * > methodInvocation ::=
- * >     ([Expression] '.')? [SimpleIdentifier] [TypeArgumentList]? [ArgumentList]
- */
-class MethodInvocation extends Expression {
-  /**
-   * The expression producing the object on which the method is defined, or
-   * `null` if there is no target (that is, the target is implicitly `this`).
-   */
-  Expression _target;
-
-  /**
-   * The operator that separates the target from the method name, or `null`
-   * if there is no target. In an ordinary method invocation this will be a
-   * period ('.'). In a cascade section this will be the cascade operator
-   * ('..').
-   */
-  Token operator;
-
-  /**
-   * The name of the method being invoked.
-   */
-  SimpleIdentifier _methodName;
-
-  /**
-   * The type arguments to be applied to the method being invoked, or `null` if
-   * no type arguments were provided.
-   */
-  TypeArgumentList _typeArguments;
-
-  /**
-   * The list of arguments to the method.
-   */
-  ArgumentList _argumentList;
-
-  /**
-   * The function type of the method invocation, or `null` if the AST
-   * structure has not been resolved, or if the invoke could not be resolved.
-   *
-   * This will usually be a [FunctionType], but it can also be an
-   * [InterfaceType] with a `call` method, `dynamic`, `Function`, or a `@proxy`
-   * interface type that implements `Function`.
-   */
-  DartType staticInvokeType;
-
-  /**
-   * Like [staticInvokeType], but reflects propagated type information.
-   */
-  DartType propagatedInvokeType;
-
-  /**
-   * Initialize a newly created method invocation. The [target] and [operator]
-   * can be `null` if there is no target.
-   */
-  MethodInvocation(
-      Expression target,
-      this.operator,
-      SimpleIdentifier methodName,
-      TypeArgumentList typeArguments,
-      ArgumentList argumentList) {
-    _target = _becomeParentOf(target);
-    _methodName = _becomeParentOf(methodName);
-    _typeArguments = _becomeParentOf(typeArguments);
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  /**
-   * Return the list of arguments to the method.
-   */
-  ArgumentList get argumentList => _argumentList;
-
-  /**
-   * Set the list of arguments to the method to the given [argumentList].
-   */
-  void set argumentList(ArgumentList argumentList) {
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  @override
-  Token get beginToken {
-    if (_target != null) {
-      return _target.beginToken;
-    } else if (operator != null) {
-      return operator;
-    }
-    return _methodName.beginToken;
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(_target)
-    ..add(operator)
-    ..add(_methodName)
-    ..add(_argumentList);
-
-  @override
-  Token get endToken => _argumentList.endToken;
-
-  /**
-   * Return `true` if this expression is cascaded. If it is, then the target of
-   * this expression is not stored locally but is stored in the nearest ancestor
-   * that is a [CascadeExpression].
-   */
-  bool get isCascaded =>
-      operator != null && operator.type == TokenType.PERIOD_PERIOD;
-
-  /**
-   * Return the name of the method being invoked.
-   */
-  SimpleIdentifier get methodName => _methodName;
-
-  /**
-   * Set the name of the method being invoked to the given [identifier].
-   */
-  void set methodName(SimpleIdentifier identifier) {
-    _methodName = _becomeParentOf(identifier);
-  }
-
-  @override
-  int get precedence => 15;
-
-  /**
-   * Return the expression used to compute the receiver of the invocation. If
-   * this invocation is not part of a cascade expression, then this is the same
-   * as [target]. If this invocation is part of a cascade expression, then the
-   * target stored with the cascade expression is returned.
-   */
-  Expression get realTarget {
-    if (isCascaded) {
-      AstNode ancestor = parent;
-      while (ancestor is! CascadeExpression) {
-        if (ancestor == null) {
-          return _target;
-        }
-        ancestor = ancestor.parent;
-      }
-      return (ancestor as CascadeExpression).target;
-    }
-    return _target;
-  }
-
-  /**
-   * Return the expression producing the object on which the method is defined,
-   * or `null` if there is no target (that is, the target is implicitly `this`)
-   * or if this method invocation is part of a cascade expression.
-   *
-   * Use [realTarget] to get the target independent of whether this is part of a
-   * cascade expression.
-   */
-  Expression get target => _target;
-
-  /**
-   * Set the expression producing the object on which the method is defined to
-   * the given [expression].
-   */
-  void set target(Expression expression) {
-    _target = _becomeParentOf(expression);
-  }
-
-  /**
-   * Return the type arguments to be applied to the method being invoked, or
-   * `null` if no type arguments were provided.
-   */
-  TypeArgumentList get typeArguments => _typeArguments;
-
-  /**
-   * Set the type arguments to be applied to the method being invoked to the
-   * given [typeArguments].
-   */
-  void set typeArguments(TypeArgumentList typeArguments) {
-    _typeArguments = _becomeParentOf(typeArguments);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitMethodInvocation(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_target, visitor);
-    _safelyVisitChild(_methodName, visitor);
-    _safelyVisitChild(_typeArguments, visitor);
-    _safelyVisitChild(_argumentList, visitor);
-  }
-}
-
-/**
- * A node that declares a single name within the scope of a compilation unit.
- */
-abstract class NamedCompilationUnitMember extends CompilationUnitMember {
-  /**
-   * The name of the member being declared.
-   */
-  SimpleIdentifier _name;
-
-  /**
-   * Initialize a newly created compilation unit member with the given [name].
-   * Either or both of the [comment] and [metadata] can be `null` if the member
-   * does not have the corresponding attribute.
-   */
-  NamedCompilationUnitMember(
-      Comment comment, List<Annotation> metadata, SimpleIdentifier name)
-      : super(comment, metadata) {
-    _name = _becomeParentOf(name);
-  }
-
-  /**
-   * Return the name of the member being declared.
-   */
-  SimpleIdentifier get name => _name;
-
-  /**
-   * Set the name of the member being declared to the given [identifier].
-   */
-  void set name(SimpleIdentifier identifier) {
-    _name = _becomeParentOf(identifier);
-  }
-}
-
-/**
- * An expression that has a name associated with it. They are used in method
- * invocations when there are named parameters.
- *
- * > namedExpression ::=
- * >     [Label] [Expression]
- */
-class NamedExpression extends Expression {
-  /**
-   * The name associated with the expression.
-   */
-  Label _name;
-
-  /**
-   * The expression with which the name is associated.
-   */
-  Expression _expression;
-
-  /**
-   * Initialize a newly created named expression..
-   */
-  NamedExpression(Label name, Expression expression) {
-    _name = _becomeParentOf(name);
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken => _name.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_name)..add(_expression);
-
-  /**
-   * Return the element representing the parameter being named by this
-   * expression, or `null` if the AST structure has not been resolved or if
-   * there is no parameter with the same name as this expression.
-   */
-  ParameterElement get element {
-    Element element = _name.label.staticElement;
-    if (element is ParameterElement) {
-      return element;
-    }
-    return null;
-  }
-
-  @override
-  Token get endToken => _expression.endToken;
-
-  /**
-   * Return the expression with which the name is associated.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression with which the name is associated to the given
-   * [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  /**
-   * Return the name associated with the expression.
-   */
-  Label get name => _name;
-
-  /**
-   * Set the name associated with the expression to the given [identifier].
-   */
-  void set name(Label identifier) {
-    _name = _becomeParentOf(identifier);
-  }
-
-  @override
-  int get precedence => 0;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitNamedExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * A node that represents a directive that impacts the namespace of a library.
- *
- * > directive ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
- */
-abstract class NamespaceDirective extends UriBasedDirective {
-  /**
-   * The token representing the 'import' or 'export' keyword.
-   */
-  Token keyword;
-
-  /**
-   * The configurations used to control which library will actually be loaded at
-   * run-time.
-   */
-  NodeList<Configuration> _configurations;
-
-  /**
-   * The combinators used to control which names are imported or exported.
-   */
-  NodeList<Combinator> _combinators;
-
-  /**
-   * The semicolon terminating the directive.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created namespace directive. Either or both of the
-   * [comment] and [metadata] can be `null` if the directive does not have the
-   * corresponding attribute. The list of [combinators] can be `null` if there
-   * are no combinators.
-   */
-  NamespaceDirective(
-      Comment comment,
-      List<Annotation> metadata,
-      this.keyword,
-      StringLiteral libraryUri,
-      List<Configuration> configurations,
-      List<Combinator> combinators,
-      this.semicolon)
-      : super(comment, metadata, libraryUri) {
-    _configurations = new NodeList<Configuration>(this, configurations);
-    _combinators = new NodeList<Combinator>(this, combinators);
-  }
-
-  /**
-   * Return the combinators used to control how names are imported or exported.
-   */
-  NodeList<Combinator> get combinators => _combinators;
-
-  /**
-   * Return the configurations used to control which library will actually be
-   * loaded at run-time.
-   */
-  NodeList<Configuration> get configurations => _configurations;
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => keyword;
-
-  @override
-  LibraryElement get uriElement;
-}
-
-/**
- * The "native" clause in an class declaration.
- *
- * > nativeClause ::=
- * >     'native' [StringLiteral]
- */
-class NativeClause extends AstNode {
-  /**
-   * The token representing the 'native' keyword.
-   */
-  Token nativeKeyword;
-
-  /**
-   * The name of the native object that implements the class.
-   */
-  StringLiteral _name;
-
-  /**
-   * Initialize a newly created native clause.
-   */
-  NativeClause(this.nativeKeyword, StringLiteral name) {
-    _name = _becomeParentOf(name);
-  }
-
-  @override
-  Token get beginToken => nativeKeyword;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(nativeKeyword)..add(_name);
-
-  @override
-  Token get endToken => _name.endToken;
-
-  /**
-   * Return the name of the native object that implements the class.
-   */
-  StringLiteral get name => _name;
-
-  /**
-   * Set the name of the native object that implements the class to the given
-   * [name].
-   */
-  void set name(StringLiteral name) {
-    _name = _becomeParentOf(name);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitNativeClause(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_name, visitor);
-  }
-}
-
-/**
- * A function body that consists of a native keyword followed by a string
- * literal.
- *
- * > nativeFunctionBody ::=
- * >     'native' [SimpleStringLiteral] ';'
- */
-class NativeFunctionBody extends FunctionBody {
-  /**
-   * The token representing 'native' that marks the start of the function body.
-   */
-  Token nativeKeyword;
-
-  /**
-   * The string literal, after the 'native' token.
-   */
-  StringLiteral _stringLiteral;
-
-  /**
-   * The token representing the semicolon that marks the end of the function
-   * body.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created function body consisting of the 'native' token,
-   * a string literal, and a semicolon.
-   */
-  NativeFunctionBody(
-      this.nativeKeyword, StringLiteral stringLiteral, this.semicolon) {
-    _stringLiteral = _becomeParentOf(stringLiteral);
-  }
-
-  @override
-  Token get beginToken => nativeKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(nativeKeyword)
-    ..add(_stringLiteral)
-    ..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  /**
-   * Return the string literal representing the string after the 'native' token.
-   */
-  StringLiteral get stringLiteral => _stringLiteral;
-
-  /**
-   * Set the string literal representing the string after the 'native' token to
-   * the given [stringLiteral].
-   */
-  void set stringLiteral(StringLiteral stringLiteral) {
-    _stringLiteral = _becomeParentOf(stringLiteral);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitNativeFunctionBody(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_stringLiteral, visitor);
-  }
-}
-
-/**
- * A list of AST nodes that have a common parent.
- */
-class NodeList<E extends AstNode> extends Object with ListMixin<E> {
-  /**
-   * The node that is the parent of each of the elements in the list.
-   */
-  AstNode owner;
-
-  /**
-   * The elements contained in the list.
-   */
-  List<E> _elements = <E>[];
-
-  /**
-   * Initialize a newly created list of nodes such that all of the nodes that
-   * are added to the list will have their parent set to the given [owner]. The
-   * list will initially be populated with the given [elements].
-   */
-  NodeList(this.owner, [List<E> elements]) {
-    addAll(elements);
-  }
-
-  /**
-   * Return the first token included in this node list's source range, or `null`
-   * if the list is empty.
-   */
-  Token get beginToken {
-    if (_elements.length == 0) {
-      return null;
-    }
-    return _elements[0].beginToken;
-  }
-
-  /**
-   * Return the last token included in this node list's source range, or `null`
-   * if the list is empty.
-   */
-  Token get endToken {
-    int length = _elements.length;
-    if (length == 0) {
-      return null;
-    }
-    return _elements[length - 1].endToken;
-  }
-
-  int get length => _elements.length;
-
-  @deprecated // Never intended for public use.
-  @override
-  void set length(int newLength) {
-    throw new UnsupportedError("Cannot resize NodeList.");
-  }
-
-  E operator [](int index) {
-    if (index < 0 || index >= _elements.length) {
-      throw new RangeError("Index: $index, Size: ${_elements.length}");
-    }
-    return _elements[index];
-  }
-
-  void operator []=(int index, E node) {
-    if (index < 0 || index >= _elements.length) {
-      throw new RangeError("Index: $index, Size: ${_elements.length}");
-    }
-    owner._becomeParentOf(node);
-    _elements[index] = node;
-  }
-
-  /**
-   * Use the given [visitor] to visit each of the nodes in this list.
-   */
-  accept(AstVisitor visitor) {
-    int length = _elements.length;
-    for (var i = 0; i < length; i++) {
-      _elements[i].accept(visitor);
-    }
-  }
-
-  @override
-  void add(E node) {
-    insert(length, node);
-  }
-
-  @override
-  bool addAll(Iterable<E> nodes) {
-    if (nodes != null && !nodes.isEmpty) {
-      _elements.addAll(nodes);
-      for (E node in nodes) {
-        owner._becomeParentOf(node);
-      }
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  void clear() {
-    _elements = <E>[];
-  }
-
-  @override
-  void insert(int index, E node) {
-    int length = _elements.length;
-    if (index < 0 || index > length) {
-      throw new RangeError("Index: $index, Size: ${_elements.length}");
-    }
-    owner._becomeParentOf(node);
-    if (length == 0) {
-      _elements.add(node);
-    } else {
-      _elements.insert(index, node);
-    }
-  }
-
-  @override
-  E removeAt(int index) {
-    if (index < 0 || index >= _elements.length) {
-      throw new RangeError("Index: $index, Size: ${_elements.length}");
-    }
-    E removedNode = _elements[index];
-    _elements.removeAt(index);
-    return removedNode;
-  }
-}
-
-/**
- * A formal parameter that is required (is not optional).
- *
- * > normalFormalParameter ::=
- * >     [FunctionTypedFormalParameter]
- * >   | [FieldFormalParameter]
- * >   | [SimpleFormalParameter]
- */
-abstract class NormalFormalParameter extends FormalParameter {
-  /**
-   * The documentation comment associated with this parameter, or `null` if this
-   * parameter does not have a documentation comment associated with it.
-   */
-  Comment _comment;
-
-  /**
-   * The annotations associated with this parameter.
-   */
-  NodeList<Annotation> _metadata;
-
-  /**
-   * The name of the parameter being declared.
-   */
-  SimpleIdentifier _identifier;
-
-  /**
-   * Initialize a newly created formal parameter. Either or both of the
-   * [comment] and [metadata] can be `null` if the parameter does not have the
-   * corresponding attribute.
-   */
-  NormalFormalParameter(
-      Comment comment, List<Annotation> metadata, SimpleIdentifier identifier) {
-    _comment = _becomeParentOf(comment);
-    _metadata = new NodeList<Annotation>(this, metadata);
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  /**
-   * Return the documentation comment associated with this parameter, or `null`
-   * if this parameter does not have a documentation comment associated with it.
-   */
-  Comment get documentationComment => _comment;
-
-  /**
-   * Set the documentation comment associated with this parameter to the given
-   * [comment].
-   */
-  void set documentationComment(Comment comment) {
-    _comment = _becomeParentOf(comment);
-  }
-
-  @override
-  SimpleIdentifier get identifier => _identifier;
-
-  /**
-   * Set the name of the parameter being declared to the given [identifier].
-   */
-  void set identifier(SimpleIdentifier identifier) {
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  @override
-  ParameterKind get kind {
-    AstNode parent = this.parent;
-    if (parent is DefaultFormalParameter) {
-      return parent.kind;
-    }
-    return ParameterKind.REQUIRED;
-  }
-
-  @override
-  NodeList<Annotation> get metadata => _metadata;
-
-  /**
-   * Set the metadata associated with this node to the given [metadata].
-   */
-  void set metadata(List<Annotation> metadata) {
-    _metadata.clear();
-    _metadata.addAll(metadata);
-  }
-
-  /**
-   * Return a list containing the comment and annotations associated with this
-   * parameter, sorted in lexical order.
-   */
-  List<AstNode> get sortedCommentAndAnnotations {
-    return <AstNode>[]
-      ..add(_comment)
-      ..addAll(_metadata)
-      ..sort(AstNode.LEXICAL_ORDER);
-  }
-
-  ChildEntities get _childEntities {
-    ChildEntities result = new ChildEntities();
-    if (_commentIsBeforeAnnotations()) {
-      result
-        ..add(_comment)
-        ..addAll(_metadata);
-    } else {
-      result.addAll(sortedCommentAndAnnotations);
-    }
-    return result;
-  }
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    //
-    // Note that subclasses are responsible for visiting the identifier because
-    // they often need to visit other nodes before visiting the identifier.
-    //
-    if (_commentIsBeforeAnnotations()) {
-      _safelyVisitChild(_comment, visitor);
-      _metadata.accept(visitor);
-    } else {
-      for (AstNode child in sortedCommentAndAnnotations) {
-        child.accept(visitor);
-      }
-    }
-  }
-
-  /**
-   * Return `true` if the comment is lexically before any annotations.
-   */
-  bool _commentIsBeforeAnnotations() {
-    if (_comment == null || _metadata.isEmpty) {
-      return true;
-    }
-    Annotation firstAnnotation = _metadata[0];
-    return _comment.offset < firstAnnotation.offset;
-  }
-}
-
-/**
- * A null literal expression.
- *
- * > nullLiteral ::=
- * >     'null'
- */
-class NullLiteral extends Literal {
-  /**
-   * The token representing the literal.
-   */
-  Token literal;
-
-  /**
-   * Initialize a newly created null literal.
-   */
-  NullLiteral(this.literal);
-
-  @override
-  Token get beginToken => literal;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(literal);
-
-  @override
-  Token get endToken => literal;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitNullLiteral(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * A parenthesized expression.
- *
- * > parenthesizedExpression ::=
- * >     '(' [Expression] ')'
- */
-class ParenthesizedExpression extends Expression {
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The expression within the parentheses.
-   */
-  Expression _expression;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * Initialize a newly created parenthesized expression.
-   */
-  ParenthesizedExpression(
-      this.leftParenthesis, Expression expression, this.rightParenthesis) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken => leftParenthesis;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(leftParenthesis)
-    ..add(_expression)
-    ..add(rightParenthesis);
-
-  @override
-  Token get endToken => rightParenthesis;
-
-  /**
-   * Return the expression within the parentheses.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression within the parentheses to the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 15;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitParenthesizedExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * A part directive.
- *
- * > partDirective ::=
- * >     [Annotation] 'part' [StringLiteral] ';'
- */
-class PartDirective extends UriBasedDirective {
-  /**
-   * The token representing the 'part' keyword.
-   */
-  Token partKeyword;
-
-  /**
-   * The semicolon terminating the directive.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created part directive. Either or both of the [comment]
-   * and [metadata] can be `null` if the directive does not have the
-   * corresponding attribute.
-   */
-  PartDirective(Comment comment, List<Annotation> metadata, this.partKeyword,
-      StringLiteral partUri, this.semicolon)
-      : super(comment, metadata, partUri);
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(partKeyword)..add(_uri)..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => partKeyword;
-
-  @override
-  Token get keyword => partKeyword;
-
-  @override
-  CompilationUnitElement get uriElement => element as CompilationUnitElement;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitPartDirective(this);
-}
-
-/**
- * A part-of directive.
- *
- * > partOfDirective ::=
- * >     [Annotation] 'part' 'of' [Identifier] ';'
- */
-class PartOfDirective extends Directive {
-  /**
-   * The token representing the 'part' keyword.
-   */
-  Token partKeyword;
-
-  /**
-   * The token representing the 'of' keyword.
-   */
-  Token ofKeyword;
-
-  /**
-   * The name of the library that the containing compilation unit is part of.
-   */
-  LibraryIdentifier _libraryName;
-
-  /**
-   * The semicolon terminating the directive.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created part-of directive. Either or both of the
-   * [comment] and [metadata] can be `null` if the directive does not have the
-   * corresponding attribute.
-   */
-  PartOfDirective(Comment comment, List<Annotation> metadata, this.partKeyword,
-      this.ofKeyword, LibraryIdentifier libraryName, this.semicolon)
-      : super(comment, metadata) {
-    _libraryName = _becomeParentOf(libraryName);
-  }
-
-  @override
-  Iterable get childEntities => super._childEntities
-    ..add(partKeyword)
-    ..add(ofKeyword)
-    ..add(_libraryName)
-    ..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => partKeyword;
-
-  @override
-  Token get keyword => partKeyword;
-
-  /**
-   * Return the name of the library that the containing compilation unit is part
-   * of.
-   */
-  LibraryIdentifier get libraryName => _libraryName;
-
-  /**
-   * Set the name of the library that the containing compilation unit is part of
-   * to the given [libraryName].
-   */
-  void set libraryName(LibraryIdentifier libraryName) {
-    _libraryName = _becomeParentOf(libraryName);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitPartOfDirective(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_libraryName, visitor);
-  }
-}
-
-/**
- * A postfix unary expression.
- *
- * > postfixExpression ::=
- * >     [Expression] [Token]
- */
-class PostfixExpression extends Expression {
-  /**
-   * The expression computing the operand for the operator.
-   */
-  Expression _operand;
-
-  /**
-   * The postfix operator being applied to the operand.
-   */
-  Token operator;
-
-  /**
-   * The element associated with this the operator based on the propagated type
-   * of the 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.
-   */
-  MethodElement propagatedElement;
-
-  /**
-   * The element associated with the operator based on the static type of the
-   * 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.
-   */
-  MethodElement staticElement;
-
-  /**
-   * Initialize a newly created postfix expression.
-   */
-  PostfixExpression(Expression operand, this.operator) {
-    _operand = _becomeParentOf(operand);
-  }
-
-  @override
-  Token get beginToken => _operand.beginToken;
-
-  /**
-   * Return the best element available for this operator. If resolution was able
-   * to find a better element based on type propagation, that element will be
-   * returned. Otherwise, the element found using the result of static analysis
-   * will be returned. If resolution has not been performed, then `null` will be
-   * returned.
-   */
-  MethodElement get bestElement {
-    MethodElement element = propagatedElement;
-    if (element == null) {
-      element = staticElement;
-    }
-    return element;
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_operand)..add(operator);
-
-  @override
-  Token get endToken => operator;
-
-  /**
-   * Return the expression computing the operand for the operator.
-   */
-  Expression get operand => _operand;
-
-  /**
-   * Set the expression computing the operand for the operator to the given
-   * [expression].
-   */
-  void set operand(Expression expression) {
-    _operand = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 15;
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on propagated type information, then return the parameter
-   * element representing the parameter to which the value of the operand will
-   * be bound. Otherwise, return `null`.
-   */
-  ParameterElement get _propagatedParameterElementForOperand {
-    if (propagatedElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = propagatedElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on static type information, then return the parameter element
-   * representing the parameter to which the value of the operand will be bound.
-   * Otherwise, return `null`.
-   */
-  ParameterElement get _staticParameterElementForOperand {
-    if (staticElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = staticElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitPostfixExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_operand, visitor);
-  }
-}
-
-/**
- * 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]
- */
-class PrefixedIdentifier extends Identifier {
-  /**
-   * The prefix associated with the library in which the identifier is defined.
-   */
-  SimpleIdentifier _prefix;
-
-  /**
-   * The period used to separate the prefix from the identifier.
-   */
-  Token period;
-
-  /**
-   * The identifier being prefixed.
-   */
-  SimpleIdentifier _identifier;
-
-  /**
-   * Initialize a newly created prefixed identifier.
-   */
-  PrefixedIdentifier(
-      SimpleIdentifier prefix, this.period, SimpleIdentifier identifier) {
-    _prefix = _becomeParentOf(prefix);
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  @override
-  Token get beginToken => _prefix.beginToken;
-
-  @override
-  Element get bestElement {
-    if (_identifier == null) {
-      return null;
-    }
-    return _identifier.bestElement;
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_prefix)..add(period)..add(_identifier);
-
-  @override
-  Token get endToken => _identifier.endToken;
-
-  /**
-   * Return the identifier being prefixed.
-   */
-  SimpleIdentifier get identifier => _identifier;
-
-  /**
-   * Set the identifier being prefixed to the given [identifier].
-   */
-  void set identifier(SimpleIdentifier identifier) {
-    _identifier = _becomeParentOf(identifier);
-  }
-
-  /**
-   * Return `true` if this type is a deferred type. If the AST structure has not
-   * been resolved, then return `false`.
-   *
-   * 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
-   * </i>p.T</i> where <i>p</i> is a deferred prefix.
-   */
-  bool get isDeferred {
-    Element element = _prefix.staticElement;
-    if (element is! PrefixElement) {
-      return false;
-    }
-    PrefixElement prefixElement = element as PrefixElement;
-    List<ImportElement> imports =
-        prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
-    if (imports.length != 1) {
-      return false;
-    }
-    return imports[0].isDeferred;
-  }
-
-  @override
-  String get name => "${_prefix.name}.${_identifier.name}";
-
-  @override
-  int get precedence => 15;
-
-  /**
-   * Return the prefix associated with the library in which the identifier is
-   * defined.
-   */
-  SimpleIdentifier get prefix => _prefix;
-
-  /**
-   * Set the prefix associated with the library in which the identifier is
-   * defined to the given [identifier].
-   */
-  void set prefix(SimpleIdentifier identifier) {
-    _prefix = _becomeParentOf(identifier);
-  }
-
-  @override
-  Element get propagatedElement {
-    if (_identifier == null) {
-      return null;
-    }
-    return _identifier.propagatedElement;
-  }
-
-  @override
-  Element get staticElement {
-    if (_identifier == null) {
-      return null;
-    }
-    return _identifier.staticElement;
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitPrefixedIdentifier(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_prefix, visitor);
-    _safelyVisitChild(_identifier, visitor);
-  }
-}
-
-/**
- * A prefix unary expression.
- *
- * > prefixExpression ::=
- * >     [Token] [Expression]
- */
-class PrefixExpression extends Expression {
-  /**
-   * The prefix operator being applied to the operand.
-   */
-  Token operator;
-
-  /**
-   * The expression computing the operand for the operator.
-   */
-  Expression _operand;
-
-  /**
-   * The element associated with the operator based on the static type of the
-   * 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.
-   */
-  MethodElement staticElement;
-
-  /**
-   * The element associated with the operator based on the propagated type of
-   * the 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.
-   */
-  MethodElement propagatedElement;
-
-  /**
-   * Initialize a newly created prefix expression.
-   */
-  PrefixExpression(this.operator, Expression operand) {
-    _operand = _becomeParentOf(operand);
-  }
-
-  @override
-  Token get beginToken => operator;
-
-  /**
-   * Return the best element available for this operator. If resolution was able
-   * to find a better element based on type propagation, that element will be
-   * returned. Otherwise, the element found using the result of static analysis
-   * will be returned. If resolution has not been performed, then `null` will be
-   * returned.
-   */
-  MethodElement get bestElement {
-    MethodElement element = propagatedElement;
-    if (element == null) {
-      element = staticElement;
-    }
-    return element;
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(operator)..add(_operand);
-
-  @override
-  Token get endToken => _operand.endToken;
-
-  /**
-   * Return the expression computing the operand for the operator.
-   */
-  Expression get operand => _operand;
-
-  /**
-   * Set the expression computing the operand for the operator to the given
-   * [expression].
-   */
-  void set operand(Expression expression) {
-    _operand = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 14;
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on propagated type information, then return the parameter
-   * element representing the parameter to which the value of the operand will
-   * be bound. Otherwise, return `null`.
-   */
-  ParameterElement get _propagatedParameterElementForOperand {
-    if (propagatedElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = propagatedElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  /**
-   * If the AST structure has been resolved, and the function being invoked is
-   * known based on static type information, then return the parameter element
-   * representing the parameter to which the value of the operand will be bound.
-   * Otherwise, return `null`.
-   */
-  ParameterElement get _staticParameterElementForOperand {
-    if (staticElement == null) {
-      return null;
-    }
-    List<ParameterElement> parameters = staticElement.parameters;
-    if (parameters.length < 1) {
-      return null;
-    }
-    return parameters[0];
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitPrefixExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_operand, visitor);
-  }
-}
-
-/**
- * The access of a property of an object.
- *
- * Note, however, that accesses to properties of objects can also be represented
- * as [PrefixedIdentifier] nodes in cases where the target is also a simple
- * identifier.
- *
- * > propertyAccess ::=
- * >     [Expression] '.' [SimpleIdentifier]
- */
-class PropertyAccess extends Expression {
-  /**
-   * The expression computing the object defining the property being accessed.
-   */
-  Expression _target;
-
-  /**
-   * The property access operator.
-   */
-  Token operator;
-
-  /**
-   * The name of the property being accessed.
-   */
-  SimpleIdentifier _propertyName;
-
-  /**
-   * Initialize a newly created property access expression.
-   */
-  PropertyAccess(
-      Expression target, this.operator, SimpleIdentifier propertyName) {
-    _target = _becomeParentOf(target);
-    _propertyName = _becomeParentOf(propertyName);
-  }
-
-  @override
-  Token get beginToken {
-    if (_target != null) {
-      return _target.beginToken;
-    }
-    return operator;
-  }
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_target)..add(operator)..add(_propertyName);
-
-  @override
-  Token get endToken => _propertyName.endToken;
-
-  @override
-  bool get isAssignable => true;
-
-  /**
-   * Return `true` if this expression is cascaded. If it is, then the target of
-   * this expression is not stored locally but is stored in the nearest ancestor
-   * that is a [CascadeExpression].
-   */
-  bool get isCascaded =>
-      operator != null && operator.type == TokenType.PERIOD_PERIOD;
-
-  @override
-  int get precedence => 15;
-
-  /**
-   * Return the name of the property being accessed.
-   */
-  SimpleIdentifier get propertyName => _propertyName;
-
-  /**
-   * Set the name of the property being accessed to the given [identifier].
-   */
-  void set propertyName(SimpleIdentifier identifier) {
-    _propertyName = _becomeParentOf(identifier);
-  }
-
-  /**
-   * Return the expression used to compute the receiver of the invocation. If
-   * this invocation is not part of a cascade expression, then this is the same
-   * as [target]. If this invocation is part of a cascade expression, then the
-   * target stored with the cascade expression is returned.
-   */
-  Expression get realTarget {
-    if (isCascaded) {
-      AstNode ancestor = parent;
-      while (ancestor is! CascadeExpression) {
-        if (ancestor == null) {
-          return _target;
-        }
-        ancestor = ancestor.parent;
-      }
-      return (ancestor as CascadeExpression).target;
-    }
-    return _target;
-  }
-
-  /**
-   * Return the expression computing the object defining the property being
-   * accessed, or `null` if this property access is part of a cascade expression.
-   *
-   * Use [realTarget] to get the target independent of whether this is part of a
-   * cascade expression.
-   */
-  Expression get target => _target;
-
-  /**
-   * Set the expression computing the object defining the property being
-   * accessed to the given [expression].
-   */
-  void set target(Expression expression) {
-    _target = _becomeParentOf(expression);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitPropertyAccess(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_target, visitor);
-    _safelyVisitChild(_propertyName, visitor);
-  }
-}
-
-/**
- * The invocation of a constructor in the same class from within a constructor's
- * initialization list.
- *
- * > redirectingConstructorInvocation ::=
- * >     'this' ('.' identifier)? arguments
- */
-class RedirectingConstructorInvocation extends ConstructorInitializer {
-  /**
-   * The token for the 'this' keyword.
-   */
-  Token thisKeyword;
-
-  /**
-   * The token for the period before the name of the constructor that is being
-   * invoked, or `null` if the unnamed constructor is being invoked.
-   */
-  Token period;
-
-  /**
-   * The name of the constructor that is being invoked, or `null` if the unnamed
-   * constructor is being invoked.
-   */
-  SimpleIdentifier _constructorName;
-
-  /**
-   * The list of arguments to the constructor.
-   */
-  ArgumentList _argumentList;
-
-  /**
-   * The element associated with the constructor based on static type
-   * information, or `null` if the AST structure has not been resolved or if the
-   * constructor could not be resolved.
-   */
-  ConstructorElement staticElement;
-
-  /**
-   * Initialize a newly created redirecting invocation to invoke the constructor
-   * with the given name with the given arguments. The [constructorName] can be
-   * `null` if the constructor being invoked is the unnamed constructor.
-   */
-  RedirectingConstructorInvocation(this.thisKeyword, this.period,
-      SimpleIdentifier constructorName, ArgumentList argumentList) {
-    _constructorName = _becomeParentOf(constructorName);
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  /**
-   * Return the list of arguments to the constructor.
-   */
-  ArgumentList get argumentList => _argumentList;
-
-  /**
-   * Set the list of arguments to the constructor to the given [argumentList].
-   */
-  void set argumentList(ArgumentList argumentList) {
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  @override
-  Token get beginToken => thisKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(thisKeyword)
-    ..add(period)
-    ..add(_constructorName)
-    ..add(_argumentList);
-
-  /**
-   * Return the name of the constructor that is being invoked, or `null` if the
-   * unnamed constructor is being invoked.
-   */
-  SimpleIdentifier get constructorName => _constructorName;
-
-  /**
-   * Set the name of the constructor that is being invoked to the given
-   * [identifier].
-   */
-  void set constructorName(SimpleIdentifier identifier) {
-    _constructorName = _becomeParentOf(identifier);
-  }
-
-  @override
-  Token get endToken => _argumentList.endToken;
-
-  @override
-  accept(AstVisitor visitor) =>
-      visitor.visitRedirectingConstructorInvocation(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_constructorName, visitor);
-    _safelyVisitChild(_argumentList, visitor);
-  }
-}
-
-/**
- * A rethrow expression.
- *
- * > rethrowExpression ::=
- * >     'rethrow'
- */
-class RethrowExpression extends Expression {
-  /**
-   * The token representing the 'rethrow' keyword.
-   */
-  Token rethrowKeyword;
-
-  /**
-   * Initialize a newly created rethrow expression.
-   */
-  RethrowExpression(this.rethrowKeyword);
-
-  @override
-  Token get beginToken => rethrowKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(rethrowKeyword);
-
-  @override
-  Token get endToken => rethrowKeyword;
-
-  @override
-  int get precedence => 0;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitRethrowExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * A return statement.
- *
- * > returnStatement ::=
- * >     'return' [Expression]? ';'
- */
-class ReturnStatement extends Statement {
-  /**
-   * The token representing the 'return' keyword.
-   */
-  Token returnKeyword;
-
-  /**
-   * The expression computing the value to be returned, or `null` if no explicit
-   * value was provided.
-   */
-  Expression _expression;
-
-  /**
-   * The semicolon terminating the statement.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created return statement. The [expression] can be `null`
-   * if no explicit value was provided.
-   */
-  ReturnStatement(this.returnKeyword, Expression expression, this.semicolon) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken => returnKeyword;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(returnKeyword)..add(_expression)..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  /**
-   * Return the expression computing the value to be returned, or `null` if no
-   * explicit value was provided.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression computing the value to be returned to the given
-   * [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitReturnStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * A script tag that can optionally occur at the beginning of a compilation unit.
- *
- * > scriptTag ::=
- * >     '#!' (~NEWLINE)* NEWLINE
- */
-class ScriptTag extends AstNode {
-  /**
-   * The token representing this script tag.
-   */
-  Token scriptTag;
-
-  /**
-   * Initialize a newly created script tag.
-   */
-  ScriptTag(this.scriptTag);
-
-  @override
-  Token get beginToken => scriptTag;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(scriptTag);
-
-  @override
-  Token get endToken => scriptTag;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitScriptTag(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * A combinator that restricts the names being imported to those in a given list.
- *
- * > showCombinator ::=
- * >     'show' [SimpleIdentifier] (',' [SimpleIdentifier])*
- */
-class ShowCombinator extends Combinator {
-  /**
-   * The list of names from the library that are made visible by this combinator.
-   */
-  NodeList<SimpleIdentifier> _shownNames;
-
-  /**
-   * Initialize a newly created import show combinator.
-   */
-  ShowCombinator(Token keyword, List<SimpleIdentifier> shownNames)
-      : super(keyword) {
-    _shownNames = new NodeList<SimpleIdentifier>(this, shownNames);
-  }
-
-  @override
-  // TODO(paulberry): add commas.
-  Iterable get childEntities => new ChildEntities()
-    ..add(keyword)
-    ..addAll(_shownNames);
-
-  @override
-  Token get endToken => _shownNames.endToken;
-
-  /**
-   * Return the list of names from the library that are made visible by this
-   * combinator.
-   */
-  NodeList<SimpleIdentifier> get shownNames => _shownNames;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitShowCombinator(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _shownNames.accept(visitor);
-  }
-}
-
-/**
- * A simple formal parameter.
- *
- * > simpleFormalParameter ::=
- * >     ('final' [TypeName] | 'var' | [TypeName])? [SimpleIdentifier]
- */
-class SimpleFormalParameter extends NormalFormalParameter {
-  /**
-   * The token representing either the 'final', 'const' or 'var' keyword, or
-   * `null` if no keyword was used.
-   */
-  Token keyword;
-
-  /**
-   * The name of the declared type of the parameter, or `null` if the parameter
-   * does not have a declared type.
-   */
-  TypeName _type;
-
-  /**
-   * Initialize a newly created formal parameter. Either or both of the
-   * [comment] and [metadata] can be `null` if the parameter does not have the
-   * corresponding attribute. The [keyword] can be `null` if a type was
-   * specified. The [type] must be `null` if the keyword is 'var'.
-   */
-  SimpleFormalParameter(Comment comment, List<Annotation> metadata,
-      this.keyword, TypeName type, SimpleIdentifier identifier)
-      : super(comment, metadata, identifier) {
-    _type = _becomeParentOf(type);
-  }
-
-  @override
-  Token get beginToken {
-    NodeList<Annotation> metadata = this.metadata;
-    if (!metadata.isEmpty) {
-      return metadata.beginToken;
-    } else if (keyword != null) {
-      return keyword;
-    } else if (_type != null) {
-      return _type.beginToken;
-    }
-    return identifier.beginToken;
-  }
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(keyword)..add(_type)..add(identifier);
-
-  @override
-  Token get endToken => identifier.endToken;
-
-  @override
-  bool get isConst =>
-      (keyword is KeywordToken) &&
-      (keyword as KeywordToken).keyword == Keyword.CONST;
-
-  @override
-  bool get isFinal =>
-      (keyword is KeywordToken) &&
-      (keyword as KeywordToken).keyword == Keyword.FINAL;
-
-  /**
-   * Return the name of the declared type of the parameter, or `null` if the
-   * parameter does not have a declared type.
-   */
-  TypeName get type => _type;
-
-  /**
-   * Set the name of the declared type of the parameter to the given [typeName].
-   */
-  void set type(TypeName typeName) {
-    _type = _becomeParentOf(typeName);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSimpleFormalParameter(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_type, visitor);
-    _safelyVisitChild(identifier, visitor);
-  }
-}
-
-/**
- * A simple identifier.
- *
- * > simpleIdentifier ::=
- * >     initialCharacter internalCharacter*
- * >
- * > initialCharacter ::= '_' | '$' | letter
- * >
- * > internalCharacter ::= '_' | '$' | letter | digit
- */
-class SimpleIdentifier extends Identifier {
-  /**
-   * The token representing the identifier.
-   */
-  Token token;
-
-  /**
-   * The element associated with this identifier based on static type
-   * information, or `null` if the AST structure has not been resolved or if
-   * this identifier could not be resolved.
-   */
-  Element _staticElement;
-
-  /**
-   * The element associated with this identifier based on propagated type
-   * information, or `null` if the AST structure has not been resolved or if
-   * this identifier could not be resolved.
-   */
-  Element _propagatedElement;
-
-  /**
-   * If this expression is both in a getter and setter context, the
-   * [AuxiliaryElements] will be set to hold onto the static and propagated
-   * information. The auxiliary element will hold onto the elements from the
-   * getter context.
-   */
-  AuxiliaryElements auxiliaryElements = null;
-
-  /**
-   * Initialize a newly created identifier.
-   */
-  SimpleIdentifier(this.token);
-
-  @override
-  Token get beginToken => token;
-
-  @override
-  Element get bestElement {
-    if (_propagatedElement == null) {
-      return _staticElement;
-    }
-    return _propagatedElement;
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(token);
-
-  @override
-  Token get endToken => token;
-
-  /**
-   * Return `true` if this identifier is the "name" part of a prefixed
-   * identifier or a method invocation.
-   */
-  bool get isQualified {
-    AstNode parent = this.parent;
-    if (parent is PrefixedIdentifier) {
-      return identical(parent.identifier, this);
-    }
-    if (parent is PropertyAccess) {
-      return identical(parent.propertyName, this);
-    }
-    if (parent is MethodInvocation) {
-      MethodInvocation invocation = parent;
-      return identical(invocation.methodName, this) &&
-          invocation.realTarget != null;
-    }
-    return false;
-  }
-
-  @override
-  bool get isSynthetic => token.isSynthetic;
-
-  @override
-  String get name => token.lexeme;
-
-  @override
-  int get precedence => 16;
-
-  @override
-  Element get propagatedElement => _propagatedElement;
-
-  /**
-   * Set the element associated with this identifier based on propagated type
-   * information to the given [element].
-   */
-  void set propagatedElement(Element element) {
-    _propagatedElement = _validateElement(element);
-  }
-
-  @override
-  Element get staticElement => _staticElement;
-
-  /**
-   * Set the element associated with this identifier based on static type
-   * information to the given [element].
-   */
-  void set staticElement(Element element) {
-    _staticElement = _validateElement(element);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSimpleIdentifier(this);
-
-  /**
-   * Return `true` if this identifier is the name being declared in a
-   * declaration.
-   */
-  bool inDeclarationContext() {
-    // TODO(brianwilkerson) Convert this to a getter.
-    AstNode parent = this.parent;
-    if (parent is CatchClause) {
-      CatchClause clause = parent;
-      return identical(this, clause.exceptionParameter) ||
-          identical(this, clause.stackTraceParameter);
-    } else if (parent is ClassDeclaration) {
-      return identical(this, parent.name);
-    } else if (parent is ClassTypeAlias) {
-      return identical(this, parent.name);
-    } else if (parent is ConstructorDeclaration) {
-      return identical(this, parent.name);
-    } else if (parent is DeclaredIdentifier) {
-      return identical(this, parent.identifier);
-    } else if (parent is EnumDeclaration) {
-      return identical(this, parent.name);
-    } else if (parent is EnumConstantDeclaration) {
-      return identical(this, parent.name);
-    } else if (parent is FunctionDeclaration) {
-      return identical(this, parent.name);
-    } else if (parent is FunctionTypeAlias) {
-      return identical(this, parent.name);
-    } else if (parent is ImportDirective) {
-      return identical(this, parent.prefix);
-    } else if (parent is Label) {
-      return identical(this, parent.label) &&
-          (parent.parent is LabeledStatement);
-    } else if (parent is MethodDeclaration) {
-      return identical(this, parent.name);
-    } else if (parent is FunctionTypedFormalParameter ||
-        parent is SimpleFormalParameter) {
-      return identical(this, (parent as NormalFormalParameter).identifier);
-    } else if (parent is TypeParameter) {
-      return identical(this, parent.name);
-    } else if (parent is VariableDeclaration) {
-      return identical(this, parent.name);
-    }
-    return false;
-  }
-
-  /**
-   * Return `true` if this expression is computing a right-hand value.
-   *
-   * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
-   * are they mutually exclusive. In other words, it is possible for both
-   * methods to return `true` when invoked on the same node.
-   */
-  bool inGetterContext() {
-    // TODO(brianwilkerson) Convert this to a getter.
-    AstNode parent = this.parent;
-    AstNode target = this;
-    // skip prefix
-    if (parent is PrefixedIdentifier) {
-      PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
-      if (identical(prefixed.prefix, this)) {
-        return true;
-      }
-      parent = prefixed.parent;
-      target = prefixed;
-    } else if (parent is PropertyAccess) {
-      PropertyAccess access = parent as PropertyAccess;
-      if (identical(access.target, this)) {
-        return true;
-      }
-      parent = access.parent;
-      target = access;
-    }
-    // skip label
-    if (parent is Label) {
-      return false;
-    }
-    // analyze usage
-    if (parent is AssignmentExpression) {
-      if (identical(parent.leftHandSide, target) &&
-          parent.operator.type == TokenType.EQ) {
-        return false;
-      }
-    }
-    if (parent is ForEachStatement) {
-      if (identical(parent.identifier, target)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Return `true` if this expression is computing a left-hand value.
-   *
-   * Note that [inGetterContext] and [inSetterContext] are not opposites, nor
-   * are they mutually exclusive. In other words, it is possible for both
-   * methods to return `true` when invoked on the same node.
-   */
-  bool inSetterContext() {
-    // TODO(brianwilkerson) Convert this to a getter.
-    AstNode parent = this.parent;
-    AstNode target = this;
-    // skip prefix
-    if (parent is PrefixedIdentifier) {
-      PrefixedIdentifier prefixed = parent as PrefixedIdentifier;
-      // if this is the prefix, then return false
-      if (identical(prefixed.prefix, this)) {
-        return false;
-      }
-      parent = prefixed.parent;
-      target = prefixed;
-    } else if (parent is PropertyAccess) {
-      PropertyAccess access = parent as PropertyAccess;
-      if (identical(access.target, this)) {
-        return false;
-      }
-      parent = access.parent;
-      target = access;
-    }
-    // analyze usage
-    if (parent is PrefixExpression) {
-      return parent.operator.type.isIncrementOperator;
-    } else if (parent is PostfixExpression) {
-      return true;
-    } else if (parent is AssignmentExpression) {
-      return identical(parent.leftHandSide, target);
-    } else if (parent is ForEachStatement) {
-      return identical(parent.identifier, target);
-    }
-    return false;
-  }
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-
-  /**
-   * Return the given element if it is valid, or report the problem and return
-   * `null` if it is not appropriate.
-   *
-   * The [parent] is the parent of the element, used for reporting when there is
-   * a problem.
-   * The [isValid] is `true` if the element is appropriate.
-   * The [element] is the element to be associated with this identifier.
-   */
-  Element _returnOrReportElement(
-      AstNode parent, bool isValid, Element element) {
-    if (!isValid) {
-      AnalysisEngine.instance.logger.logInformation(
-          "Internal error: attempting to set the name of a ${parent.runtimeType} to a ${element.runtimeType}",
-          new CaughtException(new AnalysisException(), null));
-      return null;
-    }
-    return element;
-  }
-
-  /**
-   * Return the given [element] if it is an appropriate element based on the
-   * parent of this identifier, or `null` if it is not appropriate.
-   */
-  Element _validateElement(Element element) {
-    if (element == null) {
-      return null;
-    }
-    AstNode parent = this.parent;
-    if (parent is ClassDeclaration && identical(parent.name, this)) {
-      return _returnOrReportElement(parent, element is ClassElement, element);
-    } else if (parent is ClassTypeAlias && identical(parent.name, this)) {
-      return _returnOrReportElement(parent, element is ClassElement, element);
-    } else if (parent is DeclaredIdentifier &&
-        identical(parent.identifier, this)) {
-      return _returnOrReportElement(
-          parent, element is LocalVariableElement, element);
-    } else if (parent is FormalParameter &&
-        identical(parent.identifier, this)) {
-      return _returnOrReportElement(
-          parent, element is ParameterElement, element);
-    } else if (parent is FunctionDeclaration && identical(parent.name, this)) {
-      return _returnOrReportElement(
-          parent, element is ExecutableElement, element);
-    } else if (parent is FunctionTypeAlias && identical(parent.name, this)) {
-      return _returnOrReportElement(
-          parent, element is FunctionTypeAliasElement, element);
-    } else if (parent is MethodDeclaration && identical(parent.name, this)) {
-      return _returnOrReportElement(
-          parent, element is ExecutableElement, element);
-    } else if (parent is TypeParameter && identical(parent.name, this)) {
-      return _returnOrReportElement(
-          parent, element is TypeParameterElement, element);
-    } else if (parent is VariableDeclaration && identical(parent.name, this)) {
-      return _returnOrReportElement(
-          parent, element is VariableElement, element);
-    }
-    return element;
-  }
-}
-
-/**
- * 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 '"'
- */
-class SimpleStringLiteral extends SingleStringLiteral {
-  /**
-   * The token representing the literal.
-   */
-  Token literal;
-
-  /**
-   * The value of the literal.
-   */
-  String _value;
-
-  /**
-   * Initialize a newly created simple string literal.
-   */
-  SimpleStringLiteral(this.literal, String value) {
-    _value = StringUtilities.intern(value);
-  }
-
-  @override
-  Token get beginToken => literal;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(literal);
-
-  @override
-  int get contentsEnd => offset + _helper.end;
-
-  @override
-  int get contentsOffset => offset + _helper.start;
-
-  @override
-  Token get endToken => literal;
-
-  @override
-  bool get isMultiline => _helper.isMultiline;
-
-  @override
-  bool get isRaw => _helper.isRaw;
-
-  @override
-  bool get isSingleQuoted => _helper.isSingleQuoted;
-
-  @override
-  bool get isSynthetic => literal.isSynthetic;
-
-  /**
-   * Return the value of the literal.
-   */
-  String get value => _value;
-
-  /**
-   * Set the value of the literal to the given [string].
-   */
-  void set value(String string) {
-    _value = StringUtilities.intern(_value);
-  }
-
-  StringLexemeHelper get _helper {
-    return new StringLexemeHelper(literal.lexeme, true, true);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSimpleStringLiteral(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-
-  @override
-  void _appendStringValue(StringBuffer buffer) {
-    buffer.write(value);
-  }
-}
-
-/**
- * A single string literal expression.
- *
- * > singleStringLiteral ::=
- * >     [SimpleStringLiteral]
- * >   | [StringInterpolation]
- */
-abstract class SingleStringLiteral extends StringLiteral {
-  /**
-   * Return the offset of the after-last contents character.
-   */
-  int get contentsEnd;
-
-  /**
-   * Return the offset of the first contents character.
-   * If the string is multiline, then leading whitespaces are skipped.
-   */
-  int get contentsOffset;
-
-  /**
-   * Return `true` if this string literal is a multi-line string.
-   */
-  bool get isMultiline;
-
-  /**
-   * Return `true` if this string literal is a raw string.
-   */
-  bool get isRaw;
-
-  /**
-   * Return `true` if this string literal uses single quotes (' or ''').
-   * Return `false` if this string literal uses double quotes (" or """).
-   */
-  bool get isSingleQuoted;
-}
-
-/**
- * A node that represents a statement.
- *
- * > statement ::=
- * >     [Block]
- * >   | [VariableDeclarationStatement]
- * >   | [ForStatement]
- * >   | [ForEachStatement]
- * >   | [WhileStatement]
- * >   | [DoStatement]
- * >   | [SwitchStatement]
- * >   | [IfStatement]
- * >   | [TryStatement]
- * >   | [BreakStatement]
- * >   | [ContinueStatement]
- * >   | [ReturnStatement]
- * >   | [ExpressionStatement]
- * >   | [FunctionDeclarationStatement]
- */
-abstract class Statement extends AstNode {
-  /**
-   * If this is a labeled statement, return the unlabeled portion of the
-   * statement.  Otherwise return the statement itself.
-   */
-  Statement get unlabeled => this;
-}
-
-/**
- * A string interpolation literal.
- *
- * > stringInterpolation ::=
- * >     ''' [InterpolationElement]* '''
- * >   | '"' [InterpolationElement]* '"'
- */
-class StringInterpolation extends SingleStringLiteral {
-  /**
-   * The elements that will be composed to produce the resulting string.
-   */
-  NodeList<InterpolationElement> _elements;
-
-  /**
-   * Initialize a newly created string interpolation expression.
-   */
-  StringInterpolation(List<InterpolationElement> elements) {
-    _elements = new NodeList<InterpolationElement>(this, elements);
-  }
-
-  @override
-  Token get beginToken => _elements.beginToken;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..addAll(_elements);
-
-  @override
-  int get contentsEnd {
-    InterpolationString element = _elements.last;
-    return element.contentsEnd;
-  }
-
-  @override
-  int get contentsOffset {
-    InterpolationString element = _elements.first;
-    return element.contentsOffset;
-  }
-
-  /**
-   * Return the elements that will be composed to produce the resulting string.
-   */
-  NodeList<InterpolationElement> get elements => _elements;
-
-  @override
-  Token get endToken => _elements.endToken;
-
-  @override
-  bool get isMultiline => _firstHelper.isMultiline;
-
-  @override
-  bool get isRaw => false;
-
-  @override
-  bool get isSingleQuoted => _firstHelper.isSingleQuoted;
-
-  StringLexemeHelper get _firstHelper {
-    InterpolationString lastString = _elements.first;
-    String lexeme = lastString.contents.lexeme;
-    return new StringLexemeHelper(lexeme, true, false);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitStringInterpolation(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _elements.accept(visitor);
-  }
-
-  @override
-  void _appendStringValue(StringBuffer buffer) {
-    throw new IllegalArgumentException();
-  }
-}
-
-/**
- * A helper for analyzing string lexemes.
- */
-class StringLexemeHelper {
-  final String lexeme;
-  final bool isFirst;
-  final bool isLast;
-
-  bool isRaw = false;
-  bool isSingleQuoted = false;
-  bool isMultiline = false;
-  int start = 0;
-  int end;
-
-  StringLexemeHelper(this.lexeme, this.isFirst, this.isLast) {
-    if (isFirst) {
-      isRaw = StringUtilities.startsWithChar(lexeme, 0x72);
-      if (isRaw) {
-        start++;
-      }
-      if (StringUtilities.startsWith3(lexeme, start, 0x27, 0x27, 0x27)) {
-        isSingleQuoted = true;
-        isMultiline = true;
-        start += 3;
-        start = _trimInitialWhitespace(start);
-      } else if (StringUtilities.startsWith3(lexeme, start, 0x22, 0x22, 0x22)) {
-        isSingleQuoted = false;
-        isMultiline = true;
-        start += 3;
-        start = _trimInitialWhitespace(start);
-      } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x27) {
-        isSingleQuoted = true;
-        isMultiline = false;
-        start++;
-      } else if (start < lexeme.length && lexeme.codeUnitAt(start) == 0x22) {
-        isSingleQuoted = false;
-        isMultiline = false;
-        start++;
-      }
-    }
-    end = lexeme.length;
-    if (isLast) {
-      if (start + 3 <= end &&
-          (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) ||
-              StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27))) {
-        end -= 3;
-      } else if (start + 1 <= end &&
-          (StringUtilities.endsWithChar(lexeme, 0x22) ||
-              StringUtilities.endsWithChar(lexeme, 0x27))) {
-        end -= 1;
-      }
-    }
-  }
-
-  /**
-   * Given the [lexeme] for a multi-line string whose content begins at the
-   * given [start] index, return the index of the first character that is
-   * included in the value of the string. According to the specification:
-   *
-   * If the first line of a multiline string consists solely of the whitespace
-   * characters defined by the production WHITESPACE 20.1), possibly prefixed
-   * by \, then that line is ignored, including the new line at its end.
-   */
-  int _trimInitialWhitespace(int start) {
-    int length = lexeme.length;
-    int index = start;
-    while (index < length) {
-      int currentChar = lexeme.codeUnitAt(index);
-      if (currentChar == 0x0D) {
-        if (index + 1 < length && lexeme.codeUnitAt(index + 1) == 0x0A) {
-          return index + 2;
-        }
-        return index + 1;
-      } else if (currentChar == 0x0A) {
-        return index + 1;
-      } else if (currentChar == 0x5C) {
-        if (index + 1 >= length) {
-          return start;
-        }
-        currentChar = lexeme.codeUnitAt(index + 1);
-        if (currentChar != 0x0D &&
-            currentChar != 0x0A &&
-            currentChar != 0x09 &&
-            currentChar != 0x20) {
-          return start;
-        }
-      } else if (currentChar != 0x09 && currentChar != 0x20) {
-        return start;
-      }
-      index++;
-    }
-    return start;
-  }
-}
-
-/**
- * A string literal expression.
- *
- * > stringLiteral ::=
- * >     [SimpleStringLiteral]
- * >   | [AdjacentStrings]
- * >   | [StringInterpolation]
- */
-abstract class StringLiteral extends Literal {
-  /**
-   * Return the value of the string literal, or `null` if the string is not a
-   * constant string without any string interpolation.
-   */
-  String get stringValue {
-    StringBuffer buffer = new StringBuffer();
-    try {
-      _appendStringValue(buffer);
-    } on IllegalArgumentException {
-      return null;
-    }
-    return buffer.toString();
-  }
-
-  /**
-   * Append the value of this string literal to the given [buffer]. Throw an
-   * [IllegalArgumentException] if the string is not a constant string without
-   * any string interpolation.
-   */
-  void _appendStringValue(StringBuffer buffer);
-}
-
-/**
- * The invocation of a superclass' constructor from within a constructor's
- * initialization list.
- *
- * > superInvocation ::=
- * >     'super' ('.' [SimpleIdentifier])? [ArgumentList]
- */
-class SuperConstructorInvocation extends ConstructorInitializer {
-  /**
-   * The token for the 'super' keyword.
-   */
-  Token superKeyword;
-
-  /**
-   * The token for the period before the name of the constructor that is being
-   * invoked, or `null` if the unnamed constructor is being invoked.
-   */
-  Token period;
-
-  /**
-   * The name of the constructor that is being invoked, or `null` if the unnamed
-   * constructor is being invoked.
-   */
-  SimpleIdentifier _constructorName;
-
-  /**
-   * The list of arguments to the constructor.
-   */
-  ArgumentList _argumentList;
-
-  /**
-   * The element associated with the constructor based on static type
-   * information, or `null` if the AST structure has not been resolved or if the
-   * constructor could not be resolved.
-   */
-  ConstructorElement staticElement;
-
-  /**
-   * Initialize a newly created super invocation to invoke the inherited
-   * constructor with the given name with the given arguments. The [period] and
-   * [constructorName] can be `null` if the constructor being invoked is the
-   * unnamed constructor.
-   */
-  SuperConstructorInvocation(this.superKeyword, this.period,
-      SimpleIdentifier constructorName, ArgumentList argumentList) {
-    _constructorName = _becomeParentOf(constructorName);
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  /**
-   * Return the list of arguments to the constructor.
-   */
-  ArgumentList get argumentList => _argumentList;
-
-  /**
-   * Set the list of arguments to the constructor to the given [argumentList].
-   */
-  void set argumentList(ArgumentList argumentList) {
-    _argumentList = _becomeParentOf(argumentList);
-  }
-
-  @override
-  Token get beginToken => superKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(superKeyword)
-    ..add(period)
-    ..add(_constructorName)
-    ..add(_argumentList);
-
-  /**
-   * Return the name of the constructor that is being invoked, or `null` if the
-   * unnamed constructor is being invoked.
-   */
-  SimpleIdentifier get constructorName => _constructorName;
-
-  /**
-   * Set the name of the constructor that is being invoked to the given
-   * [identifier].
-   */
-  void set constructorName(SimpleIdentifier identifier) {
-    _constructorName = _becomeParentOf(identifier);
-  }
-
-  @override
-  Token get endToken => _argumentList.endToken;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSuperConstructorInvocation(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_constructorName, visitor);
-    _safelyVisitChild(_argumentList, visitor);
-  }
-}
-
-/**
- * A super expression.
- *
- * > superExpression ::=
- * >     'super'
- */
-class SuperExpression extends Expression {
-  /**
-   * The token representing the 'super' keyword.
-   */
-  Token superKeyword;
-
-  /**
-   * Initialize a newly created super expression.
-   */
-  SuperExpression(this.superKeyword);
-
-  @override
-  Token get beginToken => superKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(superKeyword);
-
-  @override
-  Token get endToken => superKeyword;
-
-  @override
-  int get precedence => 16;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSuperExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * A case in a switch statement.
- *
- * > switchCase ::=
- * >     [SimpleIdentifier]* 'case' [Expression] ':' [Statement]*
- */
-class SwitchCase extends SwitchMember {
-  /**
-   * The expression controlling whether the statements will be executed.
-   */
-  Expression _expression;
-
-  /**
-   * Initialize a newly created switch case. The list of [labels] can be `null`
-   * if there are no labels.
-   */
-  SwitchCase(List<Label> labels, Token keyword, Expression expression,
-      Token colon, List<Statement> statements)
-      : super(labels, keyword, colon, statements) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..addAll(labels)
-    ..add(keyword)
-    ..add(_expression)
-    ..add(colon)
-    ..addAll(statements);
-
-  /**
-   * Return the expression controlling whether the statements will be executed.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression controlling whether the statements will be executed to
-   * the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSwitchCase(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    labels.accept(visitor);
-    _safelyVisitChild(_expression, visitor);
-    statements.accept(visitor);
-  }
-}
-
-/**
- * The default case in a switch statement.
- *
- * > switchDefault ::=
- * >     [SimpleIdentifier]* 'default' ':' [Statement]*
- */
-class SwitchDefault extends SwitchMember {
-  /**
-   * Initialize a newly created switch default. The list of [labels] can be
-   * `null` if there are no labels.
-   */
-  SwitchDefault(List<Label> labels, Token keyword, Token colon,
-      List<Statement> statements)
-      : super(labels, keyword, colon, statements);
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..addAll(labels)
-    ..add(keyword)
-    ..add(colon)
-    ..addAll(statements);
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSwitchDefault(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    labels.accept(visitor);
-    statements.accept(visitor);
-  }
-}
-
-/**
- * An element within a switch statement.
- *
- * > switchMember ::=
- * >     switchCase
- * >   | switchDefault
- */
-abstract class SwitchMember extends AstNode {
-  /**
-   * The labels associated with the switch member.
-   */
-  NodeList<Label> _labels;
-
-  /**
-   * The token representing the 'case' or 'default' keyword.
-   */
-  Token keyword;
-
-  /**
-   * The colon separating the keyword or the expression from the statements.
-   */
-  Token colon;
-
-  /**
-   * The statements that will be executed if this switch member is selected.
-   */
-  NodeList<Statement> _statements;
-
-  /**
-   * Initialize a newly created switch member. The list of [labels] can be
-   * `null` if there are no labels.
-   */
-  SwitchMember(List<Label> labels, this.keyword, this.colon,
-      List<Statement> statements) {
-    _labels = new NodeList<Label>(this, labels);
-    _statements = new NodeList<Statement>(this, statements);
-  }
-
-  @override
-  Token get beginToken {
-    if (!_labels.isEmpty) {
-      return _labels.beginToken;
-    }
-    return keyword;
-  }
-
-  @override
-  Token get endToken {
-    if (!_statements.isEmpty) {
-      return _statements.endToken;
-    }
-    return colon;
-  }
-
-  /**
-   * Return the labels associated with the switch member.
-   */
-  NodeList<Label> get labels => _labels;
-
-  /**
-   * Return the statements that will be executed if this switch member is
-   * selected.
-   */
-  NodeList<Statement> get statements => _statements;
-}
-
-/**
- * A switch statement.
- *
- * > switchStatement ::=
- * >     'switch' '(' [Expression] ')' '{' [SwitchCase]* [SwitchDefault]? '}'
- */
-class SwitchStatement extends Statement {
-  /**
-   * The token representing the 'switch' keyword.
-   */
-  Token switchKeyword;
-
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The expression used to determine which of the switch members will be
-   * selected.
-   */
-  Expression _expression;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * The left curly bracket.
-   */
-  Token leftBracket;
-
-  /**
-   * The switch members that can be selected by the expression.
-   */
-  NodeList<SwitchMember> _members;
-
-  /**
-   * The right curly bracket.
-   */
-  Token rightBracket;
-
-  /**
-   * Initialize a newly created switch statement. The list of [members] can be
-   * `null` if there are no switch members.
-   */
-  SwitchStatement(
-      this.switchKeyword,
-      this.leftParenthesis,
-      Expression expression,
-      this.rightParenthesis,
-      this.leftBracket,
-      List<SwitchMember> members,
-      this.rightBracket) {
-    _expression = _becomeParentOf(expression);
-    _members = new NodeList<SwitchMember>(this, members);
-  }
-
-  @override
-  Token get beginToken => switchKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(switchKeyword)
-    ..add(leftParenthesis)
-    ..add(_expression)
-    ..add(rightParenthesis)
-    ..add(leftBracket)
-    ..addAll(_members)
-    ..add(rightBracket);
-
-  @override
-  Token get endToken => rightBracket;
-
-  /**
-   * Return the expression used to determine which of the switch members will be
-   * selected.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression used to determine which of the switch members will be
-   * selected to the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  /**
-   * Return the switch members that can be selected by the expression.
-   */
-  NodeList<SwitchMember> get members => _members;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSwitchStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-    _members.accept(visitor);
-  }
-}
-
-/**
- * A symbol literal expression.
- *
- * > symbolLiteral ::=
- * >     '#' (operator | (identifier ('.' identifier)*))
- */
-class SymbolLiteral extends Literal {
-  /**
-   * The token introducing the literal.
-   */
-  Token poundSign;
-
-  /**
-   * The components of the literal.
-   */
-  final List<Token> components;
-
-  /**
-   * Initialize a newly created symbol literal.
-   */
-  SymbolLiteral(this.poundSign, this.components);
-
-  @override
-  Token get beginToken => poundSign;
-
-  @override
-  // TODO(paulberry): add "." tokens.
-  Iterable get childEntities => new ChildEntities()
-    ..add(poundSign)
-    ..addAll(components);
-
-  @override
-  Token get endToken => components[components.length - 1];
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitSymbolLiteral(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * A this expression.
- *
- * > thisExpression ::=
- * >     'this'
- */
-class ThisExpression extends Expression {
-  /**
-   * The token representing the 'this' keyword.
-   */
-  Token thisKeyword;
-
-  /**
-   * Initialize a newly created this expression.
-   */
-  ThisExpression(this.thisKeyword);
-
-  @override
-  Token get beginToken => thisKeyword;
-
-  @override
-  Iterable get childEntities => new ChildEntities()..add(thisKeyword);
-
-  @override
-  Token get endToken => thisKeyword;
-
-  @override
-  int get precedence => 16;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitThisExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    // There are no children to visit.
-  }
-}
-
-/**
- * A throw expression.
- *
- * > throwExpression ::=
- * >     'throw' [Expression]
- */
-class ThrowExpression extends Expression {
-  /**
-   * The token representing the 'throw' keyword.
-   */
-  Token throwKeyword;
-
-  /**
-   * The expression computing the exception to be thrown.
-   */
-  Expression _expression;
-
-  /**
-   * Initialize a newly created throw expression.
-   */
-  ThrowExpression(this.throwKeyword, Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken => throwKeyword;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(throwKeyword)..add(_expression);
-
-  @override
-  Token get endToken {
-    if (_expression != null) {
-      return _expression.endToken;
-    }
-    return throwKeyword;
-  }
-
-  /**
-   * Return the expression computing the exception to be thrown.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression computing the exception to be thrown to the given
-   * [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  int get precedence => 0;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitThrowExpression(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-  }
-}
-
-/**
- * The declaration of one or more top-level variables of the same type.
- *
- * > topLevelVariableDeclaration ::=
- * >     ('final' | 'const') type? staticFinalDeclarationList ';'
- * >   | variableDeclaration ';'
- */
-class TopLevelVariableDeclaration extends CompilationUnitMember {
-  /**
-   * The top-level variables being declared.
-   */
-  VariableDeclarationList _variableList;
-
-  /**
-   * The semicolon terminating the declaration.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created top-level variable declaration. Either or both
-   * of the [comment] and [metadata] can be `null` if the variable does not have
-   * the corresponding attribute.
-   */
-  TopLevelVariableDeclaration(Comment comment, List<Annotation> metadata,
-      VariableDeclarationList variableList, this.semicolon)
-      : super(comment, metadata) {
-    _variableList = _becomeParentOf(variableList);
-  }
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(_variableList)..add(semicolon);
-
-  @override
-  Element get element => null;
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => _variableList.beginToken;
-
-  /**
-   * Return the top-level variables being declared.
-   */
-  VariableDeclarationList get variables => _variableList;
-
-  /**
-   * Set the top-level variables being declared to the given list of
-   * [variables].
-   */
-  void set variables(VariableDeclarationList variables) {
-    _variableList = _becomeParentOf(variables);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitTopLevelVariableDeclaration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_variableList, visitor);
-  }
-}
-
-/**
- * A try statement.
- *
- * > tryStatement ::=
- * >     'try' [Block] ([CatchClause]+ finallyClause? | finallyClause)
- * >
- * > finallyClause ::=
- * >     'finally' [Block]
- */
-class TryStatement extends Statement {
-  /**
-   * The token representing the 'try' keyword.
-   */
-  Token tryKeyword;
-
-  /**
-   * The body of the statement.
-   */
-  Block _body;
-
-  /**
-   * The catch clauses contained in the try statement.
-   */
-  NodeList<CatchClause> _catchClauses;
-
-  /**
-   * The token representing the 'finally' keyword, or `null` if the statement
-   * does not contain a finally clause.
-   */
-  Token finallyKeyword;
-
-  /**
-   * The finally block contained in the try statement, or `null` if the
-   * statement does not contain a finally clause.
-   */
-  Block _finallyBlock;
-
-  /**
-   * Initialize a newly created try statement. The list of [catchClauses] can be
-   * `null` if there are no catch clauses. The [finallyKeyword] and
-   * [finallyBlock] can be `null` if there is no finally clause.
-   */
-  TryStatement(this.tryKeyword, Block body, List<CatchClause> catchClauses,
-      this.finallyKeyword, Block finallyBlock) {
-    _body = _becomeParentOf(body);
-    _catchClauses = new NodeList<CatchClause>(this, catchClauses);
-    _finallyBlock = _becomeParentOf(finallyBlock);
-  }
-
-  @override
-  Token get beginToken => tryKeyword;
-
-  /**
-   * Return the body of the statement.
-   */
-  Block get body => _body;
-
-  /**
-   * Set the body of the statement to the given [block].
-   */
-  void set body(Block block) {
-    _body = _becomeParentOf(block);
-  }
-
-  /**
-   * Return the catch clauses contained in the try statement.
-   */
-  NodeList<CatchClause> get catchClauses => _catchClauses;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(tryKeyword)
-    ..add(_body)
-    ..addAll(_catchClauses)
-    ..add(finallyKeyword)
-    ..add(_finallyBlock);
-
-  @override
-  Token get endToken {
-    if (_finallyBlock != null) {
-      return _finallyBlock.endToken;
-    } else if (finallyKeyword != null) {
-      return finallyKeyword;
-    } else if (!_catchClauses.isEmpty) {
-      return _catchClauses.endToken;
-    }
-    return _body.endToken;
-  }
-
-  /**
-   * Return the finally block contained in the try statement, or `null` if the
-   * statement does not contain a finally clause.
-   */
-  Block get finallyBlock => _finallyBlock;
-
-  /**
-   * Set the finally block contained in the try statement to the given [block].
-   */
-  void set finallyBlock(Block block) {
-    _finallyBlock = _becomeParentOf(block);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitTryStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_body, visitor);
-    _catchClauses.accept(visitor);
-    _safelyVisitChild(_finallyBlock, visitor);
-  }
-}
-
-/**
- * The declaration of a type alias.
- *
- * > typeAlias ::=
- * >     'typedef' typeAliasBody
- * >
- * > typeAliasBody ::=
- * >     classTypeAlias
- * >   | functionTypeAlias
- */
-abstract class TypeAlias extends NamedCompilationUnitMember {
-  /**
-   * The token representing the 'typedef' keyword.
-   */
-  Token typedefKeyword;
-
-  /**
-   * The semicolon terminating the declaration.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created type alias. Either or both of the [comment] and
-   * [metadata] can be `null` if the declaration does not have the corresponding
-   * attribute.
-   */
-  TypeAlias(Comment comment, List<Annotation> metadata, this.typedefKeyword,
-      SimpleIdentifier name, this.semicolon)
-      : super(comment, metadata, name);
-
-  @override
-  Token get endToken => semicolon;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => typedefKeyword;
-}
-
-/**
- * A list of type arguments.
- *
- * > typeArguments ::=
- * >     '<' typeName (',' typeName)* '>'
- */
-class TypeArgumentList extends AstNode {
-  /**
-   * The left bracket.
-   */
-  Token leftBracket;
-
-  /**
-   * The type arguments associated with the type.
-   */
-  NodeList<TypeName> _arguments;
-
-  /**
-   * The right bracket.
-   */
-  Token rightBracket;
-
-  /**
-   * Initialize a newly created list of type arguments.
-   */
-  TypeArgumentList(
-      this.leftBracket, List<TypeName> arguments, this.rightBracket) {
-    _arguments = new NodeList<TypeName>(this, arguments);
-  }
-
-  /**
-   * Return the type arguments associated with the type.
-   */
-  NodeList<TypeName> get arguments => _arguments;
-
-  @override
-  Token get beginToken => leftBracket;
-
-  @override
-  // TODO(paulberry): Add commas.
-  Iterable get childEntities => new ChildEntities()
-    ..add(leftBracket)
-    ..addAll(_arguments)
-    ..add(rightBracket);
-
-  @override
-  Token get endToken => rightBracket;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitTypeArgumentList(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _arguments.accept(visitor);
-  }
-}
-
-/**
- * A literal that has a type associated with it.
- *
- * > typedLiteral ::=
- * >     [ListLiteral]
- * >   | [MapLiteral]
- */
-abstract class TypedLiteral extends Literal {
-  /**
-   * The token representing the 'const' keyword, or `null` if the literal is not
-   * a constant.
-   */
-  Token constKeyword;
-
-  /**
-   * The type argument associated with this literal, or `null` if no type
-   * arguments were declared.
-   */
-  TypeArgumentList _typeArguments;
-
-  /**
-   * Initialize a newly created typed literal. The [constKeyword] can be `null`\
-   * if the literal is not a constant. The [typeArguments] can be `null` if no
-   * type arguments were declared.
-   */
-  TypedLiteral(this.constKeyword, TypeArgumentList typeArguments) {
-    _typeArguments = _becomeParentOf(typeArguments);
-  }
-
-  /**
-   * Return the type argument associated with this literal, or `null` if no type
-   * arguments were declared.
-   */
-  TypeArgumentList get typeArguments => _typeArguments;
-
-  /**
-   * Set the type argument associated with this literal to the given
-   * [typeArguments].
-   */
-  void set typeArguments(TypeArgumentList typeArguments) {
-    _typeArguments = _becomeParentOf(typeArguments);
-  }
-
-  ChildEntities get _childEntities =>
-      new ChildEntities()..add(constKeyword)..add(_typeArguments);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_typeArguments, visitor);
-  }
-}
-
-/**
- * The name of a type, which can optionally include type arguments.
- *
- * > typeName ::=
- * >     [Identifier] typeArguments?
- */
-class TypeName extends AstNode {
-  /**
-   * The name of the type.
-   */
-  Identifier _name;
-
-  /**
-   * The type arguments associated with the type, or `null` if there are no type
-   * arguments.
-   */
-  TypeArgumentList _typeArguments;
-
-  /**
-   * The type being named, or `null` if the AST structure has not been resolved.
-   */
-  DartType type;
-
-  /**
-   * Initialize a newly created type name. The [typeArguments] can be `null` if
-   * there are no type arguments.
-   */
-  TypeName(Identifier name, TypeArgumentList typeArguments) {
-    _name = _becomeParentOf(name);
-    _typeArguments = _becomeParentOf(typeArguments);
-  }
-
-  @override
-  Token get beginToken => _name.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_name)..add(_typeArguments);
-
-  @override
-  Token get endToken {
-    if (_typeArguments != null) {
-      return _typeArguments.endToken;
-    }
-    return _name.endToken;
-  }
-
-  /**
-   * Return `true` if this type is a deferred type.
-   *
-   * 15.1 Static Types: A type <i>T</i> is deferred iff it is of the form
-   * </i>p.T</i> where <i>p</i> is a deferred prefix.
-   */
-  bool get isDeferred {
-    Identifier identifier = name;
-    if (identifier is! PrefixedIdentifier) {
-      return false;
-    }
-    return (identifier as PrefixedIdentifier).isDeferred;
-  }
-
-  @override
-  bool get isSynthetic => _name.isSynthetic && _typeArguments == null;
-
-  /**
-   * Return the name of the type.
-   */
-  Identifier get name => _name;
-
-  /**
-   * Set the name of the type to the given [identifier].
-   */
-  void set name(Identifier identifier) {
-    _name = _becomeParentOf(identifier);
-  }
-
-  /**
-   * Return the type arguments associated with the type, or `null` if there are
-   * no type arguments.
-   */
-  TypeArgumentList get typeArguments => _typeArguments;
-
-  /**
-   * Set the type arguments associated with the type to the given
-   * [typeArguments].
-   */
-  void set typeArguments(TypeArgumentList typeArguments) {
-    _typeArguments = _becomeParentOf(typeArguments);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitTypeName(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_typeArguments, visitor);
-  }
-}
-
-/**
- * A type parameter.
- *
- * > typeParameter ::=
- * >     [SimpleIdentifier] ('extends' [TypeName])?
- */
-class TypeParameter extends Declaration {
-  /**
-   * The name of the type parameter.
-   */
-  SimpleIdentifier _name;
-
-  /**
-   * The token representing the 'extends' keyword, or `null` if there is no
-   * explicit upper bound.
-   */
-  Token extendsKeyword;
-
-  /**
-   * The name of the upper bound for legal arguments, or `null` if there is no
-   * explicit upper bound.
-   */
-  TypeName _bound;
-
-  /**
-   * Initialize a newly created type parameter. Either or both of the [comment]
-   * and [metadata] can be `null` if the parameter does not have the
-   * corresponding attribute. The [extendsKeyword] and [bound] can be `null` if
-   * the parameter does not have an upper bound.
-   */
-  TypeParameter(Comment comment, List<Annotation> metadata,
-      SimpleIdentifier name, this.extendsKeyword, TypeName bound)
-      : super(comment, metadata) {
-    _name = _becomeParentOf(name);
-    _bound = _becomeParentOf(bound);
-  }
-
-  /**
-   * Return the name of the upper bound for legal arguments, or `null` if there
-   * is no explicit upper bound.
-   */
-  TypeName get bound => _bound;
-
-  /**
-   * Set the name of the upper bound for legal arguments to the given
-   * [typeName].
-   */
-  void set bound(TypeName typeName) {
-    _bound = _becomeParentOf(typeName);
-  }
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(_name)..add(extendsKeyword)..add(_bound);
-
-  @override
-  TypeParameterElement get element =>
-      _name != null ? (_name.staticElement as TypeParameterElement) : null;
-
-  @override
-  Token get endToken {
-    if (_bound == null) {
-      return _name.endToken;
-    }
-    return _bound.endToken;
-  }
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
-
-  /**
-   * Return the name of the type parameter.
-   */
-  SimpleIdentifier get name => _name;
-
-  /**
-   * Set the name of the type parameter to the given [identifier].
-   */
-  void set name(SimpleIdentifier identifier) {
-    _name = _becomeParentOf(identifier);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitTypeParameter(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_bound, visitor);
-  }
-}
-
-/**
- * Type parameters within a declaration.
- *
- * > typeParameterList ::=
- * >     '<' [TypeParameter] (',' [TypeParameter])* '>'
- */
-class TypeParameterList extends AstNode {
-  /**
-   * The left angle bracket.
-   */
-  final Token leftBracket;
-
-  /**
-   * The type parameters in the list.
-   */
-  NodeList<TypeParameter> _typeParameters;
-
-  /**
-   * The right angle bracket.
-   */
-  final Token rightBracket;
-
-  /**
-   * Initialize a newly created list of type parameters.
-   */
-  TypeParameterList(
-      this.leftBracket, List<TypeParameter> typeParameters, this.rightBracket) {
-    _typeParameters = new NodeList<TypeParameter>(this, typeParameters);
-  }
-
-  @override
-  Token get beginToken => leftBracket;
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(leftBracket)
-    ..addAll(_typeParameters)
-    ..add(rightBracket);
-
-  @override
-  Token get endToken => rightBracket;
-
-  /**
-   * Return the type parameters for the type.
-   */
-  NodeList<TypeParameter> get typeParameters => _typeParameters;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitTypeParameterList(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _typeParameters.accept(visitor);
-  }
-}
-
-/**
- * A directive that references a URI.
- *
- * > uriBasedDirective ::=
- * >     [ExportDirective]
- * >   | [ImportDirective]
- * >   | [PartDirective]
- */
-abstract class UriBasedDirective extends Directive {
-  /**
-   * The prefix of a URI using the `dart-ext` scheme to reference a native code
-   * library.
-   */
-  static String _DART_EXT_SCHEME = "dart-ext:";
-
-  /**
-   * The URI referenced by this directive.
-   */
-  StringLiteral _uri;
-
-  /**
-   * The content of the URI.
-   */
-  String uriContent;
-
-  /**
-   * The source to which the URI was resolved.
-   */
-  Source source;
-
-  /**
-   * Initialize a newly create URI-based directive. Either or both of the
-   * [comment] and [metadata] can be `null` if the directive does not have the
-   * corresponding attribute.
-   */
-  UriBasedDirective(
-      Comment comment, List<Annotation> metadata, StringLiteral uri)
-      : super(comment, metadata) {
-    _uri = _becomeParentOf(uri);
-  }
-
-  /**
-   * Return the URI referenced by this directive.
-   */
-  StringLiteral get uri => _uri;
-
-  /**
-   * Set the URI referenced by this directive to the given [uri].
-   */
-  void set uri(StringLiteral uri) {
-    _uri = _becomeParentOf(uri);
-  }
-
-  /**
-   * Return the element associated with the URI of this directive, or `null` if
-   * the AST structure has not been resolved or if the URI could not be
-   * resolved. Examples of the latter case include a directive that contains an
-   * invalid URL or a URL that does not exist.
-   */
-  Element get uriElement;
-
-  /**
-   * Validate this directive, but do not check for existence. Return a code
-   * indicating the problem if there is one, or `null` no problem
-   */
-  UriValidationCode validate() {
-    StringLiteral uriLiteral = uri;
-    if (uriLiteral is StringInterpolation) {
-      return UriValidationCode.URI_WITH_INTERPOLATION;
-    }
-    String uriContent = this.uriContent;
-    if (uriContent == null) {
-      return UriValidationCode.INVALID_URI;
-    }
-    if (this is ImportDirective && uriContent.startsWith(_DART_EXT_SCHEME)) {
-      return UriValidationCode.URI_WITH_DART_EXT_SCHEME;
-    }
-    try {
-      parseUriWithException(Uri.encodeFull(uriContent));
-    } on URISyntaxException {
-      return UriValidationCode.INVALID_URI;
-    }
-    return null;
-  }
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_uri, visitor);
-  }
-}
-
-/**
- * Validation codes returned by [UriBasedDirective.validate].
- */
-class UriValidationCode {
-  static const UriValidationCode INVALID_URI =
-      const UriValidationCode('INVALID_URI');
-
-  static const UriValidationCode URI_WITH_INTERPOLATION =
-      const UriValidationCode('URI_WITH_INTERPOLATION');
-
-  static const UriValidationCode URI_WITH_DART_EXT_SCHEME =
-      const UriValidationCode('URI_WITH_DART_EXT_SCHEME');
-
-  /**
-   * The name of the validation code.
-   */
-  final String name;
-
-  /**
-   * Initialize a newly created validation code to have the given [name].
-   */
-  const UriValidationCode(this.name);
-
-  @override
-  String toString() => name;
-}
-
-/**
- * An identifier that has an initial value associated with it. Instances of this
- * class are always children of the class [VariableDeclarationList].
- *
- * > 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.
- * Consider changing the class hierarchy so that [VariableDeclaration] does not
- * extend [Declaration].
- */
-class VariableDeclaration extends Declaration {
-  /**
-   * The name of the variable being declared.
-   */
-  SimpleIdentifier _name;
-
-  /**
-   * The equal sign separating the variable name from the initial value, or
-   * `null` if the initial value was not specified.
-   */
-  Token equals;
-
-  /**
-   * The expression used to compute the initial value for the variable, or
-   * `null` if the initial value was not specified.
-   */
-  Expression _initializer;
-
-  /**
-   * Initialize a newly created variable declaration. The [equals] and
-   * [initializer] can be `null` if there is no initializer.
-   */
-  VariableDeclaration(
-      SimpleIdentifier name, this.equals, Expression initializer)
-      : super(null, null) {
-    _name = _becomeParentOf(name);
-    _initializer = _becomeParentOf(initializer);
-  }
-
-  @override
-  Iterable get childEntities =>
-      super._childEntities..add(_name)..add(equals)..add(_initializer);
-
-  /**
-   * This overridden implementation of getDocumentationComment() looks in the
-   * grandparent node for Dartdoc comments if no documentation is specifically
-   * available on the node.
-   */
-  @override
-  Comment get documentationComment {
-    Comment comment = super.documentationComment;
-    if (comment == null) {
-      if (parent != null && parent.parent != null) {
-        AstNode node = parent.parent;
-        if (node is AnnotatedNode) {
-          return node.documentationComment;
-        }
-      }
-    }
-    return comment;
-  }
-
-  @override
-  VariableElement get element =>
-      _name != null ? (_name.staticElement as VariableElement) : null;
-
-  @override
-  Token get endToken {
-    if (_initializer != null) {
-      return _initializer.endToken;
-    }
-    return _name.endToken;
-  }
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata => _name.beginToken;
-
-  /**
-   * Return the expression used to compute the initial value for the variable,
-   * or `null` if the initial value was not specified.
-   */
-  Expression get initializer => _initializer;
-
-  /**
-   * Set the expression used to compute the initial value for the variable to
-   * the given [expression].
-   */
-  void set initializer(Expression expression) {
-    _initializer = _becomeParentOf(expression);
-  }
-
-  /**
-   * Return `true` if this variable was declared with the 'const' modifier.
-   */
-  bool get isConst {
-    AstNode parent = this.parent;
-    return parent is VariableDeclarationList && parent.isConst;
-  }
-
-  /**
-   * Return `true` if this variable was declared with the 'final' modifier.
-   * Variables that are declared with the 'const' modifier will return `false`
-   * even though they are implicitly final.
-   */
-  bool get isFinal {
-    AstNode parent = this.parent;
-    return parent is VariableDeclarationList && parent.isFinal;
-  }
-
-  /**
-   * Return the name of the variable being declared.
-   */
-  SimpleIdentifier get name => _name;
-
-  /**
-   * Set the name of the variable being declared to the given [identifier].
-   */
-  void set name(SimpleIdentifier identifier) {
-    _name = _becomeParentOf(identifier);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitVariableDeclaration(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_name, visitor);
-    _safelyVisitChild(_initializer, visitor);
-  }
-}
-
-/**
- * The declaration of one or more variables of the same type.
- *
- * > variableDeclarationList ::=
- * >     finalConstVarOrType [VariableDeclaration] (',' [VariableDeclaration])*
- * >
- * > finalConstVarOrType ::=
- * >   | 'final' [TypeName]?
- * >   | 'const' [TypeName]?
- * >   | 'var'
- * >   | [TypeName]
- */
-class VariableDeclarationList extends AnnotatedNode {
-  /**
-   * The token representing the 'final', 'const' or 'var' keyword, or `null` if
-   * no keyword was included.
-   */
-  Token keyword;
-
-  /**
-   * The type of the variables being declared, or `null` if no type was provided.
-   */
-  TypeName _type;
-
-  /**
-   * A list containing the individual variables being declared.
-   */
-  NodeList<VariableDeclaration> _variables;
-
-  /**
-   * Initialize a newly created variable declaration list. Either or both of the
-   * [comment] and [metadata] can be `null` if the variable list does not have
-   * the corresponding attribute. The [keyword] can be `null` if a type was
-   * specified. The [type] must be `null` if the keyword is 'var'.
-   */
-  VariableDeclarationList(Comment comment, List<Annotation> metadata,
-      this.keyword, TypeName type, List<VariableDeclaration> variables)
-      : super(comment, metadata) {
-    _type = _becomeParentOf(type);
-    _variables = new NodeList<VariableDeclaration>(this, variables);
-  }
-
-  @override
-  // TODO(paulberry): include commas.
-  Iterable get childEntities => super._childEntities
-    ..add(keyword)
-    ..add(_type)
-    ..addAll(_variables);
-
-  @override
-  Token get endToken => _variables.endToken;
-
-  @override
-  Token get firstTokenAfterCommentAndMetadata {
-    if (keyword != null) {
-      return keyword;
-    } else if (_type != null) {
-      return _type.beginToken;
-    }
-    return _variables.beginToken;
-  }
-
-  /**
-   * Return `true` if the variables in this list were declared with the 'const'
-   * modifier.
-   */
-  bool get isConst =>
-      keyword is KeywordToken &&
-      (keyword as KeywordToken).keyword == Keyword.CONST;
-
-  /**
-   * Return `true` if the variables in this list were declared with the 'final'
-   * modifier. Variables that are declared with the 'const' modifier will return
-   * `false` even though they are implicitly final. (In other words, this is a
-   * syntactic check rather than a semantic check.)
-   */
-  bool get isFinal =>
-      keyword is KeywordToken &&
-      (keyword as KeywordToken).keyword == Keyword.FINAL;
-
-  /**
-   * Return the type of the variables being declared, or `null` if no type was
-   * provided.
-   */
-  TypeName get type => _type;
-
-  /**
-   * Set the type of the variables being declared to the given [typeName].
-   */
-  void set type(TypeName typeName) {
-    _type = _becomeParentOf(typeName);
-  }
-
-  /**
-   * Return a list containing the individual variables being declared.
-   */
-  NodeList<VariableDeclaration> get variables => _variables;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitVariableDeclarationList(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    super.visitChildren(visitor);
-    _safelyVisitChild(_type, visitor);
-    _variables.accept(visitor);
-  }
-}
-
-/**
- * A list of variables that are being declared in a context where a statement is
- * required.
- *
- * > variableDeclarationStatement ::=
- * >     [VariableDeclarationList] ';'
- */
-class VariableDeclarationStatement extends Statement {
-  /**
-   * The variables being declared.
-   */
-  VariableDeclarationList _variableList;
-
-  /**
-   * The semicolon terminating the statement.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created variable declaration statement.
-   */
-  VariableDeclarationStatement(
-      VariableDeclarationList variableList, this.semicolon) {
-    _variableList = _becomeParentOf(variableList);
-  }
-
-  @override
-  Token get beginToken => _variableList.beginToken;
-
-  @override
-  Iterable get childEntities =>
-      new ChildEntities()..add(_variableList)..add(semicolon);
-
-  @override
-  Token get endToken => semicolon;
-
-  /**
-   * Return the variables being declared.
-   */
-  VariableDeclarationList get variables => _variableList;
-
-  /**
-   * Set the variables being declared to the given list of [variables].
-   */
-  void set variables(VariableDeclarationList variables) {
-    _variableList = _becomeParentOf(variables);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitVariableDeclarationStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_variableList, visitor);
-  }
-}
-
-/**
- * A while statement.
- *
- * > whileStatement ::=
- * >     'while' '(' [Expression] ')' [Statement]
- */
-class WhileStatement extends Statement {
-  /**
-   * The token representing the 'while' keyword.
-   */
-  Token whileKeyword;
-
-  /**
-   * The left parenthesis.
-   */
-  Token leftParenthesis;
-
-  /**
-   * The expression used to determine whether to execute the body of the loop.
-   */
-  Expression _condition;
-
-  /**
-   * The right parenthesis.
-   */
-  Token rightParenthesis;
-
-  /**
-   * The body of the loop.
-   */
-  Statement _body;
-
-  /**
-   * Initialize a newly created while statement.
-   */
-  WhileStatement(this.whileKeyword, this.leftParenthesis, Expression condition,
-      this.rightParenthesis, Statement body) {
-    _condition = _becomeParentOf(condition);
-    _body = _becomeParentOf(body);
-  }
-
-  @override
-  Token get beginToken => whileKeyword;
-
-  /**
-   * Return the body of the loop.
-   */
-  Statement get body => _body;
-
-  /**
-   * Set the body of the loop to the given [statement].
-   */
-  void set body(Statement statement) {
-    _body = _becomeParentOf(statement);
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(whileKeyword)
-    ..add(leftParenthesis)
-    ..add(_condition)
-    ..add(rightParenthesis)
-    ..add(_body);
-
-  /**
-   * Return the expression used to determine whether to execute the body of the
-   * loop.
-   */
-  Expression get condition => _condition;
-
-  /**
-   * Set the expression used to determine whether to execute the body of the
-   * loop to the given [expression].
-   */
-  void set condition(Expression expression) {
-    _condition = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get endToken => _body.endToken;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitWhileStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_condition, visitor);
-    _safelyVisitChild(_body, visitor);
-  }
-}
-
-/**
- * The with clause in a class declaration.
- *
- * > withClause ::=
- * >     'with' [TypeName] (',' [TypeName])*
- */
-class WithClause extends AstNode {
-  /**
-   * The token representing the 'with' keyword.
-   */
-  Token withKeyword;
-
-  /**
-   * The names of the mixins that were specified.
-   */
-  NodeList<TypeName> _mixinTypes;
-
-  /**
-   * Initialize a newly created with clause.
-   */
-  WithClause(this.withKeyword, List<TypeName> mixinTypes) {
-    _mixinTypes = new NodeList<TypeName>(this, mixinTypes);
-  }
-
-  @override
-  Token get beginToken => withKeyword;
-
-  @override
-  // TODO(paulberry): add commas.
-  Iterable get childEntities => new ChildEntities()
-    ..add(withKeyword)
-    ..addAll(_mixinTypes);
-
-  @override
-  Token get endToken => _mixinTypes.endToken;
-
-  /**
-   * Return the names of the mixins that were specified.
-   */
-  NodeList<TypeName> get mixinTypes => _mixinTypes;
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitWithClause(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _mixinTypes.accept(visitor);
-  }
-}
-
-/**
- * A yield statement.
- *
- * > yieldStatement ::=
- * >     'yield' '*'? [Expression] ‘;’
- */
-class YieldStatement extends Statement {
-  /**
-   * The 'yield' keyword.
-   */
-  Token yieldKeyword;
-
-  /**
-   * The star optionally following the 'yield' keyword.
-   */
-  Token star;
-
-  /**
-   * The expression whose value will be yielded.
-   */
-  Expression _expression;
-
-  /**
-   * The semicolon following the expression.
-   */
-  Token semicolon;
-
-  /**
-   * Initialize a newly created yield expression. The [star] can be `null` if no
-   * star was provided.
-   */
-  YieldStatement(
-      this.yieldKeyword, this.star, Expression expression, this.semicolon) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  Token get beginToken {
-    if (yieldKeyword != null) {
-      return yieldKeyword;
-    }
-    return _expression.beginToken;
-  }
-
-  @override
-  Iterable get childEntities => new ChildEntities()
-    ..add(yieldKeyword)
-    ..add(star)
-    ..add(_expression)
-    ..add(semicolon);
-
-  @override
-  Token get endToken {
-    if (semicolon != null) {
-      return semicolon;
-    }
-    return _expression.endToken;
-  }
-
-  /**
-   * Return the expression whose value will be yielded.
-   */
-  Expression get expression => _expression;
-
-  /**
-   * Set the expression whose value will be yielded to the given [expression].
-   */
-  void set expression(Expression expression) {
-    _expression = _becomeParentOf(expression);
-  }
-
-  @override
-  accept(AstVisitor visitor) => visitor.visitYieldStatement(this);
-
-  @override
-  void visitChildren(AstVisitor visitor) {
-    _safelyVisitChild(_expression, visitor);
-  }
-}
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index a561978..8d4de8e 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -6,18 +6,22 @@
 
 import 'dart:collection';
 
+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/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element_handle.dart'
+    show ConstructorElementHandle;
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisEngine, RecordingErrorListener;
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
-import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType;
 import 'package:analyzer/src/generated/source.dart' show Source;
 import 'package:analyzer/src/generated/type_system.dart'
     show TypeSystem, TypeSystemImpl;
@@ -26,6 +30,16 @@
 import 'package:analyzer/src/generated/utilities_general.dart';
 import 'package:analyzer/src/task/dart.dart';
 
+ConstructorElementImpl _getConstructorImpl(ConstructorElement constructor) {
+  while (constructor is ConstructorMember) {
+    constructor = (constructor as ConstructorMember).baseElement;
+  }
+  if (constructor is ConstructorElementHandle) {
+    constructor = (constructor as ConstructorElementHandle).actualElement;
+  }
+  return constructor;
+}
+
 /**
  * Callback used by [ReferenceFinder] to report that a dependency was found.
  */
@@ -157,6 +171,13 @@
   ConstantAstCloner() : super(true);
 
   @override
+  ConstructorName visitConstructorName(ConstructorName node) {
+    ConstructorName name = super.visitConstructorName(node);
+    name.staticElement = node.staticElement;
+    return name;
+  }
+
+  @override
   InstanceCreationExpression visitInstanceCreationExpression(
       InstanceCreationExpression node) {
     InstanceCreationExpression expression =
@@ -228,7 +249,7 @@
   final TypeProvider typeProvider;
 
   /**
-   * The type system.  This is used to gues the types of constants when their
+   * The type system.  This is used to guess the types of constants when their
    * exact value is unknown.
    */
   final TypeSystem typeSystem;
@@ -330,17 +351,15 @@
   void computeConstantValue(ConstantEvaluationTarget constant) {
     validator.beforeComputeValue(constant);
     if (constant is ParameterElementImpl) {
-      if (constant.initializer != null) {
-        Expression defaultValue = constant.constantInitializer;
-        if (defaultValue != null) {
-          RecordingErrorListener errorListener = new RecordingErrorListener();
-          ErrorReporter errorReporter =
-              new ErrorReporter(errorListener, constant.source);
-          DartObjectImpl dartObject =
-              defaultValue.accept(new ConstantVisitor(this, errorReporter));
-          constant.evaluationResult =
-              new EvaluationResultImpl(dartObject, errorListener.errors);
-        }
+      Expression defaultValue = constant.constantInitializer;
+      if (defaultValue != null) {
+        RecordingErrorListener errorListener = new RecordingErrorListener();
+        ErrorReporter errorReporter =
+            new ErrorReporter(errorListener, constant.source);
+        DartObjectImpl dartObject =
+            defaultValue.accept(new ConstantVisitor(this, errorReporter));
+        constant.evaluationResult =
+            new EvaluationResultImpl(dartObject, errorListener.errors);
       }
     } else if (constant is VariableElementImpl) {
       Expression constantInitializer = constant.constantInitializer;
@@ -375,57 +394,49 @@
         // code will know that it is safe to evaluate.
         (constant as ConstructorElementImpl).isCycleFree = true;
       }
-    } else if (constant is ConstantEvaluationTarget_Annotation) {
-      Annotation constNode = constant.annotation;
-      ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation;
-      // elementAnnotation is null if the annotation couldn't be resolved, in
-      // which case we skip it.
-      if (elementAnnotation != null) {
-        Element element = elementAnnotation.element;
-        if (element is PropertyAccessorElement &&
-            element.variable is VariableElementImpl) {
-          // The annotation is a reference to a compile-time constant variable.
-          // Just copy the evaluation result.
-          VariableElementImpl variableElement =
-              element.variable as VariableElementImpl;
-          if (variableElement.evaluationResult != null) {
-            elementAnnotation.evaluationResult =
-                variableElement.evaluationResult;
-          } else {
-            // This could happen in the event that the annotation refers to a
-            // non-constant.  The error is detected elsewhere, so just silently
-            // ignore it here.
-            elementAnnotation.evaluationResult = new EvaluationResultImpl(null);
-          }
-        } else if (element is ConstructorElementImpl &&
-            element.isConst &&
-            constNode.arguments != null) {
-          RecordingErrorListener errorListener = new RecordingErrorListener();
-          CompilationUnit sourceCompilationUnit =
-              constNode.getAncestor((node) => node is CompilationUnit);
-          ErrorReporter errorReporter = new ErrorReporter(
-              errorListener, sourceCompilationUnit.element.source);
-          ConstantVisitor constantVisitor =
-              new ConstantVisitor(this, errorReporter);
-          DartObjectImpl result = evaluateConstructorCall(
-              constNode,
-              constNode.arguments.arguments,
-              element,
-              constantVisitor,
-              errorReporter);
-          elementAnnotation.evaluationResult =
-              new EvaluationResultImpl(result, errorListener.errors);
+    } else if (constant is ElementAnnotationImpl) {
+      Annotation constNode = constant.annotationAst;
+      Element element = constant.element;
+      if (element is PropertyAccessorElement &&
+          element.variable is VariableElementImpl) {
+        // The annotation is a reference to a compile-time constant variable.
+        // Just copy the evaluation result.
+        VariableElementImpl variableElement =
+            element.variable as VariableElementImpl;
+        if (variableElement.evaluationResult != null) {
+          constant.evaluationResult = variableElement.evaluationResult;
         } else {
-          // This may happen for invalid code (e.g. failing to pass arguments
-          // to an annotation which references a const constructor).  The error
-          // is detected elsewhere, so just silently ignore it here.
-          elementAnnotation.evaluationResult = new EvaluationResultImpl(null);
+          // This could happen in the event that the annotation refers to a
+          // non-constant.  The error is detected elsewhere, so just silently
+          // ignore it here.
+          constant.evaluationResult = new EvaluationResultImpl(null);
         }
+      } else if (element is ConstructorElementImpl &&
+          element.isConst &&
+          constNode.arguments != null) {
+        RecordingErrorListener errorListener = new RecordingErrorListener();
+        ErrorReporter errorReporter =
+            new ErrorReporter(errorListener, constant.source);
+        ConstantVisitor constantVisitor =
+            new ConstantVisitor(this, errorReporter);
+        DartObjectImpl result = evaluateConstructorCall(
+            constNode,
+            constNode.arguments.arguments,
+            element,
+            constantVisitor,
+            errorReporter);
+        constant.evaluationResult =
+            new EvaluationResultImpl(result, errorListener.errors);
+      } else {
+        // This may happen for invalid code (e.g. failing to pass arguments
+        // to an annotation which references a const constructor).  The error
+        // is detected elsewhere, so just silently ignore it here.
+        constant.evaluationResult = new EvaluationResultImpl(null);
       }
     } else if (constant is VariableElement) {
       // constant is a VariableElement but not a VariableElementImpl.  This can
       // happen sometimes in the case of invalid user code (for example, a
-      // constant expression that refers to a nonstatic field inside a generic
+      // constant expression that refers to a non-static field inside a generic
       // class will wind up referring to a FieldMember).  The error is detected
       // elsewhere, so just silently ignore it here.
     } else {
@@ -441,25 +452,14 @@
    * Determine which constant elements need to have their values computed
    * prior to computing the value of [constant], and report them using
    * [callback].
-   *
-   * Note that it's possible (in erroneous code) for a constant to depend on a
-   * non-constant.  When this happens, we report the dependency anyhow so that
-   * if the non-constant changes to a constant, we will know to recompute the
-   * thing that depends on it.  [computeDependencies] and
-   * [computeConstantValue] are responsible for ignoring the request if they
-   * are asked to act on a non-constant target.
    */
   void computeDependencies(
       ConstantEvaluationTarget constant, ReferenceFinderCallback callback) {
     ReferenceFinder referenceFinder = new ReferenceFinder(callback);
-    if (constant is ParameterElementImpl) {
-      if (constant.initializer != null) {
-        Expression defaultValue = constant.constantInitializer;
-        if (defaultValue != null) {
-          defaultValue.accept(referenceFinder);
-        }
-      }
-    } else if (constant is VariableElementImpl) {
+    if (constant is ConstructorElement) {
+      constant = _getConstructorImpl(constant);
+    }
+    if (constant is VariableElementImpl) {
       Expression initializer = constant.constantInitializer;
       if (initializer != null) {
         initializer.accept(referenceFinder);
@@ -471,8 +471,7 @@
             getConstRedirectedConstructor(constant);
         if (redirectedConstructor != null) {
           ConstructorElement redirectedConstructorBase =
-              ConstantEvaluationEngine
-                  ._getConstructorBase(redirectedConstructor);
+              _getConstructorImpl(redirectedConstructor);
           callback(redirectedConstructorBase);
           return;
         } else if (constant.isFactory) {
@@ -500,8 +499,8 @@
           InterfaceType superclass =
               (constant.returnType as InterfaceType).superclass;
           if (superclass != null && !superclass.isObject) {
-            ConstructorElement unnamedConstructor = ConstantEvaluationEngine
-                ._getConstructorBase(superclass.element.unnamedConstructor);
+            ConstructorElement unnamedConstructor =
+                _getConstructorImpl(superclass.element.unnamedConstructor);
             if (unnamedConstructor != null) {
               callback(unnamedConstructor);
             }
@@ -520,26 +519,21 @@
           callback(parameterElement);
         }
       }
-    } else if (constant is ConstantEvaluationTarget_Annotation) {
-      Annotation constNode = constant.annotation;
-      ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation;
-      // elementAnnotation is null if the annotation couldn't be resolved, in
-      // which case we skip it.
-      if (elementAnnotation != null) {
-        Element element = elementAnnotation.element;
-        if (element is PropertyAccessorElement &&
-            element.variable is VariableElementImpl) {
-          // The annotation is a reference to a compile-time constant variable,
-          // so it depends on the variable.
-          callback(element.variable);
-        } else if (element is ConstructorElementImpl) {
-          // The annotation is a constructor invocation, so it depends on the
-          // constructor.
-          callback(element);
-        } else {
-          // This could happen in the event of invalid code.  The error will be
-          // reported at constant evaluation time.
-        }
+    } else if (constant is ElementAnnotationImpl) {
+      Annotation constNode = constant.annotationAst;
+      Element element = constant.element;
+      if (element is PropertyAccessorElement &&
+          element.variable is VariableElementImpl) {
+        // The annotation is a reference to a compile-time constant variable,
+        // so it depends on the variable.
+        callback(element.variable);
+      } else if (element is ConstructorElementImpl) {
+        // The annotation is a constructor invocation, so it depends on the
+        // constructor.
+        callback(element);
+      } else {
+        // This could happen in the event of invalid code.  The error will be
+        // reported at constant evaluation time.
       }
       if (constNode.arguments != null) {
         constNode.arguments.accept(referenceFinder);
@@ -547,7 +541,7 @@
     } else if (constant is VariableElement) {
       // constant is a VariableElement but not a VariableElementImpl.  This can
       // happen sometimes in the case of invalid user code (for example, a
-      // constant expression that refers to a nonstatic field inside a generic
+      // constant expression that refers to a non-static field inside a generic
       // class will wind up referring to a FieldMember).  So just don't bother
       // computing any dependencies.
     } else {
@@ -601,7 +595,7 @@
       ConstructorElement constructor,
       ConstantVisitor constantVisitor,
       ErrorReporter errorReporter) {
-    if (!_getConstructorBase(constructor).isCycleFree) {
+    if (!_getConstructorImpl(constructor).isCycleFree) {
       // It's not safe to evaluate this constructor, so bail out.
       // TODO(paulberry): ensure that a reasonable error message is produced
       // in this case, as well as other cases involving constant expression
@@ -691,7 +685,7 @@
       // it an unknown value will suppress further errors.
       return new DartObjectImpl.validWithUnknownValue(definingClass);
     }
-    ConstructorElementImpl constructorBase = _getConstructorBase(constructor);
+    ConstructorElementImpl constructorBase = _getConstructorImpl(constructor);
     validator.beforeGetConstantInitializers(constructorBase);
     List<ConstructorInitializer> initializers =
         constructorBase.constantInitializers;
@@ -909,10 +903,10 @@
       if (redirectedConstructor == null) {
         break;
       } else {
-        ConstructorElement constructorBase = _getConstructorBase(constructor);
+        ConstructorElement constructorBase = _getConstructorImpl(constructor);
         constructorsVisited.add(constructorBase);
         ConstructorElement redirectedConstructorBase =
-            _getConstructorBase(redirectedConstructor);
+            _getConstructorImpl(redirectedConstructor);
         if (constructorsVisited.contains(redirectedConstructorBase)) {
           // Cycle in redirecting factory constructors--this is not allowed
           // and is checked elsewhere--see
@@ -1010,47 +1004,6 @@
       name.isEmpty ||
       name == "void" ||
       new JavaPatternMatcher(_PUBLIC_SYMBOL_PATTERN, name).matches();
-
-  static ConstructorElementImpl _getConstructorBase(
-      ConstructorElement constructor) {
-    while (constructor is ConstructorMember) {
-      constructor = (constructor as ConstructorMember).baseElement;
-    }
-    return constructor;
-  }
-}
-
-/**
- * Wrapper around an [Annotation] which can be used as a
- * [ConstantEvaluationTarget].
- */
-class ConstantEvaluationTarget_Annotation implements ConstantEvaluationTarget {
-  final AnalysisContext context;
-  final Source source;
-  final Source librarySource;
-  final Annotation annotation;
-
-  ConstantEvaluationTarget_Annotation(
-      this.context, this.source, this.librarySource, this.annotation);
-
-  @override
-  int get hashCode => JenkinsSmiHash.hash3(
-      source.hashCode, librarySource.hashCode, annotation.hashCode);
-
-  @override
-  bool operator ==(other) {
-    if (other is ConstantEvaluationTarget_Annotation) {
-      return this.context == other.context &&
-          this.source == other.source &&
-          this.librarySource == other.librarySource &&
-          this.annotation == other.annotation;
-    } else {
-      return false;
-    }
-  }
-
-  @override
-  String toString() => 'Constant: $annotation';
 }
 
 /**
@@ -1295,8 +1248,8 @@
   /**
    * The elements and AST nodes whose constant values need to be computed.
    */
-  HashSet<ConstantEvaluationTarget> constantsToCompute =
-      new HashSet<ConstantEvaluationTarget>();
+  List<ConstantEvaluationTarget> constantsToCompute =
+      <ConstantEvaluationTarget>[];
 
   /**
    * True if instance variables marked as "final" should be treated as "const".
@@ -1308,9 +1261,13 @@
   @override
   Object visitAnnotation(Annotation node) {
     super.visitAnnotation(node);
-    AnalysisContext owningContext = _getOwningContext();
-    constantsToCompute.add(new ConstantEvaluationTarget_Annotation(
-        owningContext, source, librarySource, node));
+    ElementAnnotation elementAnnotation = node.elementAnnotation;
+    if (elementAnnotation == null) {
+      // Analyzer ignores annotations on "part of" directives.
+      assert(node.parent is PartOfDirective);
+    } else {
+      constantsToCompute.add(elementAnnotation);
+    }
     return null;
   }
 
@@ -1370,14 +1327,6 @@
     }
     return null;
   }
-
-  AnalysisContext _getOwningContext() {
-    if (context is InternalAnalysisContext) {
-      InternalAnalysisContext internalContext = context;
-      return internalContext.getContextFor(librarySource);
-    }
-    return context;
-  }
 }
 
 /**
@@ -1616,7 +1565,9 @@
     DartObjectImpl rightResult = node.rightOperand.accept(this);
     TokenType operatorType = node.operator.type;
     // 'null' is almost never good operand
-    if (operatorType != TokenType.BANG_EQ && operatorType != TokenType.EQ_EQ) {
+    if (operatorType != TokenType.BANG_EQ &&
+        operatorType != TokenType.EQ_EQ &&
+        operatorType != TokenType.QUESTION_QUESTION) {
       if (leftResult != null && leftResult.isNull ||
           rightResult != null && rightResult.isNull) {
         _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
@@ -1665,6 +1616,9 @@
         return _dartObjectComputer.divide(node, leftResult, rightResult);
       } else if (operatorType == TokenType.TILDE_SLASH) {
         return _dartObjectComputer.integerDivide(node, leftResult, rightResult);
+      } else if (operatorType == TokenType.QUESTION_QUESTION) {
+        return _dartObjectComputer.questionQuestion(
+            node, leftResult, rightResult);
       } else {
         // TODO(brianwilkerson) Figure out which error to report.
         _error(node, null);
@@ -1792,8 +1746,8 @@
       return null;
     }
     bool errorOccurred = false;
-    HashMap<DartObjectImpl, DartObjectImpl> map =
-        new HashMap<DartObjectImpl, DartObjectImpl>();
+    LinkedHashMap<DartObjectImpl, DartObjectImpl> map =
+        new LinkedHashMap<DartObjectImpl, DartObjectImpl>();
     for (MapLiteralEntry entry in node.entries) {
       DartObjectImpl keyResult = entry.key.accept(this);
       DartObjectImpl valueResult = entry.value.accept(this);
@@ -2461,6 +2415,17 @@
     return null;
   }
 
+  DartObjectImpl questionQuestion(Expression node, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (leftOperand != null && rightOperand != null) {
+      if (leftOperand.isNull) {
+        return rightOperand;
+      }
+      return leftOperand;
+    }
+    return null;
+  }
+
   DartObjectImpl remainder(BinaryExpression node, DartObjectImpl leftOperand,
       DartObjectImpl rightOperand) {
     if (leftOperand != null && rightOperand != null) {
@@ -2540,6 +2505,7 @@
   /**
    * The run-time type of this object.
    */
+  @override
   final ParameterizedType type;
 
   /**
@@ -5195,8 +5161,7 @@
   @override
   Object visitInstanceCreationExpression(InstanceCreationExpression node) {
     if (node.isConst) {
-      ConstructorElement constructor =
-          ConstantEvaluationEngine._getConstructorBase(node.staticElement);
+      ConstructorElement constructor = _getConstructorImpl(node.staticElement);
       if (constructor != null) {
         _callback(constructor);
       }
@@ -5218,8 +5183,7 @@
   Object visitRedirectingConstructorInvocation(
       RedirectingConstructorInvocation node) {
     super.visitRedirectingConstructorInvocation(node);
-    ConstructorElement target =
-        ConstantEvaluationEngine._getConstructorBase(node.staticElement);
+    ConstructorElement target = _getConstructorImpl(node.staticElement);
     if (target != null) {
       _callback(target);
     }
@@ -5232,7 +5196,7 @@
     if (element is PropertyAccessorElement) {
       element = (element as PropertyAccessorElement).variable;
     }
-    if (element is VariableElement) {
+    if (element is VariableElement && element.isConst) {
       _callback(element);
     }
     return null;
@@ -5241,8 +5205,7 @@
   @override
   Object visitSuperConstructorInvocation(SuperConstructorInvocation node) {
     super.visitSuperConstructorInvocation(node);
-    ConstructorElement constructor =
-        ConstantEvaluationEngine._getConstructorBase(node.staticElement);
+    ConstructorElement constructor = _getConstructorImpl(node.staticElement);
     if (constructor != null) {
       _callback(constructor);
     }
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 968d797..4ff96d5 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -9,7 +9,7 @@
  * * package:analyzer/dart/element/type.dart
  * * package:analyzer/dart/element/visitor.dart
  *
- * If your code is using API's not available in these public libraries, please
+ * If your code is using APIs not available in these public libraries, please
  * contact the analyzer team to either find an alternate API or have the API you
  * depend on added to the public API.
  */
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 0a29cfb..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/src/generated/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
@@ -754,6 +757,9 @@
   bool get isBrowserApplication => actualElement.isBrowserApplication;
 
   @override
+  bool get isDartAsync => actualElement.isDartAsync;
+
+  @override
   bool get isDartCore => actualElement.isDartCore;
 
   @override
@@ -763,6 +769,9 @@
   ElementKind get kind => ElementKind.LIBRARY;
 
   @override
+  List<LibraryElement> get libraryCycle => actualElement.libraryCycle;
+
+  @override
   FunctionElement get loadLibraryFunction => actualElement.loadLibraryFunction;
 
   @override
@@ -912,7 +921,7 @@
       super.enclosingElement as LibraryElement;
 
   @override
-  List<LibraryElement> get importedLibraries => actualElement.importedLibraries;
+  List<LibraryElement> get importedLibraries => LibraryElement.EMPTY_LIST;
 
   @override
   ElementKind get kind => ElementKind.PREFIX;
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 368da2a..a9a3881 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -6,15 +6,18 @@
 
 import 'dart:collection';
 
+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/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart'
+    show ChildEntities, IdentifierImpl;
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart' as sc;
 
 /**
  * An object used by instances of [ResolverVisitor] to resolve references within
@@ -146,10 +149,10 @@
 
   @override
   Object visitAssignmentExpression(AssignmentExpression node) {
-    sc.Token operator = node.operator;
-    sc.TokenType operatorType = operator.type;
-    if (operatorType != sc.TokenType.EQ &&
-        operatorType != sc.TokenType.QUESTION_QUESTION_EQ) {
+    Token operator = node.operator;
+    TokenType operatorType = operator.type;
+    if (operatorType != TokenType.EQ &&
+        operatorType != TokenType.QUESTION_QUESTION_EQ) {
       operatorType = _operatorFromCompoundAssignment(operatorType);
       Expression leftHandSide = node.leftHandSide;
       if (leftHandSide != null) {
@@ -185,11 +188,11 @@
 
   @override
   Object visitBinaryExpression(BinaryExpression node) {
-    sc.Token operator = node.operator;
+    Token operator = node.operator;
     if (operator.isUserDefinableOperator) {
       _resolveBinaryExpression(node, operator.lexeme);
-    } else if (operator.type == sc.TokenType.BANG_EQ) {
-      _resolveBinaryExpression(node, sc.TokenType.EQ_EQ.lexeme);
+    } else if (operator.type == TokenType.BANG_EQ) {
+      _resolveBinaryExpression(node, TokenType.EQ_EQ.lexeme);
     }
     return null;
   }
@@ -202,13 +205,13 @@
 
   @override
   Object visitClassDeclaration(ClassDeclaration node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
   @override
   Object visitClassTypeAlias(ClassTypeAlias node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
@@ -333,7 +336,7 @@
           }
         }
       }
-      setMetadata(constructorElement, node);
+      resolveMetadata(node);
     }
     return null;
   }
@@ -389,13 +392,13 @@
 
   @override
   Object visitDeclaredIdentifier(DeclaredIdentifier node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
   @override
   Object visitEnumDeclaration(EnumDeclaration node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
@@ -407,29 +410,29 @@
       // TODO(brianwilkerson) Figure out whether the element can ever be
       // something other than an ExportElement
       _resolveCombinators(exportElement.exportedLibrary, node.combinators);
-      setMetadata(exportElement, node);
+      resolveMetadata(node);
     }
     return null;
   }
 
   @override
   Object visitFieldFormalParameter(FieldFormalParameter node) {
-    _setMetadataForParameter(node.element, node);
+    _resolveMetadataForParameter(node.element, node);
     return super.visitFieldFormalParameter(node);
   }
 
   @override
   Object visitFunctionDeclaration(FunctionDeclaration node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
   @override
   Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
     Expression function = node.function;
-    DartType staticInvokeType =
-        _resolveGenericMethod(function.staticType, node.typeArguments, node);
-    DartType propagatedInvokeType = _resolveGenericMethod(
+    DartType staticInvokeType = _instantiateGenericMethod(
+        function.staticType, node.typeArguments, node);
+    DartType propagatedInvokeType = _instantiateGenericMethod(
         function.propagatedType, node.typeArguments, node);
 
     node.staticInvokeType = staticInvokeType;
@@ -452,13 +455,13 @@
 
   @override
   Object visitFunctionTypeAlias(FunctionTypeAlias node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
   @override
   Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
-    _setMetadataForParameter(node.element, node);
+    _resolveMetadataForParameter(node.element, node);
     return null;
   }
 
@@ -481,7 +484,7 @@
       if (library != null) {
         _resolveCombinators(library, node.combinators);
       }
-      setMetadata(importElement, node);
+      resolveMetadata(node);
     }
     return null;
   }
@@ -491,8 +494,8 @@
     Expression target = node.realTarget;
     DartType staticType = _getStaticType(target);
     DartType propagatedType = _getPropagatedType(target);
-    String getterMethodName = sc.TokenType.INDEX.lexeme;
-    String setterMethodName = sc.TokenType.INDEX_EQ.lexeme;
+    String getterMethodName = TokenType.INDEX.lexeme;
+    String setterMethodName = TokenType.INDEX_EQ.lexeme;
     bool isInGetterContext = node.inGetterContext();
     bool isInSetterContext = node.inSetterContext();
     if (isInGetterContext && isInSetterContext) {
@@ -574,13 +577,13 @@
 
   @override
   Object visitLibraryDirective(LibraryDirective node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
   @override
   Object visitMethodDeclaration(MethodDeclaration node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
@@ -609,14 +612,16 @@
       propagatedElement = null;
     } else if (methodName.name == FunctionElement.LOAD_LIBRARY_NAME &&
         _isDeferredPrefix(target)) {
-      if (node.operator.type == sc.TokenType.QUESTION_PERIOD) {
+      if (node.operator.type == TokenType.QUESTION_PERIOD) {
         _resolver.reportErrorForNode(
             CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
             target,
             [(target as SimpleIdentifier).name]);
       }
       LibraryElement importedLibrary = _getImportedLibrary(target);
-      methodName.staticElement = importedLibrary.loadLibraryFunction;
+      FunctionElement loadLibraryFunction = importedLibrary.loadLibraryFunction;
+      methodName.staticElement = loadLibraryFunction;
+      node.staticInvokeType = loadLibraryFunction.type;
       return null;
     } else {
       //
@@ -625,7 +630,7 @@
       // hierarchy, instead we just look for the member in the type only.  This
       // does not apply to conditional method invocation (i.e. 'C?.m(...)').
       //
-      bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
+      bool isConditional = node.operator.type == TokenType.QUESTION_PERIOD;
       ClassElementImpl typeReference = getTypeReference(target);
       if (typeReference != null) {
         if (node.isCascaded) {
@@ -650,9 +655,23 @@
     staticElement = _convertSetterToGetter(staticElement);
     propagatedElement = _convertSetterToGetter(propagatedElement);
 
-    DartType staticInvokeType = _computeMethodInvokeType(node, staticElement);
-    DartType propagatedInvokeType =
-        _computeMethodInvokeType(node, propagatedElement);
+    //
+    // Given the elements, determine the type of the function we are invoking
+    //
+    DartType staticInvokeType = _getInvokeType(staticElement);
+    methodName.staticType = staticInvokeType;
+
+    DartType propagatedInvokeType = _getInvokeType(propagatedElement);
+    methodName.propagatedType =
+        _propagatedInvokeTypeIfBetter(propagatedInvokeType, staticInvokeType);
+
+    //
+    // Instantiate generic function or method if needed.
+    //
+    staticInvokeType = _instantiateGenericMethod(
+        staticInvokeType, node.typeArguments, node.methodName);
+    propagatedInvokeType = _instantiateGenericMethod(
+        propagatedInvokeType, node.typeArguments, node.methodName);
 
     //
     // Record the results.
@@ -802,13 +821,7 @@
 
   @override
   Object visitPartDirective(PartDirective node) {
-    setMetadata(node.element, node);
-    return null;
-  }
-
-  @override
-  Object visitPartOfDirective(PartOfDirective node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
@@ -921,11 +934,11 @@
 
   @override
   Object visitPrefixExpression(PrefixExpression node) {
-    sc.Token operator = node.operator;
-    sc.TokenType operatorType = operator.type;
+    Token operator = node.operator;
+    TokenType operatorType = operator.type;
     if (operatorType.isUserDefinableOperator ||
-        operatorType == sc.TokenType.PLUS_PLUS ||
-        operatorType == sc.TokenType.MINUS_MINUS) {
+        operatorType == TokenType.PLUS_PLUS ||
+        operatorType == TokenType.MINUS_MINUS) {
       Expression operand = node.operand;
       String methodName = _getPrefixOperator(node);
       DartType staticType = _getStaticType(operand);
@@ -1010,7 +1023,7 @@
 
   @override
   Object visitSimpleFormalParameter(SimpleFormalParameter node) {
-    _setMetadataForParameter(node.element, node);
+    _resolveMetadataForParameter(node.element, node);
     return null;
   }
 
@@ -1164,13 +1177,13 @@
 
   @override
   Object visitTypeParameter(TypeParameter node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
   @override
   Object visitVariableDeclaration(VariableDeclaration node) {
-    setMetadata(node.element, node);
+    resolveMetadata(node);
     return null;
   }
 
@@ -1287,8 +1300,8 @@
                 propagatedType.element, methodName, true, false);
     if (shouldReportMissingMember_static ||
         shouldReportMissingMember_propagated) {
-      sc.Token leftBracket = expression.leftBracket;
-      sc.Token rightBracket = expression.rightBracket;
+      Token leftBracket = expression.leftBracket;
+      Token rightBracket = expression.rightBracket;
       ErrorCode errorCode;
       if (shouldReportMissingMember_static) {
         if (target is SuperExpression) {
@@ -1336,30 +1349,6 @@
     return null;
   }
 
-  DartType _computeMethodInvokeType(MethodInvocation node, Element element) {
-    if (element == null) {
-      // TODO(jmesserly): should we return `dynamic` in this case?
-      // Otherwise we have to guard against `null` every time we use
-      // `staticInvokeType`.
-      // If we do return `dynamic` we need to be careful that this doesn't
-      // adversely affect propagatedType code path. But it shouldn't because
-      // we'll discard `dynamic` anyway (see _propagatedInvokeTypeIfBetter).
-      return null;
-    }
-
-    DartType invokeType;
-    if (element is PropertyAccessorElement) {
-      invokeType = element.returnType;
-    } else if (element is ExecutableElement) {
-      invokeType = element.type;
-    } else if (element is VariableElement) {
-      invokeType = _promoteManager.getStaticType(element);
-    }
-
-    return _resolveGenericMethod(
-        invokeType, node.typeArguments, node.methodName);
-  }
-
   /**
    * If the given [element] is a setter, return the getter associated with it.
    * Otherwise, return the element unchanged.
@@ -1437,24 +1426,46 @@
   }
 
   /**
+   * Given an element, computes the type of the invocation.
+   *
+   * For executable elements (like methods, functions) this is just their type.
+   *
+   * For variables it is their type taking into account any type promotion.
+   *
+   * For calls to getters in Dart, we invoke the function that is returned by
+   * the getter, so the invoke type is the getter's returnType.
+   */
+  DartType _getInvokeType(Element element) {
+    DartType invokeType;
+    if (element is PropertyAccessorElement) {
+      invokeType = element.returnType;
+    } else if (element is ExecutableElement) {
+      invokeType = element.type;
+    } else if (element is VariableElement) {
+      invokeType = _promoteManager.getStaticType(element);
+    }
+    return invokeType ?? DynamicTypeImpl.instance;
+  }
+
+  /**
    * Return the name of the method invoked by the given postfix [expression].
    */
   String _getPostfixOperator(PostfixExpression expression) =>
-      (expression.operator.type == sc.TokenType.PLUS_PLUS)
-          ? sc.TokenType.PLUS.lexeme
-          : sc.TokenType.MINUS.lexeme;
+      (expression.operator.type == TokenType.PLUS_PLUS)
+          ? TokenType.PLUS.lexeme
+          : TokenType.MINUS.lexeme;
 
   /**
    * Return the name of the method invoked by the given postfix [expression].
    */
   String _getPrefixOperator(PrefixExpression expression) {
-    sc.Token operator = expression.operator;
-    sc.TokenType operatorType = operator.type;
-    if (operatorType == sc.TokenType.PLUS_PLUS) {
-      return sc.TokenType.PLUS.lexeme;
-    } else if (operatorType == sc.TokenType.MINUS_MINUS) {
-      return sc.TokenType.MINUS.lexeme;
-    } else if (operatorType == sc.TokenType.MINUS) {
+    Token operator = expression.operator;
+    TokenType operatorType = operator.type;
+    if (operatorType == TokenType.PLUS_PLUS) {
+      return TokenType.PLUS.lexeme;
+    } else if (operatorType == TokenType.MINUS_MINUS) {
+      return TokenType.MINUS.lexeme;
+    } else if (operatorType == TokenType.MINUS) {
       return "unary-";
     } else {
       return operator.lexeme;
@@ -1497,6 +1508,37 @@
   }
 
   /**
+   * Check for a generic method & apply type arguments if any were passed.
+   */
+  DartType _instantiateGenericMethod(
+      DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
+    // TODO(jmesserly): support generic "call" methods on InterfaceType.
+    if (invokeType is FunctionType) {
+      FunctionType type = invokeType;
+      List<TypeParameterElement> parameters = type.typeFormals;
+
+      NodeList<TypeName> arguments = typeArguments?.arguments;
+      if (arguments != null && arguments.length != parameters.length) {
+        _resolver.reportErrorForNode(
+            StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
+            node,
+            [type, parameters.length, arguments?.length ?? 0]);
+
+        // Wrong number of type arguments. Ignore them.
+        arguments = null;
+      }
+      if (parameters.isNotEmpty) {
+        if (arguments == null) {
+          invokeType = _resolver.typeSystem.instantiateToBounds(type);
+        } else {
+          invokeType = type.instantiate(arguments.map((n) => n.type).toList());
+        }
+      }
+    }
+    return invokeType;
+  }
+
+  /**
    * Return `true` if the given [expression] is a prefix for a deferred import.
    */
   bool _isDeferredPrefix(Expression expression) {
@@ -1705,30 +1747,30 @@
    * Return the binary operator that is invoked by the given compound assignment
    * [operator].
    */
-  sc.TokenType _operatorFromCompoundAssignment(sc.TokenType operator) {
+  TokenType _operatorFromCompoundAssignment(TokenType operator) {
     while (true) {
-      if (operator == sc.TokenType.AMPERSAND_EQ) {
-        return sc.TokenType.AMPERSAND;
-      } else if (operator == sc.TokenType.BAR_EQ) {
-        return sc.TokenType.BAR;
-      } else if (operator == sc.TokenType.CARET_EQ) {
-        return sc.TokenType.CARET;
-      } else if (operator == sc.TokenType.GT_GT_EQ) {
-        return sc.TokenType.GT_GT;
-      } else if (operator == sc.TokenType.LT_LT_EQ) {
-        return sc.TokenType.LT_LT;
-      } else if (operator == sc.TokenType.MINUS_EQ) {
-        return sc.TokenType.MINUS;
-      } else if (operator == sc.TokenType.PERCENT_EQ) {
-        return sc.TokenType.PERCENT;
-      } else if (operator == sc.TokenType.PLUS_EQ) {
-        return sc.TokenType.PLUS;
-      } else if (operator == sc.TokenType.SLASH_EQ) {
-        return sc.TokenType.SLASH;
-      } else if (operator == sc.TokenType.STAR_EQ) {
-        return sc.TokenType.STAR;
-      } else if (operator == sc.TokenType.TILDE_SLASH_EQ) {
-        return sc.TokenType.TILDE_SLASH;
+      if (operator == TokenType.AMPERSAND_EQ) {
+        return TokenType.AMPERSAND;
+      } else if (operator == TokenType.BAR_EQ) {
+        return TokenType.BAR;
+      } else if (operator == TokenType.CARET_EQ) {
+        return TokenType.CARET;
+      } else if (operator == TokenType.GT_GT_EQ) {
+        return TokenType.GT_GT;
+      } else if (operator == TokenType.LT_LT_EQ) {
+        return TokenType.LT_LT;
+      } else if (operator == TokenType.MINUS_EQ) {
+        return TokenType.MINUS;
+      } else if (operator == TokenType.PERCENT_EQ) {
+        return TokenType.PERCENT;
+      } else if (operator == TokenType.PLUS_EQ) {
+        return TokenType.PLUS;
+      } else if (operator == TokenType.SLASH_EQ) {
+        return TokenType.SLASH;
+      } else if (operator == TokenType.STAR_EQ) {
+        return TokenType.STAR;
+      } else if (operator == TokenType.TILDE_SLASH_EQ) {
+        return TokenType.TILDE_SLASH;
       } else {
         // Internal error: Unmapped assignment operator.
         AnalysisEngine.instance.logger.logError(
@@ -1796,7 +1838,7 @@
    * message.
    */
   void _recordUndefinedToken(Element declaringElement, ErrorCode errorCode,
-      sc.Token token, List<Object> arguments) {
+      Token token, List<Object> arguments) {
     if (_doesntHaveProxy(declaringElement)) {
       _resolver.reportErrorForToken(errorCode, token, arguments);
     }
@@ -2081,36 +2123,6 @@
   }
 
   /**
-   * Check for a generic method & apply type arguments if any were passed.
-   */
-  DartType _resolveGenericMethod(
-      DartType invokeType, TypeArgumentList typeArguments, AstNode node) {
-    // TODO(jmesserly): support generic "call" methods on InterfaceType.
-    if (invokeType is FunctionType) {
-      FunctionType type = invokeType;
-      List<TypeParameterElement> parameters = type.typeFormals;
-
-      NodeList<TypeName> arguments = typeArguments?.arguments;
-      if (arguments != null && arguments.length != parameters.length) {
-        // Wrong number of type arguments. Ignore them
-        arguments = null;
-        _resolver.reportErrorForNode(
-            StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
-            node,
-            [type, parameters.length, arguments?.length ?? 0]);
-      }
-      if (parameters.isNotEmpty) {
-        if (arguments == null) {
-          invokeType = _resolver.typeSystem.instantiateToBounds(type);
-        } else {
-          invokeType = type.instantiate(arguments.map((n) => n.type).toList());
-        }
-      }
-    }
-    return invokeType;
-  }
-
-  /**
    * Given an invocation of the form 'm(a1, ..., an)', resolve 'm' to the
    * element being invoked. If the returned element is a method, then the method
    * will be invoked. If the returned element is a getter, the getter will be
@@ -2200,6 +2212,15 @@
   }
 
   /**
+   * Given a [node] that can have annotations associated with it, resolve the
+   * annotations in the element model representing annotations to the node.
+   */
+  void _resolveMetadataForParameter(
+      Element element, NormalFormalParameter node) {
+    _resolveAnnotations(node.metadata);
+  }
+
+  /**
    * Given that we are accessing a property of the given [targetType] with the
    * given [propertyName], return the element that represents the property. The
    * [target] is the target of the invocation ('e').
@@ -2404,43 +2425,15 @@
    * If the given [type] is a type parameter, resolve it to the type that should
    * be used when looking up members. Otherwise, return the original type.
    */
-  DartType _resolveTypeParameter(DartType type) {
-    if (type is TypeParameterType) {
-      DartType bound = type.element.bound;
-      if (bound == null) {
-        return _resolver.typeProvider.objectType;
-      }
-      return bound;
-    }
-    return type;
-  }
-
-  /**
-   * Given a [node] that can have annotations associated with it and the
-   * [element] to which that node has been resolved, create the annotations in
-   * the element model representing the annotations on the node.
-   */
-  void _setMetadataForParameter(Element element, NormalFormalParameter node) {
-    if (element is! ElementImpl) {
-      return;
-    }
-    List<ElementAnnotationImpl> annotationList =
-        new List<ElementAnnotationImpl>();
-    _addAnnotations(annotationList, node.metadata);
-    if (!annotationList.isEmpty) {
-      (element as ElementImpl).metadata = annotationList;
-    }
-  }
+  DartType _resolveTypeParameter(DartType type) =>
+      type?.resolveToBound(_resolver.typeProvider.objectType);
 
   /**
    * Return `true` if we should report an error as a result of looking up a
    * [member] in the given [type] and not finding any member.
    */
   bool _shouldReportMissingMember(DartType type, Element member) {
-    if (member != null || type == null || type.isDynamic || type.isBottom) {
-      return false;
-    }
-    return true;
+    return member == null && type != null && !type.isDynamic && !type.isBottom;
   }
 
   /**
@@ -2459,48 +2452,21 @@
   }
 
   /**
-   * Given a [node] that can have annotations associated with it and the
-   * [element] to which that node has been resolved, create the annotations in
-   * the element model representing the annotations on the node.
+   * Given a [node] that can have annotations associated with it, resolve the
+   * annotations in the element model representing the annotations on the node.
    */
-  static void setMetadata(Element element, AnnotatedNode node) {
-    if (element is! ElementImpl) {
-      return;
-    }
-    List<ElementAnnotationImpl> annotationList = <ElementAnnotationImpl>[];
-    _addAnnotations(annotationList, node.metadata);
+  static void resolveMetadata(AnnotatedNode node) {
+    _resolveAnnotations(node.metadata);
     if (node is VariableDeclaration && node.parent is VariableDeclarationList) {
       VariableDeclarationList list = node.parent as VariableDeclarationList;
-      _addAnnotations(annotationList, list.metadata);
+      _resolveAnnotations(list.metadata);
       if (list.parent is FieldDeclaration) {
         FieldDeclaration fieldDeclaration = list.parent as FieldDeclaration;
-        _addAnnotations(annotationList, fieldDeclaration.metadata);
+        _resolveAnnotations(fieldDeclaration.metadata);
       } else if (list.parent is TopLevelVariableDeclaration) {
         TopLevelVariableDeclaration variableDeclaration =
             list.parent as TopLevelVariableDeclaration;
-        _addAnnotations(annotationList, variableDeclaration.metadata);
-      }
-    }
-    if (!annotationList.isEmpty) {
-      (element as ElementImpl).metadata = annotationList;
-    }
-  }
-
-  /**
-   * Generate annotation elements for each of the annotations in the
-   * [annotationList] and add them to the given list of [annotations].
-   */
-  static void _addAnnotations(List<ElementAnnotationImpl> annotationList,
-      NodeList<Annotation> annotations) {
-    int annotationCount = annotations.length;
-    for (int i = 0; i < annotationCount; i++) {
-      Annotation annotation = annotations[i];
-      Element resolvedElement = annotation.element;
-      if (resolvedElement != null) {
-        ElementAnnotationImpl elementAnnotation =
-            new ElementAnnotationImpl(resolvedElement);
-        annotation.elementAnnotation = elementAnnotation;
-        annotationList.add(elementAnnotation);
+        _resolveAnnotations(variableDeclaration.metadata);
       }
     }
   }
@@ -2551,6 +2517,16 @@
     }
     return false;
   }
+
+  /**
+   * Resolve each of the annotations in the given list of [annotations].
+   */
+  static void _resolveAnnotations(NodeList<Annotation> annotations) {
+    for (Annotation annotation in annotations) {
+      ElementAnnotationImpl elementAnnotation = annotation.elementAnnotation;
+      elementAnnotation.element = annotation.element;
+    }
+  }
 }
 
 /**
@@ -2559,10 +2535,11 @@
  * AST when the parser could not distinguish between a method invocation and an
  * invocation of a top-level function imported with a prefix.
  */
-class SyntheticIdentifier extends Identifier {
+class SyntheticIdentifier extends IdentifierImpl {
   /**
    * The name of the synthetic identifier.
    */
+  @override
   final String name;
 
   /**
@@ -2577,7 +2554,7 @@
   SyntheticIdentifier(this.name, this.targetIdentifier);
 
   @override
-  sc.Token get beginToken => null;
+  Token get beginToken => null;
 
   @override
   Element get bestElement => null;
@@ -2591,7 +2568,7 @@
   }
 
   @override
-  sc.Token get endToken => null;
+  Token get endToken => null;
 
   @override
   int get length => targetIdentifier.length;
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 4f8d664..57d35d9 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -7,13 +7,14 @@
 import 'dart:async';
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/source/embedder.dart';
 import 'package:analyzer/src/cancelable_future.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_core.dart';
@@ -312,8 +313,8 @@
    * Perform work until the given [result] has been computed for the given
    * [target]. Return the computed value.
    */
-  Object /*=V*/ computeResult /*<V>*/ (
-      AnalysisTarget target, ResultDescriptor /*<V>*/ result);
+  Object/*=V*/ computeResult/*<V>*/(
+      AnalysisTarget target, ResultDescriptor/*<V>*/ result);
 
   /**
    * Notifies the context that the client is going to stop using this context.
@@ -474,8 +475,8 @@
    * If the corresponding [target] does not exist, or the [result] is not
    * computed yet, then the default value is returned.
    */
-  Object /*=V*/ getResult /*<V>*/ (
-      AnalysisTarget target, ResultDescriptor /*<V>*/ result);
+  Object/*=V*/ getResult/*<V>*/(
+      AnalysisTarget target, ResultDescriptor/*<V>*/ result);
 
   /**
    * Return a list of the sources being analyzed in this context whose full path
@@ -880,8 +881,8 @@
     if (fileName == null) {
       return false;
     }
-    return javaStringEqualsIgnoreCase(
-        FileNameUtilities.getExtension(fileName), SUFFIX_DART);
+    String extension = FileNameUtilities.getExtension(fileName).toLowerCase();
+    return extension == SUFFIX_DART;
   }
 
   /**
@@ -891,9 +892,8 @@
     if (fileName == null) {
       return false;
     }
-    String extension = FileNameUtilities.getExtension(fileName);
-    return javaStringEqualsIgnoreCase(extension, SUFFIX_HTML) ||
-        javaStringEqualsIgnoreCase(extension, SUFFIX_HTM);
+    String extension = FileNameUtilities.getExtension(fileName).toLowerCase();
+    return extension == SUFFIX_HTML || extension == SUFFIX_HTM;
   }
 }
 
@@ -922,6 +922,7 @@
    * The analysis errors associated with a source, or `null` if there are no
    * errors.
    */
+  @override
   final List<AnalysisError> errors;
 
   /**
@@ -1122,6 +1123,19 @@
    * Return `true` if strong mode analysis should be used.
    */
   bool get strongMode;
+
+  /**
+   * Return an integer encoding of the values of the options that need to be the
+   * same across all of the contexts associated with partitions that are to be
+   * shared by a single analysis context.
+   */
+  int encodeCrossContextOptions();
+
+  /**
+   * Set the values of the cross-context options to match those in the given set
+   * of [options].
+   */
+  void setCrossContextOptionsFrom(AnalysisOptions options);
 }
 
 /**
@@ -1134,6 +1148,14 @@
    */
   static const int DEFAULT_CACHE_SIZE = 64;
 
+  static const int ENABLE_ASSERT_FLAG = 0x01;
+  static const int ENABLE_ASYNC_FLAG = 0x02;
+  static const int ENABLE_GENERIC_METHODS_FLAG = 0x04;
+  static const int ENABLE_STRICT_CALL_CHECKS_FLAG = 0x08;
+  static const int ENABLE_STRONG_MODE_FLAG = 0x10;
+  static const int ENABLE_STRONG_MODE_HINTS_FLAG = 0x20;
+  static const int ENABLE_SUPER_MIXINS_FLAG = 0x40;
+
   /**
    * A predicate indicating whether analysis is to parse and analyze function
    * bodies.
@@ -1307,6 +1329,29 @@
     _analyzeFunctionBodiesPredicate = value;
   }
 
+  @override
+  int encodeCrossContextOptions() =>
+      (enableAssertMessage ? ENABLE_ASSERT_FLAG : 0) |
+      (enableAsync ? ENABLE_ASYNC_FLAG : 0) |
+      (enableGenericMethods ? ENABLE_GENERIC_METHODS_FLAG : 0) |
+      (enableStrictCallChecks ? ENABLE_STRICT_CALL_CHECKS_FLAG : 0) |
+      (strongMode ? ENABLE_STRONG_MODE_FLAG : 0) |
+      (strongModeHints ? ENABLE_STRONG_MODE_HINTS_FLAG : 0) |
+      (enableSuperMixins ? ENABLE_SUPER_MIXINS_FLAG : 0);
+
+  @override
+  void setCrossContextOptionsFrom(AnalysisOptions options) {
+    enableAssertMessage = options.enableAssertMessage;
+    enableAsync = options.enableAsync;
+    enableGenericMethods = options.enableGenericMethods;
+    enableStrictCallChecks = options.enableStrictCallChecks;
+    enableSuperMixins = options.enableSuperMixins;
+    strongMode = options.strongMode;
+    if (options is AnalysisOptionsImpl) {
+      strongModeHints = options.strongModeHints;
+    }
+  }
+
   /**
    * Predicate used for [analyzeFunctionBodiesPredicate] when
    * [analyzeFunctionBodies] is set to `true`.
@@ -1484,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;
 
   /**
@@ -1589,6 +1637,7 @@
   /**
    * A list containing the sources that have been deleted.
    */
+  @deprecated
   final List<Source> deletedSources = new List<Source>();
 
   /**
@@ -1651,6 +1700,7 @@
   /**
    * Record that the specified [source] has been deleted.
    */
+  @deprecated
   void deletedSource(Source source) {
     deletedSources.add(source);
   }
@@ -1850,6 +1900,11 @@
  */
 abstract class InternalAnalysisContext implements AnalysisContext {
   /**
+   * The result provider for [aboutToComputeResult].
+   */
+  ResultProvider resultProvider;
+
+  /**
    * A table mapping the sources known to the context to the information known
    * about the source.
    */
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index aa43a7e..59879fc 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -6,14 +6,16 @@
 
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/ast.dart' show AstNode;
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/source/error_processor.dart';
-import 'package:analyzer/src/generated/ast.dart' show AstNode;
+import 'package:analyzer/src/dart/scanner/scanner.dart' show ScannerErrorCode;
+import 'package:analyzer/src/generated/generated/shared_messages.dart'
+    as shared_messages;
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
-import 'package:analyzer/src/generated/scanner.dart'
-    show ScannerErrorCode, Token;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/task/model.dart';
 import 'package:analyzer/task/model.dart';
@@ -83,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
@@ -1658,25 +1660,6 @@
           "Map literals must be prefixed with 'const' when used as a constant expression");
 
   /**
-   * Enum proposal: It is a static warning if all of the following conditions
-   * hold:
-   * * The switch statement does not have a 'default' clause.
-   * * The static type of <i>e</i> is an enumerated typed with elements
-   *   <i>id<sub>1</sub></i>, &hellip;, <i>id<sub>n</sub></i>.
-   * * The sets {<i>e<sub>1</sub></i>, &hellip;, <i>e<sub>k</sub></i>} and
-   *   {<i>id<sub>1</sub></i>, &hellip;, <i>id<sub>n</sub></i>} are not the
-   *   same.
-   *
-   * Parameters:
-   * 0: the name of the constant that is missing
-   */
-  static const CompileTimeErrorCode MISSING_ENUM_CONSTANT_IN_SWITCH =
-      const CompileTimeErrorCode(
-          'MISSING_ENUM_CONSTANT_IN_SWITCH',
-          "Missing case clause for '{0}'",
-          "Add a case clause for the missing constant or add a default clause.");
-
-  /**
    * 9 Mixins: It is a compile-time error if a declared or derived mixin
    * explicitly declares a constructor.
    *
@@ -2239,24 +2222,21 @@
    * <i>rethrow;</i> is not enclosed within a on-catch clause.
    */
   static const CompileTimeErrorCode RETHROW_OUTSIDE_CATCH =
-      const CompileTimeErrorCode(
-          'RETHROW_OUTSIDE_CATCH', "rethrow must be inside of a catch clause");
+      shared_messages.RETHROW_OUTSIDE_CATCH;
 
   /**
    * 13.12 Return: It is a compile-time error if a return statement of the form
    * <i>return e;</i> appears in a generative constructor.
    */
   static const CompileTimeErrorCode RETURN_IN_GENERATIVE_CONSTRUCTOR =
-      const CompileTimeErrorCode('RETURN_IN_GENERATIVE_CONSTRUCTOR',
-          "Constructors cannot return a value");
+      shared_messages.RETURN_IN_GENERATIVE_CONSTRUCTOR;
 
   /**
    * 13.12 Return: It is a compile-time error if a return statement of the form
    * <i>return e;</i> appears in a generator function.
    */
   static const CompileTimeErrorCode RETURN_IN_GENERATOR =
-      const CompileTimeErrorCode('RETURN_IN_GENERATOR',
-          "Cannot return a value from a generator function (one marked with either 'async*' or 'sync*')");
+      shared_messages.RETURN_IN_GENERATOR;
 
   /**
    * 14.1 Imports: It is a compile-time error if a prefix used in a deferred
@@ -2502,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,
@@ -2569,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,
@@ -2613,7 +2596,6 @@
     CompileTimeErrorCode.METHOD_AND_GETTER_WITH_SAME_NAME,
     CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL,
     CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL,
-    CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
     CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR,
     CompileTimeErrorCode.MIXIN_DEFERRED_CLASS,
     CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS,
@@ -2685,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,
@@ -2697,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,
@@ -2709,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,
@@ -2720,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,
@@ -2748,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,
@@ -2794,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,
@@ -2848,6 +2834,7 @@
     StaticWarningCode.UNDEFINED_SUPER_GETTER,
     StaticWarningCode.UNDEFINED_SUPER_SETTER,
     StaticWarningCode.VOID_RETURN_FOR_GETTER,
+    StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
     TodoCode.TODO,
 
     //
@@ -2865,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,
@@ -2928,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,
@@ -2980,6 +2969,7 @@
     ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS,
     ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT,
     ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP,
+    ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY,
     ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR,
     ParserErrorCode.SETTER_IN_FUNCTION,
     ParserErrorCode.STATIC_AFTER_CONST,
@@ -3552,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
@@ -5646,6 +5648,25 @@
           "The return type of the getter must not be 'void'");
 
   /**
+   * 17.9 Switch: It is a static warning if all of the following conditions
+   * hold:
+   * * The switch statement does not have a 'default' clause.
+   * * The static type of <i>e</i> is an enumerated typed with elements
+   *   <i>id<sub>1</sub></i>, &hellip;, <i>id<sub>n</sub></i>.
+   * * The sets {<i>e<sub>1</sub></i>, &hellip;, <i>e<sub>k</sub></i>} and
+   *   {<i>id<sub>1</sub></i>, &hellip;, <i>id<sub>n</sub></i>} are not the
+   *   same.
+   *
+   * Parameters:
+   * 0: the name of the constant that is missing
+   */
+  static const StaticWarningCode MISSING_ENUM_CONSTANT_IN_SWITCH =
+      const StaticWarningCode(
+          'MISSING_ENUM_CONSTANT_IN_SWITCH',
+          "Missing case clause for '{0}'",
+          "Add a case clause for the missing constant or add a default clause.");
+
+  /**
    * Initialize a newly created error code to have the given [name]. The message
    * associated with the error will be created from the given [message]
    * template. The correction associated with the error will be created from the
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index d644fcd..32b4d31 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -7,13 +7,16 @@
 import 'dart:collection';
 import "dart:math" as math;
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/visitor.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/element_resolver.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -21,9 +24,7 @@
 import 'package:analyzer/src/generated/parser.dart'
     show Parser, ParserErrorCode;
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart' as sc;
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk, SdkLibrary;
-import 'package:analyzer/src/generated/static_type_analyzer.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
 /**
@@ -328,11 +329,11 @@
 
   @override
   Object visitAssignmentExpression(AssignmentExpression node) {
-    sc.TokenType operatorType = node.operator.type;
+    TokenType operatorType = node.operator.type;
     Expression lhs = node.leftHandSide;
     Expression rhs = node.rightHandSide;
-    if (operatorType == sc.TokenType.EQ ||
-        operatorType == sc.TokenType.QUESTION_QUESTION_EQ) {
+    if (operatorType == TokenType.EQ ||
+        operatorType == TokenType.QUESTION_QUESTION_EQ) {
       _checkForInvalidAssignment(lhs, rhs);
     } else {
       _checkForInvalidCompoundAssignment(node, lhs, rhs);
@@ -353,10 +354,10 @@
 
   @override
   Object visitBinaryExpression(BinaryExpression node) {
-    sc.Token operator = node.operator;
-    sc.TokenType type = operator.type;
-    if (type == sc.TokenType.AMPERSAND_AMPERSAND ||
-        type == sc.TokenType.BAR_BAR) {
+    Token operator = node.operator;
+    TokenType type = operator.type;
+    if (type == TokenType.AMPERSAND_AMPERSAND ||
+        type == TokenType.BAR_BAR) {
       String lexeme = operator.lexeme;
       _checkForAssignability(node.leftOperand, _boolType,
           StaticTypeWarningCode.NON_BOOL_OPERAND, [lexeme]);
@@ -681,6 +682,14 @@
   }
 
   @override
+  Object visitForStatement(ForStatement node) {
+    if (node.condition != null) {
+      _checkForNonBoolCondition(node.condition);
+    }
+    return super.visitForStatement(node);
+  }
+
+  @override
   Object visitFunctionDeclaration(FunctionDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
     try {
@@ -947,9 +956,9 @@
 
   @override
   Object visitPrefixExpression(PrefixExpression node) {
-    sc.TokenType operatorType = node.operator.type;
+    TokenType operatorType = node.operator.type;
     Expression operand = node.operand;
-    if (operatorType == sc.TokenType.BANG) {
+    if (operatorType == TokenType.BANG) {
       _checkForNonBoolNegationExpression(operand);
     } else if (operatorType.isIncrementOperator) {
       _checkForAssignmentToFinal(operand);
@@ -1285,27 +1294,27 @@
         }
       }
     });
+
     if (notInitFinalFields.isNotEmpty) {
       foundError = true;
       AnalysisErrorWithProperties analysisError;
-      if (notInitFinalFields.length == 1) {
+      List<String> names = notInitFinalFields.map((item) => item.name).toList();
+      names.sort();
+      if (names.length == 1) {
         analysisError = _errorReporter.newErrorWithProperties(
             StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1,
             constructor.returnType,
-            [notInitFinalFields[0].name]);
-      } else if (notInitFinalFields.length == 2) {
+            names);
+      } else if (names.length == 2) {
         analysisError = _errorReporter.newErrorWithProperties(
             StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2,
             constructor.returnType,
-            [notInitFinalFields[0].name, notInitFinalFields[1].name]);
+            names);
       } else {
         analysisError = _errorReporter.newErrorWithProperties(
             StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS,
-            constructor.returnType, [
-          notInitFinalFields[0].name,
-          notInitFinalFields[1].name,
-          notInitFinalFields.length - 2
-        ]);
+            constructor.returnType,
+            [names[0], names[1], names.length - 2]);
       }
       analysisError.setProperty(
           ErrorProperty.NOT_INITIALIZED_FIELDS, notInitFinalFields);
@@ -1927,7 +1936,9 @@
     } else if (_inGenerator) {
       // RETURN_IN_GENERATOR
       _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.RETURN_IN_GENERATOR, statement);
+          CompileTimeErrorCode.RETURN_IN_GENERATOR,
+          statement,
+          [_inAsync ? "async*" : "sync*"]);
     }
     // RETURN_OF_INVALID_TYPE
     return _checkForReturnOfInvalidType(returnExpression, expectedReturnType);
@@ -2169,8 +2180,8 @@
    */
   bool _checkForBuiltInIdentifierAsName(
       SimpleIdentifier identifier, ErrorCode errorCode) {
-    sc.Token token = identifier.token;
-    if (token.type == sc.TokenType.KEYWORD) {
+    Token token = identifier.token;
+    if (token.type == TokenType.KEYWORD) {
       _errorReporter
           .reportErrorForNode(errorCode, identifier, [identifier.name]);
       return true;
@@ -2831,8 +2842,8 @@
     if (type.element.isAbstract) {
       ConstructorElement element = expression.staticElement;
       if (element != null && !element.isFactory) {
-        if ((expression.keyword as sc.KeywordToken).keyword ==
-            sc.Keyword.CONST) {
+        if ((expression.keyword as KeywordToken).keyword ==
+            Keyword.CONST) {
           _errorReporter.reportErrorForNode(
               StaticWarningCode.CONST_WITH_ABSTRACT_CLASS, typeName);
         } else {
@@ -3981,7 +3992,7 @@
    */
   bool _checkForInvalidModifierOnBody(
       FunctionBody body, CompileTimeErrorCode errorCode) {
-    sc.Token keyword = body.keyword;
+    Token keyword = body.keyword;
     if (keyword != null) {
       _errorReporter.reportErrorForToken(errorCode, keyword, [keyword.lexeme]);
       return true;
@@ -4280,7 +4291,7 @@
       int offset = statement.offset;
       int end = statement.rightParenthesis.end;
       _errorReporter.reportErrorForOffset(
-          CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
+          StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
           offset,
           end - offset,
           [constantNames[i]]);
@@ -4642,6 +4653,7 @@
       stringMembersArrayListSet.add(newStrMember);
     }
     List<String> stringMembersArray = new List.from(stringMembersArrayListSet);
+    stringMembersArray.sort();
     AnalysisErrorWithProperties analysisError;
     if (stringMembersArray.length == 1) {
       analysisError = _errorReporter.newErrorWithProperties(
@@ -5771,9 +5783,8 @@
     }
     DartType staticReturnType = getStaticType(returnExpression);
     if (staticReturnType != null && _enclosingFunction.isAsynchronous) {
-      return _typeProvider.futureType.substitute4(<DartType>[
-        StaticTypeAnalyzer.flattenFutures(_typeProvider, staticReturnType)
-      ]);
+      return _typeProvider.futureType.substitute4(
+          <DartType>[staticReturnType.flattenFutures(_typeSystem)]);
     }
     return staticReturnType;
   }
@@ -5852,7 +5863,7 @@
     int count = directives.length;
     if (count > 1) {
       for (int i = 0; i < count; i++) {
-        sc.Token deferredToken = directives[i].deferredKeyword;
+        Token deferredToken = directives[i].deferredKeyword;
         if (deferredToken != null) {
           _errorReporter.reportErrorForToken(
               CompileTimeErrorCode.SHARED_DEFERRED_PREFIX, deferredToken);
diff --git a/pkg/analyzer/lib/src/generated/generated/shared_messages.dart b/pkg/analyzer/lib/src/generated/generated/shared_messages.dart
new file mode 100644
index 0000000..c0be1d2
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/generated/shared_messages.dart
@@ -0,0 +1,83 @@
+// 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.
+/*
+DON'T EDIT. GENERATED. DON'T EDIT.
+This file has been generated by 'publish.dart' in the dart_messages package.
+
+Messages are maintained in `lib/shared_messages.dart` of that same package.
+After any change to that file, run `bin/publish.dart` to generate a new version
+of the json, dart2js and analyzer representations.
+*/
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
+
+const ParserErrorCode CONST_CONSTRUCTOR_WITH_BODY = const ParserErrorCode(
+    'CONST_CONSTRUCTOR_WITH_BODY',
+    "Const constructor can't have a body.",
+    "Try removing the 'const' keyword or the body.");  // Generated. Don't edit.
+
+const ParserErrorCode CONST_FACTORY = const ParserErrorCode(
+    'CONST_FACTORY',
+    "Only redirecting factory constructors can be declared to be 'const'.",
+    "Try removing the 'const' keyword or replacing the body with '=' followed by a valid target.");  // Generated. Don't edit.
+
+const ParserErrorCode CONST_CLASS = const ParserErrorCode(
+    'CONST_CLASS',
+    "Classes can't be declared to be 'const'",
+    "Try removing the 'const' keyword or moving to the class' constructor(s).");  // Generated. Don't edit.
+
+const ParserErrorCode CONST_METHOD = const ParserErrorCode(
+    'CONST_METHOD',
+    "Getters, setters and methods can't be declared to be 'const'",
+    "Try removing the 'const' keyword.");  // Generated. Don't edit.
+
+const ParserErrorCode CONST_ENUM = const ParserErrorCode(
+    'CONST_ENUM',
+    "Enums can't be declared to be 'const'",
+    "Try removing the 'const' keyword.");  // Generated. Don't edit.
+
+const ParserErrorCode CONST_TYPEDEF = const ParserErrorCode(
+    'CONST_TYPEDEF',
+    "Type aliases can't be declared to be 'const'",
+    "Try removing the 'const' keyword.");  // Generated. Don't edit.
+
+const ParserErrorCode CONST_AND_FINAL = const ParserErrorCode(
+    'CONST_AND_FINAL',
+    "Members can't be declared to be both 'const' and 'final'",
+    "Try removing either the 'const' or 'final' keyword.");  // Generated. Don't edit.
+
+const ParserErrorCode CONST_AND_VAR = const ParserErrorCode(
+    'CONST_AND_VAR',
+    "Members can't be declared to be both 'const' and 'var'",
+    "Try removing either the 'const' or 'var' keyword.");  // Generated. Don't edit.
+
+const ParserErrorCode CLASS_IN_CLASS = const ParserErrorCode(
+    'CLASS_IN_CLASS',
+    "Classes can't be declared inside other classes.",
+    "Try moving the class to the top-level.");  // Generated. Don't edit.
+
+const ParserErrorCode CONSTRUCTOR_WITH_RETURN_TYPE = const ParserErrorCode(
+    'CONSTRUCTOR_WITH_RETURN_TYPE',
+    "Constructors can't have a return type",
+    "Try removing the return type.");  // Generated. Don't edit.
+
+const ParserErrorCode MISSING_EXPRESSION_IN_THROW = const ParserErrorCode(
+    'MISSING_EXPRESSION_IN_THROW',
+    "Missing expression after 'throw'.",
+    "Did you mean 'rethrow'?");  // Generated. Don't edit.
+
+const CompileTimeErrorCode RETHROW_OUTSIDE_CATCH = const CompileTimeErrorCode(
+    'RETHROW_OUTSIDE_CATCH',
+    "Rethrow must be inside of catch clause",
+    "Try moving the expression into a catch clause, or using a 'throw' expression.");  // Generated. Don't edit.
+
+const CompileTimeErrorCode RETURN_IN_GENERATIVE_CONSTRUCTOR = const CompileTimeErrorCode(
+    'RETURN_IN_GENERATIVE_CONSTRUCTOR',
+    "Constructors can't return values.",
+    "Try removing the return statement or using a factory constructor.");  // Generated. Don't edit.
+
+const CompileTimeErrorCode RETURN_IN_GENERATOR = const CompileTimeErrorCode(
+    'RETURN_IN_GENERATOR',
+    "Can't return a value from a generator function (using the '{0}' modifier).",
+    "Try removing the value, replacing 'return' with 'yield' or changing the method body modifier");  // Generated. Don't edit.
diff --git a/pkg/analyzer/lib/src/generated/incremental_logger.dart b/pkg/analyzer/lib/src/generated/incremental_logger.dart
index d942aba..1de2534 100644
--- a/pkg/analyzer/lib/src/generated/incremental_logger.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_logger.dart
@@ -40,6 +40,11 @@
   void log(Object obj);
 
   /**
+   * Logs the given [exception] and [stackTrace].
+   */
+  void logException(Object exception, [Object stackTrace]);
+
+  /**
    * Starts a new timer.
    */
   LoggingTimer startTimer();
@@ -102,6 +107,16 @@
   }
 
   @override
+  void logException(Object exception, [Object stackTrace]) {
+    if (exception != null) {
+      log(exception);
+    }
+    if (stackTrace != null) {
+      log(stackTrace);
+    }
+  }
+
+  @override
   LoggingTimer startTimer() {
     return new LoggingTimer(this);
   }
@@ -147,6 +162,9 @@
   void log(Object obj) {}
 
   @override
+  void logException(Object exception, [Object stackTrace]) {}
+
+  @override
   LoggingTimer startTimer() {
     return new LoggingTimer(this);
   }
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolution_validator.dart b/pkg/analyzer/lib/src/generated/incremental_resolution_validator.dart
index 36d8784..cf2c0dd 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolution_validator.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolution_validator.dart
@@ -4,11 +4,11 @@
 
 library analyzer.src.generated.incremental_resolution_validator;
 
+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/src/dart/element/member.dart';
-import 'package:analyzer/src/generated/ast.dart';
 
 /**
  * Validates that the [actual] and the [expected] units have the same structure
@@ -28,10 +28,15 @@
 class IncrementalResolutionMismatch {
   final String message;
   IncrementalResolutionMismatch(this.message);
+
+  @override
+  String toString() => "IncrementalResolutionMismatch: $message";
 }
 
 class _SameResolutionValidator implements AstVisitor {
   final bool validateTypes;
+
+  /// The expected node to compare with the visted node.
   AstNode other;
 
   _SameResolutionValidator(this.validateTypes, this.other);
@@ -887,11 +892,11 @@
     _assertNode(a, b);
   }
 
-  void _visitList(NodeList nodeList, NodeList otherList) {
+  void _visitList(NodeList nodeList, NodeList expected) {
     int length = nodeList.length;
-    _expectLength(otherList, length);
+    _expectLength(nodeList, expected.length);
     for (int i = 0; i < length; i++) {
-      _visitNode(nodeList[i], otherList[i]);
+      _visitNode(nodeList[i], expected[i]);
     }
   }
 
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index b67b905..fc8c860 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -7,12 +7,19 @@
 import 'dart:collection';
 import 'dart:math' as math;
 
+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/dart/element/type.dart';
 import 'package:analyzer/dart/element/visitor.dart';
 import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -22,7 +29,6 @@
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/task/dart.dart';
@@ -112,12 +118,14 @@
       _gatherElements(element);
       node.accept(this);
     } on _DeclarationMismatchException {
+      logger.log("mismatched");
       return DeclarationMatchKind.MISMATCH;
     } finally {
       logger.exit();
     }
     // no API changes
     if (_removedElements.isEmpty && _addedElements.isEmpty) {
+      logger.log("no API changes");
       return DeclarationMatchKind.MATCH;
     }
     // simple API change
@@ -474,7 +482,8 @@
   void _assertCompatibleParameter(
       FormalParameter node, ParameterElement element) {
     _assertEquals(node.kind, element.parameterKind);
-    if (node.kind == ParameterKind.NAMED) {
+    if (node.kind == ParameterKind.NAMED ||
+        element.enclosingElement is ConstructorElement) {
       _assertEquals(node.identifier.name, element.name);
     }
     // check parameter type specific properties
@@ -597,12 +606,12 @@
   }
 
   void _assertSameAnnotations(AnnotatedNode node, Element element) {
-    List<Annotation> nodeAnnotaitons = node.metadata;
+    List<Annotation> nodeAnnotations = node.metadata;
     List<ElementAnnotation> elementAnnotations = element.metadata;
-    int length = nodeAnnotaitons.length;
+    int length = nodeAnnotations.length;
     _assertEquals(elementAnnotations.length, length);
     for (int i = 0; i < length; i++) {
-      _assertSameAnnotation(nodeAnnotaitons[i], elementAnnotations[i]);
+      _assertSameAnnotation(nodeAnnotations[i], elementAnnotations[i]);
     }
   }
 
@@ -905,8 +914,6 @@
         isByTask(ReadyLibraryElement5Task.DESCRIPTOR) ||
         isByTask(ReadyLibraryElement6Task.DESCRIPTOR) ||
         isByTask(ReadyResolvedUnitTask.DESCRIPTOR) ||
-        isByTask(ReadyResolvedUnit10Task.DESCRIPTOR) ||
-        isByTask(ReadyResolvedUnit11Task.DESCRIPTOR) ||
         isByTask(EvaluateUnitConstantsTask.DESCRIPTOR) ||
         isByTask(GenerateHintsTask.DESCRIPTOR) ||
         isByTask(InferInstanceMembersInUnitTask.DESCRIPTOR) ||
@@ -920,6 +927,7 @@
         isByTask(PropagateVariableTypesInUnitTask.DESCRIPTOR) ||
         isByTask(PropagateVariableTypeTask.DESCRIPTOR) ||
         isByTask(ScanDartTask.DESCRIPTOR) ||
+        isByTask(ResolveConstantExpressionTask.DESCRIPTOR) ||
         isByTask(ResolveInstanceFieldsInUnitTask.DESCRIPTOR) ||
         isByTask(ResolveLibraryReferencesTask.DESCRIPTOR) ||
         isByTask(ResolveLibraryTask.DESCRIPTOR) ||
@@ -949,42 +957,44 @@
   /**
    * The context the compilation unit being resolved in.
    */
-  AnalysisContext _context;
+  final AnalysisContext _context;
 
   /**
    * The object used to access the types from the core library.
    */
-  TypeProvider _typeProvider;
+  final TypeProvider _typeProvider;
 
   /**
    * The type system primitives.
    */
-  TypeSystem _typeSystem;
+  final TypeSystem _typeSystem;
 
   /**
    * The element for the library containing the compilation unit being resolved.
    */
-  LibraryElementImpl _definingLibrary;
+  final LibraryElementImpl _definingLibrary;
+
+  final AnalysisCache _cache;
 
   /**
    * The [CacheEntry] corresponding to the source being resolved.
    */
-  CacheEntry newSourceEntry;
+  final CacheEntry newSourceEntry;
 
   /**
    * The [CacheEntry] corresponding to the [LibrarySpecificUnit] being resolved.
    */
-  CacheEntry newUnitEntry;
+  final CacheEntry newUnitEntry;
 
   /**
    * The source representing the compilation unit being visited.
    */
-  Source _source;
+  final Source _source;
 
   /**
    * The source representing the library of the compilation unit being visited.
    */
-  Source _librarySource;
+  final Source _librarySource;
 
   /**
    * The offset of the changed contents.
@@ -1004,14 +1014,14 @@
   /**
    * The delta between [_updateEndNew] and [_updateEndOld].
    */
-  int _updateDelta;
+  final int _updateDelta;
 
   /**
    * The set of [AnalysisError]s that have been already shifted.
    */
-  Set<AnalysisError> _alreadyShiftedErrors = new HashSet.identity();
+  final Set<AnalysisError> _alreadyShiftedErrors = new HashSet.identity();
 
-  RecordingErrorListener errorListener = new RecordingErrorListener();
+  final RecordingErrorListener errorListener = new RecordingErrorListener();
   ResolutionContext _resolutionContext;
 
   List<AnalysisError> _resolveErrors = AnalysisError.NO_ERRORS;
@@ -1022,20 +1032,23 @@
    * given source in the given library.
    */
   IncrementalResolver(
+      this._cache,
       this.newSourceEntry,
       this.newUnitEntry,
-      this._definingUnit,
+      CompilationUnitElementImpl definingUnit,
       this._updateOffset,
-      this._updateEndOld,
-      this._updateEndNew) {
-    _updateDelta = _updateEndNew - _updateEndOld;
-    _definingLibrary = _definingUnit.library;
-    _librarySource = _definingLibrary.source;
-    _source = _definingUnit.source;
-    _context = _definingUnit.context;
-    _typeProvider = _context.typeProvider;
-    _typeSystem = _context.typeSystem;
-  }
+      int updateEndOld,
+      int updateEndNew)
+      : _definingUnit = definingUnit,
+        _context = definingUnit.context,
+        _typeProvider = definingUnit.context.typeProvider,
+        _typeSystem = definingUnit.context.typeSystem,
+        _definingLibrary = definingUnit.library,
+        _source = definingUnit.source,
+        _librarySource = definingUnit.library.source,
+        _updateEndOld = updateEndOld,
+        _updateEndNew = updateEndNew,
+        _updateDelta = updateEndNew - updateEndOld;
 
   /**
    * Resolve [node], reporting any errors or warnings to the given listener.
@@ -1076,7 +1089,7 @@
     LoggingTimer timer = logger.startTimer();
     try {
       ElementHolder holder = new ElementHolder();
-      ElementBuilder builder = new ElementBuilder(holder);
+      ElementBuilder builder = new ElementBuilder(holder, _definingUnit);
       if (_resolutionContext.enclosingClassDeclaration != null) {
         builder.visitClassDeclarationIncrementally(
             _resolutionContext.enclosingClassDeclaration);
@@ -1276,8 +1289,8 @@
   void _updateElementNameOffsets() {
     LoggingTimer timer = logger.startTimer();
     try {
-      _definingUnit
-          .accept(new _ElementOffsetUpdater(_updateOffset, _updateDelta));
+      _definingUnit.accept(
+          new _ElementOffsetUpdater(_updateOffset, _updateDelta, _cache));
       _definingUnit.afterIncrementalResolution();
     } finally {
       timer.stop('update element offsets');
@@ -1355,16 +1368,17 @@
 class PoorMansIncrementalResolver {
   final TypeProvider _typeProvider;
   final Source _unitSource;
+  final AnalysisCache _cache;
 
   /**
    * The [CacheEntry] corresponding to the source being resolved.
    */
-  CacheEntry _sourceEntry;
+  final CacheEntry _sourceEntry;
 
   /**
    * The [CacheEntry] corresponding to the [LibrarySpecificUnit] being resolved.
    */
-  CacheEntry _unitEntry;
+  final CacheEntry _unitEntry;
 
   final CompilationUnit _oldUnit;
   CompilationUnitElement _unitElement;
@@ -1381,6 +1395,7 @@
   PoorMansIncrementalResolver(
       this._typeProvider,
       this._unitSource,
+      this._cache,
       this._sourceEntry,
       this._unitEntry,
       this._oldUnit,
@@ -1441,6 +1456,7 @@
             _shiftTokens(firstPair.oldToken);
             {
               IncrementalResolver incrementalResolver = new IncrementalResolver(
+                  _cache,
                   _sourceEntry,
                   _unitEntry,
                   _unitElement,
@@ -1468,37 +1484,67 @@
         {
           List<AstNode> oldParents = _getParents(oldNode);
           List<AstNode> newParents = _getParents(newNode);
+          // fail if an initializer change
+          if (oldParents.any((n) => n is ConstructorInitializer) ||
+              newParents.any((n) => n is ConstructorInitializer)) {
+            logger.log('Failure: a change in a constructor initializer');
+            return false;
+          }
+          // find matching methods / bodies
           int length = math.min(oldParents.length, newParents.length);
           bool found = false;
           for (int i = 0; i < length; i++) {
             AstNode oldParent = oldParents[i];
             AstNode newParent = newParents[i];
-            if (oldParent is ConstructorInitializer ||
-                newParent is ConstructorInitializer) {
-              logger.log('Failure: changes in constant constructor initializers'
-                  ' may cause external changes in constant objects.');
-              return false;
-            }
-            if (oldParent is FunctionDeclaration &&
+            if (oldParent is CompilationUnit && newParent is CompilationUnit) {
+              int oldLength = oldParent.declarations.length;
+              int newLength = newParent.declarations.length;
+              if (oldLength != newLength) {
+                logger.log(
+                    'Failure: unit declarations mismatch $oldLength vs. $newLength');
+                return false;
+              }
+            } else if (oldParent is ClassDeclaration &&
+                newParent is ClassDeclaration) {
+              int oldLength = oldParent.members.length;
+              int newLength = newParent.members.length;
+              if (oldLength != newLength) {
+                logger.log(
+                    'Failure: class declarations mismatch $oldLength vs. $newLength');
+                return false;
+              }
+            } else if (oldParent is FunctionDeclaration &&
                     newParent is FunctionDeclaration ||
-                oldParent is MethodDeclaration &&
-                    newParent is MethodDeclaration ||
                 oldParent is ConstructorDeclaration &&
-                    newParent is ConstructorDeclaration) {
+                    newParent is ConstructorDeclaration ||
+                oldParent is MethodDeclaration &&
+                    newParent is MethodDeclaration) {
               Element oldElement = (oldParent as Declaration).element;
               if (new DeclarationMatcher().matches(newParent, oldElement) ==
                   DeclarationMatchKind.MATCH) {
                 oldNode = oldParent;
                 newNode = newParent;
                 found = true;
+              } else {
+                return false;
               }
-            }
-            if (oldParent is BlockFunctionBody &&
-                newParent is BlockFunctionBody) {
-              oldNode = oldParent;
-              newNode = newParent;
-              found = true;
-              break;
+            } else if (oldParent is FunctionBody && newParent is FunctionBody) {
+              if (oldParent is BlockFunctionBody &&
+                  newParent is BlockFunctionBody) {
+                oldNode = oldParent;
+                newNode = newParent;
+                found = true;
+                break;
+              }
+              logger.log('Failure: not a block function body.');
+              return false;
+            } else if (oldParent is FunctionExpression &&
+                newParent is FunctionExpression) {
+              // skip
+            } else {
+              logger.log('Failure: old and new parent mismatch'
+                  ' ${oldParent.runtimeType} vs. ${newParent.runtimeType}');
+              return false;
             }
           }
           if (!found) {
@@ -1537,6 +1583,7 @@
         }
         // perform incremental resolution
         IncrementalResolver incrementalResolver = new IncrementalResolver(
+            _cache,
             _sourceEntry,
             _unitEntry,
             _unitElement,
@@ -1555,9 +1602,12 @@
         return true;
       }
     } catch (e, st) {
-      logger.log(e);
-      logger.log(st);
+      logger.logException(e, st);
       logger.log('Failure: exception.');
+      // The incremental resolver log is usually turned off,
+      // so also log the exception to the instrumentation log.
+      AnalysisEngine.instance.logger.logError(
+          'Failure in incremental resolver', new CaughtException(e, st));
     } finally {
       logger.exit();
     }
@@ -1571,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;
@@ -1595,8 +1646,13 @@
     // find nodes
     int offset = oldComments.offset;
     logger.log('offset: $offset');
-    Comment oldComment = _findNodeCovering(_oldUnit, offset, offset);
-    Comment newComment = _findNodeCovering(newUnit, offset, offset);
+    AstNode oldNode = _findNodeCovering(_oldUnit, offset, offset);
+    AstNode newNode = _findNodeCovering(newUnit, offset, offset);
+    if (oldNode is! Comment || newNode is! Comment) {
+      return false;
+    }
+    Comment oldComment = oldNode;
+    Comment newComment = newNode;
     logger.log('oldComment.beginToken: ${oldComment.beginToken}');
     logger.log('newComment.beginToken: ${newComment.beginToken}');
     _updateOffset = oldToken.offset - 1;
@@ -1607,6 +1663,7 @@
     NodeReplacer.replace(oldComment, newComment);
     // update elements
     IncrementalResolver incrementalResolver = new IncrementalResolver(
+        _cache,
         _sourceEntry,
         _unitEntry,
         _unitElement,
@@ -1733,7 +1790,7 @@
         Token newComment = newToken.precedingComments;
         if (_compareToken(oldComment, newComment, 0, true) != null) {
           _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT;
-          if (oldComment is DocumentationCommentToken ||
+          if (oldComment is DocumentationCommentToken &&
               newComment is DocumentationCommentToken) {
             diffKind = _TokenDifferenceKind.COMMENT_DOC;
           }
@@ -1769,7 +1826,7 @@
         Token newComment = newToken.precedingComments;
         if (_compareToken(oldComment, newComment, delta, true) != null) {
           _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT;
-          if (oldComment is DocumentationCommentToken ||
+          if (oldComment is DocumentationCommentToken &&
               newComment is DocumentationCommentToken) {
             diffKind = _TokenDifferenceKind.COMMENT_DOC;
           }
@@ -1995,36 +2052,84 @@
  */
 class _DeclarationMismatchException {}
 
+/**
+ * Adjusts the location of each Element that moved.
+ *
+ * Since `==` and `hashCode` of a local variable or function Element are based
+ * on the element name offsets, we also need to remove these elements from the
+ * cache to avoid a memory leak. TODO(scheglov) fix and remove this
+ */
 class _ElementOffsetUpdater extends GeneralizingElementVisitor {
   final int updateOffset;
   final int updateDelta;
+  final AnalysisCache cache;
 
-  _ElementOffsetUpdater(this.updateOffset, this.updateDelta);
+  _ElementOffsetUpdater(this.updateOffset, this.updateDelta, this.cache);
 
   @override
   visitElement(Element element) {
     // name offset
     int nameOffset = element.nameOffset;
     if (nameOffset > updateOffset) {
-      (element as ElementImpl).nameOffset = nameOffset + updateDelta;
+      // TODO(scheglov) make sure that we don't put local variables
+      // and functions into the cache at all.
+      try {
+        (element as ElementImpl).nameOffset = nameOffset + updateDelta;
+      } on FrozenHashCodeException {
+        cache.remove(element);
+        (element as ElementImpl).nameOffset = nameOffset + updateDelta;
+      }
+      if (element is ConstVariableElement) {
+        ConstVariableElement constVariable = element as ConstVariableElement;
+        Expression initializer = constVariable.constantInitializer;
+        if (initializer != null) {
+          _shiftTokens(initializer.beginToken);
+        }
+      }
     }
     // visible range
     if (element is LocalElement) {
       SourceRange visibleRange = element.visibleRange;
-      if (visibleRange != null && visibleRange.offset > updateOffset) {
-        int newOffset = visibleRange.offset + updateDelta;
-        int length = visibleRange.length;
-        if (element is FunctionElementImpl) {
-          element.setVisibleRange(newOffset, length);
-        } else if (element is LocalVariableElementImpl) {
-          element.setVisibleRange(newOffset, length);
-        } else if (element is ParameterElementImpl) {
-          element.setVisibleRange(newOffset, length);
+      if (visibleRange != null) {
+        int oldOffset = visibleRange.offset;
+        int oldLength = visibleRange.length;
+        int newOffset = oldOffset;
+        int newLength = oldLength;
+        newOffset += oldOffset > updateOffset ? updateDelta : 0;
+        newLength += visibleRange.contains(updateOffset) ? updateDelta : 0;
+        if (newOffset != oldOffset || newLength != oldLength) {
+          if (element is FunctionElementImpl) {
+            element.setVisibleRange(newOffset, newLength);
+          } else if (element is LocalVariableElementImpl) {
+            element.setVisibleRange(newOffset, newLength);
+          } else if (element is ParameterElementImpl) {
+            element.setVisibleRange(newOffset, newLength);
+          }
         }
       }
     }
     super.visitElement(element);
   }
+
+  void _shiftTokens(Token token) {
+    while (token != null) {
+      if (token.offset > updateOffset) {
+        token.offset += updateDelta;
+      }
+      // comments
+      _shiftTokens(token.precedingComments);
+      if (token is DocumentationCommentToken) {
+        for (Token reference in token.references) {
+          _shiftTokens(reference);
+        }
+      }
+      // next
+      if (token.type == TokenType.EOF) {
+        break;
+      }
+      token = token.next;
+    }
+  }
 }
 
 class _ElementsGatherer extends GeneralizingElementVisitor {
diff --git a/pkg/analyzer/lib/src/generated/incremental_scanner.dart b/pkg/analyzer/lib/src/generated/incremental_scanner.dart
index 6f4abee..ae34471 100644
--- a/pkg/analyzer/lib/src/generated/incremental_scanner.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_scanner.dart
@@ -6,9 +6,11 @@
 
 import "dart:math" as math;
 
+import 'package:analyzer/dart/ast/token.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/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart' show TokenMap;
 
@@ -203,8 +205,8 @@
    */
   bool _equalTokens(Token oldToken, Token newToken) =>
       oldToken.type == newToken.type &&
-          oldToken.length == newToken.length &&
-          oldToken.lexeme == newToken.lexeme;
+      oldToken.length == newToken.length &&
+      oldToken.lexeme == newToken.lexeme;
 
   /**
    * Given a [token], return the EOF token that follows the token.
diff --git a/pkg/analyzer/lib/src/generated/java_core.dart b/pkg/analyzer/lib/src/generated/java_core.dart
index acd2337..d28dd98 100644
--- a/pkg/analyzer/lib/src/generated/java_core.dart
+++ b/pkg/analyzer/lib/src/generated/java_core.dart
@@ -4,8 +4,6 @@
 
 library analyzer.src.generated.java_core;
 
-const int LONG_MAX_VALUE = 0x7fffffffffffffff;
-
 final Stopwatch nanoTimeStopwatch = new Stopwatch();
 
 /**
@@ -17,6 +15,8 @@
  */
 String format(String pattern,
     [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7]) {
+  // TODO(rnystrom): This is not used by analyzer, but is called by
+  // analysis_server. Move this code there and remove it from here.
   return formatList(pattern, [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7]);
 }
 
@@ -41,35 +41,6 @@
   });
 }
 
-bool javaCollectionContainsAll(Iterable list, Iterable c) {
-  return c.fold(true, (bool prev, e) => prev && list.contains(e));
-}
-
-javaListSet(List list, int index, newValue) {
-  var oldValue = list[index];
-  list[index] = newValue;
-  return oldValue;
-}
-
-bool javaSetEquals(Set a, Set b) {
-  return a.containsAll(b) && b.containsAll(a);
-}
-
-bool javaStringEqualsIgnoreCase(String a, String b) {
-  return a.toLowerCase() == b.toLowerCase();
-}
-
-bool javaStringRegionMatches(
-    String t, int toffset, String o, int ooffset, int len) {
-  if (toffset < 0) return false;
-  if (ooffset < 0) return false;
-  var tend = toffset + len;
-  var oend = ooffset + len;
-  if (tend > t.length) return false;
-  if (oend > o.length) return false;
-  return t.substring(toffset, tend) == o.substring(ooffset, oend);
-}
-
 /// Parses given string to [Uri], throws [URISyntaxException] if invalid.
 Uri parseUriWithException(String str) {
   Uri uri;
@@ -130,6 +101,7 @@
   static const int MIN_SUPPLEMENTARY_CODE_POINT = 0x010000;
   static const int MIN_LOW_SURROGATE = 0xDC00;
   static const int MIN_HIGH_SURROGATE = 0xD800;
+
   static int digit(int codePoint, int radix) {
     if (radix != 16) {
       throw new ArgumentError("only radix == 16 is supported");
@@ -146,29 +118,15 @@
     return -1;
   }
 
-  static bool isDigit(int c) {
-    return c >= 0x30 && c <= 0x39;
-  }
+  static bool isDigit(int c) => c >= 0x30 && c <= 0x39;
 
-  static bool isLetter(int c) {
-    return c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A;
-  }
+  static bool isLetter(int c) =>
+      c >= 0x41 && c <= 0x5A || c >= 0x61 && c <= 0x7A;
 
-  static bool isLetterOrDigit(int c) {
-    return isLetter(c) || isDigit(c);
-  }
+  static bool isLetterOrDigit(int c) => isLetter(c) || isDigit(c);
 
-  static bool isLowerCase(int c) {
-    return c >= 0x61 && c <= 0x7A;
-  }
-
-  static bool isUpperCase(int c) {
-    return c >= 0x41 && c <= 0x5A;
-  }
-
-  static bool isWhitespace(int c) {
-    return c == 0x09 || c == 0x20 || c == 0x0A || c == 0x0D;
-  }
+  static bool isWhitespace(int c) =>
+      c == 0x09 || c == 0x20 || c == 0x0A || c == 0x0D;
 
   static String toChars(int codePoint) {
     if (codePoint < 0 || codePoint > MAX_CODE_POINT) {
@@ -182,20 +140,6 @@
     int c1 = (offset & 0x3ff) + MIN_LOW_SURROGATE;
     return new String.fromCharCodes([c0, c1]);
   }
-
-  static int toLowerCase(int c) {
-    if (c >= 0x41 && c <= 0x5A) {
-      return 0x61 + (c - 0x41);
-    }
-    return c;
-  }
-
-  static int toUpperCase(int c) {
-    if (c >= 0x61 && c <= 0x7A) {
-      return 0x41 + (c - 0x61);
-    }
-    return c;
-  }
 }
 
 abstract class Enum<E extends Enum> implements Comparable<E> {
@@ -220,23 +164,9 @@
 }
 
 class JavaArrays {
-  static bool equals(List a, List b) {
-    if (identical(a, b)) {
-      return true;
-    }
-    if (a.length != b.length) {
-      return false;
-    }
-    var len = a.length;
-    for (int i = 0; i < len; i++) {
-      if (a[i] != b[i]) {
-        return false;
-      }
-    }
-    return true;
-  }
-
   static int makeHashCode(List a) {
+    // TODO(rnystrom): This is not used by analyzer, but is called by
+    // analysis_server. Move this code there and remove it from here.
     if (a == null) {
       return 0;
     }
@@ -250,7 +180,7 @@
 
 class JavaException implements Exception {
   final String message;
-  final Exception cause;
+  final Object cause;
   JavaException([this.message = "", this.cause = null]);
   JavaException.withCause(this.cause) : message = null;
   String toString() => "$runtimeType: $message $cause";
@@ -292,10 +222,6 @@
     if (fromIndex < 0) fromIndex = 0;
     return target.lastIndexOf(str, fromIndex);
   }
-
-  static bool startsWithBefore(String s, String other, int start) {
-    return s.indexOf(other, start) != -1;
-  }
 }
 
 class JavaSystem {
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 de0306f..9eff933 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -7,13 +7,21 @@
 import 'dart:collection';
 import "dart:math" as math;
 
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisEngine, AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/generated/shared_messages.dart'
+    as shared_messages;
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart' show TokenMap;
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -117,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(
@@ -2502,7 +2508,7 @@
             commentAndMetadata.metadata,
             null,
             new VariableDeclarationList(null, null, keyword, null, variables),
-            _expectSemicolon());
+            _expect(TokenType.SEMICOLON));
       }
       _reportErrorForToken(
           ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
@@ -3789,17 +3795,15 @@
       }
       _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;
   }
 
   /**
    * If the current token has the type [TokenType.GT], return it after advancing
-   * to the next token. Otherwise report an error and return the current token
-   * without advancing.
+   * to the next token. Otherwise report an error and create a synthetic token.
    */
   Token _expectGt() {
     if (_matchesGt()) {
@@ -3807,7 +3811,7 @@
     }
     _reportErrorForCurrentToken(
         ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
-    return _currentToken;
+    return _createSyntheticToken(TokenType.GT);
   }
 
   /**
@@ -3827,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.
@@ -3944,6 +3933,8 @@
           String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2);
           Token list = _scanGenericMethodComment(comment, t.offset + prefixLen);
           if (list != null) {
+            // Remove the token from the comment stream.
+            t.remove();
             // Insert the tokens into the stream.
             _injectTokenList(list);
             return true;
@@ -4167,7 +4158,7 @@
     return false;
   }
 
-  bool _isLikelyParameterList() {
+  bool _isLikelyArgumentList() {
     if (_matches(TokenType.OPEN_PAREN)) {
       return true;
     }
@@ -4235,7 +4226,7 @@
     if (!parseGenericMethods) {
       return false;
     }
-    Token token = _skipTypeArgumentList(_peek());
+    Token token = _skipTypeParameterList(_peek());
     return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
   }
 
@@ -4455,7 +4446,7 @@
     Expression expression = _parsePrimaryExpression();
     bool isOptional = primaryAllowed || expression is SimpleIdentifier;
     while (true) {
-      while (_isLikelyParameterList()) {
+      while (_isLikelyArgumentList()) {
         TypeArgumentList typeArguments = _parseOptionalTypeArguments();
         ArgumentList argumentList = parseArgumentList();
         if (expression is SimpleIdentifier) {
@@ -4663,8 +4654,8 @@
     }
     assert((expression == null && functionName != null) ||
         (expression != null && functionName == null));
-    if (_isLikelyParameterList()) {
-      while (_isLikelyParameterList()) {
+    if (_isLikelyArgumentList()) {
+      while (_isLikelyArgumentList()) {
         TypeArgumentList typeArguments = _parseOptionalTypeArguments();
         if (functionName != null) {
           expression = new MethodInvocation(expression, period, functionName,
@@ -4692,7 +4683,7 @@
       if (!identical(selector, expression)) {
         expression = selector;
         progress = true;
-        while (_isLikelyParameterList()) {
+        while (_isLikelyArgumentList()) {
           TypeArgumentList typeArguments = _parseOptionalTypeArguments();
           if (expression is PropertyAccess) {
             PropertyAccess propertyAccess = expression as PropertyAccess;
@@ -5232,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;
@@ -5369,12 +5360,13 @@
    */
   Expression _parseConstExpression() {
     Token keyword = _expectKeyword(Keyword.CONST);
-    if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.INDEX)) {
+    if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) {
+      return _parseListOrMapLiteral(keyword);
+    } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
+        _matches(TokenType.INDEX)) {
       return _parseListLiteral(keyword, null);
     } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
       return _parseMapLiteral(keyword, null);
-    } else if (_matches(TokenType.LT)) {
-      return _parseListOrMapLiteral(keyword);
     }
     return _parseInstanceCreationExpression(keyword);
   }
@@ -5449,9 +5441,12 @@
         if (constKeyword != null) {
           _reportErrorForNode(
               ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body);
-        } else if (!bodyAllowed) {
+        } else if (externalKeyword != null) {
           _reportErrorForNode(
               ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body);
+        } else if (!bodyAllowed) {
+          _reportErrorForNode(
+              ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, body);
         }
       }
     }
@@ -5804,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,
@@ -6027,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();
@@ -6507,7 +6502,7 @@
       }
     }
     List<Combinator> combinators = _parseCombinators();
-    Token semicolon = _expectSemicolon();
+    Token semicolon = _expect(TokenType.SEMICOLON);
     return new ImportDirective(
         commentAndMetadata.comment,
         commentAndMetadata.metadata,
@@ -7044,7 +7039,8 @@
             _peek().matchesAny([
               TokenType.OPEN_PAREN,
               TokenType.OPEN_CURLY_BRACKET,
-              TokenType.FUNCTION
+              TokenType.FUNCTION,
+              TokenType.LT
             ])) {
           return _parseFunctionDeclarationStatementAfterReturnType(
               commentAndMetadata, returnType);
@@ -7140,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));
     }
   }
 
@@ -7299,7 +7296,7 @@
         _matches(TokenType.OPEN_PAREN) ||
         (parseGenericMethods && _matches(TokenType.LT))) {
       do {
-        if (_isLikelyParameterList()) {
+        if (_isLikelyArgumentList()) {
           TypeArgumentList typeArguments = _parseOptionalTypeArguments();
           ArgumentList argumentList = parseArgumentList();
           if (operand is PropertyAccess) {
@@ -7394,11 +7391,6 @@
       return new IntegerLiteral(token, value);
     } else if (_matches(TokenType.STRING)) {
       return parseStringLiteral();
-    } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
-      return _parseMapLiteral(null, null);
-    } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
-        _matches(TokenType.INDEX)) {
-      return _parseListLiteral(null, null);
     } else if (_matchesIdentifier()) {
       // TODO(brianwilkerson) The code below was an attempt to recover from an
       // error case, but it needs to be applied as a recovery only after we
@@ -7431,8 +7423,13 @@
       } finally {
         _inInitializer = wasInInitializer;
       }
-    } else if (_matches(TokenType.LT)) {
+    } else if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) {
       return _parseListOrMapLiteral(null);
+    } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
+      return _parseMapLiteral(null, null);
+    } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
+        _matches(TokenType.INDEX)) {
+      return _parseListLiteral(null, null);
     } else if (_matches(TokenType.QUESTION) &&
         _tokenMatches(_peek(), TokenType.IDENTIFIER)) {
       _reportErrorForCurrentToken(
@@ -9381,52 +9378,39 @@
   /**
    * Some environments, such as Fletch, do not support async.
    */
-  static const CompileTimeErrorCode ASYNC_NOT_SUPPORTED =
-      const CompileTimeErrorCode('ASYNC_NOT_SUPPORTED',
-          "Async and sync are not supported in this environment.");
+  static const ParserErrorCode ASYNC_NOT_SUPPORTED = const ParserErrorCode(
+      'ASYNC_NOT_SUPPORTED',
+      "Async and sync are not supported in this environment.");
 
   static const ParserErrorCode BREAK_OUTSIDE_OF_LOOP = const ParserErrorCode(
       'BREAK_OUTSIDE_OF_LOOP',
       "A break statement cannot be used outside of a loop or switch statement");
 
-  static const ParserErrorCode CLASS_IN_CLASS = const ParserErrorCode(
-      'CLASS_IN_CLASS', "Classes cannot be declared inside other classes");
+  static const ParserErrorCode CLASS_IN_CLASS = shared_messages.CLASS_IN_CLASS;
 
   static const ParserErrorCode COLON_IN_PLACE_OF_IN = const ParserErrorCode(
       'COLON_IN_PLACE_OF_IN', "For-in loops use 'in' rather than a colon");
 
-  static const ParserErrorCode CONST_AND_FINAL = const ParserErrorCode(
-      'CONST_AND_FINAL',
-      "Members cannot be declared to be both 'const' and 'final'");
+  static const ParserErrorCode CONST_AND_FINAL =
+      shared_messages.CONST_AND_FINAL;
 
-  static const ParserErrorCode CONST_AND_VAR = const ParserErrorCode(
-      'CONST_AND_VAR',
-      "Members cannot be declared to be both 'const' and 'var'");
+  static const ParserErrorCode CONST_AND_VAR = shared_messages.CONST_AND_VAR;
 
-  static const ParserErrorCode CONST_CLASS = const ParserErrorCode(
-      'CONST_CLASS', "Classes cannot be declared to be 'const'");
+  static const ParserErrorCode CONST_CLASS = shared_messages.CONST_CLASS;
 
   static const ParserErrorCode CONST_CONSTRUCTOR_WITH_BODY =
-      const ParserErrorCode('CONST_CONSTRUCTOR_WITH_BODY',
-          "'const' constructors cannot have a body");
+      shared_messages.CONST_CONSTRUCTOR_WITH_BODY;
 
-  static const ParserErrorCode CONST_ENUM = const ParserErrorCode(
-      'CONST_ENUM', "Enums cannot be declared to be 'const'");
+  static const ParserErrorCode CONST_ENUM = shared_messages.CONST_ENUM;
 
-  static const ParserErrorCode CONST_FACTORY = const ParserErrorCode(
-      'CONST_FACTORY',
-      "Only redirecting factory constructors can be declared to be 'const'");
+  static const ParserErrorCode CONST_FACTORY = shared_messages.CONST_FACTORY;
 
-  static const ParserErrorCode CONST_METHOD = const ParserErrorCode(
-      'CONST_METHOD',
-      "Getters, setters and methods cannot be declared to be 'const'");
+  static const ParserErrorCode CONST_METHOD = shared_messages.CONST_METHOD;
 
-  static const ParserErrorCode CONST_TYPEDEF = const ParserErrorCode(
-      'CONST_TYPEDEF', "Type aliases cannot be declared to be 'const'");
+  static const ParserErrorCode CONST_TYPEDEF = shared_messages.CONST_TYPEDEF;
 
   static const ParserErrorCode CONSTRUCTOR_WITH_RETURN_TYPE =
-      const ParserErrorCode('CONSTRUCTOR_WITH_RETURN_TYPE',
-          "Constructors cannot have a return type");
+      shared_messages.CONSTRUCTOR_WITH_RETURN_TYPE;
 
   static const ParserErrorCode CONTINUE_OUTSIDE_OF_LOOP = const ParserErrorCode(
       'CONTINUE_OUTSIDE_OF_LOOP',
@@ -9686,8 +9670,7 @@
           "Expected an expression after the assignment operator");
 
   static const ParserErrorCode MISSING_EXPRESSION_IN_THROW =
-      const ParserErrorCode('MISSING_EXPRESSION_IN_THROW',
-          "Throw expressions must compute the object to be thrown");
+      shared_messages.MISSING_EXPRESSION_IN_THROW;
 
   static const ParserErrorCode MISSING_FUNCTION_BODY = const ParserErrorCode(
       'MISSING_FUNCTION_BODY', "A function body must be provided");
@@ -9832,6 +9815,10 @@
       const ParserErrorCode('POSITIONAL_PARAMETER_OUTSIDE_GROUP',
           "Positional parameters must be enclosed in square brackets ('[' and ']')");
 
+  static const ParserErrorCode REDIRECTING_CONSTRUCTOR_WITH_BODY =
+      const ParserErrorCode('REDIRECTING_CONSTRUCTOR_WITH_BODY',
+          "Redirecting constructors cannot have a body");
+
   static const ParserErrorCode REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR =
       const ParserErrorCode('REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR',
           "Only factory constructor can specify '=' redirection.");
@@ -9969,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
@@ -10519,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;
@@ -10781,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 0d856c8..491d391 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -6,13 +6,19 @@
 
 import 'dart:collection';
 
+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/dart/element/type.dart';
 import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/element/utilities.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/element_resolver.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -20,7 +26,6 @@
 import 'package:analyzer/src/generated/error_verifier.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/static_type_analyzer.dart';
 import 'package:analyzer/src/generated/type_system.dart';
@@ -201,6 +206,7 @@
   @override
   Object visitMethodInvocation(MethodInvocation node) {
     _checkForCanBeNullAfterNullAware(node.realTarget, node.operator);
+    _checkForInvalidProtectedMethodCalls(node);
     return super.visitMethodInvocation(node);
   }
 
@@ -232,6 +238,7 @@
   @override
   Object visitSimpleIdentifier(SimpleIdentifier node) {
     _checkForDeprecatedMemberUseAtIdentifier(node);
+    _checkForInvalidProtectedPropertyAccess(node);
     return super.visitSimpleIdentifier(node);
   }
 
@@ -517,6 +524,8 @@
     }
     AstNode parent = identifier.parent;
     if ((parent is ConstructorName && identical(identifier, parent.name)) ||
+        (parent is ConstructorDeclaration &&
+            identical(identifier, parent.returnType)) ||
         (parent is SuperConstructorInvocation &&
             identical(identifier, parent.constructorName)) ||
         parent is HideCombinator) {
@@ -601,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.
    *
@@ -783,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`.
    *
@@ -860,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 =
@@ -884,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
@@ -906,6 +997,63 @@
 }
 
 /**
+ * Utilities for [LibraryElementImpl] building.
+ */
+class BuildLibraryElementUtils {
+  /**
+   * Look through all of the compilation units defined for the given [library],
+   * looking for getters and setters that are defined in different compilation
+   * units but that have the same names. If any are found, make sure that they
+   * have the same variable element.
+   */
+  static void patchTopLevelAccessors(LibraryElementImpl library) {
+    // Without parts getters/setters already share the same variable element.
+    if (library.parts.isEmpty) {
+      return;
+    }
+    // Collect getters and setters.
+    HashMap<String, PropertyAccessorElement> getters =
+        new HashMap<String, PropertyAccessorElement>();
+    List<PropertyAccessorElement> setters = <PropertyAccessorElement>[];
+    _collectAccessors(getters, setters, library.definingCompilationUnit);
+    for (CompilationUnitElement unit in library.parts) {
+      _collectAccessors(getters, setters, unit);
+    }
+    // Move every setter to the corresponding getter's variable (if exists).
+    for (PropertyAccessorElement setter in setters) {
+      PropertyAccessorElement getter = getters[setter.displayName];
+      if (getter != null) {
+        TopLevelVariableElementImpl variable = getter.variable;
+        TopLevelVariableElementImpl setterVariable = setter.variable;
+        CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement;
+        setterUnit.replaceTopLevelVariable(setterVariable, variable);
+        variable.setter = setter;
+        (setter as PropertyAccessorElementImpl).variable = variable;
+      }
+    }
+  }
+
+  /**
+   * Add all of the non-synthetic [getters] and [setters] defined in the given
+   * [unit] that have no corresponding accessor to one of the given collections.
+   */
+  static void _collectAccessors(Map<String, PropertyAccessorElement> getters,
+      List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
+    for (PropertyAccessorElement accessor in unit.accessors) {
+      if (accessor.isGetter) {
+        if (!accessor.isSynthetic && accessor.correspondingSetter == null) {
+          getters[accessor.displayName] = accessor;
+        }
+      } else {
+        if (!accessor.isSynthetic && accessor.correspondingGetter == null) {
+          setters.add(accessor);
+        }
+      }
+    }
+  }
+}
+
+/**
  * Instances of the class `ClassScope` implement the scope defined by a class.
  */
 class ClassScope extends EnclosedScope {
@@ -961,43 +1109,6 @@
 }
 
 /**
- * A `CompilationUnitBuilder` builds an element model for a single compilation
- * unit.
- */
-class CompilationUnitBuilder {
-  /**
-   * Build the compilation unit element for the given [source] based on the
-   * compilation [unit] associated with the source. Throw an AnalysisException
-   * if the element could not be built.  [librarySource] is the source for the
-   * containing library.
-   */
-  CompilationUnitElementImpl buildCompilationUnit(
-      Source source, CompilationUnit unit, Source librarySource) {
-    return PerformanceStatistics.resolve.makeCurrentWhile(() {
-      if (unit == null) {
-        return null;
-      }
-      ElementHolder holder = new ElementHolder();
-      ElementBuilder builder = new ElementBuilder(holder);
-      unit.accept(builder);
-      CompilationUnitElementImpl element =
-          new CompilationUnitElementImpl(source.shortName);
-      element.accessors = holder.accessors;
-      element.enums = holder.enums;
-      element.functions = holder.functions;
-      element.source = source;
-      element.librarySource = librarySource;
-      element.typeAliases = holder.typeAliases;
-      element.types = holder.types;
-      element.topLevelVariables = holder.topLevelVariables;
-      unit.element = element;
-      holder.validate();
-      return element;
-    });
-  }
-}
-
-/**
  * Instances of the class `ConstantVerifier` traverse an AST structure looking for additional
  * errors and warnings not covered by the parser and resolver. In particular, it looks for errors
  * and warnings related to constant expressions.
@@ -2006,50 +2117,65 @@
 }
 
 /**
- * Instances of the class `DeclarationResolver` are used to resolve declarations in an AST
- * structure to already built elements.
+ * A visitor that resolves declarations in an AST structure to already built
+ * elements.
  */
 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.
+   */
+  Set<Element> _expectedElements;
+
+  /**
    * The compilation unit containing the AST nodes being visited.
    */
   CompilationUnitElement _enclosingUnit;
 
   /**
-   * The function type alias containing the AST nodes being visited, or `null` if we are not
-   * in the scope of a function type alias.
+   * The function type alias containing the AST nodes being visited, or `null`
+   * if we are not in the scope of a function type alias.
    */
   FunctionTypeAliasElement _enclosingAlias;
 
   /**
-   * The class containing the AST nodes being visited, or `null` if we are not in the scope of
-   * a class.
+   * The class containing the AST nodes being visited, or `null` if we are not
+   * in the scope of a class.
    */
   ClassElement _enclosingClass;
 
   /**
-   * The method or function containing the AST nodes being visited, or `null` if we are not in
-   * the scope of a method or function.
+   * The method or function containing the AST nodes being visited, or `null` if
+   * we are not in the scope of a method or function.
    */
   ExecutableElement _enclosingExecutable;
 
   /**
-   * The parameter containing the AST nodes being visited, or `null` if we are not in the
-   * scope of a parameter.
+   * The parameter containing the AST nodes being visited, or `null` if we are
+   * not in the scope of a parameter.
    */
   ParameterElement _enclosingParameter;
 
   /**
-   * Resolve the declarations within the given compilation unit to the elements rooted at the given
-   * element.
-   *
-   * @param unit the compilation unit to be resolved
-   * @param element the root of the element model used to resolve the AST nodes
+   * Resolve the declarations within the given compilation [unit] to the
+   * elements rooted at the given [element]. Throw an [ElementMismatchException]
+   * 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;
     _enclosingUnit = element;
+    _expectedElements.remove(element);
     unit.element = element;
     unit.accept(this);
+    _validateResolution();
   }
 
   @override
@@ -2073,7 +2199,9 @@
     try {
       SimpleIdentifier className = node.name;
       _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
-      return super.visitClassDeclaration(node);
+      super.visitClassDeclaration(node);
+      _resolveMetadata(node.metadata, _enclosingClass);
+      return null;
     } finally {
       _enclosingClass = outerClass;
     }
@@ -2085,7 +2213,9 @@
     try {
       SimpleIdentifier className = node.name;
       _enclosingClass = _findIdentifier(_enclosingUnit.types, className);
-      return super.visitClassTypeAlias(node);
+      super.visitClassTypeAlias(node);
+      _resolveMetadata(node.metadata, _enclosingClass);
+      return null;
     } finally {
       _enclosingClass = outerClass;
     }
@@ -2098,13 +2228,24 @@
       SimpleIdentifier constructorName = node.name;
       if (constructorName == null) {
         _enclosingExecutable = _enclosingClass.unnamedConstructor;
+        if (_enclosingExecutable == null) {
+          _mismatch('Could not find default constructor', node);
+        }
       } else {
         _enclosingExecutable =
             _enclosingClass.getNamedConstructor(constructorName.name);
+        if (_enclosingExecutable == null) {
+          _mismatch(
+              'Could not find constructor element with name "${constructorName.name}',
+              node);
+        }
         constructorName.staticElement = _enclosingExecutable;
       }
+      _expectedElements.remove(_enclosingExecutable);
       node.element = _enclosingExecutable as ConstructorElement;
-      return super.visitConstructorDeclaration(node);
+      super.visitConstructorDeclaration(node);
+      _resolveMetadata(node.metadata, _enclosingExecutable);
+      return null;
     } finally {
       _enclosingExecutable = outerExecutable;
     }
@@ -2113,8 +2254,11 @@
   @override
   Object visitDeclaredIdentifier(DeclaredIdentifier node) {
     SimpleIdentifier variableName = node.identifier;
-    _findIdentifier(_enclosingExecutable.localVariables, variableName);
-    return super.visitDeclaredIdentifier(node);
+    Element element =
+        _findIdentifier(_enclosingExecutable.localVariables, variableName);
+    super.visitDeclaredIdentifier(node);
+    _resolveMetadata(node.metadata, element);
+    return null;
   }
 
   @override
@@ -2125,11 +2269,7 @@
     if (defaultValue != null) {
       ExecutableElement outerExecutable = _enclosingExecutable;
       try {
-        if (element == null) {
-          // TODO(brianwilkerson) Report this internal error.
-        } else {
-          _enclosingExecutable = element.initializer;
-        }
+        _enclosingExecutable = element.initializer;
         defaultValue.accept(this);
       } finally {
         _enclosingExecutable = outerExecutable;
@@ -2138,7 +2278,9 @@
     ParameterElement outerParameter = _enclosingParameter;
     try {
       _enclosingParameter = element;
-      return super.visitDefaultFormalParameter(node);
+      super.visitDefaultFormalParameter(node);
+      _resolveMetadata(node.metadata, element);
+      return null;
     } finally {
       _enclosingParameter = outerParameter;
     }
@@ -2152,21 +2294,32 @@
     for (EnumConstantDeclaration constant in node.constants) {
       _findIdentifier(constants, constant.name);
     }
-    return super.visitEnumDeclaration(node);
+    super.visitEnumDeclaration(node);
+    _resolveMetadata(node.metadata, enclosingEnum);
+    return null;
   }
 
   @override
   Object visitExportDirective(ExportDirective node) {
     String uri = _getStringValue(node.uri);
+    ExportElement exportElement;
     if (uri != null) {
       LibraryElement library = _enclosingUnit.library;
-      ExportElement exportElement = _findExport(
-          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;
     }
-    return super.visitExportDirective(node);
+    super.visitExportDirective(node);
+    _resolveMetadata(node.metadata, exportElement);
+    return null;
+  }
+
+  @override
+  Object visitFieldDeclaration(FieldDeclaration node) {
+    super.visitFieldDeclaration(node);
+    _resolveMetadata(node.metadata, node.fields.variables[0].element);
+    return null;
   }
 
   @override
@@ -2177,7 +2330,9 @@
       ParameterElement outerParameter = _enclosingParameter;
       try {
         _enclosingParameter = element;
-        return super.visitFieldFormalParameter(node);
+        super.visitFieldFormalParameter(node);
+        _resolveMetadata(node.metadata, element);
+        return null;
       } finally {
         _enclosingParameter = outerParameter;
       }
@@ -2205,17 +2360,28 @@
           _enclosingExecutable =
               _findIdentifier(_enclosingExecutable.functions, functionName);
         } else {
-          PropertyAccessorElement accessor =
-              _findIdentifier(_enclosingUnit.accessors, functionName);
-          if ((property as KeywordToken).keyword == Keyword.SET) {
-            accessor = accessor.variable.setter;
+          List<PropertyAccessorElement> accessors;
+          if (_enclosingClass != null) {
+            accessors = _enclosingClass.accessors;
+          } else {
+            accessors = _enclosingUnit.accessors;
+          }
+          PropertyAccessorElement accessor;
+          if ((property as KeywordToken).keyword == Keyword.GET) {
+            accessor = _findIdentifier(accessors, functionName);
+          } else if ((property as KeywordToken).keyword == Keyword.SET) {
+            accessor = _findWithNameAndOffset(accessors, functionName,
+                functionName.name + '=', functionName.offset);
+            _expectedElements.remove(accessor);
             functionName.staticElement = accessor;
           }
           _enclosingExecutable = accessor;
         }
       }
       node.functionExpression.element = _enclosingExecutable;
-      return super.visitFunctionDeclaration(node);
+      super.visitFunctionDeclaration(node);
+      _resolveMetadata(node.metadata, _enclosingExecutable);
+      return null;
     } finally {
       _enclosingExecutable = outerExecutable;
     }
@@ -2224,8 +2390,9 @@
   @override
   Object visitFunctionExpression(FunctionExpression node) {
     if (node.parent is! FunctionDeclaration) {
-      FunctionElement element =
-          _findAtOffset(_enclosingExecutable.functions, node.beginToken.offset);
+      FunctionElement element = _findAtOffset(
+          _enclosingExecutable.functions, node, node.beginToken.offset);
+      _expectedElements.remove(element);
       node.element = element;
     }
     ExecutableElement outerExecutable = _enclosingExecutable;
@@ -2244,7 +2411,9 @@
       SimpleIdentifier aliasName = node.name;
       _enclosingAlias =
           _findIdentifier(_enclosingUnit.functionTypeAliases, aliasName);
-      return super.visitFunctionTypeAlias(node);
+      super.visitFunctionTypeAlias(node);
+      _resolveMetadata(node.metadata, _enclosingAlias);
+      return null;
     } finally {
       _enclosingAlias = outerAlias;
     }
@@ -2258,7 +2427,9 @@
       ParameterElement outerParameter = _enclosingParameter;
       try {
         _enclosingParameter = element;
-        return super.visitFunctionTypedFormalParameter(node);
+        super.visitFunctionTypedFormalParameter(node);
+        _resolveMetadata(node.metadata, _enclosingParameter);
+        return null;
       } finally {
         _enclosingParameter = outerParameter;
       }
@@ -2270,16 +2441,17 @@
   @override
   Object visitImportDirective(ImportDirective node) {
     String uri = _getStringValue(node.uri);
+    ImportElement importElement;
     if (uri != null) {
       LibraryElement library = _enclosingUnit.library;
-      ImportElement importElement = _findImport(
-          library.imports,
-          _enclosingUnit.context.sourceFactory
-              .resolveUri(_enclosingUnit.source, uri),
-          node.prefix);
+      Source source = _enclosingUnit.context.sourceFactory
+          .resolveUri(_enclosingUnit.source, uri);
+      importElement = _findImport(node, library.imports, source);
       node.element = importElement;
     }
-    return super.visitImportDirective(node);
+    super.visitImportDirective(node);
+    _resolveMetadata(node.metadata, importElement);
+    return null;
   }
 
   @override
@@ -2293,8 +2465,11 @@
 
   @override
   Object visitLibraryDirective(LibraryDirective node) {
-    node.element = _enclosingUnit.library;
-    return super.visitLibraryDirective(node);
+    LibraryElement libraryElement = _enclosingUnit.library;
+    node.element = libraryElement;
+    super.visitLibraryDirective(node);
+    _resolveMetadata(node.metadata, libraryElement);
+    return null;
   }
 
   @override
@@ -2305,19 +2480,28 @@
       SimpleIdentifier methodName = node.name;
       String nameOfMethod = methodName.name;
       if (property == null) {
-        _enclosingExecutable = _findWithNameAndOffset(
-            _enclosingClass.methods, nameOfMethod, methodName.offset);
+        String elementName = nameOfMethod == '-' &&
+            node.parameters != null &&
+            node.parameters.parameters.isEmpty ? 'unary-' : nameOfMethod;
+        _enclosingExecutable = _findWithNameAndOffset(_enclosingClass.methods,
+            methodName, elementName, methodName.offset);
+        _expectedElements.remove(_enclosingExecutable);
         methodName.staticElement = _enclosingExecutable;
       } else {
-        PropertyAccessorElement accessor =
-            _findIdentifier(_enclosingClass.accessors, methodName);
-        if ((property as KeywordToken).keyword == Keyword.SET) {
-          accessor = accessor.variable.setter;
+        PropertyAccessorElement accessor;
+        if ((property as KeywordToken).keyword == Keyword.GET) {
+          accessor = _findIdentifier(_enclosingClass.accessors, methodName);
+        } else if ((property as KeywordToken).keyword == Keyword.SET) {
+          accessor = _findWithNameAndOffset(_enclosingClass.accessors,
+              methodName, nameOfMethod + '=', methodName.offset);
+          _expectedElements.remove(accessor);
           methodName.staticElement = accessor;
         }
         _enclosingExecutable = accessor;
       }
-      return super.visitMethodDeclaration(node);
+      super.visitMethodDeclaration(node);
+      _resolveMetadata(node.metadata, _enclosingExecutable);
+      return null;
     } finally {
       _enclosingExecutable = outerExecutable;
     }
@@ -2326,12 +2510,16 @@
   @override
   Object visitPartDirective(PartDirective node) {
     String uri = _getStringValue(node.uri);
+    CompilationUnitElement compilationUnitElement;
     if (uri != null) {
       Source partSource = _enclosingUnit.context.sourceFactory
           .resolveUri(_enclosingUnit.source, uri);
-      node.element = _findPart(_enclosingUnit.library.parts, partSource);
+      compilationUnitElement =
+          _findPart(_enclosingUnit.library.parts, node, partSource);
     }
-    return super.visitPartDirective(node);
+    super.visitPartDirective(node);
+    _resolveMetadata(node.metadata, compilationUnitElement);
+    return null;
   }
 
   @override
@@ -2348,7 +2536,9 @@
       ParameterElement outerParameter = _enclosingParameter;
       try {
         _enclosingParameter = element;
-        return super.visitSimpleFormalParameter(node);
+        super.visitSimpleFormalParameter(node);
+        _resolveMetadata(node.metadata, element);
+        return null;
       } finally {
         _enclosingParameter = outerParameter;
       }
@@ -2375,22 +2565,39 @@
   }
 
   @override
+  Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+    super.visitTopLevelVariableDeclaration(node);
+    _resolveMetadata(node.metadata, node.variables.variables[0].element);
+    return null;
+  }
+
+  @override
   Object visitTypeParameter(TypeParameter node) {
     SimpleIdentifier parameterName = node.name;
-
-    Element element;
+    Element element = null;
     if (_enclosingExecutable != null) {
-      element =
-          _findIdentifier(_enclosingExecutable.typeParameters, parameterName);
+      element = _findIdentifier(
+          _enclosingExecutable.typeParameters, parameterName,
+          required: false);
     }
     if (element == null) {
       if (_enclosingClass != null) {
-        _findIdentifier(_enclosingClass.typeParameters, parameterName);
+        element =
+            _findIdentifier(_enclosingClass.typeParameters, parameterName);
       } else if (_enclosingAlias != null) {
-        _findIdentifier(_enclosingAlias.typeParameters, parameterName);
+        element =
+            _findIdentifier(_enclosingAlias.typeParameters, parameterName);
       }
     }
-    return super.visitTypeParameter(node);
+    if (element == null) {
+      String name = parameterName.name;
+      int offset = parameterName.offset;
+      _mismatch(
+          'Could not find type parameter with name "$name" at $offset', node);
+    }
+    super.visitTypeParameter(node);
+    _resolveMetadata(node.metadata, element);
+    return null;
   }
 
   @override
@@ -2398,11 +2605,13 @@
     VariableElement element = null;
     SimpleIdentifier variableName = node.name;
     if (_enclosingExecutable != null) {
-      element =
-          _findIdentifier(_enclosingExecutable.localVariables, variableName);
+      element = _findIdentifier(
+          _enclosingExecutable.localVariables, variableName,
+          required: false);
     }
     if (element == null && _enclosingClass != null) {
-      element = _findIdentifier(_enclosingClass.fields, variableName);
+      element = _findIdentifier(_enclosingClass.fields, variableName,
+          required: false);
     }
     if (element == null && _enclosingUnit != null) {
       element = _findIdentifier(_enclosingUnit.topLevelVariables, variableName);
@@ -2411,11 +2620,7 @@
     if (initializer != null) {
       ExecutableElement outerExecutable = _enclosingExecutable;
       try {
-        if (element == null) {
-          // TODO(brianwilkerson) Report this internal error.
-        } else {
-          _enclosingExecutable = element.initializer;
-        }
+        _enclosingExecutable = element.initializer;
         return super.visitVariableDeclaration(node);
       } finally {
         _enclosingExecutable = outerExecutable;
@@ -2424,64 +2629,78 @@
     return super.visitVariableDeclaration(node);
   }
 
-  /**
-   * Return the element in the given array of elements that was created for the declaration at the
-   * given offset. This method should only be used when there is no name
-   *
-   * @param elements the elements of the appropriate kind that exist in the current context
-   * @param offset the offset of the name of the element to be returned
-   * @return the element at the given offset
-   */
-  Element _findAtOffset(List<Element> elements, int offset) =>
-      _findWithNameAndOffset(elements, "", offset);
-
-  /**
-   * Return the export element from the given array whose library has the given source, or
-   * `null` if there is no such export.
-   *
-   * @param exports the export elements being searched
-   * @param source the source of the library associated with the export element to being searched
-   *          for
-   * @return the export element whose library has the given source
-   */
-  ExportElement _findExport(List<ExportElement> exports, Source source) {
-    for (ExportElement export in exports) {
-      if (export.exportedLibrary.source == source) {
-        return export;
-      }
+  @override
+  Object visitVariableDeclarationList(VariableDeclarationList node) {
+    super.visitVariableDeclarationList(node);
+    if (node.parent is! FieldDeclaration &&
+        node.parent is! TopLevelVariableDeclaration) {
+      _resolveMetadata(node.metadata, node.variables[0].element);
     }
     return null;
   }
 
   /**
-   * Return the element in the given array of elements that was created for the declaration with the
-   * given name.
+   * Return the element in the given list of [elements] that was created for the
+   * declaration at the given [offset]. Throw an [ElementMismatchException] if
+   * an element at that offset cannot be found.
    *
-   * @param elements the elements of the appropriate kind that exist in the current context
-   * @param identifier the name node in the declaration of the element to be returned
-   * @return the element created for the declaration with the given name
+   * This method should only be used when there is no name associated with the
+   * node.
    */
-  Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier) {
-    Element element =
-        _findWithNameAndOffset(elements, identifier.name, identifier.offset);
+  Element _findAtOffset(List<Element> elements, AstNode node, int offset) =>
+      _findWithNameAndOffset(elements, node, '', offset);
+
+  /**
+   * Return the export element from the given list of [exports] whose library
+   * has the given [source]. Throw an [ElementMismatchException] if an element
+   * corresponding to the identifier cannot be found.
+   */
+  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;
+      }
+    }
+    _mismatch("Could not find export element for '$source'", node);
+    return null; // Never reached
+  }
+
+  /**
+   * Return the element in the given list of [elements] that was created for the
+   * declaration with the given [identifier]. As a side-effect, associate the
+   * returned element with the identifier. Throw an [ElementMismatchException]
+   * if an element corresponding to the identifier cannot be found unless
+   * [required] is `false`, in which case return `null`.
+   */
+  Element _findIdentifier(List<Element> elements, SimpleIdentifier identifier,
+      {bool required: true}) {
+    Element element = _findWithNameAndOffset(
+        elements, identifier, identifier.name, identifier.offset,
+        required: required);
+    _expectedElements.remove(element);
     identifier.staticElement = element;
     return element;
   }
 
   /**
-   * Return the import element from the given array whose library has the given source and that has
-   * the given prefix, or `null` if there is no such import.
-   *
-   * @param imports the import elements being searched
-   * @param source the source of the library associated with the import element to being searched
-   *          for
-   * @param prefix the prefix with which the library was imported
-   * @return the import element whose library has the given source and prefix
+   * Return the import element from the given list of [imports] whose library
+   * has the given [source]. Throw an [ElementMismatchException] if an element
+   * corresponding to the [source] cannot be found.
    */
   ImportElement _findImport(
-      List<ImportElement> imports, Source source, SimpleIdentifier prefix) {
+      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) {
       if (element.importedLibrary.source == source) {
+        foundSource = true;
         PrefixElement prefixElement = element.prefix;
         if (prefix == null) {
           if (prefixElement == null) {
@@ -2495,52 +2714,76 @@
         }
       }
     }
-    return null;
+    if (foundSource) {
+      if (prefix == null) {
+        _mismatch(
+            "Could not find import element for '$source' with no prefix", node);
+      }
+      _mismatch(
+          "Could not find import element for '$source' with prefix ${prefix.name}",
+          node);
+    }
+    _mismatch("Could not find import element for '$source'", node);
+    return null; // Never reached
   }
 
   /**
-   * Return the element for the part with the given source, or `null` if there is no element
-   * for the given source.
-   *
-   * @param parts the elements for the parts
-   * @param partSource the source for the part whose element is to be returned
-   * @return the element for the part with the given source
+   * Return the element in the given list of [parts] that was created for the
+   * part with the given [source]. Throw an [ElementMismatchException] if an
+   * element corresponding to the source cannot be found.
    */
-  CompilationUnitElement _findPart(
-      List<CompilationUnitElement> parts, Source partSource) {
+  CompilationUnitElement _findPart(List<CompilationUnitElement> parts,
+      PartDirective directive, Source source) {
     for (CompilationUnitElement part in parts) {
-      if (part.source == partSource) {
+      if (part.source == source) {
         return part;
       }
     }
-    return null;
+    _mismatch(
+        'Could not find compilation unit element for "$source"', directive);
+    return null; // Never reached
   }
 
   /**
-   * Return the element in the given array of elements that was created for the declaration with the
-   * given name at the given offset.
-   *
-   * @param elements the elements of the appropriate kind that exist in the current context
-   * @param name the name of the element to be returned
-   * @param offset the offset of the name of the element to be returned
-   * @return the element with the given name and offset
+   * Return the element in the given list of [elements] that was created for the
+   * declaration with the given [name] at the given [offset]. Throw an
+   * [ElementMismatchException] if an element corresponding to the identifier
+   * cannot be found unless [required] is `false`, in which case return `null`.
    */
   Element _findWithNameAndOffset(
-      List<Element> elements, String name, int offset) {
+      List<Element> elements, AstNode node, String name, int offset,
+      {bool required: true}) {
     for (Element element in elements) {
-      if (element.nameOffset == offset && element.displayName == name) {
+      if (element.nameOffset == offset && element.name == name) {
         return element;
       }
     }
-    return null;
+    if (!required) {
+      return null;
+    }
+    for (Element element in elements) {
+      if (element.name == name) {
+        _mismatch(
+            'Found element with name "$name" at ${element.nameOffset}, '
+            'but expected offset of $offset',
+            node);
+      }
+      if (element.nameOffset == offset) {
+        _mismatch(
+            'Found element with name "${element.name}" at $offset, '
+            'but expected element with name "$name"',
+            node);
+      }
+    }
+    _mismatch('Could not find element with name "$name" at $offset', node);
+    return null; // Never reached
   }
 
   /**
-   * Search the most closely enclosing list of parameters for a parameter with the given name.
-   *
-   * @param node the node defining the parameter with the given name
-   * @param parameterName the name of the parameter being searched for
-   * @return the element representing the parameter with that name
+   * Search the most closely enclosing list of parameter elements for a
+   * parameter, defined by the given [node], with the given [parameterName].
+   * Return the element that was found, or throw an [ElementMismatchException]
+   * if an element corresponding to the identifier cannot be found.
    */
   ParameterElement _getElementForParameter(
       FormalParameter node, SimpleIdentifier parameterName) {
@@ -2554,32 +2797,22 @@
     if (parameters == null && _enclosingAlias != null) {
       parameters = _enclosingAlias.parameters;
     }
-    ParameterElement element =
-        parameters == null ? null : _findIdentifier(parameters, parameterName);
-    if (element == null) {
+    if (parameters == null) {
       StringBuffer buffer = new StringBuffer();
-      buffer.writeln("Invalid state found in the Analysis Engine:");
+      buffer.writeln('Could not find parameter in enclosing scope');
       buffer.writeln(
-          "DeclarationResolver.getElementForParameter() is visiting a parameter that does not appear to be in a method or function.");
-      buffer.writeln("Ancestors:");
-      AstNode parent = node.parent;
-      while (parent != null) {
-        buffer.writeln(parent.runtimeType.toString());
-        buffer.writeln("---------");
-        parent = parent.parent;
-      }
-      AnalysisEngine.instance.logger.logError(buffer.toString(),
-          new CaughtException(new AnalysisException(), null));
+          '(_enclosingParameter == null) == ${_enclosingParameter == null}');
+      buffer.writeln(
+          '(_enclosingExecutable == null) == ${_enclosingExecutable == null}');
+      buffer.writeln('(_enclosingAlias == null) == ${_enclosingAlias == null}');
+      _mismatch(buffer.toString(), parameterName);
     }
-    return element;
+    return _findIdentifier(parameters, parameterName);
   }
 
   /**
-   * Return the value of the given string literal, or `null` if the string is not a constant
-   * string without any string interpolation.
-   *
-   * @param literal the string literal whose value is to be returned
-   * @return the value of the given string literal
+   * Return the value of the given string [literal], or `null` if the string is
+   * not a constant string without any string interpolation.
    */
   String _getStringValue(StringLiteral literal) {
     if (literal is StringInterpolation) {
@@ -2587,1037 +2820,59 @@
     }
     return literal.stringValue;
   }
-}
-
-/**
- * Instances of the class `ElementBuilder` traverse an AST structure and build the element
- * model representing the AST structure.
- */
-class ElementBuilder extends RecursiveAstVisitor<Object> {
-  /**
-   * The element holder associated with the element that is currently being built.
-   */
-  ElementHolder _currentHolder;
 
   /**
-   * A flag indicating whether a variable declaration is in the context of a field declaration.
+   * Throw an [ElementMismatchException] to report that the element model and
+   * the AST do not match. The [message] will have the path to the given [node]
+   * appended to it.
    */
-  bool _inFieldContext = false;
-
-  /**
-   * A flag indicating whether a variable declaration is within the body of a method or function.
-   */
-  bool _inFunction = false;
-
-  /**
-   * A flag indicating whether the class currently being visited can be used as a mixin.
-   */
-  bool _isValidMixin = false;
-
-  /**
-   * A collection holding the elements defined in a class that need to have
-   * their function type fixed to take into account type parameters of the
-   * enclosing class, or `null` if we are not currently processing nodes within
-   * a class.
-   */
-  List<ExecutableElementImpl> _functionTypesToFix = null;
-
-  /**
-   * A table mapping field names to field elements for the fields defined in the current class, or
-   * `null` if we are not in the scope of a class.
-   */
-  HashMap<String, FieldElement> _fieldMap;
-
-  /**
-   * Initialize a newly created element builder to build the elements for a compilation unit.
-   *
-   * @param initialHolder the element holder associated with the compilation unit being built
-   */
-  ElementBuilder(ElementHolder initialHolder) {
-    _currentHolder = initialHolder;
-  }
-
-  @override
-  Object visitBlock(Block node) {
-    bool wasInField = _inFieldContext;
-    _inFieldContext = false;
-    try {
-      node.visitChildren(this);
-    } finally {
-      _inFieldContext = wasInField;
-    }
-    return null;
-  }
-
-  @override
-  Object visitCatchClause(CatchClause node) {
-    SimpleIdentifier exceptionParameter = node.exceptionParameter;
-    if (exceptionParameter != null) {
-      // exception
-      LocalVariableElementImpl exception =
-          new LocalVariableElementImpl.forNode(exceptionParameter);
-      if (node.exceptionType == null) {
-        exception.hasImplicitType = true;
-      }
-      _currentHolder.addLocalVariable(exception);
-      exceptionParameter.staticElement = exception;
-      // stack trace
-      SimpleIdentifier stackTraceParameter = node.stackTraceParameter;
-      if (stackTraceParameter != null) {
-        LocalVariableElementImpl stackTrace =
-            new LocalVariableElementImpl.forNode(stackTraceParameter);
-        _currentHolder.addLocalVariable(stackTrace);
-        stackTraceParameter.staticElement = stackTrace;
-      }
-    }
-    return super.visitCatchClause(node);
-  }
-
-  @override
-  Object visitClassDeclaration(ClassDeclaration node) {
-    ElementHolder holder = new ElementHolder();
-    _isValidMixin = true;
-    _functionTypesToFix = new List<ExecutableElementImpl>();
-    //
-    // Process field declarations before constructors and methods so that field
-    // formal parameters can be correctly resolved to their fields.
-    //
-    ElementHolder previousHolder = _currentHolder;
-    _currentHolder = holder;
-    try {
-      List<ClassMember> nonFields = new List<ClassMember>();
-      node.visitChildren(
-          new _ElementBuilder_visitClassDeclaration(this, nonFields));
-      _buildFieldMap(holder.fieldsWithoutFlushing);
-      int count = nonFields.length;
-      for (int i = 0; i < count; i++) {
-        nonFields[i].accept(this);
-      }
-    } finally {
-      _currentHolder = previousHolder;
-    }
-    SimpleIdentifier className = node.name;
-    ClassElementImpl element = new ClassElementImpl.forNode(className);
-    List<TypeParameterElement> typeParameters = holder.typeParameters;
-    List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
-    InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
-    interfaceType.typeArguments = typeArguments;
-    element.type = interfaceType;
-    element.typeParameters = typeParameters;
-    _setDoc(element, node);
-    element.abstract = node.isAbstract;
-    element.accessors = holder.accessors;
-    List<ConstructorElement> constructors = holder.constructors;
-    if (constructors.isEmpty) {
-      constructors = _createDefaultConstructors(element);
-    }
-    element.constructors = constructors;
-    element.fields = holder.fields;
-    element.methods = holder.methods;
-    element.validMixin = _isValidMixin;
-    // Function types must be initialized after the enclosing element has been
-    // set, for them to pick up the type parameters.
-    for (ExecutableElementImpl e in _functionTypesToFix) {
-      e.type = new FunctionTypeImpl(e);
-    }
-    _functionTypesToFix = null;
-    _currentHolder.addType(element);
-    className.staticElement = element;
-    _fieldMap = null;
-    holder.validate();
-    return null;
-  }
-
-  /**
-   * Implementation of this method should be synchronized with
-   * [visitClassDeclaration].
-   */
-  void visitClassDeclarationIncrementally(ClassDeclaration node) {
-    //
-    // Process field declarations before constructors and methods so that field
-    // formal parameters can be correctly resolved to their fields.
-    //
-    ClassElement classElement = node.element;
-    _buildFieldMap(classElement.fields);
-  }
-
-  @override
-  Object visitClassTypeAlias(ClassTypeAlias node) {
-    ElementHolder holder = new ElementHolder();
-    _visitChildren(holder, node);
-    SimpleIdentifier className = node.name;
-    ClassElementImpl element = new ClassElementImpl.forNode(className);
-    element.abstract = node.abstractKeyword != null;
-    element.mixinApplication = true;
-    List<TypeParameterElement> typeParameters = holder.typeParameters;
-    element.typeParameters = typeParameters;
-    List<DartType> typeArguments = _createTypeParameterTypes(typeParameters);
-    InterfaceTypeImpl interfaceType = new InterfaceTypeImpl(element);
-    interfaceType.typeArguments = typeArguments;
-    element.type = interfaceType;
-    _setDoc(element, node);
-    _currentHolder.addType(element);
-    className.staticElement = element;
-    holder.validate();
-    return null;
-  }
-
-  @override
-  Object visitConstructorDeclaration(ConstructorDeclaration node) {
-    _isValidMixin = false;
-    ElementHolder holder = new ElementHolder();
-    bool wasInFunction = _inFunction;
-    _inFunction = true;
-    try {
-      _visitChildren(holder, node);
-    } finally {
-      _inFunction = wasInFunction;
-    }
-    FunctionBody body = node.body;
-    SimpleIdentifier constructorName = node.name;
-    ConstructorElementImpl element =
-        new ConstructorElementImpl.forNode(constructorName);
-    _setDoc(element, node);
-    if (node.externalKeyword != null) {
-      element.external = true;
-    }
-    if (node.factoryKeyword != null) {
-      element.factory = true;
-    }
-    element.functions = holder.functions;
-    element.labels = holder.labels;
-    element.localVariables = holder.localVariables;
-    element.parameters = holder.parameters;
-    element.const2 = node.constKeyword != null;
-    if (body.isAsynchronous) {
-      element.asynchronous = true;
-    }
-    if (body.isGenerator) {
-      element.generator = true;
-    }
-    _currentHolder.addConstructor(element);
-    node.element = element;
-    if (constructorName == null) {
-      Identifier returnType = node.returnType;
-      if (returnType != null) {
-        element.nameOffset = returnType.offset;
-        element.nameEnd = returnType.end;
-      }
-    } else {
-      constructorName.staticElement = element;
-      element.periodOffset = node.period.offset;
-      element.nameEnd = constructorName.end;
-    }
-    holder.validate();
-    return null;
-  }
-
-  @override
-  Object visitDeclaredIdentifier(DeclaredIdentifier node) {
-    SimpleIdentifier variableName = node.identifier;
-    LocalVariableElementImpl element =
-        new LocalVariableElementImpl.forNode(variableName);
-    ForEachStatement statement = node.parent as ForEachStatement;
-    int declarationEnd = node.offset + node.length;
-    int statementEnd = statement.offset + statement.length;
-    element.setVisibleRange(declarationEnd, statementEnd - declarationEnd - 1);
-    element.const3 = node.isConst;
-    element.final2 = node.isFinal;
-    if (node.type == null) {
-      element.hasImplicitType = true;
-    }
-    _currentHolder.addLocalVariable(element);
-    variableName.staticElement = element;
-    return super.visitDeclaredIdentifier(node);
-  }
-
-  @override
-  Object visitDefaultFormalParameter(DefaultFormalParameter node) {
-    ElementHolder holder = new ElementHolder();
-    NormalFormalParameter normalParameter = node.parameter;
-    SimpleIdentifier parameterName = normalParameter.identifier;
-    ParameterElementImpl parameter;
-    if (normalParameter is FieldFormalParameter) {
-      parameter = new DefaultFieldFormalParameterElementImpl(parameterName);
-      FieldElement field =
-          _fieldMap == null ? null : _fieldMap[parameterName.name];
-      if (field != null) {
-        (parameter as DefaultFieldFormalParameterElementImpl).field = field;
-      }
-    } else {
-      parameter = new DefaultParameterElementImpl(parameterName);
-    }
-    parameter.const3 = node.isConst;
-    parameter.final2 = node.isFinal;
-    parameter.parameterKind = node.kind;
-    // set initializer, default value range
-    Expression defaultValue = node.defaultValue;
-    if (defaultValue != null) {
-      _visit(holder, defaultValue);
-      FunctionElementImpl initializer =
-          new FunctionElementImpl.forOffset(defaultValue.beginToken.offset);
-      initializer.functions = holder.functions;
-      initializer.labels = holder.labels;
-      initializer.localVariables = holder.localVariables;
-      initializer.parameters = holder.parameters;
-      initializer.synthetic = true;
-      parameter.initializer = initializer;
-      parameter.defaultValueCode = defaultValue.toSource();
-    }
-    // visible range
-    _setParameterVisibleRange(node, parameter);
-    if (normalParameter is SimpleFormalParameter &&
-        normalParameter.type == null) {
-      parameter.hasImplicitType = true;
-    }
-    _currentHolder.addParameter(parameter);
-    parameterName.staticElement = parameter;
-    normalParameter.accept(this);
-    holder.validate();
-    return null;
-  }
-
-  @override
-  Object visitEnumDeclaration(EnumDeclaration node) {
-    SimpleIdentifier enumName = node.name;
-    ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
-    enumElement.enum2 = true;
-    _setDoc(enumElement, node);
-    InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
-    enumElement.type = enumType;
-    // The equivalent code for enums in the spec shows a single constructor,
-    // but that constructor is not callable (since it is a compile-time error
-    // to subclass, mix-in, implement, or explicitly instantiate an enum).  So
-    // we represent this as having no constructors.
-    enumElement.constructors = ConstructorElement.EMPTY_LIST;
-    _currentHolder.addEnum(enumElement);
-    enumName.staticElement = enumElement;
-    return super.visitEnumDeclaration(node);
-  }
-
-  @override
-  Object visitFieldDeclaration(FieldDeclaration node) {
-    bool wasInField = _inFieldContext;
-    _inFieldContext = true;
-    try {
-      node.visitChildren(this);
-    } finally {
-      _inFieldContext = wasInField;
-    }
-    return null;
-  }
-
-  @override
-  Object visitFieldFormalParameter(FieldFormalParameter node) {
-    if (node.parent is! DefaultFormalParameter) {
-      SimpleIdentifier parameterName = node.identifier;
-      FieldElement field =
-          _fieldMap == null ? null : _fieldMap[parameterName.name];
-      FieldFormalParameterElementImpl parameter =
-          new FieldFormalParameterElementImpl(parameterName);
-      parameter.const3 = node.isConst;
-      parameter.final2 = node.isFinal;
-      parameter.parameterKind = node.kind;
-      if (field != null) {
-        parameter.field = field;
-      }
-      _currentHolder.addParameter(parameter);
-      parameterName.staticElement = parameter;
-    }
-    //
-    // The children of this parameter include any parameters defined on the type
-    // of this parameter.
-    //
-    ElementHolder holder = new ElementHolder();
-    _visitChildren(holder, node);
-    ParameterElementImpl element = node.element;
-    element.parameters = holder.parameters;
-    element.typeParameters = holder.typeParameters;
-    holder.validate();
-    return null;
-  }
-
-  @override
-  Object visitFunctionDeclaration(FunctionDeclaration node) {
-    FunctionExpression expression = node.functionExpression;
-    if (expression != null) {
-      ElementHolder holder = new ElementHolder();
-      bool wasInFunction = _inFunction;
-      _inFunction = true;
-      try {
-        _visitChildren(holder, node);
-      } finally {
-        _inFunction = wasInFunction;
-      }
-      FunctionBody body = expression.body;
-      Token property = node.propertyKeyword;
-      if (property == null || _inFunction) {
-        SimpleIdentifier functionName = node.name;
-        FunctionElementImpl element =
-            new FunctionElementImpl.forNode(functionName);
-        _setDoc(element, node);
-        if (node.externalKeyword != null) {
-          element.external = true;
-        }
-        element.functions = holder.functions;
-        element.labels = holder.labels;
-        element.localVariables = holder.localVariables;
-        element.parameters = holder.parameters;
-        element.typeParameters = holder.typeParameters;
-        if (body.isAsynchronous) {
-          element.asynchronous = true;
-        }
-        if (body.isGenerator) {
-          element.generator = true;
-        }
-        if (_inFunction) {
-          Block enclosingBlock = node.getAncestor((node) => node is Block);
-          if (enclosingBlock != null) {
-            int functionEnd = node.offset + node.length;
-            int blockEnd = enclosingBlock.offset + enclosingBlock.length;
-            element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
-          }
-        }
-        if (node.returnType == null) {
-          element.hasImplicitReturnType = true;
-        }
-        _currentHolder.addFunction(element);
-        expression.element = element;
-        functionName.staticElement = element;
-      } else {
-        SimpleIdentifier propertyNameNode = node.name;
-        if (propertyNameNode == null) {
-          // TODO(brianwilkerson) Report this internal error.
-          return null;
-        }
-        String propertyName = propertyNameNode.name;
-        TopLevelVariableElementImpl variable = _currentHolder
-            .getTopLevelVariable(propertyName) as TopLevelVariableElementImpl;
-        if (variable == null) {
-          variable = new TopLevelVariableElementImpl(node.name.name, -1);
-          variable.final2 = true;
-          variable.synthetic = true;
-          _currentHolder.addTopLevelVariable(variable);
-        }
-        if (node.isGetter) {
-          PropertyAccessorElementImpl getter =
-              new PropertyAccessorElementImpl.forNode(propertyNameNode);
-          _setDoc(getter, node);
-          if (node.externalKeyword != null) {
-            getter.external = true;
-          }
-          getter.functions = holder.functions;
-          getter.labels = holder.labels;
-          getter.localVariables = holder.localVariables;
-          if (body.isAsynchronous) {
-            getter.asynchronous = true;
-          }
-          if (body.isGenerator) {
-            getter.generator = true;
-          }
-          getter.variable = variable;
-          getter.getter = true;
-          getter.static = true;
-          variable.getter = getter;
-          if (node.returnType == null) {
-            getter.hasImplicitReturnType = true;
-          }
-          _currentHolder.addAccessor(getter);
-          expression.element = getter;
-          propertyNameNode.staticElement = getter;
-        } else {
-          PropertyAccessorElementImpl setter =
-              new PropertyAccessorElementImpl.forNode(propertyNameNode);
-          _setDoc(setter, node);
-          if (node.externalKeyword != null) {
-            setter.external = true;
-          }
-          setter.functions = holder.functions;
-          setter.labels = holder.labels;
-          setter.localVariables = holder.localVariables;
-          setter.parameters = holder.parameters;
-          if (body.isAsynchronous) {
-            setter.asynchronous = true;
-          }
-          if (body.isGenerator) {
-            setter.generator = true;
-          }
-          setter.variable = variable;
-          setter.setter = true;
-          setter.static = true;
-          if (node.returnType == null) {
-            setter.hasImplicitReturnType = true;
-          }
-          variable.setter = setter;
-          variable.final2 = false;
-          _currentHolder.addAccessor(setter);
-          expression.element = setter;
-          propertyNameNode.staticElement = setter;
-        }
-      }
-      holder.validate();
-    }
-    return null;
-  }
-
-  @override
-  Object visitFunctionExpression(FunctionExpression node) {
-    if (node.parent is FunctionDeclaration) {
-      // visitFunctionDeclaration has already created the element for the
-      // declaration.  We just need to visit children.
-      return super.visitFunctionExpression(node);
-    }
-    ElementHolder holder = new ElementHolder();
-    bool wasInFunction = _inFunction;
-    _inFunction = true;
-    try {
-      _visitChildren(holder, node);
-    } finally {
-      _inFunction = wasInFunction;
-    }
-    FunctionBody body = node.body;
-    FunctionElementImpl element =
-        new FunctionElementImpl.forOffset(node.beginToken.offset);
-    element.functions = holder.functions;
-    element.labels = holder.labels;
-    element.localVariables = holder.localVariables;
-    element.parameters = holder.parameters;
-    element.typeParameters = holder.typeParameters;
-    if (body.isAsynchronous) {
-      element.asynchronous = true;
-    }
-    if (body.isGenerator) {
-      element.generator = true;
-    }
-    if (_inFunction) {
-      Block enclosingBlock = node.getAncestor((node) => node is Block);
-      if (enclosingBlock != null) {
-        int functionEnd = node.offset + node.length;
-        int blockEnd = enclosingBlock.offset + enclosingBlock.length;
-        element.setVisibleRange(functionEnd, blockEnd - functionEnd - 1);
-      }
-    }
-    if (_functionTypesToFix != null) {
-      _functionTypesToFix.add(element);
-    } else {
-      element.type = new FunctionTypeImpl(element);
-    }
-    element.hasImplicitReturnType = true;
-    _currentHolder.addFunction(element);
-    node.element = element;
-    holder.validate();
-    return null;
-  }
-
-  @override
-  Object visitFunctionTypeAlias(FunctionTypeAlias node) {
-    ElementHolder holder = new ElementHolder();
-    _visitChildren(holder, node);
-    SimpleIdentifier aliasName = node.name;
-    List<ParameterElement> parameters = holder.parameters;
-    List<TypeParameterElement> typeParameters = holder.typeParameters;
-    FunctionTypeAliasElementImpl element =
-        new FunctionTypeAliasElementImpl.forNode(aliasName);
-    _setDoc(element, node);
-    element.parameters = parameters;
-    element.typeParameters = typeParameters;
-    _createTypeParameterTypes(typeParameters);
-    element.type = new FunctionTypeImpl.forTypedef(element);
-    _currentHolder.addTypeAlias(element);
-    aliasName.staticElement = element;
-    holder.validate();
-    return null;
-  }
-
-  @override
-  Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
-    if (node.parent is! DefaultFormalParameter) {
-      SimpleIdentifier parameterName = node.identifier;
-      ParameterElementImpl parameter =
-          new ParameterElementImpl.forNode(parameterName);
-      parameter.parameterKind = node.kind;
-      _setParameterVisibleRange(node, parameter);
-      _currentHolder.addParameter(parameter);
-      parameterName.staticElement = parameter;
-    }
-    //
-    // The children of this parameter include any parameters defined on the type
-    //of this parameter.
-    //
-    ElementHolder holder = new ElementHolder();
-    _visitChildren(holder, node);
-    ParameterElementImpl element = node.element;
-    element.parameters = holder.parameters;
-    element.typeParameters = holder.typeParameters;
-    holder.validate();
-    return null;
-  }
-
-  @override
-  Object visitLabeledStatement(LabeledStatement node) {
-    bool onSwitchStatement = node.statement is SwitchStatement;
-    for (Label label in node.labels) {
-      SimpleIdentifier labelName = label.label;
-      LabelElementImpl element =
-          new LabelElementImpl(labelName, onSwitchStatement, false);
-      _currentHolder.addLabel(element);
-      labelName.staticElement = element;
-    }
-    return super.visitLabeledStatement(node);
-  }
-
-  @override
-  Object visitMethodDeclaration(MethodDeclaration node) {
-    try {
-      ElementHolder holder = new ElementHolder();
-      bool wasInFunction = _inFunction;
-      _inFunction = true;
-      try {
-        _visitChildren(holder, node);
-      } finally {
-        _inFunction = wasInFunction;
-      }
-      bool isStatic = node.isStatic;
-      Token property = node.propertyKeyword;
-      FunctionBody body = node.body;
-      if (property == null) {
-        SimpleIdentifier methodName = node.name;
-        String nameOfMethod = methodName.name;
-        if (nameOfMethod == TokenType.MINUS.lexeme &&
-            node.parameters.parameters.length == 0) {
-          nameOfMethod = "unary-";
-        }
-        MethodElementImpl element =
-            new MethodElementImpl(nameOfMethod, methodName.offset);
-        _setDoc(element, node);
-        element.abstract = node.isAbstract;
-        if (node.externalKeyword != null) {
-          element.external = true;
-        }
-        element.functions = holder.functions;
-        element.labels = holder.labels;
-        element.localVariables = holder.localVariables;
-        element.parameters = holder.parameters;
-        element.static = isStatic;
-        element.typeParameters = holder.typeParameters;
-        if (body.isAsynchronous) {
-          element.asynchronous = true;
-        }
-        if (body.isGenerator) {
-          element.generator = true;
-        }
-        if (node.returnType == null) {
-          element.hasImplicitReturnType = true;
-        }
-        _currentHolder.addMethod(element);
-        methodName.staticElement = element;
-      } else {
-        SimpleIdentifier propertyNameNode = node.name;
-        String propertyName = propertyNameNode.name;
-        FieldElementImpl field =
-            _currentHolder.getField(propertyName) as FieldElementImpl;
-        if (field == null) {
-          field = new FieldElementImpl(node.name.name, -1);
-          field.final2 = true;
-          field.static = isStatic;
-          field.synthetic = true;
-          _currentHolder.addField(field);
-        }
-        if (node.isGetter) {
-          PropertyAccessorElementImpl getter =
-              new PropertyAccessorElementImpl.forNode(propertyNameNode);
-          _setDoc(getter, node);
-          if (node.externalKeyword != null) {
-            getter.external = true;
-          }
-          getter.functions = holder.functions;
-          getter.labels = holder.labels;
-          getter.localVariables = holder.localVariables;
-          if (body.isAsynchronous) {
-            getter.asynchronous = true;
-          }
-          if (body.isGenerator) {
-            getter.generator = true;
-          }
-          getter.variable = field;
-          getter.abstract = node.isAbstract;
-          getter.getter = true;
-          getter.static = isStatic;
-          field.getter = getter;
-          if (node.returnType == null) {
-            getter.hasImplicitReturnType = true;
-          }
-          _currentHolder.addAccessor(getter);
-          propertyNameNode.staticElement = getter;
-        } else {
-          PropertyAccessorElementImpl setter =
-              new PropertyAccessorElementImpl.forNode(propertyNameNode);
-          _setDoc(setter, node);
-          if (node.externalKeyword != null) {
-            setter.external = true;
-          }
-          setter.functions = holder.functions;
-          setter.labels = holder.labels;
-          setter.localVariables = holder.localVariables;
-          setter.parameters = holder.parameters;
-          if (body.isAsynchronous) {
-            setter.asynchronous = true;
-          }
-          if (body.isGenerator) {
-            setter.generator = true;
-          }
-          setter.variable = field;
-          setter.abstract = node.isAbstract;
-          setter.setter = true;
-          setter.static = isStatic;
-          if (node.returnType == null) {
-            setter.hasImplicitReturnType = true;
-          }
-          field.setter = setter;
-          field.final2 = false;
-          _currentHolder.addAccessor(setter);
-          propertyNameNode.staticElement = setter;
-        }
-      }
-      holder.validate();
-    } catch (exception, stackTrace) {
-      if (node.name.staticElement == null) {
-        ClassDeclaration classNode =
-            node.getAncestor((node) => node is ClassDeclaration);
-        StringBuffer buffer = new StringBuffer();
-        buffer.write("The element for the method ");
-        buffer.write(node.name);
-        buffer.write(" in ");
-        buffer.write(classNode.name);
-        buffer.write(" was not set while trying to build the element model.");
-        AnalysisEngine.instance.logger.logError(
-            buffer.toString(), new CaughtException(exception, stackTrace));
-      } else {
-        String message =
-            "Exception caught in ElementBuilder.visitMethodDeclaration()";
-        AnalysisEngine.instance.logger
-            .logError(message, new CaughtException(exception, stackTrace));
-      }
-    } finally {
-      if (node.name.staticElement == null) {
-        ClassDeclaration classNode =
-            node.getAncestor((node) => node is ClassDeclaration);
-        StringBuffer buffer = new StringBuffer();
-        buffer.write("The element for the method ");
-        buffer.write(node.name);
-        buffer.write(" in ");
-        buffer.write(classNode.name);
-        buffer.write(" was not set while trying to resolve types.");
-        AnalysisEngine.instance.logger.logError(
-            buffer.toString(),
-            new CaughtException(
-                new AnalysisException(buffer.toString()), null));
-      }
-    }
-    return null;
-  }
-
-  @override
-  Object visitSimpleFormalParameter(SimpleFormalParameter node) {
-    if (node.parent is! DefaultFormalParameter) {
-      SimpleIdentifier parameterName = node.identifier;
-      ParameterElementImpl parameter =
-          new ParameterElementImpl.forNode(parameterName);
-      parameter.const3 = node.isConst;
-      parameter.final2 = node.isFinal;
-      parameter.parameterKind = node.kind;
-      _setParameterVisibleRange(node, parameter);
-      if (node.type == null) {
-        parameter.hasImplicitType = true;
-      }
-      _currentHolder.addParameter(parameter);
-      parameterName.staticElement = parameter;
-    }
-    return super.visitSimpleFormalParameter(node);
-  }
-
-  @override
-  Object visitSuperExpression(SuperExpression node) {
-    _isValidMixin = false;
-    return super.visitSuperExpression(node);
-  }
-
-  @override
-  Object visitSwitchCase(SwitchCase node) {
-    for (Label label in node.labels) {
-      SimpleIdentifier labelName = label.label;
-      LabelElementImpl element = new LabelElementImpl(labelName, false, true);
-      _currentHolder.addLabel(element);
-      labelName.staticElement = element;
-    }
-    return super.visitSwitchCase(node);
-  }
-
-  @override
-  Object visitSwitchDefault(SwitchDefault node) {
-    for (Label label in node.labels) {
-      SimpleIdentifier labelName = label.label;
-      LabelElementImpl element = new LabelElementImpl(labelName, false, true);
-      _currentHolder.addLabel(element);
-      labelName.staticElement = element;
-    }
-    return super.visitSwitchDefault(node);
-  }
-
-  @override
-  Object visitTypeParameter(TypeParameter node) {
-    SimpleIdentifier parameterName = node.name;
-    TypeParameterElementImpl typeParameter =
-        new TypeParameterElementImpl.forNode(parameterName);
-    TypeParameterTypeImpl typeParameterType =
-        new TypeParameterTypeImpl(typeParameter);
-    typeParameter.type = typeParameterType;
-    _currentHolder.addTypeParameter(typeParameter);
-    parameterName.staticElement = typeParameter;
-    return super.visitTypeParameter(node);
-  }
-
-  @override
-  Object visitVariableDeclaration(VariableDeclaration node) {
-    bool isConst = node.isConst;
-    bool isFinal = node.isFinal;
-    bool hasInitializer = node.initializer != null;
-    VariableElementImpl element;
-    if (_inFieldContext) {
-      SimpleIdentifier fieldName = node.name;
-      FieldElementImpl field;
-      if ((isConst || isFinal) && hasInitializer) {
-        field = new ConstFieldElementImpl.forNode(fieldName);
-      } else {
-        field = new FieldElementImpl.forNode(fieldName);
-      }
-      element = field;
-      if (node.parent.parent is FieldDeclaration) {
-        _setDoc(element, node.parent.parent);
-      }
-      if ((node.parent as VariableDeclarationList).type == null) {
-        field.hasImplicitType = true;
-      }
-      _currentHolder.addField(field);
-      fieldName.staticElement = field;
-    } else if (_inFunction) {
-      SimpleIdentifier variableName = node.name;
-      LocalVariableElementImpl variable;
-      if (isConst && hasInitializer) {
-        variable = new ConstLocalVariableElementImpl.forNode(variableName);
-      } else {
-        variable = new LocalVariableElementImpl.forNode(variableName);
-      }
-      element = variable;
-      Block enclosingBlock = node.getAncestor((node) => node is Block);
-      // TODO(brianwilkerson) This isn't right for variables declared in a for
-      // loop.
-      variable.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
-      if ((node.parent as VariableDeclarationList).type == null) {
-        variable.hasImplicitType = true;
-      }
-      _currentHolder.addLocalVariable(variable);
-      variableName.staticElement = element;
-    } else {
-      SimpleIdentifier variableName = node.name;
-      TopLevelVariableElementImpl variable;
-      if (isConst && hasInitializer) {
-        variable = new ConstTopLevelVariableElementImpl(variableName);
-      } else {
-        variable = new TopLevelVariableElementImpl.forNode(variableName);
-      }
-      element = variable;
-      if (node.parent.parent is TopLevelVariableDeclaration) {
-        _setDoc(element, node.parent.parent);
-      }
-      if ((node.parent as VariableDeclarationList).type == null) {
-        variable.hasImplicitType = true;
-      }
-      _currentHolder.addTopLevelVariable(variable);
-      variableName.staticElement = element;
-    }
-    element.const3 = isConst;
-    element.final2 = isFinal;
-    if (hasInitializer) {
-      ElementHolder holder = new ElementHolder();
-      bool wasInFieldContext = _inFieldContext;
-      _inFieldContext = false;
-      try {
-        _visit(holder, node.initializer);
-      } finally {
-        _inFieldContext = wasInFieldContext;
-      }
-      FunctionElementImpl initializer =
-          new FunctionElementImpl.forOffset(node.initializer.beginToken.offset);
-      initializer.functions = holder.functions;
-      initializer.labels = holder.labels;
-      initializer.localVariables = holder.localVariables;
-      initializer.synthetic = true;
-      element.initializer = initializer;
-      holder.validate();
-    }
-    if (element is PropertyInducingElementImpl) {
-      if (_inFieldContext) {
-        (element as FieldElementImpl).static =
-            (node.parent.parent as FieldDeclaration).isStatic;
-      }
-      PropertyAccessorElementImpl getter =
-          new PropertyAccessorElementImpl.forVariable(element);
-      getter.getter = true;
-      if (element.hasImplicitType) {
-        getter.hasImplicitReturnType = true;
-      }
-      _currentHolder.addAccessor(getter);
-      element.getter = getter;
-      if (!isConst && !isFinal) {
-        PropertyAccessorElementImpl setter =
-            new PropertyAccessorElementImpl.forVariable(element);
-        setter.setter = true;
-        ParameterElementImpl parameter =
-            new ParameterElementImpl("_${element.name}", element.nameOffset);
-        parameter.synthetic = true;
-        parameter.parameterKind = ParameterKind.REQUIRED;
-        setter.parameters = <ParameterElement>[parameter];
-        _currentHolder.addAccessor(setter);
-        element.setter = setter;
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Build the table mapping field names to field elements for the fields defined in the current
-   * class.
-   *
-   * @param fields the field elements defined in the current class
-   */
-  void _buildFieldMap(List<FieldElement> fields) {
-    _fieldMap = new HashMap<String, FieldElement>();
-    int count = fields.length;
-    for (int i = 0; i < count; i++) {
-      FieldElement field = fields[i];
-      _fieldMap[field.name] = field;
-    }
-  }
-
-  /**
-   * Creates the [ConstructorElement]s array with the single default constructor element.
-   *
-   * @param interfaceType the interface type for which to create a default constructor
-   * @return the [ConstructorElement]s array with the single default constructor element
-   */
-  List<ConstructorElement> _createDefaultConstructors(
-      ClassElementImpl definingClass) {
-    ConstructorElementImpl constructor =
-        new ConstructorElementImpl.forNode(null);
-    constructor.synthetic = true;
-    constructor.returnType = definingClass.type;
-    constructor.enclosingElement = definingClass;
-    constructor.type = new FunctionTypeImpl(constructor);
-    return <ConstructorElement>[constructor];
-  }
-
-  /**
-   * Create the types associated with the given type parameters, setting the type of each type
-   * parameter, and return an array of types corresponding to the given parameters.
-   *
-   * @param typeParameters the type parameters for which types are to be created
-   * @return an array of types corresponding to the given parameters
-   */
-  List<DartType> _createTypeParameterTypes(
-      List<TypeParameterElement> typeParameters) {
-    int typeParameterCount = typeParameters.length;
-    List<DartType> typeArguments = new List<DartType>(typeParameterCount);
-    for (int i = 0; i < typeParameterCount; i++) {
-      TypeParameterElementImpl typeParameter =
-          typeParameters[i] as TypeParameterElementImpl;
-      TypeParameterTypeImpl typeParameterType =
-          new TypeParameterTypeImpl(typeParameter);
-      typeParameter.type = typeParameterType;
-      typeArguments[i] = typeParameterType;
-    }
-    return typeArguments;
-  }
-
-  /**
-   * Return the body of the function that contains the given parameter, or `null` if no
-   * function body could be found.
-   *
-   * @param node the parameter contained in the function whose body is to be returned
-   * @return the body of the function that contains the given parameter
-   */
-  FunctionBody _getFunctionBody(FormalParameter node) {
-    AstNode parent = node.parent;
+  void _mismatch(String message, AstNode node) {
+    StringBuffer buffer = new StringBuffer();
+    buffer.writeln(message);
+    buffer.write('Path to root:');
+    String separator = ' ';
+    AstNode parent = node;
     while (parent != null) {
-      if (parent is ConstructorDeclaration) {
-        return parent.body;
-      } else if (parent is FunctionExpression) {
-        return parent.body;
-      } else if (parent is MethodDeclaration) {
-        return parent.body;
-      }
+      buffer.write(separator);
+      buffer.write(parent.runtimeType.toString());
+      separator = ', ';
       parent = parent.parent;
     }
-    return null;
+    throw new ElementMismatchException(buffer.toString());
   }
 
   /**
-   * If the given [node] has a documentation comment, remember its content
-   * and range into the given [element].
-   */
-  void _setDoc(ElementImpl element, AnnotatedNode node) {
-    Comment comment = node.documentationComment;
-    if (comment != null && comment.isDocumentation) {
-      element.documentationComment =
-          comment.tokens.map((Token t) => t.lexeme).join('\n');
-      element.setDocRange(comment.offset, comment.length);
-    }
-  }
-
-  /**
-   * Sets the visible source range for formal parameter.
-   */
-  void _setParameterVisibleRange(
-      FormalParameter node, ParameterElementImpl element) {
-    FunctionBody body = _getFunctionBody(node);
-    if (body != null) {
-      element.setVisibleRange(body.offset, body.length);
-    }
-  }
-
-  /**
-   * Make the given holder be the current holder while visiting the given node.
+   * If [element] is not `null`, associate each [Annotation] in [astMetadata]
+   * with the corresponding [ElementAnnotation] in [element.metadata].
    *
-   * @param holder the holder that will gather elements that are built while visiting the children
-   * @param node the node to be visited
+   * If [element] is `null`, do nothing--this allows us to be robust in the
+   * case where we are operating on an element model that hasn't been fully
+   * built.
    */
-  void _visit(ElementHolder holder, AstNode node) {
-    if (node != null) {
-      ElementHolder previousHolder = _currentHolder;
-      _currentHolder = holder;
-      try {
-        node.accept(this);
-      } finally {
-        _currentHolder = previousHolder;
+  void _resolveMetadata(NodeList<Annotation> astMetadata, Element element) {
+    if (element != null) {
+      List<ElementAnnotation> elementMetadata = element.metadata;
+      assert(astMetadata.length == elementMetadata.length);
+      for (int i = 0; i < astMetadata.length; i++) {
+        astMetadata[i].elementAnnotation = elementMetadata[i];
       }
     }
   }
 
   /**
-   * Make the given holder be the current holder while visiting the children of the given node.
-   *
-   * @param holder the holder that will gather elements that are built while visiting the children
-   * @param node the node whose children are to be visited
+   * Throw an exception if there are non-synthetic elements in the element model
+   * that were not associated with an AST node.
    */
-  void _visitChildren(ElementHolder holder, AstNode node) {
-    if (node != null) {
-      ElementHolder previousHolder = _currentHolder;
-      _currentHolder = holder;
-      try {
-        node.visitChildren(this);
-      } finally {
-        _currentHolder = previousHolder;
+  void _validateResolution() {
+    if (_expectedElements.isNotEmpty) {
+      StringBuffer buffer = new StringBuffer();
+      buffer.write(_expectedElements.length);
+      buffer.writeln(' unmatched elements found:');
+      for (Element element in _expectedElements) {
+        buffer.write('  ');
+        buffer.writeln(element);
       }
+      throw new ElementMismatchException(buffer.toString());
     }
   }
 }
@@ -3983,6 +3238,15 @@
   }
 }
 
+class ElementMismatchException extends AnalysisException {
+  /**
+   * Initialize a newly created exception to have the given [message] and
+   * [cause].
+   */
+  ElementMismatchException(String message, [CaughtException cause = null])
+      : super(message, cause);
+}
+
 /**
  * Instances of the class `EnclosedScope` implement a scope that is lexically enclosed in
  * another scope.
@@ -4109,12 +3373,14 @@
     List<DartObjectImpl> constantValues = new List<DartObjectImpl>();
     int constantCount = constants.length;
     for (int i = 0; i < constantCount; i++) {
-      SimpleIdentifier constantName = constants[i].name;
+      EnumConstantDeclaration constant = constants[i];
+      SimpleIdentifier constantName = constant.name;
       FieldElementImpl constantField =
           new ConstFieldElementImpl.forNode(constantName);
       constantField.static = true;
       constantField.const3 = true;
       constantField.type = enumType;
+      setElementDocumentationComment(constantField, constant);
       //
       // Create a value for the constant.
       //
@@ -5423,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)
@@ -5447,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'>`
@@ -5459,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);
   }
 
   /**
@@ -6938,16 +6242,6 @@
 }
 
 /**
- * Instances of the class `LibraryResolver` are used to resolve one or more mutually dependent
- * libraries within a single context.
- */
-
-/**
- * Instances of the class `LibraryResolver` are used to resolve one or more mutually dependent
- * libraries within a single context.
- */
-
-/**
  * Instances of the class `LibraryScope` implement a scope containing all of the names defined
  * in a given library.
  */
@@ -7411,14 +6705,6 @@
    */
   HashMap<String, Element> _createExportMapping(
       LibraryElement library, HashSet<LibraryElement> visitedElements) {
-    // Check if the export namespace has been already computed.
-    {
-      Namespace exportNamespace = library.exportNamespace;
-      if (exportNamespace != null) {
-        return exportNamespace.definedNames;
-      }
-    }
-    // TODO(scheglov) Remove this after switching to the new task model.
     visitedElements.add(library);
     try {
       HashMap<String, Element> definedNames = new HashMap<String, Element>();
@@ -7640,7 +6926,7 @@
    */
   void _addPropagableVariables(List<VariableDeclaration> variables) {
     for (VariableDeclaration variable in variables) {
-      if (variable.initializer != null) {
+      if (variable.name.name.isNotEmpty && variable.initializer != null) {
         VariableElement element = variable.element;
         if (element.isConst || element.isFinal) {
           propagableVariables.add(element);
@@ -7658,7 +6944,7 @@
    */
   void _addStaticVariables(List<VariableDeclaration> variables) {
     for (VariableDeclaration variable in variables) {
-      if (variable.initializer != null) {
+      if (variable.name.name.isNotEmpty && variable.initializer != null) {
         staticVariables.add(variable.element);
       }
     }
@@ -7948,7 +7234,7 @@
    */
   StaticTypeAnalyzer typeAnalyzer;
 
-  /*
+  /**
    * The type system in use during resolution.
    */
   TypeSystem typeSystem;
@@ -8000,6 +7286,11 @@
   bool resolveOnlyCommentInFunctionBody = false;
 
   /**
+   * Body of the function currently being analyzed, if any.
+   */
+  FunctionBody _currentFunctionBody;
+
+  /**
    * Initialize a newly created visitor to resolve the nodes in an AST node.
    *
    * The [definingLibrary] is the element for the library containing the node
@@ -8131,17 +7422,53 @@
   /**
    * Prepares this [ResolverVisitor] to using it for incremental resolution.
    */
-  void initForIncrementalResolution([Declaration declaration = null]) {
-    if (declaration != null) {
-      Element element = declaration.element;
-      if (element is ExecutableElement) {
-        _enclosingFunction = element;
-      }
-    }
+  void initForIncrementalResolution() {
     _overrideManager.enterScope();
   }
 
   /**
+   * Given a downward inference type [fnType], and the declared
+   * [typeParameterList] for a function expression, determines if we can enable
+   * downward inference and if so, returns the function type to use for
+   * inference.
+   *
+   * This will return null if inference is not possible. This happens when
+   * there is no way we can find a subtype of the function type, given the
+   * provided type parameter list.
+   */
+  FunctionType matchFunctionTypeParameters(
+      TypeParameterList typeParameterList, FunctionType fnType) {
+    if (typeParameterList == null) {
+      if (fnType.typeFormals.isEmpty) {
+        return fnType;
+      }
+
+      // A non-generic function cannot be a subtype of a generic one.
+      return null;
+    }
+
+    NodeList<TypeParameter> typeParameters = typeParameterList.typeParameters;
+    if (fnType.typeFormals.isEmpty) {
+      // TODO(jmesserly): this is a legal subtype. We don't currently infer
+      // here, but we could.  This is similar to
+      // StrongTypeSystemImpl.inferFunctionTypeInstantiation, but we don't
+      // have the FunctionType yet for the current node, so it's not quite
+      // straightforward to apply.
+      return null;
+    }
+
+    if (fnType.typeFormals.length != typeParameters.length) {
+      // A subtype cannot have different number of type formals.
+      return null;
+    }
+
+    // Same number of type formals. Instantiate the function type so its
+    // parameter and return type are in terms of the surrounding context.
+    return fnType.instantiate(
+        typeParameters.map((t) => t.name.staticElement.type).toList());
+  }
+
+  /**
    * If it is appropriate to do so, override the current type of the static and propagated elements
    * associated with the given expression with the given type. Generally speaking, it is appropriate
    * if the given type is more specific than the current type.
@@ -8296,6 +7623,14 @@
     safelyVisit(node.arguments);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
+    ElementAnnotationImpl elementAnnotationImpl = node.elementAnnotation;
+    if (elementAnnotationImpl == null) {
+      // Analyzer ignores annotations on "part of" directives.
+      assert(parent is PartOfDirective);
+    } else {
+      elementAnnotationImpl.annotationAst =
+          new ConstantAstCloner().cloneNode(node);
+    }
     return null;
   }
 
@@ -8380,11 +7715,10 @@
   Object visitAwaitExpression(AwaitExpression node) {
     // TODO(leafp): Handle the implicit union type here
     // https://github.com/dart-lang/sdk/issues/25322
-    DartType contextType = StaticTypeAnalyzer.flattenFutures(
-        typeProvider, InferenceContext.getType(node));
+    DartType contextType = InferenceContext.getType(node);
     if (contextType != null) {
-      InterfaceType futureT =
-          typeProvider.futureType.substitute4([contextType]);
+      InterfaceType futureT = typeProvider.futureType
+          .substitute4([contextType.flattenFutures(typeSystem)]);
       InferenceContext.setType(node.expression, futureT);
     }
     return super.visitAwaitExpression(node);
@@ -8448,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;
   }
@@ -8642,12 +7976,15 @@
   @override
   Object visitConstructorDeclaration(ConstructorDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
+    FunctionBody outerFunctionBody = _currentFunctionBody;
     try {
+      _currentFunctionBody = node.body;
       _enclosingFunction = node.element;
       FunctionType type = _enclosingFunction.type;
       InferenceContext.setType(node.body, type.returnType);
       super.visitConstructorDeclaration(node);
     } finally {
+      _currentFunctionBody = outerFunctionBody;
       _enclosingFunction = outerFunction;
     }
     ConstructorElementImpl constructor = node.element;
@@ -8744,7 +8081,7 @@
     //
     if (node.metadata != null) {
       node.metadata.accept(this);
-      ElementResolver.setMetadata(node.element, node);
+      ElementResolver.resolveMetadata(node);
     }
     //
     // Continue the enum resolution.
@@ -8891,13 +8228,16 @@
   @override
   Object visitFunctionDeclaration(FunctionDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
+    FunctionBody outerFunctionBody = _currentFunctionBody;
     try {
       SimpleIdentifier functionName = node.name;
+      _currentFunctionBody = node.functionExpression.body;
       _enclosingFunction = functionName.staticElement as ExecutableElement;
       InferenceContext.setType(
           node.functionExpression, _enclosingFunction.type);
       super.visitFunctionDeclaration(node);
     } finally {
+      _currentFunctionBody = outerFunctionBody;
       _enclosingFunction = outerFunction;
     }
     return null;
@@ -8912,24 +8252,29 @@
   @override
   Object visitFunctionExpression(FunctionExpression node) {
     ExecutableElement outerFunction = _enclosingFunction;
+    FunctionBody outerFunctionBody = _currentFunctionBody;
     try {
+      _currentFunctionBody = node.body;
       _enclosingFunction = node.element;
       _overrideManager.enterScope();
       try {
         DartType functionType = InferenceContext.getType(node);
         if (functionType is FunctionType) {
-          _inferFormalParameterList(node.parameters, functionType);
-          DartType returnType = _computeReturnOrYieldType(
-              functionType.returnType,
-              _enclosingFunction.isGenerator,
-              _enclosingFunction.isAsynchronous);
-          InferenceContext.setType(node.body, returnType);
+          functionType =
+              matchFunctionTypeParameters(node.typeParameters, functionType);
+          if (functionType is FunctionType) {
+            _inferFormalParameterList(node.parameters, functionType);
+            DartType returnType =
+                _computeReturnOrYieldType(functionType.returnType);
+            InferenceContext.setType(node.body, returnType);
+          }
         }
         super.visitFunctionExpression(node);
       } finally {
         _overrideManager.exitScope();
       }
     } finally {
+      _currentFunctionBody = outerFunctionBody;
       _enclosingFunction = outerFunction;
     }
     return null;
@@ -8940,7 +8285,7 @@
     safelyVisit(node.function);
     node.accept(elementResolver);
     _inferFunctionExpressionsParametersTypes(node.argumentList);
-    InferenceContext.setType(node.argumentList, node.function.staticType);
+    _inferArgumentTypesFromContext(node);
     safelyVisit(node.argumentList);
     node.accept(typeAnalyzer);
     return null;
@@ -9126,15 +8471,16 @@
   @override
   Object visitMethodDeclaration(MethodDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
+    FunctionBody outerFunctionBody = _currentFunctionBody;
     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 {
+      _currentFunctionBody = outerFunctionBody;
       _enclosingFunction = outerFunction;
     }
     return null;
@@ -9156,114 +8502,12 @@
     safelyVisit(node.typeArguments);
     node.accept(elementResolver);
     _inferFunctionExpressionsParametersTypes(node.argumentList);
-    DartType contextType = node.staticInvokeType;
-    if (contextType is FunctionType) {
-      InferenceContext.setType(node.argumentList, contextType);
-    }
+    _inferArgumentTypesFromContext(node);
     safelyVisit(node.argumentList);
     node.accept(typeAnalyzer);
     return null;
   }
 
-  /**
-   * Given an [argumentList] and the [parameters] related to the element that
-   * will be invoked using those arguments, compute the list of parameters that
-   * correspond to the list of arguments.
-   *
-   * An error will be reported to [onError] if any of the arguments cannot be
-   * matched to a parameter. onError can be null to ignore the error.
-   *
-   * The flag [reportAsError] should be `true` if a compile-time error should be
-   * reported; or `false` if a compile-time warning should be reported
-   *
-   * Returns the parameters that correspond to the arguments.
-   */
-  static List<ParameterElement> resolveArgumentsToParameters(
-      ArgumentList argumentList,
-      List<ParameterElement> parameters,
-      void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]),
-      {bool reportAsError: false}) {
-    List<ParameterElement> requiredParameters = new List<ParameterElement>();
-    List<ParameterElement> positionalParameters = new List<ParameterElement>();
-    HashMap<String, ParameterElement> namedParameters =
-        new HashMap<String, ParameterElement>();
-    for (ParameterElement parameter in parameters) {
-      ParameterKind kind = parameter.parameterKind;
-      if (kind == ParameterKind.REQUIRED) {
-        requiredParameters.add(parameter);
-      } else if (kind == ParameterKind.POSITIONAL) {
-        positionalParameters.add(parameter);
-      } else {
-        namedParameters[parameter.name] = parameter;
-      }
-    }
-    List<ParameterElement> unnamedParameters =
-        new List<ParameterElement>.from(requiredParameters);
-    unnamedParameters.addAll(positionalParameters);
-    int unnamedParameterCount = unnamedParameters.length;
-    int unnamedIndex = 0;
-    NodeList<Expression> arguments = argumentList.arguments;
-    int argumentCount = arguments.length;
-    List<ParameterElement> resolvedParameters =
-        new List<ParameterElement>(argumentCount);
-    int positionalArgumentCount = 0;
-    HashSet<String> usedNames = new HashSet<String>();
-    bool noBlankArguments = true;
-    for (int i = 0; i < argumentCount; i++) {
-      Expression argument = arguments[i];
-      if (argument is NamedExpression) {
-        SimpleIdentifier nameNode = argument.name.label;
-        String name = nameNode.name;
-        ParameterElement element = namedParameters[name];
-        if (element == null) {
-          ErrorCode errorCode = (reportAsError
-              ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
-              : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
-          if (onError != null) {
-            onError(errorCode, nameNode, [name]);
-          }
-        } else {
-          resolvedParameters[i] = element;
-          nameNode.staticElement = element;
-        }
-        if (!usedNames.add(name)) {
-          if (onError != null) {
-            onError(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode,
-                [name]);
-          }
-        }
-      } else {
-        if (argument is SimpleIdentifier && argument.name.isEmpty) {
-          noBlankArguments = false;
-        }
-        positionalArgumentCount++;
-        if (unnamedIndex < unnamedParameterCount) {
-          resolvedParameters[i] = unnamedParameters[unnamedIndex++];
-        }
-      }
-    }
-    if (positionalArgumentCount < requiredParameters.length &&
-        noBlankArguments) {
-      ErrorCode errorCode = (reportAsError
-          ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
-          : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
-      if (onError != null) {
-        onError(errorCode, argumentList,
-            [requiredParameters.length, positionalArgumentCount]);
-      }
-    } else if (positionalArgumentCount > unnamedParameterCount &&
-        noBlankArguments) {
-      ErrorCode errorCode = (reportAsError
-          ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
-          : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
-      if (onError != null) {
-        onError(errorCode, argumentList,
-            [unnamedParameterCount, positionalArgumentCount]);
-      }
-    }
-    return resolvedParameters;
-  }
-
   @override
   Object visitNamedExpression(NamedExpression node) {
     InferenceContext.setType(node.expression, InferenceContext.getType(node));
@@ -9325,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
@@ -9409,7 +8664,8 @@
     return null;
   }
 
-  @override visitVariableDeclarationList(VariableDeclarationList node) {
+  @override
+  visitVariableDeclarationList(VariableDeclarationList node) {
     for (VariableDeclaration decl in node.variables) {
       InferenceContext.setType(decl, node.type?.type);
     }
@@ -9447,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;
   }
 
   /**
@@ -9478,7 +8753,7 @@
   void _clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
       AstNode target) {
     for (Element element in _promoteManager.promotedElements) {
-      if ((element as VariableElementImpl).isPotentiallyMutatedInScope) {
+      if (_currentFunctionBody.isPotentiallyMutatedInScope(element)) {
         if (_isVariableAccessedInClosure(element, target)) {
           _promoteManager.setType(element, null);
         }
@@ -9505,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;
@@ -9525,7 +8802,40 @@
       return (typeArgs?.length == 1) ? typeArgs[0] : null;
     }
     // Must be asynchronous to reach here, so strip off any layers of Future
-    return StaticTypeAnalyzer.flattenFutures(typeProvider, declaredType);
+    return declaredType.flattenFutures(typeSystem);
+  }
+
+  /**
+   * 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;
   }
 
   /**
@@ -9590,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
@@ -9771,28 +9100,21 @@
     VariableElement element = getPromotionStaticElement(expression);
     if (element != null) {
       // may be mutated somewhere in closure
-      if (element.isPotentiallyMutatedInClosure) {
+      if (_currentFunctionBody.isPotentiallyMutatedInClosure(element)) {
         return;
       }
       // prepare current variable type
-      DartType type = _promoteManager.getType(element);
-      if (type == null) {
-        type = expression.staticType;
+      DartType type = _promoteManager.getType(element) ??
+          expression.staticType ??
+          DynamicTypeImpl.instance;
+
+      potentialType ??= DynamicTypeImpl.instance;
+
+      // Check if we can promote to potentialType from type.
+      if (typeSystem.canPromoteToType(potentialType, type)) {
+        // Do promote type of variable.
+        _promoteManager.setType(element, potentialType);
       }
-      // Declared type should not be "dynamic".
-      if (type == null || type.isDynamic) {
-        return;
-      }
-      // Promoted type should not be "dynamic".
-      if (potentialType == null || potentialType.isDynamic) {
-        return;
-      }
-      // Promoted type should be more specific than declared.
-      if (!potentialType.isMoreSpecificThan(type)) {
-        return;
-      }
-      // Do promote type of variable.
-      _promoteManager.setType(element, potentialType);
     }
   }
 
@@ -9890,6 +9212,106 @@
       _propagateTrueState(condition.expression);
     }
   }
+
+  /**
+   * Given an [argumentList] and the [parameters] related to the element that
+   * will be invoked using those arguments, compute the list of parameters that
+   * correspond to the list of arguments.
+   *
+   * An error will be reported to [onError] if any of the arguments cannot be
+   * matched to a parameter. onError can be null to ignore the error.
+   *
+   * The flag [reportAsError] should be `true` if a compile-time error should be
+   * reported; or `false` if a compile-time warning should be reported.
+   *
+   * Returns the parameters that correspond to the arguments. If no parameter
+   * matched an argument, that position will be `null` in the list.
+   */
+  static List<ParameterElement> resolveArgumentsToParameters(
+      ArgumentList argumentList,
+      List<ParameterElement> parameters,
+      void onError(ErrorCode errorCode, AstNode node, [List<Object> arguments]),
+      {bool reportAsError: false}) {
+    List<ParameterElement> requiredParameters = new List<ParameterElement>();
+    List<ParameterElement> positionalParameters = new List<ParameterElement>();
+    HashMap<String, ParameterElement> namedParameters =
+        new HashMap<String, ParameterElement>();
+    for (ParameterElement parameter in parameters) {
+      ParameterKind kind = parameter.parameterKind;
+      if (kind == ParameterKind.REQUIRED) {
+        requiredParameters.add(parameter);
+      } else if (kind == ParameterKind.POSITIONAL) {
+        positionalParameters.add(parameter);
+      } else {
+        namedParameters[parameter.name] = parameter;
+      }
+    }
+    List<ParameterElement> unnamedParameters =
+        new List<ParameterElement>.from(requiredParameters);
+    unnamedParameters.addAll(positionalParameters);
+    int unnamedParameterCount = unnamedParameters.length;
+    int unnamedIndex = 0;
+    NodeList<Expression> arguments = argumentList.arguments;
+    int argumentCount = arguments.length;
+    List<ParameterElement> resolvedParameters =
+        new List<ParameterElement>(argumentCount);
+    int positionalArgumentCount = 0;
+    HashSet<String> usedNames = new HashSet<String>();
+    bool noBlankArguments = true;
+    for (int i = 0; i < argumentCount; i++) {
+      Expression argument = arguments[i];
+      if (argument is NamedExpression) {
+        SimpleIdentifier nameNode = argument.name.label;
+        String name = nameNode.name;
+        ParameterElement element = namedParameters[name];
+        if (element == null) {
+          ErrorCode errorCode = (reportAsError
+              ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER
+              : StaticWarningCode.UNDEFINED_NAMED_PARAMETER);
+          if (onError != null) {
+            onError(errorCode, nameNode, [name]);
+          }
+        } else {
+          resolvedParameters[i] = element;
+          nameNode.staticElement = element;
+        }
+        if (!usedNames.add(name)) {
+          if (onError != null) {
+            onError(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode,
+                [name]);
+          }
+        }
+      } else {
+        if (argument is SimpleIdentifier && argument.name.isEmpty) {
+          noBlankArguments = false;
+        }
+        positionalArgumentCount++;
+        if (unnamedIndex < unnamedParameterCount) {
+          resolvedParameters[i] = unnamedParameters[unnamedIndex++];
+        }
+      }
+    }
+    if (positionalArgumentCount < requiredParameters.length &&
+        noBlankArguments) {
+      ErrorCode errorCode = (reportAsError
+          ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS
+          : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS);
+      if (onError != null) {
+        onError(errorCode, argumentList,
+            [requiredParameters.length, positionalArgumentCount]);
+      }
+    } else if (positionalArgumentCount > unnamedParameterCount &&
+        noBlankArguments) {
+      ErrorCode errorCode = (reportAsError
+          ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS
+          : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS);
+      if (onError != null) {
+        onError(errorCode, argumentList,
+            [unnamedParameterCount, positionalArgumentCount]);
+      }
+    }
+    return resolvedParameters;
+  }
 }
 
 /**
@@ -11889,8 +11311,8 @@
   Object visitAnnotation(Annotation node) {
     //
     // Visit annotations, if the annotation is @proxy, on a class, and "proxy"
-    // resolves to the proxy annotation in dart.core, then create create the
-    // ElementAnnotationImpl and set it as the metadata on the enclosing class.
+    // resolves to the proxy annotation in dart.core, then resolve the
+    // ElementAnnotation.
     //
     // Element resolution is done in the ElementResolver, and this work will be
     // done in the general case for all annotations in the ElementResolver.
@@ -11907,12 +11329,8 @@
           element.library.isDartCore &&
           element is PropertyAccessorElement) {
         // This is the @proxy from dart.core
-        ClassDeclaration classDeclaration = node.parent as ClassDeclaration;
-        ElementAnnotationImpl elementAnnotation =
-            new ElementAnnotationImpl(element);
-        node.elementAnnotation = elementAnnotation;
-        (classDeclaration.element as ClassElementImpl).metadata =
-            <ElementAnnotationImpl>[elementAnnotation];
+        ElementAnnotationImpl elementAnnotation = node.elementAnnotation;
+        elementAnnotation.element = element;
       }
     }
     return null;
@@ -11981,9 +11399,6 @@
           : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS);
       superclassType = _resolveType(extendsClause.superclass, errorCode,
           CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
-      if (!identical(superclassType, typeProvider.objectType)) {
-        classElement.validMixin = false;
-      }
     }
     if (classElement != null) {
       if (superclassType == null) {
@@ -12218,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) {
@@ -12366,8 +11782,6 @@
     if (!elementValid) {
       if (element is MultiplyDefinedElement) {
         _setElement(typeName, element);
-      } else {
-        _setElement(typeName, _dynamicType.element);
       }
       typeName.staticType = _undefinedType;
       node.type = _undefinedType;
@@ -12432,7 +11846,6 @@
               StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
         }
       }
-      _setElement(typeName, _dynamicType.element);
       typeName.staticType = _dynamicType;
       node.type = _dynamicType;
       return null;
@@ -12836,8 +12249,6 @@
           CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
       if (classElement != null) {
         classElement.mixins = mixinTypes;
-        classElement.withClauseRange =
-            new SourceRange(withClause.offset, withClause.length);
       }
     }
     if (implementsClause != null) {
@@ -12934,19 +12345,20 @@
     return types;
   }
 
+  /**
+   * 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 (element != null) {
-      if (typeName is SimpleIdentifier) {
-        typeName.staticElement = element;
-      } else if (typeName is PrefixedIdentifier) {
-        PrefixedIdentifier identifier = typeName;
-        identifier.identifier.staticElement = element;
-        SimpleIdentifier prefix = identifier.prefix;
-        Element prefixElement = nameScope.lookup(prefix, definingLibrary);
-        if (prefixElement != null) {
-          prefix.staticElement = prefixElement;
-        }
-      }
+    if (typeName is SimpleIdentifier) {
+      typeName.staticElement = element;
+    } else if (typeName is PrefixedIdentifier) {
+      typeName.identifier.staticElement = element;
+      SimpleIdentifier prefix = typeName.prefix;
+      prefix.staticElement = nameScope.lookup(prefix, definingLibrary);
     }
   }
 
@@ -13252,6 +12664,11 @@
   ExecutableElement _enclosingFunction;
 
   /**
+   * Information about local variables in the enclosing function or method.
+   */
+  LocalVariableInfo _localVariableInfo;
+
+  /**
    * Initialize a newly created visitor to resolve the nodes in an AST node.
    *
    * [definingLibrary] is the element for the library containing the node being
@@ -13273,15 +12690,47 @@
             nameScope: nameScope);
 
   @override
+  Object visitBlockFunctionBody(BlockFunctionBody node) {
+    assert(_localVariableInfo != null);
+    return super.visitBlockFunctionBody(node);
+  }
+
+  @override
+  Object visitConstructorDeclaration(ConstructorDeclaration node) {
+    ExecutableElement outerFunction = _enclosingFunction;
+    LocalVariableInfo outerLocalVariableInfo = _localVariableInfo;
+    try {
+      _localVariableInfo ??= new LocalVariableInfo();
+      (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo;
+      _enclosingFunction = node.element;
+      return super.visitConstructorDeclaration(node);
+    } finally {
+      _localVariableInfo = outerLocalVariableInfo;
+      _enclosingFunction = outerFunction;
+    }
+  }
+
+  @override
   Object visitExportDirective(ExportDirective node) => null;
 
   @override
+  Object visitExpressionFunctionBody(ExpressionFunctionBody node) {
+    assert(_localVariableInfo != null);
+    return super.visitExpressionFunctionBody(node);
+  }
+
+  @override
   Object visitFunctionDeclaration(FunctionDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
+    LocalVariableInfo outerLocalVariableInfo = _localVariableInfo;
     try {
+      _localVariableInfo ??= new LocalVariableInfo();
+      (node.functionExpression.body as FunctionBodyImpl).localVariableInfo =
+          _localVariableInfo;
       _enclosingFunction = node.element;
       return super.visitFunctionDeclaration(node);
     } finally {
+      _localVariableInfo = outerLocalVariableInfo;
       _enclosingFunction = outerFunction;
     }
   }
@@ -13290,10 +12739,14 @@
   Object visitFunctionExpression(FunctionExpression node) {
     if (node.parent is! FunctionDeclaration) {
       ExecutableElement outerFunction = _enclosingFunction;
+      LocalVariableInfo outerLocalVariableInfo = _localVariableInfo;
       try {
+        _localVariableInfo ??= new LocalVariableInfo();
+        (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo;
         _enclosingFunction = node.element;
         return super.visitFunctionExpression(node);
       } finally {
+        _localVariableInfo = outerLocalVariableInfo;
         _enclosingFunction = outerFunction;
       }
     } else {
@@ -13307,10 +12760,14 @@
   @override
   Object visitMethodDeclaration(MethodDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
+    LocalVariableInfo outerLocalVariableInfo = _localVariableInfo;
     try {
+      _localVariableInfo ??= new LocalVariableInfo();
+      (node.body as FunctionBodyImpl).localVariableInfo = _localVariableInfo;
       _enclosingFunction = node.element;
       return super.visitMethodDeclaration(node);
     } finally {
+      _localVariableInfo = outerLocalVariableInfo;
       _enclosingFunction = outerFunction;
     }
   }
@@ -13356,26 +12813,12 @@
     }
     // Must be local or parameter.
     ElementKind kind = element.kind;
-    if (kind == ElementKind.LOCAL_VARIABLE) {
+    if (kind == ElementKind.LOCAL_VARIABLE || kind == ElementKind.PARAMETER) {
       node.staticElement = element;
-      LocalVariableElementImpl variableImpl =
-          element as LocalVariableElementImpl;
       if (node.inSetterContext()) {
-        variableImpl.markPotentiallyMutatedInScope();
+        _localVariableInfo.potentiallyMutatedInScope.add(element);
         if (element.enclosingElement != _enclosingFunction) {
-          variableImpl.markPotentiallyMutatedInClosure();
-        }
-      }
-    } else if (kind == ElementKind.PARAMETER) {
-      node.staticElement = element;
-      if (node.inSetterContext()) {
-        ParameterElementImpl parameterImpl = element as ParameterElementImpl;
-        parameterImpl.markPotentiallyMutatedInScope();
-        // If we are in some closure, check if it is not the same as where
-        // variable is declared.
-        if (_enclosingFunction != null &&
-            (element.enclosingElement != _enclosingFunction)) {
-          parameterImpl.markPotentiallyMutatedInClosure();
+          _localVariableInfo.potentiallyMutatedInClosure.add(element);
         }
       }
     }
@@ -13452,29 +12895,6 @@
   }
 }
 
-class _ElementBuilder_visitClassDeclaration extends UnifyingAstVisitor<Object> {
-  final ElementBuilder builder;
-
-  List<ClassMember> nonFields;
-
-  _ElementBuilder_visitClassDeclaration(this.builder, this.nonFields) : super();
-
-  @override
-  Object visitConstructorDeclaration(ConstructorDeclaration node) {
-    nonFields.add(node);
-    return null;
-  }
-
-  @override
-  Object visitMethodDeclaration(MethodDeclaration node) {
-    nonFields.add(node);
-    return null;
-  }
-
-  @override
-  Object visitNode(AstNode node) => node.accept(builder);
-}
-
 class _ResolverVisitor_isVariableAccessedInClosure
     extends RecursiveAstVisitor<Object> {
   final Element variable;
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index 49ea3ba..5a2e2c0 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -2,2707 +2,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+@deprecated
 library analyzer.src.generated.scanner;
 
-import 'dart:collection';
-
-import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-
-/**
- * The opening half of a grouping pair of tokens. This is used for curly
- * brackets ('{'), parentheses ('('), and square brackets ('[').
- */
-class BeginToken extends Token {
-  /**
-   * The token that corresponds to this token.
-   */
-  Token endToken;
-
-  /**
-   * Initialize a newly created token to have the given [type] at the given
-   * [offset].
-   */
-  BeginToken(TokenType type, int offset) : super(type, offset) {
-    assert(type == TokenType.OPEN_CURLY_BRACKET ||
-        type == TokenType.OPEN_PAREN ||
-        type == TokenType.OPEN_SQUARE_BRACKET ||
-        type == TokenType.STRING_INTERPOLATION_EXPRESSION);
-  }
-
-  @override
-  Token copy() => new BeginToken(type, offset);
-}
-
-/**
- * A begin token that is preceded by comments.
- */
-class BeginTokenWithComment extends BeginToken {
-  /**
-   * The first comment in the list of comments that precede this token.
-   */
-  CommentToken _precedingComment;
-
-  /**
-   * Initialize a newly created token to have the given [type] at the given
-   * [offset] and to be preceded by the comments reachable from the given
-   * [comment].
-   */
-  BeginTokenWithComment(TokenType type, int offset, this._precedingComment)
-      : super(type, offset) {
-    _setCommentParent(_precedingComment);
-  }
-
-  CommentToken get precedingComments => _precedingComment;
-
-  void set precedingComments(CommentToken comment) {
-    _precedingComment = comment;
-    _setCommentParent(_precedingComment);
-  }
-
-  @override
-  void applyDelta(int delta) {
-    super.applyDelta(delta);
-    Token token = precedingComments;
-    while (token != null) {
-      token.applyDelta(delta);
-      token = token.next;
-    }
-  }
-
-  @override
-  Token copy() =>
-      new BeginTokenWithComment(type, offset, copyComments(precedingComments));
-}
-
-/**
- * A [CharacterReader] that reads a range of characters from another character
- * reader.
- */
-class CharacterRangeReader extends CharacterReader {
-  /**
-   * The reader from which the characters are actually being read.
-   */
-  final CharacterReader baseReader;
-
-  /**
-   * The last character to be read.
-   */
-  final int endIndex;
-
-  /**
-   * Initialize a newly created reader to read the characters from the given
-   * [baseReader] between the [startIndex] inclusive to [endIndex] exclusive.
-   */
-  CharacterRangeReader(this.baseReader, int startIndex, this.endIndex) {
-    baseReader.offset = startIndex - 1;
-  }
-
-  @override
-  int get offset => baseReader.offset;
-
-  @override
-  void set offset(int offset) {
-    baseReader.offset = offset;
-  }
-
-  @override
-  int advance() {
-    if (baseReader.offset + 1 >= endIndex) {
-      return -1;
-    }
-    return baseReader.advance();
-  }
-
-  @override
-  String getString(int start, int endDelta) =>
-      baseReader.getString(start, endDelta);
-
-  @override
-  int peek() {
-    if (baseReader.offset + 1 >= endIndex) {
-      return -1;
-    }
-    return baseReader.peek();
-  }
-}
-
-/**
- * An object used by the scanner to read the characters to be scanned.
- */
-abstract class CharacterReader {
-  /**
-   * The current offset relative to the beginning of the source. Return the
-   * initial offset if the scanner has not yet scanned the source code, and one
-   * (1) past the end of the source code if the entire source code has been
-   * scanned.
-   */
-  int get offset;
-
-  /**
-   * Set the current offset relative to the beginning of the source to the given
-   * [offset]. The new offset must be between the initial offset and one (1)
-   * past the end of the source code.
-   */
-  void set offset(int offset);
-
-  /**
-   * Advance the current position and return the character at the new current
-   * position.
-   */
-  int advance();
-
-  /**
-   * Return the substring of the source code between the [start] offset and the
-   * modified current position. The current position is modified by adding the
-   * [endDelta], which is the number of characters after the current location to
-   * be included in the string, or the number of characters before the current
-   * location to be excluded if the offset is negative.
-   */
-  String getString(int start, int endDelta);
-
-  /**
-   * Return the character at the current position without changing the current
-   * position.
-   */
-  int peek();
-}
-
-/**
- * A [CharacterReader] that reads characters from a character sequence.
- */
-class CharSequenceReader implements CharacterReader {
-  /**
-   * The sequence from which characters will be read.
-   */
-  final String _sequence;
-
-  /**
-   * The number of characters in the string.
-   */
-  int _stringLength = 0;
-
-  /**
-   * The index, relative to the string, of the last character that was read.
-   */
-  int _charOffset = 0;
-
-  /**
-   * Initialize a newly created reader to read the characters in the given
-   * [_sequence].
-   */
-  CharSequenceReader(this._sequence) {
-    this._stringLength = _sequence.length;
-    this._charOffset = -1;
-  }
-
-  @override
-  int get offset => _charOffset;
-
-  @override
-  void set offset(int offset) {
-    _charOffset = offset;
-  }
-
-  @override
-  int advance() {
-    if (_charOffset + 1 >= _stringLength) {
-      return -1;
-    }
-    return _sequence.codeUnitAt(++_charOffset);
-  }
-
-  @override
-  String getString(int start, int endDelta) =>
-      _sequence.substring(start, _charOffset + 1 + endDelta).toString();
-
-  @override
-  int peek() {
-    if (_charOffset + 1 >= _stringLength) {
-      return -1;
-    }
-    return _sequence.codeUnitAt(_charOffset + 1);
-  }
-}
-
-/**
- * A token representing a comment.
- */
-class CommentToken extends StringToken {
-  /**
-   * The [Token] that contains this comment.
-   */
-  Token parent;
-
-  /**
-   * Initialize a newly created token to represent a token of the given [type]
-   * with the given [value] at the given [offset].
-   */
-  CommentToken(TokenType type, String value, int offset)
-      : super(type, value, offset);
-
-  @override
-  CommentToken copy() => new CommentToken(type, _value, offset);
-}
-
-/**
- * A documentation comment token.
- */
-class DocumentationCommentToken extends CommentToken {
-  /**
-   * The references embedded within the documentation comment.
-   * This list will be empty unless this is a documentation comment that has
-   * references embedded within it.
-   */
-  final List<Token> references = <Token>[];
-
-  /**
-   * Initialize a newly created token to represent a token of the given [type]
-   * with the given [value] at the given [offset].
-   */
-  DocumentationCommentToken(TokenType type, String value, int offset)
-      : super(type, value, offset);
-
-  @override
-  CommentToken copy() => new DocumentationCommentToken(type, _value, offset);
-}
-
-/**
- * The keywords in the Dart programming language.
- */
-class Keyword {
-  static const Keyword ASSERT = const Keyword('ASSERT', "assert");
-
-  static const Keyword BREAK = const Keyword('BREAK', "break");
-
-  static const Keyword CASE = const Keyword('CASE', "case");
-
-  static const Keyword CATCH = const Keyword('CATCH', "catch");
-
-  static const Keyword CLASS = const Keyword('CLASS', "class");
-
-  static const Keyword CONST = const Keyword('CONST', "const");
-
-  static const Keyword CONTINUE = const Keyword('CONTINUE', "continue");
-
-  static const Keyword DEFAULT = const Keyword('DEFAULT', "default");
-
-  static const Keyword DO = const Keyword('DO', "do");
-
-  static const Keyword ELSE = const Keyword('ELSE', "else");
-
-  static const Keyword ENUM = const Keyword('ENUM', "enum");
-
-  static const Keyword EXTENDS = const Keyword('EXTENDS', "extends");
-
-  static const Keyword FALSE = const Keyword('FALSE', "false");
-
-  static const Keyword FINAL = const Keyword('FINAL', "final");
-
-  static const Keyword FINALLY = const Keyword('FINALLY', "finally");
-
-  static const Keyword FOR = const Keyword('FOR', "for");
-
-  static const Keyword IF = const Keyword('IF', "if");
-
-  static const Keyword IN = const Keyword('IN', "in");
-
-  static const Keyword IS = const Keyword('IS', "is");
-
-  static const Keyword NEW = const Keyword('NEW', "new");
-
-  static const Keyword NULL = const Keyword('NULL', "null");
-
-  static const Keyword RETHROW = const Keyword('RETHROW', "rethrow");
-
-  static const Keyword RETURN = const Keyword('RETURN', "return");
-
-  static const Keyword SUPER = const Keyword('SUPER', "super");
-
-  static const Keyword SWITCH = const Keyword('SWITCH', "switch");
-
-  static const Keyword THIS = const Keyword('THIS', "this");
-
-  static const Keyword THROW = const Keyword('THROW', "throw");
-
-  static const Keyword TRUE = const Keyword('TRUE', "true");
-
-  static const Keyword TRY = const Keyword('TRY', "try");
-
-  static const Keyword VAR = const Keyword('VAR', "var");
-
-  static const Keyword VOID = const Keyword('VOID', "void");
-
-  static const Keyword WHILE = const Keyword('WHILE', "while");
-
-  static const Keyword WITH = const Keyword('WITH', "with");
-
-  static const Keyword ABSTRACT = const Keyword('ABSTRACT', "abstract", true);
-
-  static const Keyword AS = const Keyword('AS', "as", true);
-
-  static const Keyword DEFERRED = const Keyword('DEFERRED', "deferred", true);
-
-  static const Keyword DYNAMIC = const Keyword('DYNAMIC', "dynamic", true);
-
-  static const Keyword EXPORT = const Keyword('EXPORT', "export", true);
-
-  static const Keyword EXTERNAL = const Keyword('EXTERNAL', "external", true);
-
-  static const Keyword FACTORY = const Keyword('FACTORY', "factory", true);
-
-  static const Keyword GET = const Keyword('GET', "get", true);
-
-  static const Keyword IMPLEMENTS =
-      const Keyword('IMPLEMENTS', "implements", true);
-
-  static const Keyword IMPORT = const Keyword('IMPORT', "import", true);
-
-  static const Keyword LIBRARY = const Keyword('LIBRARY', "library", true);
-
-  static const Keyword OPERATOR = const Keyword('OPERATOR', "operator", true);
-
-  static const Keyword PART = const Keyword('PART', "part", true);
-
-  static const Keyword SET = const Keyword('SET', "set", true);
-
-  static const Keyword STATIC = const Keyword('STATIC', "static", true);
-
-  static const Keyword TYPEDEF = const Keyword('TYPEDEF', "typedef", true);
-
-  static const List<Keyword> values = const [
-    ASSERT,
-    BREAK,
-    CASE,
-    CATCH,
-    CLASS,
-    CONST,
-    CONTINUE,
-    DEFAULT,
-    DO,
-    ELSE,
-    ENUM,
-    EXTENDS,
-    FALSE,
-    FINAL,
-    FINALLY,
-    FOR,
-    IF,
-    IN,
-    IS,
-    NEW,
-    NULL,
-    RETHROW,
-    RETURN,
-    SUPER,
-    SWITCH,
-    THIS,
-    THROW,
-    TRUE,
-    TRY,
-    VAR,
-    VOID,
-    WHILE,
-    WITH,
-    ABSTRACT,
-    AS,
-    DEFERRED,
-    DYNAMIC,
-    EXPORT,
-    EXTERNAL,
-    FACTORY,
-    GET,
-    IMPLEMENTS,
-    IMPORT,
-    LIBRARY,
-    OPERATOR,
-    PART,
-    SET,
-    STATIC,
-    TYPEDEF
-  ];
-
-  /**
-   * A table mapping the lexemes of keywords to the corresponding keyword.
-   */
-  static final Map<String, Keyword> keywords = _createKeywordMap();
-
-  /**
-   * The name of the keyword type.
-   */
-  final String name;
-
-  /**
-   * The lexeme for the keyword.
-   */
-  final String syntax;
-
-  /**
-   * A flag indicating whether the keyword is a pseudo-keyword. Pseudo keywords
-   * can be used as identifiers.
-   */
-  final bool isPseudoKeyword;
-
-  /**
-   * Initialize a newly created keyword to have the given [name] and [syntax].
-   * The keyword is a pseudo-keyword if the [isPseudoKeyword] flag is `true`.
-   */
-  const Keyword(this.name, this.syntax, [this.isPseudoKeyword = false]);
-
-  @override
-  String toString() => name;
-
-  /**
-   * Create a table mapping the lexemes of keywords to the corresponding keyword
-   * and return the table that was created.
-   */
-  static Map<String, Keyword> _createKeywordMap() {
-    LinkedHashMap<String, Keyword> result =
-        new LinkedHashMap<String, Keyword>();
-    for (Keyword keyword in values) {
-      result[keyword.syntax] = keyword;
-    }
-    return result;
-  }
-}
-
-/**
- * A state in a state machine used to scan keywords.
- */
-class KeywordState {
-  /**
-   * An empty transition table used by leaf states.
-   */
-  static List<KeywordState> _EMPTY_TABLE = new List<KeywordState>(26);
-
-  /**
-   * The initial state in the state machine.
-   */
-  static final KeywordState KEYWORD_STATE = _createKeywordStateTable();
-
-  /**
-   * A table mapping characters to the states to which those characters will
-   * transition. (The index into the array is the offset from the character
-   * `'a'` to the transitioning character.)
-   */
-  final List<KeywordState> _table;
-
-  /**
-   * The keyword that is recognized by this state, or `null` if this state is
-   * not a terminal state.
-   */
-  Keyword _keyword;
-
-  /**
-   * Initialize a newly created state to have the given transitions and to
-   * recognize the keyword with the given [syntax].
-   */
-  KeywordState(this._table, String syntax) {
-    this._keyword = (syntax == null) ? null : Keyword.keywords[syntax];
-  }
-
-  /**
-   * Return the keyword that was recognized by this state, or `null` if this
-   * state does not recognized a keyword.
-   */
-  Keyword keyword() => _keyword;
-
-  /**
-   * Return the state that follows this state on a transition of the given
-   * [character], or `null` if there is no valid state reachable from this state
-   * with such a transition.
-   */
-  KeywordState next(int character) => _table[character - 0x61];
-
-  /**
-   * Create the next state in the state machine where we have already recognized
-   * the subset of strings in the given array of [strings] starting at the given
-   * [offset] and having the given [length]. All of these strings have a common
-   * prefix and the next character is at the given [start] index.
-   */
-  static KeywordState _computeKeywordStateTable(
-      int start, List<String> strings, int offset, int length) {
-    List<KeywordState> result = new List<KeywordState>(26);
-    assert(length != 0);
-    int chunk = 0x0;
-    int chunkStart = -1;
-    bool isLeaf = false;
-    for (int i = offset; i < offset + length; i++) {
-      if (strings[i].length == start) {
-        isLeaf = true;
-      }
-      if (strings[i].length > start) {
-        int c = strings[i].codeUnitAt(start);
-        if (chunk != c) {
-          if (chunkStart != -1) {
-            result[chunk - 0x61] = _computeKeywordStateTable(
-                start + 1, strings, chunkStart, i - chunkStart);
-          }
-          chunkStart = i;
-          chunk = c;
-        }
-      }
-    }
-    if (chunkStart != -1) {
-      assert(result[chunk - 0x61] == null);
-      result[chunk - 0x61] = _computeKeywordStateTable(
-          start + 1, strings, chunkStart, offset + length - chunkStart);
-    } else {
-      assert(length == 1);
-      return new KeywordState(_EMPTY_TABLE, strings[offset]);
-    }
-    if (isLeaf) {
-      return new KeywordState(result, strings[offset]);
-    } else {
-      return new KeywordState(result, null);
-    }
-  }
-
-  /**
-   * Create and return the initial state in the state machine.
-   */
-  static KeywordState _createKeywordStateTable() {
-    List<Keyword> values = Keyword.values;
-    List<String> strings = new List<String>(values.length);
-    for (int i = 0; i < values.length; i++) {
-      strings[i] = values[i].syntax;
-    }
-    strings.sort();
-    return _computeKeywordStateTable(0, strings, 0, strings.length);
-  }
-}
-
-/**
- * A token representing a keyword in the language.
- */
-class KeywordToken extends Token {
-  /**
-   * The keyword being represented by this token.
-   */
-  final Keyword keyword;
-
-  /**
-   * Initialize a newly created token to represent the given [keyword] at the
-   * given [offset].
-   */
-  KeywordToken(this.keyword, int offset) : super(TokenType.KEYWORD, offset);
-
-  @override
-  String get lexeme => keyword.syntax;
-
-  @override
-  Token copy() => new KeywordToken(keyword, offset);
-
-  @override
-  Keyword value() => keyword;
-}
-
-/**
- * A keyword token that is preceded by comments.
- */
-class KeywordTokenWithComment extends KeywordToken {
-  /**
-   * The first comment in the list of comments that precede this token.
-   */
-  CommentToken _precedingComment;
-
-  /**
-   * Initialize a newly created token to to represent the given [keyword] at the
-   * given [offset] and to be preceded by the comments reachable from the given
-   * [comment].
-   */
-  KeywordTokenWithComment(Keyword keyword, int offset, this._precedingComment)
-      : super(keyword, offset) {
-    _setCommentParent(_precedingComment);
-  }
-
-  CommentToken get precedingComments => _precedingComment;
-
-  void set precedingComments(CommentToken comment) {
-    _precedingComment = comment;
-    _setCommentParent(_precedingComment);
-  }
-
-  @override
-  void applyDelta(int delta) {
-    super.applyDelta(delta);
-    Token token = precedingComments;
-    while (token != null) {
-      token.applyDelta(delta);
-      token = token.next;
-    }
-  }
-
-  @override
-  Token copy() => new KeywordTokenWithComment(
-      keyword, offset, copyComments(precedingComments));
-}
-
-/**
- * The class `Scanner` implements a scanner for Dart code.
- *
- * The lexical structure of Dart is ambiguous without knowledge of the context
- * in which a token is being scanned. For example, without context we cannot
- * determine whether source of the form "<<" should be scanned as a single
- * left-shift operator or as two left angle brackets. This scanner does not have
- * any context, so it always resolves such conflicts by scanning the longest
- * possible token.
- */
-class Scanner {
-  /**
-   * The source being scanned.
-   */
-  final Source source;
-
-  /**
-   * The reader used to access the characters in the source.
-   */
-  final CharacterReader _reader;
-
-  /**
-   * The error listener that will be informed of any errors that are found
-   * during the scan.
-   */
-  final AnalysisErrorListener _errorListener;
-
-  /**
-   * The flag specifying whether documentation comments should be parsed.
-   */
-  bool _preserveComments = true;
-
-  /**
-   * The token pointing to the head of the linked list of tokens.
-   */
-  Token _tokens;
-
-  /**
-   * The last token that was scanned.
-   */
-  Token _tail;
-
-  /**
-   * The first token in the list of comment tokens found since the last
-   * non-comment token.
-   */
-  Token _firstComment;
-
-  /**
-   * The last token in the list of comment tokens found since the last
-   * non-comment token.
-   */
-  Token _lastComment;
-
-  /**
-   * The index of the first character of the current token.
-   */
-  int _tokenStart = 0;
-
-  /**
-   * A list containing the offsets of the first character of each line in the
-   * source code.
-   */
-  List<int> _lineStarts = new List<int>();
-
-  /**
-   * A list, treated something like a stack, of tokens representing the
-   * beginning of a matched pair. It is used to pair the end tokens with the
-   * begin tokens.
-   */
-  List<BeginToken> _groupingStack = new List<BeginToken>();
-
-  /**
-   * The index of the last item in the [_groupingStack], or `-1` if the stack is
-   * empty.
-   */
-  int _stackEnd = -1;
-
-  /**
-   * A flag indicating whether any unmatched groups were found during the parse.
-   */
-  bool _hasUnmatchedGroups = false;
-
-  /**
-   * A flag indicating whether to parse generic method comments, of the form
-   * `/*=T*/` and `/*<T>*/`.
-   */
-  bool scanGenericMethodComments = false;
-
-  /**
-   * Initialize a newly created scanner to scan characters from the given
-   * [source]. The given character [_reader] will be used to read the characters
-   * in the source. The given [_errorListener] will be informed of any errors
-   * that are found.
-   */
-  Scanner(this.source, this._reader, this._errorListener) {
-    _tokens = new Token(TokenType.EOF, -1);
-    _tokens.setNext(_tokens);
-    _tail = _tokens;
-    _tokenStart = -1;
-    _lineStarts.add(0);
-  }
-
-  /**
-   * Return the first token in the token stream that was scanned.
-   */
-  Token get firstToken => _tokens.next;
-
-  /**
-   * Return `true` if any unmatched groups were found during the parse.
-   */
-  bool get hasUnmatchedGroups => _hasUnmatchedGroups;
-
-  /**
-   * Return an array containing the offsets of the first character of each line
-   * in the source code.
-   */
-  List<int> get lineStarts => _lineStarts;
-
-  /**
-   * Set whether documentation tokens should be preserved.
-   */
-  void set preserveComments(bool preserveComments) {
-    this._preserveComments = preserveComments;
-  }
-
-  /**
-   * Return the last token that was scanned.
-   */
-  Token get tail => _tail;
-
-  /**
-   * Append the given [token] to the end of the token stream being scanned. This
-   * method is intended to be used by subclasses that copy existing tokens and
-   * should not normally be used because it will fail to correctly associate any
-   * comments with the token being passed in.
-   */
-  void appendToken(Token token) {
-    _tail = _tail.setNext(token);
-  }
-
-  int bigSwitch(int next) {
-    _beginToken();
-    if (next == 0xD) {
-      // '\r'
-      next = _reader.advance();
-      if (next == 0xA) {
-        // '\n'
-        next = _reader.advance();
-      }
-      recordStartOfLine();
-      return next;
-    } else if (next == 0xA) {
-      // '\n'
-      next = _reader.advance();
-      recordStartOfLine();
-      return next;
-    } else if (next == 0x9 || next == 0x20) {
-      // '\t' || ' '
-      return _reader.advance();
-    }
-    if (next == 0x72) {
-      // 'r'
-      int peek = _reader.peek();
-      if (peek == 0x22 || peek == 0x27) {
-        // '"' || "'"
-        int start = _reader.offset;
-        return _tokenizeString(_reader.advance(), start, true);
-      }
-    }
-    if (0x61 <= next && next <= 0x7A) {
-      // 'a'-'z'
-      return _tokenizeKeywordOrIdentifier(next, true);
-    }
-    if ((0x41 <= next && next <= 0x5A) || next == 0x5F || next == 0x24) {
-      // 'A'-'Z' || '_' || '$'
-      return _tokenizeIdentifier(next, _reader.offset, true);
-    }
-    if (next == 0x3C) {
-      // '<'
-      return _tokenizeLessThan(next);
-    }
-    if (next == 0x3E) {
-      // '>'
-      return _tokenizeGreaterThan(next);
-    }
-    if (next == 0x3D) {
-      // '='
-      return _tokenizeEquals(next);
-    }
-    if (next == 0x21) {
-      // '!'
-      return _tokenizeExclamation(next);
-    }
-    if (next == 0x2B) {
-      // '+'
-      return _tokenizePlus(next);
-    }
-    if (next == 0x2D) {
-      // '-'
-      return _tokenizeMinus(next);
-    }
-    if (next == 0x2A) {
-      // '*'
-      return _tokenizeMultiply(next);
-    }
-    if (next == 0x25) {
-      // '%'
-      return _tokenizePercent(next);
-    }
-    if (next == 0x26) {
-      // '&'
-      return _tokenizeAmpersand(next);
-    }
-    if (next == 0x7C) {
-      // '|'
-      return _tokenizeBar(next);
-    }
-    if (next == 0x5E) {
-      // '^'
-      return _tokenizeCaret(next);
-    }
-    if (next == 0x5B) {
-      // '['
-      return _tokenizeOpenSquareBracket(next);
-    }
-    if (next == 0x7E) {
-      // '~'
-      return _tokenizeTilde(next);
-    }
-    if (next == 0x5C) {
-      // '\\'
-      _appendTokenOfType(TokenType.BACKSLASH);
-      return _reader.advance();
-    }
-    if (next == 0x23) {
-      // '#'
-      return _tokenizeTag(next);
-    }
-    if (next == 0x28) {
-      // '('
-      _appendBeginToken(TokenType.OPEN_PAREN);
-      return _reader.advance();
-    }
-    if (next == 0x29) {
-      // ')'
-      _appendEndToken(TokenType.CLOSE_PAREN, TokenType.OPEN_PAREN);
-      return _reader.advance();
-    }
-    if (next == 0x2C) {
-      // ','
-      _appendTokenOfType(TokenType.COMMA);
-      return _reader.advance();
-    }
-    if (next == 0x3A) {
-      // ':'
-      _appendTokenOfType(TokenType.COLON);
-      return _reader.advance();
-    }
-    if (next == 0x3B) {
-      // ';'
-      _appendTokenOfType(TokenType.SEMICOLON);
-      return _reader.advance();
-    }
-    if (next == 0x3F) {
-      // '?'
-      return _tokenizeQuestion();
-    }
-    if (next == 0x5D) {
-      // ']'
-      _appendEndToken(
-          TokenType.CLOSE_SQUARE_BRACKET, TokenType.OPEN_SQUARE_BRACKET);
-      return _reader.advance();
-    }
-    if (next == 0x60) {
-      // '`'
-      _appendTokenOfType(TokenType.BACKPING);
-      return _reader.advance();
-    }
-    if (next == 0x7B) {
-      // '{'
-      _appendBeginToken(TokenType.OPEN_CURLY_BRACKET);
-      return _reader.advance();
-    }
-    if (next == 0x7D) {
-      // '}'
-      _appendEndToken(
-          TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET);
-      return _reader.advance();
-    }
-    if (next == 0x2F) {
-      // '/'
-      return _tokenizeSlashOrComment(next);
-    }
-    if (next == 0x40) {
-      // '@'
-      _appendTokenOfType(TokenType.AT);
-      return _reader.advance();
-    }
-    if (next == 0x22 || next == 0x27) {
-      // '"' || "'"
-      return _tokenizeString(next, _reader.offset, false);
-    }
-    if (next == 0x2E) {
-      // '.'
-      return _tokenizeDotOrNumber(next);
-    }
-    if (next == 0x30) {
-      // '0'
-      return _tokenizeHexOrNumber(next);
-    }
-    if (0x31 <= next && next <= 0x39) {
-      // '1'-'9'
-      return _tokenizeNumber(next);
-    }
-    if (next == -1) {
-      // EOF
-      return -1;
-    }
-    _reportError(ScannerErrorCode.ILLEGAL_CHARACTER, [next]);
-    return _reader.advance();
-  }
-
-  /**
-   * Record the fact that we are at the beginning of a new line in the source.
-   */
-  void recordStartOfLine() {
-    _lineStarts.add(_reader.offset);
-  }
-
-  /**
-   * Record that the source begins on the given [line] and [column] at the
-   * current offset as given by the reader. Both the line and the column are
-   * one-based indexes. The line starts for lines before the given line will not
-   * be correct.
-   *
-   * This method must be invoked at most one time and must be invoked before
-   * scanning begins. The values provided must be sensible. The results are
-   * undefined if these conditions are violated.
-   */
-  void setSourceStart(int line, int column) {
-    int offset = _reader.offset;
-    if (line < 1 || column < 1 || offset < 0 || (line + column - 2) >= offset) {
-      return;
-    }
-    for (int i = 2; i < line; i++) {
-      _lineStarts.add(1);
-    }
-    _lineStarts.add(offset - column + 1);
-  }
-
-  /**
-   * Scan the source code to produce a list of tokens representing the source,
-   * and return the first token in the list of tokens that were produced.
-   */
-  Token tokenize() {
-    int next = _reader.advance();
-    while (next != -1) {
-      next = bigSwitch(next);
-    }
-    _appendEofToken();
-    return firstToken;
-  }
-
-  void _appendBeginToken(TokenType type) {
-    BeginToken token;
-    if (_firstComment == null) {
-      token = new BeginToken(type, _tokenStart);
-    } else {
-      token = new BeginTokenWithComment(type, _tokenStart, _firstComment);
-      _firstComment = null;
-      _lastComment = null;
-    }
-    _tail = _tail.setNext(token);
-    _groupingStack.add(token);
-    _stackEnd++;
-  }
-
-  void _appendCommentToken(TokenType type, String value) {
-    CommentToken token = null;
-    TokenType genericComment = _matchGenericMethodCommentType(value);
-    if (genericComment != null) {
-      token = new CommentToken(genericComment, value, _tokenStart);
-    } else if (!_preserveComments) {
-      // Ignore comment tokens if client specified that it doesn't need them.
-      return;
-    } else {
-      // OK, remember comment tokens.
-      if (_isDocumentationComment(value)) {
-        token = new DocumentationCommentToken(type, value, _tokenStart);
-      } else {
-        token = new CommentToken(type, value, _tokenStart);
-      }
-    }
-    if (_firstComment == null) {
-      _firstComment = token;
-      _lastComment = _firstComment;
-    } else {
-      _lastComment = _lastComment.setNext(token);
-    }
-  }
-
-  void _appendEndToken(TokenType type, TokenType beginType) {
-    Token token;
-    if (_firstComment == null) {
-      token = new Token(type, _tokenStart);
-    } else {
-      token = new TokenWithComment(type, _tokenStart, _firstComment);
-      _firstComment = null;
-      _lastComment = null;
-    }
-    _tail = _tail.setNext(token);
-    if (_stackEnd >= 0) {
-      BeginToken begin = _groupingStack[_stackEnd];
-      if (begin.type == beginType) {
-        begin.endToken = token;
-        _groupingStack.removeAt(_stackEnd--);
-      }
-    }
-  }
-
-  void _appendEofToken() {
-    Token eofToken;
-    if (_firstComment == null) {
-      eofToken = new Token(TokenType.EOF, _reader.offset + 1);
-    } else {
-      eofToken = new TokenWithComment(
-          TokenType.EOF, _reader.offset + 1, _firstComment);
-      _firstComment = null;
-      _lastComment = null;
-    }
-    // The EOF token points to itself so that there is always infinite
-    // look-ahead.
-    eofToken.setNext(eofToken);
-    _tail = _tail.setNext(eofToken);
-    if (_stackEnd >= 0) {
-      _hasUnmatchedGroups = true;
-      // TODO(brianwilkerson) Fix the ungrouped tokens?
-    }
-  }
-
-  void _appendKeywordToken(Keyword keyword) {
-    if (_firstComment == null) {
-      _tail = _tail.setNext(new KeywordToken(keyword, _tokenStart));
-    } else {
-      _tail = _tail.setNext(
-          new KeywordTokenWithComment(keyword, _tokenStart, _firstComment));
-      _firstComment = null;
-      _lastComment = null;
-    }
-  }
-
-  void _appendStringToken(TokenType type, String value) {
-    if (_firstComment == null) {
-      _tail = _tail.setNext(new StringToken(type, value, _tokenStart));
-    } else {
-      _tail = _tail.setNext(
-          new StringTokenWithComment(type, value, _tokenStart, _firstComment));
-      _firstComment = null;
-      _lastComment = null;
-    }
-  }
-
-  void _appendStringTokenWithOffset(TokenType type, String value, int offset) {
-    if (_firstComment == null) {
-      _tail = _tail.setNext(new StringToken(type, value, _tokenStart + offset));
-    } else {
-      _tail = _tail.setNext(new StringTokenWithComment(
-          type, value, _tokenStart + offset, _firstComment));
-      _firstComment = null;
-      _lastComment = null;
-    }
-  }
-
-  void _appendTokenOfType(TokenType type) {
-    if (_firstComment == null) {
-      _tail = _tail.setNext(new Token(type, _tokenStart));
-    } else {
-      _tail =
-          _tail.setNext(new TokenWithComment(type, _tokenStart, _firstComment));
-      _firstComment = null;
-      _lastComment = null;
-    }
-  }
-
-  void _appendTokenOfTypeWithOffset(TokenType type, int offset) {
-    if (_firstComment == null) {
-      _tail = _tail.setNext(new Token(type, offset));
-    } else {
-      _tail = _tail.setNext(new TokenWithComment(type, offset, _firstComment));
-      _firstComment = null;
-      _lastComment = null;
-    }
-  }
-
-  void _beginToken() {
-    _tokenStart = _reader.offset;
-  }
-
-  /**
-   * Return the beginning token corresponding to a closing brace that was found
-   * while scanning inside a string interpolation expression. Tokens that cannot
-   * be matched with the closing brace will be dropped from the stack.
-   */
-  BeginToken _findTokenMatchingClosingBraceInInterpolationExpression() {
-    while (_stackEnd >= 0) {
-      BeginToken begin = _groupingStack[_stackEnd];
-      if (begin.type == TokenType.OPEN_CURLY_BRACKET ||
-          begin.type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
-        return begin;
-      }
-      _hasUnmatchedGroups = true;
-      _groupingStack.removeAt(_stackEnd--);
-    }
-    //
-    // We should never get to this point because we wouldn't be inside a string
-    // interpolation expression unless we had previously found the start of the
-    // expression.
-    //
-    return null;
-  }
-
-  /**
-   * Checks if [value] is the start of a generic method type annotation comment.
-   *
-   * This can either be of the form `/*<T>*/` or `/*=T*/`. The token type is
-   * returned, or null if it was not a generic method comment.
-   */
-  TokenType _matchGenericMethodCommentType(String value) {
-    if (scanGenericMethodComments) {
-      // Match /*< and >*/
-      if (StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x3C) &&
-          StringUtilities.endsWith3(value, 0x3E, 0x2A, 0x2F)) {
-        return TokenType.GENERIC_METHOD_TYPE_LIST;
-      }
-      // Match /*=
-      if (StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x3D)) {
-        return TokenType.GENERIC_METHOD_TYPE_ASSIGN;
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Report an error at the current offset. The [errorCode] is the error code
-   * indicating the nature of the error. The [arguments] are any arguments
-   * needed to complete the error message
-   */
-  void _reportError(ScannerErrorCode errorCode, [List<Object> arguments]) {
-    _errorListener.onError(
-        new AnalysisError(source, _reader.offset, 1, errorCode, arguments));
-  }
-
-  int _select(int choice, TokenType yesType, TokenType noType) {
-    int next = _reader.advance();
-    if (next == choice) {
-      _appendTokenOfType(yesType);
-      return _reader.advance();
-    } else {
-      _appendTokenOfType(noType);
-      return next;
-    }
-  }
-
-  int _selectWithOffset(
-      int choice, TokenType yesType, TokenType noType, int offset) {
-    int next = _reader.advance();
-    if (next == choice) {
-      _appendTokenOfTypeWithOffset(yesType, offset);
-      return _reader.advance();
-    } else {
-      _appendTokenOfTypeWithOffset(noType, offset);
-      return next;
-    }
-  }
-
-  int _tokenizeAmpersand(int next) {
-    // && &= &
-    next = _reader.advance();
-    if (next == 0x26) {
-      _appendTokenOfType(TokenType.AMPERSAND_AMPERSAND);
-      return _reader.advance();
-    } else if (next == 0x3D) {
-      _appendTokenOfType(TokenType.AMPERSAND_EQ);
-      return _reader.advance();
-    } else {
-      _appendTokenOfType(TokenType.AMPERSAND);
-      return next;
-    }
-  }
-
-  int _tokenizeBar(int next) {
-    // | || |=
-    next = _reader.advance();
-    if (next == 0x7C) {
-      _appendTokenOfType(TokenType.BAR_BAR);
-      return _reader.advance();
-    } else if (next == 0x3D) {
-      _appendTokenOfType(TokenType.BAR_EQ);
-      return _reader.advance();
-    } else {
-      _appendTokenOfType(TokenType.BAR);
-      return next;
-    }
-  }
-
-  int _tokenizeCaret(int next) =>
-      _select(0x3D, TokenType.CARET_EQ, TokenType.CARET);
-
-  int _tokenizeDotOrNumber(int next) {
-    int start = _reader.offset;
-    next = _reader.advance();
-    if (0x30 <= next && next <= 0x39) {
-      return _tokenizeFractionPart(next, start);
-    } else if (0x2E == next) {
-      return _select(
-          0x2E, TokenType.PERIOD_PERIOD_PERIOD, TokenType.PERIOD_PERIOD);
-    } else {
-      _appendTokenOfType(TokenType.PERIOD);
-      return next;
-    }
-  }
-
-  int _tokenizeEquals(int next) {
-    // = == =>
-    next = _reader.advance();
-    if (next == 0x3D) {
-      _appendTokenOfType(TokenType.EQ_EQ);
-      return _reader.advance();
-    } else if (next == 0x3E) {
-      _appendTokenOfType(TokenType.FUNCTION);
-      return _reader.advance();
-    }
-    _appendTokenOfType(TokenType.EQ);
-    return next;
-  }
-
-  int _tokenizeExclamation(int next) {
-    // ! !=
-    next = _reader.advance();
-    if (next == 0x3D) {
-      _appendTokenOfType(TokenType.BANG_EQ);
-      return _reader.advance();
-    }
-    _appendTokenOfType(TokenType.BANG);
-    return next;
-  }
-
-  int _tokenizeExponent(int next) {
-    if (next == 0x2B || next == 0x2D) {
-      next = _reader.advance();
-    }
-    bool hasDigits = false;
-    while (true) {
-      if (0x30 <= next && next <= 0x39) {
-        hasDigits = true;
-      } else {
-        if (!hasDigits) {
-          _reportError(ScannerErrorCode.MISSING_DIGIT);
-        }
-        return next;
-      }
-      next = _reader.advance();
-    }
-  }
-
-  int _tokenizeFractionPart(int next, int start) {
-    bool done = false;
-    bool hasDigit = false;
-    LOOP: while (!done) {
-      if (0x30 <= next && next <= 0x39) {
-        hasDigit = true;
-      } else if (0x65 == next || 0x45 == next) {
-        hasDigit = true;
-        next = _tokenizeExponent(_reader.advance());
-        done = true;
-        continue LOOP;
-      } else {
-        done = true;
-        continue LOOP;
-      }
-      next = _reader.advance();
-    }
-    if (!hasDigit) {
-      _appendStringToken(TokenType.INT, _reader.getString(start, -2));
-      if (0x2E == next) {
-        return _selectWithOffset(0x2E, TokenType.PERIOD_PERIOD_PERIOD,
-            TokenType.PERIOD_PERIOD, _reader.offset - 1);
-      }
-      _appendTokenOfTypeWithOffset(TokenType.PERIOD, _reader.offset - 1);
-      return bigSwitch(next);
-    }
-    _appendStringToken(
-        TokenType.DOUBLE, _reader.getString(start, next < 0 ? 0 : -1));
-    return next;
-  }
-
-  int _tokenizeGreaterThan(int next) {
-    // > >= >> >>=
-    next = _reader.advance();
-    if (0x3D == next) {
-      _appendTokenOfType(TokenType.GT_EQ);
-      return _reader.advance();
-    } else if (0x3E == next) {
-      next = _reader.advance();
-      if (0x3D == next) {
-        _appendTokenOfType(TokenType.GT_GT_EQ);
-        return _reader.advance();
-      } else {
-        _appendTokenOfType(TokenType.GT_GT);
-        return next;
-      }
-    } else {
-      _appendTokenOfType(TokenType.GT);
-      return next;
-    }
-  }
-
-  int _tokenizeHex(int next) {
-    int start = _reader.offset - 1;
-    bool hasDigits = false;
-    while (true) {
-      next = _reader.advance();
-      if ((0x30 <= next && next <= 0x39) ||
-          (0x41 <= next && next <= 0x46) ||
-          (0x61 <= next && next <= 0x66)) {
-        hasDigits = true;
-      } else {
-        if (!hasDigits) {
-          _reportError(ScannerErrorCode.MISSING_HEX_DIGIT);
-        }
-        _appendStringToken(
-            TokenType.HEXADECIMAL, _reader.getString(start, next < 0 ? 0 : -1));
-        return next;
-      }
-    }
-  }
-
-  int _tokenizeHexOrNumber(int next) {
-    int x = _reader.peek();
-    if (x == 0x78 || x == 0x58) {
-      _reader.advance();
-      return _tokenizeHex(x);
-    }
-    return _tokenizeNumber(next);
-  }
-
-  int _tokenizeIdentifier(int next, int start, bool allowDollar) {
-    while ((0x61 <= next && next <= 0x7A) ||
-        (0x41 <= next && next <= 0x5A) ||
-        (0x30 <= next && next <= 0x39) ||
-        next == 0x5F ||
-        (next == 0x24 && allowDollar)) {
-      next = _reader.advance();
-    }
-    _appendStringToken(
-        TokenType.IDENTIFIER, _reader.getString(start, next < 0 ? 0 : -1));
-    return next;
-  }
-
-  int _tokenizeInterpolatedExpression(int next, int start) {
-    _appendBeginToken(TokenType.STRING_INTERPOLATION_EXPRESSION);
-    next = _reader.advance();
-    while (next != -1) {
-      if (next == 0x7D) {
-        BeginToken begin =
-            _findTokenMatchingClosingBraceInInterpolationExpression();
-        if (begin == null) {
-          _beginToken();
-          _appendTokenOfType(TokenType.CLOSE_CURLY_BRACKET);
-          next = _reader.advance();
-          _beginToken();
-          return next;
-        } else if (begin.type == TokenType.OPEN_CURLY_BRACKET) {
-          _beginToken();
-          _appendEndToken(
-              TokenType.CLOSE_CURLY_BRACKET, TokenType.OPEN_CURLY_BRACKET);
-          next = _reader.advance();
-          _beginToken();
-        } else if (begin.type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
-          _beginToken();
-          _appendEndToken(TokenType.CLOSE_CURLY_BRACKET,
-              TokenType.STRING_INTERPOLATION_EXPRESSION);
-          next = _reader.advance();
-          _beginToken();
-          return next;
-        }
-      } else {
-        next = bigSwitch(next);
-      }
-    }
-    return next;
-  }
-
-  int _tokenizeInterpolatedIdentifier(int next, int start) {
-    _appendStringTokenWithOffset(
-        TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 0);
-    if ((0x41 <= next && next <= 0x5A) ||
-        (0x61 <= next && next <= 0x7A) ||
-        next == 0x5F) {
-      _beginToken();
-      next = _tokenizeKeywordOrIdentifier(next, false);
-    }
-    _beginToken();
-    return next;
-  }
-
-  int _tokenizeKeywordOrIdentifier(int next, bool allowDollar) {
-    KeywordState state = KeywordState.KEYWORD_STATE;
-    int start = _reader.offset;
-    while (state != null && 0x61 <= next && next <= 0x7A) {
-      state = state.next(next);
-      next = _reader.advance();
-    }
-    if (state == null || state.keyword() == null) {
-      return _tokenizeIdentifier(next, start, allowDollar);
-    }
-    if ((0x41 <= next && next <= 0x5A) ||
-        (0x30 <= next && next <= 0x39) ||
-        next == 0x5F ||
-        next == 0x24) {
-      return _tokenizeIdentifier(next, start, allowDollar);
-    } else if (next < 128) {
-      _appendKeywordToken(state.keyword());
-      return next;
-    } else {
-      return _tokenizeIdentifier(next, start, allowDollar);
-    }
-  }
-
-  int _tokenizeLessThan(int next) {
-    // < <= << <<=
-    next = _reader.advance();
-    if (0x3D == next) {
-      _appendTokenOfType(TokenType.LT_EQ);
-      return _reader.advance();
-    } else if (0x3C == next) {
-      return _select(0x3D, TokenType.LT_LT_EQ, TokenType.LT_LT);
-    } else {
-      _appendTokenOfType(TokenType.LT);
-      return next;
-    }
-  }
-
-  int _tokenizeMinus(int next) {
-    // - -- -=
-    next = _reader.advance();
-    if (next == 0x2D) {
-      _appendTokenOfType(TokenType.MINUS_MINUS);
-      return _reader.advance();
-    } else if (next == 0x3D) {
-      _appendTokenOfType(TokenType.MINUS_EQ);
-      return _reader.advance();
-    } else {
-      _appendTokenOfType(TokenType.MINUS);
-      return next;
-    }
-  }
-
-  int _tokenizeMultiLineComment(int next) {
-    int nesting = 1;
-    next = _reader.advance();
-    while (true) {
-      if (-1 == next) {
-        _reportError(ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT);
-        _appendCommentToken(
-            TokenType.MULTI_LINE_COMMENT, _reader.getString(_tokenStart, 0));
-        return next;
-      } else if (0x2A == next) {
-        next = _reader.advance();
-        if (0x2F == next) {
-          --nesting;
-          if (0 == nesting) {
-            _appendCommentToken(TokenType.MULTI_LINE_COMMENT,
-                _reader.getString(_tokenStart, 0));
-            return _reader.advance();
-          } else {
-            next = _reader.advance();
-          }
-        }
-      } else if (0x2F == next) {
-        next = _reader.advance();
-        if (0x2A == next) {
-          next = _reader.advance();
-          ++nesting;
-        }
-      } else if (next == 0xD) {
-        next = _reader.advance();
-        if (next == 0xA) {
-          next = _reader.advance();
-        }
-        recordStartOfLine();
-      } else if (next == 0xA) {
-        next = _reader.advance();
-        recordStartOfLine();
-      } else {
-        next = _reader.advance();
-      }
-    }
-  }
-
-  int _tokenizeMultiLineRawString(int quoteChar, int start) {
-    int next = _reader.advance();
-    outer: while (next != -1) {
-      while (next != quoteChar) {
-        if (next == -1) {
-          break outer;
-        } else if (next == 0xD) {
-          next = _reader.advance();
-          if (next == 0xA) {
-            next = _reader.advance();
-          }
-          recordStartOfLine();
-        } else if (next == 0xA) {
-          next = _reader.advance();
-          recordStartOfLine();
-        } else {
-          next = _reader.advance();
-        }
-      }
-      next = _reader.advance();
-      if (next == quoteChar) {
-        next = _reader.advance();
-        if (next == quoteChar) {
-          _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
-          return _reader.advance();
-        }
-      }
-    }
-    _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
-    _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
-    return _reader.advance();
-  }
-
-  int _tokenizeMultiLineString(int quoteChar, int start, bool raw) {
-    if (raw) {
-      return _tokenizeMultiLineRawString(quoteChar, start);
-    }
-    int next = _reader.advance();
-    while (next != -1) {
-      if (next == 0x24) {
-        _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
-        next = _tokenizeStringInterpolation(start);
-        _beginToken();
-        start = _reader.offset;
-        continue;
-      }
-      if (next == quoteChar) {
-        next = _reader.advance();
-        if (next == quoteChar) {
-          next = _reader.advance();
-          if (next == quoteChar) {
-            _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
-            return _reader.advance();
-          }
-        }
-        continue;
-      }
-      if (next == 0x5C) {
-        next = _reader.advance();
-        if (next == -1) {
-          break;
-        }
-        if (next == 0xD) {
-          next = _reader.advance();
-          if (next == 0xA) {
-            next = _reader.advance();
-          }
-          recordStartOfLine();
-        } else if (next == 0xA) {
-          recordStartOfLine();
-          next = _reader.advance();
-        } else {
-          next = _reader.advance();
-        }
-      } else if (next == 0xD) {
-        next = _reader.advance();
-        if (next == 0xA) {
-          next = _reader.advance();
-        }
-        recordStartOfLine();
-      } else if (next == 0xA) {
-        recordStartOfLine();
-        next = _reader.advance();
-      } else {
-        next = _reader.advance();
-      }
-    }
-    _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
-    if (start == _reader.offset) {
-      _appendStringTokenWithOffset(TokenType.STRING, "", 1);
-    } else {
-      _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
-    }
-    return _reader.advance();
-  }
-
-  int _tokenizeMultiply(int next) =>
-      _select(0x3D, TokenType.STAR_EQ, TokenType.STAR);
-
-  int _tokenizeNumber(int next) {
-    int start = _reader.offset;
-    while (true) {
-      next = _reader.advance();
-      if (0x30 <= next && next <= 0x39) {
-        continue;
-      } else if (next == 0x2E) {
-        return _tokenizeFractionPart(_reader.advance(), start);
-      } else if (next == 0x65 || next == 0x45) {
-        return _tokenizeFractionPart(next, start);
-      } else {
-        _appendStringToken(
-            TokenType.INT, _reader.getString(start, next < 0 ? 0 : -1));
-        return next;
-      }
-    }
-  }
-
-  int _tokenizeOpenSquareBracket(int next) {
-    // [ []  []=
-    next = _reader.advance();
-    if (next == 0x5D) {
-      return _select(0x3D, TokenType.INDEX_EQ, TokenType.INDEX);
-    } else {
-      _appendBeginToken(TokenType.OPEN_SQUARE_BRACKET);
-      return next;
-    }
-  }
-
-  int _tokenizePercent(int next) =>
-      _select(0x3D, TokenType.PERCENT_EQ, TokenType.PERCENT);
-
-  int _tokenizePlus(int next) {
-    // + ++ +=
-    next = _reader.advance();
-    if (0x2B == next) {
-      _appendTokenOfType(TokenType.PLUS_PLUS);
-      return _reader.advance();
-    } else if (0x3D == next) {
-      _appendTokenOfType(TokenType.PLUS_EQ);
-      return _reader.advance();
-    } else {
-      _appendTokenOfType(TokenType.PLUS);
-      return next;
-    }
-  }
-
-  int _tokenizeQuestion() {
-    // ? ?. ?? ??=
-    int next = _reader.advance();
-    if (next == 0x2E) {
-      // '.'
-      _appendTokenOfType(TokenType.QUESTION_PERIOD);
-      return _reader.advance();
-    } else if (next == 0x3F) {
-      // '?'
-      next = _reader.advance();
-      if (next == 0x3D) {
-        // '='
-        _appendTokenOfType(TokenType.QUESTION_QUESTION_EQ);
-        return _reader.advance();
-      } else {
-        _appendTokenOfType(TokenType.QUESTION_QUESTION);
-        return next;
-      }
-    } else {
-      _appendTokenOfType(TokenType.QUESTION);
-      return next;
-    }
-  }
-
-  int _tokenizeSingleLineComment(int next) {
-    while (true) {
-      next = _reader.advance();
-      if (-1 == next) {
-        _appendCommentToken(
-            TokenType.SINGLE_LINE_COMMENT, _reader.getString(_tokenStart, 0));
-        return next;
-      } else if (0xA == next || 0xD == next) {
-        _appendCommentToken(
-            TokenType.SINGLE_LINE_COMMENT, _reader.getString(_tokenStart, -1));
-        return next;
-      }
-    }
-  }
-
-  int _tokenizeSingleLineRawString(int next, int quoteChar, int start) {
-    next = _reader.advance();
-    while (next != -1) {
-      if (next == quoteChar) {
-        _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
-        return _reader.advance();
-      } else if (next == 0xD || next == 0xA) {
-        _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
-        _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
-        return _reader.advance();
-      }
-      next = _reader.advance();
-    }
-    _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
-    _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
-    return _reader.advance();
-  }
-
-  int _tokenizeSingleLineString(int next, int quoteChar, int start) {
-    while (next != quoteChar) {
-      if (next == 0x5C) {
-        next = _reader.advance();
-      } else if (next == 0x24) {
-        _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
-        next = _tokenizeStringInterpolation(start);
-        _beginToken();
-        start = _reader.offset;
-        continue;
-      }
-      if (next <= 0xD && (next == 0xA || next == 0xD || next == -1)) {
-        _reportError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL);
-        if (start == _reader.offset) {
-          _appendStringTokenWithOffset(TokenType.STRING, "", 1);
-        } else if (next == -1) {
-          _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
-        } else {
-          _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
-        }
-        return _reader.advance();
-      }
-      next = _reader.advance();
-    }
-    _appendStringToken(TokenType.STRING, _reader.getString(start, 0));
-    return _reader.advance();
-  }
-
-  int _tokenizeSlashOrComment(int next) {
-    next = _reader.advance();
-    if (0x2A == next) {
-      return _tokenizeMultiLineComment(next);
-    } else if (0x2F == next) {
-      return _tokenizeSingleLineComment(next);
-    } else if (0x3D == next) {
-      _appendTokenOfType(TokenType.SLASH_EQ);
-      return _reader.advance();
-    } else {
-      _appendTokenOfType(TokenType.SLASH);
-      return next;
-    }
-  }
-
-  int _tokenizeString(int next, int start, bool raw) {
-    int quoteChar = next;
-    next = _reader.advance();
-    if (quoteChar == next) {
-      next = _reader.advance();
-      if (quoteChar == next) {
-        // Multiline string.
-        return _tokenizeMultiLineString(quoteChar, start, raw);
-      } else {
-        // Empty string.
-        _appendStringToken(TokenType.STRING, _reader.getString(start, -1));
-        return next;
-      }
-    }
-    if (raw) {
-      return _tokenizeSingleLineRawString(next, quoteChar, start);
-    } else {
-      return _tokenizeSingleLineString(next, quoteChar, start);
-    }
-  }
-
-  int _tokenizeStringInterpolation(int start) {
-    _beginToken();
-    int next = _reader.advance();
-    if (next == 0x7B) {
-      return _tokenizeInterpolatedExpression(next, start);
-    } else {
-      return _tokenizeInterpolatedIdentifier(next, start);
-    }
-  }
-
-  int _tokenizeTag(int next) {
-    // # or #!.*[\n\r]
-    if (_reader.offset == 0) {
-      if (_reader.peek() == 0x21) {
-        do {
-          next = _reader.advance();
-        } while (next != 0xA && next != 0xD && next > 0);
-        _appendStringToken(
-            TokenType.SCRIPT_TAG, _reader.getString(_tokenStart, 0));
-        return next;
-      }
-    }
-    _appendTokenOfType(TokenType.HASH);
-    return _reader.advance();
-  }
-
-  int _tokenizeTilde(int next) {
-    // ~ ~/ ~/=
-    next = _reader.advance();
-    if (next == 0x2F) {
-      return _select(0x3D, TokenType.TILDE_SLASH_EQ, TokenType.TILDE_SLASH);
-    } else {
-      _appendTokenOfType(TokenType.TILDE);
-      return next;
-    }
-  }
-
-  /**
-   * Checks if [value] is a single-line or multi-line comment.
-   */
-  static bool _isDocumentationComment(String value) {
-    return StringUtilities.startsWith3(value, 0, 0x2F, 0x2F, 0x2F) ||
-        StringUtilities.startsWith3(value, 0, 0x2F, 0x2A, 0x2A);
-  }
-}
-
-/**
- * The error codes used for errors detected by the scanner.
- */
-class ScannerErrorCode extends ErrorCode {
-  static const ScannerErrorCode ILLEGAL_CHARACTER =
-      const ScannerErrorCode('ILLEGAL_CHARACTER', "Illegal character {0}");
-
-  static const ScannerErrorCode MISSING_DIGIT =
-      const ScannerErrorCode('MISSING_DIGIT', "Decimal digit expected");
-
-  static const ScannerErrorCode MISSING_HEX_DIGIT =
-      const ScannerErrorCode('MISSING_HEX_DIGIT', "Hexidecimal digit expected");
-
-  static const ScannerErrorCode MISSING_QUOTE =
-      const ScannerErrorCode('MISSING_QUOTE', "Expected quote (' or \")");
-
-  static const ScannerErrorCode UNABLE_GET_CONTENT = const ScannerErrorCode(
-      'UNABLE_GET_CONTENT', "Unable to get content: {0}");
-
-  static const ScannerErrorCode UNTERMINATED_MULTI_LINE_COMMENT =
-      const ScannerErrorCode(
-          'UNTERMINATED_MULTI_LINE_COMMENT', "Unterminated multi-line comment");
-
-  static const ScannerErrorCode UNTERMINATED_STRING_LITERAL =
-      const ScannerErrorCode(
-          'UNTERMINATED_STRING_LITERAL', "Unterminated string literal");
-
-  /**
-   * Initialize a newly created error code to have the given [name]. The message
-   * associated with the error will be created from the given [message]
-   * template. The correction associated with the error will be created from the
-   * given [correction] template.
-   */
-  const ScannerErrorCode(String name, String message, [String correction])
-      : super(name, message, correction);
-
-  @override
-  ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
-
-  @override
-  ErrorType get type => ErrorType.SYNTACTIC_ERROR;
-}
-
-/**
- * A token whose value is independent of it's type.
- */
-class StringToken extends Token {
-  /**
-   * The lexeme represented by this token.
-   */
-  String _value;
-
-  /**
-   * Initialize a newly created token to represent a token of the given [type]
-   * with the given [value] at the given [offset].
-   */
-  StringToken(TokenType type, String value, int offset) : super(type, offset) {
-    this._value = StringUtilities.intern(value);
-  }
-
-  @override
-  String get lexeme => _value;
-
-  @override
-  Token copy() => new StringToken(type, _value, offset);
-
-  @override
-  String value() => _value;
-}
-
-/**
- * A string token that is preceded by comments.
- */
-class StringTokenWithComment extends StringToken {
-  /**
-   * The first comment in the list of comments that precede this token.
-   */
-  CommentToken _precedingComment;
-
-  /**
-   * Initialize a newly created token to have the given [type] at the given
-   * [offset] and to be preceded by the comments reachable from the given
-   * [comment].
-   */
-  StringTokenWithComment(
-      TokenType type, String value, int offset, this._precedingComment)
-      : super(type, value, offset) {
-    _setCommentParent(_precedingComment);
-  }
-
-  CommentToken get precedingComments => _precedingComment;
-
-  void set precedingComments(CommentToken comment) {
-    _precedingComment = comment;
-    _setCommentParent(_precedingComment);
-  }
-
-  @override
-  void applyDelta(int delta) {
-    super.applyDelta(delta);
-    Token token = precedingComments;
-    while (token != null) {
-      token.applyDelta(delta);
-      token = token.next;
-    }
-  }
-
-  @override
-  Token copy() => new StringTokenWithComment(
-      type, lexeme, offset, copyComments(precedingComments));
-}
-
-/**
- * A [CharacterReader] that reads characters from a character sequence, but adds
- * a delta when reporting the current character offset so that the character
- * sequence can be a subsequence from a larger sequence.
- */
-class SubSequenceReader extends CharSequenceReader {
-  /**
-   * The offset from the beginning of the file to the beginning of the source
-   * being scanned.
-   */
-  final int _offsetDelta;
-
-  /**
-   * Initialize a newly created reader to read the characters in the given
-   * [sequence]. The [_offsetDelta] is the offset from the beginning of the file
-   * to the beginning of the source being scanned
-   */
-  SubSequenceReader(String sequence, this._offsetDelta) : super(sequence);
-
-  @override
-  int get offset => _offsetDelta + super.offset;
-
-  @override
-  void set offset(int offset) {
-    super.offset = offset - _offsetDelta;
-  }
-
-  @override
-  String getString(int start, int endDelta) =>
-      super.getString(start - _offsetDelta, endDelta);
-}
-
-/**
- * A token whose value is independent of it's type.
- */
-class SyntheticStringToken extends StringToken {
-  /**
-   * Initialize a newly created token to represent a token of the given [type]
-   * with the given [value] at the given [offset].
-   */
-  SyntheticStringToken(TokenType type, String value, int offset)
-      : super(type, value, offset);
-
-  @override
-  bool get isSynthetic => true;
-}
-
-/**
- * A token that was scanned from the input. Each token knows which tokens
- * precede and follow it, acting as a link in a doubly linked list of tokens.
- */
-class Token {
-  /**
-   * The type of the token.
-   */
-  final TokenType type;
-
-  /**
-   * The offset from the beginning of the file to the first character in the
-   * token.
-   */
-  int offset = 0;
-
-  /**
-   * The previous token in the token stream.
-   */
-  Token previous;
-
-  /**
-   * The next token in the token stream.
-   */
-  Token _next;
-
-  /**
-   * Initialize a newly created token to have the given [type] and [offset].
-   */
-  Token(this.type, this.offset);
-
-  /**
-   * Return the offset from the beginning of the file to the character after the
-   * last character of the token.
-   */
-  int get end => offset + length;
-
-  /**
-   * Return `true` if this token represents an operator.
-   */
-  bool get isOperator => type.isOperator;
-
-  /**
-   * Return `true` if this token is a synthetic token. A synthetic token is a
-   * token that was introduced by the parser in order to recover from an error
-   * in the code.
-   */
-  bool get isSynthetic => length == 0;
-
-  /**
-   * Return `true` if this token represents an operator that can be defined by
-   * users.
-   */
-  bool get isUserDefinableOperator => type.isUserDefinableOperator;
-
-  /**
-   * Return the number of characters in the node's source range.
-   */
-  int get length => lexeme.length;
-
-  /**
-   * Return the lexeme that represents this token.
-   */
-  String get lexeme => type.lexeme;
-
-  /**
-   * Return the next token in the token stream.
-   */
-  Token get next => _next;
-
-  /**
-   * Return the first comment in the list of comments that precede this token,
-   * or `null` if there are no comments preceding this token. Additional
-   * comments can be reached by following the token stream using [next] until
-   * `null` is returned.
-   *
-   * For example, if the original contents were `/* one */ /* two */ id`, then
-   * the first preceding comment token will have a lexeme of `/* one */` and
-   * the next comment token will have a lexeme of `/* two */`.
-   */
-  CommentToken get precedingComments => null;
-
-  /**
-   * Apply (add) the given [delta] to this token's offset.
-   */
-  void applyDelta(int delta) {
-    offset += delta;
-  }
-
-  /**
-   * Return a newly created token that is a copy of this token but that is not a
-   * part of any token stream.
-   */
-  Token copy() => new Token(type, offset);
-
-  /**
-   * Copy a linked list of comment tokens identical to the given comment tokens.
-   */
-  Token copyComments(Token token) {
-    if (token == null) {
-      return null;
-    }
-    Token head = token.copy();
-    Token tail = head;
-    token = token.next;
-    while (token != null) {
-      tail = tail.setNext(token.copy());
-      token = token.next;
-    }
-    return head;
-  }
-
-  /**
-   * Return `true` if this token has any one of the given [types].
-   */
-  bool matchesAny(List<TokenType> types) {
-    for (TokenType type in types) {
-      if (this.type == type) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Set the next token in the token stream to the given [token]. This has the
-   * side-effect of setting this token to be the previous token for the given
-   * token. Return the token that was passed in.
-   */
-  Token setNext(Token token) {
-    _next = token;
-    token.previous = this;
-    return token;
-  }
-
-  /**
-   * Set the next token in the token stream to the given token without changing
-   * which token is the previous token for the given token. Return the token
-   * that was passed in.
-   */
-  Token setNextWithoutSettingPrevious(Token token) {
-    _next = token;
-    return token;
-  }
-
-  @override
-  String toString() => lexeme;
-
-  /**
-   * Return the value of this token. For keyword tokens, this is the keyword
-   * associated with the token, for other tokens it is the lexeme associated
-   * with the token.
-   */
-  Object value() => type.lexeme;
-
-  /**
-   * Sets the `parent` property to `this` for the given [comment] and all the
-   * next tokens.
-   */
-  void _setCommentParent(CommentToken comment) {
-    while (comment != null) {
-      comment.parent = this;
-      comment = comment.next;
-    }
-  }
-
-  /**
-   * Compare the given [tokens] to find the token that appears first in the
-   * source being parsed. That is, return the left-most of all of the tokens.
-   * The list must be non-`null`, but the elements of the list are allowed to be
-   * `null`. Return the token with the smallest offset, or `null` if the list is
-   * empty or if all of the elements of the list are `null`.
-   */
-  static Token lexicallyFirst(List<Token> tokens) {
-    Token first = null;
-    int offset = -1;
-    for (Token token in tokens) {
-      if (token != null && (offset < 0 || token.offset < offset)) {
-        first = token;
-        offset = token.offset;
-      }
-    }
-    return first;
-  }
-}
-
-/**
- * The classes (or groups) of tokens with a similar use.
- */
-class TokenClass {
-  /**
-   * A value used to indicate that the token type is not part of any specific
-   * class of token.
-   */
-  static const TokenClass NO_CLASS = const TokenClass('NO_CLASS');
-
-  /**
-   * A value used to indicate that the token type is an additive operator.
-   */
-  static const TokenClass ADDITIVE_OPERATOR =
-      const TokenClass('ADDITIVE_OPERATOR', 13);
-
-  /**
-   * A value used to indicate that the token type is an assignment operator.
-   */
-  static const TokenClass ASSIGNMENT_OPERATOR =
-      const TokenClass('ASSIGNMENT_OPERATOR', 1);
-
-  /**
-   * A value used to indicate that the token type is a bitwise-and operator.
-   */
-  static const TokenClass BITWISE_AND_OPERATOR =
-      const TokenClass('BITWISE_AND_OPERATOR', 11);
-
-  /**
-   * A value used to indicate that the token type is a bitwise-or operator.
-   */
-  static const TokenClass BITWISE_OR_OPERATOR =
-      const TokenClass('BITWISE_OR_OPERATOR', 9);
-
-  /**
-   * A value used to indicate that the token type is a bitwise-xor operator.
-   */
-  static const TokenClass BITWISE_XOR_OPERATOR =
-      const TokenClass('BITWISE_XOR_OPERATOR', 10);
-
-  /**
-   * A value used to indicate that the token type is a cascade operator.
-   */
-  static const TokenClass CASCADE_OPERATOR =
-      const TokenClass('CASCADE_OPERATOR', 2);
-
-  /**
-   * A value used to indicate that the token type is a conditional operator.
-   */
-  static const TokenClass CONDITIONAL_OPERATOR =
-      const TokenClass('CONDITIONAL_OPERATOR', 3);
-
-  /**
-   * A value used to indicate that the token type is an equality operator.
-   */
-  static const TokenClass EQUALITY_OPERATOR =
-      const TokenClass('EQUALITY_OPERATOR', 7);
-
-  /**
-   * A value used to indicate that the token type is an if-null operator.
-   */
-  static const TokenClass IF_NULL_OPERATOR =
-      const TokenClass('IF_NULL_OPERATOR', 4);
-
-  /**
-   * A value used to indicate that the token type is a logical-and operator.
-   */
-  static const TokenClass LOGICAL_AND_OPERATOR =
-      const TokenClass('LOGICAL_AND_OPERATOR', 6);
-
-  /**
-   * A value used to indicate that the token type is a logical-or operator.
-   */
-  static const TokenClass LOGICAL_OR_OPERATOR =
-      const TokenClass('LOGICAL_OR_OPERATOR', 5);
-
-  /**
-   * A value used to indicate that the token type is a multiplicative operator.
-   */
-  static const TokenClass MULTIPLICATIVE_OPERATOR =
-      const TokenClass('MULTIPLICATIVE_OPERATOR', 14);
-
-  /**
-   * A value used to indicate that the token type is a relational operator.
-   */
-  static const TokenClass RELATIONAL_OPERATOR =
-      const TokenClass('RELATIONAL_OPERATOR', 8);
-
-  /**
-   * A value used to indicate that the token type is a shift operator.
-   */
-  static const TokenClass SHIFT_OPERATOR =
-      const TokenClass('SHIFT_OPERATOR', 12);
-
-  /**
-   * A value used to indicate that the token type is a unary operator.
-   */
-  static const TokenClass UNARY_POSTFIX_OPERATOR =
-      const TokenClass('UNARY_POSTFIX_OPERATOR', 16);
-
-  /**
-   * A value used to indicate that the token type is a unary operator.
-   */
-  static const TokenClass UNARY_PREFIX_OPERATOR =
-      const TokenClass('UNARY_PREFIX_OPERATOR', 15);
-
-  /**
-   * The name of the token class.
-   */
-  final String name;
-
-  /**
-   * The precedence of tokens of this class, or `0` if the such tokens do not
-   * represent an operator.
-   */
-  final int precedence;
-
-  const TokenClass(this.name, [this.precedence = 0]);
-
-  @override
-  String toString() => name;
-}
-
-/**
- * The types of tokens that can be returned by the scanner.
- */
-class TokenType {
-  /**
-   * The type of the token that marks the end of the input.
-   */
-  static const TokenType EOF = const TokenType_EOF('EOF');
-
-  static const TokenType DOUBLE = const TokenType('DOUBLE');
-
-  static const TokenType HEXADECIMAL = const TokenType('HEXADECIMAL');
-
-  static const TokenType IDENTIFIER = const TokenType('IDENTIFIER');
-
-  static const TokenType INT = const TokenType('INT');
-
-  static const TokenType KEYWORD = const TokenType('KEYWORD');
-
-  static const TokenType MULTI_LINE_COMMENT =
-      const TokenType('MULTI_LINE_COMMENT');
-
-  static const TokenType SCRIPT_TAG = const TokenType('SCRIPT_TAG');
-
-  static const TokenType SINGLE_LINE_COMMENT =
-      const TokenType('SINGLE_LINE_COMMENT');
-
-  static const TokenType STRING = const TokenType('STRING');
-
-  static const TokenType AMPERSAND =
-      const TokenType('AMPERSAND', TokenClass.BITWISE_AND_OPERATOR, "&");
-
-  static const TokenType AMPERSAND_AMPERSAND = const TokenType(
-      'AMPERSAND_AMPERSAND', TokenClass.LOGICAL_AND_OPERATOR, "&&");
-
-  static const TokenType AMPERSAND_EQ =
-      const TokenType('AMPERSAND_EQ', TokenClass.ASSIGNMENT_OPERATOR, "&=");
-
-  static const TokenType AT = const TokenType('AT', TokenClass.NO_CLASS, "@");
-
-  static const TokenType BANG =
-      const TokenType('BANG', TokenClass.UNARY_PREFIX_OPERATOR, "!");
-
-  static const TokenType BANG_EQ =
-      const TokenType('BANG_EQ', TokenClass.EQUALITY_OPERATOR, "!=");
-
-  static const TokenType BAR =
-      const TokenType('BAR', TokenClass.BITWISE_OR_OPERATOR, "|");
-
-  static const TokenType BAR_BAR =
-      const TokenType('BAR_BAR', TokenClass.LOGICAL_OR_OPERATOR, "||");
-
-  static const TokenType BAR_EQ =
-      const TokenType('BAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, "|=");
-
-  static const TokenType COLON =
-      const TokenType('COLON', TokenClass.NO_CLASS, ":");
-
-  static const TokenType COMMA =
-      const TokenType('COMMA', TokenClass.NO_CLASS, ",");
-
-  static const TokenType CARET =
-      const TokenType('CARET', TokenClass.BITWISE_XOR_OPERATOR, "^");
-
-  static const TokenType CARET_EQ =
-      const TokenType('CARET_EQ', TokenClass.ASSIGNMENT_OPERATOR, "^=");
-
-  static const TokenType CLOSE_CURLY_BRACKET =
-      const TokenType('CLOSE_CURLY_BRACKET', TokenClass.NO_CLASS, "}");
-
-  static const TokenType CLOSE_PAREN =
-      const TokenType('CLOSE_PAREN', TokenClass.NO_CLASS, ")");
-
-  static const TokenType CLOSE_SQUARE_BRACKET =
-      const TokenType('CLOSE_SQUARE_BRACKET', TokenClass.NO_CLASS, "]");
-
-  static const TokenType EQ =
-      const TokenType('EQ', TokenClass.ASSIGNMENT_OPERATOR, "=");
-
-  static const TokenType EQ_EQ =
-      const TokenType('EQ_EQ', TokenClass.EQUALITY_OPERATOR, "==");
-
-  static const TokenType FUNCTION =
-      const TokenType('FUNCTION', TokenClass.NO_CLASS, "=>");
-
-  static const TokenType GT =
-      const TokenType('GT', TokenClass.RELATIONAL_OPERATOR, ">");
-
-  static const TokenType GT_EQ =
-      const TokenType('GT_EQ', TokenClass.RELATIONAL_OPERATOR, ">=");
-
-  static const TokenType GT_GT =
-      const TokenType('GT_GT', TokenClass.SHIFT_OPERATOR, ">>");
-
-  static const TokenType GT_GT_EQ =
-      const TokenType('GT_GT_EQ', TokenClass.ASSIGNMENT_OPERATOR, ">>=");
-
-  static const TokenType HASH =
-      const TokenType('HASH', TokenClass.NO_CLASS, "#");
-
-  static const TokenType INDEX =
-      const TokenType('INDEX', TokenClass.UNARY_POSTFIX_OPERATOR, "[]");
-
-  static const TokenType INDEX_EQ =
-      const TokenType('INDEX_EQ', TokenClass.UNARY_POSTFIX_OPERATOR, "[]=");
-
-  static const TokenType IS =
-      const TokenType('IS', TokenClass.RELATIONAL_OPERATOR, "is");
-
-  static const TokenType LT =
-      const TokenType('LT', TokenClass.RELATIONAL_OPERATOR, "<");
-
-  static const TokenType LT_EQ =
-      const TokenType('LT_EQ', TokenClass.RELATIONAL_OPERATOR, "<=");
-
-  static const TokenType LT_LT =
-      const TokenType('LT_LT', TokenClass.SHIFT_OPERATOR, "<<");
-
-  static const TokenType LT_LT_EQ =
-      const TokenType('LT_LT_EQ', TokenClass.ASSIGNMENT_OPERATOR, "<<=");
-
-  static const TokenType MINUS =
-      const TokenType('MINUS', TokenClass.ADDITIVE_OPERATOR, "-");
-
-  static const TokenType MINUS_EQ =
-      const TokenType('MINUS_EQ', TokenClass.ASSIGNMENT_OPERATOR, "-=");
-
-  static const TokenType MINUS_MINUS =
-      const TokenType('MINUS_MINUS', TokenClass.UNARY_PREFIX_OPERATOR, "--");
-
-  static const TokenType OPEN_CURLY_BRACKET =
-      const TokenType('OPEN_CURLY_BRACKET', TokenClass.NO_CLASS, "{");
-
-  static const TokenType OPEN_PAREN =
-      const TokenType('OPEN_PAREN', TokenClass.UNARY_POSTFIX_OPERATOR, "(");
-
-  static const TokenType OPEN_SQUARE_BRACKET = const TokenType(
-      'OPEN_SQUARE_BRACKET', TokenClass.UNARY_POSTFIX_OPERATOR, "[");
-
-  static const TokenType PERCENT =
-      const TokenType('PERCENT', TokenClass.MULTIPLICATIVE_OPERATOR, "%");
-
-  static const TokenType PERCENT_EQ =
-      const TokenType('PERCENT_EQ', TokenClass.ASSIGNMENT_OPERATOR, "%=");
-
-  static const TokenType PERIOD =
-      const TokenType('PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, ".");
-
-  static const TokenType PERIOD_PERIOD =
-      const TokenType('PERIOD_PERIOD', TokenClass.CASCADE_OPERATOR, "..");
-
-  static const TokenType PLUS =
-      const TokenType('PLUS', TokenClass.ADDITIVE_OPERATOR, "+");
-
-  static const TokenType PLUS_EQ =
-      const TokenType('PLUS_EQ', TokenClass.ASSIGNMENT_OPERATOR, "+=");
-
-  static const TokenType PLUS_PLUS =
-      const TokenType('PLUS_PLUS', TokenClass.UNARY_PREFIX_OPERATOR, "++");
-
-  static const TokenType QUESTION =
-      const TokenType('QUESTION', TokenClass.CONDITIONAL_OPERATOR, "?");
-
-  static const TokenType QUESTION_PERIOD = const TokenType(
-      'QUESTION_PERIOD', TokenClass.UNARY_POSTFIX_OPERATOR, '?.');
-
-  static const TokenType QUESTION_QUESTION =
-      const TokenType('QUESTION_QUESTION', TokenClass.IF_NULL_OPERATOR, '??');
-
-  static const TokenType QUESTION_QUESTION_EQ = const TokenType(
-      'QUESTION_QUESTION_EQ', TokenClass.ASSIGNMENT_OPERATOR, '??=');
-
-  static const TokenType SEMICOLON =
-      const TokenType('SEMICOLON', TokenClass.NO_CLASS, ";");
-
-  static const TokenType SLASH =
-      const TokenType('SLASH', TokenClass.MULTIPLICATIVE_OPERATOR, "/");
-
-  static const TokenType SLASH_EQ =
-      const TokenType('SLASH_EQ', TokenClass.ASSIGNMENT_OPERATOR, "/=");
-
-  static const TokenType STAR =
-      const TokenType('STAR', TokenClass.MULTIPLICATIVE_OPERATOR, "*");
-
-  static const TokenType STAR_EQ =
-      const TokenType('STAR_EQ', TokenClass.ASSIGNMENT_OPERATOR, "*=");
-
-  static const TokenType STRING_INTERPOLATION_EXPRESSION = const TokenType(
-      'STRING_INTERPOLATION_EXPRESSION', TokenClass.NO_CLASS, "\${");
-
-  static const TokenType STRING_INTERPOLATION_IDENTIFIER = const TokenType(
-      'STRING_INTERPOLATION_IDENTIFIER', TokenClass.NO_CLASS, "\$");
-
-  static const TokenType TILDE =
-      const TokenType('TILDE', TokenClass.UNARY_PREFIX_OPERATOR, "~");
-
-  static const TokenType TILDE_SLASH =
-      const TokenType('TILDE_SLASH', TokenClass.MULTIPLICATIVE_OPERATOR, "~/");
-
-  static const TokenType TILDE_SLASH_EQ =
-      const TokenType('TILDE_SLASH_EQ', TokenClass.ASSIGNMENT_OPERATOR, "~/=");
-
-  static const TokenType BACKPING =
-      const TokenType('BACKPING', TokenClass.NO_CLASS, "`");
-
-  static const TokenType BACKSLASH =
-      const TokenType('BACKSLASH', TokenClass.NO_CLASS, "\\");
-
-  static const TokenType PERIOD_PERIOD_PERIOD =
-      const TokenType('PERIOD_PERIOD_PERIOD', TokenClass.NO_CLASS, "...");
-
-  static const TokenType GENERIC_METHOD_TYPE_LIST =
-      const TokenType('GENERIC_METHOD_TYPE_LIST');
-
-  static const TokenType GENERIC_METHOD_TYPE_ASSIGN =
-      const TokenType('GENERIC_METHOD_TYPE_ASSIGN');
-
-  /**
-   * The class of the token.
-   */
-  final TokenClass _tokenClass;
-
-  /**
-   * The name of the token type.
-   */
-  final String name;
-
-  /**
-   * The lexeme that defines this type of token, or `null` if there is more than
-   * one possible lexeme for this type of token.
-   */
-  final String lexeme;
-
-  const TokenType(this.name,
-      [this._tokenClass = TokenClass.NO_CLASS, this.lexeme = null]);
-
-  /**
-   * Return `true` if this type of token represents an additive operator.
-   */
-  bool get isAdditiveOperator => _tokenClass == TokenClass.ADDITIVE_OPERATOR;
-
-  /**
-   * Return `true` if this type of token represents an assignment operator.
-   */
-  bool get isAssignmentOperator =>
-      _tokenClass == TokenClass.ASSIGNMENT_OPERATOR;
-
-  /**
-   * Return `true` if this type of token represents an associative operator. An
-   * associative operator is an operator for which the following equality is
-   * true: `(a * b) * c == a * (b * c)`. In other words, if the result of
-   * applying the operator to multiple operands does not depend on the order in
-   * which those applications occur.
-   *
-   * Note: This method considers the logical-and and logical-or operators to be
-   * associative, even though the order in which the application of those
-   * operators can have an effect because evaluation of the right-hand operand
-   * is conditional.
-   */
-  bool get isAssociativeOperator => this == AMPERSAND ||
-      this == AMPERSAND_AMPERSAND ||
-      this == BAR ||
-      this == BAR_BAR ||
-      this == CARET ||
-      this == PLUS ||
-      this == STAR;
-
-  /**
-   * Return `true` if this type of token represents an equality operator.
-   */
-  bool get isEqualityOperator => _tokenClass == TokenClass.EQUALITY_OPERATOR;
-
-  /**
-   * Return `true` if this type of token represents an increment operator.
-   */
-  bool get isIncrementOperator =>
-      identical(lexeme, "++") || identical(lexeme, "--");
-
-  /**
-   * Return `true` if this type of token represents a multiplicative operator.
-   */
-  bool get isMultiplicativeOperator =>
-      _tokenClass == TokenClass.MULTIPLICATIVE_OPERATOR;
-
-  /**
-   * Return `true` if this token type represents an operator.
-   */
-  bool get isOperator => _tokenClass != TokenClass.NO_CLASS &&
-      this != OPEN_PAREN &&
-      this != OPEN_SQUARE_BRACKET &&
-      this != PERIOD;
-
-  /**
-   * Return `true` if this type of token represents a relational operator.
-   */
-  bool get isRelationalOperator =>
-      _tokenClass == TokenClass.RELATIONAL_OPERATOR;
-
-  /**
-   * Return `true` if this type of token represents a shift operator.
-   */
-  bool get isShiftOperator => _tokenClass == TokenClass.SHIFT_OPERATOR;
-
-  /**
-   * Return `true` if this type of token represents a unary postfix operator.
-   */
-  bool get isUnaryPostfixOperator =>
-      _tokenClass == TokenClass.UNARY_POSTFIX_OPERATOR;
-
-  /**
-   * Return `true` if this type of token represents a unary prefix operator.
-   */
-  bool get isUnaryPrefixOperator =>
-      _tokenClass == TokenClass.UNARY_PREFIX_OPERATOR;
-
-  /**
-   * Return `true` if this token type represents an operator that can be defined
-   * by users.
-   */
-  bool get isUserDefinableOperator => identical(lexeme, "==") ||
-      identical(lexeme, "~") ||
-      identical(lexeme, "[]") ||
-      identical(lexeme, "[]=") ||
-      identical(lexeme, "*") ||
-      identical(lexeme, "/") ||
-      identical(lexeme, "%") ||
-      identical(lexeme, "~/") ||
-      identical(lexeme, "+") ||
-      identical(lexeme, "-") ||
-      identical(lexeme, "<<") ||
-      identical(lexeme, ">>") ||
-      identical(lexeme, ">=") ||
-      identical(lexeme, ">") ||
-      identical(lexeme, "<=") ||
-      identical(lexeme, "<") ||
-      identical(lexeme, "&") ||
-      identical(lexeme, "^") ||
-      identical(lexeme, "|");
-
-  /**
-   * Return the precedence of the token, or `0` if the token does not represent
-   * an operator.
-   */
-  int get precedence => _tokenClass.precedence;
-
-  @override
-  String toString() => name;
-}
-
-class TokenType_EOF extends TokenType {
-  const TokenType_EOF(String name) : super(name, TokenClass.NO_CLASS, "");
-
-  @override
-  String toString() => "-eof-";
-}
-
-/**
- * A normal token that is preceded by comments.
- */
-class TokenWithComment extends Token {
-  /**
-   * The first comment in the list of comments that precede this token.
-   */
-  CommentToken _precedingComment;
-
-  /**
-   * Initialize a newly created token to have the given [type] at the given
-   * [offset] and to be preceded by the comments reachable from the given
-   * [comment].
-   */
-  TokenWithComment(TokenType type, int offset, this._precedingComment)
-      : super(type, offset) {
-    _setCommentParent(_precedingComment);
-  }
-
-  CommentToken get precedingComments => _precedingComment;
-
-  void set precedingComments(CommentToken comment) {
-    _precedingComment = comment;
-    _setCommentParent(_precedingComment);
-  }
-
-  @override
-  Token copy() => new TokenWithComment(type, offset, precedingComments);
-}
+export 'package:analyzer/dart/ast/token.dart';
+export 'package:analyzer/src/dart/ast/token.dart' hide SimpleToken;
+export 'package:analyzer/src/dart/scanner/scanner.dart';
+export 'package:analyzer/src/dart/scanner/reader.dart';
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index 4c756e2..0670b7c 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -6,35 +6,42 @@
 
 import 'dart:collection';
 
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/src/generated/engine.dart'
+    show AnalysisContext, AnalysisOptions;
 import 'package:analyzer/src/generated/source.dart'
     show ContentCache, Source, UriKind;
 
 /**
+ * A function used to create a new DartSdk
+ */
+typedef DartSdk SdkCreator();
+
+/**
  * A Dart SDK installed in a specified location.
  */
 abstract class DartSdk {
   /**
    * The short name of the dart SDK 'async' library.
    */
-  static final String DART_ASYNC = "dart:async";
+  static const String DART_ASYNC = "dart:async";
 
   /**
    * The short name of the dart SDK 'core' library.
    */
-  static final String DART_CORE = "dart:core";
+  static const String DART_CORE = "dart:core";
 
   /**
    * The short name of the dart SDK 'html' library.
    */
-  static final String DART_HTML = "dart:html";
+  static const String DART_HTML = "dart:html";
 
   /**
    * The version number that is returned when the real version number could not
    * be determined.
    */
-  static final String DEFAULT_VERSION = "0";
+  static const String DEFAULT_VERSION = "0";
 
   /**
    * Return the analysis context used for all of the sources in this [DartSdk].
@@ -78,6 +85,56 @@
 }
 
 /**
+ * Manages the DartSdk's that have been created. Clients need to create multiple
+ * SDKs when the analysis options associated with those SDK's contexts will
+ * produce different analysis results.
+ */
+class DartSdkManager {
+  /**
+   * The function used to create new SDK's.
+   */
+  final SdkCreator sdkCreator;
+
+  /**
+   * A table mapping (an encoding of) analysis options to the SDK that has been
+   * configured with those options.
+   */
+  Map<int, DartSdk> sdkMap = new HashMap<int, DartSdk>();
+
+  /**
+   * Initialize a newly created manager.
+   */
+  DartSdkManager(this.sdkCreator);
+
+  /**
+   * Return any SDK that has been created, or `null` if no SDKs have been
+   * created.
+   */
+  DartSdk get anySdk {
+    if (sdkMap.isEmpty) {
+      return null;
+    }
+    return sdkMap.values.first;
+  }
+
+  /**
+   * Return the Dart SDK that is appropriate for the given analysis [options].
+   * If such an SDK has not yet been created, then the [sdkCreator] will be
+   * invoked to create it.
+   */
+  DartSdk getSdkForOptions(AnalysisOptions options) {
+    int encoding = options.encodeCrossContextOptions();
+    DartSdk sdk = sdkMap[encoding];
+    if (sdk == null) {
+      sdk = sdkCreator();
+      sdkMap[encoding] = sdk;
+      sdk.context.analysisOptions.setCrossContextOptionsFrom(options);
+    }
+    return sdk;
+  }
+}
+
+/**
  * A map from Dart library URI's to the [SdkLibraryImpl] representing that
  * library.
  */
@@ -85,8 +142,8 @@
   /**
    * A table mapping Dart library URI's to the library.
    */
-  HashMap<String, SdkLibraryImpl> _libraryMap =
-      new HashMap<String, SdkLibraryImpl>();
+  LinkedHashMap<String, SdkLibraryImpl> _libraryMap =
+      new LinkedHashMap<String, SdkLibraryImpl>();
 
   /**
    * Return a list containing all of the sdk libraries in this mapping.
@@ -96,7 +153,7 @@
   /**
    * Return a list containing the library URI's for which a mapping is available.
    */
-  List<String> get uris => new List.from(_libraryMap.keys.toSet());
+  List<String> get uris => _libraryMap.keys.toList();
 
   /**
    * Return the library with the given 'dart:' [uri], or `null` if the URI does
@@ -184,16 +241,20 @@
    */
   LibraryMap get librariesMap => _librariesMap;
 
-
   // To be backwards-compatible the new categories field is translated to
   // an old approximation.
   String convertCategories(String categories) {
     switch (categories) {
-      case "": return "Internal";
-      case "Client": return "Client";
-      case "Server": return "Server";
-      case "Client,Server": return "Shared";
-      case "Client,Server,Embedded": return "Shared";
+      case "":
+        return "Internal";
+      case "Client":
+        return "Client";
+      case "Server":
+        return "Server";
+      case "Client,Server":
+        return "Shared";
+      case "Client,Server,Embedded":
+        return "Shared";
     }
     return "Shared";
   }
@@ -219,7 +280,7 @@
             library.category =
                 convertCategories((expression as StringLiteral).stringValue);
           } else if (name == _IMPLEMENTATION) {
-            library.implementation = (expression as BooleanLiteral).value;
+            library._implementation = (expression as BooleanLiteral).value;
           } else if (name == _DOCUMENTED) {
             library.documented = (expression as BooleanLiteral).value;
           } else if (name == _PLATFORMS) {
@@ -316,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;
 
   /**
@@ -329,6 +392,7 @@
    * in the libraries file all libraries are assumed to be shared between server
    * and client.
    */
+  @override
   String category = "Shared";
 
   /**
@@ -359,13 +423,6 @@
     this._documented = documented;
   }
 
-  /**
-   * Set whether the library is an implementation library.
-   */
-  void set implementation(bool implementation) {
-    this._implementation = implementation;
-  }
-
   @override
   bool get isDart2JsLibrary => (_platforms & DART2JS_PLATFORM) != 0;
 
@@ -376,7 +433,7 @@
   bool get isImplementation => _implementation;
 
   @override
-  bool get isInternal => "Internal" == category;
+  bool get isInternal => category == "Internal";
 
   @override
   bool get isShared => category == "Shared";
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index 863a3d4..6f03a84 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -7,8 +7,10 @@
 import 'dart:collection';
 import 'dart:io';
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/generated/ast.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';
@@ -16,10 +18,9 @@
 import 'package:analyzer/src/generated/java_engine_io.dart';
 import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/summary/format.dart' show SdkBundle;
+import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
 import 'package:analyzer/src/summary/summary_sdk.dart';
 import 'package:path/path.dart' as pathos;
 
@@ -207,6 +208,11 @@
   JavaFile _libraryDirectory;
 
   /**
+   * The flag that specifies whether SDK summary should be used.
+   */
+  bool _useSummary = false;
+
+  /**
    * The revision number of this SDK, or `"0"` if the revision number cannot be
    * discovered.
    */
@@ -255,20 +261,9 @@
   @override
   AnalysisContext get context {
     if (_analysisContext == null) {
-      SdkBundle sdkBundle = _getSummarySdkBundle();
-      if (sdkBundle != null) {
-        _analysisContext = new SummarySdkAnalysisContext(sdkBundle);
-      } else {
-        _analysisContext = new SdkAnalysisContext();
-      }
+      _analysisContext = new SdkAnalysisContext();
       SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
       _analysisContext.sourceFactory = factory;
-      List<String> uris = this.uris;
-      ChangeSet changeSet = new ChangeSet();
-      for (String uri in uris) {
-        changeSet.addedSource(factory.forUri(uri));
-      }
-      _analysisContext.applyChanges(changeSet);
     }
     return _analysisContext;
   }
@@ -395,6 +390,20 @@
   List<String> get uris => _libraryMap.uris;
 
   /**
+   * Specify whether SDK summary should be used.
+   */
+  void set useSummary(bool use) {
+    _useSummary = use;
+    if (_useSummary) {
+      PackageBundle sdkBundle = _getSummarySdkBundle();
+      if (sdkBundle != null) {
+        _analysisContext.resultProvider =
+            new SdkSummaryResultProvider(_analysisContext, sdkBundle);
+      }
+    }
+  }
+
+  /**
    * Return the name of the file containing the VM executable.
    */
   String get vmBinaryName {
@@ -456,7 +465,7 @@
           return null;
         }
       }
-      libraryPath = new JavaFile(libraryPath).getParent();
+      libraryPath = new JavaFile(library.path).getParent();
       if (filePath.startsWith("$libraryPath${JavaFile.separator}")) {
         String path =
             "${library.shortName}/${filePath.substring(libraryPath.length + 1)}";
@@ -539,16 +548,18 @@
   }
 
   /**
-   * Return the [SdkBundle] for this SDK, if it exists, or `null` otherwise.
+   * Return the [PackageBundle] for this SDK, if it exists, or `null` otherwise.
    */
-  SdkBundle _getSummarySdkBundle() {
+  PackageBundle _getSummarySdkBundle() {
     String rootPath = directory.getAbsolutePath();
-    String path = pathos.join(rootPath, 'lib', '_internal', 'analysis_summary');
+    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()) {
         List<int> bytes = file.readAsBytesSync();
-        return new SdkBundle.fromBuffer(bytes);
+        return new PackageBundle.fromBuffer(bytes);
       }
     } catch (exception, stackTrace) {
       AnalysisEngine.instance.logger.logError(
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 950f36e0..092671e 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -8,15 +8,13 @@
 import "dart:math" as math;
 
 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/source.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/java_io.dart' show JavaFile;
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
 import 'package:analyzer/src/generated/source_io.dart' show FileBasedSource;
-import 'package:analyzer/src/generated/utilities_dart.dart' as utils;
 import 'package:analyzer/task/model.dart';
 import 'package:package_config/packages.dart';
 import 'package:path/path.dart' as pathos;
@@ -178,12 +176,12 @@
 }
 
 /**
- * Instances of the class `LineInfo` encapsulate information about line and column information
- * within a source file.
+ * Information about line and column information within a source file.
  */
 class LineInfo {
   /**
-   * An array containing the offsets of the first character of each line in the source code.
+   * A list containing the offsets of the first character of each line in the
+   * source code.
    */
   final List<int> _lineStarts;
 
@@ -194,12 +192,23 @@
   int _previousLine = 0;
 
   /**
-   * Initialize a newly created set of line information to represent the data encoded in the given
-   * array.
-   *
-   * @param lineStarts the offsets of the first character of each line in the source code
+   * Initialize a newly created set of line information to represent the data
+   * encoded in the given list of [_lineStarts].
    */
-  LineInfo(this._lineStarts) {
+  factory LineInfo(List<int> _lineStarts) => new LineInfoWithCount(_lineStarts);
+
+  /**
+   * Initialize a newly created set of line information corresponding to the
+   * given file [content].
+   */
+  factory LineInfo.fromContent(String content) =>
+      new LineInfoWithCount(StringUtilities.computeLineStarts(content));
+
+  /**
+   * Initialize a newly created set of line information to represent the data
+   * encoded in the given list of [_lineStarts].
+   */
+  LineInfo._(this._lineStarts) {
     if (_lineStarts == null) {
       throw new IllegalArgumentException("lineStarts must be non-null");
     } else if (_lineStarts.length < 1) {
@@ -208,10 +217,7 @@
   }
 
   /**
-   * Return the location information for the character at the given offset.
-   *
-   * @param offset the offset of the character for which location information is to be returned
-   * @return the location information for the character at the given offset
+   * Return the location information for the character at the given [offset].
    */
   LineInfo_Location getLocation(int offset) {
     var min = 0;
@@ -288,6 +294,26 @@
 }
 
 /**
+ * Information about line and column information within a source file,
+ * including a count of the total number of lines.
+ *
+ * TODO(paulberry): in the next major version roll of analyzer, merge this
+ * class into [LineInfo].
+ */
+class LineInfoWithCount extends LineInfo {
+  /**
+   * Initialize a newly created set of line information to represent the data
+   * encoded in the given list of [_lineStarts].
+   */
+  LineInfoWithCount(List<int> _lineStarts) : super._(_lineStarts);
+
+  /**
+   * Return the number of lines in the file.
+   */
+  int get lineCount => _lineStarts.length;
+}
+
+/**
  * Instances of interface `LocalSourcePredicate` are used to determine if the given
  * [Source] is "local" in some sense, so can be updated.
  */
@@ -343,6 +369,7 @@
   @override
   final Uri uri;
 
+  @override
   final UriKind uriKind;
 
   NonExistingSource(this.fullName, this.uri, this.uriKind);
@@ -353,9 +380,7 @@
   }
 
   @override
-  String get encoding {
-    throw new UnsupportedOperationException('$fullName does not exist.');
-  }
+  String get encoding => uri.toString();
 
   @override
   int get hashCode => fullName.hashCode;
@@ -575,159 +600,74 @@
  * Instances of the class `SourceFactory` resolve possibly relative URI's against an existing
  * [Source].
  */
-class SourceFactory {
+abstract class SourceFactory {
   /**
    * The analysis context that this source factory is associated with.
    */
   AnalysisContext context;
 
   /**
-   * URI processor used to find mappings for `package:` URIs found in a `.packages` config
-   * file.
+   * Initialize a newly created source factory with the given absolute URI
+   * [resolvers] and optional [packages] resolution helper.
    */
-  final Packages _packages;
+  factory SourceFactory(List<UriResolver> resolvers,
+      [Packages packages,
+      ResourceProvider resourceProvider]) = SourceFactoryImpl;
 
   /**
-   * Resource provider used in working with package maps.
-   */
-  final ResourceProvider _resourceProvider;
-
-  /**
-   * The resolvers used to resolve absolute URI's.
-   */
-  final List<UriResolver> _resolvers;
-
-  /**
-   * The predicate to determine is [Source] is local.
-   */
-  LocalSourcePredicate _localSourcePredicate = LocalSourcePredicate.NOT_SDK;
-
-  /**
-   * Initialize a newly created source factory with the given absolute URI [resolvers] and
-   * optional [packages] resolution helper.
-   */
-  SourceFactory(this._resolvers,
-      [this._packages, ResourceProvider resourceProvider])
-      : _resourceProvider = resourceProvider != null
-            ? resourceProvider
-            : PhysicalResourceProvider.INSTANCE;
-
-  /**
-   * Return the [DartSdk] associated with this [SourceFactory], or `null` if there
-   * is no such SDK.
+   * Return the [DartSdk] associated with this [SourceFactory], or `null` if
+   * there is no such SDK.
    *
    * @return the [DartSdk] associated with this [SourceFactory], or `null` if
    *         there is no such SDK
    */
-  DartSdk get dartSdk {
-    for (UriResolver resolver in _resolvers) {
-      if (resolver is DartUriResolver) {
-        DartUriResolver dartUriResolver = resolver;
-        return dartUriResolver.dartSdk;
-      }
-    }
-    return null;
-  }
+  DartSdk get dartSdk;
 
   /**
    * Sets the [LocalSourcePredicate].
    *
    * @param localSourcePredicate the predicate to determine is [Source] is local
    */
-  void set localSourcePredicate(LocalSourcePredicate localSourcePredicate) {
-    this._localSourcePredicate = localSourcePredicate;
-  }
+  void set localSourcePredicate(LocalSourcePredicate localSourcePredicate);
 
   /// A table mapping package names to paths of directories containing
   /// the package (or [null] if there is no registered package URI resolver).
-  Map<String, List<Folder>> get packageMap {
-    // Start by looking in .packages.
-    if (_packages != null) {
-      Map<String, List<Folder>> packageMap = <String, List<Folder>>{};
-      _packages.asMap().forEach((String name, Uri uri) {
-        if (uri.scheme == 'file' || uri.scheme == '' /* unspecified */) {
-          packageMap[name] = <Folder>[
-            _resourceProvider.getFolder(uri.toFilePath())
-          ];
-        }
-      });
-      return packageMap;
-    }
-
-    // Default to the PackageMapUriResolver.
-    PackageMapUriResolver resolver = _resolvers
-        .firstWhere((r) => r is PackageMapUriResolver, orElse: () => null);
-    return resolver != null ? resolver.packageMap : null;
-  }
+  Map<String, List<Folder>> get packageMap;
 
   /**
    * Return a source factory that will resolve URI's in the same way that this
    * source factory does.
    */
-  SourceFactory clone() {
-    SourceFactory factory =
-        new SourceFactory(_resolvers, _packages, _resourceProvider);
-    factory.localSourcePredicate = _localSourcePredicate;
-    return factory;
-  }
+  SourceFactory clone();
 
   /**
-   * Return a source object representing the given absolute URI, or `null` if the URI is not a
-   * valid URI or if it is not an absolute URI.
+   * Return a source object representing the given absolute URI, or `null` if
+   * the URI is not a valid URI or if it is not an absolute URI.
    *
    * @param absoluteUri the absolute URI to be resolved
    * @return a source object representing the absolute URI
    */
-  Source forUri(String absoluteUri) {
-    try {
-      Uri uri = parseUriWithException(absoluteUri);
-      if (uri.isAbsolute) {
-        return _internalResolveUri(null, uri);
-      }
-    } catch (exception, stackTrace) {
-      AnalysisEngine.instance.logger.logError(
-          "Could not resolve URI: $absoluteUri",
-          new CaughtException(exception, stackTrace));
-    }
-    return null;
-  }
+  Source forUri(String absoluteUri);
 
   /**
-   * Return a source object representing the given absolute URI, or `null` if the URI is not
-   * an absolute URI.
+   * Return a source object representing the given absolute URI, or `null` if
+   * the URI is not an absolute URI.
    *
    * @param absoluteUri the absolute URI to be resolved
    * @return a source object representing the absolute URI
    */
-  Source forUri2(Uri absoluteUri) {
-    if (absoluteUri.isAbsolute) {
-      try {
-        return _internalResolveUri(null, absoluteUri);
-      } on AnalysisException catch (exception, stackTrace) {
-        AnalysisEngine.instance.logger.logError(
-            "Could not resolve URI: $absoluteUri",
-            new CaughtException(exception, stackTrace));
-      }
-    }
-    return null;
-  }
+  Source forUri2(Uri absoluteUri);
 
   /**
-   * Return a source object that is equal to the source object used to obtain the given encoding.
+   * Return a source object that is equal to the source object used to obtain
+   * the given encoding.
    *
    * @param encoding the encoding of a source object
    * @return a source object that is described by the given encoding
    * @throws IllegalArgumentException if the argument is not a valid encoding
    * See [Source.encoding].
    */
-  Source fromEncoding(String encoding) {
-    Source source = forUri(encoding);
-    if (source == null) {
-      throw new IllegalArgumentException(
-          "Invalid source encoding: '$encoding'");
-    }
-    return source;
-  }
+  Source fromEncoding(String encoding);
 
   /**
    * Determines if the given [Source] is local.
@@ -735,7 +675,7 @@
    * @param source the [Source] to analyze
    * @return `true` if the given [Source] is local
    */
-  bool isLocalSource(Source source) => _localSourcePredicate.isLocal(source);
+  bool isLocalSource(Source source);
 
   /**
    * Return a source representing the URI that results from resolving the given
@@ -744,127 +684,21 @@
    * if either the [containedUri] is invalid or if it cannot be resolved against
    * the [containingSource]'s URI.
    */
-  Source resolveUri(Source containingSource, String containedUri) {
-    if (containedUri == null || containedUri.isEmpty) {
-      return null;
-    }
-    try {
-      // Force the creation of an escaped URI to deal with spaces, etc.
-      return _internalResolveUri(
-          containingSource, parseUriWithException(containedUri));
-    } on URISyntaxException {
-      return null;
-    } catch (exception, stackTrace) {
-      String containingFullName =
-          containingSource != null ? containingSource.fullName : '<null>';
-      AnalysisEngine.instance.logger.logInformation(
-          "Could not resolve URI ($containedUri) relative to source ($containingFullName)",
-          new CaughtException(exception, stackTrace));
-      return null;
-    }
-  }
+  Source resolveUri(Source containingSource, String containedUri);
 
   /**
-   * Return an absolute URI that represents the given source, or `null` if a valid URI cannot
-   * be computed.
+   * Return an absolute URI that represents the given source, or `null` if a
+   * valid URI cannot be computed.
    *
    * @param source the source to get URI for
    * @return the absolute URI representing the given source
    */
-  Uri restoreUri(Source source) {
-    // First see if a resolver can restore the URI.
-    for (UriResolver resolver in _resolvers) {
-      Uri uri = resolver.restoreAbsolute(source);
-      if (uri != null) {
-        // Now see if there's a package mapping.
-        Uri packageMappedUri = _getPackageMapping(uri);
-        if (packageMappedUri != null) {
-          return packageMappedUri;
-        }
-        // Fall back to the resolver's computed URI.
-        return uri;
-      }
-    }
-
-    return null;
-  }
-
-  Uri _getPackageMapping(Uri sourceUri) {
-    if (_packages == null) {
-      return null;
-    }
-    if (sourceUri.scheme != 'file') {
-      //TODO(pquitslund): verify this works for non-file URIs.
-      return null;
-    }
-
-    Uri packageUri;
-    _packages.asMap().forEach((String name, Uri uri) {
-      if (packageUri == null) {
-        if (utils.startsWith(sourceUri, uri)) {
-          packageUri = Uri.parse(
-              'package:$name/${sourceUri.path.substring(uri.path.length)}');
-        }
-      }
-    });
-    return packageUri;
-  }
-
-  /**
-   * Return a source object representing the URI that results from resolving the given (possibly
-   * relative) contained URI against the URI associated with an existing source object, or
-   * `null` if the URI could not be resolved.
-   *
-   * @param containingSource the source containing the given URI
-   * @param containedUri the (possibly relative) URI to be resolved against the containing source
-   * @return the source representing the contained URI
-   * @throws AnalysisException if either the contained URI is invalid or if it cannot be resolved
-   *           against the source object's URI
-   */
-  Source _internalResolveUri(Source containingSource, Uri containedUri) {
-    if (!containedUri.isAbsolute) {
-      if (containingSource == null) {
-        throw new AnalysisException(
-            "Cannot resolve a relative URI without a containing source: $containedUri");
-      }
-      containedUri = containingSource.resolveRelativeUri(containedUri);
-    }
-
-    Uri actualUri = containedUri;
-
-    // Check .packages and update target and actual URIs as appropriate.
-    if (_packages != null && containedUri.scheme == 'package') {
-      Uri packageUri = null;
-      try {
-        packageUri =
-            _packages.resolve(containedUri, notFound: (Uri packageUri) => null);
-      } on ArgumentError {
-        // Fall through to try resolvers.
-      }
-
-      if (packageUri != null) {
-        // Ensure scheme is set.
-        if (packageUri.scheme == '') {
-          packageUri = packageUri.replace(scheme: 'file');
-        }
-        containedUri = packageUri;
-      }
-    }
-
-    for (UriResolver resolver in _resolvers) {
-      Source result = resolver.resolveAbsolute(containedUri, actualUri);
-      if (result != null) {
-        return result;
-      }
-    }
-
-    return null;
-  }
+  Uri restoreUri(Source source);
 }
 
 /**
- * The enumeration `SourceKind` defines the different kinds of sources that are known to the
- * analysis engine.
+ * The enumeration `SourceKind` defines the different kinds of sources that are
+ * known to the analysis engine.
  */
 class SourceKind extends Enum<SourceKind> {
   /**
@@ -873,20 +707,22 @@
   static const SourceKind HTML = const SourceKind('HTML', 0);
 
   /**
-   * A Dart compilation unit that is not a part of another library. Libraries might or might not
-   * contain any directives, including a library directive.
+   * A Dart compilation unit that is not a part of another library. Libraries
+   * might or might not contain any directives, including a library directive.
    */
   static const SourceKind LIBRARY = const SourceKind('LIBRARY', 1);
 
   /**
-   * A Dart compilation unit that is part of another library. Parts contain a part-of directive.
+   * A Dart compilation unit that is part of another library. Parts contain a
+   * part-of directive.
    */
   static const SourceKind PART = const SourceKind('PART', 2);
 
   /**
-   * An unknown kind of source. Used both when it is not possible to identify the kind of a source
-   * and also when the kind of a source is not known without performing a computation and the client
-   * does not want to spend the time to identify the kind.
+   * An unknown kind of source. Used both when it is not possible to identify
+   * the kind of a source and also when the kind of a source is not known
+   * without performing a computation and the client does not want to spend the
+   * time to identify the kind.
    */
   static const SourceKind UNKNOWN = const SourceKind('UNKNOWN', 3);
 
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 28f42f7..b54bc04 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -6,15 +6,15 @@
 
 import 'dart:collection';
 
+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/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/scanner.dart' as sc;
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
 /**
@@ -237,8 +237,8 @@
    */
   @override
   Object visitAssignmentExpression(AssignmentExpression node) {
-    sc.TokenType operator = node.operator.type;
-    if (operator == sc.TokenType.EQ) {
+    TokenType operator = node.operator.type;
+    if (operator == TokenType.EQ) {
       Expression rightHandSide = node.rightHandSide;
       DartType staticType = _getStaticType(rightHandSide);
       _recordStaticType(node, staticType);
@@ -249,7 +249,7 @@
         overrideType = propagatedType;
       }
       _resolver.overrideExpression(node.leftHandSide, overrideType, true, true);
-    } else if (operator == sc.TokenType.QUESTION_QUESTION_EQ) {
+    } else if (operator == TokenType.QUESTION_QUESTION_EQ) {
       // The static type of a compound assignment using ??= is the least upper
       // bound of the static types of the LHS and RHS.
       _analyzeLeastUpperBound(node, node.leftHandSide, node.rightHandSide);
@@ -281,11 +281,11 @@
       // TODO(brianwilkerson) Determine whether this can still happen.
       staticExpressionType = _dynamicType;
     }
-    DartType staticType = flattenFutures(_typeProvider, staticExpressionType);
+    DartType staticType = staticExpressionType.flattenFutures(_typeSystem);
     _recordStaticType(node, staticType);
     DartType propagatedExpressionType = node.expression.propagatedType;
     DartType propagatedType =
-        flattenFutures(_typeProvider, propagatedExpressionType);
+        propagatedExpressionType?.flattenFutures(_typeSystem);
     _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
     return null;
   }
@@ -461,23 +461,37 @@
       // node.
       return null;
     }
+    bool recordInference = false;
     ExecutableElementImpl functionElement =
         node.element as ExecutableElementImpl;
-    DartType computedType = _computeStaticReturnTypeOfFunctionExpression(node);
-    if (_strongMode) {
-      DartType functionType = InferenceContext.getType(node);
-      if (functionType is FunctionType) {
-        DartType returnType = functionType.returnType;
-        if ((computedType.isDynamic || computedType.isBottom) &&
-            !(returnType.isDynamic || returnType.isBottom)) {
-          computedType = returnType;
-          _resolver.inferenceContext.recordInference(node, functionType);
-        }
-      }
+
+    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;
   }
 
@@ -495,6 +509,9 @@
    */
   @override
   Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+    if (_strongMode) {
+      _inferGenericInvoke(node);
+    }
     DartType staticType = _computeInvokeReturnType(node.staticInvokeType);
     _recordStaticType(node, staticType);
     DartType functionPropagatedType = node.propagatedInvokeType;
@@ -609,14 +626,18 @@
           staticType = argumentType;
         }
       }
-    } else {
+    } else if (_strongMode) {
       DartType contextType = InferenceContext.getType(node);
-      if (_strongMode &&
-          contextType is InterfaceType &&
+      if (contextType is InterfaceType &&
           contextType.typeArguments.length == 1 &&
           contextType.element == _typeProvider.listType.element) {
         staticType = contextType.typeArguments[0];
         _resolver.inferenceContext.recordInference(node, contextType);
+      } else if (node.elements.isNotEmpty) {
+        // Infer the list type from the arguments.
+        staticType =
+            node.elements.map((e) => e.staticType).reduce(_leastUpperBound);
+        // TODO(jmesserly): record inference here?
       }
     }
     _recordStaticType(
@@ -655,15 +676,22 @@
           staticValueType = entryValueType;
         }
       }
-    } else {
+    } else if (_strongMode) {
       DartType contextType = InferenceContext.getType(node);
-      if (_strongMode &&
-          contextType is InterfaceType &&
+      if (contextType is InterfaceType &&
           contextType.typeArguments.length == 2 &&
           contextType.element == _typeProvider.mapType.element) {
         staticKeyType = contextType.typeArguments[0] ?? staticKeyType;
         staticValueType = contextType.typeArguments[1] ?? staticValueType;
         _resolver.inferenceContext.recordInference(node, contextType);
+      } else if (node.entries.isNotEmpty) {
+        // Infer the list type from the arguments.
+        staticKeyType =
+            node.entries.map((e) => e.key.staticType).reduce(_leastUpperBound);
+        staticValueType = node.entries
+            .map((e) => e.value.staticType)
+            .reduce(_leastUpperBound);
+        // TODO(jmesserly): record inference here?
       }
     }
     _recordStaticType(
@@ -713,17 +741,25 @@
   Object visitMethodInvocation(MethodInvocation node) {
     SimpleIdentifier methodNameNode = node.methodName;
     Element staticMethodElement = methodNameNode.staticElement;
+    if (_strongMode) {
+      _inferGenericInvoke(node);
+    }
     // Record types of the variable invoked as a function.
     if (staticMethodElement is VariableElement) {
-      VariableElement variable = staticMethodElement;
-      DartType staticType = variable.type;
-      _recordStaticType(methodNameNode, staticType);
-      DartType propagatedType = _overrideManager.getType(variable);
+      DartType propagatedType = _overrideManager.getType(staticMethodElement);
       _resolver.recordPropagatedTypeIfBetter(methodNameNode, propagatedType);
     }
     // Record static return type of the static element.
-    DartType staticStaticType = _computeInvokeReturnType(node.staticInvokeType);
-    _recordStaticType(node, staticStaticType);
+    bool inferredStaticType = _strongMode &&
+        (_inferMethodInvocationObject(node) ||
+            _inferMethodInvocationInlineJS(node));
+
+    if (!inferredStaticType) {
+      DartType staticStaticType =
+          _computeInvokeReturnType(node.staticInvokeType);
+      _recordStaticType(node, staticStaticType);
+    }
+
     // Record propagated return type of the static element.
     DartType staticPropagatedType =
         _computePropagatedReturnType(staticMethodElement);
@@ -731,10 +767,7 @@
     // Check for special cases.
     bool needPropagatedType = true;
     String methodName = methodNameNode.name;
-    if (_strongMode) {
-      _inferMethodInvocation(node);
-    }
-    if (methodName == "then") {
+    if (!_strongMode && methodName == "then") {
       Expression target = node.realTarget;
       if (target != null) {
         DartType targetType = target.bestType;
@@ -753,16 +786,10 @@
                   _computePropagatedReturnType(closureExpr.element);
               if (returnType != null) {
                 // prepare the type of the returned Future
-                InterfaceTypeImpl newFutureType;
-                if (_isAsyncFutureType(returnType)) {
-                  newFutureType = returnType as InterfaceTypeImpl;
-                } else {
-                  InterfaceType futureType = targetType as InterfaceType;
-                  newFutureType = new InterfaceTypeImpl(futureType.element);
-                  newFutureType.typeArguments = <DartType>[returnType];
-                }
+                InterfaceType newFutureType = _typeProvider.futureType
+                    .substitute4([returnType.flattenFutures(_typeSystem)]);
                 // set the 'then' invocation type
-                _recordPropagatedType(node, newFutureType);
+                _resolver.recordPropagatedTypeIfBetter(node, newFutureType);
                 needPropagatedType = false;
                 return null;
               }
@@ -873,16 +900,21 @@
     }
     if (needPropagatedType) {
       Element propagatedElement = methodNameNode.propagatedElement;
+      DartType propagatedInvokeType = node.propagatedInvokeType;
       // HACK: special case for object methods ([toString]) on dynamic
       // expressions. More special cases in [visitPrefixedIdentfier].
       if (propagatedElement == null) {
-        propagatedElement =
+        MethodElement objMethod =
             _typeProvider.objectType.getMethod(methodNameNode.name);
+        if (objMethod != null) {
+          propagatedElement = objMethod;
+          propagatedInvokeType = objMethod.type;
+        }
       }
       if (!identical(propagatedElement, staticMethodElement)) {
         // Record static return type of the propagated element.
         DartType propagatedStaticType =
-            _computeStaticReturnType(propagatedElement);
+            _computeInvokeReturnType(propagatedInvokeType);
         _resolver.recordPropagatedTypeIfBetter(
             node, propagatedStaticType, true);
         // Record propagated return type of the propagated element.
@@ -909,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;
   }
@@ -951,9 +984,8 @@
   Object visitPostfixExpression(PostfixExpression node) {
     Expression operand = node.operand;
     DartType staticType = _getStaticType(operand);
-    sc.TokenType operator = node.operator.type;
-    if (operator == sc.TokenType.MINUS_MINUS ||
-        operator == sc.TokenType.PLUS_PLUS) {
+    TokenType operator = node.operator.type;
+    if (operator == TokenType.MINUS_MINUS || operator == TokenType.PLUS_PLUS) {
       DartType intType = _typeProvider.intType;
       if (identical(_getStaticType(node.operand), intType)) {
         staticType = intType;
@@ -998,6 +1030,10 @@
     } else if (staticElement is VariableElement) {
       staticType = staticElement.type;
     }
+    if (_strongMode) {
+      staticType = _inferGenericInstantiationFromContext(
+          InferenceContext.getType(node), staticType);
+    }
     if (!(_strongMode &&
         _inferObjectAccess(node, staticType, prefixedIdentifier))) {
       _recordStaticType(prefixedIdentifier, staticType);
@@ -1049,15 +1085,15 @@
    */
   @override
   Object visitPrefixExpression(PrefixExpression node) {
-    sc.TokenType operator = node.operator.type;
-    if (operator == sc.TokenType.BANG) {
+    TokenType operator = node.operator.type;
+    if (operator == TokenType.BANG) {
       _recordStaticType(node, _typeProvider.boolType);
     } else {
       // The other cases are equivalent to invoking a method.
       ExecutableElement staticMethodElement = node.staticElement;
       DartType staticType = _computeStaticReturnType(staticMethodElement);
-      if (operator == sc.TokenType.MINUS_MINUS ||
-          operator == sc.TokenType.PLUS_PLUS) {
+      if (operator == TokenType.MINUS_MINUS ||
+          operator == TokenType.PLUS_PLUS) {
         DartType intType = _typeProvider.intType;
         if (identical(_getStaticType(node.operand), intType)) {
           staticType = intType;
@@ -1127,6 +1163,10 @@
     } else {
       // TODO(brianwilkerson) Report this internal error.
     }
+    if (_strongMode) {
+      staticType = _inferGenericInstantiationFromContext(
+          InferenceContext.getType(node), staticType);
+    }
     if (!(_strongMode && _inferObjectAccess(node, staticType, propertyName))) {
       _recordStaticType(propertyName, staticType);
       _recordStaticType(node, staticType);
@@ -1227,6 +1267,10 @@
     } else {
       staticType = _dynamicType;
     }
+    if (_strongMode) {
+      staticType = _inferGenericInstantiationFromContext(
+          InferenceContext.getType(node), staticType);
+    }
     _recordStaticType(node, staticType);
     // TODO(brianwilkerson) I think we want to repeat the logic above using the
     // propagated element to get another candidate for the propagated type.
@@ -1379,6 +1423,21 @@
   }
 
   /**
+   * Compute the return type of the method or function represented by the given
+   * type that is being invoked.
+   */
+  DartType _computeInvokeReturnType(DartType type) {
+    if (type is InterfaceType) {
+      MethodElement callMethod = type.lookUpMethod(
+          FunctionElement.CALL_METHOD_NAME, _resolver.definingLibrary);
+      return callMethod?.type?.returnType ?? _dynamicType;
+    } else if (type is FunctionType) {
+      return type.returnType ?? _dynamicType;
+    }
+    return _dynamicType;
+  }
+
+  /**
    * Compute the propagated 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
@@ -1415,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
@@ -1440,21 +1520,6 @@
   }
 
   /**
-   * Compute the return type of the method or function represented by the given
-   * type that is being invoked.
-   */
-  DartType _computeInvokeReturnType(DartType type) {
-    if (type is InterfaceType) {
-      MethodElement callMethod = type.lookUpMethod(
-          FunctionElement.CALL_METHOD_NAME, _resolver.definingLibrary);
-      return callMethod?.type?.returnType ?? _dynamicType;
-    } else if (type is FunctionType) {
-      return type.returnType ?? _dynamicType;
-    }
-    return _dynamicType;
-  }
-
-  /**
    * Given a function declaration, compute the return static 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.
@@ -1471,49 +1536,14 @@
     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>[flattenFutures(_typeProvider, type)]);
-    } else {
-      return type;
-    }
-  }
-
-  // TODO(vsm): Use leafp's matchType here?
   DartType _findIteratedType(DartType type, DartType targetType) {
+    // TODO(vsm): Use leafp's matchType here?
     // Set by _find if match is found
-    DartType result = null;
+    DartType result;
     // Elements we've already visited on a given inheritance path.
-    HashSet<ClassElement> visitedClasses = null;
+    HashSet<ClassElement> visitedClasses;
 
-    while (type is TypeParameterType) {
-      TypeParameterElement element = type.element;
-      type = element.bound;
-    }
+    type = type.resolveToBound(_typeProvider.objectType);
 
     bool _find(InterfaceType type) {
       ClassElement element = type.element;
@@ -1571,6 +1601,12 @@
       }
       ClassElement returnType = library.getType(elementName);
       if (returnType != null) {
+        if (returnType.typeParameters.isNotEmpty) {
+          // Caller can't deal with unbound type parameters, so substitute
+          // `dynamic`.
+          return returnType.type.substitute4(
+              returnType.typeParameters.map((_) => _dynamicType).toList());
+        }
         return returnType.type;
       }
     }
@@ -1769,6 +1805,59 @@
   }
 
   /**
+   * Given an uninstantiated generic type, try to infer the instantiated generic
+   * type from the surrounding context.
+   */
+  DartType _inferGenericInstantiationFromContext(
+      DartType context, DartType type) {
+    TypeSystem ts = _typeSystem;
+    if (context is FunctionType &&
+        type is FunctionType &&
+        ts is StrongTypeSystemImpl) {
+      return ts.inferFunctionTypeInstantiation(_typeProvider, context, type);
+    }
+    return type;
+  }
+
+  bool _inferGenericInvoke(InvocationExpression node) {
+    TypeSystem ts = _typeSystem;
+    DartType fnType = node.function.staticType;
+    if (node.typeArguments == null &&
+        fnType is FunctionType &&
+        fnType.typeFormals.isNotEmpty &&
+        ts is StrongTypeSystemImpl) {
+      ArgumentList argumentList = node.argumentList;
+      // Get the parameters that correspond to the uninstantiated generic.
+      List<ParameterElement> rawParameters = ResolverVisitor
+          .resolveArgumentsToParameters(argumentList, fnType.parameters, null);
+
+      List<DartType> paramTypes = <DartType>[];
+      List<DartType> argTypes = <DartType>[];
+      for (int i = 0, length = rawParameters.length; i < length; i++) {
+        ParameterElement parameter = rawParameters[i];
+        if (parameter != null) {
+          paramTypes.add(parameter.type);
+          argTypes.add(argumentList.arguments[i].staticType);
+        }
+      }
+
+      FunctionType inferred = ts.inferGenericFunctionCall(_typeProvider, fnType,
+          paramTypes, argTypes, InferenceContext.getType(node));
+
+      if (inferred != node.staticInvokeType) {
+        // Fix up the parameter elements based on inferred method.
+        List<ParameterElement> inferredParameters =
+            ResolverVisitor.resolveArgumentsToParameters(
+                argumentList, inferred.parameters, null);
+        argumentList.correspondingStaticParameters = inferredParameters;
+        node.staticInvokeType = inferred;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
    * Given a local variable declaration and its initializer, attempt to infer
    * a type for the local variable declaration based on the initializer.
    * Inference is only done if an explicit type is not present, and if
@@ -1789,64 +1878,11 @@
 
   /**
    * Given a method invocation [node], attempt to infer a better
-   * type for the result.
-   */
-  bool _inferMethodInvocation(MethodInvocation node) {
-    return _inferMethodInvocationObject(node) ||
-        _inferMethodInvocationGeneric(node) ||
-        _inferMethodInvocationInlineJS(node);
-  }
-
-  /**
-   * Given a generic method invocation [node], attempt to infer the method's
-   * type variables, using the actual types of the arguments.
-   */
-  bool _inferMethodInvocationGeneric(MethodInvocation node) {
-    Element element = node.methodName.staticElement;
-    DartType invokeType = node.staticInvokeType;
-
-    TypeSystem ts = _typeSystem;
-    if (node.typeArguments == null &&
-        element is ExecutableElement &&
-        ts is StrongTypeSystemImpl) {
-      FunctionType fnType = element.type;
-      if (fnType.typeFormals.isNotEmpty &&
-          ts.instantiateToBounds(fnType) == invokeType) {
-        // Get the parameters that correspond to the uninstantiated generic.
-        List<ParameterElement> genericParameters =
-            ResolverVisitor.resolveArgumentsToParameters(
-                node.argumentList, fnType.parameters, null);
-
-        int length = genericParameters.length;
-        List<DartType> argTypes = new List<DartType>(length);
-        List<DartType> paramTypes = new List<DartType>(length);
-        for (int i = 0; i < length; i++) {
-          argTypes[i] = node.argumentList.arguments[i].staticType;
-          paramTypes[i] = genericParameters[i].type;
-        }
-
-        FunctionType inferred = ts.inferCallFromArguments(
-            _typeProvider, fnType, paramTypes, argTypes);
-
-        if (inferred != fnType) {
-          // Fix up the parameter elements based on inferred method.
-          List<ParameterElement> inferredParameters =
-              ResolverVisitor.resolveArgumentsToParameters(
-                  node.argumentList, inferred.parameters, null);
-          node.argumentList.correspondingStaticParameters = inferredParameters;
-          node.staticInvokeType = inferred;
-          _recordStaticType(node, inferred.returnType);
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Given a method invocation [node], attempt to infer a better
    * type for the result if it is an inline JS invocation
    */
+  // TODO(jmesserly): we should remove this, and infer type from context, rather
+  // than try to understand the dart2js type grammar.
+  // (At the very least, we should lookup type name in the correct scope.)
   bool _inferMethodInvocationInlineJS(MethodInvocation node) {
     Element e = node.methodName.staticElement;
     if (e is FunctionElement &&
@@ -1873,6 +1909,10 @@
    * type for the result if the target is dynamic and the method
    * being called is one of the object methods.
    */
+  // TODO(jmesserly): we should move this logic to ElementResolver.
+  // If we do it here, we won't have correct parameter elements set on the
+  // node's argumentList. (This likely affects only explicit calls to
+  // `Object.noSuchMethod`.)
   bool _inferMethodInvocationObject(MethodInvocation node) {
     // If we have a call like `toString()` or `libraryPrefix.toString()` don't
     // infer it.
@@ -1890,7 +1930,7 @@
       return false;
     }
     DartType inferredType = inferredElement.type;
-    DartType nodeType = node.staticType;
+    DartType nodeType = node.staticInvokeType;
     if (nodeType != null &&
         nodeType.isDynamic &&
         inferredType is FunctionType &&
@@ -1983,6 +2023,14 @@
   }
 
   /**
+   * Computes the least upper bound between two types.
+   *
+   * See [TypeSystem.getLeastUpperBound].
+   */
+  DartType _leastUpperBound(DartType s, DartType t) =>
+      _typeSystem.getLeastUpperBound(_typeProvider, s, t);
+
+  /**
    * Record that the propagated type of the given node is the given type.
    *
    * @param expression the node whose type is to be recorded
@@ -2046,32 +2094,32 @@
   DartType _refineBinaryExpressionType(
       BinaryExpression expression, DartType currentType,
       [DartType typeAccessor(Expression node)]) {
-    sc.TokenType operator = expression.operator.type;
+    TokenType operator = expression.operator.type;
     // bool
-    if (operator == sc.TokenType.AMPERSAND_AMPERSAND ||
-        operator == sc.TokenType.BAR_BAR ||
-        operator == sc.TokenType.EQ_EQ ||
-        operator == sc.TokenType.BANG_EQ) {
+    if (operator == TokenType.AMPERSAND_AMPERSAND ||
+        operator == TokenType.BAR_BAR ||
+        operator == TokenType.EQ_EQ ||
+        operator == TokenType.BANG_EQ) {
       return _typeProvider.boolType;
     }
     DartType intType = _typeProvider.intType;
     if (typeAccessor(expression.leftOperand) == intType) {
       // int op double
-      if (operator == sc.TokenType.MINUS ||
-          operator == sc.TokenType.PERCENT ||
-          operator == sc.TokenType.PLUS ||
-          operator == sc.TokenType.STAR) {
+      if (operator == TokenType.MINUS ||
+          operator == TokenType.PERCENT ||
+          operator == TokenType.PLUS ||
+          operator == TokenType.STAR) {
         DartType doubleType = _typeProvider.doubleType;
         if (typeAccessor(expression.rightOperand) == doubleType) {
           return doubleType;
         }
       }
       // int op int
-      if (operator == sc.TokenType.MINUS ||
-          operator == sc.TokenType.PERCENT ||
-          operator == sc.TokenType.PLUS ||
-          operator == sc.TokenType.STAR ||
-          operator == sc.TokenType.TILDE_SLASH) {
+      if (operator == TokenType.MINUS ||
+          operator == TokenType.PERCENT ||
+          operator == TokenType.PLUS ||
+          operator == TokenType.STAR ||
+          operator == TokenType.TILDE_SLASH) {
         if (typeAccessor(expression.rightOperand) == intType) {
           return intType;
         }
@@ -2082,47 +2130,6 @@
   }
 
   /**
-   * Implements the function "flatten" defined in the spec:
-   *
-   *   If T = Future<S> then flatten(T) = flatten(S).
-   *
-   *   Otherwise if T <: Future then let S be a type such that T << Future<S>
-   *   and for all R, if T << Future<R> then S << R.  Then flatten(T) = S.
-   *
-   *   In any other circumstance, flatten(T) = T.
-   */
-  static DartType flattenFutures(TypeProvider typeProvider, DartType type) {
-    if (type is InterfaceType) {
-      // Implement the case: "If T = Future<S> then flatten(T) = flatten(S)."
-      if (type.element == typeProvider.futureType.element &&
-          type.typeArguments.length > 0) {
-        return flattenFutures(typeProvider, type.typeArguments[0]);
-      }
-
-      // Implement the case: "Otherwise if T <: Future then let S be a type
-      // such that T << Future<S> and for all R, if T << Future<R> then S << R.
-      // Then flatten(T) = S."
-      //
-      // 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
-      // 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 =
-          _searchTypeHierarchyForFutureParameters(typeProvider, type);
-      DartType flattenResult = _findMostSpecificType(candidateTypes);
-      if (flattenResult != null) {
-        return flattenResult;
-      }
-    }
-
-    // Implement the case: "In any other circumstance, flatten(T) = T."
-    return type;
-  }
-
-  /**
    * Create a table mapping HTML tag names to the names of the classes (in 'dart:html') that
    * implement those tags.
    *
@@ -2190,88 +2197,6 @@
     map["video"] = "VideoElement";
     return map;
   }
-
-  /**
-   * 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(List<DartType> types) {
-    // 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
-    // specific types seen so far such that no type in the bucket is more
-    // specific than any other type in the bucket.
-    List<DartType> bucket = <DartType>[];
-
-    // Then we consider each type in turn.
-    for (DartType type in types) {
-      // If any existing type in the bucket is more specific than this type,
-      // then we can ignore this type.
-      if (bucket.any((DartType t) => t.isMoreSpecificThan(type))) {
-        continue;
-      }
-      // Otherwise, we need to add this type to the bucket and remove any types
-      // that are less specific than it.
-      bool added = false;
-      int i = 0;
-      while (i < bucket.length) {
-        if (type.isMoreSpecificThan(bucket[i])) {
-          if (added) {
-            if (i < bucket.length - 1) {
-              bucket[i] = bucket.removeLast();
-            } else {
-              bucket.removeLast();
-            }
-          } else {
-            bucket[i] = type;
-            i++;
-            added = true;
-          }
-        } else {
-          i++;
-        }
-      }
-      if (!added) {
-        bucket.add(type);
-      }
-    }
-
-    // Now that we are finished, if there is exactly one type left in the
-    // bucket, it is the most specific type.
-    if (bucket.length == 1) {
-      return bucket[0];
-    }
-
-    // Otherwise, there is no single type that is more specific than the
-    // others.
-    return null;
-  }
-
-  /**
-   * Given a seed type [type], search its class hierarchy for types of the form
-   * Future<R>, and return a list of the resulting R's.
-   */
-  static List<DartType> _searchTypeHierarchyForFutureParameters(
-      TypeProvider typeProvider, InterfaceType type) {
-    List<DartType> result = <DartType>[];
-    HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
-    void recurse(InterfaceType type) {
-      if (type.element == typeProvider.futureType.element &&
-          type.typeArguments.length > 0) {
-        result.add(type.typeArguments[0]);
-      }
-      if (visitedClasses.add(type.element)) {
-        if (type.superclass != null) {
-          recurse(type.superclass);
-        }
-        for (InterfaceType interface in type.interfaces) {
-          recurse(interface);
-        }
-        visitedClasses.remove(type.element);
-      }
-    }
-    recurse(type);
-    return result;
-  }
 }
 
 class _StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
index c6892c2..d8d44f4 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
@@ -4,9 +4,10 @@
 
 library analyzer.src.generated.testing.ast_factory;
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 
@@ -34,7 +35,9 @@
       new Annotation(
           TokenFactory.tokenFromType(TokenType.AT),
           name,
-          TokenFactory.tokenFromType(TokenType.PERIOD),
+          constructorName == null
+              ? null
+              : TokenFactory.tokenFromType(TokenType.PERIOD),
           constructorName,
           arguments);
 
@@ -799,6 +802,10 @@
       new MapLiteralEntry(
           string2(key), TokenFactory.tokenFromType(TokenType.COLON), value);
 
+  static MapLiteralEntry mapLiteralEntry2(Expression key, Expression value) =>
+      new MapLiteralEntry(
+          key, TokenFactory.tokenFromType(TokenType.COLON), value);
+
   static MethodDeclaration methodDeclaration(
           Keyword modifier,
           TypeName returnType,
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 0dc3c7b..2beeab4 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -6,16 +6,16 @@
 
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.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/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -100,6 +100,15 @@
     ConstructorElementImpl constructor = name == null
         ? new ConstructorElementImpl("", -1)
         : new ConstructorElementImpl(name, 0);
+    if (name != null) {
+      if (name.isEmpty) {
+        constructor.nameEnd = definingClass.name.length;
+      } else {
+        constructor.periodOffset = definingClass.name.length;
+        constructor.nameEnd = definingClass.name.length + name.length + 1;
+      }
+    }
+    constructor.synthetic = name == null;
     constructor.const2 = isConst;
     if (argumentTypes != null) {
       int count = argumentTypes.length;
@@ -117,6 +126,9 @@
     constructor.returnType = type;
     constructor.enclosingElement = definingClass;
     constructor.type = new FunctionTypeImpl(constructor);
+    if (!constructor.isSynthetic) {
+      constructor.constantInitializers = <ConstructorInitializer>[];
+    }
     return constructor;
   }
 
@@ -198,7 +210,8 @@
   }
 
   static FieldElementImpl fieldElement(
-      String name, bool isStatic, bool isFinal, bool isConst, DartType type) {
+      String name, bool isStatic, bool isFinal, bool isConst, DartType type,
+      {Expression initializer}) {
     FieldElementImpl field = isConst
         ? new ConstFieldElementImpl(name, 0)
         : new FieldElementImpl(name, 0);
@@ -206,6 +219,9 @@
     field.final2 = isFinal;
     field.static = isStatic;
     field.type = type;
+    if (isConst) {
+      (field as ConstFieldElementImpl).constantInitializer = initializer;
+    }
     PropertyAccessorElementImpl getter =
         new PropertyAccessorElementImpl.forVariable(field);
     getter.getter = true;
@@ -233,7 +249,16 @@
 
   static FieldFormalParameterElementImpl fieldFormalParameter(
           Identifier name) =>
-      new FieldFormalParameterElementImpl(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);
@@ -405,11 +430,12 @@
     field.type = type;
     field.final2 = true;
     PropertyAccessorElementImpl getter =
-        new PropertyAccessorElementImpl.forVariable(field);
+        new PropertyAccessorElementImpl(name, 0);
     getter.synthetic = false;
     getter.getter = true;
     getter.variable = field;
     getter.returnType = type;
+    getter.static = isStatic;
     field.getter = getter;
     FunctionTypeImpl getterType = new FunctionTypeImpl(getter);
     getter.type = getterType;
@@ -491,6 +517,17 @@
     return parameter;
   }
 
+  static ParameterElementImpl namedParameter3(String name,
+      {DartType type, Expression initializer, String initializerCode}) {
+    DefaultParameterElementImpl parameter =
+        new DefaultParameterElementImpl(name, 0);
+    parameter.parameterKind = ParameterKind.NAMED;
+    parameter.type = type;
+    parameter.constantInitializer = initializer;
+    parameter.defaultValueCode = initializerCode;
+    return parameter;
+  }
+
   static ParameterElementImpl positionalParameter(String name) {
     ParameterElementImpl parameter = new ParameterElementImpl(name, 0);
     parameter.parameterKind = ParameterKind.POSITIONAL;
@@ -558,9 +595,17 @@
     TopLevelVariableElementImpl variable;
     if (isConst) {
       ConstTopLevelVariableElementImpl constant =
-          new ConstTopLevelVariableElementImpl(AstFactory.identifier3(name));
-      constant.constantInitializer = AstFactory.instanceCreationExpression2(
-          Keyword.CONST, AstFactory.typeName(type.element));
+          new ConstTopLevelVariableElementImpl.forNode(
+              AstFactory.identifier3(name));
+      InstanceCreationExpression initializer =
+          AstFactory.instanceCreationExpression2(
+              Keyword.CONST, AstFactory.typeName(type.element));
+      if (type is InterfaceType) {
+        ConstructorElement element = type.element.unnamedConstructor;
+        initializer.staticElement = element;
+        initializer.constructorName.staticElement = element;
+      }
+      constant.constantInitializer = initializer;
       variable = constant;
     } else {
       variable = new TopLevelVariableElementImpl(name, -1);
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index 5f1a49b..06f4bee 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -4,14 +4,17 @@
 
 library analyzer.src.generated.testing.test_type_provider;
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.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/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
+import 'package:analyzer/src/generated/source.dart' show Source;
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 
@@ -150,6 +153,14 @@
    */
   DartType _undefinedType;
 
+  /**
+   * The analysis context, if any. Used to create an appropriate 'dart:async'
+   * library to back `Future<T>`.
+   */
+  AnalysisContext _context;
+
+  TestTypeProvider([this._context]);
+
   @override
   InterfaceType get boolType {
     if (_boolType == null) {
@@ -159,7 +170,10 @@
           .constructorElement(boolElement, "fromEnvironment", true);
       fromEnvironment.parameters = <ParameterElement>[
         ElementFactory.requiredParameter2("name", stringType),
-        ElementFactory.namedParameter2("defaultValue", _boolType)
+        ElementFactory.namedParameter3("defaultValue",
+            type: _boolType,
+            initializer: AstFactory.booleanLiteral(false),
+            initializerCode: 'false')
       ];
       fromEnvironment.factory = true;
       fromEnvironment.isCycleFree = true;
@@ -181,12 +195,22 @@
     if (_deprecatedType == null) {
       ClassElementImpl deprecatedElement =
           ElementFactory.classElement2("Deprecated");
-      ConstructorElementImpl constructor = ElementFactory.constructorElement(
-          deprecatedElement, null, true, [stringType]);
-      constructor.constantInitializers = <ConstructorInitializer>[
-        AstFactory.constructorFieldInitializer(
-            true, 'expires', AstFactory.identifier3('expires'))
+      FieldElementImpl expiresField = ElementFactory.fieldElement(
+          'expires', false, true, false, stringType);
+      deprecatedElement.fields = <FieldElement>[expiresField];
+      deprecatedElement.accessors = <PropertyAccessorElement>[
+        expiresField.getter
       ];
+      ConstructorElementImpl constructor = ElementFactory
+          .constructorElement(deprecatedElement, '', true, [stringType]);
+      (constructor.parameters[0] as ParameterElementImpl).name = 'expires';
+      ConstructorFieldInitializer expiresInit =
+          AstFactory.constructorFieldInitializer(
+              true, 'expires', AstFactory.identifier3('expires'));
+      expiresInit.fieldName.staticElement = expiresField;
+      (expiresInit.expression as SimpleIdentifier).staticElement =
+          constructor.parameters[0];
+      constructor.constantInitializers = <ConstructorInitializer>[expiresInit];
       deprecatedElement.constructors = <ConstructorElement>[constructor];
       _deprecatedType = deprecatedElement.type;
     }
@@ -240,7 +264,18 @@
   @override
   InterfaceType get futureType {
     if (_futureType == null) {
-      _futureType = ElementFactory.classElement2("Future", ["T"]).type;
+      Source asyncSource = _context.sourceFactory.forUri(DartSdk.DART_ASYNC);
+      _context.setContents(asyncSource, "");
+      CompilationUnitElementImpl asyncUnit =
+          new CompilationUnitElementImpl("async.dart");
+      LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
+          _context, AstFactory.libraryIdentifier2(["dart.async"]));
+      asyncLibrary.definingCompilationUnit = asyncUnit;
+      asyncUnit.librarySource = asyncUnit.source = asyncSource;
+
+      ClassElementImpl future = ElementFactory.classElement2("Future", ["T"]);
+      _futureType = future.type;
+      asyncUnit.types = <ClassElement>[future];
     }
     return _futureType;
   }
@@ -274,7 +309,7 @@
         ElementFactory.getterElement("last", false, eType)
       ]);
       iterableElement.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(iterableElement, null, true)
+        ElementFactory.constructorElement(iterableElement, '', true)
           ..isCycleFree = true
       ];
       _propagateTypeArguments(iterableElement);
@@ -317,8 +352,8 @@
       ]);
       listElement.methods = <MethodElement>[
         ElementFactory.methodElement("[]", eType, [intType]),
-        ElementFactory.methodElement(
-            "[]=", VoidTypeImpl.instance, [intType, eType]),
+        ElementFactory
+            .methodElement("[]=", VoidTypeImpl.instance, [intType, eType]),
         ElementFactory.methodElement("add", VoidTypeImpl.instance, [eType])
       ];
       _propagateTypeArguments(listElement);
@@ -339,11 +374,11 @@
       ]);
       mapElement.methods = <MethodElement>[
         ElementFactory.methodElement("[]", vType, [objectType]),
-        ElementFactory.methodElement(
-            "[]=", VoidTypeImpl.instance, [kType, vType])
+        ElementFactory
+            .methodElement("[]=", VoidTypeImpl.instance, [kType, vType])
       ];
       mapElement.constructors = <ConstructorElement>[
-        ElementFactory.constructorElement(mapElement, null, false)
+        ElementFactory.constructorElement(mapElement, '', false)
           ..external = true
           ..factory = true
       ];
@@ -397,7 +432,7 @@
       ClassElementImpl objectElement = ElementFactory.object;
       _objectType = objectElement.type;
       ConstructorElementImpl constructor =
-          ElementFactory.constructorElement(objectElement, null, true);
+          ElementFactory.constructorElement(objectElement, '', true);
       constructor.constantInitializers = <ConstructorInitializer>[];
       objectElement.constructors = <ConstructorElement>[constructor];
       objectElement.methods = <MethodElement>[
@@ -462,7 +497,7 @@
           .constructorElement(stringElement, "fromEnvironment", true);
       fromEnvironment.parameters = <ParameterElement>[
         ElementFactory.requiredParameter2("name", stringType),
-        ElementFactory.namedParameter2("defaultValue", _stringType)
+        ElementFactory.namedParameter3("defaultValue", type: _stringType)
       ];
       fromEnvironment.factory = true;
       fromEnvironment.isCycleFree = true;
@@ -475,8 +510,8 @@
   InterfaceType get symbolType {
     if (_symbolType == null) {
       ClassElementImpl symbolClass = ElementFactory.classElement2("Symbol");
-      ConstructorElementImpl constructor = ElementFactory.constructorElement(
-          symbolClass, null, true, [stringType]);
+      ConstructorElementImpl constructor = ElementFactory
+          .constructorElement(symbolClass, '', true, [stringType]);
       constructor.factory = true;
       constructor.isCycleFree = true;
       symbolClass.constructors = <ConstructorElement>[constructor];
@@ -555,10 +590,10 @@
       ElementFactory.methodElement("toInt", _intType),
       ElementFactory.methodElement("toDouble", _doubleType),
       ElementFactory.methodElement("toStringAsFixed", _stringType, [_intType]),
-      ElementFactory.methodElement(
-          "toStringAsExponential", _stringType, [_intType]),
-      ElementFactory.methodElement(
-          "toStringAsPrecision", _stringType, [_intType]),
+      ElementFactory
+          .methodElement("toStringAsExponential", _stringType, [_intType]),
+      ElementFactory
+          .methodElement("toStringAsPrecision", _stringType, [_intType]),
       ElementFactory.methodElement("toRadixString", _stringType, [_intType])
     ];
     intElement.methods = <MethodElement>[
@@ -580,7 +615,7 @@
         ElementFactory.constructorElement(intElement, "fromEnvironment", true);
     fromEnvironment.parameters = <ParameterElement>[
       ElementFactory.requiredParameter2("name", stringType),
-      ElementFactory.namedParameter2("defaultValue", _intType)
+      ElementFactory.namedParameter3("defaultValue", type: _intType)
     ];
     fromEnvironment.factory = true;
     fromEnvironment.isCycleFree = true;
@@ -593,18 +628,23 @@
       ElementFactory.constructorElement(doubleElement, null, false)
         ..synthetic = true
     ];
-    ConstFieldElementImpl varINFINITY =
-        ElementFactory.fieldElement("INFINITY", true, false, true, _doubleType);
+    ConstFieldElementImpl varINFINITY = ElementFactory.fieldElement(
+        "INFINITY", true, false, true, _doubleType,
+        initializer: AstFactory.doubleLiteral(double.INFINITY));
     varINFINITY.constantInitializer = AstFactory.binaryExpression(
         AstFactory.integer(1), TokenType.SLASH, AstFactory.integer(0));
     List<FieldElement> fields = <FieldElement>[
-      ElementFactory.fieldElement("NAN", true, false, true, _doubleType),
+      ElementFactory.fieldElement("NAN", true, false, true, _doubleType,
+          initializer: AstFactory.doubleLiteral(double.NAN)),
       varINFINITY,
       ElementFactory.fieldElement(
-          "NEGATIVE_INFINITY", true, false, true, _doubleType),
+          "NEGATIVE_INFINITY", true, false, true, _doubleType,
+          initializer: AstFactory.doubleLiteral(double.NEGATIVE_INFINITY)),
       ElementFactory.fieldElement(
-          "MIN_POSITIVE", true, false, true, _doubleType),
-      ElementFactory.fieldElement("MAX_FINITE", true, false, true, _doubleType)
+          "MIN_POSITIVE", true, false, true, _doubleType,
+          initializer: AstFactory.doubleLiteral(double.MIN_POSITIVE)),
+      ElementFactory.fieldElement("MAX_FINITE", true, false, true, _doubleType,
+          initializer: AstFactory.doubleLiteral(double.MAX_FINITE))
     ];
     doubleElement.fields = fields;
     int fieldCount = fields.length;
diff --git a/pkg/analyzer/lib/src/generated/testing/token_factory.dart b/pkg/analyzer/lib/src/generated/testing/token_factory.dart
index a293842..918b9a1 100644
--- a/pkg/analyzer/lib/src/generated/testing/token_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/token_factory.dart
@@ -4,7 +4,8 @@
 
 library analyzer.src.generated.testing.token_factory;
 
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 
 /**
  * A set of utility methods that can be used to create tokens.
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 911dfa9..ee4d0a1 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -5,6 +5,7 @@
 library analyzer.src.generated.type_system;
 
 import 'dart:collection';
+import 'dart:math' as math;
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -12,9 +13,9 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
+import 'package:analyzer/src/generated/utilities_dart.dart';
 
 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
-typedef bool _SubtypeChecker<T>(T t1, T t2);
 
 /**
  * Implementation of [TypeSystem] using the strong mode rules.
@@ -29,6 +30,9 @@
     return ft.parameters.any((p) => predicate(p.type));
   }
 
+  @override
+  bool canPromoteToType(DartType to, DartType from) => isSubtypeOf(to, from);
+
   /**
    * Given a type t, if t is an interface type with a call method
    * defined, return the function type for the call method, otherwise
@@ -49,39 +53,41 @@
   }
 
   /// Given a function type with generic type parameters, infer the type
-  /// parameters from the actual argument types, and return it. If we can't.
-  /// returns the original function type.
+  /// parameters from the actual argument types, and return the instantiated
+  /// function type. If we can't, returns the original function type.
   ///
   /// Concretely, given a function type with parameter types P0, P1, ... Pn,
   /// result type R, and generic type parameters T0, T1, ... Tm, use the
   /// argument types A0, A1, ... An to solve for the type parameters.
   ///
   /// For each parameter Pi, we want to ensure that Ai <: Pi. We can do this by
-  /// running the subtype algorithm, and when we reach a type parameter Pj,
+  /// running the subtype algorithm, and when we reach a type parameter Tj,
   /// recording the lower or upper bound it must satisfy. At the end, all
   /// constraints can be combined to determine the type.
   ///
   /// As a simplification, we do not actually store all constraints on each type
-  /// parameter Pj. Instead we track Uj and Lj where U is the upper bound and
+  /// parameter Tj. Instead we track Uj and Lj where U is the upper bound and
   /// L is the lower bound of that type parameter.
-  FunctionType inferCallFromArguments(
+  FunctionType inferGenericFunctionCall(
       TypeProvider typeProvider,
-      FunctionTypeImpl fnType,
+      FunctionType fnType,
       List<DartType> correspondingParameterTypes,
-      List<DartType> argumentTypes) {
+      List<DartType> argumentTypes,
+      DartType returnContextType) {
     if (fnType.typeFormals.isEmpty) {
       return fnType;
     }
 
-    List<TypeParameterType> fnTypeParams =
-        TypeParameterTypeImpl.getTypes(fnType.typeFormals);
-
     // Create a TypeSystem that will allow certain type parameters to be
     // inferred. It will optimistically assume these type parameters can be
     // subtypes (or supertypes) as necessary, and track the constraints that
     // are implied by this.
     var inferringTypeSystem =
-        new _StrongInferenceTypeSystem(typeProvider, fnTypeParams);
+        new _StrongInferenceTypeSystem(typeProvider, fnType.typeFormals);
+
+    if (returnContextType != null) {
+      inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType);
+    }
 
     for (int i = 0; i < argumentTypes.length; i++) {
       // Try to pass each argument to each parameter, recording any type
@@ -90,61 +96,59 @@
           argumentTypes[i], correspondingParameterTypes[i]);
     }
 
-    var inferredTypes = new List<DartType>.from(fnTypeParams, growable: false);
-    for (int i = 0; i < fnTypeParams.length; i++) {
-      TypeParameterType typeParam = fnTypeParams[i];
-      _TypeParameterBound bound = inferringTypeSystem._bounds[typeParam];
+    // We are okay inferring some type variables and not others.
+    //
+    // This lets our return type be as precise as possible, which will help
+    // make any type information resulting from it more precise.
+    //
+    // This is simply a heuristic: the code is incorrect, and we'll issue an
+    // error on this call, to indicate that types don't match.
+    return inferringTypeSystem._infer(fnType, allowPartialSolution: true);
+  }
 
-      // Now we've computed lower and upper bounds for each type parameter.
-      //
-      // To decide on which type to assign, we look at the return type and see
-      // if the type parameter occurs in covariant or contravariant positions.
-      //
-      // If the type is "passed in" at all, or if our lower bound was bottom,
-      // we choose the upper bound as being the most useful.
-      //
-      // Otherwise we choose the more precise lower bound.
-      _TypeParameterVariance variance =
-          new _TypeParameterVariance.from(typeParam, fnType.returnType);
-
-      inferredTypes[i] =
-          variance.passedIn || bound.lower.isBottom ? bound.upper : bound.lower;
-
-      // Assumption: if the current type parameter has an "extends" clause
-      // that refers to another type variable we are inferring, it will appear
-      // before us or in this list position. For example:
-      //
-      //     <TFrom, TTo extends TFrom>
-      //
-      // We may infer TTo is TFrom. In that case, we already know what TFrom
-      // is inferred as, so we can substitute it now. This also handles more
-      // complex cases such as:
-      //
-      //     <TFrom, TTo extends Iterable<TFrom>>
-      //
-      // Or if the type parameter's bound depends on itself such as:
-      //
-      //     <T extends Clonable<T>>
-      inferredTypes[i] =
-          inferredTypes[i].substitute2(inferredTypes, fnTypeParams);
-
-      // See if this actually worked.
-      // If not, fall back to the known upper bound (if any) or `dynamic`.
-      if (inferredTypes[i].isBottom ||
-          !isSubtypeOf(inferredTypes[i],
-              bound.upper.substitute2(inferredTypes, fnTypeParams)) ||
-          !isSubtypeOf(bound.lower.substitute2(inferredTypes, fnTypeParams),
-              inferredTypes[i])) {
-        inferredTypes[i] = DynamicTypeImpl.instance;
-        if (typeParam.element.bound != null) {
-          inferredTypes[i] =
-              typeParam.element.bound.substitute2(inferredTypes, fnTypeParams);
-        }
-      }
+  /**
+   * Given a generic function type `F<T0, T1, ... Tn>` and a context type C,
+   * infer an instantiation of F, such that `F<S0, S1, ..., Sn>` <: C.
+   *
+   * This is similar to [inferGenericFunctionCall], but the return type is also
+   * considered as part of the solution.
+   *
+   * If this function is called with a [contextType] that is also
+   * uninstantiated, or a [fnType] that is already instantiated, it will have
+   * no effect and return [fnType].
+   */
+  FunctionType inferFunctionTypeInstantiation(TypeProvider typeProvider,
+      FunctionType contextType, FunctionType fnType) {
+    if (contextType.typeFormals.isNotEmpty || fnType.typeFormals.isEmpty) {
+      return fnType;
     }
 
-    // Return the instantiated type.
-    return fnType.instantiate(inferredTypes);
+    // Create a TypeSystem that will allow certain type parameters to be
+    // inferred. It will optimistically assume these type parameters can be
+    // subtypes (or supertypes) as necessary, and track the constraints that
+    // are implied by this.
+    var inferringTypeSystem =
+        new _StrongInferenceTypeSystem(typeProvider, fnType.typeFormals);
+
+    // Since we're trying to infer the instantiation, we want to ignore type
+    // formals as we check the parameters and return type.
+    var inferFnType =
+        fnType.instantiate(TypeParameterTypeImpl.getTypes(fnType.typeFormals));
+    if (!inferringTypeSystem.isSubtypeOf(inferFnType, contextType)) {
+      return fnType;
+    }
+
+    // Try to infer and instantiate the resulting type.
+    var resultType =
+        inferringTypeSystem._infer(fnType, allowPartialSolution: false);
+
+    // If the instantiation failed (because some type variable constraints
+    // could not be solved, in other words, we could not find a valid subtype),
+    // then return the original type, so the error is in terms of it.
+    //
+    // It would be safe to return a partial solution here, but the user
+    // experience may be better if we simply do not infer in this case.
+    return resultType ?? fnType;
   }
 
   /**
@@ -242,6 +246,9 @@
   }
 
   @override
+  bool isMoreSpecificThan(DartType t1, DartType t2) => isSubtypeOf(t1, t2);
+
+  @override
   bool isSubtypeOf(DartType leftType, DartType rightType) {
     return _isSubtypeOf(leftType, rightType, null);
   }
@@ -281,145 +288,18 @@
 
   /**
    * Check that [f1] is a subtype of [f2].
-   * [fuzzyArrows] indicates whether or not the f1 and f2 should be
-   * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
-   * as bottom).
+   *
+   * This will always assume function types use fuzzy arrows, in other words
+   * that dynamic parameters of f1 and f2 are treated as bottom.
    */
-  bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
-      {bool fuzzyArrows: true}) {
-    if (!f1.typeFormals.isEmpty) {
-      if (f2.typeFormals.isEmpty) {
-        f1 = instantiateToBounds(f1);
-        return _isFunctionSubtypeOf(f1, f2);
-      } else {
-        return _isGenericFunctionSubtypeOf(f1, f2, fuzzyArrows: fuzzyArrows);
-      }
-    }
-    final List<DartType> r1s = f1.normalParameterTypes;
-    final List<DartType> r2s = f2.normalParameterTypes;
-    final List<DartType> o1s = f1.optionalParameterTypes;
-    final List<DartType> o2s = f2.optionalParameterTypes;
-    final Map<String, DartType> n1s = f1.namedParameterTypes;
-    final Map<String, DartType> n2s = f2.namedParameterTypes;
-    final DartType ret1 = f1.returnType;
-    final DartType ret2 = f2.returnType;
-
-    // A -> B <: C -> D if C <: A and
-    // either D is void or B <: D
-    if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
-      return false;
-    }
-
-    // Reject if one has named and the other has optional
-    if (n1s.length > 0 && o2s.length > 0) {
-      return false;
-    }
-    if (n2s.length > 0 && o1s.length > 0) {
-      return false;
-    }
-
-    // Rebind _isSubtypeOf for convenience
-    _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
-        _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
-
-    // f2 has named parameters
-    if (n2s.length > 0) {
-      // Check that every named parameter in f2 has a match in f1
-      for (String k2 in n2s.keys) {
-        if (!n1s.containsKey(k2)) {
-          return false;
-        }
-        if (!parameterSubtype(n2s[k2], n1s[k2])) {
-          return false;
-        }
-      }
-    }
-    // If we get here, we either have no named parameters,
-    // or else the named parameters match and we have no optional
-    // parameters
-
-    // If f1 has more required parameters, reject
-    if (r1s.length > r2s.length) {
-      return false;
-    }
-
-    // If f2 has more required + optional parameters, reject
-    if (r2s.length + o2s.length > r1s.length + o1s.length) {
-      return false;
-    }
-
-    // The parameter lists must look like the following at this point
-    // where rrr is a region of required, and ooo is a region of optionals.
-    // f1: rrr ooo ooo ooo
-    // f2: rrr rrr ooo
-    int rr = r1s.length; // required in both
-    int or = r2s.length - r1s.length; // optional in f1, required in f2
-    int oo = o2s.length; // optional in both
-
-    for (int i = 0; i < rr; ++i) {
-      if (!parameterSubtype(r2s[i], r1s[i])) {
-        return false;
-      }
-    }
-    for (int i = 0, j = rr; i < or; ++i, ++j) {
-      if (!parameterSubtype(r2s[j], o1s[i])) {
-        return false;
-      }
-    }
-    for (int i = or, j = 0; i < oo; ++i, ++j) {
-      if (!parameterSubtype(o2s[j], o1s[i])) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Check that [f1] is a subtype of [f2] where f1 and f2 are known
-   * to be generic function types (both have type parameters)
-   * [fuzzyArrows] indicates whether or not the f1 and f2 should be
-   * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
-   * as bottom).
-   */
-  bool _isGenericFunctionSubtypeOf(FunctionType f1, FunctionType f2,
-      {bool fuzzyArrows: true}) {
-    List<TypeParameterElement> params1 = f1.typeFormals;
-    List<TypeParameterElement> params2 = f2.typeFormals;
-    int count = params1.length;
-    if (params2.length != count) {
-      return false;
-    }
-    // We build up a substitution matching up the type parameters
-    // from the two types, {variablesFresh/variables1} and
-    // {variablesFresh/variables2}
-    List<DartType> variables1 = new List<DartType>();
-    List<DartType> variables2 = new List<DartType>();
-    List<DartType> variablesFresh = new List<DartType>();
-    for (int i = 0; i < count; i++) {
-      TypeParameterElement p1 = params1[i];
-      TypeParameterElement p2 = params2[i];
-      TypeParameterElementImpl pFresh =
-          new TypeParameterElementImpl(p2.name, -1);
-
-      DartType variable1 = p1.type;
-      DartType variable2 = p2.type;
-      DartType variableFresh = new TypeParameterTypeImpl(pFresh);
-
-      variables1.add(variable1);
-      variables2.add(variable2);
-      variablesFresh.add(variableFresh);
-      DartType bound1 = p1.bound ?? DynamicTypeImpl.instance;
-      DartType bound2 = p2.bound ?? DynamicTypeImpl.instance;
-      bound1 = bound1.substitute2(variablesFresh, variables1);
-      bound2 = bound2.substitute2(variablesFresh, variables2);
-      pFresh.bound = bound2;
-      if (!isSubtypeOf(bound2, bound1)) {
-        return false;
-      }
-    }
-    return _isFunctionSubtypeOf(
-        f1.instantiate(variablesFresh), f2.instantiate(variablesFresh),
-        fuzzyArrows: fuzzyArrows);
+  bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2) {
+    return FunctionTypeImpl.relate(
+        f1,
+        f2,
+        (DartType t1, DartType t2) =>
+            _isSubtypeOf(t2, t1, null, dynamicIsBottom: true),
+        instantiateToBounds,
+        returnRelation: isSubtypeOf);
   }
 
   bool _isInterfaceSubtypeOf(
@@ -563,6 +443,17 @@
  */
 abstract class TypeSystem {
   /**
+   * Returns `true` if we can promote to the first type from the second type.
+   *
+   * In the standard Dart type system, it is not possible to promote from or to
+   * `dynamic`, and we must be promoting to a more specific type, see
+   * [isMoreSpecificThan].
+   *
+   * In strong mode, this is equivalent to [isSubtypeOf].
+   */
+  bool canPromoteToType(DartType to, DartType from);
+
+  /**
    * Compute the least upper bound of two types.
    */
   DartType getLeastUpperBound(
@@ -584,6 +475,14 @@
   bool isAssignableTo(DartType leftType, DartType rightType);
 
   /**
+   * Return `true` if the [leftType] is more specific than the [rightType]
+   * (that is, if leftType << rightType), as defined in the Dart language spec.
+   *
+   * In strong mode, this is equivalent to [isSubtypeOf].
+   */
+  bool isMoreSpecificThan(DartType leftType, DartType rightType);
+
+  /**
    * Return `true` if the [leftType] is a subtype of the [rightType] (that is,
    * if leftType <: rightType).
    */
@@ -606,6 +505,14 @@
   TypeSystemImpl();
 
   @override
+  bool canPromoteToType(DartType to, DartType from) {
+    // Declared type should not be "dynamic".
+    // Promoted type should not be "dynamic".
+    // Promoted type should be more specific than declared.
+    return !from.isDynamic && !to.isDynamic && to.isMoreSpecificThan(from);
+  }
+
+  @override
   DartType getLeastUpperBound(
       TypeProvider typeProvider, DartType type1, DartType type2) {
     // The least upper bound relation is reflexive.
@@ -633,26 +540,12 @@
     if (type2.isBottom) {
       return type1;
     }
+
     // Let U be a type variable with upper bound B.  The least upper bound of U
     // and a type T is the least upper bound of B and T.
-    while (type1 is TypeParameterType) {
-      // TODO(paulberry): is this correct in the complex of F-bounded
-      // polymorphism?
-      DartType bound = (type1 as TypeParameterType).element.bound;
-      if (bound == null) {
-        bound = typeProvider.objectType;
-      }
-      type1 = bound;
-    }
-    while (type2 is TypeParameterType) {
-      // TODO(paulberry): is this correct in the context of F-bounded
-      // polymorphism?
-      DartType bound = (type2 as TypeParameterType).element.bound;
-      if (bound == null) {
-        bound = typeProvider.objectType;
-      }
-      type2 = bound;
-    }
+    type1 = type1.resolveToBound(typeProvider.objectType);
+    type2 = type2.resolveToBound(typeProvider.objectType);
+
     // The least upper bound of a function type and an interface type T is the
     // least upper bound of Function and T.
     if (type1 is FunctionType && type2 is InterfaceType) {
@@ -672,12 +565,7 @@
       }
       return result;
     } else if (type1 is FunctionType && type2 is FunctionType) {
-      FunctionType result =
-          FunctionTypeImpl.computeLeastUpperBound(type1, type2);
-      if (result == null) {
-        return typeProvider.functionType;
-      }
-      return result;
+      return _functionLeastUpperBound(typeProvider, type1, type2);
     } else {
       // Should never happen.  As a defensive measure, return the dynamic type.
       assert(false);
@@ -703,9 +591,91 @@
   }
 
   @override
+  bool isMoreSpecificThan(DartType t1, DartType t2) =>
+      t1.isMoreSpecificThan(t2);
+
+  @override
   bool isSubtypeOf(DartType leftType, DartType rightType) {
     return leftType.isSubtypeOf(rightType);
   }
+
+  /**
+   * Compute the least upper bound of function types [f] and [g].
+   *
+   * The spec rules for LUB on function types, informally, are pretty simple
+   * (though unsound):
+   *
+   * - If the functions don't have the same number of required parameters,
+   *   always return `Function`.
+   *
+   * - Discard any optional named or positional parameters the two types do not
+   *   have in common.
+   *
+   * - Compute the LUB of each corresponding pair of parameter and return types.
+   *   Return a function type with those types.
+   */
+  DartType _functionLeastUpperBound(
+      TypeProvider provider, FunctionType f, FunctionType g) {
+    // TODO(rnystrom): Right now, this assumes f and g do not have any type
+    // parameters. Revisit that in the presence of generic methods.
+    List<DartType> fRequired = f.normalParameterTypes;
+    List<DartType> gRequired = g.normalParameterTypes;
+
+    // We need some parameter names for in the synthesized function type, so
+    // arbitrarily use f's.
+    List<String> fRequiredNames = f.normalParameterNames;
+    List<String> fPositionalNames = f.optionalParameterNames;
+
+    // If F and G differ in their number of required parameters, then the
+    // least upper bound of F and G is Function.
+    if (fRequired.length != gRequired.length) {
+      return provider.functionType;
+    }
+
+    // Calculate the LUB of each corresponding pair of parameters.
+    List<ParameterElement> parameters = [];
+
+    for (int i = 0; i < fRequired.length; i++) {
+      parameters.add(new ParameterElementImpl.synthetic(
+          fRequiredNames[i],
+          getLeastUpperBound(provider, fRequired[i], gRequired[i]),
+          ParameterKind.REQUIRED));
+    }
+
+    List<DartType> fPositional = f.optionalParameterTypes;
+    List<DartType> gPositional = g.optionalParameterTypes;
+
+    // Ignore any extra optional positional parameters if one has more than the
+    // other.
+    int length = math.min(fPositional.length, gPositional.length);
+    for (int i = 0; i < length; i++) {
+      parameters.add(new ParameterElementImpl.synthetic(
+          fPositionalNames[i],
+          getLeastUpperBound(provider, fPositional[i], gPositional[i]),
+          ParameterKind.POSITIONAL));
+    }
+
+    Map<String, DartType> fNamed = f.namedParameterTypes;
+    Map<String, DartType> gNamed = g.namedParameterTypes;
+    for (String name in fNamed.keys.toSet()..retainAll(gNamed.keys)) {
+      parameters.add(new ParameterElementImpl.synthetic(
+          name,
+          getLeastUpperBound(provider, fNamed[name], gNamed[name]),
+          ParameterKind.NAMED));
+    }
+
+    // Calculate the LUB of the return type.
+    DartType returnType =
+        getLeastUpperBound(provider, f.returnType, g.returnType);
+
+    FunctionElementImpl function = new FunctionElementImpl("", -1);
+    function.synthetic = true;
+    function.returnType = returnType;
+    function.parameters = parameters;
+
+    function.type = new FunctionTypeImpl(function);
+    return function.type;
+  }
 }
 
 /// Tracks upper and lower type bounds for a set of type parameters.
@@ -714,13 +684,86 @@
   final Map<TypeParameterType, _TypeParameterBound> _bounds;
 
   _StrongInferenceTypeSystem(
-      this._typeProvider, Iterable<TypeParameterType> typeParams)
-      : _bounds = new Map.fromIterable(typeParams, value: (t) {
+      this._typeProvider, Iterable<TypeParameterElement> typeFormals)
+      : _bounds =
+            new Map.fromIterable(typeFormals, key: (t) => t.type, value: (t) {
           _TypeParameterBound bound = new _TypeParameterBound();
-          if (t.element.bound != null) bound.upper = t.element.bound;
+          if (t.bound != null) bound.upper = t.bound;
           return bound;
         });
 
+  /// Given the constraints that were given by calling [isSubtypeOf], find the
+  /// instantiation of the generic function that satisfies these constraints.
+  FunctionType _infer(FunctionType fnType, {bool allowPartialSolution: false}) {
+    List<TypeParameterType> fnTypeParams =
+        TypeParameterTypeImpl.getTypes(fnType.typeFormals);
+
+    var inferredTypes = new List<DartType>.from(fnTypeParams, growable: false);
+    for (int i = 0; i < fnTypeParams.length; i++) {
+      TypeParameterType typeParam = fnTypeParams[i];
+      _TypeParameterBound bound = _bounds[typeParam];
+
+      // Now we've computed lower and upper bounds for each type parameter.
+      //
+      // To decide on which type to assign, we look at the return type and see
+      // if the type parameter occurs in covariant or contravariant positions.
+      //
+      // If the type is "passed in" at all, or if our lower bound was bottom,
+      // we choose the upper bound as being the most useful.
+      //
+      // Otherwise we choose the more precise lower bound.
+      _TypeParameterVariance variance =
+          new _TypeParameterVariance.from(typeParam, fnType.returnType);
+
+      inferredTypes[i] =
+          variance.passedIn || bound.lower.isBottom ? bound.upper : bound.lower;
+
+      // Assumption: if the current type parameter has an "extends" clause
+      // that refers to another type variable we are inferring, it will appear
+      // before us or in this list position. For example:
+      //
+      //     <TFrom, TTo extends TFrom>
+      //
+      // We may infer TTo is TFrom. In that case, we already know what TFrom
+      // is inferred as, so we can substitute it now. This also handles more
+      // complex cases such as:
+      //
+      //     <TFrom, TTo extends Iterable<TFrom>>
+      //
+      // Or if the type parameter's bound depends on itself such as:
+      //
+      //     <T extends Clonable<T>>
+      inferredTypes[i] =
+          inferredTypes[i].substitute2(inferredTypes, fnTypeParams);
+
+      // See if the constraints on the type variable are satisfied.
+      //
+      // If not, bail out of the analysis, unless a partial solution was
+      // requested. If we are willing to accept a partial solution, fall back to
+      // the known upper bound (if any) or `dynamic` for this unsolvable type
+      // variable.
+      if (inferredTypes[i].isBottom ||
+          !isSubtypeOf(inferredTypes[i],
+              bound.upper.substitute2(inferredTypes, fnTypeParams)) ||
+          !isSubtypeOf(bound.lower.substitute2(inferredTypes, fnTypeParams),
+              inferredTypes[i])) {
+        // Unless a partial solution was requested, bail.
+        if (!allowPartialSolution) {
+          return null;
+        }
+
+        inferredTypes[i] = DynamicTypeImpl.instance;
+        if (typeParam.element.bound != null) {
+          inferredTypes[i] =
+              typeParam.element.bound.substitute2(inferredTypes, fnTypeParams);
+        }
+      }
+    }
+
+    // Return the instantiated type.
+    return fnType.instantiate(inferredTypes);
+  }
+
   @override
   bool _inferTypeParameterSubtypeOf(
       DartType t1, DartType t2, Set<Element> visited) {
diff --git a/pkg/analyzer/lib/src/generated/utilities_collection.dart b/pkg/analyzer/lib/src/generated/utilities_collection.dart
index 6a71b97..a1f6cd6 100644
--- a/pkg/analyzer/lib/src/generated/utilities_collection.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_collection.dart
@@ -7,8 +7,31 @@
 import 'dart:collection';
 import "dart:math" as math;
 
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/scanner.dart' show Token;
+
+/**
+ * Returns `true` if a and b contain equal elements in the same order.
+ */
+bool listsEqual(List a, List b) {
+  // TODO(rnystrom): package:collection also implements this, and analyzer
+  // already transitively depends on that package. Consider using it instead.
+  if (identical(a, b)) {
+    return true;
+  }
+
+  if (a.length != b.length) {
+    return false;
+  }
+
+  for (int i = 0; i < a.length; i++) {
+    if (a[i] != b[i]) {
+      return false;
+    }
+  }
+
+  return true;
+}
 
 /**
  * The class `BooleanArray` defines methods for operating on integers as if they were arrays
@@ -466,25 +489,6 @@
 }
 
 /**
- * The class `ListUtilities` defines utility methods useful for working with [List
- ].
- */
-class ListUtilities {
-  /**
-   * Add all of the elements in the given array to the given list.
-   *
-   * @param list the list to which the elements are to be added
-   * @param elements the elements to be added to the list
-   */
-  static void addAll(List list, List<Object> elements) {
-    int count = elements.length;
-    for (int i = 0; i < count; i++) {
-      list.add(elements[i]);
-    }
-  }
-}
-
-/**
  * The interface `MapIterator` defines the behavior of objects that iterate over the entries
  * in a map.
  *
diff --git a/pkg/analyzer/lib/src/generated/utilities_dart.dart b/pkg/analyzer/lib/src/generated/utilities_dart.dart
index 5fe5e72..695f75e 100644
--- a/pkg/analyzer/lib/src/generated/utilities_dart.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_dart.dart
@@ -4,9 +4,25 @@
 
 library analyzer.src.generated.utilities_dart;
 
+import 'package:analyzer/dart/ast/ast.dart' show AnnotatedNode, Comment;
+import 'package:analyzer/dart/ast/token.dart' show Token;
+import 'package:analyzer/src/generated/element.dart' show ElementImpl;
 import 'package:analyzer/src/generated/java_core.dart';
 
 /**
+ * If the given [node] has a documentation comment, remember its content
+ * and range into the given [element].
+ */
+void setElementDocumentationComment(ElementImpl element, AnnotatedNode node) {
+  Comment comment = node.documentationComment;
+  if (comment != null && comment.isDocumentation) {
+    element.documentationComment =
+        comment.tokens.map((Token t) => t.lexeme).join('\n');
+    element.setDocRange(comment.offset, comment.length);
+  }
+}
+
+/**
  * Check whether [uri1] starts with (or 'is prefixed by') [uri2] by checking
  * path segments.
  */
diff --git a/pkg/analyzer/lib/src/generated/utilities_general.dart b/pkg/analyzer/lib/src/generated/utilities_general.dart
index 1adc883..e0600dc 100644
--- a/pkg/analyzer/lib/src/generated/utilities_general.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_general.dart
@@ -20,6 +20,24 @@
     value is bool ? value : toLowerCase(value) == 'true';
 
 /**
+ * Safely convert the given [value] to a bool value, or return `null` if the
+ * value coult not be converted.
+ */
+bool toBool(Object value) {
+  if (value is bool) {
+    return value;
+  }
+  String string = toLowerCase(value);
+  if (string == 'true') {
+    return true;
+  }
+  if (string == 'false') {
+    return false;
+  }
+  return null;
+}
+
+/**
  * Safely convert this [value] to lower case, returning `null` if [value] is
  * null.
  */
diff --git a/pkg/analyzer/lib/src/generated/visitors.dart b/pkg/analyzer/lib/src/generated/visitors.dart
index 46e2a41..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/src/generated/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/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 07b0def..545064a 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/task/html.dart';
 import 'package:analyzer/src/task/html_work_manager.dart';
 import 'package:analyzer/src/task/options_work_manager.dart';
+import 'package:analyzer/src/task/yaml.dart';
 import 'package:analyzer/task/model.dart';
 import 'package:plugin/plugin.dart';
 
@@ -222,8 +223,7 @@
     registerExtension(taskId, ReadyLibraryElement5Task.DESCRIPTOR);
     registerExtension(taskId, ReadyLibraryElement6Task.DESCRIPTOR);
     registerExtension(taskId, ReadyResolvedUnitTask.DESCRIPTOR);
-    registerExtension(taskId, ReadyResolvedUnit10Task.DESCRIPTOR);
-    registerExtension(taskId, ReadyResolvedUnit11Task.DESCRIPTOR);
+    registerExtension(taskId, ResolveConstantExpressionTask.DESCRIPTOR);
     registerExtension(taskId, ResolveInstanceFieldsInUnitTask.DESCRIPTOR);
     registerExtension(taskId, ResolveLibraryReferencesTask.DESCRIPTOR);
     registerExtension(taskId, ResolveLibraryTask.DESCRIPTOR);
@@ -240,6 +240,10 @@
     registerExtension(taskId, DartScriptsTask.DESCRIPTOR);
     registerExtension(taskId, HtmlErrorsTask.DESCRIPTOR);
     registerExtension(taskId, ParseHtmlTask.DESCRIPTOR);
+    //
+    // Register YAML tasks.
+    //
+    registerExtension(taskId, ParseYamlTask.DESCRIPTOR);
   }
 
   void _registerWorkManagerFactoryExtensions(
diff --git a/pkg/analyzer/lib/src/services/lint.dart b/pkg/analyzer/lib/src/services/lint.dart
index 91d72a2..af20f59 100644
--- a/pkg/analyzer/lib/src/services/lint.dart
+++ b/pkg/analyzer/lib/src/services/lint.dart
@@ -4,11 +4,11 @@
 
 library analyzer.src.services.lint;
 
-import 'package:analyzer/src/generated/ast.dart';
+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 0c99e69..04eb0a3 100644
--- a/pkg/analyzer/lib/src/string_source.dart
+++ b/pkg/analyzer/lib/src/string_source.dart
@@ -7,44 +7,65 @@
 import 'package:analyzer/src/generated/engine.dart' show TimestampedData;
 import 'package:analyzer/src/generated/source.dart';
 
-/// An implementation of [Source] that's based on an in-memory Dart string.
+/**
+ * An implementation of [Source] that's based on an in-memory Dart string.
+ */
 class StringSource extends Source {
+  /**
+   * The content of the source.
+   */
   final String _contents;
+
+  @override
   final String fullName;
+
+  @override
+  final Uri uri;
+
+  @override
   final int modificationStamp;
 
-  StringSource(this._contents, this.fullName)
-      : modificationStamp = new DateTime.now().millisecondsSinceEpoch;
+  StringSource(this._contents, String fullName)
+      : this.fullName = fullName,
+        uri = fullName == null ? null : new Uri.file(fullName),
+        modificationStamp = new DateTime.now().millisecondsSinceEpoch;
 
+  @override
   TimestampedData<String> get contents =>
       new TimestampedData(modificationStamp, _contents);
 
-  String get encoding =>
-      throw new UnsupportedError("StringSource doesn't support " "encoding.");
+  @override
+  String get encoding => uri.toString();
 
+  @override
   int get hashCode => _contents.hashCode ^ fullName.hashCode;
 
+  @override
   bool get isInSystemLibrary => false;
 
+  @override
   String get shortName => fullName;
 
   @override
-  Uri get uri =>
-      throw new UnsupportedError("StringSource doesn't support uri.");
+  UriKind get uriKind => UriKind.FILE_URI;
 
-  UriKind get uriKind =>
-      throw new UnsupportedError("StringSource doesn't support " "uriKind.");
-
+  /**
+   * Return `true` if the given [object] is a string source that is equal to
+   * this source.
+   */
+  @override
   bool operator ==(Object object) {
-    if (object is StringSource) {
-      StringSource ssObject = object;
-      return ssObject._contents == _contents && ssObject.fullName == fullName;
-    }
-    return false;
+    return object is StringSource &&
+        object._contents == _contents &&
+        object.fullName == fullName;
   }
 
+  @override
   bool exists() => true;
 
-  Uri resolveRelativeUri(Uri relativeUri) => throw new UnsupportedError(
-      "StringSource doesn't support resolveRelative.");
+  @override
+  Uri resolveRelativeUri(Uri relativeUri) => uri.resolveUri(relativeUri);
+
+  @override
+  String toString() => 'StringSource ($fullName)';
 }
diff --git a/pkg/analyzer/lib/src/summary/base.dart b/pkg/analyzer/lib/src/summary/base.dart
index a04476b..acdb839 100644
--- a/pkg/analyzer/lib/src/summary/base.dart
+++ b/pkg/analyzer/lib/src/summary/base.dart
@@ -8,6 +8,35 @@
 library analyzer.src.summary.base;
 
 /**
+ * Annotation used in the summary IDL to indicate the id of a field.  The set
+ * of ids used by a class must cover the contiguous range from 0 to N-1, where
+ * N is the number of fields.
+ *
+ * In order to preserve forwards and backwards compatibility, id numbers must
+ * be stable between releases.  So when new fields are added they should take
+ * the next available id without renumbering other fields.
+ */
+class Id {
+  final int value;
+
+  const Id(this.value);
+}
+
+/**
+ * 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 {
@@ -18,4 +47,15 @@
    * Intended for testing and debugging only.
    */
   Map<String, Object> toMap();
+
+  /**
+   * Translate the data in this class into a JSON map, whose keys are the names
+   * of fields and whose values are the data stored in those fields,
+   * recursively converted into JSON.
+   *
+   * Fields containing their default value are elided.
+   *
+   * Intended for testing and debugging only.
+   */
+  Map<String, Object> toJson();
 }
diff --git a/pkg/analyzer/lib/src/summary/flat_buffers.dart b/pkg/analyzer/lib/src/summary/flat_buffers.dart
index 3c7de13..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> {
@@ -49,6 +64,9 @@
     return new BufferPointer._(_buffer, _offset + delta);
   }
 
+  double _getFloat64([int delta = 0]) =>
+      _buffer.getFloat64(_offset + delta, Endianness.LITTLE_ENDIAN);
+
   int _getInt32([int delta = 0]) =>
       _buffer.getInt32(_offset + delta, Endianness.LITTLE_ENDIAN);
 
@@ -60,6 +78,8 @@
   int _getUint32([int delta = 0]) =>
       _buffer.getUint32(_offset + delta, Endianness.LITTLE_ENDIAN);
 
+  int _getUint8([int delta = 0]) => _buffer.getUint8(_offset + delta);
+
   /**
    * If the [byteList] is already a [Uint8List] return it.
    * Otherwise return a [Uint8List] copy of the [byteList].
@@ -107,6 +127,12 @@
 
   _VTable _currentVTable;
 
+  /**
+   * Map containing all strings that have been written so far.  This allows us
+   * to avoid duplicating strings.
+   */
+  Map<String, Offset<String>> _strings = <String, Offset<String>>{};
+
   Builder({this.initialSize: 1024}) {
     reset();
   }
@@ -117,9 +143,7 @@
    * `0` for `false` and `1` for `true`.
    */
   void addBool(int field, bool value, [bool def]) {
-    if (_currentVTable == null) {
-      throw new StateError('Start a table before adding values.');
-    }
+    _ensureCurrentVTable();
     if (value != null && value != def) {
       int size = 1;
       _prepare(size, 1);
@@ -133,9 +157,7 @@
    * not added if the [value] is equal to [def].
    */
   void addInt32(int field, int value, [int def]) {
-    if (_currentVTable == null) {
-      throw new StateError('Start a table before adding values.');
-    }
+    _ensureCurrentVTable();
     if (value != null && value != def) {
       int size = 4;
       _prepare(size, 1);
@@ -149,9 +171,7 @@
    * not added if the [value] is equal to [def].
    */
   void addInt8(int field, int value, [int def]) {
-    if (_currentVTable == null) {
-      throw new StateError('Start a table before adding values.');
-    }
+    _ensureCurrentVTable();
     if (value != null && value != def) {
       int size = 1;
       _prepare(size, 1);
@@ -164,9 +184,7 @@
    * Add the [field] referencing an object with the given [offset].
    */
   void addOffset(int field, Offset offset) {
-    if (_currentVTable == null) {
-      throw new StateError('Start a table before adding values.');
-    }
+    _ensureCurrentVTable();
     if (offset != null) {
       _prepare(4, 1);
       _trackField(field);
@@ -175,17 +193,45 @@
   }
 
   /**
+   * Add the [field] with the given 32-bit unsigned integer [value].  The field
+   * is not added if the [value] is equal to [def].
+   */
+  void addUint32(int field, int value, [int def]) {
+    _ensureCurrentVTable();
+    if (value != null && value != def) {
+      int size = 4;
+      _prepare(size, 1);
+      _trackField(field);
+      _setUint32AtTail(_buf, _tail, value);
+    }
+  }
+
+  /**
+   * Add the [field] with the given 8-bit unsigned integer [value].  The field
+   * is not added if the [value] is equal to [def].
+   */
+  void addUint8(int field, int value, [int def]) {
+    _ensureCurrentVTable();
+    if (value != null && value != def) {
+      int size = 1;
+      _prepare(size, 1);
+      _trackField(field);
+      _setUint8AtTail(_buf, _tail, value);
+    }
+  }
+
+  /**
    * End the current table and return its offset.
    */
   Offset endTable() {
     if (_currentVTable == null) {
       throw new StateError('Start a table before ending it.');
     }
-    // Prepare the size of the current table.
-    _currentVTable.tableSize = _tail - _currentTableEndTail;
     // Prepare for writing the VTable.
     _prepare(4, 1);
     int tableTail = _tail;
+    // Prepare the size of the current table.
+    _currentVTable.tableSize = tableTail - _currentTableEndTail;
     // Prepare the VTable to use for the current table.
     int vTableTail;
     {
@@ -215,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);
   }
 
@@ -282,10 +336,7 @@
    * Write the given list of [values].
    */
   Offset writeList(List<Offset> values) {
-    if (_currentVTable != null) {
-      throw new StateError(
-          'Cannot write a non-scalar value while writing a table.');
-    }
+    _ensureNoVTable();
     _prepare(4, 1 + values.length);
     Offset result = new Offset(_tail);
     int tail = _tail;
@@ -299,13 +350,59 @@
   }
 
   /**
+   * 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) {
+    _ensureNoVTable();
+    _prepare(8, 1 + values.length);
+    Offset result = new Offset(_tail);
+    int tail = _tail;
+    _setUint32AtTail(_buf, tail, values.length);
+    tail -= 8;
+    for (double value in values) {
+      _setFloat64AtTail(_buf, tail, value);
+      tail -= 8;
+    }
+    return result;
+  }
+
+  /**
    * Write the given list of signed 32-bit integer [values].
    */
   Offset writeListInt32(List<int> values) {
-    if (_currentVTable != null) {
-      throw new StateError(
-          'Cannot write a non-scalar value while writing a table.');
-    }
+    _ensureNoVTable();
     _prepare(4, 1 + values.length);
     Offset result = new Offset(_tail);
     int tail = _tail;
@@ -319,28 +416,80 @@
   }
 
   /**
+   * Write the given list of unsigned 32-bit integer [values].
+   */
+  Offset writeListUint32(List<int> values) {
+    _ensureNoVTable();
+    _prepare(4, 1 + values.length);
+    Offset result = new Offset(_tail);
+    int tail = _tail;
+    _setUint32AtTail(_buf, tail, values.length);
+    tail -= 4;
+    for (int value in values) {
+      _setUint32AtTail(_buf, tail, value);
+      tail -= 4;
+    }
+    return result;
+  }
+
+  /**
+   * Write the given list of unsigned 8-bit integer [values].
+   */
+  Offset writeListUint8(List<int> values) {
+    _ensureNoVTable();
+    _prepare(4, 1, additionalBytes: values.length);
+    Offset result = new Offset(_tail);
+    int tail = _tail;
+    _setUint32AtTail(_buf, tail, values.length);
+    tail -= 4;
+    for (int value in values) {
+      _setUint8AtTail(_buf, tail, value);
+      tail -= 1;
+    }
+    return result;
+  }
+
+  /**
    * Write the given string [value] and return its [Offset], or `null` if
    * the [value] is equal to [def].
    */
   Offset<String> writeString(String value, [String def]) {
+    _ensureNoVTable();
+    if (value != def) {
+      return _strings.putIfAbsent(value, () {
+        // TODO(scheglov) optimize for ASCII strings
+        List<int> bytes = UTF8.encode(value);
+        int length = bytes.length;
+        _prepare(4, 1, additionalBytes: length);
+        Offset<String> result = new Offset(_tail);
+        _setUint32AtTail(_buf, _tail, length);
+        int offset = _buf.lengthInBytes - _tail + 4;
+        for (int i = 0; i < length; i++) {
+          _buf.setUint8(offset++, bytes[i]);
+        }
+        return result;
+      });
+    }
+    return null;
+  }
+
+  /**
+   * Throw an exception if there is not currently a vtable.
+   */
+  void _ensureCurrentVTable() {
+    if (_currentVTable == null) {
+      throw new StateError('Start a table before adding values.');
+    }
+  }
+
+  /**
+   * Throw an exception if there is currently a vtable.
+   */
+  void _ensureNoVTable() {
     if (_currentVTable != null) {
       throw new StateError(
           'Cannot write a non-scalar value while writing a table.');
     }
-    if (value != def) {
-      // TODO(scheglov) optimize for ASCII strings
-      List<int> bytes = UTF8.encode(value);
-      int length = bytes.length;
-      _prepare(4, 1, additionalBytes: length);
-      Offset<String> result = new Offset(_tail);
-      _setUint32AtTail(_buf, _tail, length);
-      int offset = _buf.lengthInBytes - _tail + 4;
-      for (int i = 0; i < length; i++) {
-        _buf.setUint8(offset++, bytes[i]);
-      }
-      return result;
-    }
-    return null;
   }
 
   /**
@@ -383,6 +532,10 @@
     _currentVTable.addField(field, _tail);
   }
 
+  static void _setFloat64AtTail(ByteData _buf, int tail, double x) {
+    _buf.setFloat64(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
+  }
+
   static void _setInt32AtTail(ByteData _buf, int tail, int x) {
     _buf.setInt32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
   }
@@ -390,10 +543,29 @@
   static void _setUint32AtTail(ByteData _buf, int tail, int x) {
     _buf.setUint32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
   }
+
+  static void _setUint8AtTail(ByteData _buf, int tail, int x) {
+    _buf.setUint8(_buf.lengthInBytes - tail, x);
+  }
 }
 
 /**
- * The reader of 32-bit signed integers.
+ * The reader of lists of 64-bit float values.
+ *
+ * The returned unmodifiable lists lazily read values on access.
+ */
+class Float64ListReader extends Reader<List<double>> {
+  const Float64ListReader();
+
+  @override
+  int get size => 4;
+
+  @override
+  List<double> read(BufferPointer bp) => new _FbFloat64List(bp.derefObject());
+}
+
+/**
+ * The reader of signed 32-bit integers.
  */
 class Int32Reader extends Reader<int> {
   const Int32Reader() : super();
@@ -433,7 +605,7 @@
 
   @override
   List<E> read(BufferPointer bp) =>
-      new _FbList<E>(_elementReader, bp.derefObject());
+      new _FbGenericList<E>(_elementReader, bp.derefObject());
 }
 
 /**
@@ -519,18 +691,62 @@
   }
 }
 
-class _FbList<E> extends Object with ListMixin<E> implements List<E> {
-  final Reader<E> elementReader;
-  final BufferPointer bp;
+/**
+ * Reader of lists of unsigned 32-bit integer values.
+ *
+ * The returned unmodifiable lists lazily read values on access.
+ */
+class Uint32ListReader extends Reader<List<int>> {
+  const Uint32ListReader();
 
+  @override
+  int get size => 4;
+
+  @override
+  List<int> read(BufferPointer bp) => new _FbUint32List(bp.derefObject());
+}
+
+/**
+ * The reader of unsigned 32-bit integers.
+ */
+class Uint32Reader extends Reader<int> {
+  const Uint32Reader() : super();
+
+  @override
+  int get size => 4;
+
+  @override
+  int read(BufferPointer bp) => bp._getUint32();
+}
+
+/**
+ * The reader of unsigned 8-bit integers.
+ */
+class Uint8Reader extends Reader<int> {
+  const Uint8Reader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  int read(BufferPointer bp) => bp._getUint8();
+}
+
+/**
+ * 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;
-  List<E> _items;
 
-  _FbList(this.elementReader, this.bp);
+  _FbBoolList(BufferPointer bp)
+      : uint8List = new _FbGenericList<int>(const Uint8Reader(), bp);
 
   @override
   int get length {
-    _length ??= bp._getUint32();
+    if (_length == null) {
+      _length = (uint8List.length - 1) * 8 - uint8List.last;
+    }
     return _length;
   }
 
@@ -539,6 +755,49 @@
       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> {
+  List<double> _items;
+
+  _FbFloat64List(BufferPointer bp) : super(bp);
+
+  @override
+  double operator [](int i) {
+    _items ??= new List<double>(length);
+    double item = _items[i];
+    if (item == null) {
+      BufferPointer ref = bp._advance(8 + 8 * i);
+      item = ref._getFloat64();
+      _items[i] = item;
+    }
+    return item;
+  }
+}
+
+/**
+ * List backed by a generic object which may have any size.
+ */
+class _FbGenericList<E> extends _FbList<E> {
+  final Reader<E> elementReader;
+
+  List<E> _items;
+
+  _FbGenericList(this.elementReader, BufferPointer bp) : super(bp);
+
+  @override
   E operator [](int i) {
     _items ??= new List<E>(length);
     E item = _items[i];
@@ -549,6 +808,26 @@
     }
     return item;
   }
+}
+
+/**
+ * The base class for immutable lists read from flat buffers.
+ */
+abstract class _FbList<E> extends Object with ListMixin<E> implements List<E> {
+  final BufferPointer bp;
+  int _length;
+
+  _FbList(this.bp);
+
+  @override
+  int get length {
+    _length ??= bp._getUint32();
+    return _length;
+  }
+
+  @override
+  void set length(int i) =>
+      throw new StateError('Attempt to modify immutable list');
 
   @override
   void operator []=(int i, E e) =>
@@ -556,6 +835,26 @@
 }
 
 /**
+ * List backed by 32-bit unsigned integers.
+ */
+class _FbUint32List extends _FbList<int> {
+  List<int> _items;
+
+  _FbUint32List(BufferPointer bp) : super(bp);
+
+  @override
+  int operator [](int i) {
+    _items ??= new List<int>(length);
+    int item = _items[i];
+    if (item == null) {
+      item = bp._getUint32(4 + 4 * i);
+      _items[i] = item;
+    }
+    return item;
+  }
+}
+
+/**
  * Class that describes the structure of a table.
  */
 class _VTable {
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 97f9db6..e5c4630 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -7,3768 +7,159 @@
 
 library analyzer.src.summary.format;
 
-import 'base.dart' as base;
 import 'flat_buffers.dart' as fb;
+import 'idl.dart' as idl;
+import 'dart:convert' as convert;
 
-/**
- * Enum used to indicate the kind of entity referred to by a
- * [PrelinkedReference].
- */
-enum PrelinkedReferenceKind {
-  classOrEnum,
-  typedef,
-  other,
-  prefix,
-  unresolved,
+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;
+  }
 }
 
-/**
- * Enum used to indicate the kind of an executable.
- */
-enum UnlinkedExecutableKind {
-  functionOrMethod,
-  getter,
-  setter,
-  constructor,
+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;
+  }
 }
 
-/**
- * Enum used to indicate the kind of a parameter.
- */
-enum UnlinkedParamKind {
-  required,
-  positional,
-  named,
+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 PrelinkedDependencyBuilder {
+class _ReferenceKindReader extends fb.Reader<idl.ReferenceKind> {
+  const _ReferenceKindReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.ReferenceKind read(fb.BufferPointer bp) {
+    int index = const fb.Uint8Reader().read(bp);
+    return index < idl.ReferenceKind.values.length ? idl.ReferenceKind.values[index] : idl.ReferenceKind.classOrEnum;
+  }
+}
+
+class _UnlinkedConstOperationReader extends fb.Reader<idl.UnlinkedConstOperation> {
+  const _UnlinkedConstOperationReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.UnlinkedConstOperation read(fb.BufferPointer bp) {
+    int index = const fb.Uint8Reader().read(bp);
+    return index < idl.UnlinkedConstOperation.values.length ? idl.UnlinkedConstOperation.values[index] : idl.UnlinkedConstOperation.pushInt;
+  }
+}
+
+class _UnlinkedConstructorInitializerKindReader extends fb.Reader<idl.UnlinkedConstructorInitializerKind> {
+  const _UnlinkedConstructorInitializerKindReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.UnlinkedConstructorInitializerKind read(fb.BufferPointer bp) {
+    int index = const fb.Uint8Reader().read(bp);
+    return index < idl.UnlinkedConstructorInitializerKind.values.length ? idl.UnlinkedConstructorInitializerKind.values[index] : idl.UnlinkedConstructorInitializerKind.field;
+  }
+}
+
+class _UnlinkedExecutableKindReader extends fb.Reader<idl.UnlinkedExecutableKind> {
+  const _UnlinkedExecutableKindReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.UnlinkedExecutableKind read(fb.BufferPointer bp) {
+    int index = const fb.Uint8Reader().read(bp);
+    return index < idl.UnlinkedExecutableKind.values.length ? idl.UnlinkedExecutableKind.values[index] : idl.UnlinkedExecutableKind.functionOrMethod;
+  }
+}
+
+class _UnlinkedParamKindReader extends fb.Reader<idl.UnlinkedParamKind> {
+  const _UnlinkedParamKindReader() : super();
+
+  @override
+  int get size => 1;
+
+  @override
+  idl.UnlinkedParamKind read(fb.BufferPointer bp) {
+    int index = const fb.Uint8Reader().read(bp);
+    return index < idl.UnlinkedParamKind.values.length ? idl.UnlinkedParamKind.values[index] : idl.UnlinkedParamKind.required;
+  }
+}
+
+class EntityRefBuilder extends Object with _EntityRefMixin implements idl.EntityRef {
   bool _finished = false;
 
-  String _uri;
-  List<String> _parts;
-
-  PrelinkedDependencyBuilder();
-
-  /**
-   * 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`.
-   */
-  void set uri(String _value) {
-    assert(!_finished);
-    _uri = _value;
-  }
-
-  /**
-   * URI for the compilation units listed in the library's `part` declarations.
-   * These URIs are relative to the importing library.
-   */
-  void set parts(List<String> _value) {
-    assert(!_finished);
-    _parts = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_uri;
-    fb.Offset offset_parts;
-    if (_uri != null) {
-      offset_uri = fbBuilder.writeString(_uri);
-    }
-    if (!(_parts == null || _parts.isEmpty)) {
-      offset_parts = fbBuilder.writeList(_parts.map((b) => fbBuilder.writeString(b)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_uri != null) {
-      fbBuilder.addOffset(0, offset_uri);
-    }
-    if (offset_parts != null) {
-      fbBuilder.addOffset(1, offset_parts);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-PrelinkedDependencyBuilder encodePrelinkedDependency({String uri, List<String> parts}) {
-  PrelinkedDependencyBuilder builder = new PrelinkedDependencyBuilder();
-  builder.uri = uri;
-  builder.parts = parts;
-  return builder;
-}
-
-/**
- * Information about a dependency that exists between one library and another
- * due to an "import" declaration.
- */
-abstract class PrelinkedDependency extends base.SummaryClass {
-
-  /**
-   * 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`.
-   */
-  String get uri;
-
-  /**
-   * URI for the compilation units listed in the library's `part` declarations.
-   * These URIs are relative to the importing library.
-   */
-  List<String> get parts;
-}
-
-class _PrelinkedDependencyReader extends fb.TableReader<_PrelinkedDependencyImpl> {
-  const _PrelinkedDependencyReader();
-
-  @override
-  _PrelinkedDependencyImpl createObject(fb.BufferPointer bp) => new _PrelinkedDependencyImpl(bp);
-}
-
-class _PrelinkedDependencyImpl implements PrelinkedDependency {
-  final fb.BufferPointer _bp;
-
-  _PrelinkedDependencyImpl(this._bp);
-
-  String _uri;
-  List<String> _parts;
-
-  @override
-  Map<String, Object> toMap() => {
-    "uri": uri,
-    "parts": parts,
-  };
-
-  @override
-  String get uri {
-    _uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _uri;
-  }
-
-  @override
-  List<String> get parts {
-    _parts ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
-    return _parts;
-  }
-}
-
-class PrelinkedLibraryBuilder {
-  bool _finished = false;
-
-  List<PrelinkedUnitBuilder> _units;
-  List<PrelinkedDependencyBuilder> _dependencies;
-  List<int> _importDependencies;
-
-  PrelinkedLibraryBuilder();
-
-  /**
-   * The pre-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.
-   */
-  void set units(List<PrelinkedUnitBuilder> _value) {
-    assert(!_finished);
-    _units = _value;
-  }
-
-  /**
-   * 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").
-   *
-   * TODO(paulberry): consider removing this entirely and just using
-   * [UnlinkedLibrary.imports].
-   */
-  void set dependencies(List<PrelinkedDependencyBuilder> _value) {
-    assert(!_finished);
-    _dependencies = _value;
-  }
-
-  /**
-   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
-   * of the library being imported.
-   *
-   * TODO(paulberry): if [dependencies] is removed, this can be removed as
-   * well, since there will effectively be a one-to-one mapping.
-   */
-  void set importDependencies(List<int> _value) {
-    assert(!_finished);
-    _importDependencies = _value;
-  }
-
-  List<int> toBuffer() {
-    fb.Builder fbBuilder = new fb.Builder();
-    return fbBuilder.finish(finish(fbBuilder));
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_units;
-    fb.Offset offset_dependencies;
-    fb.Offset offset_importDependencies;
-    if (!(_units == null || _units.isEmpty)) {
-      offset_units = fbBuilder.writeList(_units.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_dependencies == null || _dependencies.isEmpty)) {
-      offset_dependencies = fbBuilder.writeList(_dependencies.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_importDependencies == null || _importDependencies.isEmpty)) {
-      offset_importDependencies = fbBuilder.writeListInt32(_importDependencies);
-    }
-    fbBuilder.startTable();
-    if (offset_units != null) {
-      fbBuilder.addOffset(0, offset_units);
-    }
-    if (offset_dependencies != null) {
-      fbBuilder.addOffset(1, offset_dependencies);
-    }
-    if (offset_importDependencies != null) {
-      fbBuilder.addOffset(2, offset_importDependencies);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-PrelinkedLibraryBuilder encodePrelinkedLibrary({List<PrelinkedUnitBuilder> units, List<PrelinkedDependencyBuilder> dependencies, List<int> importDependencies}) {
-  PrelinkedLibraryBuilder builder = new PrelinkedLibraryBuilder();
-  builder.units = units;
-  builder.dependencies = dependencies;
-  builder.importDependencies = importDependencies;
-  return builder;
-}
-
-/**
- * Pre-linked summary of a library.
- */
-abstract class PrelinkedLibrary extends base.SummaryClass {
-  factory PrelinkedLibrary.fromBuffer(List<int> buffer) {
-    fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
-    return const _PrelinkedLibraryReader().read(rootRef);
-  }
-
-  /**
-   * The pre-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.
-   */
-  List<PrelinkedUnit> get units;
-
-  /**
-   * 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").
-   *
-   * TODO(paulberry): consider removing this entirely and just using
-   * [UnlinkedLibrary.imports].
-   */
-  List<PrelinkedDependency> get dependencies;
-
-  /**
-   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
-   * of the library being imported.
-   *
-   * TODO(paulberry): if [dependencies] is removed, this can be removed as
-   * well, since there will effectively be a one-to-one mapping.
-   */
-  List<int> get importDependencies;
-}
-
-class _PrelinkedLibraryReader extends fb.TableReader<_PrelinkedLibraryImpl> {
-  const _PrelinkedLibraryReader();
-
-  @override
-  _PrelinkedLibraryImpl createObject(fb.BufferPointer bp) => new _PrelinkedLibraryImpl(bp);
-}
-
-class _PrelinkedLibraryImpl implements PrelinkedLibrary {
-  final fb.BufferPointer _bp;
-
-  _PrelinkedLibraryImpl(this._bp);
-
-  List<PrelinkedUnit> _units;
-  List<PrelinkedDependency> _dependencies;
-  List<int> _importDependencies;
-
-  @override
-  Map<String, Object> toMap() => {
-    "units": units,
-    "dependencies": dependencies,
-    "importDependencies": importDependencies,
-  };
-
-  @override
-  List<PrelinkedUnit> get units {
-    _units ??= const fb.ListReader<PrelinkedUnit>(const _PrelinkedUnitReader()).vTableGet(_bp, 0, const <PrelinkedUnit>[]);
-    return _units;
-  }
-
-  @override
-  List<PrelinkedDependency> get dependencies {
-    _dependencies ??= const fb.ListReader<PrelinkedDependency>(const _PrelinkedDependencyReader()).vTableGet(_bp, 1, const <PrelinkedDependency>[]);
-    return _dependencies;
-  }
-
-  @override
-  List<int> get importDependencies {
-    _importDependencies ??= const fb.ListReader<int>(const fb.Int32Reader()).vTableGet(_bp, 2, const <int>[]);
-    return _importDependencies;
-  }
-}
-
-class PrelinkedReferenceBuilder {
-  bool _finished = false;
-
-  int _dependency;
-  PrelinkedReferenceKind _kind;
-  int _unit;
-  int _numTypeParameters;
-
-  PrelinkedReferenceBuilder();
-
-  /**
-   * Index into [PrelinkedLibrary.dependencies] indicating which imported library
-   * declares the entity being referred to.
-   */
-  void set dependency(int _value) {
-    assert(!_finished);
-    _dependency = _value;
-  }
-
-  /**
-   * The kind of the entity being referred to.  For the pseudo-type `dynamic`,
-   * the kind is [PrelinkedReferenceKind.classOrEnum].
-   */
-  void set kind(PrelinkedReferenceKind _value) {
-    assert(!_finished);
-    _kind = _value;
-  }
-
-  /**
-   * Integer index indicating which unit in the imported library contains the
-   * definition of the entity.  As with indices into [PrelinkedLibrary.units],
-   * zero represents the defining compilation unit, and nonzero values
-   * represent parts in the order of the corresponding `part` declarations.
-   */
-  void set unit(int _value) {
-    assert(!_finished);
-    _unit = _value;
-  }
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  void set numTypeParameters(int _value) {
-    assert(!_finished);
-    _numTypeParameters = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fbBuilder.startTable();
-    if (_dependency != null && _dependency != 0) {
-      fbBuilder.addInt32(0, _dependency);
-    }
-    if (_kind != null && _kind != PrelinkedReferenceKind.classOrEnum) {
-      fbBuilder.addInt32(1, _kind.index);
-    }
-    if (_unit != null && _unit != 0) {
-      fbBuilder.addInt32(2, _unit);
-    }
-    if (_numTypeParameters != null && _numTypeParameters != 0) {
-      fbBuilder.addInt32(3, _numTypeParameters);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-PrelinkedReferenceBuilder encodePrelinkedReference({int dependency, PrelinkedReferenceKind kind, int unit, int numTypeParameters}) {
-  PrelinkedReferenceBuilder builder = new PrelinkedReferenceBuilder();
-  builder.dependency = dependency;
-  builder.kind = kind;
-  builder.unit = unit;
-  builder.numTypeParameters = numTypeParameters;
-  return builder;
-}
-
-/**
- * Information about the resolution of an [UnlinkedReference].
- */
-abstract class PrelinkedReference extends base.SummaryClass {
-
-  /**
-   * Index into [PrelinkedLibrary.dependencies] indicating which imported library
-   * declares the entity being referred to.
-   */
-  int get dependency;
-
-  /**
-   * The kind of the entity being referred to.  For the pseudo-type `dynamic`,
-   * the kind is [PrelinkedReferenceKind.classOrEnum].
-   */
-  PrelinkedReferenceKind get kind;
-
-  /**
-   * Integer index indicating which unit in the imported library contains the
-   * definition of the entity.  As with indices into [PrelinkedLibrary.units],
-   * zero represents the defining compilation unit, and nonzero values
-   * represent parts in the order of the corresponding `part` declarations.
-   */
-  int get unit;
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  int get numTypeParameters;
-}
-
-class _PrelinkedReferenceReader extends fb.TableReader<_PrelinkedReferenceImpl> {
-  const _PrelinkedReferenceReader();
-
-  @override
-  _PrelinkedReferenceImpl createObject(fb.BufferPointer bp) => new _PrelinkedReferenceImpl(bp);
-}
-
-class _PrelinkedReferenceImpl implements PrelinkedReference {
-  final fb.BufferPointer _bp;
-
-  _PrelinkedReferenceImpl(this._bp);
-
-  int _dependency;
-  PrelinkedReferenceKind _kind;
-  int _unit;
-  int _numTypeParameters;
-
-  @override
-  Map<String, Object> toMap() => {
-    "dependency": dependency,
-    "kind": kind,
-    "unit": unit,
-    "numTypeParameters": numTypeParameters,
-  };
-
-  @override
-  int get dependency {
-    _dependency ??= const fb.Int32Reader().vTableGet(_bp, 0, 0);
-    return _dependency;
-  }
-
-  @override
-  PrelinkedReferenceKind get kind {
-    _kind ??= PrelinkedReferenceKind.values[const fb.Int32Reader().vTableGet(_bp, 1, 0)];
-    return _kind;
-  }
-
-  @override
-  int get unit {
-    _unit ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
-    return _unit;
-  }
-
-  @override
-  int get numTypeParameters {
-    _numTypeParameters ??= const fb.Int32Reader().vTableGet(_bp, 3, 0);
-    return _numTypeParameters;
-  }
-}
-
-class PrelinkedUnitBuilder {
-  bool _finished = false;
-
-  List<PrelinkedReferenceBuilder> _references;
-
-  PrelinkedUnitBuilder();
-
-  /**
-   * For each reference in [UnlinkedUnit.references], information about how
-   * that reference is resolved.
-   */
-  void set references(List<PrelinkedReferenceBuilder> _value) {
-    assert(!_finished);
-    _references = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_references;
-    if (!(_references == null || _references.isEmpty)) {
-      offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_references != null) {
-      fbBuilder.addOffset(0, offset_references);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-PrelinkedUnitBuilder encodePrelinkedUnit({List<PrelinkedReferenceBuilder> references}) {
-  PrelinkedUnitBuilder builder = new PrelinkedUnitBuilder();
-  builder.references = references;
-  return builder;
-}
-
-/**
- * Pre-linked summary of a compilation unit.
- */
-abstract class PrelinkedUnit extends base.SummaryClass {
-
-  /**
-   * For each reference in [UnlinkedUnit.references], information about how
-   * that reference is resolved.
-   */
-  List<PrelinkedReference> get references;
-}
-
-class _PrelinkedUnitReader extends fb.TableReader<_PrelinkedUnitImpl> {
-  const _PrelinkedUnitReader();
-
-  @override
-  _PrelinkedUnitImpl createObject(fb.BufferPointer bp) => new _PrelinkedUnitImpl(bp);
-}
-
-class _PrelinkedUnitImpl implements PrelinkedUnit {
-  final fb.BufferPointer _bp;
-
-  _PrelinkedUnitImpl(this._bp);
-
-  List<PrelinkedReference> _references;
-
-  @override
-  Map<String, Object> toMap() => {
-    "references": references,
-  };
-
-  @override
-  List<PrelinkedReference> get references {
-    _references ??= const fb.ListReader<PrelinkedReference>(const _PrelinkedReferenceReader()).vTableGet(_bp, 0, const <PrelinkedReference>[]);
-    return _references;
-  }
-}
-
-class SdkBundleBuilder {
-  bool _finished = false;
-
-  List<String> _prelinkedLibraryUris;
-  List<PrelinkedLibraryBuilder> _prelinkedLibraries;
-  List<String> _unlinkedUnitUris;
-  List<UnlinkedUnitBuilder> _unlinkedUnits;
-
-  SdkBundleBuilder();
-
-  /**
-   * The list of URIs of items in [prelinkedLibraries], e.g. `dart:core`.
-   */
-  void set prelinkedLibraryUris(List<String> _value) {
-    assert(!_finished);
-    _prelinkedLibraryUris = _value;
-  }
-
-  /**
-   * Pre-linked libraries.
-   */
-  void set prelinkedLibraries(List<PrelinkedLibraryBuilder> _value) {
-    assert(!_finished);
-    _prelinkedLibraries = _value;
-  }
-
-  /**
-   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
-   */
-  void set unlinkedUnitUris(List<String> _value) {
-    assert(!_finished);
-    _unlinkedUnitUris = _value;
-  }
-
-  /**
-   * Unlinked information for the compilation units constituting the SDK.
-   */
-  void set unlinkedUnits(List<UnlinkedUnitBuilder> _value) {
-    assert(!_finished);
-    _unlinkedUnits = _value;
-  }
-
-  List<int> toBuffer() {
-    fb.Builder fbBuilder = new fb.Builder();
-    return fbBuilder.finish(finish(fbBuilder));
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_prelinkedLibraryUris;
-    fb.Offset offset_prelinkedLibraries;
-    fb.Offset offset_unlinkedUnitUris;
-    fb.Offset offset_unlinkedUnits;
-    if (!(_prelinkedLibraryUris == null || _prelinkedLibraryUris.isEmpty)) {
-      offset_prelinkedLibraryUris = fbBuilder.writeList(_prelinkedLibraryUris.map((b) => fbBuilder.writeString(b)).toList());
-    }
-    if (!(_prelinkedLibraries == null || _prelinkedLibraries.isEmpty)) {
-      offset_prelinkedLibraries = fbBuilder.writeList(_prelinkedLibraries.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_unlinkedUnitUris == null || _unlinkedUnitUris.isEmpty)) {
-      offset_unlinkedUnitUris = fbBuilder.writeList(_unlinkedUnitUris.map((b) => fbBuilder.writeString(b)).toList());
-    }
-    if (!(_unlinkedUnits == null || _unlinkedUnits.isEmpty)) {
-      offset_unlinkedUnits = fbBuilder.writeList(_unlinkedUnits.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_prelinkedLibraryUris != null) {
-      fbBuilder.addOffset(0, offset_prelinkedLibraryUris);
-    }
-    if (offset_prelinkedLibraries != null) {
-      fbBuilder.addOffset(1, offset_prelinkedLibraries);
-    }
-    if (offset_unlinkedUnitUris != null) {
-      fbBuilder.addOffset(2, offset_unlinkedUnitUris);
-    }
-    if (offset_unlinkedUnits != null) {
-      fbBuilder.addOffset(3, offset_unlinkedUnits);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-SdkBundleBuilder encodeSdkBundle({List<String> prelinkedLibraryUris, List<PrelinkedLibraryBuilder> prelinkedLibraries, List<String> unlinkedUnitUris, List<UnlinkedUnitBuilder> unlinkedUnits}) {
-  SdkBundleBuilder builder = new SdkBundleBuilder();
-  builder.prelinkedLibraryUris = prelinkedLibraryUris;
-  builder.prelinkedLibraries = prelinkedLibraries;
-  builder.unlinkedUnitUris = unlinkedUnitUris;
-  builder.unlinkedUnits = unlinkedUnits;
-  return builder;
-}
-
-/**
- * Information about SDK.
- */
-abstract class SdkBundle extends base.SummaryClass {
-  factory SdkBundle.fromBuffer(List<int> buffer) {
-    fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
-    return const _SdkBundleReader().read(rootRef);
-  }
-
-  /**
-   * The list of URIs of items in [prelinkedLibraries], e.g. `dart:core`.
-   */
-  List<String> get prelinkedLibraryUris;
-
-  /**
-   * Pre-linked libraries.
-   */
-  List<PrelinkedLibrary> get prelinkedLibraries;
-
-  /**
-   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
-   */
-  List<String> get unlinkedUnitUris;
-
-  /**
-   * Unlinked information for the compilation units constituting the SDK.
-   */
-  List<UnlinkedUnit> get unlinkedUnits;
-}
-
-class _SdkBundleReader extends fb.TableReader<_SdkBundleImpl> {
-  const _SdkBundleReader();
-
-  @override
-  _SdkBundleImpl createObject(fb.BufferPointer bp) => new _SdkBundleImpl(bp);
-}
-
-class _SdkBundleImpl implements SdkBundle {
-  final fb.BufferPointer _bp;
-
-  _SdkBundleImpl(this._bp);
-
-  List<String> _prelinkedLibraryUris;
-  List<PrelinkedLibrary> _prelinkedLibraries;
-  List<String> _unlinkedUnitUris;
-  List<UnlinkedUnit> _unlinkedUnits;
-
-  @override
-  Map<String, Object> toMap() => {
-    "prelinkedLibraryUris": prelinkedLibraryUris,
-    "prelinkedLibraries": prelinkedLibraries,
-    "unlinkedUnitUris": unlinkedUnitUris,
-    "unlinkedUnits": unlinkedUnits,
-  };
-
-  @override
-  List<String> get prelinkedLibraryUris {
-    _prelinkedLibraryUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
-    return _prelinkedLibraryUris;
-  }
-
-  @override
-  List<PrelinkedLibrary> get prelinkedLibraries {
-    _prelinkedLibraries ??= const fb.ListReader<PrelinkedLibrary>(const _PrelinkedLibraryReader()).vTableGet(_bp, 1, const <PrelinkedLibrary>[]);
-    return _prelinkedLibraries;
-  }
-
-  @override
-  List<String> get unlinkedUnitUris {
-    _unlinkedUnitUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 2, const <String>[]);
-    return _unlinkedUnitUris;
-  }
-
-  @override
-  List<UnlinkedUnit> get unlinkedUnits {
-    _unlinkedUnits ??= const fb.ListReader<UnlinkedUnit>(const _UnlinkedUnitReader()).vTableGet(_bp, 3, const <UnlinkedUnit>[]);
-    return _unlinkedUnits;
-  }
-}
-
-class UnlinkedClassBuilder {
-  bool _finished = false;
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-  List<UnlinkedTypeParamBuilder> _typeParameters;
-  UnlinkedTypeRefBuilder _supertype;
-  List<UnlinkedTypeRefBuilder> _mixins;
-  List<UnlinkedTypeRefBuilder> _interfaces;
-  List<UnlinkedVariableBuilder> _fields;
-  List<UnlinkedExecutableBuilder> _executables;
-  bool _isAbstract;
-  bool _isMixinApplication;
-  bool _hasNoSupertype;
-
-  UnlinkedClassBuilder();
-
-  /**
-   * Name of the class.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * Offset of the class name relative to the beginning of the file.
-   */
-  void set nameOffset(int _value) {
-    assert(!_finished);
-    _nameOffset = _value;
-  }
-
-  /**
-   * Documentation comment for the class, or `null` if there is no
-   * documentation comment.
-   */
-  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
-    assert(!_finished);
-    _documentationComment = _value;
-  }
-
-  /**
-   * Type parameters of the class, if any.
-   */
-  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
-    assert(!_finished);
-    _typeParameters = _value;
-  }
-
-  /**
-   * 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).
-   */
-  void set supertype(UnlinkedTypeRefBuilder _value) {
-    assert(!_finished);
-    _supertype = _value;
-  }
-
-  /**
-   * Mixins appearing in a `with` clause, if any.
-   */
-  void set mixins(List<UnlinkedTypeRefBuilder> _value) {
-    assert(!_finished);
-    _mixins = _value;
-  }
-
-  /**
-   * Interfaces appearing in an `implements` clause, if any.
-   */
-  void set interfaces(List<UnlinkedTypeRefBuilder> _value) {
-    assert(!_finished);
-    _interfaces = _value;
-  }
-
-  /**
-   * Field declarations contained in the class.
-   */
-  void set fields(List<UnlinkedVariableBuilder> _value) {
-    assert(!_finished);
-    _fields = _value;
-  }
-
-  /**
-   * Executable objects (methods, getters, and setters) contained in the class.
-   */
-  void set executables(List<UnlinkedExecutableBuilder> _value) {
-    assert(!_finished);
-    _executables = _value;
-  }
-
-  /**
-   * Indicates whether the class is declared with the `abstract` keyword.
-   */
-  void set isAbstract(bool _value) {
-    assert(!_finished);
-    _isAbstract = _value;
-  }
-
-  /**
-   * Indicates whether the class is declared using mixin application syntax.
-   */
-  void set isMixinApplication(bool _value) {
-    assert(!_finished);
-    _isMixinApplication = _value;
-  }
-
-  /**
-   * Indicates whether this class is the core "Object" class (and hence has no
-   * supertype)
-   */
-  void set hasNoSupertype(bool _value) {
-    assert(!_finished);
-    _hasNoSupertype = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    fb.Offset offset_documentationComment;
-    fb.Offset offset_typeParameters;
-    fb.Offset offset_supertype;
-    fb.Offset offset_mixins;
-    fb.Offset offset_interfaces;
-    fb.Offset offset_fields;
-    fb.Offset offset_executables;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    if (_documentationComment != null) {
-      offset_documentationComment = _documentationComment.finish(fbBuilder);
-    }
-    if (!(_typeParameters == null || _typeParameters.isEmpty)) {
-      offset_typeParameters = fbBuilder.writeList(_typeParameters.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (_supertype != null) {
-      offset_supertype = _supertype.finish(fbBuilder);
-    }
-    if (!(_mixins == null || _mixins.isEmpty)) {
-      offset_mixins = fbBuilder.writeList(_mixins.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_interfaces == null || _interfaces.isEmpty)) {
-      offset_interfaces = fbBuilder.writeList(_interfaces.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_fields == null || _fields.isEmpty)) {
-      offset_fields = fbBuilder.writeList(_fields.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_executables == null || _executables.isEmpty)) {
-      offset_executables = fbBuilder.writeList(_executables.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addInt32(1, _nameOffset);
-    }
-    if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
-    }
-    if (offset_typeParameters != null) {
-      fbBuilder.addOffset(3, offset_typeParameters);
-    }
-    if (offset_supertype != null) {
-      fbBuilder.addOffset(4, offset_supertype);
-    }
-    if (offset_mixins != null) {
-      fbBuilder.addOffset(5, offset_mixins);
-    }
-    if (offset_interfaces != null) {
-      fbBuilder.addOffset(6, offset_interfaces);
-    }
-    if (offset_fields != null) {
-      fbBuilder.addOffset(7, offset_fields);
-    }
-    if (offset_executables != null) {
-      fbBuilder.addOffset(8, offset_executables);
-    }
-    if (_isAbstract == true) {
-      fbBuilder.addBool(9, true);
-    }
-    if (_isMixinApplication == true) {
-      fbBuilder.addBool(10, true);
-    }
-    if (_hasNoSupertype == true) {
-      fbBuilder.addBool(11, true);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedClassBuilder encodeUnlinkedClass({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, UnlinkedTypeRefBuilder supertype, List<UnlinkedTypeRefBuilder> mixins, List<UnlinkedTypeRefBuilder> interfaces, List<UnlinkedVariableBuilder> fields, List<UnlinkedExecutableBuilder> executables, bool isAbstract, bool isMixinApplication, bool hasNoSupertype}) {
-  UnlinkedClassBuilder builder = new UnlinkedClassBuilder();
-  builder.name = name;
-  builder.nameOffset = nameOffset;
-  builder.documentationComment = documentationComment;
-  builder.typeParameters = typeParameters;
-  builder.supertype = supertype;
-  builder.mixins = mixins;
-  builder.interfaces = interfaces;
-  builder.fields = fields;
-  builder.executables = executables;
-  builder.isAbstract = isAbstract;
-  builder.isMixinApplication = isMixinApplication;
-  builder.hasNoSupertype = hasNoSupertype;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a class declaration.
- */
-abstract class UnlinkedClass extends base.SummaryClass {
-
-  /**
-   * Name of the class.
-   */
-  String get name;
-
-  /**
-   * Offset of the class name relative to the beginning of the file.
-   */
-  int get nameOffset;
-
-  /**
-   * Documentation comment for the class, or `null` if there is no
-   * documentation comment.
-   */
-  UnlinkedDocumentationComment get documentationComment;
-
-  /**
-   * Type parameters of the class, if any.
-   */
-  List<UnlinkedTypeParam> get typeParameters;
-
-  /**
-   * 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).
-   */
-  UnlinkedTypeRef get supertype;
-
-  /**
-   * Mixins appearing in a `with` clause, if any.
-   */
-  List<UnlinkedTypeRef> get mixins;
-
-  /**
-   * Interfaces appearing in an `implements` clause, if any.
-   */
-  List<UnlinkedTypeRef> get interfaces;
-
-  /**
-   * Field declarations contained in the class.
-   */
-  List<UnlinkedVariable> get fields;
-
-  /**
-   * Executable objects (methods, getters, and setters) contained in the class.
-   */
-  List<UnlinkedExecutable> get executables;
-
-  /**
-   * Indicates whether the class is declared with the `abstract` keyword.
-   */
-  bool get isAbstract;
-
-  /**
-   * Indicates whether the class is declared using mixin application syntax.
-   */
-  bool get isMixinApplication;
-
-  /**
-   * Indicates whether this class is the core "Object" class (and hence has no
-   * supertype)
-   */
-  bool get hasNoSupertype;
-}
-
-class _UnlinkedClassReader extends fb.TableReader<_UnlinkedClassImpl> {
-  const _UnlinkedClassReader();
-
-  @override
-  _UnlinkedClassImpl createObject(fb.BufferPointer bp) => new _UnlinkedClassImpl(bp);
-}
-
-class _UnlinkedClassImpl implements UnlinkedClass {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedClassImpl(this._bp);
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-  List<UnlinkedTypeParam> _typeParameters;
-  UnlinkedTypeRef _supertype;
-  List<UnlinkedTypeRef> _mixins;
-  List<UnlinkedTypeRef> _interfaces;
-  List<UnlinkedVariable> _fields;
-  List<UnlinkedExecutable> _executables;
-  bool _isAbstract;
-  bool _isMixinApplication;
-  bool _hasNoSupertype;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-    "typeParameters": typeParameters,
-    "supertype": supertype,
-    "mixins": mixins,
-    "interfaces": interfaces,
-    "fields": fields,
-    "executables": executables,
-    "isAbstract": isAbstract,
-    "isMixinApplication": isMixinApplication,
-    "hasNoSupertype": hasNoSupertype,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
-  }
-
-  @override
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
-    return _documentationComment;
-  }
-
-  @override
-  List<UnlinkedTypeParam> get typeParameters {
-    _typeParameters ??= const fb.ListReader<UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 3, const <UnlinkedTypeParam>[]);
-    return _typeParameters;
-  }
-
-  @override
-  UnlinkedTypeRef get supertype {
-    _supertype ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 4, null);
-    return _supertype;
-  }
-
-  @override
-  List<UnlinkedTypeRef> get mixins {
-    _mixins ??= const fb.ListReader<UnlinkedTypeRef>(const _UnlinkedTypeRefReader()).vTableGet(_bp, 5, const <UnlinkedTypeRef>[]);
-    return _mixins;
-  }
-
-  @override
-  List<UnlinkedTypeRef> get interfaces {
-    _interfaces ??= const fb.ListReader<UnlinkedTypeRef>(const _UnlinkedTypeRefReader()).vTableGet(_bp, 6, const <UnlinkedTypeRef>[]);
-    return _interfaces;
-  }
-
-  @override
-  List<UnlinkedVariable> get fields {
-    _fields ??= const fb.ListReader<UnlinkedVariable>(const _UnlinkedVariableReader()).vTableGet(_bp, 7, const <UnlinkedVariable>[]);
-    return _fields;
-  }
-
-  @override
-  List<UnlinkedExecutable> get executables {
-    _executables ??= const fb.ListReader<UnlinkedExecutable>(const _UnlinkedExecutableReader()).vTableGet(_bp, 8, const <UnlinkedExecutable>[]);
-    return _executables;
-  }
-
-  @override
-  bool get isAbstract {
-    _isAbstract ??= const fb.BoolReader().vTableGet(_bp, 9, false);
-    return _isAbstract;
-  }
-
-  @override
-  bool get isMixinApplication {
-    _isMixinApplication ??= const fb.BoolReader().vTableGet(_bp, 10, false);
-    return _isMixinApplication;
-  }
-
-  @override
-  bool get hasNoSupertype {
-    _hasNoSupertype ??= const fb.BoolReader().vTableGet(_bp, 11, false);
-    return _hasNoSupertype;
-  }
-}
-
-class UnlinkedCombinatorBuilder {
-  bool _finished = false;
-
-  List<String> _shows;
-  List<String> _hides;
-
-  UnlinkedCombinatorBuilder();
-
-  /**
-   * List of names which are shown.  Empty if this is a `hide` combinator.
-   */
-  void set shows(List<String> _value) {
-    assert(!_finished);
-    _shows = _value;
-  }
-
-  /**
-   * List of names which are hidden.  Empty if this is a `show` combinator.
-   */
-  void set hides(List<String> _value) {
-    assert(!_finished);
-    _hides = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_shows;
-    fb.Offset offset_hides;
-    if (!(_shows == null || _shows.isEmpty)) {
-      offset_shows = fbBuilder.writeList(_shows.map((b) => fbBuilder.writeString(b)).toList());
-    }
-    if (!(_hides == null || _hides.isEmpty)) {
-      offset_hides = fbBuilder.writeList(_hides.map((b) => fbBuilder.writeString(b)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_shows != null) {
-      fbBuilder.addOffset(0, offset_shows);
-    }
-    if (offset_hides != null) {
-      fbBuilder.addOffset(1, offset_hides);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedCombinatorBuilder encodeUnlinkedCombinator({List<String> shows, List<String> hides}) {
-  UnlinkedCombinatorBuilder builder = new UnlinkedCombinatorBuilder();
-  builder.shows = shows;
-  builder.hides = hides;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a `show` or `hide` combinator in an
- * import or export declaration.
- */
-abstract class UnlinkedCombinator extends base.SummaryClass {
-
-  /**
-   * List of names which are shown.  Empty if this is a `hide` combinator.
-   */
-  List<String> get shows;
-
-  /**
-   * List of names which are hidden.  Empty if this is a `show` combinator.
-   */
-  List<String> get hides;
-}
-
-class _UnlinkedCombinatorReader extends fb.TableReader<_UnlinkedCombinatorImpl> {
-  const _UnlinkedCombinatorReader();
-
-  @override
-  _UnlinkedCombinatorImpl createObject(fb.BufferPointer bp) => new _UnlinkedCombinatorImpl(bp);
-}
-
-class _UnlinkedCombinatorImpl implements UnlinkedCombinator {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedCombinatorImpl(this._bp);
-
-  List<String> _shows;
-  List<String> _hides;
-
-  @override
-  Map<String, Object> toMap() => {
-    "shows": shows,
-    "hides": hides,
-  };
-
-  @override
-  List<String> get shows {
-    _shows ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
-    return _shows;
-  }
-
-  @override
-  List<String> get hides {
-    _hides ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
-    return _hides;
-  }
-}
-
-class UnlinkedDocumentationCommentBuilder {
-  bool _finished = false;
-
-  String _text;
-  int _offset;
-  int _length;
-
-  UnlinkedDocumentationCommentBuilder();
-
-  /**
-   * Text of the documentation comment, with '\r\n' replaced by '\n'.
-   *
-   * References appearing within the doc comment in square brackets are not
-   * specially encoded.
-   */
-  void set text(String _value) {
-    assert(!_finished);
-    _text = _value;
-  }
-
-  /**
-   * Offset of the beginning of the documentation comment relative to the
-   * beginning of the file.
-   */
-  void set offset(int _value) {
-    assert(!_finished);
-    _offset = _value;
-  }
-
-  /**
-   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
-   */
-  void set length(int _value) {
-    assert(!_finished);
-    _length = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_text;
-    if (_text != null) {
-      offset_text = fbBuilder.writeString(_text);
-    }
-    fbBuilder.startTable();
-    if (offset_text != null) {
-      fbBuilder.addOffset(0, offset_text);
-    }
-    if (_offset != null && _offset != 0) {
-      fbBuilder.addInt32(1, _offset);
-    }
-    if (_length != null && _length != 0) {
-      fbBuilder.addInt32(2, _length);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedDocumentationCommentBuilder encodeUnlinkedDocumentationComment({String text, int offset, int length}) {
-  UnlinkedDocumentationCommentBuilder builder = new UnlinkedDocumentationCommentBuilder();
-  builder.text = text;
-  builder.offset = offset;
-  builder.length = length;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a documentation comment.
- */
-abstract class UnlinkedDocumentationComment extends base.SummaryClass {
-
-  /**
-   * Text of the documentation comment, with '\r\n' replaced by '\n'.
-   *
-   * References appearing within the doc comment in square brackets are not
-   * specially encoded.
-   */
-  String get text;
-
-  /**
-   * Offset of the beginning of the documentation comment relative to the
-   * beginning of the file.
-   */
-  int get offset;
-
-  /**
-   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
-   */
-  int get length;
-}
-
-class _UnlinkedDocumentationCommentReader extends fb.TableReader<_UnlinkedDocumentationCommentImpl> {
-  const _UnlinkedDocumentationCommentReader();
-
-  @override
-  _UnlinkedDocumentationCommentImpl createObject(fb.BufferPointer bp) => new _UnlinkedDocumentationCommentImpl(bp);
-}
-
-class _UnlinkedDocumentationCommentImpl implements UnlinkedDocumentationComment {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedDocumentationCommentImpl(this._bp);
-
-  String _text;
-  int _offset;
-  int _length;
-
-  @override
-  Map<String, Object> toMap() => {
-    "text": text,
-    "offset": offset,
-    "length": length,
-  };
-
-  @override
-  String get text {
-    _text ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _text;
-  }
-
-  @override
-  int get offset {
-    _offset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _offset;
-  }
-
-  @override
-  int get length {
-    _length ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
-    return _length;
-  }
-}
-
-class UnlinkedEnumBuilder {
-  bool _finished = false;
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-  List<UnlinkedEnumValueBuilder> _values;
-
-  UnlinkedEnumBuilder();
-
-  /**
-   * Name of the enum type.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * Offset of the enum name relative to the beginning of the file.
-   */
-  void set nameOffset(int _value) {
-    assert(!_finished);
-    _nameOffset = _value;
-  }
-
-  /**
-   * Documentation comment for the enum, or `null` if there is no documentation
-   * comment.
-   */
-  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
-    assert(!_finished);
-    _documentationComment = _value;
-  }
-
-  /**
-   * Values listed in the enum declaration, in declaration order.
-   */
-  void set values(List<UnlinkedEnumValueBuilder> _value) {
-    assert(!_finished);
-    _values = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    fb.Offset offset_documentationComment;
-    fb.Offset offset_values;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    if (_documentationComment != null) {
-      offset_documentationComment = _documentationComment.finish(fbBuilder);
-    }
-    if (!(_values == null || _values.isEmpty)) {
-      offset_values = fbBuilder.writeList(_values.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addInt32(1, _nameOffset);
-    }
-    if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
-    }
-    if (offset_values != null) {
-      fbBuilder.addOffset(3, offset_values);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedEnumBuilder encodeUnlinkedEnum({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedEnumValueBuilder> values}) {
-  UnlinkedEnumBuilder builder = new UnlinkedEnumBuilder();
-  builder.name = name;
-  builder.nameOffset = nameOffset;
-  builder.documentationComment = documentationComment;
-  builder.values = values;
-  return builder;
-}
-
-/**
- * Unlinked summary information about an enum declaration.
- */
-abstract class UnlinkedEnum extends base.SummaryClass {
-
-  /**
-   * Name of the enum type.
-   */
-  String get name;
-
-  /**
-   * Offset of the enum name relative to the beginning of the file.
-   */
-  int get nameOffset;
-
-  /**
-   * Documentation comment for the enum, or `null` if there is no documentation
-   * comment.
-   */
-  UnlinkedDocumentationComment get documentationComment;
-
-  /**
-   * Values listed in the enum declaration, in declaration order.
-   */
-  List<UnlinkedEnumValue> get values;
-}
-
-class _UnlinkedEnumReader extends fb.TableReader<_UnlinkedEnumImpl> {
-  const _UnlinkedEnumReader();
-
-  @override
-  _UnlinkedEnumImpl createObject(fb.BufferPointer bp) => new _UnlinkedEnumImpl(bp);
-}
-
-class _UnlinkedEnumImpl implements UnlinkedEnum {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedEnumImpl(this._bp);
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-  List<UnlinkedEnumValue> _values;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-    "values": values,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
-  }
-
-  @override
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
-    return _documentationComment;
-  }
-
-  @override
-  List<UnlinkedEnumValue> get values {
-    _values ??= const fb.ListReader<UnlinkedEnumValue>(const _UnlinkedEnumValueReader()).vTableGet(_bp, 3, const <UnlinkedEnumValue>[]);
-    return _values;
-  }
-}
-
-class UnlinkedEnumValueBuilder {
-  bool _finished = false;
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-
-  UnlinkedEnumValueBuilder();
-
-  /**
-   * Name of the enumerated value.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * Offset of the enum value name relative to the beginning of the file.
-   */
-  void set nameOffset(int _value) {
-    assert(!_finished);
-    _nameOffset = _value;
-  }
-
-  /**
-   * Documentation comment for the enum value, or `null` if there is no
-   * documentation comment.
-   */
-  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
-    assert(!_finished);
-    _documentationComment = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    fb.Offset offset_documentationComment;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    if (_documentationComment != null) {
-      offset_documentationComment = _documentationComment.finish(fbBuilder);
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addInt32(1, _nameOffset);
-    }
-    if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedEnumValueBuilder encodeUnlinkedEnumValue({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment}) {
-  UnlinkedEnumValueBuilder builder = new UnlinkedEnumValueBuilder();
-  builder.name = name;
-  builder.nameOffset = nameOffset;
-  builder.documentationComment = documentationComment;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a single enumerated value in an enum
- * declaration.
- */
-abstract class UnlinkedEnumValue extends base.SummaryClass {
-
-  /**
-   * Name of the enumerated value.
-   */
-  String get name;
-
-  /**
-   * Offset of the enum value name relative to the beginning of the file.
-   */
-  int get nameOffset;
-
-  /**
-   * Documentation comment for the enum value, or `null` if there is no
-   * documentation comment.
-   */
-  UnlinkedDocumentationComment get documentationComment;
-}
-
-class _UnlinkedEnumValueReader extends fb.TableReader<_UnlinkedEnumValueImpl> {
-  const _UnlinkedEnumValueReader();
-
-  @override
-  _UnlinkedEnumValueImpl createObject(fb.BufferPointer bp) => new _UnlinkedEnumValueImpl(bp);
-}
-
-class _UnlinkedEnumValueImpl implements UnlinkedEnumValue {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedEnumValueImpl(this._bp);
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
-  }
-
-  @override
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
-    return _documentationComment;
-  }
-}
-
-class UnlinkedExecutableBuilder {
-  bool _finished = false;
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-  List<UnlinkedTypeParamBuilder> _typeParameters;
-  UnlinkedTypeRefBuilder _returnType;
-  List<UnlinkedParamBuilder> _parameters;
-  UnlinkedExecutableKind _kind;
-  bool _isAbstract;
-  bool _isStatic;
-  bool _isConst;
-  bool _isFactory;
-  bool _hasImplicitReturnType;
-  bool _isExternal;
-
-  UnlinkedExecutableBuilder();
-
-  /**
-   * 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.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * 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(); }").
-   */
-  void set nameOffset(int _value) {
-    assert(!_finished);
-    _nameOffset = _value;
-  }
-
-  /**
-   * Documentation comment for the executable, or `null` if there is no
-   * documentation comment.
-   */
-  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
-    assert(!_finished);
-    _documentationComment = _value;
-  }
-
-  /**
-   * Type parameters of the executable, if any.  Empty if support for generic
-   * method syntax is disabled.
-   */
-  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
-    assert(!_finished);
-    _typeParameters = _value;
-  }
-
-  /**
-   * Declared return type of the executable.  Absent if the return type is
-   * `void` or the executable is a constructor.  Note that when strong mode is
-   * enabled, the actual return type may be different due to type inference.
-   */
-  void set returnType(UnlinkedTypeRefBuilder _value) {
-    assert(!_finished);
-    _returnType = _value;
-  }
-
-  /**
-   * 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.
-   */
-  void set parameters(List<UnlinkedParamBuilder> _value) {
-    assert(!_finished);
-    _parameters = _value;
-  }
-
-  /**
-   * The kind of the executable (function/method, getter, setter, or
-   * constructor).
-   */
-  void set kind(UnlinkedExecutableKind _value) {
-    assert(!_finished);
-    _kind = _value;
-  }
-
-  /**
-   * Indicates whether the executable is declared using the `abstract` keyword.
-   */
-  void set isAbstract(bool _value) {
-    assert(!_finished);
-    _isAbstract = _value;
-  }
-
-  /**
-   * 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).
-   */
-  void set isStatic(bool _value) {
-    assert(!_finished);
-    _isStatic = _value;
-  }
-
-  /**
-   * Indicates whether the executable is declared using the `const` keyword.
-   */
-  void set isConst(bool _value) {
-    assert(!_finished);
-    _isConst = _value;
-  }
-
-  /**
-   * Indicates whether the executable is declared using the `factory` keyword.
-   */
-  void set isFactory(bool _value) {
-    assert(!_finished);
-    _isFactory = _value;
-  }
-
-  /**
-   * Indicates whether the executable lacks an explicit return type
-   * declaration.  False for constructors and setters.
-   */
-  void set hasImplicitReturnType(bool _value) {
-    assert(!_finished);
-    _hasImplicitReturnType = _value;
-  }
-
-  /**
-   * Indicates whether the executable is declared using the `external` keyword.
-   */
-  void set isExternal(bool _value) {
-    assert(!_finished);
-    _isExternal = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    fb.Offset offset_documentationComment;
-    fb.Offset offset_typeParameters;
-    fb.Offset offset_returnType;
-    fb.Offset offset_parameters;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    if (_documentationComment != null) {
-      offset_documentationComment = _documentationComment.finish(fbBuilder);
-    }
-    if (!(_typeParameters == null || _typeParameters.isEmpty)) {
-      offset_typeParameters = fbBuilder.writeList(_typeParameters.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (_returnType != null) {
-      offset_returnType = _returnType.finish(fbBuilder);
-    }
-    if (!(_parameters == null || _parameters.isEmpty)) {
-      offset_parameters = fbBuilder.writeList(_parameters.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addInt32(1, _nameOffset);
-    }
-    if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
-    }
-    if (offset_typeParameters != null) {
-      fbBuilder.addOffset(3, offset_typeParameters);
-    }
-    if (offset_returnType != null) {
-      fbBuilder.addOffset(4, offset_returnType);
-    }
-    if (offset_parameters != null) {
-      fbBuilder.addOffset(5, offset_parameters);
-    }
-    if (_kind != null && _kind != UnlinkedExecutableKind.functionOrMethod) {
-      fbBuilder.addInt32(6, _kind.index);
-    }
-    if (_isAbstract == true) {
-      fbBuilder.addBool(7, true);
-    }
-    if (_isStatic == true) {
-      fbBuilder.addBool(8, true);
-    }
-    if (_isConst == true) {
-      fbBuilder.addBool(9, true);
-    }
-    if (_isFactory == true) {
-      fbBuilder.addBool(10, true);
-    }
-    if (_hasImplicitReturnType == true) {
-      fbBuilder.addBool(11, true);
-    }
-    if (_isExternal == true) {
-      fbBuilder.addBool(12, true);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedExecutableBuilder encodeUnlinkedExecutable({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, UnlinkedTypeRefBuilder returnType, List<UnlinkedParamBuilder> parameters, UnlinkedExecutableKind kind, bool isAbstract, bool isStatic, bool isConst, bool isFactory, bool hasImplicitReturnType, bool isExternal}) {
-  UnlinkedExecutableBuilder builder = new UnlinkedExecutableBuilder();
-  builder.name = name;
-  builder.nameOffset = nameOffset;
-  builder.documentationComment = documentationComment;
-  builder.typeParameters = typeParameters;
-  builder.returnType = returnType;
-  builder.parameters = parameters;
-  builder.kind = kind;
-  builder.isAbstract = isAbstract;
-  builder.isStatic = isStatic;
-  builder.isConst = isConst;
-  builder.isFactory = isFactory;
-  builder.hasImplicitReturnType = hasImplicitReturnType;
-  builder.isExternal = isExternal;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a function, method, getter, or setter
- * declaration.
- */
-abstract class UnlinkedExecutable extends base.SummaryClass {
-
-  /**
-   * 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.
-   */
-  String get name;
-
-  /**
-   * 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(); }").
-   */
-  int get nameOffset;
-
-  /**
-   * Documentation comment for the executable, or `null` if there is no
-   * documentation comment.
-   */
-  UnlinkedDocumentationComment get documentationComment;
-
-  /**
-   * Type parameters of the executable, if any.  Empty if support for generic
-   * method syntax is disabled.
-   */
-  List<UnlinkedTypeParam> get typeParameters;
-
-  /**
-   * Declared return type of the executable.  Absent if the return type is
-   * `void` or the executable is a constructor.  Note that when strong mode is
-   * enabled, the actual return type may be different due to type inference.
-   */
-  UnlinkedTypeRef get returnType;
-
-  /**
-   * 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.
-   */
-  List<UnlinkedParam> get parameters;
-
-  /**
-   * The kind of the executable (function/method, getter, setter, or
-   * constructor).
-   */
-  UnlinkedExecutableKind get kind;
-
-  /**
-   * Indicates whether the executable is declared using the `abstract` keyword.
-   */
-  bool get isAbstract;
-
-  /**
-   * 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).
-   */
-  bool get isStatic;
-
-  /**
-   * Indicates whether the executable is declared using the `const` keyword.
-   */
-  bool get isConst;
-
-  /**
-   * Indicates whether the executable is declared using the `factory` keyword.
-   */
-  bool get isFactory;
-
-  /**
-   * Indicates whether the executable lacks an explicit return type
-   * declaration.  False for constructors and setters.
-   */
-  bool get hasImplicitReturnType;
-
-  /**
-   * Indicates whether the executable is declared using the `external` keyword.
-   */
-  bool get isExternal;
-}
-
-class _UnlinkedExecutableReader extends fb.TableReader<_UnlinkedExecutableImpl> {
-  const _UnlinkedExecutableReader();
-
-  @override
-  _UnlinkedExecutableImpl createObject(fb.BufferPointer bp) => new _UnlinkedExecutableImpl(bp);
-}
-
-class _UnlinkedExecutableImpl implements UnlinkedExecutable {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedExecutableImpl(this._bp);
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-  List<UnlinkedTypeParam> _typeParameters;
-  UnlinkedTypeRef _returnType;
-  List<UnlinkedParam> _parameters;
-  UnlinkedExecutableKind _kind;
-  bool _isAbstract;
-  bool _isStatic;
-  bool _isConst;
-  bool _isFactory;
-  bool _hasImplicitReturnType;
-  bool _isExternal;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-    "typeParameters": typeParameters,
-    "returnType": returnType,
-    "parameters": parameters,
-    "kind": kind,
-    "isAbstract": isAbstract,
-    "isStatic": isStatic,
-    "isConst": isConst,
-    "isFactory": isFactory,
-    "hasImplicitReturnType": hasImplicitReturnType,
-    "isExternal": isExternal,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
-  }
-
-  @override
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
-    return _documentationComment;
-  }
-
-  @override
-  List<UnlinkedTypeParam> get typeParameters {
-    _typeParameters ??= const fb.ListReader<UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 3, const <UnlinkedTypeParam>[]);
-    return _typeParameters;
-  }
-
-  @override
-  UnlinkedTypeRef get returnType {
-    _returnType ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 4, null);
-    return _returnType;
-  }
-
-  @override
-  List<UnlinkedParam> get parameters {
-    _parameters ??= const fb.ListReader<UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 5, const <UnlinkedParam>[]);
-    return _parameters;
-  }
-
-  @override
-  UnlinkedExecutableKind get kind {
-    _kind ??= UnlinkedExecutableKind.values[const fb.Int32Reader().vTableGet(_bp, 6, 0)];
-    return _kind;
-  }
-
-  @override
-  bool get isAbstract {
-    _isAbstract ??= const fb.BoolReader().vTableGet(_bp, 7, false);
-    return _isAbstract;
-  }
-
-  @override
-  bool get isStatic {
-    _isStatic ??= const fb.BoolReader().vTableGet(_bp, 8, false);
-    return _isStatic;
-  }
-
-  @override
-  bool get isConst {
-    _isConst ??= const fb.BoolReader().vTableGet(_bp, 9, false);
-    return _isConst;
-  }
-
-  @override
-  bool get isFactory {
-    _isFactory ??= const fb.BoolReader().vTableGet(_bp, 10, false);
-    return _isFactory;
-  }
-
-  @override
-  bool get hasImplicitReturnType {
-    _hasImplicitReturnType ??= const fb.BoolReader().vTableGet(_bp, 11, false);
-    return _hasImplicitReturnType;
-  }
-
-  @override
-  bool get isExternal {
-    _isExternal ??= const fb.BoolReader().vTableGet(_bp, 12, false);
-    return _isExternal;
-  }
-}
-
-class UnlinkedExportNonPublicBuilder {
-  bool _finished = false;
-
-  int _offset;
-  int _uriOffset;
-  int _uriEnd;
-
-  UnlinkedExportNonPublicBuilder();
-
-  /**
-   * Offset of the "export" keyword.
-   */
-  void set offset(int _value) {
-    assert(!_finished);
-    _offset = _value;
-  }
-
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.
-   */
-  void set uriOffset(int _value) {
-    assert(!_finished);
-    _uriOffset = _value;
-  }
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.
-   */
-  void set uriEnd(int _value) {
-    assert(!_finished);
-    _uriEnd = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fbBuilder.startTable();
-    if (_offset != null && _offset != 0) {
-      fbBuilder.addInt32(0, _offset);
-    }
-    if (_uriOffset != null && _uriOffset != 0) {
-      fbBuilder.addInt32(1, _uriOffset);
-    }
-    if (_uriEnd != null && _uriEnd != 0) {
-      fbBuilder.addInt32(2, _uriEnd);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedExportNonPublicBuilder encodeUnlinkedExportNonPublic({int offset, int uriOffset, int uriEnd}) {
-  UnlinkedExportNonPublicBuilder builder = new UnlinkedExportNonPublicBuilder();
-  builder.offset = offset;
-  builder.uriOffset = uriOffset;
-  builder.uriEnd = uriEnd;
-  return builder;
-}
-
-/**
- * Unlinked summary information about an export declaration (stored outside
- * [UnlinkedPublicNamespace]).
- */
-abstract class UnlinkedExportNonPublic extends base.SummaryClass {
-
-  /**
-   * Offset of the "export" keyword.
-   */
-  int get offset;
-
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.
-   */
-  int get uriOffset;
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.
-   */
-  int get uriEnd;
-}
-
-class _UnlinkedExportNonPublicReader extends fb.TableReader<_UnlinkedExportNonPublicImpl> {
-  const _UnlinkedExportNonPublicReader();
-
-  @override
-  _UnlinkedExportNonPublicImpl createObject(fb.BufferPointer bp) => new _UnlinkedExportNonPublicImpl(bp);
-}
-
-class _UnlinkedExportNonPublicImpl implements UnlinkedExportNonPublic {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedExportNonPublicImpl(this._bp);
-
-  int _offset;
-  int _uriOffset;
-  int _uriEnd;
-
-  @override
-  Map<String, Object> toMap() => {
-    "offset": offset,
-    "uriOffset": uriOffset,
-    "uriEnd": uriEnd,
-  };
-
-  @override
-  int get offset {
-    _offset ??= const fb.Int32Reader().vTableGet(_bp, 0, 0);
-    return _offset;
-  }
-
-  @override
-  int get uriOffset {
-    _uriOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _uriOffset;
-  }
-
-  @override
-  int get uriEnd {
-    _uriEnd ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
-    return _uriEnd;
-  }
-}
-
-class UnlinkedExportPublicBuilder {
-  bool _finished = false;
-
-  String _uri;
-  List<UnlinkedCombinatorBuilder> _combinators;
-
-  UnlinkedExportPublicBuilder();
-
-  /**
-   * URI used in the source code to reference the exported library.
-   */
-  void set uri(String _value) {
-    assert(!_finished);
-    _uri = _value;
-  }
-
-  /**
-   * Combinators contained in this import declaration.
-   */
-  void set combinators(List<UnlinkedCombinatorBuilder> _value) {
-    assert(!_finished);
-    _combinators = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_uri;
-    fb.Offset offset_combinators;
-    if (_uri != null) {
-      offset_uri = fbBuilder.writeString(_uri);
-    }
-    if (!(_combinators == null || _combinators.isEmpty)) {
-      offset_combinators = fbBuilder.writeList(_combinators.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_uri != null) {
-      fbBuilder.addOffset(0, offset_uri);
-    }
-    if (offset_combinators != null) {
-      fbBuilder.addOffset(1, offset_combinators);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedExportPublicBuilder encodeUnlinkedExportPublic({String uri, List<UnlinkedCombinatorBuilder> combinators}) {
-  UnlinkedExportPublicBuilder builder = new UnlinkedExportPublicBuilder();
-  builder.uri = uri;
-  builder.combinators = combinators;
-  return builder;
-}
-
-/**
- * Unlinked summary information about an export declaration (stored inside
- * [UnlinkedPublicNamespace]).
- */
-abstract class UnlinkedExportPublic extends base.SummaryClass {
-
-  /**
-   * URI used in the source code to reference the exported library.
-   */
-  String get uri;
-
-  /**
-   * Combinators contained in this import declaration.
-   */
-  List<UnlinkedCombinator> get combinators;
-}
-
-class _UnlinkedExportPublicReader extends fb.TableReader<_UnlinkedExportPublicImpl> {
-  const _UnlinkedExportPublicReader();
-
-  @override
-  _UnlinkedExportPublicImpl createObject(fb.BufferPointer bp) => new _UnlinkedExportPublicImpl(bp);
-}
-
-class _UnlinkedExportPublicImpl implements UnlinkedExportPublic {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedExportPublicImpl(this._bp);
-
-  String _uri;
-  List<UnlinkedCombinator> _combinators;
-
-  @override
-  Map<String, Object> toMap() => {
-    "uri": uri,
-    "combinators": combinators,
-  };
-
-  @override
-  String get uri {
-    _uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _uri;
-  }
-
-  @override
-  List<UnlinkedCombinator> get combinators {
-    _combinators ??= const fb.ListReader<UnlinkedCombinator>(const _UnlinkedCombinatorReader()).vTableGet(_bp, 1, const <UnlinkedCombinator>[]);
-    return _combinators;
-  }
-}
-
-class UnlinkedImportBuilder {
-  bool _finished = false;
-
-  String _uri;
-  int _offset;
-  int _prefixReference;
-  List<UnlinkedCombinatorBuilder> _combinators;
-  bool _isDeferred;
-  bool _isImplicit;
-  int _uriOffset;
-  int _uriEnd;
-  int _prefixOffset;
-
-  UnlinkedImportBuilder();
-
-  /**
-   * URI used in the source code to reference the imported library.
-   */
-  void set uri(String _value) {
-    assert(!_finished);
-    _uri = _value;
-  }
-
-  /**
-   * If [isImplicit] is false, offset of the "import" keyword.  If [isImplicit]
-   * is true, zero.
-   */
-  void set offset(int _value) {
-    assert(!_finished);
-    _offset = _value;
-  }
-
-  /**
-   * 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.
-   */
-  void set prefixReference(int _value) {
-    assert(!_finished);
-    _prefixReference = _value;
-  }
-
-  /**
-   * Combinators contained in this import declaration.
-   */
-  void set combinators(List<UnlinkedCombinatorBuilder> _value) {
-    assert(!_finished);
-    _combinators = _value;
-  }
-
-  /**
-   * Indicates whether the import declaration uses the `deferred` keyword.
-   */
-  void set isDeferred(bool _value) {
-    assert(!_finished);
-    _isDeferred = _value;
-  }
-
-  /**
-   * Indicates whether the import declaration is implicit.
-   */
-  void set isImplicit(bool _value) {
-    assert(!_finished);
-    _isImplicit = _value;
-  }
-
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.  If [isImplicit] is true, zero.
-   */
-  void set uriOffset(int _value) {
-    assert(!_finished);
-    _uriOffset = _value;
-  }
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.  If [isImplicit] is true, zero.
-   */
-  void set uriEnd(int _value) {
-    assert(!_finished);
-    _uriEnd = _value;
-  }
-
-  /**
-   * Offset of the prefix name relative to the beginning of the file, or zero
-   * if there is no prefix.
-   */
-  void set prefixOffset(int _value) {
-    assert(!_finished);
-    _prefixOffset = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_uri;
-    fb.Offset offset_combinators;
-    if (_uri != null) {
-      offset_uri = fbBuilder.writeString(_uri);
-    }
-    if (!(_combinators == null || _combinators.isEmpty)) {
-      offset_combinators = fbBuilder.writeList(_combinators.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_uri != null) {
-      fbBuilder.addOffset(0, offset_uri);
-    }
-    if (_offset != null && _offset != 0) {
-      fbBuilder.addInt32(1, _offset);
-    }
-    if (_prefixReference != null && _prefixReference != 0) {
-      fbBuilder.addInt32(2, _prefixReference);
-    }
-    if (offset_combinators != null) {
-      fbBuilder.addOffset(3, offset_combinators);
-    }
-    if (_isDeferred == true) {
-      fbBuilder.addBool(4, true);
-    }
-    if (_isImplicit == true) {
-      fbBuilder.addBool(5, true);
-    }
-    if (_uriOffset != null && _uriOffset != 0) {
-      fbBuilder.addInt32(6, _uriOffset);
-    }
-    if (_uriEnd != null && _uriEnd != 0) {
-      fbBuilder.addInt32(7, _uriEnd);
-    }
-    if (_prefixOffset != null && _prefixOffset != 0) {
-      fbBuilder.addInt32(8, _prefixOffset);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedImportBuilder encodeUnlinkedImport({String uri, int offset, int prefixReference, List<UnlinkedCombinatorBuilder> combinators, bool isDeferred, bool isImplicit, int uriOffset, int uriEnd, int prefixOffset}) {
-  UnlinkedImportBuilder builder = new UnlinkedImportBuilder();
-  builder.uri = uri;
-  builder.offset = offset;
-  builder.prefixReference = prefixReference;
-  builder.combinators = combinators;
-  builder.isDeferred = isDeferred;
-  builder.isImplicit = isImplicit;
-  builder.uriOffset = uriOffset;
-  builder.uriEnd = uriEnd;
-  builder.prefixOffset = prefixOffset;
-  return builder;
-}
-
-/**
- * Unlinked summary information about an import declaration.
- */
-abstract class UnlinkedImport extends base.SummaryClass {
-
-  /**
-   * URI used in the source code to reference the imported library.
-   */
-  String get uri;
-
-  /**
-   * If [isImplicit] is false, offset of the "import" keyword.  If [isImplicit]
-   * is true, zero.
-   */
-  int get offset;
-
-  /**
-   * 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.
-   */
-  int get prefixReference;
-
-  /**
-   * Combinators contained in this import declaration.
-   */
-  List<UnlinkedCombinator> get combinators;
-
-  /**
-   * Indicates whether the import declaration uses the `deferred` keyword.
-   */
-  bool get isDeferred;
-
-  /**
-   * Indicates whether the import declaration is implicit.
-   */
-  bool get isImplicit;
-
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.  If [isImplicit] is true, zero.
-   */
-  int get uriOffset;
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.  If [isImplicit] is true, zero.
-   */
-  int get uriEnd;
-
-  /**
-   * Offset of the prefix name relative to the beginning of the file, or zero
-   * if there is no prefix.
-   */
-  int get prefixOffset;
-}
-
-class _UnlinkedImportReader extends fb.TableReader<_UnlinkedImportImpl> {
-  const _UnlinkedImportReader();
-
-  @override
-  _UnlinkedImportImpl createObject(fb.BufferPointer bp) => new _UnlinkedImportImpl(bp);
-}
-
-class _UnlinkedImportImpl implements UnlinkedImport {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedImportImpl(this._bp);
-
-  String _uri;
-  int _offset;
-  int _prefixReference;
-  List<UnlinkedCombinator> _combinators;
-  bool _isDeferred;
-  bool _isImplicit;
-  int _uriOffset;
-  int _uriEnd;
-  int _prefixOffset;
-
-  @override
-  Map<String, Object> toMap() => {
-    "uri": uri,
-    "offset": offset,
-    "prefixReference": prefixReference,
-    "combinators": combinators,
-    "isDeferred": isDeferred,
-    "isImplicit": isImplicit,
-    "uriOffset": uriOffset,
-    "uriEnd": uriEnd,
-    "prefixOffset": prefixOffset,
-  };
-
-  @override
-  String get uri {
-    _uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _uri;
-  }
-
-  @override
-  int get offset {
-    _offset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _offset;
-  }
-
-  @override
-  int get prefixReference {
-    _prefixReference ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
-    return _prefixReference;
-  }
-
-  @override
-  List<UnlinkedCombinator> get combinators {
-    _combinators ??= const fb.ListReader<UnlinkedCombinator>(const _UnlinkedCombinatorReader()).vTableGet(_bp, 3, const <UnlinkedCombinator>[]);
-    return _combinators;
-  }
-
-  @override
-  bool get isDeferred {
-    _isDeferred ??= const fb.BoolReader().vTableGet(_bp, 4, false);
-    return _isDeferred;
-  }
-
-  @override
-  bool get isImplicit {
-    _isImplicit ??= const fb.BoolReader().vTableGet(_bp, 5, false);
-    return _isImplicit;
-  }
-
-  @override
-  int get uriOffset {
-    _uriOffset ??= const fb.Int32Reader().vTableGet(_bp, 6, 0);
-    return _uriOffset;
-  }
-
-  @override
-  int get uriEnd {
-    _uriEnd ??= const fb.Int32Reader().vTableGet(_bp, 7, 0);
-    return _uriEnd;
-  }
-
-  @override
-  int get prefixOffset {
-    _prefixOffset ??= const fb.Int32Reader().vTableGet(_bp, 8, 0);
-    return _prefixOffset;
-  }
-}
-
-class UnlinkedParamBuilder {
-  bool _finished = false;
-
-  String _name;
-  int _nameOffset;
-  UnlinkedTypeRefBuilder _type;
-  List<UnlinkedParamBuilder> _parameters;
-  UnlinkedParamKind _kind;
-  bool _isFunctionTyped;
-  bool _isInitializingFormal;
-  bool _hasImplicitType;
-
-  UnlinkedParamBuilder();
-
-  /**
-   * Name of the parameter.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * Offset of the parameter name relative to the beginning of the file.
-   */
-  void set nameOffset(int _value) {
-    assert(!_finished);
-    _nameOffset = _value;
-  }
-
-  /**
-   * If [isFunctionTyped] is `true`, the declared return type.  If
-   * [isFunctionTyped] is `false`, the declared type.  Absent if
-   * [isFunctionTyped] is `true` and the declared return type is `void`.  Note
-   * that when strong mode is enabled, the actual type may be different due to
-   * type inference.
-   */
-  void set type(UnlinkedTypeRefBuilder _value) {
-    assert(!_finished);
-    _type = _value;
-  }
-
-  /**
-   * If [isFunctionTyped] is `true`, the parameters of the function type.
-   */
-  void set parameters(List<UnlinkedParamBuilder> _value) {
-    assert(!_finished);
-    _parameters = _value;
-  }
-
-  /**
-   * Kind of the parameter.
-   */
-  void set kind(UnlinkedParamKind _value) {
-    assert(!_finished);
-    _kind = _value;
-  }
-
-  /**
-   * Indicates whether this is a function-typed parameter.
-   */
-  void set isFunctionTyped(bool _value) {
-    assert(!_finished);
-    _isFunctionTyped = _value;
-  }
-
-  /**
-   * Indicates whether this is an initializing formal parameter (i.e. it is
-   * declared using `this.` syntax).
-   */
-  void set isInitializingFormal(bool _value) {
-    assert(!_finished);
-    _isInitializingFormal = _value;
-  }
-
-  /**
-   * Indicates whether this parameter lacks an explicit type declaration.
-   * Always false for a function-typed parameter.
-   */
-  void set hasImplicitType(bool _value) {
-    assert(!_finished);
-    _hasImplicitType = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    fb.Offset offset_type;
-    fb.Offset offset_parameters;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    if (_type != null) {
-      offset_type = _type.finish(fbBuilder);
-    }
-    if (!(_parameters == null || _parameters.isEmpty)) {
-      offset_parameters = fbBuilder.writeList(_parameters.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addInt32(1, _nameOffset);
-    }
-    if (offset_type != null) {
-      fbBuilder.addOffset(2, offset_type);
-    }
-    if (offset_parameters != null) {
-      fbBuilder.addOffset(3, offset_parameters);
-    }
-    if (_kind != null && _kind != UnlinkedParamKind.required) {
-      fbBuilder.addInt32(4, _kind.index);
-    }
-    if (_isFunctionTyped == true) {
-      fbBuilder.addBool(5, true);
-    }
-    if (_isInitializingFormal == true) {
-      fbBuilder.addBool(6, true);
-    }
-    if (_hasImplicitType == true) {
-      fbBuilder.addBool(7, true);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedParamBuilder encodeUnlinkedParam({String name, int nameOffset, UnlinkedTypeRefBuilder type, List<UnlinkedParamBuilder> parameters, UnlinkedParamKind kind, bool isFunctionTyped, bool isInitializingFormal, bool hasImplicitType}) {
-  UnlinkedParamBuilder builder = new UnlinkedParamBuilder();
-  builder.name = name;
-  builder.nameOffset = nameOffset;
-  builder.type = type;
-  builder.parameters = parameters;
-  builder.kind = kind;
-  builder.isFunctionTyped = isFunctionTyped;
-  builder.isInitializingFormal = isInitializingFormal;
-  builder.hasImplicitType = hasImplicitType;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a function parameter.
- */
-abstract class UnlinkedParam extends base.SummaryClass {
-
-  /**
-   * Name of the parameter.
-   */
-  String get name;
-
-  /**
-   * Offset of the parameter name relative to the beginning of the file.
-   */
-  int get nameOffset;
-
-  /**
-   * If [isFunctionTyped] is `true`, the declared return type.  If
-   * [isFunctionTyped] is `false`, the declared type.  Absent if
-   * [isFunctionTyped] is `true` and the declared return type is `void`.  Note
-   * that when strong mode is enabled, the actual type may be different due to
-   * type inference.
-   */
-  UnlinkedTypeRef get type;
-
-  /**
-   * If [isFunctionTyped] is `true`, the parameters of the function type.
-   */
-  List<UnlinkedParam> get parameters;
-
-  /**
-   * Kind of the parameter.
-   */
-  UnlinkedParamKind get kind;
-
-  /**
-   * Indicates whether this is a function-typed parameter.
-   */
-  bool get isFunctionTyped;
-
-  /**
-   * Indicates whether this is an initializing formal parameter (i.e. it is
-   * declared using `this.` syntax).
-   */
-  bool get isInitializingFormal;
-
-  /**
-   * Indicates whether this parameter lacks an explicit type declaration.
-   * Always false for a function-typed parameter.
-   */
-  bool get hasImplicitType;
-}
-
-class _UnlinkedParamReader extends fb.TableReader<_UnlinkedParamImpl> {
-  const _UnlinkedParamReader();
-
-  @override
-  _UnlinkedParamImpl createObject(fb.BufferPointer bp) => new _UnlinkedParamImpl(bp);
-}
-
-class _UnlinkedParamImpl implements UnlinkedParam {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedParamImpl(this._bp);
-
-  String _name;
-  int _nameOffset;
-  UnlinkedTypeRef _type;
-  List<UnlinkedParam> _parameters;
-  UnlinkedParamKind _kind;
-  bool _isFunctionTyped;
-  bool _isInitializingFormal;
-  bool _hasImplicitType;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "type": type,
-    "parameters": parameters,
-    "kind": kind,
-    "isFunctionTyped": isFunctionTyped,
-    "isInitializingFormal": isInitializingFormal,
-    "hasImplicitType": hasImplicitType,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
-  }
-
-  @override
-  UnlinkedTypeRef get type {
-    _type ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 2, null);
-    return _type;
-  }
-
-  @override
-  List<UnlinkedParam> get parameters {
-    _parameters ??= const fb.ListReader<UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 3, const <UnlinkedParam>[]);
-    return _parameters;
-  }
-
-  @override
-  UnlinkedParamKind get kind {
-    _kind ??= UnlinkedParamKind.values[const fb.Int32Reader().vTableGet(_bp, 4, 0)];
-    return _kind;
-  }
-
-  @override
-  bool get isFunctionTyped {
-    _isFunctionTyped ??= const fb.BoolReader().vTableGet(_bp, 5, false);
-    return _isFunctionTyped;
-  }
-
-  @override
-  bool get isInitializingFormal {
-    _isInitializingFormal ??= const fb.BoolReader().vTableGet(_bp, 6, false);
-    return _isInitializingFormal;
-  }
-
-  @override
-  bool get hasImplicitType {
-    _hasImplicitType ??= const fb.BoolReader().vTableGet(_bp, 7, false);
-    return _hasImplicitType;
-  }
-}
-
-class UnlinkedPartBuilder {
-  bool _finished = false;
-
-  int _uriOffset;
-  int _uriEnd;
-
-  UnlinkedPartBuilder();
-
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.
-   */
-  void set uriOffset(int _value) {
-    assert(!_finished);
-    _uriOffset = _value;
-  }
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.
-   */
-  void set uriEnd(int _value) {
-    assert(!_finished);
-    _uriEnd = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fbBuilder.startTable();
-    if (_uriOffset != null && _uriOffset != 0) {
-      fbBuilder.addInt32(0, _uriOffset);
-    }
-    if (_uriEnd != null && _uriEnd != 0) {
-      fbBuilder.addInt32(1, _uriEnd);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedPartBuilder encodeUnlinkedPart({int uriOffset, int uriEnd}) {
-  UnlinkedPartBuilder builder = new UnlinkedPartBuilder();
-  builder.uriOffset = uriOffset;
-  builder.uriEnd = uriEnd;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a part declaration.
- */
-abstract class UnlinkedPart extends base.SummaryClass {
-
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.
-   */
-  int get uriOffset;
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.
-   */
-  int get uriEnd;
-}
-
-class _UnlinkedPartReader extends fb.TableReader<_UnlinkedPartImpl> {
-  const _UnlinkedPartReader();
-
-  @override
-  _UnlinkedPartImpl createObject(fb.BufferPointer bp) => new _UnlinkedPartImpl(bp);
-}
-
-class _UnlinkedPartImpl implements UnlinkedPart {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedPartImpl(this._bp);
-
-  int _uriOffset;
-  int _uriEnd;
-
-  @override
-  Map<String, Object> toMap() => {
-    "uriOffset": uriOffset,
-    "uriEnd": uriEnd,
-  };
-
-  @override
-  int get uriOffset {
-    _uriOffset ??= const fb.Int32Reader().vTableGet(_bp, 0, 0);
-    return _uriOffset;
-  }
-
-  @override
-  int get uriEnd {
-    _uriEnd ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _uriEnd;
-  }
-}
-
-class UnlinkedPublicNameBuilder {
-  bool _finished = false;
-
-  String _name;
-  PrelinkedReferenceKind _kind;
-  int _numTypeParameters;
-
-  UnlinkedPublicNameBuilder();
-
-  /**
-   * The name itself.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * The kind of object referred to by the name.
-   */
-  void set kind(PrelinkedReferenceKind _value) {
-    assert(!_finished);
-    _kind = _value;
-  }
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  void set numTypeParameters(int _value) {
-    assert(!_finished);
-    _numTypeParameters = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_kind != null && _kind != PrelinkedReferenceKind.classOrEnum) {
-      fbBuilder.addInt32(1, _kind.index);
-    }
-    if (_numTypeParameters != null && _numTypeParameters != 0) {
-      fbBuilder.addInt32(2, _numTypeParameters);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedPublicNameBuilder encodeUnlinkedPublicName({String name, PrelinkedReferenceKind kind, int numTypeParameters}) {
-  UnlinkedPublicNameBuilder builder = new UnlinkedPublicNameBuilder();
-  builder.name = name;
-  builder.kind = kind;
-  builder.numTypeParameters = numTypeParameters;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a specific name contributed by a
- * compilation unit to a library's public namespace.
- *
- * TODO(paulberry): add a count of generic parameters, so that resynthesis
- * doesn't have to peek into the library to obtain this info.
- *
- * TODO(paulberry): for classes, add info about static members and
- * constructors, since this will be needed to prelink info about constants.
- *
- * TODO(paulberry): some of this information is redundant with information
- * elsewhere in the summary.  Consider reducing the redundancy to reduce
- * summary size.
- */
-abstract class UnlinkedPublicName extends base.SummaryClass {
-
-  /**
-   * The name itself.
-   */
-  String get name;
-
-  /**
-   * The kind of object referred to by the name.
-   */
-  PrelinkedReferenceKind get kind;
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  int get numTypeParameters;
-}
-
-class _UnlinkedPublicNameReader extends fb.TableReader<_UnlinkedPublicNameImpl> {
-  const _UnlinkedPublicNameReader();
-
-  @override
-  _UnlinkedPublicNameImpl createObject(fb.BufferPointer bp) => new _UnlinkedPublicNameImpl(bp);
-}
-
-class _UnlinkedPublicNameImpl implements UnlinkedPublicName {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedPublicNameImpl(this._bp);
-
-  String _name;
-  PrelinkedReferenceKind _kind;
-  int _numTypeParameters;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "kind": kind,
-    "numTypeParameters": numTypeParameters,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  PrelinkedReferenceKind get kind {
-    _kind ??= PrelinkedReferenceKind.values[const fb.Int32Reader().vTableGet(_bp, 1, 0)];
-    return _kind;
-  }
-
-  @override
-  int get numTypeParameters {
-    _numTypeParameters ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
-    return _numTypeParameters;
-  }
-}
-
-class UnlinkedPublicNamespaceBuilder {
-  bool _finished = false;
-
-  List<UnlinkedPublicNameBuilder> _names;
-  List<UnlinkedExportPublicBuilder> _exports;
-  List<String> _parts;
-
-  UnlinkedPublicNamespaceBuilder();
-
-  /**
-   * Public names defined in the compilation unit.
-   *
-   * TODO(paulberry): consider sorting these names to reduce unnecessary
-   * relinking.
-   */
-  void set names(List<UnlinkedPublicNameBuilder> _value) {
-    assert(!_finished);
-    _names = _value;
-  }
-
-  /**
-   * Export declarations in the compilation unit.
-   */
-  void set exports(List<UnlinkedExportPublicBuilder> _value) {
-    assert(!_finished);
-    _exports = _value;
-  }
-
-  /**
-   * URIs referenced by part declarations in the compilation unit.
-   */
-  void set parts(List<String> _value) {
-    assert(!_finished);
-    _parts = _value;
-  }
-
-  List<int> toBuffer() {
-    fb.Builder fbBuilder = new fb.Builder();
-    return fbBuilder.finish(finish(fbBuilder));
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_names;
-    fb.Offset offset_exports;
-    fb.Offset offset_parts;
-    if (!(_names == null || _names.isEmpty)) {
-      offset_names = fbBuilder.writeList(_names.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_exports == null || _exports.isEmpty)) {
-      offset_exports = fbBuilder.writeList(_exports.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (!(_parts == null || _parts.isEmpty)) {
-      offset_parts = fbBuilder.writeList(_parts.map((b) => fbBuilder.writeString(b)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_names != null) {
-      fbBuilder.addOffset(0, offset_names);
-    }
-    if (offset_exports != null) {
-      fbBuilder.addOffset(1, offset_exports);
-    }
-    if (offset_parts != null) {
-      fbBuilder.addOffset(2, offset_parts);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedPublicNamespaceBuilder encodeUnlinkedPublicNamespace({List<UnlinkedPublicNameBuilder> names, List<UnlinkedExportPublicBuilder> exports, List<String> parts}) {
-  UnlinkedPublicNamespaceBuilder builder = new UnlinkedPublicNamespaceBuilder();
-  builder.names = names;
-  builder.exports = exports;
-  builder.parts = parts;
-  return builder;
-}
-
-/**
- * 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.
- */
-abstract class UnlinkedPublicNamespace extends base.SummaryClass {
-  factory UnlinkedPublicNamespace.fromBuffer(List<int> buffer) {
-    fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
-    return const _UnlinkedPublicNamespaceReader().read(rootRef);
-  }
-
-  /**
-   * Public names defined in the compilation unit.
-   *
-   * TODO(paulberry): consider sorting these names to reduce unnecessary
-   * relinking.
-   */
-  List<UnlinkedPublicName> get names;
-
-  /**
-   * Export declarations in the compilation unit.
-   */
-  List<UnlinkedExportPublic> get exports;
-
-  /**
-   * URIs referenced by part declarations in the compilation unit.
-   */
-  List<String> get parts;
-}
-
-class _UnlinkedPublicNamespaceReader extends fb.TableReader<_UnlinkedPublicNamespaceImpl> {
-  const _UnlinkedPublicNamespaceReader();
-
-  @override
-  _UnlinkedPublicNamespaceImpl createObject(fb.BufferPointer bp) => new _UnlinkedPublicNamespaceImpl(bp);
-}
-
-class _UnlinkedPublicNamespaceImpl implements UnlinkedPublicNamespace {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedPublicNamespaceImpl(this._bp);
-
-  List<UnlinkedPublicName> _names;
-  List<UnlinkedExportPublic> _exports;
-  List<String> _parts;
-
-  @override
-  Map<String, Object> toMap() => {
-    "names": names,
-    "exports": exports,
-    "parts": parts,
-  };
-
-  @override
-  List<UnlinkedPublicName> get names {
-    _names ??= const fb.ListReader<UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 0, const <UnlinkedPublicName>[]);
-    return _names;
-  }
-
-  @override
-  List<UnlinkedExportPublic> get exports {
-    _exports ??= const fb.ListReader<UnlinkedExportPublic>(const _UnlinkedExportPublicReader()).vTableGet(_bp, 1, const <UnlinkedExportPublic>[]);
-    return _exports;
-  }
-
-  @override
-  List<String> get parts {
-    _parts ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 2, const <String>[]);
-    return _parts;
-  }
-}
-
-class UnlinkedReferenceBuilder {
-  bool _finished = false;
-
-  String _name;
-  int _prefixReference;
-
-  UnlinkedReferenceBuilder();
-
-  /**
-   * Name of the entity being referred to.  The empty string refers to the
-   * pseudo-type `dynamic`.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * 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.
-   */
-  void set prefixReference(int _value) {
-    assert(!_finished);
-    _prefixReference = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_prefixReference != null && _prefixReference != 0) {
-      fbBuilder.addInt32(1, _prefixReference);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedReferenceBuilder encodeUnlinkedReference({String name, int prefixReference}) {
-  UnlinkedReferenceBuilder builder = new UnlinkedReferenceBuilder();
-  builder.name = name;
-  builder.prefixReference = prefixReference;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a name referred to in one library that
- * might be defined in another.
- */
-abstract class UnlinkedReference extends base.SummaryClass {
-
-  /**
-   * Name of the entity being referred to.  The empty string refers to the
-   * pseudo-type `dynamic`.
-   */
-  String get name;
-
-  /**
-   * 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.
-   */
-  int get prefixReference;
-}
-
-class _UnlinkedReferenceReader extends fb.TableReader<_UnlinkedReferenceImpl> {
-  const _UnlinkedReferenceReader();
-
-  @override
-  _UnlinkedReferenceImpl createObject(fb.BufferPointer bp) => new _UnlinkedReferenceImpl(bp);
-}
-
-class _UnlinkedReferenceImpl implements UnlinkedReference {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedReferenceImpl(this._bp);
-
-  String _name;
-  int _prefixReference;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "prefixReference": prefixReference,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  int get prefixReference {
-    _prefixReference ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _prefixReference;
-  }
-}
-
-class UnlinkedTypedefBuilder {
-  bool _finished = false;
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-  List<UnlinkedTypeParamBuilder> _typeParameters;
-  UnlinkedTypeRefBuilder _returnType;
-  List<UnlinkedParamBuilder> _parameters;
-
-  UnlinkedTypedefBuilder();
-
-  /**
-   * Name of the typedef.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * Offset of the typedef name relative to the beginning of the file.
-   */
-  void set nameOffset(int _value) {
-    assert(!_finished);
-    _nameOffset = _value;
-  }
-
-  /**
-   * Documentation comment for the typedef, or `null` if there is no
-   * documentation comment.
-   */
-  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
-    assert(!_finished);
-    _documentationComment = _value;
-  }
-
-  /**
-   * Type parameters of the typedef, if any.
-   */
-  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
-    assert(!_finished);
-    _typeParameters = _value;
-  }
-
-  /**
-   * Return type of the typedef.  Absent if the return type is `void`.
-   */
-  void set returnType(UnlinkedTypeRefBuilder _value) {
-    assert(!_finished);
-    _returnType = _value;
-  }
-
-  /**
-   * Parameters of the executable, if any.
-   */
-  void set parameters(List<UnlinkedParamBuilder> _value) {
-    assert(!_finished);
-    _parameters = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    fb.Offset offset_documentationComment;
-    fb.Offset offset_typeParameters;
-    fb.Offset offset_returnType;
-    fb.Offset offset_parameters;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    if (_documentationComment != null) {
-      offset_documentationComment = _documentationComment.finish(fbBuilder);
-    }
-    if (!(_typeParameters == null || _typeParameters.isEmpty)) {
-      offset_typeParameters = fbBuilder.writeList(_typeParameters.map((b) => b.finish(fbBuilder)).toList());
-    }
-    if (_returnType != null) {
-      offset_returnType = _returnType.finish(fbBuilder);
-    }
-    if (!(_parameters == null || _parameters.isEmpty)) {
-      offset_parameters = fbBuilder.writeList(_parameters.map((b) => b.finish(fbBuilder)).toList());
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addInt32(1, _nameOffset);
-    }
-    if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
-    }
-    if (offset_typeParameters != null) {
-      fbBuilder.addOffset(3, offset_typeParameters);
-    }
-    if (offset_returnType != null) {
-      fbBuilder.addOffset(4, offset_returnType);
-    }
-    if (offset_parameters != null) {
-      fbBuilder.addOffset(5, offset_parameters);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedTypedefBuilder encodeUnlinkedTypedef({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedTypeParamBuilder> typeParameters, UnlinkedTypeRefBuilder returnType, List<UnlinkedParamBuilder> parameters}) {
-  UnlinkedTypedefBuilder builder = new UnlinkedTypedefBuilder();
-  builder.name = name;
-  builder.nameOffset = nameOffset;
-  builder.documentationComment = documentationComment;
-  builder.typeParameters = typeParameters;
-  builder.returnType = returnType;
-  builder.parameters = parameters;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a typedef declaration.
- */
-abstract class UnlinkedTypedef extends base.SummaryClass {
-
-  /**
-   * Name of the typedef.
-   */
-  String get name;
-
-  /**
-   * Offset of the typedef name relative to the beginning of the file.
-   */
-  int get nameOffset;
-
-  /**
-   * Documentation comment for the typedef, or `null` if there is no
-   * documentation comment.
-   */
-  UnlinkedDocumentationComment get documentationComment;
-
-  /**
-   * Type parameters of the typedef, if any.
-   */
-  List<UnlinkedTypeParam> get typeParameters;
-
-  /**
-   * Return type of the typedef.  Absent if the return type is `void`.
-   */
-  UnlinkedTypeRef get returnType;
-
-  /**
-   * Parameters of the executable, if any.
-   */
-  List<UnlinkedParam> get parameters;
-}
-
-class _UnlinkedTypedefReader extends fb.TableReader<_UnlinkedTypedefImpl> {
-  const _UnlinkedTypedefReader();
-
-  @override
-  _UnlinkedTypedefImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypedefImpl(bp);
-}
-
-class _UnlinkedTypedefImpl implements UnlinkedTypedef {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedTypedefImpl(this._bp);
-
-  String _name;
-  int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-  List<UnlinkedTypeParam> _typeParameters;
-  UnlinkedTypeRef _returnType;
-  List<UnlinkedParam> _parameters;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-    "typeParameters": typeParameters,
-    "returnType": returnType,
-    "parameters": parameters,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
-  }
-
-  @override
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
-    return _documentationComment;
-  }
-
-  @override
-  List<UnlinkedTypeParam> get typeParameters {
-    _typeParameters ??= const fb.ListReader<UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 3, const <UnlinkedTypeParam>[]);
-    return _typeParameters;
-  }
-
-  @override
-  UnlinkedTypeRef get returnType {
-    _returnType ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 4, null);
-    return _returnType;
-  }
-
-  @override
-  List<UnlinkedParam> get parameters {
-    _parameters ??= const fb.ListReader<UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 5, const <UnlinkedParam>[]);
-    return _parameters;
-  }
-}
-
-class UnlinkedTypeParamBuilder {
-  bool _finished = false;
-
-  String _name;
-  int _nameOffset;
-  UnlinkedTypeRefBuilder _bound;
-
-  UnlinkedTypeParamBuilder();
-
-  /**
-   * Name of the type parameter.
-   */
-  void set name(String _value) {
-    assert(!_finished);
-    _name = _value;
-  }
-
-  /**
-   * Offset of the type parameter name relative to the beginning of the file.
-   */
-  void set nameOffset(int _value) {
-    assert(!_finished);
-    _nameOffset = _value;
-  }
-
-  /**
-   * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
-   * null.
-   */
-  void set bound(UnlinkedTypeRefBuilder _value) {
-    assert(!_finished);
-    _bound = _value;
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    assert(!_finished);
-    _finished = true;
-    fb.Offset offset_name;
-    fb.Offset offset_bound;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
-    }
-    if (_bound != null) {
-      offset_bound = _bound.finish(fbBuilder);
-    }
-    fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
-    }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addInt32(1, _nameOffset);
-    }
-    if (offset_bound != null) {
-      fbBuilder.addOffset(2, offset_bound);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-UnlinkedTypeParamBuilder encodeUnlinkedTypeParam({String name, int nameOffset, UnlinkedTypeRefBuilder bound}) {
-  UnlinkedTypeParamBuilder builder = new UnlinkedTypeParamBuilder();
-  builder.name = name;
-  builder.nameOffset = nameOffset;
-  builder.bound = bound;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a type parameter declaration.
- */
-abstract class UnlinkedTypeParam extends base.SummaryClass {
-
-  /**
-   * Name of the type parameter.
-   */
-  String get name;
-
-  /**
-   * Offset of the type parameter name relative to the beginning of the file.
-   */
-  int get nameOffset;
-
-  /**
-   * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
-   * null.
-   */
-  UnlinkedTypeRef get bound;
-}
-
-class _UnlinkedTypeParamReader extends fb.TableReader<_UnlinkedTypeParamImpl> {
-  const _UnlinkedTypeParamReader();
-
-  @override
-  _UnlinkedTypeParamImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypeParamImpl(bp);
-}
-
-class _UnlinkedTypeParamImpl implements UnlinkedTypeParam {
-  final fb.BufferPointer _bp;
-
-  _UnlinkedTypeParamImpl(this._bp);
-
-  String _name;
-  int _nameOffset;
-  UnlinkedTypeRef _bound;
-
-  @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "bound": bound,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
-  }
-
-  @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
-  }
-
-  @override
-  UnlinkedTypeRef get bound {
-    _bound ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 2, null);
-    return _bound;
-  }
-}
-
-class UnlinkedTypeRefBuilder {
-  bool _finished = false;
-
-  int _reference;
+  List<int> _implicitFunctionTypeIndices;
   int _paramReference;
-  List<UnlinkedTypeRefBuilder> _typeArguments;
+  int _reference;
+  int _slot;
+  List<UnlinkedParamBuilder> _syntheticParams;
+  EntityRefBuilder _syntheticReturnType;
+  List<EntityRefBuilder> _typeArguments;
 
-  UnlinkedTypeRefBuilder();
+  @override
+  List<int> get implicitFunctionTypeIndices => _implicitFunctionTypeIndices ??= <int>[];
 
   /**
-   * Index into [UnlinkedUnit.references] for the type being referred to, or
-   * zero if this is a reference to a type parameter.
+   * 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.
    *
-   * Note that since zero is also a valid index into
-   * [UnlinkedUnit.references], we cannot distinguish between references to
-   * type parameters and references to types by checking [reference] against
-   * zero.  To distinguish between references to type parameters and references
-   * to types, check whether [paramReference] is zero.
+   * 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.
    */
-  void set reference(int _value) {
+  void set implicitFunctionTypeIndices(List<int> _value) {
     assert(!_finished);
-    _reference = _value;
+    assert(_value == null || _value.every((e) => e >= 0));
+    _implicitFunctionTypeIndices = _value;
   }
 
+  @override
+  int get paramReference => _paramReference ??= 0;
+
   /**
    * 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
@@ -3790,206 +181,6248 @@
    */
   void set paramReference(int _value) {
     assert(!_finished);
+    assert(_value == null || _value >= 0);
     _paramReference = _value;
   }
 
+  @override
+  int get reference => _reference ??= 0;
+
   /**
-   * If this is an instantiation of a generic type, the type arguments used to
-   * instantiate it.  Trailing type arguments of type `dynamic` are omitted.
+   * Index into [UnlinkedUnit.references] for the entity being referred to, or
+   * zero if this is a reference to a type parameter.
    */
-  void set typeArguments(List<UnlinkedTypeRefBuilder> _value) {
+  void set reference(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _reference = _value;
+  }
+
+  @override
+  int get slot => _slot ??= 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.
+   */
+  void set slot(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _slot = _value;
+  }
+
+  @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>[];
+
+  /**
+   * 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.
+   */
+  void set typeArguments(List<EntityRefBuilder> _value) {
     assert(!_finished);
     _typeArguments = _value;
   }
 
+  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());
     }
     fbBuilder.startTable();
-    if (_reference != null && _reference != 0) {
-      fbBuilder.addInt32(0, _reference);
+    if (offset_implicitFunctionTypeIndices != null) {
+      fbBuilder.addOffset(4, offset_implicitFunctionTypeIndices);
     }
     if (_paramReference != null && _paramReference != 0) {
-      fbBuilder.addInt32(1, _paramReference);
+      fbBuilder.addUint32(3, _paramReference);
+    }
+    if (_reference != null && _reference != 0) {
+      fbBuilder.addUint32(0, _reference);
+    }
+    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(2, offset_typeArguments);
+      fbBuilder.addOffset(1, offset_typeArguments);
     }
     return fbBuilder.endTable();
   }
 }
 
-UnlinkedTypeRefBuilder encodeUnlinkedTypeRef({int reference, int paramReference, List<UnlinkedTypeRefBuilder> typeArguments}) {
-  UnlinkedTypeRefBuilder builder = new UnlinkedTypeRefBuilder();
-  builder.reference = reference;
-  builder.paramReference = paramReference;
-  builder.typeArguments = typeArguments;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a reference to a type.
- */
-abstract class UnlinkedTypeRef extends base.SummaryClass {
-
-  /**
-   * Index into [UnlinkedUnit.references] for the type being referred to, or
-   * zero if this is a reference to a type parameter.
-   *
-   * Note that since zero is also a valid index into
-   * [UnlinkedUnit.references], we cannot distinguish between references to
-   * type parameters and references to types by checking [reference] against
-   * zero.  To distinguish between references to type parameters and references
-   * to types, check whether [paramReference] is zero.
-   */
-  int get reference;
-
-  /**
-   * 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.
-   */
-  int get paramReference;
-
-  /**
-   * If this is an instantiation of a generic type, the type arguments used to
-   * instantiate it.  Trailing type arguments of type `dynamic` are omitted.
-   */
-  List<UnlinkedTypeRef> get typeArguments;
-}
-
-class _UnlinkedTypeRefReader extends fb.TableReader<_UnlinkedTypeRefImpl> {
-  const _UnlinkedTypeRefReader();
+class _EntityRefReader extends fb.TableReader<_EntityRefImpl> {
+  const _EntityRefReader();
 
   @override
-  _UnlinkedTypeRefImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypeRefImpl(bp);
+  _EntityRefImpl createObject(fb.BufferPointer bp) => new _EntityRefImpl(bp);
 }
 
-class _UnlinkedTypeRefImpl implements UnlinkedTypeRef {
+class _EntityRefImpl extends Object with _EntityRefMixin implements idl.EntityRef {
   final fb.BufferPointer _bp;
 
-  _UnlinkedTypeRefImpl(this._bp);
+  _EntityRefImpl(this._bp);
 
-  int _reference;
+  List<int> _implicitFunctionTypeIndices;
   int _paramReference;
-  List<UnlinkedTypeRef> _typeArguments;
+  int _reference;
+  int _slot;
+  List<idl.UnlinkedParam> _syntheticParams;
+  idl.EntityRef _syntheticReturnType;
+  List<idl.EntityRef> _typeArguments;
 
   @override
-  Map<String, Object> toMap() => {
-    "reference": reference,
-    "paramReference": paramReference,
-    "typeArguments": typeArguments,
-  };
-
-  @override
-  int get reference {
-    _reference ??= const fb.Int32Reader().vTableGet(_bp, 0, 0);
-    return _reference;
+  List<int> get implicitFunctionTypeIndices {
+    _implicitFunctionTypeIndices ??= const fb.Uint32ListReader().vTableGet(_bp, 4, const <int>[]);
+    return _implicitFunctionTypeIndices;
   }
 
   @override
   int get paramReference {
-    _paramReference ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
+    _paramReference ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
     return _paramReference;
   }
 
   @override
-  List<UnlinkedTypeRef> get typeArguments {
-    _typeArguments ??= const fb.ListReader<UnlinkedTypeRef>(const _UnlinkedTypeRefReader()).vTableGet(_bp, 2, const <UnlinkedTypeRef>[]);
+  int get reference {
+    _reference ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _reference;
+  }
+
+  @override
+  int get slot {
+    _slot ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _slot;
+  }
+
+  @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;
   }
 }
 
-class UnlinkedUnitBuilder {
+abstract class _EntityRefMixin implements idl.EntityRef {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (implicitFunctionTypeIndices.isNotEmpty) _result["implicitFunctionTypeIndices"] = implicitFunctionTypeIndices;
+    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;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "implicitFunctionTypeIndices": implicitFunctionTypeIndices,
+    "paramReference": paramReference,
+    "reference": reference,
+    "slot": slot,
+    "syntheticParams": syntheticParams,
+    "syntheticReturnType": syntheticReturnType,
+    "typeArguments": typeArguments,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class LinkedDependencyBuilder extends Object with _LinkedDependencyMixin implements idl.LinkedDependency {
   bool _finished = false;
 
-  String _libraryName;
-  int _libraryNameOffset;
-  int _libraryNameLength;
-  UnlinkedDocumentationCommentBuilder _libraryDocumentationComment;
-  UnlinkedPublicNamespaceBuilder _publicNamespace;
-  List<UnlinkedReferenceBuilder> _references;
+  List<String> _parts;
+  String _uri;
+
+  @override
+  List<String> get parts => _parts ??= <String>[];
+
+  /**
+   * URI for the compilation units listed in the library's `part` declarations.
+   * These URIs are relative to the importing library.
+   */
+  void set parts(List<String> _value) {
+    assert(!_finished);
+    _parts = _value;
+  }
+
+  @override
+  String get uri => _uri ??= '';
+
+  /**
+   * 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`.
+   */
+  void set uri(String _value) {
+    assert(!_finished);
+    _uri = _value;
+  }
+
+  LinkedDependencyBuilder({List<String> parts, String uri})
+    : _parts = parts,
+      _uri = uri;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_parts;
+    fb.Offset offset_uri;
+    if (!(_parts == null || _parts.isEmpty)) {
+      offset_parts = fbBuilder.writeList(_parts.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    if (_uri != null) {
+      offset_uri = fbBuilder.writeString(_uri);
+    }
+    fbBuilder.startTable();
+    if (offset_parts != null) {
+      fbBuilder.addOffset(1, offset_parts);
+    }
+    if (offset_uri != null) {
+      fbBuilder.addOffset(0, offset_uri);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _LinkedDependencyReader extends fb.TableReader<_LinkedDependencyImpl> {
+  const _LinkedDependencyReader();
+
+  @override
+  _LinkedDependencyImpl createObject(fb.BufferPointer bp) => new _LinkedDependencyImpl(bp);
+}
+
+class _LinkedDependencyImpl extends Object with _LinkedDependencyMixin implements idl.LinkedDependency {
+  final fb.BufferPointer _bp;
+
+  _LinkedDependencyImpl(this._bp);
+
+  List<String> _parts;
+  String _uri;
+
+  @override
+  List<String> get parts {
+    _parts ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
+    return _parts;
+  }
+
+  @override
+  String get uri {
+    _uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _uri;
+  }
+}
+
+abstract class _LinkedDependencyMixin implements idl.LinkedDependency {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (parts.isNotEmpty) _result["parts"] = parts;
+    if (uri != '') _result["uri"] = uri;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "parts": parts,
+    "uri": uri,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class LinkedExportNameBuilder extends Object with _LinkedExportNameMixin implements idl.LinkedExportName {
+  bool _finished = false;
+
+  int _dependency;
+  idl.ReferenceKind _kind;
+  String _name;
+  int _unit;
+
+  @override
+  int get dependency => _dependency ??= 0;
+
+  /**
+   * Index into [LinkedLibrary.dependencies] for the library in which the
+   * entity is defined.
+   */
+  void set dependency(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _dependency = _value;
+  }
+
+  @override
+  idl.ReferenceKind get kind => _kind ??= idl.ReferenceKind.classOrEnum;
+
+  /**
+   * The kind of the entity being referred to.
+   */
+  void set kind(idl.ReferenceKind _value) {
+    assert(!_finished);
+    _kind = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * Name of the exported entity.  For an exported setter, this name includes
+   * the trailing '='.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get unit => _unit ??= 0;
+
+  /**
+   * 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.
+   */
+  void set unit(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _unit = _value;
+  }
+
+  LinkedExportNameBuilder({int dependency, idl.ReferenceKind kind, String name, int unit})
+    : _dependency = dependency,
+      _kind = kind,
+      _name = name,
+      _unit = unit;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_name;
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (_dependency != null && _dependency != 0) {
+      fbBuilder.addUint32(0, _dependency);
+    }
+    if (_kind != null && _kind != idl.ReferenceKind.classOrEnum) {
+      fbBuilder.addUint8(3, _kind.index);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(1, offset_name);
+    }
+    if (_unit != null && _unit != 0) {
+      fbBuilder.addUint32(2, _unit);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _LinkedExportNameReader extends fb.TableReader<_LinkedExportNameImpl> {
+  const _LinkedExportNameReader();
+
+  @override
+  _LinkedExportNameImpl createObject(fb.BufferPointer bp) => new _LinkedExportNameImpl(bp);
+}
+
+class _LinkedExportNameImpl extends Object with _LinkedExportNameMixin implements idl.LinkedExportName {
+  final fb.BufferPointer _bp;
+
+  _LinkedExportNameImpl(this._bp);
+
+  int _dependency;
+  idl.ReferenceKind _kind;
+  String _name;
+  int _unit;
+
+  @override
+  int get dependency {
+    _dependency ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _dependency;
+  }
+
+  @override
+  idl.ReferenceKind get kind {
+    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 3, idl.ReferenceKind.classOrEnum);
+    return _kind;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 1, '');
+    return _name;
+  }
+
+  @override
+  int get unit {
+    _unit ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _unit;
+  }
+}
+
+abstract class _LinkedExportNameMixin implements idl.LinkedExportName {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (dependency != 0) _result["dependency"] = dependency;
+    if (kind != idl.ReferenceKind.classOrEnum) _result["kind"] = kind.toString().split('.')[1];
+    if (name != '') _result["name"] = name;
+    if (unit != 0) _result["unit"] = unit;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "dependency": dependency,
+    "kind": kind,
+    "name": name,
+    "unit": unit,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class LinkedLibraryBuilder extends Object with _LinkedLibraryMixin implements idl.LinkedLibrary {
+  bool _finished = false;
+
+  List<LinkedDependencyBuilder> _dependencies;
+  List<LinkedExportNameBuilder> _exportNames;
+  List<int> _importDependencies;
+  int _numPrelinkedDependencies;
+  List<LinkedUnitBuilder> _units;
+
+  @override
+  List<LinkedDependencyBuilder> get dependencies => _dependencies ??= <LinkedDependencyBuilder>[];
+
+  /**
+   * 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).
+   */
+  void set dependencies(List<LinkedDependencyBuilder> _value) {
+    assert(!_finished);
+    _dependencies = _value;
+  }
+
+  @override
+  List<LinkedExportNameBuilder> get exportNames => _exportNames ??= <LinkedExportNameBuilder>[];
+
+  /**
+   * 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.
+   */
+  void set exportNames(List<LinkedExportNameBuilder> _value) {
+    assert(!_finished);
+    _exportNames = _value;
+  }
+
+  @override
+  List<int> get importDependencies => _importDependencies ??= <int>[];
+
+  /**
+   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
+   * of the library being imported.
+   */
+  void set importDependencies(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _importDependencies = _value;
+  }
+
+  @override
+  int get numPrelinkedDependencies => _numPrelinkedDependencies ??= 0;
+
+  /**
+   * 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).
+   */
+  void set numPrelinkedDependencies(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _numPrelinkedDependencies = _value;
+  }
+
+  @override
+  List<LinkedUnitBuilder> get units => _units ??= <LinkedUnitBuilder>[];
+
+  /**
+   * 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.
+   */
+  void set units(List<LinkedUnitBuilder> _value) {
+    assert(!_finished);
+    _units = _value;
+  }
+
+  LinkedLibraryBuilder({List<LinkedDependencyBuilder> dependencies, List<LinkedExportNameBuilder> exportNames, List<int> importDependencies, int numPrelinkedDependencies, List<LinkedUnitBuilder> units})
+    : _dependencies = dependencies,
+      _exportNames = exportNames,
+      _importDependencies = importDependencies,
+      _numPrelinkedDependencies = numPrelinkedDependencies,
+      _units = units;
+
+  List<int> toBuffer() {
+    fb.Builder fbBuilder = new fb.Builder();
+    return fbBuilder.finish(finish(fbBuilder), "LLib");
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_dependencies;
+    fb.Offset offset_exportNames;
+    fb.Offset offset_importDependencies;
+    fb.Offset offset_units;
+    if (!(_dependencies == null || _dependencies.isEmpty)) {
+      offset_dependencies = fbBuilder.writeList(_dependencies.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_exportNames == null || _exportNames.isEmpty)) {
+      offset_exportNames = fbBuilder.writeList(_exportNames.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_importDependencies == null || _importDependencies.isEmpty)) {
+      offset_importDependencies = fbBuilder.writeListUint32(_importDependencies);
+    }
+    if (!(_units == null || _units.isEmpty)) {
+      offset_units = fbBuilder.writeList(_units.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_dependencies != null) {
+      fbBuilder.addOffset(0, offset_dependencies);
+    }
+    if (offset_exportNames != null) {
+      fbBuilder.addOffset(4, offset_exportNames);
+    }
+    if (offset_importDependencies != null) {
+      fbBuilder.addOffset(1, offset_importDependencies);
+    }
+    if (_numPrelinkedDependencies != null && _numPrelinkedDependencies != 0) {
+      fbBuilder.addUint32(2, _numPrelinkedDependencies);
+    }
+    if (offset_units != null) {
+      fbBuilder.addOffset(3, offset_units);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+idl.LinkedLibrary readLinkedLibrary(List<int> buffer) {
+  fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
+  return const _LinkedLibraryReader().read(rootRef);
+}
+
+class _LinkedLibraryReader extends fb.TableReader<_LinkedLibraryImpl> {
+  const _LinkedLibraryReader();
+
+  @override
+  _LinkedLibraryImpl createObject(fb.BufferPointer bp) => new _LinkedLibraryImpl(bp);
+}
+
+class _LinkedLibraryImpl extends Object with _LinkedLibraryMixin implements idl.LinkedLibrary {
+  final fb.BufferPointer _bp;
+
+  _LinkedLibraryImpl(this._bp);
+
+  List<idl.LinkedDependency> _dependencies;
+  List<idl.LinkedExportName> _exportNames;
+  List<int> _importDependencies;
+  int _numPrelinkedDependencies;
+  List<idl.LinkedUnit> _units;
+
+  @override
+  List<idl.LinkedDependency> get dependencies {
+    _dependencies ??= const fb.ListReader<idl.LinkedDependency>(const _LinkedDependencyReader()).vTableGet(_bp, 0, const <idl.LinkedDependency>[]);
+    return _dependencies;
+  }
+
+  @override
+  List<idl.LinkedExportName> get exportNames {
+    _exportNames ??= const fb.ListReader<idl.LinkedExportName>(const _LinkedExportNameReader()).vTableGet(_bp, 4, const <idl.LinkedExportName>[]);
+    return _exportNames;
+  }
+
+  @override
+  List<int> get importDependencies {
+    _importDependencies ??= const fb.Uint32ListReader().vTableGet(_bp, 1, const <int>[]);
+    return _importDependencies;
+  }
+
+  @override
+  int get numPrelinkedDependencies {
+    _numPrelinkedDependencies ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _numPrelinkedDependencies;
+  }
+
+  @override
+  List<idl.LinkedUnit> get units {
+    _units ??= const fb.ListReader<idl.LinkedUnit>(const _LinkedUnitReader()).vTableGet(_bp, 3, const <idl.LinkedUnit>[]);
+    return _units;
+  }
+}
+
+abstract class _LinkedLibraryMixin implements idl.LinkedLibrary {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (dependencies.isNotEmpty) _result["dependencies"] = dependencies.map((_value) => _value.toJson()).toList();
+    if (exportNames.isNotEmpty) _result["exportNames"] = exportNames.map((_value) => _value.toJson()).toList();
+    if (importDependencies.isNotEmpty) _result["importDependencies"] = importDependencies;
+    if (numPrelinkedDependencies != 0) _result["numPrelinkedDependencies"] = numPrelinkedDependencies;
+    if (units.isNotEmpty) _result["units"] = units.map((_value) => _value.toJson()).toList();
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "dependencies": dependencies,
+    "exportNames": exportNames,
+    "importDependencies": importDependencies,
+    "numPrelinkedDependencies": numPrelinkedDependencies,
+    "units": units,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class LinkedReferenceBuilder extends Object with _LinkedReferenceMixin implements idl.LinkedReference {
+  bool _finished = false;
+
+  int _containingReference;
+  int _dependency;
+  idl.ReferenceKind _kind;
+  int _localIndex;
+  String _name;
+  int _numTypeParameters;
+  int _unit;
+
+  @override
+  int get containingReference => _containingReference ??= 0;
+
+  /**
+   * 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.
+   */
+  void set containingReference(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _containingReference = _value;
+  }
+
+  @override
+  int get dependency => _dependency ??= 0;
+
+  /**
+   * 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].
+   */
+  void set dependency(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _dependency = _value;
+  }
+
+  @override
+  idl.ReferenceKind get kind => _kind ??= idl.ReferenceKind.classOrEnum;
+
+  /**
+   * The kind of the entity being referred to.  For the pseudo-types `dynamic`
+   * and `void`, the kind is [ReferenceKind.classOrEnum].
+   */
+  void set kind(idl.ReferenceKind _value) {
+    assert(!_finished);
+    _kind = _value;
+  }
+
+  @override
+  int get localIndex => _localIndex ??= 0;
+
+  /**
+   * 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.
+   */
+  void set localIndex(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _localIndex = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * 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".
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get numTypeParameters => _numTypeParameters ??= 0;
+
+  /**
+   * 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.
+   */
+  void set numTypeParameters(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _numTypeParameters = _value;
+  }
+
+  @override
+  int get unit => _unit ??= 0;
+
+  /**
+   * 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).
+   */
+  void set unit(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _unit = _value;
+  }
+
+  LinkedReferenceBuilder({int containingReference, int dependency, idl.ReferenceKind kind, int localIndex, String name, int numTypeParameters, int unit})
+    : _containingReference = containingReference,
+      _dependency = dependency,
+      _kind = kind,
+      _localIndex = localIndex,
+      _name = name,
+      _numTypeParameters = numTypeParameters,
+      _unit = unit;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_name;
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (_containingReference != null && _containingReference != 0) {
+      fbBuilder.addUint32(5, _containingReference);
+    }
+    if (_dependency != null && _dependency != 0) {
+      fbBuilder.addUint32(1, _dependency);
+    }
+    if (_kind != null && _kind != idl.ReferenceKind.classOrEnum) {
+      fbBuilder.addUint8(2, _kind.index);
+    }
+    if (_localIndex != null && _localIndex != 0) {
+      fbBuilder.addUint32(6, _localIndex);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(3, offset_name);
+    }
+    if (_numTypeParameters != null && _numTypeParameters != 0) {
+      fbBuilder.addUint32(4, _numTypeParameters);
+    }
+    if (_unit != null && _unit != 0) {
+      fbBuilder.addUint32(0, _unit);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _LinkedReferenceReader extends fb.TableReader<_LinkedReferenceImpl> {
+  const _LinkedReferenceReader();
+
+  @override
+  _LinkedReferenceImpl createObject(fb.BufferPointer bp) => new _LinkedReferenceImpl(bp);
+}
+
+class _LinkedReferenceImpl extends Object with _LinkedReferenceMixin implements idl.LinkedReference {
+  final fb.BufferPointer _bp;
+
+  _LinkedReferenceImpl(this._bp);
+
+  int _containingReference;
+  int _dependency;
+  idl.ReferenceKind _kind;
+  int _localIndex;
+  String _name;
+  int _numTypeParameters;
+  int _unit;
+
+  @override
+  int get containingReference {
+    _containingReference ??= const fb.Uint32Reader().vTableGet(_bp, 5, 0);
+    return _containingReference;
+  }
+
+  @override
+  int get dependency {
+    _dependency ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _dependency;
+  }
+
+  @override
+  idl.ReferenceKind get kind {
+    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 2, idl.ReferenceKind.classOrEnum);
+    return _kind;
+  }
+
+  @override
+  int get localIndex {
+    _localIndex ??= const fb.Uint32Reader().vTableGet(_bp, 6, 0);
+    return _localIndex;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 3, '');
+    return _name;
+  }
+
+  @override
+  int get numTypeParameters {
+    _numTypeParameters ??= const fb.Uint32Reader().vTableGet(_bp, 4, 0);
+    return _numTypeParameters;
+  }
+
+  @override
+  int get unit {
+    _unit ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _unit;
+  }
+}
+
+abstract class _LinkedReferenceMixin implements idl.LinkedReference {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (containingReference != 0) _result["containingReference"] = containingReference;
+    if (dependency != 0) _result["dependency"] = dependency;
+    if (kind != idl.ReferenceKind.classOrEnum) _result["kind"] = kind.toString().split('.')[1];
+    if (localIndex != 0) _result["localIndex"] = localIndex;
+    if (name != '') _result["name"] = name;
+    if (numTypeParameters != 0) _result["numTypeParameters"] = numTypeParameters;
+    if (unit != 0) _result["unit"] = unit;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "containingReference": containingReference,
+    "dependency": dependency,
+    "kind": kind,
+    "localIndex": localIndex,
+    "name": name,
+    "numTypeParameters": numTypeParameters,
+    "unit": unit,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class LinkedUnitBuilder extends Object with _LinkedUnitMixin implements idl.LinkedUnit {
+  bool _finished = false;
+
+  List<LinkedReferenceBuilder> _references;
+  List<EntityRefBuilder> _types;
+
+  @override
+  List<LinkedReferenceBuilder> get references => _references ??= <LinkedReferenceBuilder>[];
+
+  /**
+   * 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).
+   */
+  void set references(List<LinkedReferenceBuilder> _value) {
+    assert(!_finished);
+    _references = _value;
+  }
+
+  @override
+  List<EntityRefBuilder> get types => _types ??= <EntityRefBuilder>[];
+
+  /**
+   * List associating slot ids found inside the unlinked summary for the
+   * compilation unit with propagated and inferred types.
+   */
+  void set types(List<EntityRefBuilder> _value) {
+    assert(!_finished);
+    _types = _value;
+  }
+
+  LinkedUnitBuilder({List<LinkedReferenceBuilder> references, List<EntityRefBuilder> types})
+    : _references = references,
+      _types = types;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_references;
+    fb.Offset offset_types;
+    if (!(_references == null || _references.isEmpty)) {
+      offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_types == null || _types.isEmpty)) {
+      offset_types = fbBuilder.writeList(_types.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_references != null) {
+      fbBuilder.addOffset(0, offset_references);
+    }
+    if (offset_types != null) {
+      fbBuilder.addOffset(1, offset_types);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _LinkedUnitReader extends fb.TableReader<_LinkedUnitImpl> {
+  const _LinkedUnitReader();
+
+  @override
+  _LinkedUnitImpl createObject(fb.BufferPointer bp) => new _LinkedUnitImpl(bp);
+}
+
+class _LinkedUnitImpl extends Object with _LinkedUnitMixin implements idl.LinkedUnit {
+  final fb.BufferPointer _bp;
+
+  _LinkedUnitImpl(this._bp);
+
+  List<idl.LinkedReference> _references;
+  List<idl.EntityRef> _types;
+
+  @override
+  List<idl.LinkedReference> get references {
+    _references ??= const fb.ListReader<idl.LinkedReference>(const _LinkedReferenceReader()).vTableGet(_bp, 0, const <idl.LinkedReference>[]);
+    return _references;
+  }
+
+  @override
+  List<idl.EntityRef> get types {
+    _types ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 1, const <idl.EntityRef>[]);
+    return _types;
+  }
+}
+
+abstract class _LinkedUnitMixin implements idl.LinkedUnit {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (references.isNotEmpty) _result["references"] = references.map((_value) => _value.toJson()).toList();
+    if (types.isNotEmpty) _result["types"] = types.map((_value) => _value.toJson()).toList();
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "references": references,
+    "types": types,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class PackageBundleBuilder extends Object with _PackageBundleMixin implements idl.PackageBundle {
+  bool _finished = false;
+
+  List<LinkedLibraryBuilder> _linkedLibraries;
+  List<String> _linkedLibraryUris;
+  int _majorVersion;
+  int _minorVersion;
+  List<String> _unlinkedUnitHashes;
+  List<UnlinkedUnitBuilder> _unlinkedUnits;
+  List<String> _unlinkedUnitUris;
+
+  @override
+  List<LinkedLibraryBuilder> get linkedLibraries => _linkedLibraries ??= <LinkedLibraryBuilder>[];
+
+  /**
+   * Linked libraries.
+   */
+  void set linkedLibraries(List<LinkedLibraryBuilder> _value) {
+    assert(!_finished);
+    _linkedLibraries = _value;
+  }
+
+  @override
+  List<String> get linkedLibraryUris => _linkedLibraryUris ??= <String>[];
+
+  /**
+   * The list of URIs of items in [linkedLibraries], e.g. `dart:core` or
+   * `package:foo/bar.dart`.
+   */
+  void set linkedLibraryUris(List<String> _value) {
+    assert(!_finished);
+    _linkedLibraryUris = _value;
+  }
+
+  @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>[];
+
+  /**
+   * List of MD5 hashes of the files listed in [unlinkedUnitUris].  Each hash
+   * is encoded as a hexadecimal string using lower case letters.
+   */
+  void set unlinkedUnitHashes(List<String> _value) {
+    assert(!_finished);
+    _unlinkedUnitHashes = _value;
+  }
+
+  @override
+  List<UnlinkedUnitBuilder> get unlinkedUnits => _unlinkedUnits ??= <UnlinkedUnitBuilder>[];
+
+  /**
+   * Unlinked information for the compilation units constituting the package.
+   */
+  void set unlinkedUnits(List<UnlinkedUnitBuilder> _value) {
+    assert(!_finished);
+    _unlinkedUnits = _value;
+  }
+
+  @override
+  List<String> get unlinkedUnitUris => _unlinkedUnitUris ??= <String>[];
+
+  /**
+   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
+   */
+  void set unlinkedUnitUris(List<String> _value) {
+    assert(!_finished);
+    _unlinkedUnitUris = _value;
+  }
+
+  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), "PBdl");
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_linkedLibraries;
+    fb.Offset offset_linkedLibraryUris;
+    fb.Offset offset_unlinkedUnitHashes;
+    fb.Offset offset_unlinkedUnits;
+    fb.Offset offset_unlinkedUnitUris;
+    if (!(_linkedLibraries == null || _linkedLibraries.isEmpty)) {
+      offset_linkedLibraries = fbBuilder.writeList(_linkedLibraries.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_linkedLibraryUris == null || _linkedLibraryUris.isEmpty)) {
+      offset_linkedLibraryUris = fbBuilder.writeList(_linkedLibraryUris.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    if (!(_unlinkedUnitHashes == null || _unlinkedUnitHashes.isEmpty)) {
+      offset_unlinkedUnitHashes = fbBuilder.writeList(_unlinkedUnitHashes.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    if (!(_unlinkedUnits == null || _unlinkedUnits.isEmpty)) {
+      offset_unlinkedUnits = fbBuilder.writeList(_unlinkedUnits.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_unlinkedUnitUris == null || _unlinkedUnitUris.isEmpty)) {
+      offset_unlinkedUnitUris = fbBuilder.writeList(_unlinkedUnitUris.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_linkedLibraries != null) {
+      fbBuilder.addOffset(0, offset_linkedLibraries);
+    }
+    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);
+    }
+    if (offset_unlinkedUnits != null) {
+      fbBuilder.addOffset(2, offset_unlinkedUnits);
+    }
+    if (offset_unlinkedUnitUris != null) {
+      fbBuilder.addOffset(3, offset_unlinkedUnitUris);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+idl.PackageBundle readPackageBundle(List<int> buffer) {
+  fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
+  return const _PackageBundleReader().read(rootRef);
+}
+
+class _PackageBundleReader extends fb.TableReader<_PackageBundleImpl> {
+  const _PackageBundleReader();
+
+  @override
+  _PackageBundleImpl createObject(fb.BufferPointer bp) => new _PackageBundleImpl(bp);
+}
+
+class _PackageBundleImpl extends Object with _PackageBundleMixin implements idl.PackageBundle {
+  final fb.BufferPointer _bp;
+
+  _PackageBundleImpl(this._bp);
+
+  List<idl.LinkedLibrary> _linkedLibraries;
+  List<String> _linkedLibraryUris;
+  int _majorVersion;
+  int _minorVersion;
+  List<String> _unlinkedUnitHashes;
+  List<idl.UnlinkedUnit> _unlinkedUnits;
+  List<String> _unlinkedUnitUris;
+
+  @override
+  List<idl.LinkedLibrary> get linkedLibraries {
+    _linkedLibraries ??= const fb.ListReader<idl.LinkedLibrary>(const _LinkedLibraryReader()).vTableGet(_bp, 0, const <idl.LinkedLibrary>[]);
+    return _linkedLibraries;
+  }
+
+  @override
+  List<String> get linkedLibraryUris {
+    _linkedLibraryUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
+    return _linkedLibraryUris;
+  }
+
+  @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;
+  }
+
+  @override
+  List<idl.UnlinkedUnit> get unlinkedUnits {
+    _unlinkedUnits ??= const fb.ListReader<idl.UnlinkedUnit>(const _UnlinkedUnitReader()).vTableGet(_bp, 2, const <idl.UnlinkedUnit>[]);
+    return _unlinkedUnits;
+  }
+
+  @override
+  List<String> get unlinkedUnitUris {
+    _unlinkedUnitUris ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 3, const <String>[]);
+    return _unlinkedUnitUris;
+  }
+}
+
+abstract class _PackageBundleMixin implements idl.PackageBundle {
+  @override
+  Map<String, Object> toJson() {
+    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;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "linkedLibraries": linkedLibraries,
+    "linkedLibraryUris": linkedLibraryUris,
+    "majorVersion": majorVersion,
+    "minorVersion": minorVersion,
+    "unlinkedUnitHashes": unlinkedUnitHashes,
+    "unlinkedUnits": unlinkedUnits,
+    "unlinkedUnitUris": unlinkedUnitUris,
+  };
+
+  @override
+  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;
+
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedDocumentationCommentBuilder _documentationComment;
+  List<UnlinkedExecutableBuilder> _executables;
+  List<UnlinkedVariableBuilder> _fields;
+  bool _hasNoSupertype;
+  List<EntityRefBuilder> _interfaces;
+  bool _isAbstract;
+  bool _isMixinApplication;
+  List<EntityRefBuilder> _mixins;
+  String _name;
+  int _nameOffset;
+  EntityRefBuilder _supertype;
+  List<UnlinkedTypeParamBuilder> _typeParameters;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this class.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
+  /**
+   * Documentation comment for the class, or `null` if there is no
+   * documentation comment.
+   */
+  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
+    assert(!_finished);
+    _documentationComment = _value;
+  }
+
+  @override
+  List<UnlinkedExecutableBuilder> get executables => _executables ??= <UnlinkedExecutableBuilder>[];
+
+  /**
+   * Executable objects (methods, getters, and setters) contained in the class.
+   */
+  void set executables(List<UnlinkedExecutableBuilder> _value) {
+    assert(!_finished);
+    _executables = _value;
+  }
+
+  @override
+  List<UnlinkedVariableBuilder> get fields => _fields ??= <UnlinkedVariableBuilder>[];
+
+  /**
+   * Field declarations contained in the class.
+   */
+  void set fields(List<UnlinkedVariableBuilder> _value) {
+    assert(!_finished);
+    _fields = _value;
+  }
+
+  @override
+  bool get hasNoSupertype => _hasNoSupertype ??= false;
+
+  /**
+   * Indicates whether this class is the core "Object" class (and hence has no
+   * supertype)
+   */
+  void set hasNoSupertype(bool _value) {
+    assert(!_finished);
+    _hasNoSupertype = _value;
+  }
+
+  @override
+  List<EntityRefBuilder> get interfaces => _interfaces ??= <EntityRefBuilder>[];
+
+  /**
+   * Interfaces appearing in an `implements` clause, if any.
+   */
+  void set interfaces(List<EntityRefBuilder> _value) {
+    assert(!_finished);
+    _interfaces = _value;
+  }
+
+  @override
+  bool get isAbstract => _isAbstract ??= false;
+
+  /**
+   * Indicates whether the class is declared with the `abstract` keyword.
+   */
+  void set isAbstract(bool _value) {
+    assert(!_finished);
+    _isAbstract = _value;
+  }
+
+  @override
+  bool get isMixinApplication => _isMixinApplication ??= false;
+
+  /**
+   * Indicates whether the class is declared using mixin application syntax.
+   */
+  void set isMixinApplication(bool _value) {
+    assert(!_finished);
+    _isMixinApplication = _value;
+  }
+
+  @override
+  List<EntityRefBuilder> get mixins => _mixins ??= <EntityRefBuilder>[];
+
+  /**
+   * Mixins appearing in a `with` clause, if any.
+   */
+  void set mixins(List<EntityRefBuilder> _value) {
+    assert(!_finished);
+    _mixins = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * Name of the class.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
+  /**
+   * Offset of the class name relative to the beginning of the file.
+   */
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
+
+  @override
+  EntityRefBuilder get supertype => _supertype;
+
+  /**
+   * 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).
+   */
+  void set supertype(EntityRefBuilder _value) {
+    assert(!_finished);
+    _supertype = _value;
+  }
+
+  @override
+  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+
+  /**
+   * Type parameters of the class, if any.
+   */
+  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+    assert(!_finished);
+    _typeParameters = _value;
+  }
+
+  UnlinkedClassBuilder({List<UnlinkedConstBuilder> annotations, UnlinkedDocumentationCommentBuilder documentationComment, List<UnlinkedExecutableBuilder> executables, List<UnlinkedVariableBuilder> fields, bool hasNoSupertype, List<EntityRefBuilder> interfaces, bool isAbstract, bool isMixinApplication, List<EntityRefBuilder> mixins, String name, int nameOffset, EntityRefBuilder supertype, List<UnlinkedTypeParamBuilder> typeParameters})
+    : _annotations = annotations,
+      _documentationComment = documentationComment,
+      _executables = executables,
+      _fields = fields,
+      _hasNoSupertype = hasNoSupertype,
+      _interfaces = interfaces,
+      _isAbstract = isAbstract,
+      _isMixinApplication = isMixinApplication,
+      _mixins = mixins,
+      _name = name,
+      _nameOffset = nameOffset,
+      _supertype = supertype,
+      _typeParameters = typeParameters;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_documentationComment;
+    fb.Offset offset_executables;
+    fb.Offset offset_fields;
+    fb.Offset offset_interfaces;
+    fb.Offset offset_mixins;
+    fb.Offset offset_name;
+    fb.Offset offset_supertype;
+    fb.Offset offset_typeParameters;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_documentationComment != null) {
+      offset_documentationComment = _documentationComment.finish(fbBuilder);
+    }
+    if (!(_executables == null || _executables.isEmpty)) {
+      offset_executables = fbBuilder.writeList(_executables.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_fields == null || _fields.isEmpty)) {
+      offset_fields = fbBuilder.writeList(_fields.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_interfaces == null || _interfaces.isEmpty)) {
+      offset_interfaces = fbBuilder.writeList(_interfaces.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_mixins == null || _mixins.isEmpty)) {
+      offset_mixins = fbBuilder.writeList(_mixins.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    if (_supertype != null) {
+      offset_supertype = _supertype.finish(fbBuilder);
+    }
+    if (!(_typeParameters == null || _typeParameters.isEmpty)) {
+      offset_typeParameters = fbBuilder.writeList(_typeParameters.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(5, offset_annotations);
+    }
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(6, offset_documentationComment);
+    }
+    if (offset_executables != null) {
+      fbBuilder.addOffset(2, offset_executables);
+    }
+    if (offset_fields != null) {
+      fbBuilder.addOffset(4, offset_fields);
+    }
+    if (_hasNoSupertype == true) {
+      fbBuilder.addBool(12, true);
+    }
+    if (offset_interfaces != null) {
+      fbBuilder.addOffset(7, offset_interfaces);
+    }
+    if (_isAbstract == true) {
+      fbBuilder.addBool(8, true);
+    }
+    if (_isMixinApplication == true) {
+      fbBuilder.addBool(11, true);
+    }
+    if (offset_mixins != null) {
+      fbBuilder.addOffset(10, offset_mixins);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(1, _nameOffset);
+    }
+    if (offset_supertype != null) {
+      fbBuilder.addOffset(3, offset_supertype);
+    }
+    if (offset_typeParameters != null) {
+      fbBuilder.addOffset(9, offset_typeParameters);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedClassReader extends fb.TableReader<_UnlinkedClassImpl> {
+  const _UnlinkedClassReader();
+
+  @override
+  _UnlinkedClassImpl createObject(fb.BufferPointer bp) => new _UnlinkedClassImpl(bp);
+}
+
+class _UnlinkedClassImpl extends Object with _UnlinkedClassMixin implements idl.UnlinkedClass {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedClassImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  idl.UnlinkedDocumentationComment _documentationComment;
+  List<idl.UnlinkedExecutable> _executables;
+  List<idl.UnlinkedVariable> _fields;
+  bool _hasNoSupertype;
+  List<idl.EntityRef> _interfaces;
+  bool _isAbstract;
+  bool _isMixinApplication;
+  List<idl.EntityRef> _mixins;
+  String _name;
+  int _nameOffset;
+  idl.EntityRef _supertype;
+  List<idl.UnlinkedTypeParam> _typeParameters;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 5, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 6, null);
+    return _documentationComment;
+  }
+
+  @override
+  List<idl.UnlinkedExecutable> get executables {
+    _executables ??= const fb.ListReader<idl.UnlinkedExecutable>(const _UnlinkedExecutableReader()).vTableGet(_bp, 2, const <idl.UnlinkedExecutable>[]);
+    return _executables;
+  }
+
+  @override
+  List<idl.UnlinkedVariable> get fields {
+    _fields ??= const fb.ListReader<idl.UnlinkedVariable>(const _UnlinkedVariableReader()).vTableGet(_bp, 4, const <idl.UnlinkedVariable>[]);
+    return _fields;
+  }
+
+  @override
+  bool get hasNoSupertype {
+    _hasNoSupertype ??= const fb.BoolReader().vTableGet(_bp, 12, false);
+    return _hasNoSupertype;
+  }
+
+  @override
+  List<idl.EntityRef> get interfaces {
+    _interfaces ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 7, const <idl.EntityRef>[]);
+    return _interfaces;
+  }
+
+  @override
+  bool get isAbstract {
+    _isAbstract ??= const fb.BoolReader().vTableGet(_bp, 8, false);
+    return _isAbstract;
+  }
+
+  @override
+  bool get isMixinApplication {
+    _isMixinApplication ??= const fb.BoolReader().vTableGet(_bp, 11, false);
+    return _isMixinApplication;
+  }
+
+  @override
+  List<idl.EntityRef> get mixins {
+    _mixins ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 10, const <idl.EntityRef>[]);
+    return _mixins;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _nameOffset;
+  }
+
+  @override
+  idl.EntityRef get supertype {
+    _supertype ??= const _EntityRefReader().vTableGet(_bp, 3, null);
+    return _supertype;
+  }
+
+  @override
+  List<idl.UnlinkedTypeParam> get typeParameters {
+    _typeParameters ??= const fb.ListReader<idl.UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 9, const <idl.UnlinkedTypeParam>[]);
+    return _typeParameters;
+  }
+}
+
+abstract class _UnlinkedClassMixin implements idl.UnlinkedClass {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (documentationComment != null) _result["documentationComment"] = documentationComment.toJson();
+    if (executables.isNotEmpty) _result["executables"] = executables.map((_value) => _value.toJson()).toList();
+    if (fields.isNotEmpty) _result["fields"] = fields.map((_value) => _value.toJson()).toList();
+    if (hasNoSupertype != false) _result["hasNoSupertype"] = hasNoSupertype;
+    if (interfaces.isNotEmpty) _result["interfaces"] = interfaces.map((_value) => _value.toJson()).toList();
+    if (isAbstract != false) _result["isAbstract"] = isAbstract;
+    if (isMixinApplication != false) _result["isMixinApplication"] = isMixinApplication;
+    if (mixins.isNotEmpty) _result["mixins"] = mixins.map((_value) => _value.toJson()).toList();
+    if (name != '') _result["name"] = name;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    if (supertype != null) _result["supertype"] = supertype.toJson();
+    if (typeParameters.isNotEmpty) _result["typeParameters"] = typeParameters.map((_value) => _value.toJson()).toList();
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "documentationComment": documentationComment,
+    "executables": executables,
+    "fields": fields,
+    "hasNoSupertype": hasNoSupertype,
+    "interfaces": interfaces,
+    "isAbstract": isAbstract,
+    "isMixinApplication": isMixinApplication,
+    "mixins": mixins,
+    "name": name,
+    "nameOffset": nameOffset,
+    "supertype": supertype,
+    "typeParameters": typeParameters,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedCombinatorBuilder extends Object with _UnlinkedCombinatorMixin implements idl.UnlinkedCombinator {
+  bool _finished = false;
+
+  int _end;
+  List<String> _hides;
+  int _offset;
+  List<String> _shows;
+
+  @override
+  int get end => _end ??= 0;
+
+  /**
+   * If this is a `show` combinator, offset of the end of the list of shown
+   * names.  Otherwise zero.
+   */
+  void set end(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _end = _value;
+  }
+
+  @override
+  List<String> get hides => _hides ??= <String>[];
+
+  /**
+   * List of names which are hidden.  Empty if this is a `show` combinator.
+   */
+  void set hides(List<String> _value) {
+    assert(!_finished);
+    _hides = _value;
+  }
+
+  @override
+  int get offset => _offset ??= 0;
+
+  /**
+   * If this is a `show` combinator, offset of the `show` keyword.  Otherwise
+   * zero.
+   */
+  void set offset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _offset = _value;
+  }
+
+  @override
+  List<String> get shows => _shows ??= <String>[];
+
+  /**
+   * List of names which are shown.  Empty if this is a `hide` combinator.
+   */
+  void set shows(List<String> _value) {
+    assert(!_finished);
+    _shows = _value;
+  }
+
+  UnlinkedCombinatorBuilder({int end, List<String> hides, int offset, List<String> shows})
+    : _end = end,
+      _hides = hides,
+      _offset = offset,
+      _shows = shows;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_hides;
+    fb.Offset offset_shows;
+    if (!(_hides == null || _hides.isEmpty)) {
+      offset_hides = fbBuilder.writeList(_hides.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    if (!(_shows == null || _shows.isEmpty)) {
+      offset_shows = fbBuilder.writeList(_shows.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    fbBuilder.startTable();
+    if (_end != null && _end != 0) {
+      fbBuilder.addUint32(3, _end);
+    }
+    if (offset_hides != null) {
+      fbBuilder.addOffset(1, offset_hides);
+    }
+    if (_offset != null && _offset != 0) {
+      fbBuilder.addUint32(2, _offset);
+    }
+    if (offset_shows != null) {
+      fbBuilder.addOffset(0, offset_shows);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedCombinatorReader extends fb.TableReader<_UnlinkedCombinatorImpl> {
+  const _UnlinkedCombinatorReader();
+
+  @override
+  _UnlinkedCombinatorImpl createObject(fb.BufferPointer bp) => new _UnlinkedCombinatorImpl(bp);
+}
+
+class _UnlinkedCombinatorImpl extends Object with _UnlinkedCombinatorMixin implements idl.UnlinkedCombinator {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedCombinatorImpl(this._bp);
+
+  int _end;
+  List<String> _hides;
+  int _offset;
+  List<String> _shows;
+
+  @override
+  int get end {
+    _end ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _end;
+  }
+
+  @override
+  List<String> get hides {
+    _hides ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
+    return _hides;
+  }
+
+  @override
+  int get offset {
+    _offset ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _offset;
+  }
+
+  @override
+  List<String> get shows {
+    _shows ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 0, const <String>[]);
+    return _shows;
+  }
+}
+
+abstract class _UnlinkedCombinatorMixin implements idl.UnlinkedCombinator {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (end != 0) _result["end"] = end;
+    if (hides.isNotEmpty) _result["hides"] = hides;
+    if (offset != 0) _result["offset"] = offset;
+    if (shows.isNotEmpty) _result["shows"] = shows;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "end": end,
+    "hides": hides,
+    "offset": offset,
+    "shows": shows,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedConstBuilder extends Object with _UnlinkedConstMixin implements idl.UnlinkedConst {
+  bool _finished = false;
+
+  List<double> _doubles;
+  List<int> _ints;
+  bool _isInvalid;
+  List<idl.UnlinkedConstOperation> _operations;
+  List<EntityRefBuilder> _references;
+  List<String> _strings;
+
+  @override
+  List<double> get doubles => _doubles ??= <double>[];
+
+  /**
+   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+   */
+  void set doubles(List<double> _value) {
+    assert(!_finished);
+    _doubles = _value;
+  }
+
+  @override
+  List<int> get ints => _ints ??= <int>[];
+
+  /**
+   * Sequence of unsigned 32-bit integers consumed by the operations
+   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+   * `makeList`, and `makeMap`.
+   */
+  void set ints(List<int> _value) {
+    assert(!_finished);
+    assert(_value == null || _value.every((e) => e >= 0));
+    _ints = _value;
+  }
+
+  @override
+  bool get isInvalid => _isInvalid ??= false;
+
+  /**
+   * Indicates whether the expression is not a valid potentially constant
+   * expression.
+   */
+  void set isInvalid(bool _value) {
+    assert(!_finished);
+    _isInvalid = _value;
+  }
+
+  @override
+  List<idl.UnlinkedConstOperation> get operations => _operations ??= <idl.UnlinkedConstOperation>[];
+
+  /**
+   * Sequence of operations to execute (starting with an empty stack) to form
+   * the constant value.
+   */
+  void set operations(List<idl.UnlinkedConstOperation> _value) {
+    assert(!_finished);
+    _operations = _value;
+  }
+
+  @override
+  List<EntityRefBuilder> get references => _references ??= <EntityRefBuilder>[];
+
+  /**
+   * Sequence of language constructs consumed by the operations
+   * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`.  Note
+   * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+   * actual entity being referred to may be something other than a type.
+   */
+  void set references(List<EntityRefBuilder> _value) {
+    assert(!_finished);
+    _references = _value;
+  }
+
+  @override
+  List<String> get strings => _strings ??= <String>[];
+
+  /**
+   * Sequence of strings consumed by the operations `pushString` and
+   * `invokeConstructor`.
+   */
+  void set strings(List<String> _value) {
+    assert(!_finished);
+    _strings = _value;
+  }
+
+  UnlinkedConstBuilder({List<double> doubles, List<int> ints, bool isInvalid, List<idl.UnlinkedConstOperation> operations, List<EntityRefBuilder> references, List<String> strings})
+    : _doubles = doubles,
+      _ints = ints,
+      _isInvalid = isInvalid,
+      _operations = operations,
+      _references = references,
+      _strings = strings;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_doubles;
+    fb.Offset offset_ints;
+    fb.Offset offset_operations;
+    fb.Offset offset_references;
+    fb.Offset offset_strings;
+    if (!(_doubles == null || _doubles.isEmpty)) {
+      offset_doubles = fbBuilder.writeListFloat64(_doubles);
+    }
+    if (!(_ints == null || _ints.isEmpty)) {
+      offset_ints = fbBuilder.writeListUint32(_ints);
+    }
+    if (!(_operations == null || _operations.isEmpty)) {
+      offset_operations = fbBuilder.writeListUint8(_operations.map((b) => b.index).toList());
+    }
+    if (!(_references == null || _references.isEmpty)) {
+      offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_strings == null || _strings.isEmpty)) {
+      offset_strings = fbBuilder.writeList(_strings.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_doubles != null) {
+      fbBuilder.addOffset(4, offset_doubles);
+    }
+    if (offset_ints != null) {
+      fbBuilder.addOffset(1, offset_ints);
+    }
+    if (_isInvalid == true) {
+      fbBuilder.addBool(5, true);
+    }
+    if (offset_operations != null) {
+      fbBuilder.addOffset(0, offset_operations);
+    }
+    if (offset_references != null) {
+      fbBuilder.addOffset(2, offset_references);
+    }
+    if (offset_strings != null) {
+      fbBuilder.addOffset(3, offset_strings);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedConstReader extends fb.TableReader<_UnlinkedConstImpl> {
+  const _UnlinkedConstReader();
+
+  @override
+  _UnlinkedConstImpl createObject(fb.BufferPointer bp) => new _UnlinkedConstImpl(bp);
+}
+
+class _UnlinkedConstImpl extends Object with _UnlinkedConstMixin implements idl.UnlinkedConst {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedConstImpl(this._bp);
+
+  List<double> _doubles;
+  List<int> _ints;
+  bool _isInvalid;
+  List<idl.UnlinkedConstOperation> _operations;
+  List<idl.EntityRef> _references;
+  List<String> _strings;
+
+  @override
+  List<double> get doubles {
+    _doubles ??= const fb.Float64ListReader().vTableGet(_bp, 4, const <double>[]);
+    return _doubles;
+  }
+
+  @override
+  List<int> get ints {
+    _ints ??= const fb.Uint32ListReader().vTableGet(_bp, 1, const <int>[]);
+    return _ints;
+  }
+
+  @override
+  bool get isInvalid {
+    _isInvalid ??= const fb.BoolReader().vTableGet(_bp, 5, false);
+    return _isInvalid;
+  }
+
+  @override
+  List<idl.UnlinkedConstOperation> get operations {
+    _operations ??= const fb.ListReader<idl.UnlinkedConstOperation>(const _UnlinkedConstOperationReader()).vTableGet(_bp, 0, const <idl.UnlinkedConstOperation>[]);
+    return _operations;
+  }
+
+  @override
+  List<idl.EntityRef> get references {
+    _references ??= const fb.ListReader<idl.EntityRef>(const _EntityRefReader()).vTableGet(_bp, 2, const <idl.EntityRef>[]);
+    return _references;
+  }
+
+  @override
+  List<String> get strings {
+    _strings ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 3, const <String>[]);
+    return _strings;
+  }
+}
+
+abstract class _UnlinkedConstMixin implements idl.UnlinkedConst {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (doubles.isNotEmpty) _result["doubles"] = doubles.map((_value) => _value.isFinite ? _value : _value.toString()).toList();
+    if (ints.isNotEmpty) _result["ints"] = ints;
+    if (isInvalid != false) _result["isInvalid"] = isInvalid;
+    if (operations.isNotEmpty) _result["operations"] = operations.map((_value) => _value.toString().split('.')[1]).toList();
+    if (references.isNotEmpty) _result["references"] = references.map((_value) => _value.toJson()).toList();
+    if (strings.isNotEmpty) _result["strings"] = strings;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "doubles": doubles,
+    "ints": ints,
+    "isInvalid": isInvalid,
+    "operations": operations,
+    "references": references,
+    "strings": strings,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedConstructorInitializerBuilder extends Object with _UnlinkedConstructorInitializerMixin implements idl.UnlinkedConstructorInitializer {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _arguments;
+  UnlinkedConstBuilder _expression;
+  idl.UnlinkedConstructorInitializerKind _kind;
+  String _name;
+
+  @override
+  List<UnlinkedConstBuilder> get arguments => _arguments ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * If [kind] is `thisInvocation` or `superInvocation`, the arguments of the
+   * invocation.  Otherwise empty.
+   */
+  void set arguments(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _arguments = _value;
+  }
+
+  @override
+  UnlinkedConstBuilder get expression => _expression;
+
+  /**
+   * If [kind] is `field`, the expression of the field initializer.
+   * Otherwise `null`.
+   */
+  void set expression(UnlinkedConstBuilder _value) {
+    assert(!_finished);
+    _expression = _value;
+  }
+
+  @override
+  idl.UnlinkedConstructorInitializerKind get kind => _kind ??= idl.UnlinkedConstructorInitializerKind.field;
+
+  /**
+   * The kind of the constructor initializer (field, redirect, super).
+   */
+  void set kind(idl.UnlinkedConstructorInitializerKind _value) {
+    assert(!_finished);
+    _kind = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * 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.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  UnlinkedConstructorInitializerBuilder({List<UnlinkedConstBuilder> arguments, UnlinkedConstBuilder expression, idl.UnlinkedConstructorInitializerKind kind, String name})
+    : _arguments = arguments,
+      _expression = expression,
+      _kind = kind,
+      _name = name;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_arguments;
+    fb.Offset offset_expression;
+    fb.Offset offset_name;
+    if (!(_arguments == null || _arguments.isEmpty)) {
+      offset_arguments = fbBuilder.writeList(_arguments.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_expression != null) {
+      offset_expression = _expression.finish(fbBuilder);
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (offset_arguments != null) {
+      fbBuilder.addOffset(3, offset_arguments);
+    }
+    if (offset_expression != null) {
+      fbBuilder.addOffset(1, offset_expression);
+    }
+    if (_kind != null && _kind != idl.UnlinkedConstructorInitializerKind.field) {
+      fbBuilder.addUint8(2, _kind.index);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedConstructorInitializerReader extends fb.TableReader<_UnlinkedConstructorInitializerImpl> {
+  const _UnlinkedConstructorInitializerReader();
+
+  @override
+  _UnlinkedConstructorInitializerImpl createObject(fb.BufferPointer bp) => new _UnlinkedConstructorInitializerImpl(bp);
+}
+
+class _UnlinkedConstructorInitializerImpl extends Object with _UnlinkedConstructorInitializerMixin implements idl.UnlinkedConstructorInitializer {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedConstructorInitializerImpl(this._bp);
+
+  List<idl.UnlinkedConst> _arguments;
+  idl.UnlinkedConst _expression;
+  idl.UnlinkedConstructorInitializerKind _kind;
+  String _name;
+
+  @override
+  List<idl.UnlinkedConst> get arguments {
+    _arguments ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 3, const <idl.UnlinkedConst>[]);
+    return _arguments;
+  }
+
+  @override
+  idl.UnlinkedConst get expression {
+    _expression ??= const _UnlinkedConstReader().vTableGet(_bp, 1, null);
+    return _expression;
+  }
+
+  @override
+  idl.UnlinkedConstructorInitializerKind get kind {
+    _kind ??= const _UnlinkedConstructorInitializerKindReader().vTableGet(_bp, 2, idl.UnlinkedConstructorInitializerKind.field);
+    return _kind;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+}
+
+abstract class _UnlinkedConstructorInitializerMixin implements idl.UnlinkedConstructorInitializer {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (arguments.isNotEmpty) _result["arguments"] = arguments.map((_value) => _value.toJson()).toList();
+    if (expression != null) _result["expression"] = expression.toJson();
+    if (kind != idl.UnlinkedConstructorInitializerKind.field) _result["kind"] = kind.toString().split('.')[1];
+    if (name != '') _result["name"] = name;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "arguments": arguments,
+    "expression": expression,
+    "kind": kind,
+    "name": name,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedDocumentationCommentBuilder extends Object with _UnlinkedDocumentationCommentMixin implements idl.UnlinkedDocumentationComment {
+  bool _finished = false;
+
+  int _length;
+  int _offset;
+  String _text;
+
+  @override
+  int get length => _length ??= 0;
+
+  /**
+   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
+   */
+  void set length(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _length = _value;
+  }
+
+  @override
+  int get offset => _offset ??= 0;
+
+  /**
+   * Offset of the beginning of the documentation comment relative to the
+   * beginning of the file.
+   */
+  void set offset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _offset = _value;
+  }
+
+  @override
+  String get text => _text ??= '';
+
+  /**
+   * Text of the documentation comment, with '\r\n' replaced by '\n'.
+   *
+   * References appearing within the doc comment in square brackets are not
+   * specially encoded.
+   */
+  void set text(String _value) {
+    assert(!_finished);
+    _text = _value;
+  }
+
+  UnlinkedDocumentationCommentBuilder({int length, int offset, String text})
+    : _length = length,
+      _offset = offset,
+      _text = text;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_text;
+    if (_text != null) {
+      offset_text = fbBuilder.writeString(_text);
+    }
+    fbBuilder.startTable();
+    if (_length != null && _length != 0) {
+      fbBuilder.addUint32(0, _length);
+    }
+    if (_offset != null && _offset != 0) {
+      fbBuilder.addUint32(2, _offset);
+    }
+    if (offset_text != null) {
+      fbBuilder.addOffset(1, offset_text);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedDocumentationCommentReader extends fb.TableReader<_UnlinkedDocumentationCommentImpl> {
+  const _UnlinkedDocumentationCommentReader();
+
+  @override
+  _UnlinkedDocumentationCommentImpl createObject(fb.BufferPointer bp) => new _UnlinkedDocumentationCommentImpl(bp);
+}
+
+class _UnlinkedDocumentationCommentImpl extends Object with _UnlinkedDocumentationCommentMixin implements idl.UnlinkedDocumentationComment {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedDocumentationCommentImpl(this._bp);
+
+  int _length;
+  int _offset;
+  String _text;
+
+  @override
+  int get length {
+    _length ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _length;
+  }
+
+  @override
+  int get offset {
+    _offset ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _offset;
+  }
+
+  @override
+  String get text {
+    _text ??= const fb.StringReader().vTableGet(_bp, 1, '');
+    return _text;
+  }
+}
+
+abstract class _UnlinkedDocumentationCommentMixin implements idl.UnlinkedDocumentationComment {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (length != 0) _result["length"] = length;
+    if (offset != 0) _result["offset"] = offset;
+    if (text != '') _result["text"] = text;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "length": length,
+    "offset": offset,
+    "text": text,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedEnumBuilder extends Object with _UnlinkedEnumMixin implements idl.UnlinkedEnum {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedDocumentationCommentBuilder _documentationComment;
+  String _name;
+  int _nameOffset;
+  List<UnlinkedEnumValueBuilder> _values;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this enum.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
+  /**
+   * Documentation comment for the enum, or `null` if there is no documentation
+   * comment.
+   */
+  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
+    assert(!_finished);
+    _documentationComment = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * Name of the enum type.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
+  /**
+   * Offset of the enum name relative to the beginning of the file.
+   */
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
+
+  @override
+  List<UnlinkedEnumValueBuilder> get values => _values ??= <UnlinkedEnumValueBuilder>[];
+
+  /**
+   * Values listed in the enum declaration, in declaration order.
+   */
+  void set values(List<UnlinkedEnumValueBuilder> _value) {
+    assert(!_finished);
+    _values = _value;
+  }
+
+  UnlinkedEnumBuilder({List<UnlinkedConstBuilder> annotations, UnlinkedDocumentationCommentBuilder documentationComment, String name, int nameOffset, List<UnlinkedEnumValueBuilder> values})
+    : _annotations = annotations,
+      _documentationComment = documentationComment,
+      _name = name,
+      _nameOffset = nameOffset,
+      _values = values;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_documentationComment;
+    fb.Offset offset_name;
+    fb.Offset offset_values;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_documentationComment != null) {
+      offset_documentationComment = _documentationComment.finish(fbBuilder);
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    if (!(_values == null || _values.isEmpty)) {
+      offset_values = fbBuilder.writeList(_values.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(4, offset_annotations);
+    }
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(3, offset_documentationComment);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(1, _nameOffset);
+    }
+    if (offset_values != null) {
+      fbBuilder.addOffset(2, offset_values);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedEnumReader extends fb.TableReader<_UnlinkedEnumImpl> {
+  const _UnlinkedEnumReader();
+
+  @override
+  _UnlinkedEnumImpl createObject(fb.BufferPointer bp) => new _UnlinkedEnumImpl(bp);
+}
+
+class _UnlinkedEnumImpl extends Object with _UnlinkedEnumMixin implements idl.UnlinkedEnum {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedEnumImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  idl.UnlinkedDocumentationComment _documentationComment;
+  String _name;
+  int _nameOffset;
+  List<idl.UnlinkedEnumValue> _values;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 4, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 3, null);
+    return _documentationComment;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _nameOffset;
+  }
+
+  @override
+  List<idl.UnlinkedEnumValue> get values {
+    _values ??= const fb.ListReader<idl.UnlinkedEnumValue>(const _UnlinkedEnumValueReader()).vTableGet(_bp, 2, const <idl.UnlinkedEnumValue>[]);
+    return _values;
+  }
+}
+
+abstract class _UnlinkedEnumMixin implements idl.UnlinkedEnum {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (documentationComment != null) _result["documentationComment"] = documentationComment.toJson();
+    if (name != '') _result["name"] = name;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    if (values.isNotEmpty) _result["values"] = values.map((_value) => _value.toJson()).toList();
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "documentationComment": documentationComment,
+    "name": name,
+    "nameOffset": nameOffset,
+    "values": values,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedEnumValueBuilder extends Object with _UnlinkedEnumValueMixin implements idl.UnlinkedEnumValue {
+  bool _finished = false;
+
+  UnlinkedDocumentationCommentBuilder _documentationComment;
+  String _name;
+  int _nameOffset;
+
+  @override
+  UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
+  /**
+   * Documentation comment for the enum value, or `null` if there is no
+   * documentation comment.
+   */
+  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
+    assert(!_finished);
+    _documentationComment = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * Name of the enumerated value.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
+  /**
+   * Offset of the enum value name relative to the beginning of the file.
+   */
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
+
+  UnlinkedEnumValueBuilder({UnlinkedDocumentationCommentBuilder documentationComment, String name, int nameOffset})
+    : _documentationComment = documentationComment,
+      _name = name,
+      _nameOffset = nameOffset;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_documentationComment;
+    fb.Offset offset_name;
+    if (_documentationComment != null) {
+      offset_documentationComment = _documentationComment.finish(fbBuilder);
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(2, offset_documentationComment);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(1, _nameOffset);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedEnumValueReader extends fb.TableReader<_UnlinkedEnumValueImpl> {
+  const _UnlinkedEnumValueReader();
+
+  @override
+  _UnlinkedEnumValueImpl createObject(fb.BufferPointer bp) => new _UnlinkedEnumValueImpl(bp);
+}
+
+class _UnlinkedEnumValueImpl extends Object with _UnlinkedEnumValueMixin implements idl.UnlinkedEnumValue {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedEnumValueImpl(this._bp);
+
+  idl.UnlinkedDocumentationComment _documentationComment;
+  String _name;
+  int _nameOffset;
+
+  @override
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
+    return _documentationComment;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _nameOffset;
+  }
+}
+
+abstract class _UnlinkedEnumValueMixin implements idl.UnlinkedEnumValue {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (documentationComment != null) _result["documentationComment"] = documentationComment.toJson();
+    if (name != '') _result["name"] = name;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "documentationComment": documentationComment,
+    "name": name,
+    "nameOffset": nameOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedExecutableBuilder extends Object with _UnlinkedExecutableMixin implements idl.UnlinkedExecutable {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedConstructorInitializerBuilder> _constantInitializers;
+  UnlinkedDocumentationCommentBuilder _documentationComment;
+  int _inferredReturnTypeSlot;
+  bool _isAbstract;
+  bool _isConst;
+  bool _isExternal;
+  bool _isFactory;
+  bool _isRedirectedConstructor;
+  bool _isStatic;
+  idl.UnlinkedExecutableKind _kind;
+  List<UnlinkedExecutableBuilder> _localFunctions;
+  List<UnlinkedLabelBuilder> _localLabels;
+  List<UnlinkedVariableBuilder> _localVariables;
+  String _name;
+  int _nameEnd;
+  int _nameOffset;
+  List<UnlinkedParamBuilder> _parameters;
+  int _periodOffset;
+  EntityRefBuilder _redirectedConstructor;
+  String _redirectedConstructorName;
+  EntityRefBuilder _returnType;
+  List<UnlinkedTypeParamBuilder> _typeParameters;
+  int _visibleLength;
+  int _visibleOffset;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this executable.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  List<UnlinkedConstructorInitializerBuilder> get constantInitializers => _constantInitializers ??= <UnlinkedConstructorInitializerBuilder>[];
+
+  /**
+   * If a constant [UnlinkedExecutableKind.constructor], the constructor
+   * initializers.  Otherwise empty.
+   */
+  void set constantInitializers(List<UnlinkedConstructorInitializerBuilder> _value) {
+    assert(!_finished);
+    _constantInitializers = _value;
+  }
+
+  @override
+  UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
+  /**
+   * Documentation comment for the executable, or `null` if there is no
+   * documentation comment.
+   */
+  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
+    assert(!_finished);
+    _documentationComment = _value;
+  }
+
+  @override
+  int get inferredReturnTypeSlot => _inferredReturnTypeSlot ??= 0;
+
+  /**
+   * 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`.
+   */
+  void set inferredReturnTypeSlot(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _inferredReturnTypeSlot = _value;
+  }
+
+  @override
+  bool get isAbstract => _isAbstract ??= false;
+
+  /**
+   * Indicates whether the executable is declared using the `abstract` keyword.
+   */
+  void set isAbstract(bool _value) {
+    assert(!_finished);
+    _isAbstract = _value;
+  }
+
+  @override
+  bool get isConst => _isConst ??= false;
+
+  /**
+   * Indicates whether the executable is declared using the `const` keyword.
+   */
+  void set isConst(bool _value) {
+    assert(!_finished);
+    _isConst = _value;
+  }
+
+  @override
+  bool get isExternal => _isExternal ??= false;
+
+  /**
+   * Indicates whether the executable is declared using the `external` keyword.
+   */
+  void set isExternal(bool _value) {
+    assert(!_finished);
+    _isExternal = _value;
+  }
+
+  @override
+  bool get isFactory => _isFactory ??= false;
+
+  /**
+   * Indicates whether the executable is declared using the `factory` keyword.
+   */
+  void set isFactory(bool _value) {
+    assert(!_finished);
+    _isFactory = _value;
+  }
+
+  @override
+  bool get isRedirectedConstructor => _isRedirectedConstructor ??= false;
+
+  /**
+   * Indicates whether the executable is a redirected constructor.
+   */
+  void set isRedirectedConstructor(bool _value) {
+    assert(!_finished);
+    _isRedirectedConstructor = _value;
+  }
+
+  @override
+  bool get isStatic => _isStatic ??= false;
+
+  /**
+   * 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).
+   */
+  void set isStatic(bool _value) {
+    assert(!_finished);
+    _isStatic = _value;
+  }
+
+  @override
+  idl.UnlinkedExecutableKind get kind => _kind ??= idl.UnlinkedExecutableKind.functionOrMethod;
+
+  /**
+   * The kind of the executable (function/method, getter, setter, or
+   * constructor).
+   */
+  void set kind(idl.UnlinkedExecutableKind _value) {
+    assert(!_finished);
+    _kind = _value;
+  }
+
+  @override
+  List<UnlinkedExecutableBuilder> get localFunctions => _localFunctions ??= <UnlinkedExecutableBuilder>[];
+
+  /**
+   * The list of local functions.
+   */
+  void set localFunctions(List<UnlinkedExecutableBuilder> _value) {
+    assert(!_finished);
+    _localFunctions = _value;
+  }
+
+  @override
+  List<UnlinkedLabelBuilder> get localLabels => _localLabels ??= <UnlinkedLabelBuilder>[];
+
+  /**
+   * The list of local labels.
+   */
+  void set localLabels(List<UnlinkedLabelBuilder> _value) {
+    assert(!_finished);
+    _localLabels = _value;
+  }
+
+  @override
+  List<UnlinkedVariableBuilder> get localVariables => _localVariables ??= <UnlinkedVariableBuilder>[];
+
+  /**
+   * The list of local variables.
+   */
+  void set localVariables(List<UnlinkedVariableBuilder> _value) {
+    assert(!_finished);
+    _localVariables = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * 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.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameEnd => _nameEnd ??= 0;
+
+  /**
+   * If [kind] is [UnlinkedExecutableKind.constructor] and [name] is not empty,
+   * the offset of the end of the constructor name.  Otherwise zero.
+   */
+  void set nameEnd(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameEnd = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
+  /**
+   * 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(); }").
+   */
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
+
+  @override
+  List<UnlinkedParamBuilder> get parameters => _parameters ??= <UnlinkedParamBuilder>[];
+
+  /**
+   * 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.
+   */
+  void set parameters(List<UnlinkedParamBuilder> _value) {
+    assert(!_finished);
+    _parameters = _value;
+  }
+
+  @override
+  int get periodOffset => _periodOffset ??= 0;
+
+  /**
+   * If [kind] is [UnlinkedExecutableKind.constructor] and [name] is not empty,
+   * the offset of the period before the constructor name.  Otherwise zero.
+   */
+  void set periodOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _periodOffset = _value;
+  }
+
+  @override
+  EntityRefBuilder get redirectedConstructor => _redirectedConstructor;
+
+  /**
+   * If [isRedirectedConstructor] and [isFactory] are both `true`, the
+   * constructor to which this constructor redirects; otherwise empty.
+   */
+  void set redirectedConstructor(EntityRefBuilder _value) {
+    assert(!_finished);
+    _redirectedConstructor = _value;
+  }
+
+  @override
+  String get redirectedConstructorName => _redirectedConstructorName ??= '';
+
+  /**
+   * If [isRedirectedConstructor] is `true` and [isFactory] is `false`, the
+   * name of the constructor that this constructor redirects to; otherwise
+   * empty.
+   */
+  void set redirectedConstructorName(String _value) {
+    assert(!_finished);
+    _redirectedConstructorName = _value;
+  }
+
+  @override
+  EntityRefBuilder get returnType => _returnType;
+
+  /**
+   * 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.
+   */
+  void set returnType(EntityRefBuilder _value) {
+    assert(!_finished);
+    _returnType = _value;
+  }
+
+  @override
+  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+
+  /**
+   * Type parameters of the executable, if any.  Empty if support for generic
+   * method syntax is disabled.
+   */
+  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+    assert(!_finished);
+    _typeParameters = _value;
+  }
+
+  @override
+  int get visibleLength => _visibleLength ??= 0;
+
+  /**
+   * If a local function, the length of the visible range; zero otherwise.
+   */
+  void set visibleLength(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _visibleLength = _value;
+  }
+
+  @override
+  int get visibleOffset => _visibleOffset ??= 0;
+
+  /**
+   * If a local function, the beginning of the visible range; zero otherwise.
+   */
+  void set visibleOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _visibleOffset = _value;
+  }
+
+  UnlinkedExecutableBuilder({List<UnlinkedConstBuilder> annotations, List<UnlinkedConstructorInitializerBuilder> constantInitializers, UnlinkedDocumentationCommentBuilder documentationComment, int inferredReturnTypeSlot, bool isAbstract, bool isConst, bool isExternal, bool isFactory, bool isRedirectedConstructor, bool isStatic, idl.UnlinkedExecutableKind kind, List<UnlinkedExecutableBuilder> localFunctions, List<UnlinkedLabelBuilder> localLabels, List<UnlinkedVariableBuilder> localVariables, String name, int nameEnd, int nameOffset, List<UnlinkedParamBuilder> parameters, int periodOffset, EntityRefBuilder redirectedConstructor, String redirectedConstructorName, EntityRefBuilder returnType, List<UnlinkedTypeParamBuilder> typeParameters, int visibleLength, int visibleOffset})
+    : _annotations = annotations,
+      _constantInitializers = constantInitializers,
+      _documentationComment = documentationComment,
+      _inferredReturnTypeSlot = inferredReturnTypeSlot,
+      _isAbstract = isAbstract,
+      _isConst = isConst,
+      _isExternal = isExternal,
+      _isFactory = isFactory,
+      _isRedirectedConstructor = isRedirectedConstructor,
+      _isStatic = isStatic,
+      _kind = kind,
+      _localFunctions = localFunctions,
+      _localLabels = localLabels,
+      _localVariables = localVariables,
+      _name = name,
+      _nameEnd = nameEnd,
+      _nameOffset = nameOffset,
+      _parameters = parameters,
+      _periodOffset = periodOffset,
+      _redirectedConstructor = redirectedConstructor,
+      _redirectedConstructorName = redirectedConstructorName,
+      _returnType = returnType,
+      _typeParameters = typeParameters,
+      _visibleLength = visibleLength,
+      _visibleOffset = visibleOffset;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_constantInitializers;
+    fb.Offset offset_documentationComment;
+    fb.Offset offset_localFunctions;
+    fb.Offset offset_localLabels;
+    fb.Offset offset_localVariables;
+    fb.Offset offset_name;
+    fb.Offset offset_parameters;
+    fb.Offset offset_redirectedConstructor;
+    fb.Offset offset_redirectedConstructorName;
+    fb.Offset offset_returnType;
+    fb.Offset offset_typeParameters;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_constantInitializers == null || _constantInitializers.isEmpty)) {
+      offset_constantInitializers = fbBuilder.writeList(_constantInitializers.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_documentationComment != null) {
+      offset_documentationComment = _documentationComment.finish(fbBuilder);
+    }
+    if (!(_localFunctions == null || _localFunctions.isEmpty)) {
+      offset_localFunctions = fbBuilder.writeList(_localFunctions.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_localLabels == null || _localLabels.isEmpty)) {
+      offset_localLabels = fbBuilder.writeList(_localLabels.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_localVariables == null || _localVariables.isEmpty)) {
+      offset_localVariables = fbBuilder.writeList(_localVariables.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    if (!(_parameters == null || _parameters.isEmpty)) {
+      offset_parameters = fbBuilder.writeList(_parameters.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_redirectedConstructor != null) {
+      offset_redirectedConstructor = _redirectedConstructor.finish(fbBuilder);
+    }
+    if (_redirectedConstructorName != null) {
+      offset_redirectedConstructorName = fbBuilder.writeString(_redirectedConstructorName);
+    }
+    if (_returnType != null) {
+      offset_returnType = _returnType.finish(fbBuilder);
+    }
+    if (!(_typeParameters == null || _typeParameters.isEmpty)) {
+      offset_typeParameters = fbBuilder.writeList(_typeParameters.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(6, offset_annotations);
+    }
+    if (offset_constantInitializers != null) {
+      fbBuilder.addOffset(14, offset_constantInitializers);
+    }
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(7, offset_documentationComment);
+    }
+    if (_inferredReturnTypeSlot != null && _inferredReturnTypeSlot != 0) {
+      fbBuilder.addUint32(5, _inferredReturnTypeSlot);
+    }
+    if (_isAbstract == true) {
+      fbBuilder.addBool(10, true);
+    }
+    if (_isConst == true) {
+      fbBuilder.addBool(12, true);
+    }
+    if (_isExternal == true) {
+      fbBuilder.addBool(11, true);
+    }
+    if (_isFactory == true) {
+      fbBuilder.addBool(8, true);
+    }
+    if (_isRedirectedConstructor == true) {
+      fbBuilder.addBool(13, true);
+    }
+    if (_isStatic == true) {
+      fbBuilder.addBool(9, true);
+    }
+    if (_kind != null && _kind != idl.UnlinkedExecutableKind.functionOrMethod) {
+      fbBuilder.addUint8(4, _kind.index);
+    }
+    if (offset_localFunctions != null) {
+      fbBuilder.addOffset(18, offset_localFunctions);
+    }
+    if (offset_localLabels != null) {
+      fbBuilder.addOffset(22, offset_localLabels);
+    }
+    if (offset_localVariables != null) {
+      fbBuilder.addOffset(19, offset_localVariables);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(1, offset_name);
+    }
+    if (_nameEnd != null && _nameEnd != 0) {
+      fbBuilder.addUint32(23, _nameEnd);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(0, _nameOffset);
+    }
+    if (offset_parameters != null) {
+      fbBuilder.addOffset(2, offset_parameters);
+    }
+    if (_periodOffset != null && _periodOffset != 0) {
+      fbBuilder.addUint32(24, _periodOffset);
+    }
+    if (offset_redirectedConstructor != null) {
+      fbBuilder.addOffset(15, offset_redirectedConstructor);
+    }
+    if (offset_redirectedConstructorName != null) {
+      fbBuilder.addOffset(17, offset_redirectedConstructorName);
+    }
+    if (offset_returnType != null) {
+      fbBuilder.addOffset(3, offset_returnType);
+    }
+    if (offset_typeParameters != null) {
+      fbBuilder.addOffset(16, offset_typeParameters);
+    }
+    if (_visibleLength != null && _visibleLength != 0) {
+      fbBuilder.addUint32(20, _visibleLength);
+    }
+    if (_visibleOffset != null && _visibleOffset != 0) {
+      fbBuilder.addUint32(21, _visibleOffset);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedExecutableReader extends fb.TableReader<_UnlinkedExecutableImpl> {
+  const _UnlinkedExecutableReader();
+
+  @override
+  _UnlinkedExecutableImpl createObject(fb.BufferPointer bp) => new _UnlinkedExecutableImpl(bp);
+}
+
+class _UnlinkedExecutableImpl extends Object with _UnlinkedExecutableMixin implements idl.UnlinkedExecutable {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedExecutableImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedConstructorInitializer> _constantInitializers;
+  idl.UnlinkedDocumentationComment _documentationComment;
+  int _inferredReturnTypeSlot;
+  bool _isAbstract;
+  bool _isConst;
+  bool _isExternal;
+  bool _isFactory;
+  bool _isRedirectedConstructor;
+  bool _isStatic;
+  idl.UnlinkedExecutableKind _kind;
+  List<idl.UnlinkedExecutable> _localFunctions;
+  List<idl.UnlinkedLabel> _localLabels;
+  List<idl.UnlinkedVariable> _localVariables;
+  String _name;
+  int _nameEnd;
+  int _nameOffset;
+  List<idl.UnlinkedParam> _parameters;
+  int _periodOffset;
+  idl.EntityRef _redirectedConstructor;
+  String _redirectedConstructorName;
+  idl.EntityRef _returnType;
+  List<idl.UnlinkedTypeParam> _typeParameters;
+  int _visibleLength;
+  int _visibleOffset;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 6, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  List<idl.UnlinkedConstructorInitializer> get constantInitializers {
+    _constantInitializers ??= const fb.ListReader<idl.UnlinkedConstructorInitializer>(const _UnlinkedConstructorInitializerReader()).vTableGet(_bp, 14, const <idl.UnlinkedConstructorInitializer>[]);
+    return _constantInitializers;
+  }
+
+  @override
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 7, null);
+    return _documentationComment;
+  }
+
+  @override
+  int get inferredReturnTypeSlot {
+    _inferredReturnTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 5, 0);
+    return _inferredReturnTypeSlot;
+  }
+
+  @override
+  bool get isAbstract {
+    _isAbstract ??= const fb.BoolReader().vTableGet(_bp, 10, false);
+    return _isAbstract;
+  }
+
+  @override
+  bool get isConst {
+    _isConst ??= const fb.BoolReader().vTableGet(_bp, 12, false);
+    return _isConst;
+  }
+
+  @override
+  bool get isExternal {
+    _isExternal ??= const fb.BoolReader().vTableGet(_bp, 11, false);
+    return _isExternal;
+  }
+
+  @override
+  bool get isFactory {
+    _isFactory ??= const fb.BoolReader().vTableGet(_bp, 8, false);
+    return _isFactory;
+  }
+
+  @override
+  bool get isRedirectedConstructor {
+    _isRedirectedConstructor ??= const fb.BoolReader().vTableGet(_bp, 13, false);
+    return _isRedirectedConstructor;
+  }
+
+  @override
+  bool get isStatic {
+    _isStatic ??= const fb.BoolReader().vTableGet(_bp, 9, false);
+    return _isStatic;
+  }
+
+  @override
+  idl.UnlinkedExecutableKind get kind {
+    _kind ??= const _UnlinkedExecutableKindReader().vTableGet(_bp, 4, idl.UnlinkedExecutableKind.functionOrMethod);
+    return _kind;
+  }
+
+  @override
+  List<idl.UnlinkedExecutable> get localFunctions {
+    _localFunctions ??= const fb.ListReader<idl.UnlinkedExecutable>(const _UnlinkedExecutableReader()).vTableGet(_bp, 18, const <idl.UnlinkedExecutable>[]);
+    return _localFunctions;
+  }
+
+  @override
+  List<idl.UnlinkedLabel> get localLabels {
+    _localLabels ??= const fb.ListReader<idl.UnlinkedLabel>(const _UnlinkedLabelReader()).vTableGet(_bp, 22, const <idl.UnlinkedLabel>[]);
+    return _localLabels;
+  }
+
+  @override
+  List<idl.UnlinkedVariable> get localVariables {
+    _localVariables ??= const fb.ListReader<idl.UnlinkedVariable>(const _UnlinkedVariableReader()).vTableGet(_bp, 19, const <idl.UnlinkedVariable>[]);
+    return _localVariables;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 1, '');
+    return _name;
+  }
+
+  @override
+  int get nameEnd {
+    _nameEnd ??= const fb.Uint32Reader().vTableGet(_bp, 23, 0);
+    return _nameEnd;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _nameOffset;
+  }
+
+  @override
+  List<idl.UnlinkedParam> get parameters {
+    _parameters ??= const fb.ListReader<idl.UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 2, const <idl.UnlinkedParam>[]);
+    return _parameters;
+  }
+
+  @override
+  int get periodOffset {
+    _periodOffset ??= const fb.Uint32Reader().vTableGet(_bp, 24, 0);
+    return _periodOffset;
+  }
+
+  @override
+  idl.EntityRef get redirectedConstructor {
+    _redirectedConstructor ??= const _EntityRefReader().vTableGet(_bp, 15, null);
+    return _redirectedConstructor;
+  }
+
+  @override
+  String get redirectedConstructorName {
+    _redirectedConstructorName ??= const fb.StringReader().vTableGet(_bp, 17, '');
+    return _redirectedConstructorName;
+  }
+
+  @override
+  idl.EntityRef get returnType {
+    _returnType ??= const _EntityRefReader().vTableGet(_bp, 3, null);
+    return _returnType;
+  }
+
+  @override
+  List<idl.UnlinkedTypeParam> get typeParameters {
+    _typeParameters ??= const fb.ListReader<idl.UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 16, const <idl.UnlinkedTypeParam>[]);
+    return _typeParameters;
+  }
+
+  @override
+  int get visibleLength {
+    _visibleLength ??= const fb.Uint32Reader().vTableGet(_bp, 20, 0);
+    return _visibleLength;
+  }
+
+  @override
+  int get visibleOffset {
+    _visibleOffset ??= const fb.Uint32Reader().vTableGet(_bp, 21, 0);
+    return _visibleOffset;
+  }
+}
+
+abstract class _UnlinkedExecutableMixin implements idl.UnlinkedExecutable {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (constantInitializers.isNotEmpty) _result["constantInitializers"] = constantInitializers.map((_value) => _value.toJson()).toList();
+    if (documentationComment != null) _result["documentationComment"] = documentationComment.toJson();
+    if (inferredReturnTypeSlot != 0) _result["inferredReturnTypeSlot"] = inferredReturnTypeSlot;
+    if (isAbstract != false) _result["isAbstract"] = isAbstract;
+    if (isConst != false) _result["isConst"] = isConst;
+    if (isExternal != false) _result["isExternal"] = isExternal;
+    if (isFactory != false) _result["isFactory"] = isFactory;
+    if (isRedirectedConstructor != false) _result["isRedirectedConstructor"] = isRedirectedConstructor;
+    if (isStatic != false) _result["isStatic"] = isStatic;
+    if (kind != idl.UnlinkedExecutableKind.functionOrMethod) _result["kind"] = kind.toString().split('.')[1];
+    if (localFunctions.isNotEmpty) _result["localFunctions"] = localFunctions.map((_value) => _value.toJson()).toList();
+    if (localLabels.isNotEmpty) _result["localLabels"] = localLabels.map((_value) => _value.toJson()).toList();
+    if (localVariables.isNotEmpty) _result["localVariables"] = localVariables.map((_value) => _value.toJson()).toList();
+    if (name != '') _result["name"] = name;
+    if (nameEnd != 0) _result["nameEnd"] = nameEnd;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    if (parameters.isNotEmpty) _result["parameters"] = parameters.map((_value) => _value.toJson()).toList();
+    if (periodOffset != 0) _result["periodOffset"] = periodOffset;
+    if (redirectedConstructor != null) _result["redirectedConstructor"] = redirectedConstructor.toJson();
+    if (redirectedConstructorName != '') _result["redirectedConstructorName"] = redirectedConstructorName;
+    if (returnType != null) _result["returnType"] = returnType.toJson();
+    if (typeParameters.isNotEmpty) _result["typeParameters"] = typeParameters.map((_value) => _value.toJson()).toList();
+    if (visibleLength != 0) _result["visibleLength"] = visibleLength;
+    if (visibleOffset != 0) _result["visibleOffset"] = visibleOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "constantInitializers": constantInitializers,
+    "documentationComment": documentationComment,
+    "inferredReturnTypeSlot": inferredReturnTypeSlot,
+    "isAbstract": isAbstract,
+    "isConst": isConst,
+    "isExternal": isExternal,
+    "isFactory": isFactory,
+    "isRedirectedConstructor": isRedirectedConstructor,
+    "isStatic": isStatic,
+    "kind": kind,
+    "localFunctions": localFunctions,
+    "localLabels": localLabels,
+    "localVariables": localVariables,
+    "name": name,
+    "nameEnd": nameEnd,
+    "nameOffset": nameOffset,
+    "parameters": parameters,
+    "periodOffset": periodOffset,
+    "redirectedConstructor": redirectedConstructor,
+    "redirectedConstructorName": redirectedConstructorName,
+    "returnType": returnType,
+    "typeParameters": typeParameters,
+    "visibleLength": visibleLength,
+    "visibleOffset": visibleOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedExportNonPublicBuilder extends Object with _UnlinkedExportNonPublicMixin implements idl.UnlinkedExportNonPublic {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _annotations;
+  int _offset;
+  int _uriEnd;
+  int _uriOffset;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this export directive.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  int get offset => _offset ??= 0;
+
+  /**
+   * Offset of the "export" keyword.
+   */
+  void set offset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _offset = _value;
+  }
+
+  @override
+  int get uriEnd => _uriEnd ??= 0;
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.
+   */
+  void set uriEnd(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriEnd = _value;
+  }
+
+  @override
+  int get uriOffset => _uriOffset ??= 0;
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.
+   */
+  void set uriOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriOffset = _value;
+  }
+
+  UnlinkedExportNonPublicBuilder({List<UnlinkedConstBuilder> annotations, int offset, int uriEnd, int uriOffset})
+    : _annotations = annotations,
+      _offset = offset,
+      _uriEnd = uriEnd,
+      _uriOffset = uriOffset;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(3, offset_annotations);
+    }
+    if (_offset != null && _offset != 0) {
+      fbBuilder.addUint32(0, _offset);
+    }
+    if (_uriEnd != null && _uriEnd != 0) {
+      fbBuilder.addUint32(1, _uriEnd);
+    }
+    if (_uriOffset != null && _uriOffset != 0) {
+      fbBuilder.addUint32(2, _uriOffset);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedExportNonPublicReader extends fb.TableReader<_UnlinkedExportNonPublicImpl> {
+  const _UnlinkedExportNonPublicReader();
+
+  @override
+  _UnlinkedExportNonPublicImpl createObject(fb.BufferPointer bp) => new _UnlinkedExportNonPublicImpl(bp);
+}
+
+class _UnlinkedExportNonPublicImpl extends Object with _UnlinkedExportNonPublicMixin implements idl.UnlinkedExportNonPublic {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedExportNonPublicImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  int _offset;
+  int _uriEnd;
+  int _uriOffset;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 3, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  int get offset {
+    _offset ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _offset;
+  }
+
+  @override
+  int get uriEnd {
+    _uriEnd ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _uriEnd;
+  }
+
+  @override
+  int get uriOffset {
+    _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _uriOffset;
+  }
+}
+
+abstract class _UnlinkedExportNonPublicMixin implements idl.UnlinkedExportNonPublic {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (offset != 0) _result["offset"] = offset;
+    if (uriEnd != 0) _result["uriEnd"] = uriEnd;
+    if (uriOffset != 0) _result["uriOffset"] = uriOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "offset": offset,
+    "uriEnd": uriEnd,
+    "uriOffset": uriOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedExportPublicBuilder extends Object with _UnlinkedExportPublicMixin implements idl.UnlinkedExportPublic {
+  bool _finished = false;
+
+  List<UnlinkedCombinatorBuilder> _combinators;
+  String _uri;
+
+  @override
+  List<UnlinkedCombinatorBuilder> get combinators => _combinators ??= <UnlinkedCombinatorBuilder>[];
+
+  /**
+   * Combinators contained in this import declaration.
+   */
+  void set combinators(List<UnlinkedCombinatorBuilder> _value) {
+    assert(!_finished);
+    _combinators = _value;
+  }
+
+  @override
+  String get uri => _uri ??= '';
+
+  /**
+   * URI used in the source code to reference the exported library.
+   */
+  void set uri(String _value) {
+    assert(!_finished);
+    _uri = _value;
+  }
+
+  UnlinkedExportPublicBuilder({List<UnlinkedCombinatorBuilder> combinators, String uri})
+    : _combinators = combinators,
+      _uri = uri;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_combinators;
+    fb.Offset offset_uri;
+    if (!(_combinators == null || _combinators.isEmpty)) {
+      offset_combinators = fbBuilder.writeList(_combinators.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_uri != null) {
+      offset_uri = fbBuilder.writeString(_uri);
+    }
+    fbBuilder.startTable();
+    if (offset_combinators != null) {
+      fbBuilder.addOffset(1, offset_combinators);
+    }
+    if (offset_uri != null) {
+      fbBuilder.addOffset(0, offset_uri);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedExportPublicReader extends fb.TableReader<_UnlinkedExportPublicImpl> {
+  const _UnlinkedExportPublicReader();
+
+  @override
+  _UnlinkedExportPublicImpl createObject(fb.BufferPointer bp) => new _UnlinkedExportPublicImpl(bp);
+}
+
+class _UnlinkedExportPublicImpl extends Object with _UnlinkedExportPublicMixin implements idl.UnlinkedExportPublic {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedExportPublicImpl(this._bp);
+
+  List<idl.UnlinkedCombinator> _combinators;
+  String _uri;
+
+  @override
+  List<idl.UnlinkedCombinator> get combinators {
+    _combinators ??= const fb.ListReader<idl.UnlinkedCombinator>(const _UnlinkedCombinatorReader()).vTableGet(_bp, 1, const <idl.UnlinkedCombinator>[]);
+    return _combinators;
+  }
+
+  @override
+  String get uri {
+    _uri ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _uri;
+  }
+}
+
+abstract class _UnlinkedExportPublicMixin implements idl.UnlinkedExportPublic {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (combinators.isNotEmpty) _result["combinators"] = combinators.map((_value) => _value.toJson()).toList();
+    if (uri != '') _result["uri"] = uri;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "combinators": combinators,
+    "uri": uri,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedImportBuilder extends Object with _UnlinkedImportMixin implements idl.UnlinkedImport {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _annotations;
+  List<UnlinkedCombinatorBuilder> _combinators;
+  bool _isDeferred;
+  bool _isImplicit;
+  int _offset;
+  int _prefixOffset;
+  int _prefixReference;
+  String _uri;
+  int _uriEnd;
+  int _uriOffset;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this import declaration.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  List<UnlinkedCombinatorBuilder> get combinators => _combinators ??= <UnlinkedCombinatorBuilder>[];
+
+  /**
+   * Combinators contained in this import declaration.
+   */
+  void set combinators(List<UnlinkedCombinatorBuilder> _value) {
+    assert(!_finished);
+    _combinators = _value;
+  }
+
+  @override
+  bool get isDeferred => _isDeferred ??= false;
+
+  /**
+   * Indicates whether the import declaration uses the `deferred` keyword.
+   */
+  void set isDeferred(bool _value) {
+    assert(!_finished);
+    _isDeferred = _value;
+  }
+
+  @override
+  bool get isImplicit => _isImplicit ??= false;
+
+  /**
+   * Indicates whether the import declaration is implicit.
+   */
+  void set isImplicit(bool _value) {
+    assert(!_finished);
+    _isImplicit = _value;
+  }
+
+  @override
+  int get offset => _offset ??= 0;
+
+  /**
+   * If [isImplicit] is false, offset of the "import" keyword.  If [isImplicit]
+   * is true, zero.
+   */
+  void set offset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _offset = _value;
+  }
+
+  @override
+  int get prefixOffset => _prefixOffset ??= 0;
+
+  /**
+   * Offset of the prefix name relative to the beginning of the file, or zero
+   * if there is no prefix.
+   */
+  void set prefixOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _prefixOffset = _value;
+  }
+
+  @override
+  int get prefixReference => _prefixReference ??= 0;
+
+  /**
+   * 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.
+   */
+  void set prefixReference(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _prefixReference = _value;
+  }
+
+  @override
+  String get uri => _uri ??= '';
+
+  /**
+   * URI used in the source code to reference the imported library.
+   */
+  void set uri(String _value) {
+    assert(!_finished);
+    _uri = _value;
+  }
+
+  @override
+  int get uriEnd => _uriEnd ??= 0;
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.  If [isImplicit] is true, zero.
+   */
+  void set uriEnd(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriEnd = _value;
+  }
+
+  @override
+  int get uriOffset => _uriOffset ??= 0;
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.  If [isImplicit] is true, zero.
+   */
+  void set uriOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriOffset = _value;
+  }
+
+  UnlinkedImportBuilder({List<UnlinkedConstBuilder> annotations, List<UnlinkedCombinatorBuilder> combinators, bool isDeferred, bool isImplicit, int offset, int prefixOffset, int prefixReference, String uri, int uriEnd, int uriOffset})
+    : _annotations = annotations,
+      _combinators = combinators,
+      _isDeferred = isDeferred,
+      _isImplicit = isImplicit,
+      _offset = offset,
+      _prefixOffset = prefixOffset,
+      _prefixReference = prefixReference,
+      _uri = uri,
+      _uriEnd = uriEnd,
+      _uriOffset = uriOffset;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_combinators;
+    fb.Offset offset_uri;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_combinators == null || _combinators.isEmpty)) {
+      offset_combinators = fbBuilder.writeList(_combinators.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_uri != null) {
+      offset_uri = fbBuilder.writeString(_uri);
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(8, offset_annotations);
+    }
+    if (offset_combinators != null) {
+      fbBuilder.addOffset(4, offset_combinators);
+    }
+    if (_isDeferred == true) {
+      fbBuilder.addBool(9, true);
+    }
+    if (_isImplicit == true) {
+      fbBuilder.addBool(5, true);
+    }
+    if (_offset != null && _offset != 0) {
+      fbBuilder.addUint32(0, _offset);
+    }
+    if (_prefixOffset != null && _prefixOffset != 0) {
+      fbBuilder.addUint32(6, _prefixOffset);
+    }
+    if (_prefixReference != null && _prefixReference != 0) {
+      fbBuilder.addUint32(7, _prefixReference);
+    }
+    if (offset_uri != null) {
+      fbBuilder.addOffset(1, offset_uri);
+    }
+    if (_uriEnd != null && _uriEnd != 0) {
+      fbBuilder.addUint32(2, _uriEnd);
+    }
+    if (_uriOffset != null && _uriOffset != 0) {
+      fbBuilder.addUint32(3, _uriOffset);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedImportReader extends fb.TableReader<_UnlinkedImportImpl> {
+  const _UnlinkedImportReader();
+
+  @override
+  _UnlinkedImportImpl createObject(fb.BufferPointer bp) => new _UnlinkedImportImpl(bp);
+}
+
+class _UnlinkedImportImpl extends Object with _UnlinkedImportMixin implements idl.UnlinkedImport {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedImportImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  List<idl.UnlinkedCombinator> _combinators;
+  bool _isDeferred;
+  bool _isImplicit;
+  int _offset;
+  int _prefixOffset;
+  int _prefixReference;
+  String _uri;
+  int _uriEnd;
+  int _uriOffset;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 8, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  List<idl.UnlinkedCombinator> get combinators {
+    _combinators ??= const fb.ListReader<idl.UnlinkedCombinator>(const _UnlinkedCombinatorReader()).vTableGet(_bp, 4, const <idl.UnlinkedCombinator>[]);
+    return _combinators;
+  }
+
+  @override
+  bool get isDeferred {
+    _isDeferred ??= const fb.BoolReader().vTableGet(_bp, 9, false);
+    return _isDeferred;
+  }
+
+  @override
+  bool get isImplicit {
+    _isImplicit ??= const fb.BoolReader().vTableGet(_bp, 5, false);
+    return _isImplicit;
+  }
+
+  @override
+  int get offset {
+    _offset ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _offset;
+  }
+
+  @override
+  int get prefixOffset {
+    _prefixOffset ??= const fb.Uint32Reader().vTableGet(_bp, 6, 0);
+    return _prefixOffset;
+  }
+
+  @override
+  int get prefixReference {
+    _prefixReference ??= const fb.Uint32Reader().vTableGet(_bp, 7, 0);
+    return _prefixReference;
+  }
+
+  @override
+  String get uri {
+    _uri ??= const fb.StringReader().vTableGet(_bp, 1, '');
+    return _uri;
+  }
+
+  @override
+  int get uriEnd {
+    _uriEnd ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _uriEnd;
+  }
+
+  @override
+  int get uriOffset {
+    _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _uriOffset;
+  }
+}
+
+abstract class _UnlinkedImportMixin implements idl.UnlinkedImport {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (combinators.isNotEmpty) _result["combinators"] = combinators.map((_value) => _value.toJson()).toList();
+    if (isDeferred != false) _result["isDeferred"] = isDeferred;
+    if (isImplicit != false) _result["isImplicit"] = isImplicit;
+    if (offset != 0) _result["offset"] = offset;
+    if (prefixOffset != 0) _result["prefixOffset"] = prefixOffset;
+    if (prefixReference != 0) _result["prefixReference"] = prefixReference;
+    if (uri != '') _result["uri"] = uri;
+    if (uriEnd != 0) _result["uriEnd"] = uriEnd;
+    if (uriOffset != 0) _result["uriOffset"] = uriOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "combinators": combinators,
+    "isDeferred": isDeferred,
+    "isImplicit": isImplicit,
+    "offset": offset,
+    "prefixOffset": prefixOffset,
+    "prefixReference": prefixReference,
+    "uri": uri,
+    "uriEnd": uriEnd,
+    "uriOffset": uriOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedLabelBuilder extends Object with _UnlinkedLabelMixin implements idl.UnlinkedLabel {
+  bool _finished = false;
+
+  bool _isOnSwitchMember;
+  bool _isOnSwitchStatement;
+  String _name;
+  int _nameOffset;
+
+  @override
+  bool get isOnSwitchMember => _isOnSwitchMember ??= false;
+
+  /**
+   * Return `true` if this label is associated with a `switch` member (`case` or
+   * `default`).
+   */
+  void set isOnSwitchMember(bool _value) {
+    assert(!_finished);
+    _isOnSwitchMember = _value;
+  }
+
+  @override
+  bool get isOnSwitchStatement => _isOnSwitchStatement ??= false;
+
+  /**
+   * Return `true` if this label is associated with a `switch` statement.
+   */
+  void set isOnSwitchStatement(bool _value) {
+    assert(!_finished);
+    _isOnSwitchStatement = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * Name of the label.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
+  /**
+   * Offset of the label relative to the beginning of the file.
+   */
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
+
+  UnlinkedLabelBuilder({bool isOnSwitchMember, bool isOnSwitchStatement, String name, int nameOffset})
+    : _isOnSwitchMember = isOnSwitchMember,
+      _isOnSwitchStatement = isOnSwitchStatement,
+      _name = name,
+      _nameOffset = nameOffset;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_name;
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (_isOnSwitchMember == true) {
+      fbBuilder.addBool(2, true);
+    }
+    if (_isOnSwitchStatement == true) {
+      fbBuilder.addBool(3, true);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(1, _nameOffset);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedLabelReader extends fb.TableReader<_UnlinkedLabelImpl> {
+  const _UnlinkedLabelReader();
+
+  @override
+  _UnlinkedLabelImpl createObject(fb.BufferPointer bp) => new _UnlinkedLabelImpl(bp);
+}
+
+class _UnlinkedLabelImpl extends Object with _UnlinkedLabelMixin implements idl.UnlinkedLabel {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedLabelImpl(this._bp);
+
+  bool _isOnSwitchMember;
+  bool _isOnSwitchStatement;
+  String _name;
+  int _nameOffset;
+
+  @override
+  bool get isOnSwitchMember {
+    _isOnSwitchMember ??= const fb.BoolReader().vTableGet(_bp, 2, false);
+    return _isOnSwitchMember;
+  }
+
+  @override
+  bool get isOnSwitchStatement {
+    _isOnSwitchStatement ??= const fb.BoolReader().vTableGet(_bp, 3, false);
+    return _isOnSwitchStatement;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _nameOffset;
+  }
+}
+
+abstract class _UnlinkedLabelMixin implements idl.UnlinkedLabel {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (isOnSwitchMember != false) _result["isOnSwitchMember"] = isOnSwitchMember;
+    if (isOnSwitchStatement != false) _result["isOnSwitchStatement"] = isOnSwitchStatement;
+    if (name != '') _result["name"] = name;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "isOnSwitchMember": isOnSwitchMember,
+    "isOnSwitchStatement": isOnSwitchStatement,
+    "name": name,
+    "nameOffset": nameOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedParamBuilder extends Object with _UnlinkedParamMixin implements idl.UnlinkedParam {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedConstBuilder _defaultValue;
+  String _defaultValueCode;
+  int _inferredTypeSlot;
+  UnlinkedExecutableBuilder _initializer;
+  bool _isFunctionTyped;
+  bool _isInitializingFormal;
+  idl.UnlinkedParamKind _kind;
+  String _name;
+  int _nameOffset;
+  List<UnlinkedParamBuilder> _parameters;
+  EntityRefBuilder _type;
+  int _visibleLength;
+  int _visibleOffset;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this parameter.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  UnlinkedConstBuilder get defaultValue => _defaultValue;
+
+  /**
+   * 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].
+   */
+  void set defaultValue(UnlinkedConstBuilder _value) {
+    assert(!_finished);
+    _defaultValue = _value;
+  }
+
+  @override
+  String get defaultValueCode => _defaultValueCode ??= '';
+
+  /**
+   * If the parameter has a default value, the source text of the constant
+   * expression in the default value.  Otherwise the empty string.
+   */
+  void set defaultValueCode(String _value) {
+    assert(!_finished);
+    _defaultValueCode = _value;
+  }
+
+  @override
+  int get inferredTypeSlot => _inferredTypeSlot ??= 0;
+
+  /**
+   * 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.
+   */
+  void set inferredTypeSlot(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _inferredTypeSlot = _value;
+  }
+
+  @override
+  UnlinkedExecutableBuilder get initializer => _initializer;
+
+  /**
+   * The synthetic initializer function of the parameter.  Absent if the variable
+   * does not have an initializer.
+   */
+  void set initializer(UnlinkedExecutableBuilder _value) {
+    assert(!_finished);
+    _initializer = _value;
+  }
+
+  @override
+  bool get isFunctionTyped => _isFunctionTyped ??= false;
+
+  /**
+   * Indicates whether this is a function-typed parameter.
+   */
+  void set isFunctionTyped(bool _value) {
+    assert(!_finished);
+    _isFunctionTyped = _value;
+  }
+
+  @override
+  bool get isInitializingFormal => _isInitializingFormal ??= false;
+
+  /**
+   * Indicates whether this is an initializing formal parameter (i.e. it is
+   * declared using `this.` syntax).
+   */
+  void set isInitializingFormal(bool _value) {
+    assert(!_finished);
+    _isInitializingFormal = _value;
+  }
+
+  @override
+  idl.UnlinkedParamKind get kind => _kind ??= idl.UnlinkedParamKind.required;
+
+  /**
+   * Kind of the parameter.
+   */
+  void set kind(idl.UnlinkedParamKind _value) {
+    assert(!_finished);
+    _kind = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * Name of the parameter.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
+  /**
+   * Offset of the parameter name relative to the beginning of the file.
+   */
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
+
+  @override
+  List<UnlinkedParamBuilder> get parameters => _parameters ??= <UnlinkedParamBuilder>[];
+
+  /**
+   * If [isFunctionTyped] is `true`, the parameters of the function type.
+   */
+  void set parameters(List<UnlinkedParamBuilder> _value) {
+    assert(!_finished);
+    _parameters = _value;
+  }
+
+  @override
+  EntityRefBuilder get type => _type;
+
+  /**
+   * If [isFunctionTyped] is `true`, the declared return type.  If
+   * [isFunctionTyped] is `false`, the declared type.  Absent if the type is
+   * implicit.
+   */
+  void set type(EntityRefBuilder _value) {
+    assert(!_finished);
+    _type = _value;
+  }
+
+  @override
+  int get visibleLength => _visibleLength ??= 0;
+
+  /**
+   * The length of the visible range.
+   */
+  void set visibleLength(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _visibleLength = _value;
+  }
+
+  @override
+  int get visibleOffset => _visibleOffset ??= 0;
+
+  /**
+   * The beginning of the visible range.
+   */
+  void set visibleOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _visibleOffset = _value;
+  }
+
+  UnlinkedParamBuilder({List<UnlinkedConstBuilder> annotations, UnlinkedConstBuilder defaultValue, String defaultValueCode, int inferredTypeSlot, UnlinkedExecutableBuilder initializer, bool isFunctionTyped, bool isInitializingFormal, idl.UnlinkedParamKind kind, String name, int nameOffset, List<UnlinkedParamBuilder> parameters, EntityRefBuilder type, int visibleLength, int visibleOffset})
+    : _annotations = annotations,
+      _defaultValue = defaultValue,
+      _defaultValueCode = defaultValueCode,
+      _inferredTypeSlot = inferredTypeSlot,
+      _initializer = initializer,
+      _isFunctionTyped = isFunctionTyped,
+      _isInitializingFormal = isInitializingFormal,
+      _kind = kind,
+      _name = name,
+      _nameOffset = nameOffset,
+      _parameters = parameters,
+      _type = type,
+      _visibleLength = visibleLength,
+      _visibleOffset = visibleOffset;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_defaultValue;
+    fb.Offset offset_defaultValueCode;
+    fb.Offset offset_initializer;
+    fb.Offset offset_name;
+    fb.Offset offset_parameters;
+    fb.Offset offset_type;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_defaultValue != null) {
+      offset_defaultValue = _defaultValue.finish(fbBuilder);
+    }
+    if (_defaultValueCode != null) {
+      offset_defaultValueCode = fbBuilder.writeString(_defaultValueCode);
+    }
+    if (_initializer != null) {
+      offset_initializer = _initializer.finish(fbBuilder);
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    if (!(_parameters == null || _parameters.isEmpty)) {
+      offset_parameters = fbBuilder.writeList(_parameters.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_type != null) {
+      offset_type = _type.finish(fbBuilder);
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(9, offset_annotations);
+    }
+    if (offset_defaultValue != null) {
+      fbBuilder.addOffset(7, offset_defaultValue);
+    }
+    if (offset_defaultValueCode != null) {
+      fbBuilder.addOffset(13, offset_defaultValueCode);
+    }
+    if (_inferredTypeSlot != null && _inferredTypeSlot != 0) {
+      fbBuilder.addUint32(2, _inferredTypeSlot);
+    }
+    if (offset_initializer != null) {
+      fbBuilder.addOffset(12, offset_initializer);
+    }
+    if (_isFunctionTyped == true) {
+      fbBuilder.addBool(5, true);
+    }
+    if (_isInitializingFormal == true) {
+      fbBuilder.addBool(6, true);
+    }
+    if (_kind != null && _kind != idl.UnlinkedParamKind.required) {
+      fbBuilder.addUint8(4, _kind.index);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(1, _nameOffset);
+    }
+    if (offset_parameters != null) {
+      fbBuilder.addOffset(8, offset_parameters);
+    }
+    if (offset_type != null) {
+      fbBuilder.addOffset(3, offset_type);
+    }
+    if (_visibleLength != null && _visibleLength != 0) {
+      fbBuilder.addUint32(10, _visibleLength);
+    }
+    if (_visibleOffset != null && _visibleOffset != 0) {
+      fbBuilder.addUint32(11, _visibleOffset);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedParamReader extends fb.TableReader<_UnlinkedParamImpl> {
+  const _UnlinkedParamReader();
+
+  @override
+  _UnlinkedParamImpl createObject(fb.BufferPointer bp) => new _UnlinkedParamImpl(bp);
+}
+
+class _UnlinkedParamImpl extends Object with _UnlinkedParamMixin implements idl.UnlinkedParam {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedParamImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  idl.UnlinkedConst _defaultValue;
+  String _defaultValueCode;
+  int _inferredTypeSlot;
+  idl.UnlinkedExecutable _initializer;
+  bool _isFunctionTyped;
+  bool _isInitializingFormal;
+  idl.UnlinkedParamKind _kind;
+  String _name;
+  int _nameOffset;
+  List<idl.UnlinkedParam> _parameters;
+  idl.EntityRef _type;
+  int _visibleLength;
+  int _visibleOffset;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 9, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  idl.UnlinkedConst get defaultValue {
+    _defaultValue ??= const _UnlinkedConstReader().vTableGet(_bp, 7, null);
+    return _defaultValue;
+  }
+
+  @override
+  String get defaultValueCode {
+    _defaultValueCode ??= const fb.StringReader().vTableGet(_bp, 13, '');
+    return _defaultValueCode;
+  }
+
+  @override
+  int get inferredTypeSlot {
+    _inferredTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _inferredTypeSlot;
+  }
+
+  @override
+  idl.UnlinkedExecutable get initializer {
+    _initializer ??= const _UnlinkedExecutableReader().vTableGet(_bp, 12, null);
+    return _initializer;
+  }
+
+  @override
+  bool get isFunctionTyped {
+    _isFunctionTyped ??= const fb.BoolReader().vTableGet(_bp, 5, false);
+    return _isFunctionTyped;
+  }
+
+  @override
+  bool get isInitializingFormal {
+    _isInitializingFormal ??= const fb.BoolReader().vTableGet(_bp, 6, false);
+    return _isInitializingFormal;
+  }
+
+  @override
+  idl.UnlinkedParamKind get kind {
+    _kind ??= const _UnlinkedParamKindReader().vTableGet(_bp, 4, idl.UnlinkedParamKind.required);
+    return _kind;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _nameOffset;
+  }
+
+  @override
+  List<idl.UnlinkedParam> get parameters {
+    _parameters ??= const fb.ListReader<idl.UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 8, const <idl.UnlinkedParam>[]);
+    return _parameters;
+  }
+
+  @override
+  idl.EntityRef get type {
+    _type ??= const _EntityRefReader().vTableGet(_bp, 3, null);
+    return _type;
+  }
+
+  @override
+  int get visibleLength {
+    _visibleLength ??= const fb.Uint32Reader().vTableGet(_bp, 10, 0);
+    return _visibleLength;
+  }
+
+  @override
+  int get visibleOffset {
+    _visibleOffset ??= const fb.Uint32Reader().vTableGet(_bp, 11, 0);
+    return _visibleOffset;
+  }
+}
+
+abstract class _UnlinkedParamMixin implements idl.UnlinkedParam {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (defaultValue != null) _result["defaultValue"] = defaultValue.toJson();
+    if (defaultValueCode != '') _result["defaultValueCode"] = defaultValueCode;
+    if (inferredTypeSlot != 0) _result["inferredTypeSlot"] = inferredTypeSlot;
+    if (initializer != null) _result["initializer"] = initializer.toJson();
+    if (isFunctionTyped != false) _result["isFunctionTyped"] = isFunctionTyped;
+    if (isInitializingFormal != false) _result["isInitializingFormal"] = isInitializingFormal;
+    if (kind != idl.UnlinkedParamKind.required) _result["kind"] = kind.toString().split('.')[1];
+    if (name != '') _result["name"] = name;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    if (parameters.isNotEmpty) _result["parameters"] = parameters.map((_value) => _value.toJson()).toList();
+    if (type != null) _result["type"] = type.toJson();
+    if (visibleLength != 0) _result["visibleLength"] = visibleLength;
+    if (visibleOffset != 0) _result["visibleOffset"] = visibleOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "defaultValue": defaultValue,
+    "defaultValueCode": defaultValueCode,
+    "inferredTypeSlot": inferredTypeSlot,
+    "initializer": initializer,
+    "isFunctionTyped": isFunctionTyped,
+    "isInitializingFormal": isInitializingFormal,
+    "kind": kind,
+    "name": name,
+    "nameOffset": nameOffset,
+    "parameters": parameters,
+    "type": type,
+    "visibleLength": visibleLength,
+    "visibleOffset": visibleOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedPartBuilder extends Object with _UnlinkedPartMixin implements idl.UnlinkedPart {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _annotations;
+  int _uriEnd;
+  int _uriOffset;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this part declaration.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  int get uriEnd => _uriEnd ??= 0;
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.
+   */
+  void set uriEnd(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriEnd = _value;
+  }
+
+  @override
+  int get uriOffset => _uriOffset ??= 0;
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.
+   */
+  void set uriOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _uriOffset = _value;
+  }
+
+  UnlinkedPartBuilder({List<UnlinkedConstBuilder> annotations, int uriEnd, int uriOffset})
+    : _annotations = annotations,
+      _uriEnd = uriEnd,
+      _uriOffset = uriOffset;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(2, offset_annotations);
+    }
+    if (_uriEnd != null && _uriEnd != 0) {
+      fbBuilder.addUint32(0, _uriEnd);
+    }
+    if (_uriOffset != null && _uriOffset != 0) {
+      fbBuilder.addUint32(1, _uriOffset);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedPartReader extends fb.TableReader<_UnlinkedPartImpl> {
+  const _UnlinkedPartReader();
+
+  @override
+  _UnlinkedPartImpl createObject(fb.BufferPointer bp) => new _UnlinkedPartImpl(bp);
+}
+
+class _UnlinkedPartImpl extends Object with _UnlinkedPartMixin implements idl.UnlinkedPart {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedPartImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  int _uriEnd;
+  int _uriOffset;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 2, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  int get uriEnd {
+    _uriEnd ??= const fb.Uint32Reader().vTableGet(_bp, 0, 0);
+    return _uriEnd;
+  }
+
+  @override
+  int get uriOffset {
+    _uriOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _uriOffset;
+  }
+}
+
+abstract class _UnlinkedPartMixin implements idl.UnlinkedPart {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (uriEnd != 0) _result["uriEnd"] = uriEnd;
+    if (uriOffset != 0) _result["uriOffset"] = uriOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "uriEnd": uriEnd,
+    "uriOffset": uriOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedPublicNameBuilder extends Object with _UnlinkedPublicNameMixin implements idl.UnlinkedPublicName {
+  bool _finished = false;
+
+  idl.ReferenceKind _kind;
+  List<UnlinkedPublicNameBuilder> _members;
+  String _name;
+  int _numTypeParameters;
+
+  @override
+  idl.ReferenceKind get kind => _kind ??= idl.ReferenceKind.classOrEnum;
+
+  /**
+   * The kind of object referred to by the name.
+   */
+  void set kind(idl.ReferenceKind _value) {
+    assert(!_finished);
+    _kind = _value;
+  }
+
+  @override
+  List<UnlinkedPublicNameBuilder> get members => _members ??= <UnlinkedPublicNameBuilder>[];
+
+  /**
+   * 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.
+   */
+  void set members(List<UnlinkedPublicNameBuilder> _value) {
+    assert(!_finished);
+    _members = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * The name itself.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get numTypeParameters => _numTypeParameters ??= 0;
+
+  /**
+   * If the entity being referred to is generic, the number of type parameters
+   * it accepts.  Otherwise zero.
+   */
+  void set numTypeParameters(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _numTypeParameters = _value;
+  }
+
+  UnlinkedPublicNameBuilder({idl.ReferenceKind kind, List<UnlinkedPublicNameBuilder> members, String name, int numTypeParameters})
+    : _kind = kind,
+      _members = members,
+      _name = name,
+      _numTypeParameters = numTypeParameters;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_members;
+    fb.Offset offset_name;
+    if (!(_members == null || _members.isEmpty)) {
+      offset_members = fbBuilder.writeList(_members.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (_kind != null && _kind != idl.ReferenceKind.classOrEnum) {
+      fbBuilder.addUint8(1, _kind.index);
+    }
+    if (offset_members != null) {
+      fbBuilder.addOffset(2, offset_members);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_numTypeParameters != null && _numTypeParameters != 0) {
+      fbBuilder.addUint32(3, _numTypeParameters);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedPublicNameReader extends fb.TableReader<_UnlinkedPublicNameImpl> {
+  const _UnlinkedPublicNameReader();
+
+  @override
+  _UnlinkedPublicNameImpl createObject(fb.BufferPointer bp) => new _UnlinkedPublicNameImpl(bp);
+}
+
+class _UnlinkedPublicNameImpl extends Object with _UnlinkedPublicNameMixin implements idl.UnlinkedPublicName {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedPublicNameImpl(this._bp);
+
+  idl.ReferenceKind _kind;
+  List<idl.UnlinkedPublicName> _members;
+  String _name;
+  int _numTypeParameters;
+
+  @override
+  idl.ReferenceKind get kind {
+    _kind ??= const _ReferenceKindReader().vTableGet(_bp, 1, idl.ReferenceKind.classOrEnum);
+    return _kind;
+  }
+
+  @override
+  List<idl.UnlinkedPublicName> get members {
+    _members ??= const fb.ListReader<idl.UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 2, const <idl.UnlinkedPublicName>[]);
+    return _members;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get numTypeParameters {
+    _numTypeParameters ??= const fb.Uint32Reader().vTableGet(_bp, 3, 0);
+    return _numTypeParameters;
+  }
+}
+
+abstract class _UnlinkedPublicNameMixin implements idl.UnlinkedPublicName {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (kind != idl.ReferenceKind.classOrEnum) _result["kind"] = kind.toString().split('.')[1];
+    if (members.isNotEmpty) _result["members"] = members.map((_value) => _value.toJson()).toList();
+    if (name != '') _result["name"] = name;
+    if (numTypeParameters != 0) _result["numTypeParameters"] = numTypeParameters;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "kind": kind,
+    "members": members,
+    "name": name,
+    "numTypeParameters": numTypeParameters,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedPublicNamespaceBuilder extends Object with _UnlinkedPublicNamespaceMixin implements idl.UnlinkedPublicNamespace {
+  bool _finished = false;
+
+  List<UnlinkedExportPublicBuilder> _exports;
+  List<UnlinkedPublicNameBuilder> _names;
+  List<String> _parts;
+
+  @override
+  List<UnlinkedExportPublicBuilder> get exports => _exports ??= <UnlinkedExportPublicBuilder>[];
+
+  /**
+   * Export declarations in the compilation unit.
+   */
+  void set exports(List<UnlinkedExportPublicBuilder> _value) {
+    assert(!_finished);
+    _exports = _value;
+  }
+
+  @override
+  List<UnlinkedPublicNameBuilder> get names => _names ??= <UnlinkedPublicNameBuilder>[];
+
+  /**
+   * Public names defined in the compilation unit.
+   *
+   * TODO(paulberry): consider sorting these names to reduce unnecessary
+   * relinking.
+   */
+  void set names(List<UnlinkedPublicNameBuilder> _value) {
+    assert(!_finished);
+    _names = _value;
+  }
+
+  @override
+  List<String> get parts => _parts ??= <String>[];
+
+  /**
+   * URIs referenced by part declarations in the compilation unit.
+   */
+  void set parts(List<String> _value) {
+    assert(!_finished);
+    _parts = _value;
+  }
+
+  UnlinkedPublicNamespaceBuilder({List<UnlinkedExportPublicBuilder> exports, List<UnlinkedPublicNameBuilder> names, List<String> parts})
+    : _exports = exports,
+      _names = names,
+      _parts = parts;
+
+  List<int> toBuffer() {
+    fb.Builder fbBuilder = new fb.Builder();
+    return fbBuilder.finish(finish(fbBuilder), "UPNS");
+  }
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_exports;
+    fb.Offset offset_names;
+    fb.Offset offset_parts;
+    if (!(_exports == null || _exports.isEmpty)) {
+      offset_exports = fbBuilder.writeList(_exports.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_names == null || _names.isEmpty)) {
+      offset_names = fbBuilder.writeList(_names.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (!(_parts == null || _parts.isEmpty)) {
+      offset_parts = fbBuilder.writeList(_parts.map((b) => fbBuilder.writeString(b)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_exports != null) {
+      fbBuilder.addOffset(2, offset_exports);
+    }
+    if (offset_names != null) {
+      fbBuilder.addOffset(0, offset_names);
+    }
+    if (offset_parts != null) {
+      fbBuilder.addOffset(1, offset_parts);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+idl.UnlinkedPublicNamespace readUnlinkedPublicNamespace(List<int> buffer) {
+  fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
+  return const _UnlinkedPublicNamespaceReader().read(rootRef);
+}
+
+class _UnlinkedPublicNamespaceReader extends fb.TableReader<_UnlinkedPublicNamespaceImpl> {
+  const _UnlinkedPublicNamespaceReader();
+
+  @override
+  _UnlinkedPublicNamespaceImpl createObject(fb.BufferPointer bp) => new _UnlinkedPublicNamespaceImpl(bp);
+}
+
+class _UnlinkedPublicNamespaceImpl extends Object with _UnlinkedPublicNamespaceMixin implements idl.UnlinkedPublicNamespace {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedPublicNamespaceImpl(this._bp);
+
+  List<idl.UnlinkedExportPublic> _exports;
+  List<idl.UnlinkedPublicName> _names;
+  List<String> _parts;
+
+  @override
+  List<idl.UnlinkedExportPublic> get exports {
+    _exports ??= const fb.ListReader<idl.UnlinkedExportPublic>(const _UnlinkedExportPublicReader()).vTableGet(_bp, 2, const <idl.UnlinkedExportPublic>[]);
+    return _exports;
+  }
+
+  @override
+  List<idl.UnlinkedPublicName> get names {
+    _names ??= const fb.ListReader<idl.UnlinkedPublicName>(const _UnlinkedPublicNameReader()).vTableGet(_bp, 0, const <idl.UnlinkedPublicName>[]);
+    return _names;
+  }
+
+  @override
+  List<String> get parts {
+    _parts ??= const fb.ListReader<String>(const fb.StringReader()).vTableGet(_bp, 1, const <String>[]);
+    return _parts;
+  }
+}
+
+abstract class _UnlinkedPublicNamespaceMixin implements idl.UnlinkedPublicNamespace {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (exports.isNotEmpty) _result["exports"] = exports.map((_value) => _value.toJson()).toList();
+    if (names.isNotEmpty) _result["names"] = names.map((_value) => _value.toJson()).toList();
+    if (parts.isNotEmpty) _result["parts"] = parts;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "exports": exports,
+    "names": names,
+    "parts": parts,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedReferenceBuilder extends Object with _UnlinkedReferenceMixin implements idl.UnlinkedReference {
+  bool _finished = false;
+
+  String _name;
+  int _prefixReference;
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * 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*".
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get prefixReference => _prefixReference ??= 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.
+   */
+  void set prefixReference(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _prefixReference = _value;
+  }
+
+  UnlinkedReferenceBuilder({String name, int prefixReference})
+    : _name = name,
+      _prefixReference = prefixReference;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_name;
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_prefixReference != null && _prefixReference != 0) {
+      fbBuilder.addUint32(1, _prefixReference);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedReferenceReader extends fb.TableReader<_UnlinkedReferenceImpl> {
+  const _UnlinkedReferenceReader();
+
+  @override
+  _UnlinkedReferenceImpl createObject(fb.BufferPointer bp) => new _UnlinkedReferenceImpl(bp);
+}
+
+class _UnlinkedReferenceImpl extends Object with _UnlinkedReferenceMixin implements idl.UnlinkedReference {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedReferenceImpl(this._bp);
+
+  String _name;
+  int _prefixReference;
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get prefixReference {
+    _prefixReference ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _prefixReference;
+  }
+}
+
+abstract class _UnlinkedReferenceMixin implements idl.UnlinkedReference {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (name != '') _result["name"] = name;
+    if (prefixReference != 0) _result["prefixReference"] = prefixReference;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "name": name,
+    "prefixReference": prefixReference,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedTypedefBuilder extends Object with _UnlinkedTypedefMixin implements idl.UnlinkedTypedef {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedDocumentationCommentBuilder _documentationComment;
+  String _name;
+  int _nameOffset;
+  List<UnlinkedParamBuilder> _parameters;
+  EntityRefBuilder _returnType;
+  List<UnlinkedTypeParamBuilder> _typeParameters;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this typedef.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
+  /**
+   * Documentation comment for the typedef, or `null` if there is no
+   * documentation comment.
+   */
+  void set documentationComment(UnlinkedDocumentationCommentBuilder _value) {
+    assert(!_finished);
+    _documentationComment = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * Name of the typedef.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
+  /**
+   * Offset of the typedef name relative to the beginning of the file.
+   */
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
+
+  @override
+  List<UnlinkedParamBuilder> get parameters => _parameters ??= <UnlinkedParamBuilder>[];
+
+  /**
+   * Parameters of the executable, if any.
+   */
+  void set parameters(List<UnlinkedParamBuilder> _value) {
+    assert(!_finished);
+    _parameters = _value;
+  }
+
+  @override
+  EntityRefBuilder get returnType => _returnType;
+
+  /**
+   * Return type of the typedef.
+   */
+  void set returnType(EntityRefBuilder _value) {
+    assert(!_finished);
+    _returnType = _value;
+  }
+
+  @override
+  List<UnlinkedTypeParamBuilder> get typeParameters => _typeParameters ??= <UnlinkedTypeParamBuilder>[];
+
+  /**
+   * Type parameters of the typedef, if any.
+   */
+  void set typeParameters(List<UnlinkedTypeParamBuilder> _value) {
+    assert(!_finished);
+    _typeParameters = _value;
+  }
+
+  UnlinkedTypedefBuilder({List<UnlinkedConstBuilder> annotations, UnlinkedDocumentationCommentBuilder documentationComment, String name, int nameOffset, List<UnlinkedParamBuilder> parameters, EntityRefBuilder returnType, List<UnlinkedTypeParamBuilder> typeParameters})
+    : _annotations = annotations,
+      _documentationComment = documentationComment,
+      _name = name,
+      _nameOffset = nameOffset,
+      _parameters = parameters,
+      _returnType = returnType,
+      _typeParameters = typeParameters;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_documentationComment;
+    fb.Offset offset_name;
+    fb.Offset offset_parameters;
+    fb.Offset offset_returnType;
+    fb.Offset offset_typeParameters;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_documentationComment != null) {
+      offset_documentationComment = _documentationComment.finish(fbBuilder);
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    if (!(_parameters == null || _parameters.isEmpty)) {
+      offset_parameters = fbBuilder.writeList(_parameters.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_returnType != null) {
+      offset_returnType = _returnType.finish(fbBuilder);
+    }
+    if (!(_typeParameters == null || _typeParameters.isEmpty)) {
+      offset_typeParameters = fbBuilder.writeList(_typeParameters.map((b) => b.finish(fbBuilder)).toList());
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(4, offset_annotations);
+    }
+    if (offset_documentationComment != null) {
+      fbBuilder.addOffset(6, offset_documentationComment);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(1, _nameOffset);
+    }
+    if (offset_parameters != null) {
+      fbBuilder.addOffset(3, offset_parameters);
+    }
+    if (offset_returnType != null) {
+      fbBuilder.addOffset(2, offset_returnType);
+    }
+    if (offset_typeParameters != null) {
+      fbBuilder.addOffset(5, offset_typeParameters);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedTypedefReader extends fb.TableReader<_UnlinkedTypedefImpl> {
+  const _UnlinkedTypedefReader();
+
+  @override
+  _UnlinkedTypedefImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypedefImpl(bp);
+}
+
+class _UnlinkedTypedefImpl extends Object with _UnlinkedTypedefMixin implements idl.UnlinkedTypedef {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedTypedefImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  idl.UnlinkedDocumentationComment _documentationComment;
+  String _name;
+  int _nameOffset;
+  List<idl.UnlinkedParam> _parameters;
+  idl.EntityRef _returnType;
+  List<idl.UnlinkedTypeParam> _typeParameters;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 4, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 6, null);
+    return _documentationComment;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _nameOffset;
+  }
+
+  @override
+  List<idl.UnlinkedParam> get parameters {
+    _parameters ??= const fb.ListReader<idl.UnlinkedParam>(const _UnlinkedParamReader()).vTableGet(_bp, 3, const <idl.UnlinkedParam>[]);
+    return _parameters;
+  }
+
+  @override
+  idl.EntityRef get returnType {
+    _returnType ??= const _EntityRefReader().vTableGet(_bp, 2, null);
+    return _returnType;
+  }
+
+  @override
+  List<idl.UnlinkedTypeParam> get typeParameters {
+    _typeParameters ??= const fb.ListReader<idl.UnlinkedTypeParam>(const _UnlinkedTypeParamReader()).vTableGet(_bp, 5, const <idl.UnlinkedTypeParam>[]);
+    return _typeParameters;
+  }
+}
+
+abstract class _UnlinkedTypedefMixin implements idl.UnlinkedTypedef {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (documentationComment != null) _result["documentationComment"] = documentationComment.toJson();
+    if (name != '') _result["name"] = name;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    if (parameters.isNotEmpty) _result["parameters"] = parameters.map((_value) => _value.toJson()).toList();
+    if (returnType != null) _result["returnType"] = returnType.toJson();
+    if (typeParameters.isNotEmpty) _result["typeParameters"] = typeParameters.map((_value) => _value.toJson()).toList();
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "documentationComment": documentationComment,
+    "name": name,
+    "nameOffset": nameOffset,
+    "parameters": parameters,
+    "returnType": returnType,
+    "typeParameters": typeParameters,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedTypeParamBuilder extends Object with _UnlinkedTypeParamMixin implements idl.UnlinkedTypeParam {
+  bool _finished = false;
+
+  List<UnlinkedConstBuilder> _annotations;
+  EntityRefBuilder _bound;
+  String _name;
+  int _nameOffset;
+
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for this type parameter.
+   */
+  void set annotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _annotations = _value;
+  }
+
+  @override
+  EntityRefBuilder get bound => _bound;
+
+  /**
+   * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
+   * null.
+   */
+  void set bound(EntityRefBuilder _value) {
+    assert(!_finished);
+    _bound = _value;
+  }
+
+  @override
+  String get name => _name ??= '';
+
+  /**
+   * Name of the type parameter.
+   */
+  void set name(String _value) {
+    assert(!_finished);
+    _name = _value;
+  }
+
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
+  /**
+   * Offset of the type parameter name relative to the beginning of the file.
+   */
+  void set nameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
+  }
+
+  UnlinkedTypeParamBuilder({List<UnlinkedConstBuilder> annotations, EntityRefBuilder bound, String name, int nameOffset})
+    : _annotations = annotations,
+      _bound = bound,
+      _name = name,
+      _nameOffset = nameOffset;
+
+  fb.Offset finish(fb.Builder fbBuilder) {
+    assert(!_finished);
+    _finished = true;
+    fb.Offset offset_annotations;
+    fb.Offset offset_bound;
+    fb.Offset offset_name;
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_bound != null) {
+      offset_bound = _bound.finish(fbBuilder);
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
+    fbBuilder.startTable();
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(3, offset_annotations);
+    }
+    if (offset_bound != null) {
+      fbBuilder.addOffset(2, offset_bound);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(1, _nameOffset);
+    }
+    return fbBuilder.endTable();
+  }
+}
+
+class _UnlinkedTypeParamReader extends fb.TableReader<_UnlinkedTypeParamImpl> {
+  const _UnlinkedTypeParamReader();
+
+  @override
+  _UnlinkedTypeParamImpl createObject(fb.BufferPointer bp) => new _UnlinkedTypeParamImpl(bp);
+}
+
+class _UnlinkedTypeParamImpl extends Object with _UnlinkedTypeParamMixin implements idl.UnlinkedTypeParam {
+  final fb.BufferPointer _bp;
+
+  _UnlinkedTypeParamImpl(this._bp);
+
+  List<idl.UnlinkedConst> _annotations;
+  idl.EntityRef _bound;
+  String _name;
+  int _nameOffset;
+
+  @override
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 3, const <idl.UnlinkedConst>[]);
+    return _annotations;
+  }
+
+  @override
+  idl.EntityRef get bound {
+    _bound ??= const _EntityRefReader().vTableGet(_bp, 2, null);
+    return _bound;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _nameOffset;
+  }
+}
+
+abstract class _UnlinkedTypeParamMixin implements idl.UnlinkedTypeParam {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (bound != null) _result["bound"] = bound.toJson();
+    if (name != '') _result["name"] = name;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "bound": bound,
+    "name": name,
+    "nameOffset": nameOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
+}
+
+class UnlinkedUnitBuilder extends Object with _UnlinkedUnitMixin implements idl.UnlinkedUnit {
+  bool _finished = false;
+
   List<UnlinkedClassBuilder> _classes;
   List<UnlinkedEnumBuilder> _enums;
   List<UnlinkedExecutableBuilder> _executables;
   List<UnlinkedExportNonPublicBuilder> _exports;
   List<UnlinkedImportBuilder> _imports;
+  List<UnlinkedConstBuilder> _libraryAnnotations;
+  UnlinkedDocumentationCommentBuilder _libraryDocumentationComment;
+  String _libraryName;
+  int _libraryNameLength;
+  int _libraryNameOffset;
   List<UnlinkedPartBuilder> _parts;
+  UnlinkedPublicNamespaceBuilder _publicNamespace;
+  List<UnlinkedReferenceBuilder> _references;
   List<UnlinkedTypedefBuilder> _typedefs;
   List<UnlinkedVariableBuilder> _variables;
 
-  UnlinkedUnitBuilder();
-
-  /**
-   * Name of the library (from a "library" declaration, if present).
-   */
-  void set libraryName(String _value) {
-    assert(!_finished);
-    _libraryName = _value;
-  }
-
-  /**
-   * Offset of the library name relative to the beginning of the file (or 0 if
-   * the library has no name).
-   */
-  void set libraryNameOffset(int _value) {
-    assert(!_finished);
-    _libraryNameOffset = _value;
-  }
-
-  /**
-   * Length of the library name as it appears in the source code (or 0 if the
-   * library has no name).
-   */
-  void set libraryNameLength(int _value) {
-    assert(!_finished);
-    _libraryNameLength = _value;
-  }
-
-  /**
-   * Documentation comment for the library, or `null` if there is no
-   * documentation comment.
-   */
-  void set libraryDocumentationComment(UnlinkedDocumentationCommentBuilder _value) {
-    assert(!_finished);
-    _libraryDocumentationComment = _value;
-  }
-
-  /**
-   * Unlinked public namespace of this compilation unit.
-   */
-  void set publicNamespace(UnlinkedPublicNamespaceBuilder _value) {
-    assert(!_finished);
-    _publicNamespace = _value;
-  }
-
-  /**
-   * Top level and prefixed names referred to by this compilation unit.  The
-   * zeroth element of this array is always populated and always represents a
-   * reference to the pseudo-type "dynamic".
-   */
-  void set references(List<UnlinkedReferenceBuilder> _value) {
-    assert(!_finished);
-    _references = _value;
-  }
+  @override
+  List<UnlinkedClassBuilder> get classes => _classes ??= <UnlinkedClassBuilder>[];
 
   /**
    * Classes declared in the compilation unit.
@@ -3999,6 +6432,9 @@
     _classes = _value;
   }
 
+  @override
+  List<UnlinkedEnumBuilder> get enums => _enums ??= <UnlinkedEnumBuilder>[];
+
   /**
    * Enums declared in the compilation unit.
    */
@@ -4007,6 +6443,9 @@
     _enums = _value;
   }
 
+  @override
+  List<UnlinkedExecutableBuilder> get executables => _executables ??= <UnlinkedExecutableBuilder>[];
+
   /**
    * Top level executable objects (functions, getters, and setters) declared in
    * the compilation unit.
@@ -4016,6 +6455,9 @@
     _executables = _value;
   }
 
+  @override
+  List<UnlinkedExportNonPublicBuilder> get exports => _exports ??= <UnlinkedExportNonPublicBuilder>[];
+
   /**
    * Export declarations in the compilation unit.
    */
@@ -4024,6 +6466,9 @@
     _exports = _value;
   }
 
+  @override
+  List<UnlinkedImportBuilder> get imports => _imports ??= <UnlinkedImportBuilder>[];
+
   /**
    * Import declarations in the compilation unit.
    */
@@ -4032,6 +6477,70 @@
     _imports = _value;
   }
 
+  @override
+  List<UnlinkedConstBuilder> get libraryAnnotations => _libraryAnnotations ??= <UnlinkedConstBuilder>[];
+
+  /**
+   * Annotations for the library declaration, or the empty list if there is no
+   * library declaration.
+   */
+  void set libraryAnnotations(List<UnlinkedConstBuilder> _value) {
+    assert(!_finished);
+    _libraryAnnotations = _value;
+  }
+
+  @override
+  UnlinkedDocumentationCommentBuilder get libraryDocumentationComment => _libraryDocumentationComment;
+
+  /**
+   * Documentation comment for the library, or `null` if there is no
+   * documentation comment.
+   */
+  void set libraryDocumentationComment(UnlinkedDocumentationCommentBuilder _value) {
+    assert(!_finished);
+    _libraryDocumentationComment = _value;
+  }
+
+  @override
+  String get libraryName => _libraryName ??= '';
+
+  /**
+   * Name of the library (from a "library" declaration, if present).
+   */
+  void set libraryName(String _value) {
+    assert(!_finished);
+    _libraryName = _value;
+  }
+
+  @override
+  int get libraryNameLength => _libraryNameLength ??= 0;
+
+  /**
+   * Length of the library name as it appears in the source code (or 0 if the
+   * library has no name).
+   */
+  void set libraryNameLength(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _libraryNameLength = _value;
+  }
+
+  @override
+  int get libraryNameOffset => _libraryNameOffset ??= 0;
+
+  /**
+   * Offset of the library name relative to the beginning of the file (or 0 if
+   * the library has no name).
+   */
+  void set libraryNameOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _libraryNameOffset = _value;
+  }
+
+  @override
+  List<UnlinkedPartBuilder> get parts => _parts ??= <UnlinkedPartBuilder>[];
+
   /**
    * Part declarations in the compilation unit.
    */
@@ -4040,6 +6549,35 @@
     _parts = _value;
   }
 
+  @override
+  UnlinkedPublicNamespaceBuilder get publicNamespace => _publicNamespace;
+
+  /**
+   * Unlinked public namespace of this compilation unit.
+   */
+  void set publicNamespace(UnlinkedPublicNamespaceBuilder _value) {
+    assert(!_finished);
+    _publicNamespace = _value;
+  }
+
+  @override
+  List<UnlinkedReferenceBuilder> get references => _references ??= <UnlinkedReferenceBuilder>[];
+
+  /**
+   * 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]).
+   */
+  void set references(List<UnlinkedReferenceBuilder> _value) {
+    assert(!_finished);
+    _references = _value;
+  }
+
+  @override
+  List<UnlinkedTypedefBuilder> get typedefs => _typedefs ??= <UnlinkedTypedefBuilder>[];
+
   /**
    * Typedefs declared in the compilation unit.
    */
@@ -4048,6 +6586,9 @@
     _typedefs = _value;
   }
 
+  @override
+  List<UnlinkedVariableBuilder> get variables => _variables ??= <UnlinkedVariableBuilder>[];
+
   /**
    * Top level variables declared in the compilation unit.
    */
@@ -4056,38 +6597,44 @@
     _variables = _value;
   }
 
+  UnlinkedUnitBuilder({List<UnlinkedClassBuilder> classes, List<UnlinkedEnumBuilder> enums, List<UnlinkedExecutableBuilder> executables, List<UnlinkedExportNonPublicBuilder> exports, List<UnlinkedImportBuilder> imports, List<UnlinkedConstBuilder> libraryAnnotations, UnlinkedDocumentationCommentBuilder libraryDocumentationComment, String libraryName, int libraryNameLength, int libraryNameOffset, List<UnlinkedPartBuilder> parts, UnlinkedPublicNamespaceBuilder publicNamespace, List<UnlinkedReferenceBuilder> references, List<UnlinkedTypedefBuilder> typedefs, List<UnlinkedVariableBuilder> variables})
+    : _classes = classes,
+      _enums = enums,
+      _executables = executables,
+      _exports = exports,
+      _imports = imports,
+      _libraryAnnotations = libraryAnnotations,
+      _libraryDocumentationComment = libraryDocumentationComment,
+      _libraryName = libraryName,
+      _libraryNameLength = libraryNameLength,
+      _libraryNameOffset = libraryNameOffset,
+      _parts = parts,
+      _publicNamespace = publicNamespace,
+      _references = references,
+      _typedefs = typedefs,
+      _variables = variables;
+
   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) {
     assert(!_finished);
     _finished = true;
-    fb.Offset offset_libraryName;
-    fb.Offset offset_libraryDocumentationComment;
-    fb.Offset offset_publicNamespace;
-    fb.Offset offset_references;
     fb.Offset offset_classes;
     fb.Offset offset_enums;
     fb.Offset offset_executables;
     fb.Offset offset_exports;
     fb.Offset offset_imports;
+    fb.Offset offset_libraryAnnotations;
+    fb.Offset offset_libraryDocumentationComment;
+    fb.Offset offset_libraryName;
     fb.Offset offset_parts;
+    fb.Offset offset_publicNamespace;
+    fb.Offset offset_references;
     fb.Offset offset_typedefs;
     fb.Offset offset_variables;
-    if (_libraryName != null) {
-      offset_libraryName = fbBuilder.writeString(_libraryName);
-    }
-    if (_libraryDocumentationComment != null) {
-      offset_libraryDocumentationComment = _libraryDocumentationComment.finish(fbBuilder);
-    }
-    if (_publicNamespace != null) {
-      offset_publicNamespace = _publicNamespace.finish(fbBuilder);
-    }
-    if (!(_references == null || _references.isEmpty)) {
-      offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
-    }
     if (!(_classes == null || _classes.isEmpty)) {
       offset_classes = fbBuilder.writeList(_classes.map((b) => b.finish(fbBuilder)).toList());
     }
@@ -4103,9 +6650,24 @@
     if (!(_imports == null || _imports.isEmpty)) {
       offset_imports = fbBuilder.writeList(_imports.map((b) => b.finish(fbBuilder)).toList());
     }
+    if (!(_libraryAnnotations == null || _libraryAnnotations.isEmpty)) {
+      offset_libraryAnnotations = fbBuilder.writeList(_libraryAnnotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_libraryDocumentationComment != null) {
+      offset_libraryDocumentationComment = _libraryDocumentationComment.finish(fbBuilder);
+    }
+    if (_libraryName != null) {
+      offset_libraryName = fbBuilder.writeString(_libraryName);
+    }
     if (!(_parts == null || _parts.isEmpty)) {
       offset_parts = fbBuilder.writeList(_parts.map((b) => b.finish(fbBuilder)).toList());
     }
+    if (_publicNamespace != null) {
+      offset_publicNamespace = _publicNamespace.finish(fbBuilder);
+    }
+    if (!(_references == null || _references.isEmpty)) {
+      offset_references = fbBuilder.writeList(_references.map((b) => b.finish(fbBuilder)).toList());
+    }
     if (!(_typedefs == null || _typedefs.isEmpty)) {
       offset_typedefs = fbBuilder.writeList(_typedefs.map((b) => b.finish(fbBuilder)).toList());
     }
@@ -4113,155 +6675,58 @@
       offset_variables = fbBuilder.writeList(_variables.map((b) => b.finish(fbBuilder)).toList());
     }
     fbBuilder.startTable();
-    if (offset_libraryName != null) {
-      fbBuilder.addOffset(0, offset_libraryName);
-    }
-    if (_libraryNameOffset != null && _libraryNameOffset != 0) {
-      fbBuilder.addInt32(1, _libraryNameOffset);
-    }
-    if (_libraryNameLength != null && _libraryNameLength != 0) {
-      fbBuilder.addInt32(2, _libraryNameLength);
-    }
-    if (offset_libraryDocumentationComment != null) {
-      fbBuilder.addOffset(3, offset_libraryDocumentationComment);
-    }
-    if (offset_publicNamespace != null) {
-      fbBuilder.addOffset(4, offset_publicNamespace);
-    }
-    if (offset_references != null) {
-      fbBuilder.addOffset(5, offset_references);
-    }
     if (offset_classes != null) {
-      fbBuilder.addOffset(6, offset_classes);
+      fbBuilder.addOffset(2, offset_classes);
     }
     if (offset_enums != null) {
-      fbBuilder.addOffset(7, offset_enums);
+      fbBuilder.addOffset(12, offset_enums);
     }
     if (offset_executables != null) {
-      fbBuilder.addOffset(8, offset_executables);
+      fbBuilder.addOffset(4, offset_executables);
     }
     if (offset_exports != null) {
-      fbBuilder.addOffset(9, offset_exports);
+      fbBuilder.addOffset(13, offset_exports);
     }
     if (offset_imports != null) {
-      fbBuilder.addOffset(10, offset_imports);
+      fbBuilder.addOffset(5, offset_imports);
+    }
+    if (offset_libraryAnnotations != null) {
+      fbBuilder.addOffset(14, offset_libraryAnnotations);
+    }
+    if (offset_libraryDocumentationComment != null) {
+      fbBuilder.addOffset(9, offset_libraryDocumentationComment);
+    }
+    if (offset_libraryName != null) {
+      fbBuilder.addOffset(6, offset_libraryName);
+    }
+    if (_libraryNameLength != null && _libraryNameLength != 0) {
+      fbBuilder.addUint32(7, _libraryNameLength);
+    }
+    if (_libraryNameOffset != null && _libraryNameOffset != 0) {
+      fbBuilder.addUint32(8, _libraryNameOffset);
     }
     if (offset_parts != null) {
       fbBuilder.addOffset(11, offset_parts);
     }
+    if (offset_publicNamespace != null) {
+      fbBuilder.addOffset(0, offset_publicNamespace);
+    }
+    if (offset_references != null) {
+      fbBuilder.addOffset(1, offset_references);
+    }
     if (offset_typedefs != null) {
-      fbBuilder.addOffset(12, offset_typedefs);
+      fbBuilder.addOffset(10, offset_typedefs);
     }
     if (offset_variables != null) {
-      fbBuilder.addOffset(13, offset_variables);
+      fbBuilder.addOffset(3, offset_variables);
     }
     return fbBuilder.endTable();
   }
 }
 
-UnlinkedUnitBuilder encodeUnlinkedUnit({String libraryName, int libraryNameOffset, int libraryNameLength, UnlinkedDocumentationCommentBuilder libraryDocumentationComment, UnlinkedPublicNamespaceBuilder publicNamespace, List<UnlinkedReferenceBuilder> references, List<UnlinkedClassBuilder> classes, List<UnlinkedEnumBuilder> enums, List<UnlinkedExecutableBuilder> executables, List<UnlinkedExportNonPublicBuilder> exports, List<UnlinkedImportBuilder> imports, List<UnlinkedPartBuilder> parts, List<UnlinkedTypedefBuilder> typedefs, List<UnlinkedVariableBuilder> variables}) {
-  UnlinkedUnitBuilder builder = new UnlinkedUnitBuilder();
-  builder.libraryName = libraryName;
-  builder.libraryNameOffset = libraryNameOffset;
-  builder.libraryNameLength = libraryNameLength;
-  builder.libraryDocumentationComment = libraryDocumentationComment;
-  builder.publicNamespace = publicNamespace;
-  builder.references = references;
-  builder.classes = classes;
-  builder.enums = enums;
-  builder.executables = executables;
-  builder.exports = exports;
-  builder.imports = imports;
-  builder.parts = parts;
-  builder.typedefs = typedefs;
-  builder.variables = variables;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a compilation unit ("part file").
- */
-abstract class UnlinkedUnit extends base.SummaryClass {
-  factory UnlinkedUnit.fromBuffer(List<int> buffer) {
-    fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
-    return const _UnlinkedUnitReader().read(rootRef);
-  }
-
-  /**
-   * Name of the library (from a "library" declaration, if present).
-   */
-  String get libraryName;
-
-  /**
-   * Offset of the library name relative to the beginning of the file (or 0 if
-   * the library has no name).
-   */
-  int get libraryNameOffset;
-
-  /**
-   * Length of the library name as it appears in the source code (or 0 if the
-   * library has no name).
-   */
-  int get libraryNameLength;
-
-  /**
-   * Documentation comment for the library, or `null` if there is no
-   * documentation comment.
-   */
-  UnlinkedDocumentationComment get libraryDocumentationComment;
-
-  /**
-   * Unlinked public namespace of this compilation unit.
-   */
-  UnlinkedPublicNamespace get publicNamespace;
-
-  /**
-   * Top level and prefixed names referred to by this compilation unit.  The
-   * zeroth element of this array is always populated and always represents a
-   * reference to the pseudo-type "dynamic".
-   */
-  List<UnlinkedReference> get references;
-
-  /**
-   * Classes declared in the compilation unit.
-   */
-  List<UnlinkedClass> get classes;
-
-  /**
-   * Enums declared in the compilation unit.
-   */
-  List<UnlinkedEnum> get enums;
-
-  /**
-   * Top level executable objects (functions, getters, and setters) declared in
-   * the compilation unit.
-   */
-  List<UnlinkedExecutable> get executables;
-
-  /**
-   * Export declarations in the compilation unit.
-   */
-  List<UnlinkedExportNonPublic> get exports;
-
-  /**
-   * Import declarations in the compilation unit.
-   */
-  List<UnlinkedImport> get imports;
-
-  /**
-   * Part declarations in the compilation unit.
-   */
-  List<UnlinkedPart> get parts;
-
-  /**
-   * Typedefs declared in the compilation unit.
-   */
-  List<UnlinkedTypedef> get typedefs;
-
-  /**
-   * Top level variables declared in the compilation unit.
-   */
-  List<UnlinkedVariable> get variables;
+idl.UnlinkedUnit readUnlinkedUnit(List<int> buffer) {
+  fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);
+  return const _UnlinkedUnitReader().read(rootRef);
 }
 
 class _UnlinkedUnitReader extends fb.TableReader<_UnlinkedUnitImpl> {
@@ -4271,159 +6736,208 @@
   _UnlinkedUnitImpl createObject(fb.BufferPointer bp) => new _UnlinkedUnitImpl(bp);
 }
 
-class _UnlinkedUnitImpl implements UnlinkedUnit {
+class _UnlinkedUnitImpl extends Object with _UnlinkedUnitMixin implements idl.UnlinkedUnit {
   final fb.BufferPointer _bp;
 
   _UnlinkedUnitImpl(this._bp);
 
+  List<idl.UnlinkedClass> _classes;
+  List<idl.UnlinkedEnum> _enums;
+  List<idl.UnlinkedExecutable> _executables;
+  List<idl.UnlinkedExportNonPublic> _exports;
+  List<idl.UnlinkedImport> _imports;
+  List<idl.UnlinkedConst> _libraryAnnotations;
+  idl.UnlinkedDocumentationComment _libraryDocumentationComment;
   String _libraryName;
-  int _libraryNameOffset;
   int _libraryNameLength;
-  UnlinkedDocumentationComment _libraryDocumentationComment;
-  UnlinkedPublicNamespace _publicNamespace;
-  List<UnlinkedReference> _references;
-  List<UnlinkedClass> _classes;
-  List<UnlinkedEnum> _enums;
-  List<UnlinkedExecutable> _executables;
-  List<UnlinkedExportNonPublic> _exports;
-  List<UnlinkedImport> _imports;
-  List<UnlinkedPart> _parts;
-  List<UnlinkedTypedef> _typedefs;
-  List<UnlinkedVariable> _variables;
+  int _libraryNameOffset;
+  List<idl.UnlinkedPart> _parts;
+  idl.UnlinkedPublicNamespace _publicNamespace;
+  List<idl.UnlinkedReference> _references;
+  List<idl.UnlinkedTypedef> _typedefs;
+  List<idl.UnlinkedVariable> _variables;
+
+  @override
+  List<idl.UnlinkedClass> get classes {
+    _classes ??= const fb.ListReader<idl.UnlinkedClass>(const _UnlinkedClassReader()).vTableGet(_bp, 2, const <idl.UnlinkedClass>[]);
+    return _classes;
+  }
+
+  @override
+  List<idl.UnlinkedEnum> get enums {
+    _enums ??= const fb.ListReader<idl.UnlinkedEnum>(const _UnlinkedEnumReader()).vTableGet(_bp, 12, const <idl.UnlinkedEnum>[]);
+    return _enums;
+  }
+
+  @override
+  List<idl.UnlinkedExecutable> get executables {
+    _executables ??= const fb.ListReader<idl.UnlinkedExecutable>(const _UnlinkedExecutableReader()).vTableGet(_bp, 4, const <idl.UnlinkedExecutable>[]);
+    return _executables;
+  }
+
+  @override
+  List<idl.UnlinkedExportNonPublic> get exports {
+    _exports ??= const fb.ListReader<idl.UnlinkedExportNonPublic>(const _UnlinkedExportNonPublicReader()).vTableGet(_bp, 13, const <idl.UnlinkedExportNonPublic>[]);
+    return _exports;
+  }
+
+  @override
+  List<idl.UnlinkedImport> get imports {
+    _imports ??= const fb.ListReader<idl.UnlinkedImport>(const _UnlinkedImportReader()).vTableGet(_bp, 5, const <idl.UnlinkedImport>[]);
+    return _imports;
+  }
+
+  @override
+  List<idl.UnlinkedConst> get libraryAnnotations {
+    _libraryAnnotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 14, const <idl.UnlinkedConst>[]);
+    return _libraryAnnotations;
+  }
+
+  @override
+  idl.UnlinkedDocumentationComment get libraryDocumentationComment {
+    _libraryDocumentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 9, null);
+    return _libraryDocumentationComment;
+  }
+
+  @override
+  String get libraryName {
+    _libraryName ??= const fb.StringReader().vTableGet(_bp, 6, '');
+    return _libraryName;
+  }
+
+  @override
+  int get libraryNameLength {
+    _libraryNameLength ??= const fb.Uint32Reader().vTableGet(_bp, 7, 0);
+    return _libraryNameLength;
+  }
+
+  @override
+  int get libraryNameOffset {
+    _libraryNameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 8, 0);
+    return _libraryNameOffset;
+  }
+
+  @override
+  List<idl.UnlinkedPart> get parts {
+    _parts ??= const fb.ListReader<idl.UnlinkedPart>(const _UnlinkedPartReader()).vTableGet(_bp, 11, const <idl.UnlinkedPart>[]);
+    return _parts;
+  }
+
+  @override
+  idl.UnlinkedPublicNamespace get publicNamespace {
+    _publicNamespace ??= const _UnlinkedPublicNamespaceReader().vTableGet(_bp, 0, null);
+    return _publicNamespace;
+  }
+
+  @override
+  List<idl.UnlinkedReference> get references {
+    _references ??= const fb.ListReader<idl.UnlinkedReference>(const _UnlinkedReferenceReader()).vTableGet(_bp, 1, const <idl.UnlinkedReference>[]);
+    return _references;
+  }
+
+  @override
+  List<idl.UnlinkedTypedef> get typedefs {
+    _typedefs ??= const fb.ListReader<idl.UnlinkedTypedef>(const _UnlinkedTypedefReader()).vTableGet(_bp, 10, const <idl.UnlinkedTypedef>[]);
+    return _typedefs;
+  }
+
+  @override
+  List<idl.UnlinkedVariable> get variables {
+    _variables ??= const fb.ListReader<idl.UnlinkedVariable>(const _UnlinkedVariableReader()).vTableGet(_bp, 3, const <idl.UnlinkedVariable>[]);
+    return _variables;
+  }
+}
+
+abstract class _UnlinkedUnitMixin implements idl.UnlinkedUnit {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (classes.isNotEmpty) _result["classes"] = classes.map((_value) => _value.toJson()).toList();
+    if (enums.isNotEmpty) _result["enums"] = enums.map((_value) => _value.toJson()).toList();
+    if (executables.isNotEmpty) _result["executables"] = executables.map((_value) => _value.toJson()).toList();
+    if (exports.isNotEmpty) _result["exports"] = exports.map((_value) => _value.toJson()).toList();
+    if (imports.isNotEmpty) _result["imports"] = imports.map((_value) => _value.toJson()).toList();
+    if (libraryAnnotations.isNotEmpty) _result["libraryAnnotations"] = libraryAnnotations.map((_value) => _value.toJson()).toList();
+    if (libraryDocumentationComment != null) _result["libraryDocumentationComment"] = libraryDocumentationComment.toJson();
+    if (libraryName != '') _result["libraryName"] = libraryName;
+    if (libraryNameLength != 0) _result["libraryNameLength"] = libraryNameLength;
+    if (libraryNameOffset != 0) _result["libraryNameOffset"] = libraryNameOffset;
+    if (parts.isNotEmpty) _result["parts"] = parts.map((_value) => _value.toJson()).toList();
+    if (publicNamespace != null) _result["publicNamespace"] = publicNamespace.toJson();
+    if (references.isNotEmpty) _result["references"] = references.map((_value) => _value.toJson()).toList();
+    if (typedefs.isNotEmpty) _result["typedefs"] = typedefs.map((_value) => _value.toJson()).toList();
+    if (variables.isNotEmpty) _result["variables"] = variables.map((_value) => _value.toJson()).toList();
+    return _result;
+  }
 
   @override
   Map<String, Object> toMap() => {
-    "libraryName": libraryName,
-    "libraryNameOffset": libraryNameOffset,
-    "libraryNameLength": libraryNameLength,
-    "libraryDocumentationComment": libraryDocumentationComment,
-    "publicNamespace": publicNamespace,
-    "references": references,
     "classes": classes,
     "enums": enums,
     "executables": executables,
     "exports": exports,
     "imports": imports,
+    "libraryAnnotations": libraryAnnotations,
+    "libraryDocumentationComment": libraryDocumentationComment,
+    "libraryName": libraryName,
+    "libraryNameLength": libraryNameLength,
+    "libraryNameOffset": libraryNameOffset,
     "parts": parts,
+    "publicNamespace": publicNamespace,
+    "references": references,
     "typedefs": typedefs,
     "variables": variables,
   };
 
   @override
-  String get libraryName {
-    _libraryName ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _libraryName;
-  }
-
-  @override
-  int get libraryNameOffset {
-    _libraryNameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _libraryNameOffset;
-  }
-
-  @override
-  int get libraryNameLength {
-    _libraryNameLength ??= const fb.Int32Reader().vTableGet(_bp, 2, 0);
-    return _libraryNameLength;
-  }
-
-  @override
-  UnlinkedDocumentationComment get libraryDocumentationComment {
-    _libraryDocumentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 3, null);
-    return _libraryDocumentationComment;
-  }
-
-  @override
-  UnlinkedPublicNamespace get publicNamespace {
-    _publicNamespace ??= const _UnlinkedPublicNamespaceReader().vTableGet(_bp, 4, null);
-    return _publicNamespace;
-  }
-
-  @override
-  List<UnlinkedReference> get references {
-    _references ??= const fb.ListReader<UnlinkedReference>(const _UnlinkedReferenceReader()).vTableGet(_bp, 5, const <UnlinkedReference>[]);
-    return _references;
-  }
-
-  @override
-  List<UnlinkedClass> get classes {
-    _classes ??= const fb.ListReader<UnlinkedClass>(const _UnlinkedClassReader()).vTableGet(_bp, 6, const <UnlinkedClass>[]);
-    return _classes;
-  }
-
-  @override
-  List<UnlinkedEnum> get enums {
-    _enums ??= const fb.ListReader<UnlinkedEnum>(const _UnlinkedEnumReader()).vTableGet(_bp, 7, const <UnlinkedEnum>[]);
-    return _enums;
-  }
-
-  @override
-  List<UnlinkedExecutable> get executables {
-    _executables ??= const fb.ListReader<UnlinkedExecutable>(const _UnlinkedExecutableReader()).vTableGet(_bp, 8, const <UnlinkedExecutable>[]);
-    return _executables;
-  }
-
-  @override
-  List<UnlinkedExportNonPublic> get exports {
-    _exports ??= const fb.ListReader<UnlinkedExportNonPublic>(const _UnlinkedExportNonPublicReader()).vTableGet(_bp, 9, const <UnlinkedExportNonPublic>[]);
-    return _exports;
-  }
-
-  @override
-  List<UnlinkedImport> get imports {
-    _imports ??= const fb.ListReader<UnlinkedImport>(const _UnlinkedImportReader()).vTableGet(_bp, 10, const <UnlinkedImport>[]);
-    return _imports;
-  }
-
-  @override
-  List<UnlinkedPart> get parts {
-    _parts ??= const fb.ListReader<UnlinkedPart>(const _UnlinkedPartReader()).vTableGet(_bp, 11, const <UnlinkedPart>[]);
-    return _parts;
-  }
-
-  @override
-  List<UnlinkedTypedef> get typedefs {
-    _typedefs ??= const fb.ListReader<UnlinkedTypedef>(const _UnlinkedTypedefReader()).vTableGet(_bp, 12, const <UnlinkedTypedef>[]);
-    return _typedefs;
-  }
-
-  @override
-  List<UnlinkedVariable> get variables {
-    _variables ??= const fb.ListReader<UnlinkedVariable>(const _UnlinkedVariableReader()).vTableGet(_bp, 13, const <UnlinkedVariable>[]);
-    return _variables;
-  }
+  String toString() => convert.JSON.encode(toJson());
 }
 
-class UnlinkedVariableBuilder {
+class UnlinkedVariableBuilder extends Object with _UnlinkedVariableMixin implements idl.UnlinkedVariable {
   bool _finished = false;
 
+  List<UnlinkedConstBuilder> _annotations;
+  UnlinkedConstBuilder _constExpr;
+  UnlinkedDocumentationCommentBuilder _documentationComment;
+  int _inferredTypeSlot;
+  UnlinkedExecutableBuilder _initializer;
+  bool _isConst;
+  bool _isFinal;
+  bool _isStatic;
   String _name;
   int _nameOffset;
-  UnlinkedDocumentationCommentBuilder _documentationComment;
-  UnlinkedTypeRefBuilder _type;
-  bool _isStatic;
-  bool _isFinal;
-  bool _isConst;
-  bool _hasImplicitType;
+  int _propagatedTypeSlot;
+  EntityRefBuilder _type;
+  int _visibleLength;
+  int _visibleOffset;
 
-  UnlinkedVariableBuilder();
+  @override
+  List<UnlinkedConstBuilder> get annotations => _annotations ??= <UnlinkedConstBuilder>[];
 
   /**
-   * Name of the variable.
+   * Annotations for this variable.
    */
-  void set name(String _value) {
+  void set annotations(List<UnlinkedConstBuilder> _value) {
     assert(!_finished);
-    _name = _value;
+    _annotations = _value;
   }
 
+  @override
+  UnlinkedConstBuilder get constExpr => _constExpr;
+
   /**
-   * Offset of the variable name relative to the beginning of the file.
+   * 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].
    */
-  void set nameOffset(int _value) {
+  void set constExpr(UnlinkedConstBuilder _value) {
     assert(!_finished);
-    _nameOffset = _value;
+    _constExpr = _value;
   }
 
+  @override
+  UnlinkedDocumentationCommentBuilder get documentationComment => _documentationComment;
+
   /**
    * Documentation comment for the variable, or `null` if there is no
    * documentation comment.
@@ -4433,15 +6947,58 @@
     _documentationComment = _value;
   }
 
+  @override
+  int get inferredTypeSlot => _inferredTypeSlot ??= 0;
+
   /**
-   * Declared type of the variable.  Note that when strong mode is enabled, the
-   * actual type of the variable may be different due to type inference.
+   * 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`.
    */
-  void set type(UnlinkedTypeRefBuilder _value) {
+  void set inferredTypeSlot(int _value) {
     assert(!_finished);
-    _type = _value;
+    assert(_value == null || _value >= 0);
+    _inferredTypeSlot = _value;
   }
 
+  @override
+  UnlinkedExecutableBuilder get initializer => _initializer;
+
+  /**
+   * The synthetic initializer function of the variable.  Absent if the variable
+   * does not have an initializer.
+   */
+  void set initializer(UnlinkedExecutableBuilder _value) {
+    assert(!_finished);
+    _initializer = _value;
+  }
+
+  @override
+  bool get isConst => _isConst ??= false;
+
+  /**
+   * Indicates whether the variable is declared using the `const` keyword.
+   */
+  void set isConst(bool _value) {
+    assert(!_finished);
+    _isConst = _value;
+  }
+
+  @override
+  bool get isFinal => _isFinal ??= false;
+
+  /**
+   * Indicates whether the variable is declared using the `final` keyword.
+   */
+  void set isFinal(bool _value) {
+    assert(!_finished);
+    _isFinal = _value;
+  }
+
+  @override
+  bool get isStatic => _isStatic ??= false;
+
   /**
    * Indicates whether the variable is declared using the `static` keyword.
    *
@@ -4454,140 +7011,171 @@
     _isStatic = _value;
   }
 
-  /**
-   * Indicates whether the variable is declared using the `final` keyword.
-   */
-  void set isFinal(bool _value) {
-    assert(!_finished);
-    _isFinal = _value;
-  }
+  @override
+  String get name => _name ??= '';
 
   /**
-   * Indicates whether the variable is declared using the `const` keyword.
+   * Name of the variable.
    */
-  void set isConst(bool _value) {
+  void set name(String _value) {
     assert(!_finished);
-    _isConst = _value;
+    _name = _value;
   }
 
+  @override
+  int get nameOffset => _nameOffset ??= 0;
+
   /**
-   * Indicates whether this variable lacks an explicit type declaration.
+   * Offset of the variable name relative to the beginning of the file.
    */
-  void set hasImplicitType(bool _value) {
+  void set nameOffset(int _value) {
     assert(!_finished);
-    _hasImplicitType = _value;
+    assert(_value == null || _value >= 0);
+    _nameOffset = _value;
   }
 
+  @override
+  int get propagatedTypeSlot => _propagatedTypeSlot ??= 0;
+
+  /**
+   * 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.
+   */
+  void set propagatedTypeSlot(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _propagatedTypeSlot = _value;
+  }
+
+  @override
+  EntityRefBuilder get type => _type;
+
+  /**
+   * Declared type of the variable.  Absent if the type is implicit.
+   */
+  void set type(EntityRefBuilder _value) {
+    assert(!_finished);
+    _type = _value;
+  }
+
+  @override
+  int get visibleLength => _visibleLength ??= 0;
+
+  /**
+   * If a local variable, the length of the visible range; zero otherwise.
+   */
+  void set visibleLength(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _visibleLength = _value;
+  }
+
+  @override
+  int get visibleOffset => _visibleOffset ??= 0;
+
+  /**
+   * If a local variable, the beginning of the visible range; zero otherwise.
+   */
+  void set visibleOffset(int _value) {
+    assert(!_finished);
+    assert(_value == null || _value >= 0);
+    _visibleOffset = _value;
+  }
+
+  UnlinkedVariableBuilder({List<UnlinkedConstBuilder> annotations, UnlinkedConstBuilder constExpr, UnlinkedDocumentationCommentBuilder documentationComment, int inferredTypeSlot, UnlinkedExecutableBuilder initializer, bool isConst, bool isFinal, bool isStatic, String name, int nameOffset, int propagatedTypeSlot, EntityRefBuilder type, int visibleLength, int visibleOffset})
+    : _annotations = annotations,
+      _constExpr = constExpr,
+      _documentationComment = documentationComment,
+      _inferredTypeSlot = inferredTypeSlot,
+      _initializer = initializer,
+      _isConst = isConst,
+      _isFinal = isFinal,
+      _isStatic = isStatic,
+      _name = name,
+      _nameOffset = nameOffset,
+      _propagatedTypeSlot = propagatedTypeSlot,
+      _type = type,
+      _visibleLength = visibleLength,
+      _visibleOffset = visibleOffset;
+
   fb.Offset finish(fb.Builder fbBuilder) {
     assert(!_finished);
     _finished = true;
-    fb.Offset offset_name;
+    fb.Offset offset_annotations;
+    fb.Offset offset_constExpr;
     fb.Offset offset_documentationComment;
+    fb.Offset offset_initializer;
+    fb.Offset offset_name;
     fb.Offset offset_type;
-    if (_name != null) {
-      offset_name = fbBuilder.writeString(_name);
+    if (!(_annotations == null || _annotations.isEmpty)) {
+      offset_annotations = fbBuilder.writeList(_annotations.map((b) => b.finish(fbBuilder)).toList());
+    }
+    if (_constExpr != null) {
+      offset_constExpr = _constExpr.finish(fbBuilder);
     }
     if (_documentationComment != null) {
       offset_documentationComment = _documentationComment.finish(fbBuilder);
     }
+    if (_initializer != null) {
+      offset_initializer = _initializer.finish(fbBuilder);
+    }
+    if (_name != null) {
+      offset_name = fbBuilder.writeString(_name);
+    }
     if (_type != null) {
       offset_type = _type.finish(fbBuilder);
     }
     fbBuilder.startTable();
-    if (offset_name != null) {
-      fbBuilder.addOffset(0, offset_name);
+    if (offset_annotations != null) {
+      fbBuilder.addOffset(8, offset_annotations);
     }
-    if (_nameOffset != null && _nameOffset != 0) {
-      fbBuilder.addInt32(1, _nameOffset);
+    if (offset_constExpr != null) {
+      fbBuilder.addOffset(5, offset_constExpr);
     }
     if (offset_documentationComment != null) {
-      fbBuilder.addOffset(2, offset_documentationComment);
+      fbBuilder.addOffset(10, offset_documentationComment);
     }
-    if (offset_type != null) {
-      fbBuilder.addOffset(3, offset_type);
+    if (_inferredTypeSlot != null && _inferredTypeSlot != 0) {
+      fbBuilder.addUint32(9, _inferredTypeSlot);
     }
-    if (_isStatic == true) {
-      fbBuilder.addBool(4, true);
-    }
-    if (_isFinal == true) {
-      fbBuilder.addBool(5, true);
+    if (offset_initializer != null) {
+      fbBuilder.addOffset(13, offset_initializer);
     }
     if (_isConst == true) {
       fbBuilder.addBool(6, true);
     }
-    if (_hasImplicitType == true) {
+    if (_isFinal == true) {
       fbBuilder.addBool(7, true);
     }
+    if (_isStatic == true) {
+      fbBuilder.addBool(4, true);
+    }
+    if (offset_name != null) {
+      fbBuilder.addOffset(0, offset_name);
+    }
+    if (_nameOffset != null && _nameOffset != 0) {
+      fbBuilder.addUint32(1, _nameOffset);
+    }
+    if (_propagatedTypeSlot != null && _propagatedTypeSlot != 0) {
+      fbBuilder.addUint32(2, _propagatedTypeSlot);
+    }
+    if (offset_type != null) {
+      fbBuilder.addOffset(3, offset_type);
+    }
+    if (_visibleLength != null && _visibleLength != 0) {
+      fbBuilder.addUint32(11, _visibleLength);
+    }
+    if (_visibleOffset != null && _visibleOffset != 0) {
+      fbBuilder.addUint32(12, _visibleOffset);
+    }
     return fbBuilder.endTable();
   }
 }
 
-UnlinkedVariableBuilder encodeUnlinkedVariable({String name, int nameOffset, UnlinkedDocumentationCommentBuilder documentationComment, UnlinkedTypeRefBuilder type, bool isStatic, bool isFinal, bool isConst, bool hasImplicitType}) {
-  UnlinkedVariableBuilder builder = new UnlinkedVariableBuilder();
-  builder.name = name;
-  builder.nameOffset = nameOffset;
-  builder.documentationComment = documentationComment;
-  builder.type = type;
-  builder.isStatic = isStatic;
-  builder.isFinal = isFinal;
-  builder.isConst = isConst;
-  builder.hasImplicitType = hasImplicitType;
-  return builder;
-}
-
-/**
- * Unlinked summary information about a top level variable, local variable, or
- * a field.
- */
-abstract class UnlinkedVariable extends base.SummaryClass {
-
-  /**
-   * Name of the variable.
-   */
-  String get name;
-
-  /**
-   * Offset of the variable name relative to the beginning of the file.
-   */
-  int get nameOffset;
-
-  /**
-   * Documentation comment for the variable, or `null` if there is no
-   * documentation comment.
-   */
-  UnlinkedDocumentationComment get documentationComment;
-
-  /**
-   * Declared type of the variable.  Note that when strong mode is enabled, the
-   * actual type of the variable may be different due to type inference.
-   */
-  UnlinkedTypeRef get type;
-
-  /**
-   * 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).
-   */
-  bool get isStatic;
-
-  /**
-   * Indicates whether the variable is declared using the `final` keyword.
-   */
-  bool get isFinal;
-
-  /**
-   * Indicates whether the variable is declared using the `const` keyword.
-   */
-  bool get isConst;
-
-  /**
-   * Indicates whether this variable lacks an explicit type declaration.
-   */
-  bool get hasImplicitType;
-}
-
 class _UnlinkedVariableReader extends fb.TableReader<_UnlinkedVariableImpl> {
   const _UnlinkedVariableReader();
 
@@ -4595,66 +7183,54 @@
   _UnlinkedVariableImpl createObject(fb.BufferPointer bp) => new _UnlinkedVariableImpl(bp);
 }
 
-class _UnlinkedVariableImpl implements UnlinkedVariable {
+class _UnlinkedVariableImpl extends Object with _UnlinkedVariableMixin implements idl.UnlinkedVariable {
   final fb.BufferPointer _bp;
 
   _UnlinkedVariableImpl(this._bp);
 
+  List<idl.UnlinkedConst> _annotations;
+  idl.UnlinkedConst _constExpr;
+  idl.UnlinkedDocumentationComment _documentationComment;
+  int _inferredTypeSlot;
+  idl.UnlinkedExecutable _initializer;
+  bool _isConst;
+  bool _isFinal;
+  bool _isStatic;
   String _name;
   int _nameOffset;
-  UnlinkedDocumentationComment _documentationComment;
-  UnlinkedTypeRef _type;
-  bool _isStatic;
-  bool _isFinal;
-  bool _isConst;
-  bool _hasImplicitType;
+  int _propagatedTypeSlot;
+  idl.EntityRef _type;
+  int _visibleLength;
+  int _visibleOffset;
 
   @override
-  Map<String, Object> toMap() => {
-    "name": name,
-    "nameOffset": nameOffset,
-    "documentationComment": documentationComment,
-    "type": type,
-    "isStatic": isStatic,
-    "isFinal": isFinal,
-    "isConst": isConst,
-    "hasImplicitType": hasImplicitType,
-  };
-
-  @override
-  String get name {
-    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
-    return _name;
+  List<idl.UnlinkedConst> get annotations {
+    _annotations ??= const fb.ListReader<idl.UnlinkedConst>(const _UnlinkedConstReader()).vTableGet(_bp, 8, const <idl.UnlinkedConst>[]);
+    return _annotations;
   }
 
   @override
-  int get nameOffset {
-    _nameOffset ??= const fb.Int32Reader().vTableGet(_bp, 1, 0);
-    return _nameOffset;
+  idl.UnlinkedConst get constExpr {
+    _constExpr ??= const _UnlinkedConstReader().vTableGet(_bp, 5, null);
+    return _constExpr;
   }
 
   @override
-  UnlinkedDocumentationComment get documentationComment {
-    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 2, null);
+  idl.UnlinkedDocumentationComment get documentationComment {
+    _documentationComment ??= const _UnlinkedDocumentationCommentReader().vTableGet(_bp, 10, null);
     return _documentationComment;
   }
 
   @override
-  UnlinkedTypeRef get type {
-    _type ??= const _UnlinkedTypeRefReader().vTableGet(_bp, 3, null);
-    return _type;
+  int get inferredTypeSlot {
+    _inferredTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 9, 0);
+    return _inferredTypeSlot;
   }
 
   @override
-  bool get isStatic {
-    _isStatic ??= const fb.BoolReader().vTableGet(_bp, 4, false);
-    return _isStatic;
-  }
-
-  @override
-  bool get isFinal {
-    _isFinal ??= const fb.BoolReader().vTableGet(_bp, 5, false);
-    return _isFinal;
+  idl.UnlinkedExecutable get initializer {
+    _initializer ??= const _UnlinkedExecutableReader().vTableGet(_bp, 13, null);
+    return _initializer;
   }
 
   @override
@@ -4664,9 +7240,94 @@
   }
 
   @override
-  bool get hasImplicitType {
-    _hasImplicitType ??= const fb.BoolReader().vTableGet(_bp, 7, false);
-    return _hasImplicitType;
+  bool get isFinal {
+    _isFinal ??= const fb.BoolReader().vTableGet(_bp, 7, false);
+    return _isFinal;
   }
+
+  @override
+  bool get isStatic {
+    _isStatic ??= const fb.BoolReader().vTableGet(_bp, 4, false);
+    return _isStatic;
+  }
+
+  @override
+  String get name {
+    _name ??= const fb.StringReader().vTableGet(_bp, 0, '');
+    return _name;
+  }
+
+  @override
+  int get nameOffset {
+    _nameOffset ??= const fb.Uint32Reader().vTableGet(_bp, 1, 0);
+    return _nameOffset;
+  }
+
+  @override
+  int get propagatedTypeSlot {
+    _propagatedTypeSlot ??= const fb.Uint32Reader().vTableGet(_bp, 2, 0);
+    return _propagatedTypeSlot;
+  }
+
+  @override
+  idl.EntityRef get type {
+    _type ??= const _EntityRefReader().vTableGet(_bp, 3, null);
+    return _type;
+  }
+
+  @override
+  int get visibleLength {
+    _visibleLength ??= const fb.Uint32Reader().vTableGet(_bp, 11, 0);
+    return _visibleLength;
+  }
+
+  @override
+  int get visibleOffset {
+    _visibleOffset ??= const fb.Uint32Reader().vTableGet(_bp, 12, 0);
+    return _visibleOffset;
+  }
+}
+
+abstract class _UnlinkedVariableMixin implements idl.UnlinkedVariable {
+  @override
+  Map<String, Object> toJson() {
+    Map<String, Object> _result = <String, Object>{};
+    if (annotations.isNotEmpty) _result["annotations"] = annotations.map((_value) => _value.toJson()).toList();
+    if (constExpr != null) _result["constExpr"] = constExpr.toJson();
+    if (documentationComment != null) _result["documentationComment"] = documentationComment.toJson();
+    if (inferredTypeSlot != 0) _result["inferredTypeSlot"] = inferredTypeSlot;
+    if (initializer != null) _result["initializer"] = initializer.toJson();
+    if (isConst != false) _result["isConst"] = isConst;
+    if (isFinal != false) _result["isFinal"] = isFinal;
+    if (isStatic != false) _result["isStatic"] = isStatic;
+    if (name != '') _result["name"] = name;
+    if (nameOffset != 0) _result["nameOffset"] = nameOffset;
+    if (propagatedTypeSlot != 0) _result["propagatedTypeSlot"] = propagatedTypeSlot;
+    if (type != null) _result["type"] = type.toJson();
+    if (visibleLength != 0) _result["visibleLength"] = visibleLength;
+    if (visibleOffset != 0) _result["visibleOffset"] = visibleOffset;
+    return _result;
+  }
+
+  @override
+  Map<String, Object> toMap() => {
+    "annotations": annotations,
+    "constExpr": constExpr,
+    "documentationComment": documentationComment,
+    "inferredTypeSlot": inferredTypeSlot,
+    "initializer": initializer,
+    "isConst": isConst,
+    "isFinal": isFinal,
+    "isStatic": isStatic,
+    "name": name,
+    "nameOffset": nameOffset,
+    "propagatedTypeSlot": propagatedTypeSlot,
+    "type": type,
+    "visibleLength": visibleLength,
+    "visibleOffset": visibleOffset,
+  };
+
+  @override
+  String toString() => convert.JSON.encode(toJson());
 }
 
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
new file mode 100644
index 0000000..21473a2
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -0,0 +1,2259 @@
+// 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 is an "idl" style description of the summary format.  It
+ * contains abstract classes which declare the interface for reading data from
+ * summaries.  It is parsed and transformed into code that implements the
+ * summary format.
+ *
+ * The code generation process introduces the following semantics:
+ * - Getters of type List never return null, and have a default value of the
+ *   empty list.
+ * - Getters of type int return unsigned 32-bit integers, never null, and have
+ *   a default value of zero.
+ * - Getters of type String never return null, and have a default value of ''.
+ * - Getters of type bool never return null, and have a default value of false.
+ * - Getters whose type is an enum never return null, and have a default value
+ *   of the first value declared in the enum.
+ *
+ * Terminology used in this document:
+ * - "Unlinked" refers to information that can be determined from reading a
+ *   single .dart file in isolation.
+ * - "Prelinked" refers to information that can be determined from the defining
+ *   compilation unit of a library, plus direct imports, plus the transitive
+ *   closure of exports reachable from those libraries, plus all part files
+ *   constituting those libraries.
+ * - "Linked" refers to all other information; in theory, this information may
+ *   depend on all files in the transitive import/export closure.  However, in
+ *   practice we expect that the number of additional dependencies will usually
+ *   be small, since the additional dependencies only need to be consulted for
+ *   type propagation, type inference, and constant evaluation, which typically
+ *   have short dependency chains.
+ *
+ * Since we expect "linked" and "prelinked" dependencies to be similar, we only
+ * rarely distinguish between them; most information is that is not "unlinked"
+ * is typically considered "linked" for simplicity.
+ *
+ * Except as otherwise noted, synthetic elements are not stored in the summary;
+ * they are re-synthesized at the time the summary is read.
+ */
+library analyzer.tool.summary.idl;
+
+import 'base.dart' as base;
+import 'base.dart' show Id, TopLevel;
+import 'format.dart' as generated;
+
+/**
+ * Annotation describing information which is not part of Dart semantics; in
+ * other words, if this information (or any information it refers to) changes,
+ * static analysis and runtime behavior of the library are unaffected.
+ */
+const informative = null;
+
+/**
+ * Summary information about a reference to a an entity such as a type, top
+ * level executable, or executable within a class.
+ */
+abstract class EntityRef extends base.SummaryClass {
+  /**
+   * 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.
+   */
+  @Id(4)
+  List<int> get implicitFunctionTypeIndices;
+
+  /**
+   * 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.
+   */
+  @Id(3)
+  int get paramReference;
+
+  /**
+   * Index into [UnlinkedUnit.references] for the entity being referred to, or
+   * zero if this is a reference to a type parameter.
+   */
+  @Id(0)
+  int get reference;
+
+  /**
+   * 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.
+   */
+  @Id(2)
+  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.
+   */
+  @Id(1)
+  List<EntityRef> get typeArguments;
+}
+
+/**
+ * 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.
+ */
+abstract class LinkedDependency extends base.SummaryClass {
+  /**
+   * URI for the compilation units listed in the library's `part` declarations.
+   * These URIs are relative to the importing library.
+   */
+  @Id(1)
+  List<String> get parts;
+
+  /**
+   * 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`.
+   */
+  @Id(0)
+  String get uri;
+}
+
+/**
+ * Information about a single name in the export namespace of the library that
+ * is not in the public namespace.
+ */
+abstract class LinkedExportName extends base.SummaryClass {
+  /**
+   * Index into [LinkedLibrary.dependencies] for the library in which the
+   * entity is defined.
+   */
+  @Id(0)
+  int get dependency;
+
+  /**
+   * The kind of the entity being referred to.
+   */
+  @Id(3)
+  ReferenceKind get kind;
+
+  /**
+   * Name of the exported entity.  For an exported setter, this name includes
+   * the trailing '='.
+   */
+  @Id(1)
+  String get name;
+
+  /**
+   * 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.
+   */
+  @Id(2)
+  int get unit;
+}
+
+/**
+ * Linked summary of a library.
+ */
+@TopLevel('LLib')
+abstract class LinkedLibrary extends base.SummaryClass {
+  factory LinkedLibrary.fromBuffer(List<int> buffer) =>
+      generated.readLinkedLibrary(buffer);
+
+  /**
+   * 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).
+   */
+  @Id(0)
+  List<LinkedDependency> get dependencies;
+
+  /**
+   * 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.
+   */
+  @Id(4)
+  List<LinkedExportName> get exportNames;
+
+  /**
+   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
+   * of the library being imported.
+   */
+  @Id(1)
+  List<int> get importDependencies;
+
+  /**
+   * 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).
+   */
+  @Id(2)
+  int get numPrelinkedDependencies;
+
+  /**
+   * 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.
+   */
+  @Id(3)
+  List<LinkedUnit> get units;
+}
+
+/**
+ * Information about the resolution of an [UnlinkedReference].
+ */
+abstract class LinkedReference extends base.SummaryClass {
+  /**
+   * 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.
+   */
+  @Id(5)
+  int get containingReference;
+
+  /**
+   * 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].
+   */
+  @Id(1)
+  int get dependency;
+
+  /**
+   * The kind of the entity being referred to.  For the pseudo-types `dynamic`
+   * and `void`, the kind is [ReferenceKind.classOrEnum].
+   */
+  @Id(2)
+  ReferenceKind get kind;
+
+  /**
+   * 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.
+   */
+  @Id(6)
+  int get localIndex;
+
+  /**
+   * 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".
+   */
+  @Id(3)
+  String get name;
+
+  /**
+   * 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.
+   */
+  @Id(4)
+  int get numTypeParameters;
+
+  /**
+   * 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).
+   */
+  @Id(0)
+  int get unit;
+}
+
+/**
+ * Linked summary of a compilation unit.
+ */
+abstract class LinkedUnit extends base.SummaryClass {
+  /**
+   * 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).
+   */
+  @Id(0)
+  List<LinkedReference> get references;
+
+  /**
+   * List associating slot ids found inside the unlinked summary for the
+   * compilation unit with propagated and inferred types.
+   */
+  @Id(1)
+  List<EntityRef> get types;
+}
+
+/**
+ * Summary information about a package.
+ */
+@TopLevel('PBdl')
+abstract class PackageBundle extends base.SummaryClass {
+  factory PackageBundle.fromBuffer(List<int> buffer) =>
+      generated.readPackageBundle(buffer);
+
+  /**
+   * Linked libraries.
+   */
+  @Id(0)
+  List<LinkedLibrary> get linkedLibraries;
+
+  /**
+   * The list of URIs of items in [linkedLibraries], e.g. `dart:core` or
+   * `package:foo/bar.dart`.
+   */
+  @Id(1)
+  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.
+   */
+  @Id(4)
+  List<String> get unlinkedUnitHashes;
+
+  /**
+   * Unlinked information for the compilation units constituting the package.
+   */
+  @Id(2)
+  List<UnlinkedUnit> get unlinkedUnits;
+
+  /**
+   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
+   */
+  @Id(3)
+  List<String> get unlinkedUnitUris;
+}
+
+/**
+ * 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].
+ */
+enum ReferenceKind {
+  /**
+   * 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
+}
+
+/**
+ * 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 {
+  /**
+   * Annotations for this class.
+   */
+  @Id(5)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * Documentation comment for the class, or `null` if there is no
+   * documentation comment.
+   */
+  @informative
+  @Id(6)
+  UnlinkedDocumentationComment get documentationComment;
+
+  /**
+   * Executable objects (methods, getters, and setters) contained in the class.
+   */
+  @Id(2)
+  List<UnlinkedExecutable> get executables;
+
+  /**
+   * Field declarations contained in the class.
+   */
+  @Id(4)
+  List<UnlinkedVariable> get fields;
+
+  /**
+   * Indicates whether this class is the core "Object" class (and hence has no
+   * supertype)
+   */
+  @Id(12)
+  bool get hasNoSupertype;
+
+  /**
+   * Interfaces appearing in an `implements` clause, if any.
+   */
+  @Id(7)
+  List<EntityRef> get interfaces;
+
+  /**
+   * Indicates whether the class is declared with the `abstract` keyword.
+   */
+  @Id(8)
+  bool get isAbstract;
+
+  /**
+   * Indicates whether the class is declared using mixin application syntax.
+   */
+  @Id(11)
+  bool get isMixinApplication;
+
+  /**
+   * Mixins appearing in a `with` clause, if any.
+   */
+  @Id(10)
+  List<EntityRef> get mixins;
+
+  /**
+   * Name of the class.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * Offset of the class name relative to the beginning of the file.
+   */
+  @informative
+  @Id(1)
+  int get nameOffset;
+
+  /**
+   * 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).
+   */
+  @Id(3)
+  EntityRef get supertype;
+
+  /**
+   * Type parameters of the class, if any.
+   */
+  @Id(9)
+  List<UnlinkedTypeParam> get typeParameters;
+}
+
+/**
+ * Unlinked summary information about a `show` or `hide` combinator in an
+ * import or export declaration.
+ */
+abstract class UnlinkedCombinator extends base.SummaryClass {
+  /**
+   * If this is a `show` combinator, offset of the end of the list of shown
+   * names.  Otherwise zero.
+   */
+  @informative
+  @Id(3)
+  int get end;
+
+  /**
+   * List of names which are hidden.  Empty if this is a `show` combinator.
+   */
+  @Id(1)
+  List<String> get hides;
+
+  /**
+   * If this is a `show` combinator, offset of the `show` keyword.  Otherwise
+   * zero.
+   */
+  @informative
+  @Id(2)
+  int get offset;
+
+  /**
+   * List of names which are shown.  Empty if this is a `hide` combinator.
+   */
+  @Id(0)
+  List<String> get shows;
+}
+
+/**
+ * Unlinked summary information about a compile-time constant expression, or a
+ * potentially constant expression.
+ *
+ * Constant expressions are represented using a simple stack-based language
+ * where [operations] is a sequence of operations to execute starting with an
+ * empty stack.  Once all operations have been executed, the stack should
+ * contain a single value which is the value of the constant.  Note that some
+ * operations consume additional data from the other fields of this class.
+ */
+abstract class UnlinkedConst extends base.SummaryClass {
+  /**
+   * Sequence of 64-bit doubles consumed by the operation `pushDouble`.
+   */
+  @Id(4)
+  List<double> get doubles;
+
+  /**
+   * Sequence of unsigned 32-bit integers consumed by the operations
+   * `pushArgument`, `pushInt`, `shiftOr`, `concatenate`, `invokeConstructor`,
+   * `makeList`, and `makeMap`.
+   */
+  @Id(1)
+  List<int> get ints;
+
+  /**
+   * Indicates whether the expression is not a valid potentially constant
+   * expression.
+   */
+  @Id(5)
+  bool get isInvalid;
+
+  /**
+   * Sequence of operations to execute (starting with an empty stack) to form
+   * the constant value.
+   */
+  @Id(0)
+  List<UnlinkedConstOperation> get operations;
+
+  /**
+   * Sequence of language constructs consumed by the operations
+   * `pushReference`, `invokeConstructor`, `makeList`, and `makeMap`.  Note
+   * that in the case of `pushReference` (and sometimes `invokeConstructor` the
+   * actual entity being referred to may be something other than a type.
+   */
+  @Id(2)
+  List<EntityRef> get references;
+
+  /**
+   * Sequence of strings consumed by the operations `pushString` and
+   * `invokeConstructor`.
+   */
+  @Id(3)
+  List<String> get strings;
+}
+
+/**
+ * Enum representing the various kinds of operations which may be performed to
+ * produce a constant value.  These options are assumed to execute in the
+ * context of a stack which is initially empty.
+ */
+enum UnlinkedConstOperation {
+  /**
+   * Push the next value from [UnlinkedConst.ints] (a 32-bit unsigned integer)
+   * onto the stack.
+   *
+   * Note that Dart supports integers larger than 32 bits; these are
+   * represented by composing 32-bit values using the [pushLongInt] operation.
+   */
+  pushInt,
+
+  /**
+   * Get the number of components from [UnlinkedConst.ints], then do this number
+   * of times the following operations: multiple the current value by 2^32, "or"
+   * it with the next value in [UnlinkedConst.ints]. The initial value is zero.
+   * Push the result into the stack.
+   */
+  pushLongInt,
+
+  /**
+   * Push the next value from [UnlinkedConst.doubles] (a double precision
+   * floating point value) onto the stack.
+   */
+  pushDouble,
+
+  /**
+   * Push the constant `true` onto the stack.
+   */
+  pushTrue,
+
+  /**
+   * Push the constant `false` onto the stack.
+   */
+  pushFalse,
+
+  /**
+   * Push the next value from [UnlinkedConst.strings] onto the stack.
+   */
+  pushString,
+
+  /**
+   * Pop the top n values from the stack (where n is obtained from
+   * [UnlinkedConst.ints]), convert them to strings (if they aren't already),
+   * concatenate them into a single string, and push it back onto the stack.
+   *
+   * This operation is used to represent constants whose value is a literal
+   * string containing string interpolations.
+   */
+  concatenate,
+
+  /**
+   * Get the next value from [UnlinkedConst.strings], convert it to a symbol,
+   * and push it onto the stack.
+   */
+  makeSymbol,
+
+  /**
+   * Push the constant `null` onto the stack.
+   */
+  pushNull,
+
+  /**
+   * Push the value of the 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,
+}
+
+/**
+ * Unlinked summary information about a constructor initializer.
+ */
+abstract class UnlinkedConstructorInitializer extends base.SummaryClass {
+  /**
+   * If [kind] is `thisInvocation` or `superInvocation`, the arguments of the
+   * invocation.  Otherwise empty.
+   */
+  @Id(3)
+  List<UnlinkedConst> get arguments;
+
+  /**
+   * If [kind] is `field`, the expression of the field initializer.
+   * Otherwise `null`.
+   */
+  @Id(1)
+  UnlinkedConst get expression;
+
+  /**
+   * The kind of the constructor initializer (field, redirect, super).
+   */
+  @Id(2)
+  UnlinkedConstructorInitializerKind get kind;
+
+  /**
+   * 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.
+   */
+  @Id(0)
+  String get name;
+}
+
+/**
+ * Enum used to indicate the kind of an constructor initializer.
+ */
+enum UnlinkedConstructorInitializerKind {
+  /**
+   * Initialization of a field.
+   */
+  field,
+
+  /**
+   * Invocation of a constructor in the same class.
+   */
+  thisInvocation,
+
+  /**
+   * Invocation of a superclass' constructor.
+   */
+  superInvocation
+}
+
+/**
+ * Unlinked summary information about a documentation comment.
+ */
+abstract class UnlinkedDocumentationComment extends base.SummaryClass {
+  /**
+   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
+   */
+  @Id(0)
+  int get length;
+
+  /**
+   * Offset of the beginning of the documentation comment relative to the
+   * beginning of the file.
+   */
+  @Id(2)
+  int get offset;
+
+  /**
+   * Text of the documentation comment, with '\r\n' replaced by '\n'.
+   *
+   * References appearing within the doc comment in square brackets are not
+   * specially encoded.
+   */
+  @Id(1)
+  String get text;
+}
+
+/**
+ * Unlinked summary information about an enum declaration.
+ */
+abstract class UnlinkedEnum extends base.SummaryClass {
+  /**
+   * Annotations for this enum.
+   */
+  @Id(4)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * Documentation comment for the enum, or `null` if there is no documentation
+   * comment.
+   */
+  @informative
+  @Id(3)
+  UnlinkedDocumentationComment get documentationComment;
+
+  /**
+   * Name of the enum type.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * Offset of the enum name relative to the beginning of the file.
+   */
+  @informative
+  @Id(1)
+  int get nameOffset;
+
+  /**
+   * Values listed in the enum declaration, in declaration order.
+   */
+  @Id(2)
+  List<UnlinkedEnumValue> get values;
+}
+
+/**
+ * Unlinked summary information about a single enumerated value in an enum
+ * declaration.
+ */
+abstract class UnlinkedEnumValue extends base.SummaryClass {
+  /**
+   * Documentation comment for the enum value, or `null` if there is no
+   * documentation comment.
+   */
+  @informative
+  @Id(2)
+  UnlinkedDocumentationComment get documentationComment;
+
+  /**
+   * Name of the enumerated value.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * Offset of the enum value name relative to the beginning of the file.
+   */
+  @informative
+  @Id(1)
+  int get nameOffset;
+}
+
+/**
+ * Unlinked summary information about a function, method, getter, or setter
+ * declaration.
+ */
+abstract class UnlinkedExecutable extends base.SummaryClass {
+  /**
+   * Annotations for this executable.
+   */
+  @Id(6)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * If a constant [UnlinkedExecutableKind.constructor], the constructor
+   * initializers.  Otherwise empty.
+   */
+  @Id(14)
+  List<UnlinkedConstructorInitializer> get constantInitializers;
+
+  /**
+   * Documentation comment for the executable, or `null` if there is no
+   * documentation comment.
+   */
+  @informative
+  @Id(7)
+  UnlinkedDocumentationComment get documentationComment;
+
+  /**
+   * 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`.
+   */
+  @Id(5)
+  int get inferredReturnTypeSlot;
+
+  /**
+   * Indicates whether the executable is declared using the `abstract` keyword.
+   */
+  @Id(10)
+  bool get isAbstract;
+
+  /**
+   * Indicates whether the executable is declared using the `const` keyword.
+   */
+  @Id(12)
+  bool get isConst;
+
+  /**
+   * Indicates whether the executable is declared using the `external` keyword.
+   */
+  @Id(11)
+  bool get isExternal;
+
+  /**
+   * Indicates whether the executable is declared using the `factory` keyword.
+   */
+  @Id(8)
+  bool get isFactory;
+
+  /**
+   * Indicates whether the executable is a redirected constructor.
+   */
+  @Id(13)
+  bool get isRedirectedConstructor;
+
+  /**
+   * 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).
+   */
+  @Id(9)
+  bool get isStatic;
+
+  /**
+   * The kind of the executable (function/method, getter, setter, or
+   * constructor).
+   */
+  @Id(4)
+  UnlinkedExecutableKind get kind;
+
+  /**
+   * The list of local functions.
+   */
+  @Id(18)
+  List<UnlinkedExecutable> get localFunctions;
+
+  /**
+   * The list of local labels.
+   */
+  @Id(22)
+  List<UnlinkedLabel> get localLabels;
+
+  /**
+   * The list of local variables.
+   */
+  @Id(19)
+  List<UnlinkedVariable> get localVariables;
+
+  /**
+   * 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.
+   */
+  @Id(1)
+  String get name;
+
+  /**
+   * If [kind] is [UnlinkedExecutableKind.constructor] and [name] is not empty,
+   * the offset of the end of the constructor name.  Otherwise zero.
+   */
+  @informative
+  @Id(23)
+  int get nameEnd;
+
+  /**
+   * 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(); }").
+   */
+  @informative
+  @Id(0)
+  int get nameOffset;
+
+  /**
+   * 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.
+   */
+  @Id(2)
+  List<UnlinkedParam> get parameters;
+
+  /**
+   * If [kind] is [UnlinkedExecutableKind.constructor] and [name] is not empty,
+   * the offset of the period before the constructor name.  Otherwise zero.
+   */
+  @informative
+  @Id(24)
+  int get periodOffset;
+
+  /**
+   * If [isRedirectedConstructor] and [isFactory] are both `true`, the
+   * constructor to which this constructor redirects; otherwise empty.
+   */
+  @Id(15)
+  EntityRef get redirectedConstructor;
+
+  /**
+   * If [isRedirectedConstructor] is `true` and [isFactory] is `false`, the
+   * name of the constructor that this constructor redirects to; otherwise
+   * empty.
+   */
+  @Id(17)
+  String get redirectedConstructorName;
+
+  /**
+   * 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.
+   */
+  @Id(3)
+  EntityRef get returnType;
+
+  /**
+   * Type parameters of the executable, if any.  Empty if support for generic
+   * method syntax is disabled.
+   */
+  @Id(16)
+  List<UnlinkedTypeParam> get typeParameters;
+
+  /**
+   * If a local function, the length of the visible range; zero otherwise.
+   */
+  @Id(20)
+  int get visibleLength;
+
+  /**
+   * If a local function, the beginning of the visible range; zero otherwise.
+   */
+  @Id(21)
+  int get visibleOffset;
+}
+
+/**
+ * Enum used to indicate the kind of an executable.
+ */
+enum UnlinkedExecutableKind {
+  /**
+   * Executable is a function or method.
+   */
+  functionOrMethod,
+
+  /**
+   * Executable is a getter.
+   */
+  getter,
+
+  /**
+   * Executable is a setter.
+   */
+  setter,
+
+  /**
+   * Executable is a constructor.
+   */
+  constructor
+}
+
+/**
+ * Unlinked summary information about an export declaration (stored outside
+ * [UnlinkedPublicNamespace]).
+ */
+abstract class UnlinkedExportNonPublic extends base.SummaryClass {
+  /**
+   * Annotations for this export directive.
+   */
+  @Id(3)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * Offset of the "export" keyword.
+   */
+  @informative
+  @Id(0)
+  int get offset;
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.
+   */
+  @informative
+  @Id(1)
+  int get uriEnd;
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.
+   */
+  @informative
+  @Id(2)
+  int get uriOffset;
+}
+
+/**
+ * Unlinked summary information about an export declaration (stored inside
+ * [UnlinkedPublicNamespace]).
+ */
+abstract class UnlinkedExportPublic extends base.SummaryClass {
+  /**
+   * Combinators contained in this import declaration.
+   */
+  @Id(1)
+  List<UnlinkedCombinator> get combinators;
+
+  /**
+   * URI used in the source code to reference the exported library.
+   */
+  @Id(0)
+  String get uri;
+}
+
+/**
+ * Unlinked summary information about an import declaration.
+ */
+abstract class UnlinkedImport extends base.SummaryClass {
+  /**
+   * Annotations for this import declaration.
+   */
+  @Id(8)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * Combinators contained in this import declaration.
+   */
+  @Id(4)
+  List<UnlinkedCombinator> get combinators;
+
+  /**
+   * Indicates whether the import declaration uses the `deferred` keyword.
+   */
+  @Id(9)
+  bool get isDeferred;
+
+  /**
+   * Indicates whether the import declaration is implicit.
+   */
+  @Id(5)
+  bool get isImplicit;
+
+  /**
+   * If [isImplicit] is false, offset of the "import" keyword.  If [isImplicit]
+   * is true, zero.
+   */
+  @informative
+  @Id(0)
+  int get offset;
+
+  /**
+   * Offset of the prefix name relative to the beginning of the file, or zero
+   * if there is no prefix.
+   */
+  @informative
+  @Id(6)
+  int get prefixOffset;
+
+  /**
+   * 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.
+   */
+  @Id(7)
+  int get prefixReference;
+
+  /**
+   * URI used in the source code to reference the imported library.
+   */
+  @Id(1)
+  String get uri;
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.  If [isImplicit] is true, zero.
+   */
+  @informative
+  @Id(2)
+  int get uriEnd;
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.  If [isImplicit] is true, zero.
+   */
+  @informative
+  @Id(3)
+  int get uriOffset;
+}
+
+/**
+ * Unlinked summary information about a label.
+ */
+abstract class UnlinkedLabel extends base.SummaryClass {
+  /**
+   * Return `true` if this label is associated with a `switch` member (`case` or
+   * `default`).
+   */
+  @Id(2)
+  bool get isOnSwitchMember;
+
+  /**
+   * Return `true` if this label is associated with a `switch` statement.
+   */
+  @Id(3)
+  bool get isOnSwitchStatement;
+
+  /**
+   * Name of the label.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * Offset of the label relative to the beginning of the file.
+   */
+  @informative
+  @Id(1)
+  int get nameOffset;
+}
+
+/**
+ * Unlinked summary information about a function parameter.
+ */
+abstract class UnlinkedParam extends base.SummaryClass {
+  /**
+   * Annotations for this parameter.
+   */
+  @Id(9)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * 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].
+   */
+  @Id(7)
+  UnlinkedConst get defaultValue;
+
+  /**
+   * If the parameter has a default value, the source text of the constant
+   * expression in the default value.  Otherwise the empty string.
+   */
+  @informative
+  @Id(13)
+  String get defaultValueCode;
+
+  /**
+   * 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.
+   */
+  @Id(2)
+  int get inferredTypeSlot;
+
+  /**
+   * The synthetic initializer function of the parameter.  Absent if the variable
+   * does not have an initializer.
+   */
+  @Id(12)
+  UnlinkedExecutable get initializer;
+
+  /**
+   * Indicates whether this is a function-typed parameter.
+   */
+  @Id(5)
+  bool get isFunctionTyped;
+
+  /**
+   * Indicates whether this is an initializing formal parameter (i.e. it is
+   * declared using `this.` syntax).
+   */
+  @Id(6)
+  bool get isInitializingFormal;
+
+  /**
+   * Kind of the parameter.
+   */
+  @Id(4)
+  UnlinkedParamKind get kind;
+
+  /**
+   * Name of the parameter.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * Offset of the parameter name relative to the beginning of the file.
+   */
+  @informative
+  @Id(1)
+  int get nameOffset;
+
+  /**
+   * If [isFunctionTyped] is `true`, the parameters of the function type.
+   */
+  @Id(8)
+  List<UnlinkedParam> get parameters;
+
+  /**
+   * If [isFunctionTyped] is `true`, the declared return type.  If
+   * [isFunctionTyped] is `false`, the declared type.  Absent if the type is
+   * implicit.
+   */
+  @Id(3)
+  EntityRef get type;
+
+  /**
+   * The length of the visible range.
+   */
+  @Id(10)
+  int get visibleLength;
+
+  /**
+   * The beginning of the visible range.
+   */
+  @Id(11)
+  int get visibleOffset;
+}
+
+/**
+ * Enum used to indicate the kind of a parameter.
+ */
+enum UnlinkedParamKind {
+  /**
+   * Parameter is required.
+   */
+  required,
+
+  /**
+   * Parameter is positional optional (enclosed in `[]`)
+   */
+  positional,
+
+  /**
+   * Parameter is named optional (enclosed in `{}`)
+   */
+  named
+}
+
+/**
+ * Unlinked summary information about a part declaration.
+ */
+abstract class UnlinkedPart extends base.SummaryClass {
+  /**
+   * Annotations for this part declaration.
+   */
+  @Id(2)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * End of the URI string (including quotes) relative to the beginning of the
+   * file.
+   */
+  @informative
+  @Id(0)
+  int get uriEnd;
+
+  /**
+   * Offset of the URI string (including quotes) relative to the beginning of
+   * the file.
+   */
+  @informative
+  @Id(1)
+  int get uriOffset;
+}
+
+/**
+ * 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.
+ */
+abstract class UnlinkedPublicName extends base.SummaryClass {
+  /**
+   * The kind of object referred to by the name.
+   */
+  @Id(1)
+  ReferenceKind get kind;
+
+  /**
+   * 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.
+   */
+  @Id(2)
+  List<UnlinkedPublicName> get members;
+
+  /**
+   * The name itself.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * If the entity being referred to is generic, the number of type parameters
+   * it accepts.  Otherwise zero.
+   */
+  @Id(3)
+  int get numTypeParameters;
+}
+
+/**
+ * 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.
+ */
+@TopLevel('UPNS')
+abstract class UnlinkedPublicNamespace extends base.SummaryClass {
+  factory UnlinkedPublicNamespace.fromBuffer(List<int> buffer) =>
+      generated.readUnlinkedPublicNamespace(buffer);
+
+  /**
+   * Export declarations in the compilation unit.
+   */
+  @Id(2)
+  List<UnlinkedExportPublic> get exports;
+
+  /**
+   * Public names defined in the compilation unit.
+   *
+   * TODO(paulberry): consider sorting these names to reduce unnecessary
+   * relinking.
+   */
+  @Id(0)
+  List<UnlinkedPublicName> get names;
+
+  /**
+   * URIs referenced by part declarations in the compilation unit.
+   */
+  @Id(1)
+  List<String> get parts;
+}
+
+/**
+ * Unlinked summary information about a name referred to in one library that
+ * might be defined in another.
+ */
+abstract class UnlinkedReference extends base.SummaryClass {
+  /**
+   * 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*".
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * 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.
+   */
+  @Id(1)
+  int get prefixReference;
+}
+
+/**
+ * Unlinked summary information about a typedef declaration.
+ */
+abstract class UnlinkedTypedef extends base.SummaryClass {
+  /**
+   * Annotations for this typedef.
+   */
+  @Id(4)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * Documentation comment for the typedef, or `null` if there is no
+   * documentation comment.
+   */
+  @informative
+  @Id(6)
+  UnlinkedDocumentationComment get documentationComment;
+
+  /**
+   * Name of the typedef.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * Offset of the typedef name relative to the beginning of the file.
+   */
+  @informative
+  @Id(1)
+  int get nameOffset;
+
+  /**
+   * Parameters of the executable, if any.
+   */
+  @Id(3)
+  List<UnlinkedParam> get parameters;
+
+  /**
+   * Return type of the typedef.
+   */
+  @Id(2)
+  EntityRef get returnType;
+
+  /**
+   * Type parameters of the typedef, if any.
+   */
+  @Id(5)
+  List<UnlinkedTypeParam> get typeParameters;
+}
+
+/**
+ * Unlinked summary information about a type parameter declaration.
+ */
+abstract class UnlinkedTypeParam extends base.SummaryClass {
+  /**
+   * Annotations for this type parameter.
+   */
+  @Id(3)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
+   * null.
+   */
+  @Id(2)
+  EntityRef get bound;
+
+  /**
+   * Name of the type parameter.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * Offset of the type parameter name relative to the beginning of the file.
+   */
+  @informative
+  @Id(1)
+  int get nameOffset;
+}
+
+/**
+ * Unlinked summary information about a compilation unit ("part file").
+ */
+@TopLevel('UUnt')
+abstract class UnlinkedUnit extends base.SummaryClass {
+  factory UnlinkedUnit.fromBuffer(List<int> buffer) =>
+      generated.readUnlinkedUnit(buffer);
+
+  /**
+   * Classes declared in the compilation unit.
+   */
+  @Id(2)
+  List<UnlinkedClass> get classes;
+
+  /**
+   * Enums declared in the compilation unit.
+   */
+  @Id(12)
+  List<UnlinkedEnum> get enums;
+
+  /**
+   * Top level executable objects (functions, getters, and setters) declared in
+   * the compilation unit.
+   */
+  @Id(4)
+  List<UnlinkedExecutable> get executables;
+
+  /**
+   * Export declarations in the compilation unit.
+   */
+  @Id(13)
+  List<UnlinkedExportNonPublic> get exports;
+
+  /**
+   * Import declarations in the compilation unit.
+   */
+  @Id(5)
+  List<UnlinkedImport> get imports;
+
+  /**
+   * Annotations for the library declaration, or the empty list if there is no
+   * library declaration.
+   */
+  @Id(14)
+  List<UnlinkedConst> get libraryAnnotations;
+
+  /**
+   * Documentation comment for the library, or `null` if there is no
+   * documentation comment.
+   */
+  @informative
+  @Id(9)
+  UnlinkedDocumentationComment get libraryDocumentationComment;
+
+  /**
+   * Name of the library (from a "library" declaration, if present).
+   */
+  @Id(6)
+  String get libraryName;
+
+  /**
+   * Length of the library name as it appears in the source code (or 0 if the
+   * library has no name).
+   */
+  @informative
+  @Id(7)
+  int get libraryNameLength;
+
+  /**
+   * Offset of the library name relative to the beginning of the file (or 0 if
+   * the library has no name).
+   */
+  @informative
+  @Id(8)
+  int get libraryNameOffset;
+
+  /**
+   * Part declarations in the compilation unit.
+   */
+  @Id(11)
+  List<UnlinkedPart> get parts;
+
+  /**
+   * Unlinked public namespace of this compilation unit.
+   */
+  @Id(0)
+  UnlinkedPublicNamespace get publicNamespace;
+
+  /**
+   * 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]).
+   */
+  @Id(1)
+  List<UnlinkedReference> get references;
+
+  /**
+   * Typedefs declared in the compilation unit.
+   */
+  @Id(10)
+  List<UnlinkedTypedef> get typedefs;
+
+  /**
+   * Top level variables declared in the compilation unit.
+   */
+  @Id(3)
+  List<UnlinkedVariable> get variables;
+}
+
+/**
+ * Unlinked summary information about a top level variable, local variable, or
+ * a field.
+ */
+abstract class UnlinkedVariable extends base.SummaryClass {
+  /**
+   * Annotations for this variable.
+   */
+  @Id(8)
+  List<UnlinkedConst> get annotations;
+
+  /**
+   * 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].
+   */
+  @Id(5)
+  UnlinkedConst get constExpr;
+
+  /**
+   * Documentation comment for the variable, or `null` if there is no
+   * documentation comment.
+   */
+  @informative
+  @Id(10)
+  UnlinkedDocumentationComment get documentationComment;
+
+  /**
+   * 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`.
+   */
+  @Id(9)
+  int get inferredTypeSlot;
+
+  /**
+   * The synthetic initializer function of the variable.  Absent if the variable
+   * does not have an initializer.
+   */
+  @Id(13)
+  UnlinkedExecutable get initializer;
+
+  /**
+   * Indicates whether the variable is declared using the `const` keyword.
+   */
+  @Id(6)
+  bool get isConst;
+
+  /**
+   * Indicates whether the variable is declared using the `final` keyword.
+   */
+  @Id(7)
+  bool get isFinal;
+
+  /**
+   * 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).
+   */
+  @Id(4)
+  bool get isStatic;
+
+  /**
+   * Name of the variable.
+   */
+  @Id(0)
+  String get name;
+
+  /**
+   * Offset of the variable name relative to the beginning of the file.
+   */
+  @informative
+  @Id(1)
+  int get nameOffset;
+
+  /**
+   * 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.
+   */
+  @Id(2)
+  int get propagatedTypeSlot;
+
+  /**
+   * Declared type of the variable.  Absent if the type is implicit.
+   */
+  @Id(3)
+  EntityRef get type;
+
+  /**
+   * If a local variable, the length of the visible range; zero otherwise.
+   */
+  @Id(11)
+  int get visibleLength;
+
+  /**
+   * If a local variable, the beginning of the visible range; zero otherwise.
+   */
+  @Id(12)
+  int get visibleOffset;
+}
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/name_filter.dart b/pkg/analyzer/lib/src/summary/name_filter.dart
index 7b130ec..c71ff18 100644
--- a/pkg/analyzer/lib/src/summary/name_filter.dart
+++ b/pkg/analyzer/lib/src/summary/name_filter.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
 
 /**
  * A [NameFilter] represents the set of filtering rules implied by zero or more
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/prelink.dart b/pkg/analyzer/lib/src/summary/prelink.dart
index ad4834f..688abe5 100644
--- a/pkg/analyzer/lib/src/summary/prelink.dart
+++ b/pkg/analyzer/lib/src/summary/prelink.dart
@@ -3,10 +3,11 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/name_filter.dart';
 
 /**
- * Create a [PrelinkedLibraryBuilder] corresponding to the given
+ * Create a [LinkedLibraryBuilder] corresponding to the given
  * [definingUnit], which should be the defining compilation unit for a library.
  * Compilation units referenced by the defining compilation unit via `part`
  * declarations will be retrieved using [getPart].  Public namespaces for
@@ -14,8 +15,8 @@
  * declarations (and files reachable from them via `part` and `export`
  * declarations) will be retrieved using [getImport].
  */
-PrelinkedLibraryBuilder prelink(UnlinkedUnit definingUnit,
-    GetPartCallback getPart, GetImportCallback getImport) {
+LinkedLibraryBuilder prelink(UnlinkedUnit definingUnit, GetPartCallback getPart,
+    GetImportCallback getImport) {
   return new _Prelinker(definingUnit, getPart, getImport).prelink();
 }
 
@@ -32,7 +33,7 @@
 
 /**
  * Type of the callback used by the prelinker to obtain unlinked summaries of
- * part files of the library to be prelinked.  [relaviteUri] should be
+ * part files of the library to be prelinked.  [relativeUri] should be
  * interpreted relative to the defining compilation unit of the library being
  * prelinked.
  *
@@ -41,6 +42,16 @@
 typedef UnlinkedUnit GetPartCallback(String relativeUri);
 
 /**
+ * A [_Meaning] representing a class.
+ */
+class _ClassMeaning extends _Meaning {
+  final Map<String, _Meaning> namespace;
+
+  _ClassMeaning(int unit, int dependency, int numTypeParameters, this.namespace)
+      : super(unit, ReferenceKind.classOrEnum, dependency, numTypeParameters);
+}
+
+/**
  * A [_Meaning] stores all the information necessary to find the declaration
  * referred to by a name in a namespace.
  */
@@ -53,7 +64,7 @@
   /**
    * The kind of entity being referred to.
    */
-  final PrelinkedReferenceKind kind;
+  final ReferenceKind kind;
 
   /**
    * Which of the dependencies of the library being prelinked contains the
@@ -70,10 +81,18 @@
   _Meaning(this.unit, this.kind, this.dependency, this.numTypeParameters);
 
   /**
-   * Encode this [_Meaning] as a [PrelinkedReference].
+ * Encode this [_Meaning] as a [LinkedExportName], using the given [name].
+ */
+  LinkedExportName encodeExportName(String name) {
+    return new LinkedExportNameBuilder(
+        name: name, dependency: dependency, unit: unit, kind: kind);
+  }
+
+/**
+   * Encode this [_Meaning] as a [LinkedReference].
    */
-  PrelinkedReferenceBuilder encode() {
-    return encodePrelinkedReference(
+  LinkedReferenceBuilder encodeReference() {
+    return new LinkedReferenceBuilder(
         unit: unit,
         kind: kind,
         dependency: dependency,
@@ -87,7 +106,7 @@
 class _PrefixMeaning extends _Meaning {
   final Map<String, _Meaning> namespace = <String, _Meaning>{};
 
-  _PrefixMeaning() : super(0, PrelinkedReferenceKind.prefix, 0, 0);
+  _PrefixMeaning() : super(0, ReferenceKind.prefix, 0, 0);
 }
 
 /**
@@ -117,15 +136,17 @@
    * Names defined inside the library being prelinked.
    */
   final Map<String, _Meaning> privateNamespace = <String, _Meaning>{
-    '': new _Meaning(0, PrelinkedReferenceKind.classOrEnum, 0, 0)
+    'dynamic': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0),
+    'void': new _Meaning(0, ReferenceKind.classOrEnum, 0, 0)
   };
 
   /**
    * List of dependencies of the library being prelinked.  This will be output
-   * to [PrelinkedLibrary.dependencies].
+   * to [LinkedLibrary.dependencies].
    */
-  final List<PrelinkedDependencyBuilder> dependencies =
-      <PrelinkedDependencyBuilder>[encodePrelinkedDependency()];
+  final List<LinkedDependencyBuilder> dependencies = <LinkedDependencyBuilder>[
+    new LinkedDependencyBuilder()
+  ];
 
   /**
    * Map from the relative URI of a dependent library to the index of the
@@ -157,9 +178,9 @@
     int dependency = dependencies.length;
     uriToDependency[relativeUri] = dependency;
     List<String> unitUris = getUnitUris(relativeUri);
-    PrelinkedDependencyBuilder prelinkedDependency =
-        encodePrelinkedDependency(uri: relativeUri, parts: unitUris.sublist(1));
-    dependencies.add(prelinkedDependency);
+    LinkedDependencyBuilder linkedDependency = new LinkedDependencyBuilder(
+        uri: relativeUri, parts: unitUris.sublist(1));
+    dependencies.add(linkedDependency);
 
     Map<String, _Meaning> aggregated = <String, _Meaning>{};
 
@@ -170,10 +191,19 @@
         continue;
       }
       for (UnlinkedPublicName name in importedNamespace.names) {
-        aggregated.putIfAbsent(
-            name.name,
-            () => new _Meaning(
-                unitNum, name.kind, dependency, name.numTypeParameters));
+        aggregated.putIfAbsent(name.name, () {
+          if (name.kind == ReferenceKind.classOrEnum) {
+            Map<String, _Meaning> namespace = <String, _Meaning>{};
+            name.members.forEach((executable) {
+              namespace[executable.name] = new _Meaning(
+                  unitNum, executable.kind, 0, executable.numTypeParameters);
+            });
+            return new _ClassMeaning(
+                unitNum, dependency, name.numTypeParameters, namespace);
+          }
+          return new _Meaning(
+              unitNum, name.kind, dependency, name.numTypeParameters);
+        });
       }
     }
 
@@ -185,10 +215,14 @@
    * Compute the export namespace for the library whose URI is reachable from
    * [definingUnit] via [relativeUri], by aggregating together public namespace
    * information from the library and the transitive closure of its exports.
+   *
+   * If [relativeUri] is `null` (meaning the export namespace of [definingUnit]
+   * should be computed), then names defined in [definingUnit] are ignored.
    */
   Map<String, _Meaning> computeExportNamespace(String relativeUri) {
-    Map<String, _Meaning> exportNamespace =
-        aggregatePublicNamespace(relativeUri);
+    Map<String, _Meaning> exportNamespace = relativeUri == null
+        ? <String, _Meaning>{}
+        : aggregatePublicNamespace(relativeUri);
     void chaseExports(
         NameFilter filter, String relativeUri, Set<String> seenUris) {
       if (seenUris.add(relativeUri)) {
@@ -197,17 +231,16 @@
         if (exportedNamespace != null) {
           for (UnlinkedExportPublic export in exportedNamespace.exports) {
             String exportUri = resolveUri(relativeUri, export.uri);
+            NameFilter newFilter = filter.merge(
+                new NameFilter.forUnlinkedCombinators(export.combinators));
             aggregatePublicNamespace(exportUri)
                 .forEach((String name, _Meaning meaning) {
-              if (filter.accepts(name) && !exportNamespace.containsKey(name)) {
+              if (newFilter.accepts(name) &&
+                  !exportNamespace.containsKey(name)) {
                 exportNamespace[name] = meaning;
               }
             });
-            chaseExports(
-                filter.merge(
-                    new NameFilter.forUnlinkedCombinators(export.combinators)),
-                exportUri,
-                seenUris);
+            chaseExports(newFilter, exportUri, seenUris);
           }
         }
         seenUris.remove(relativeUri);
@@ -224,32 +257,64 @@
    */
   void extractPrivateNames(UnlinkedUnit unit, int unitNum) {
     for (UnlinkedClass cls in unit.classes) {
-      privateNamespace.putIfAbsent(
-          cls.name,
-          () => new _Meaning(unitNum, PrelinkedReferenceKind.classOrEnum, 0,
-              cls.typeParameters.length));
+      privateNamespace.putIfAbsent(cls.name, () {
+        Map<String, _Meaning> namespace = <String, _Meaning>{};
+        cls.fields.forEach((field) {
+          if (field.isStatic && field.isConst) {
+            namespace[field.name] =
+                new _Meaning(unitNum, ReferenceKind.propertyAccessor, 0, 0);
+          }
+        });
+        cls.executables.forEach((executable) {
+          ReferenceKind kind = null;
+          if (executable.kind == UnlinkedExecutableKind.constructor) {
+            kind = ReferenceKind.constructor;
+          } else if (executable.kind ==
+                  UnlinkedExecutableKind.functionOrMethod &&
+              executable.isStatic) {
+            kind = ReferenceKind.method;
+          }
+          if (kind != null && executable.name.isNotEmpty) {
+            namespace[executable.name] = new _Meaning(
+                unitNum, kind, 0, executable.typeParameters.length);
+          }
+        });
+        return new _ClassMeaning(
+            unitNum, 0, cls.typeParameters.length, namespace);
+      });
     }
     for (UnlinkedEnum enm in unit.enums) {
-      privateNamespace.putIfAbsent(
-          enm.name,
-          () =>
-              new _Meaning(unitNum, PrelinkedReferenceKind.classOrEnum, 0, 0));
+      privateNamespace.putIfAbsent(enm.name,
+          () => new _Meaning(unitNum, ReferenceKind.classOrEnum, 0, 0));
     }
     for (UnlinkedExecutable executable in unit.executables) {
       privateNamespace.putIfAbsent(
           executable.name,
-          () => new _Meaning(unitNum, PrelinkedReferenceKind.other, 0,
+          () => new _Meaning(
+              unitNum,
+              executable.kind == UnlinkedExecutableKind.functionOrMethod
+                  ? ReferenceKind.topLevelFunction
+                  : ReferenceKind.topLevelPropertyAccessor,
+              0,
               executable.typeParameters.length));
     }
     for (UnlinkedTypedef typedef in unit.typedefs) {
       privateNamespace.putIfAbsent(
           typedef.name,
-          () => new _Meaning(unitNum, PrelinkedReferenceKind.typedef, 0,
+          () => new _Meaning(unitNum, ReferenceKind.typedef, 0,
               typedef.typeParameters.length));
     }
     for (UnlinkedVariable variable in unit.variables) {
-      privateNamespace.putIfAbsent(variable.name,
-          () => new _Meaning(unitNum, PrelinkedReferenceKind.other, 0, 0));
+      privateNamespace.putIfAbsent(
+          variable.name,
+          () => new _Meaning(
+              unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
+      if (!(variable.isConst || variable.isFinal)) {
+        privateNamespace.putIfAbsent(
+            variable.name + '=',
+            () => new _Meaning(
+                unitNum, ReferenceKind.topLevelPropertyAccessor, 0, 0));
+      }
     }
   }
 
@@ -328,47 +393,65 @@
   }
 
   /**
-   * Produce a [PrelinkedUnit] for the given [unit], by resolving every one of
+   * Produce a [LinkedUnit] for the given [unit], by resolving every one of
    * its references.
    */
-  PrelinkedUnitBuilder linkUnit(UnlinkedUnit unit) {
+  LinkedUnitBuilder linkUnit(UnlinkedUnit unit) {
     if (unit == null) {
-      return encodePrelinkedUnit();
+      return new LinkedUnitBuilder();
     }
     Map<int, Map<String, _Meaning>> prefixNamespaces =
         <int, Map<String, _Meaning>>{};
-    List<PrelinkedReferenceBuilder> references = <PrelinkedReferenceBuilder>[];
+    List<LinkedReferenceBuilder> references = <LinkedReferenceBuilder>[];
     for (int i = 0; i < unit.references.length; i++) {
       UnlinkedReference reference = unit.references[i];
       Map<String, _Meaning> namespace;
-      if (reference.prefixReference != 0) {
+      if (reference.prefixReference == 0) {
+        namespace = privateNamespace;
+      } else {
         // Prefix references must always point backward.
         assert(reference.prefixReference < i);
         namespace = prefixNamespaces[reference.prefixReference];
+        // If in `a.length` the `a` prefix is a top-level variable or a field,
+        // then it must be the `String.length` property reference.
+        if (namespace == null && reference.name == 'length') {
+          ReferenceKind prefixKind = references[reference.prefixReference].kind;
+          if (prefixKind == ReferenceKind.topLevelPropertyAccessor ||
+              prefixKind == ReferenceKind.propertyAccessor) {
+            references
+                .add(new LinkedReferenceBuilder(kind: ReferenceKind.length));
+            continue;
+          }
+        }
+        // Anything prefixed with 'unresolved' is unresolved.
+        if (references[reference.prefixReference].kind ==
+            ReferenceKind.unresolved) {
+          namespace = const <String, _Meaning>{};
+        }
         // Prefix references must always point to proper prefixes.
         assert(namespace != null);
-      } else {
-        namespace = privateNamespace;
       }
       _Meaning meaning = namespace[reference.name];
       if (meaning != null) {
         if (meaning is _PrefixMeaning) {
           prefixNamespaces[i] = meaning.namespace;
+        } else if (meaning is _ClassMeaning) {
+          prefixNamespaces[i] = meaning.namespace;
         }
-        references.add(meaning.encode());
+        references.add(meaning.encodeReference());
       } else {
-        references.add(
-            encodePrelinkedReference(kind: PrelinkedReferenceKind.unresolved));
+        references
+            .add(new LinkedReferenceBuilder(kind: ReferenceKind.unresolved));
       }
     }
-    return encodePrelinkedUnit(references: references);
+    return new LinkedUnitBuilder(references: references);
   }
 
   /**
-   * Form the [PrelinkedLibrary] for the [definingUnit] that was passed to the
+   * Form the [LinkedLibrary] for the [definingUnit] that was passed to the
    * constructor.
    */
-  PrelinkedLibraryBuilder prelink() {
+  LinkedLibraryBuilder prelink() {
     // Gather up the unlinked summaries for all the compilation units in the
     // library.
     List<UnlinkedUnit> units = getUnitUris(null).map(getPartCached).toList();
@@ -382,6 +465,16 @@
       }
     }
 
+    // Fill in exported names.  This must be done before filling in prefixes
+    // defined in import declarations, because prefixes shouldn't shadow
+    // exports.
+    List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[];
+    computeExportNamespace(null).forEach((String name, _Meaning meaning) {
+      if (!privateNamespace.containsKey(name)) {
+        exportNames.add(meaning.encodeExportName(name));
+      }
+    });
+
     // Fill in prefixes defined in import declarations.
     for (UnlinkedImport import in units[0].imports) {
       if (import.prefixReference != 0) {
@@ -396,12 +489,14 @@
         definingUnit.imports.map(handleImport).toList();
 
     // Link each compilation unit.
-    List<PrelinkedUnitBuilder> linkedUnits = units.map(linkUnit).toList();
+    List<LinkedUnitBuilder> linkedUnits = units.map(linkUnit).toList();
 
-    return encodePrelinkedLibrary(
+    return new LinkedLibraryBuilder(
         units: linkedUnits,
         dependencies: dependencies,
-        importDependencies: importDependencies);
+        importDependencies: importDependencies,
+        exportNames: exportNames,
+        numPrelinkedDependencies: dependencies.length);
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/summary/public_namespace_computer.dart b/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
index e8751b0..3273c9f 100644
--- a/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
+++ b/pkg/analyzer/lib/src/summary/public_namespace_computer.dart
@@ -6,6 +6,7 @@
 
 import 'package:analyzer/analyzer.dart';
 import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
 
 /**
  * Compute the public namespace portion of the summary for the given [unit],
@@ -14,7 +15,7 @@
 UnlinkedPublicNamespaceBuilder computePublicNamespace(CompilationUnit unit) {
   _PublicNamespaceVisitor visitor = new _PublicNamespaceVisitor();
   unit.accept(visitor);
-  return encodeUnlinkedPublicNamespace(
+  return new UnlinkedPublicNamespaceBuilder(
       names: visitor.names, exports: visitor.exports, parts: visitor.parts);
 }
 
@@ -26,12 +27,15 @@
 
   @override
   UnlinkedCombinatorBuilder visitHideCombinator(HideCombinator node) {
-    return encodeUnlinkedCombinator(hides: encodeNames(node.hiddenNames));
+    return new UnlinkedCombinatorBuilder(hides: encodeNames(node.hiddenNames));
   }
 
   @override
   UnlinkedCombinatorBuilder visitShowCombinator(ShowCombinator node) {
-    return encodeUnlinkedCombinator(shows: encodeNames(node.shownNames));
+    return new UnlinkedCombinatorBuilder(
+        shows: encodeNames(node.shownNames),
+        offset: node.offset,
+        end: node.end);
   }
 }
 
@@ -43,36 +47,81 @@
 
   _PublicNamespaceVisitor();
 
-  void addNameIfPublic(
-      String name, PrelinkedReferenceKind kind, int numTypeParameters) {
+  UnlinkedPublicNameBuilder addNameIfPublic(
+      String name, ReferenceKind kind, int numTypeParameters) {
     if (isPublic(name)) {
-      names.add(encodeUnlinkedPublicName(
-          name: name, kind: kind, numTypeParameters: numTypeParameters));
+      UnlinkedPublicNameBuilder b = new UnlinkedPublicNameBuilder(
+          name: name, kind: kind, numTypeParameters: numTypeParameters);
+      names.add(b);
+      return b;
     }
+    return null;
   }
 
   bool isPublic(String name) => !name.startsWith('_');
 
   @override
   visitClassDeclaration(ClassDeclaration node) {
-    addNameIfPublic(node.name.name, PrelinkedReferenceKind.classOrEnum,
+    UnlinkedPublicNameBuilder cls = addNameIfPublic(
+        node.name.name,
+        ReferenceKind.classOrEnum,
         node.typeParameters?.typeParameters?.length ?? 0);
+    if (cls != null) {
+      for (ClassMember member in node.members) {
+        if (member is FieldDeclaration &&
+            member.isStatic &&
+            member.fields.isConst) {
+          for (VariableDeclaration field in member.fields.variables) {
+            String name = field.name.name;
+            if (isPublic(name)) {
+              cls.members.add(new UnlinkedPublicNameBuilder(
+                  name: name,
+                  kind: ReferenceKind.propertyAccessor,
+                  numTypeParameters: 0));
+            }
+          }
+        }
+        if (member is MethodDeclaration &&
+            member.isStatic &&
+            !member.isGetter &&
+            !member.isSetter &&
+            !member.isOperator) {
+          String name = member.name.name;
+          if (isPublic(name)) {
+            cls.members.add(new UnlinkedPublicNameBuilder(
+                name: name,
+                kind: ReferenceKind.method,
+                numTypeParameters:
+                    member.typeParameters?.typeParameters?.length ?? 0));
+          }
+        }
+        if (member is ConstructorDeclaration && member.name != null) {
+          String name = member.name.name;
+          if (isPublic(name)) {
+            cls.members.add(new UnlinkedPublicNameBuilder(
+                name: name,
+                kind: ReferenceKind.constructor,
+                numTypeParameters: 0));
+          }
+        }
+      }
+    }
   }
 
   @override
   visitClassTypeAlias(ClassTypeAlias node) {
-    addNameIfPublic(node.name.name, PrelinkedReferenceKind.classOrEnum,
+    addNameIfPublic(node.name.name, ReferenceKind.classOrEnum,
         node.typeParameters?.typeParameters?.length ?? 0);
   }
 
   @override
   visitEnumDeclaration(EnumDeclaration node) {
-    addNameIfPublic(node.name.name, PrelinkedReferenceKind.classOrEnum, 0);
+    addNameIfPublic(node.name.name, ReferenceKind.classOrEnum, 0);
   }
 
   @override
   visitExportDirective(ExportDirective node) {
-    exports.add(encodeUnlinkedExportPublic(
+    exports.add(new UnlinkedExportPublicBuilder(
         uri: node.uri.stringValue,
         combinators: node.combinators
             .map((Combinator c) => c.accept(new _CombinatorEncoder()))
@@ -85,13 +134,17 @@
     if (node.isSetter) {
       name += '=';
     }
-    addNameIfPublic(name, PrelinkedReferenceKind.other,
+    addNameIfPublic(
+        name,
+        node.isGetter || node.isSetter
+            ? ReferenceKind.topLevelPropertyAccessor
+            : ReferenceKind.topLevelFunction,
         node.functionExpression.typeParameters?.typeParameters?.length ?? 0);
   }
 
   @override
   visitFunctionTypeAlias(FunctionTypeAlias node) {
-    addNameIfPublic(node.name.name, PrelinkedReferenceKind.typedef,
+    addNameIfPublic(node.name.name, ReferenceKind.typedef,
         node.typeParameters?.typeParameters?.length ?? 0);
   }
 
@@ -103,9 +156,9 @@
   @override
   visitVariableDeclaration(VariableDeclaration node) {
     String name = node.name.name;
-    addNameIfPublic(name, PrelinkedReferenceKind.other, 0);
+    addNameIfPublic(name, ReferenceKind.topLevelPropertyAccessor, 0);
     if (!node.isFinal && !node.isConst) {
-      addNameIfPublic('$name=', PrelinkedReferenceKind.other, 0);
+      addNameIfPublic('$name=', ReferenceKind.topLevelPropertyAccessor, 0);
     }
   }
 }
diff --git a/pkg/analyzer/lib/src/summary/resynthesize.dart b/pkg/analyzer/lib/src/summary/resynthesize.dart
index 23b103c..214861a 100644
--- a/pkg/analyzer/lib/src/summary/resynthesize.dart
+++ b/pkg/analyzer/lib/src/summary/resynthesize.dart
@@ -4,40 +4,36 @@
 
 library summary_resynthesizer;
 
-import 'package:analyzer/analyzer.dart';
-import 'package:analyzer/src/generated/element.dart';
+import 'dart:collection';
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.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/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/element_handle.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/summary/format.dart';
-
-/**
- * Callback used by [SummaryResynthesizer] to obtain the prelinked summary for
- * a given URI.
- */
-typedef PrelinkedLibrary GetPrelinkedSummaryCallback(String uri);
-
-/**
- * Callback used by [SummaryResynthesizer] to obtain the unlinked summary for a
- * given URI.
- */
-typedef UnlinkedUnit GetUnlinkedSummaryCallback(String uri);
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
+import 'package:analyzer/src/generated/testing/token_factory.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/idl.dart';
 
 /**
  * Implementation of [ElementResynthesizer] used when resynthesizing an element
  * model from summaries.
  */
-class SummaryResynthesizer extends ElementResynthesizer {
+abstract class SummaryResynthesizer extends ElementResynthesizer {
   /**
-   * Callback used to obtain the prelinked summary for a given URI.
+   * The parent [SummaryResynthesizer] which is asked to resynthesize elements
+   * and get summaries before this resynthesizer attempts to do this.
+   * Can be `null`.
    */
-  final GetPrelinkedSummaryCallback getPrelinkedSummary;
-
-  /**
-   * Callback used to obtain the unlinked summary for a given URI.
-   */
-  final GetUnlinkedSummaryCallback getUnlinkedSummary;
+  final SummaryResynthesizer parent;
 
   /**
    * Source factory used to convert URIs to [Source] objects.
@@ -56,6 +52,20 @@
   final TypeProvider typeProvider;
 
   /**
+   * Indicates whether the summary should be resynthesized assuming strong mode
+   * semantics.
+   */
+  final bool strongMode;
+
+  /**
+   * Map of compilation units resynthesized from summaries.  The two map keys
+   * are the first two elements of the element's location (the library URI and
+   * the compilation unit URI).
+   */
+  final Map<String, Map<String, CompilationUnitElement>> _resynthesizedUnits =
+      <String, Map<String, CompilationUnitElement>>{};
+
+  /**
    * Map of top level elements resynthesized from summaries.  The three map
    * keys are the first three elements of the element's location (the library
    * URI, the compilation unit URI, and the name of the top level declaration).
@@ -70,8 +80,8 @@
   final Map<String, LibraryElement> _resynthesizedLibraries =
       <String, LibraryElement>{};
 
-  SummaryResynthesizer(AnalysisContext context, this.typeProvider,
-      this.getPrelinkedSummary, this.getUnlinkedSummary, this.sourceFactory)
+  SummaryResynthesizer(this.parent, AnalysisContext context, this.typeProvider,
+      this.sourceFactory, this.strongMode)
       : super(context);
 
   /**
@@ -79,28 +89,82 @@
    */
   int get resynthesisCount => _resynthesizedLibraries.length;
 
+  /**
+   * Perform delayed finalization of the `dart:core` and `dart:async` libraries.
+   */
+  void finalizeCoreAsyncLibraries() {
+    (_resynthesizedLibraries['dart:core'] as LibraryElementImpl)
+        .createLoadLibraryFunction(typeProvider);
+    (_resynthesizedLibraries['dart:async'] as LibraryElementImpl)
+        .createLoadLibraryFunction(typeProvider);
+  }
+
   @override
   Element getElement(ElementLocation location) {
-    if (location.components.length == 1) {
-      return getLibraryElement(location.components[0]);
-    } else if (location.components.length == 3) {
-      String uri = location.components[0];
-      Map<String, Map<String, Element>> libraryMap =
-          _resynthesizedElements[uri];
+    List<String> components = location.components;
+    String libraryUri = components[0];
+    // Ask the parent resynthesizer.
+    if (parent != null && parent._hasLibrarySummary(libraryUri)) {
+      return parent.getElement(location);
+    }
+    // Resynthesize locally.
+    if (components.length == 1) {
+      return getLibraryElement(libraryUri);
+    } else if (components.length == 2) {
+      Map<String, CompilationUnitElement> libraryMap =
+          _resynthesizedUnits[libraryUri];
       if (libraryMap == null) {
-        getLibraryElement(uri);
-        libraryMap = _resynthesizedElements[uri];
+        getLibraryElement(libraryUri);
+        libraryMap = _resynthesizedUnits[libraryUri];
         assert(libraryMap != null);
       }
-      Map<String, Element> compilationUnitElements =
-          libraryMap[location.components[1]];
+      String unitUri = components[1];
+      CompilationUnitElement element = libraryMap[unitUri];
+      if (element == null) {
+        throw new Exception('Unit element not found in summary: $location');
+      }
+      return element;
+    } else if (components.length == 3 || components.length == 4) {
+      Map<String, Map<String, Element>> libraryMap =
+          _resynthesizedElements[libraryUri];
+      if (libraryMap == null) {
+        getLibraryElement(libraryUri);
+        libraryMap = _resynthesizedElements[libraryUri];
+        assert(libraryMap != null);
+      }
+      Map<String, Element> compilationUnitElements = libraryMap[components[1]];
+      Element element;
       if (compilationUnitElements != null) {
-        Element element = compilationUnitElements[location.components[2]];
-        if (element != null) {
-          return element;
+        element = compilationUnitElements[components[2]];
+      }
+      if (element != null && components.length == 4) {
+        String name = components[3];
+        Element parentElement = element;
+        if (parentElement is ClassElement) {
+          if (name.endsWith('?')) {
+            element =
+                parentElement.getGetter(name.substring(0, name.length - 1));
+          } else if (name.endsWith('=')) {
+            element =
+                parentElement.getSetter(name.substring(0, name.length - 1));
+          } else if (name.isEmpty) {
+            element = parentElement.unnamedConstructor;
+          } else {
+            element = parentElement.getField(name) ??
+                parentElement.getMethod(name) ??
+                parentElement.getNamedConstructor(name);
+          }
+        } else {
+          // The only elements that are currently retrieved using 4-component
+          // locations are class members.
+          throw new StateError(
+              '4-element locations not supported for ${element.runtimeType}');
         }
       }
-      throw new Exception('Element not found in summary: $location');
+      if (element == null) {
+        throw new Exception('Element not found in summary: $location');
+      }
+      return element;
     } else {
       throw new UnimplementedError(location.toString());
     }
@@ -111,31 +175,614 @@
    * hasn't been resynthesized already.
    */
   LibraryElement getLibraryElement(String uri) {
+    if (parent != null && parent._hasLibrarySummary(uri)) {
+      return parent.getLibraryElement(uri);
+    }
     return _resynthesizedLibraries.putIfAbsent(uri, () {
-      PrelinkedLibrary serializedLibrary = getPrelinkedSummary(uri);
+      LinkedLibrary serializedLibrary = _getLinkedSummaryOrThrow(uri);
       List<UnlinkedUnit> serializedUnits = <UnlinkedUnit>[
-        getUnlinkedSummary(uri)
+        _getUnlinkedSummaryOrThrow(uri)
       ];
       Source librarySource = _getSource(uri);
       for (String part in serializedUnits[0].publicNamespace.parts) {
         Source partSource = sourceFactory.resolveUri(librarySource, part);
         String partAbsUri = partSource.uri.toString();
-        serializedUnits.add(getUnlinkedSummary(partAbsUri));
+        serializedUnits.add(_getUnlinkedSummaryOrThrow(partAbsUri));
       }
       _LibraryResynthesizer libraryResynthesizer = new _LibraryResynthesizer(
           this, serializedLibrary, serializedUnits, librarySource);
       LibraryElement library = libraryResynthesizer.buildLibrary();
-      _resynthesizedElements[uri] = libraryResynthesizer.resummarizedElements;
+      _resynthesizedUnits[uri] = libraryResynthesizer.resynthesizedUnits;
+      _resynthesizedElements[uri] = libraryResynthesizer.resynthesizedElements;
       return library;
     });
   }
 
   /**
+   * Return the [LinkedLibrary] for the given [uri] or `null` if it could not
+   * be found.  Caller has already checked that `parent.hasLibrarySummary(uri)`
+   * returns `false`.
+   */
+  LinkedLibrary getLinkedSummary(String uri);
+
+  /**
+   * Return the [UnlinkedUnit] for the given [uri] or `null` if it could not
+   * be found.  Caller has already checked that `parent.hasLibrarySummary(uri)`
+   * returns `false`.
+   */
+  UnlinkedUnit getUnlinkedSummary(String uri);
+
+  /**
+   * Return `true` if this resynthesizer can provide summaries of the libraries
+   * with the given [uri].  Caller has already checked that
+   * `parent.hasLibrarySummary(uri)` returns `false`.
+   */
+  bool hasLibrarySummary(String uri);
+
+  /**
+   * Return the [LinkedLibrary] for the given [uri] or throw [StateError] if it
+   * could not be found.
+   */
+  LinkedLibrary _getLinkedSummaryOrThrow(String uri) {
+    if (parent != null && parent._hasLibrarySummary(uri)) {
+      return parent._getLinkedSummaryOrThrow(uri);
+    }
+    LinkedLibrary summary = getLinkedSummary(uri);
+    if (summary != null) {
+      return summary;
+    }
+    throw new StateError('Unable to find linked summary: $uri');
+  }
+
+  /**
    * Get the [Source] object for the given [uri].
    */
   Source _getSource(String uri) {
     return _sources.putIfAbsent(uri, () => sourceFactory.forUri(uri));
   }
+
+  /**
+   * Return the [UnlinkedUnit] for the given [uri] or throw [StateError] if it
+   * could not be found.
+   */
+  UnlinkedUnit _getUnlinkedSummaryOrThrow(String uri) {
+    if (parent != null && parent._hasLibrarySummary(uri)) {
+      return parent._getUnlinkedSummaryOrThrow(uri);
+    }
+    UnlinkedUnit summary = getUnlinkedSummary(uri);
+    if (summary != null) {
+      return summary;
+    }
+    throw new StateError('Unable to find unlinked summary: $uri');
+  }
+
+  /**
+   * Return `true` if this resynthesizer can provide summaries of the libraries
+   * with the given [uri].
+   */
+  bool _hasLibrarySummary(String uri) {
+    if (parent != null && parent._hasLibrarySummary(uri)) {
+      return true;
+    }
+    return hasLibrarySummary(uri);
+  }
+}
+
+/**
+ * Builder of [Expression]s from [UnlinkedConst]s.
+ */
+class _ConstExprBuilder {
+  final _LibraryResynthesizer resynthesizer;
+  final UnlinkedConst uc;
+
+  int intPtr = 0;
+  int doublePtr = 0;
+  int stringPtr = 0;
+  int refPtr = 0;
+  final List<Expression> stack = <Expression>[];
+
+  _ConstExprBuilder(this.resynthesizer, this.uc);
+
+  Expression get expr => stack.single;
+
+  Expression build() {
+    if (uc.isInvalid) {
+      return AstFactory.identifier3(r'$$invalidConstExpr$$');
+    }
+    for (UnlinkedConstOperation operation in uc.operations) {
+      switch (operation) {
+        case UnlinkedConstOperation.pushNull:
+          _push(AstFactory.nullLiteral());
+          break;
+        // bool
+        case UnlinkedConstOperation.pushFalse:
+          _push(AstFactory.booleanLiteral(false));
+          break;
+        case UnlinkedConstOperation.pushTrue:
+          _push(AstFactory.booleanLiteral(true));
+          break;
+        // literals
+        case UnlinkedConstOperation.pushInt:
+          int value = uc.ints[intPtr++];
+          _push(AstFactory.integer(value));
+          break;
+        case UnlinkedConstOperation.pushLongInt:
+          int value = 0;
+          int count = uc.ints[intPtr++];
+          for (int i = 0; i < count; i++) {
+            int next = uc.ints[intPtr++];
+            value = value << 32 | next;
+          }
+          _push(AstFactory.integer(value));
+          break;
+        case UnlinkedConstOperation.pushDouble:
+          double value = uc.doubles[doublePtr++];
+          _push(AstFactory.doubleLiteral(value));
+          break;
+        case UnlinkedConstOperation.makeSymbol:
+          String component = uc.strings[stringPtr++];
+          _push(AstFactory.symbolLiteral([component]));
+          break;
+        // String
+        case UnlinkedConstOperation.pushString:
+          String value = uc.strings[stringPtr++];
+          _push(AstFactory.string2(value));
+          break;
+        case UnlinkedConstOperation.concatenate:
+          int count = uc.ints[intPtr++];
+          List<InterpolationElement> elements = <InterpolationElement>[];
+          for (int i = 0; i < count; i++) {
+            Expression expr = _pop();
+            InterpolationElement element = _newInterpolationElement(expr);
+            elements.insert(0, element);
+          }
+          _push(AstFactory.string(elements));
+          break;
+        // binary
+        case UnlinkedConstOperation.equal:
+          _pushBinary(TokenType.EQ_EQ);
+          break;
+        case UnlinkedConstOperation.notEqual:
+          _pushBinary(TokenType.BANG_EQ);
+          break;
+        case UnlinkedConstOperation.and:
+          _pushBinary(TokenType.AMPERSAND_AMPERSAND);
+          break;
+        case UnlinkedConstOperation.or:
+          _pushBinary(TokenType.BAR_BAR);
+          break;
+        case UnlinkedConstOperation.bitXor:
+          _pushBinary(TokenType.CARET);
+          break;
+        case UnlinkedConstOperation.bitAnd:
+          _pushBinary(TokenType.AMPERSAND);
+          break;
+        case UnlinkedConstOperation.bitOr:
+          _pushBinary(TokenType.BAR);
+          break;
+        case UnlinkedConstOperation.bitShiftLeft:
+          _pushBinary(TokenType.LT_LT);
+          break;
+        case UnlinkedConstOperation.bitShiftRight:
+          _pushBinary(TokenType.GT_GT);
+          break;
+        case UnlinkedConstOperation.add:
+          _pushBinary(TokenType.PLUS);
+          break;
+        case UnlinkedConstOperation.subtract:
+          _pushBinary(TokenType.MINUS);
+          break;
+        case UnlinkedConstOperation.multiply:
+          _pushBinary(TokenType.STAR);
+          break;
+        case UnlinkedConstOperation.divide:
+          _pushBinary(TokenType.SLASH);
+          break;
+        case UnlinkedConstOperation.floorDivide:
+          _pushBinary(TokenType.TILDE_SLASH);
+          break;
+        case UnlinkedConstOperation.modulo:
+          _pushBinary(TokenType.PERCENT);
+          break;
+        case UnlinkedConstOperation.greater:
+          _pushBinary(TokenType.GT);
+          break;
+        case UnlinkedConstOperation.greaterEqual:
+          _pushBinary(TokenType.GT_EQ);
+          break;
+        case UnlinkedConstOperation.less:
+          _pushBinary(TokenType.LT);
+          break;
+        case UnlinkedConstOperation.lessEqual:
+          _pushBinary(TokenType.LT_EQ);
+          break;
+        // prefix
+        case UnlinkedConstOperation.complement:
+          _pushPrefix(TokenType.TILDE);
+          break;
+        case UnlinkedConstOperation.negate:
+          _pushPrefix(TokenType.MINUS);
+          break;
+        case UnlinkedConstOperation.not:
+          _pushPrefix(TokenType.BANG);
+          break;
+        // conditional
+        case UnlinkedConstOperation.conditional:
+          Expression elseExpr = _pop();
+          Expression thenExpr = _pop();
+          Expression condition = _pop();
+          _push(
+              AstFactory.conditionalExpression(condition, thenExpr, elseExpr));
+          break;
+        // identical
+        case UnlinkedConstOperation.identical:
+          Expression second = _pop();
+          Expression first = _pop();
+          _push(AstFactory.methodInvocation(
+              null, 'identical', <Expression>[first, second]));
+          break;
+        // containers
+        case UnlinkedConstOperation.makeUntypedList:
+          _pushList(null);
+          break;
+        case UnlinkedConstOperation.makeTypedList:
+          TypeName itemType = _newTypeName();
+          _pushList(AstFactory.typeArgumentList(<TypeName>[itemType]));
+          break;
+        case UnlinkedConstOperation.makeUntypedMap:
+          _pushMap(null);
+          break;
+        case UnlinkedConstOperation.makeTypedMap:
+          TypeName keyType = _newTypeName();
+          TypeName valueType = _newTypeName();
+          _pushMap(AstFactory.typeArgumentList(<TypeName>[keyType, valueType]));
+          break;
+        case UnlinkedConstOperation.pushReference:
+          EntityRef ref = uc.references[refPtr++];
+          _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
+          if (info.enclosing != null &&
+              info.enclosing.element != null &&
+              info.enclosing.element is! ClassElement) {
+            SimpleIdentifier prefix = AstFactory.identifier3(
+                info.enclosing.name)..staticElement = info.enclosing.element;
+            SimpleIdentifier name = AstFactory.identifier3(info.name)
+              ..staticElement = info.element;
+            PrefixedIdentifier node = AstFactory.identifier(prefix, name);
+            _push(node);
+          } else {
+            SimpleIdentifier node = AstFactory.identifier3(info.name);
+            node.staticElement = info.element;
+            _push(node);
+          }
+          break;
+        case UnlinkedConstOperation.invokeConstructor:
+          _pushInstanceCreation();
+          break;
+        case UnlinkedConstOperation.length:
+          Expression target = _pop();
+          SimpleIdentifier property = AstFactory.identifier3('length');
+          property.staticElement =
+              resynthesizer._buildStringLengthPropertyAccessorElement();
+          _push(AstFactory.propertyAccess(target, property));
+          break;
+        case UnlinkedConstOperation.pushConstructorParameter:
+          String name = uc.strings[stringPtr++];
+          SimpleIdentifier identifier = AstFactory.identifier3(name);
+          identifier.staticElement = resynthesizer.currentConstructor.parameters
+              .firstWhere((parameter) => parameter.name == name,
+                  orElse: () => throw new StateError(
+                      'Unable to resolve constructor parameter: $name'));
+          _push(identifier);
+          break;
+      }
+    }
+    return stack.single;
+  }
+
+  TypeName _buildTypeAst(DartType type) {
+    if (type is DynamicTypeImpl) {
+      TypeName node = AstFactory.typeName4('dynamic');
+      node.type = type;
+      (node.name as SimpleIdentifier).staticElement = type.element;
+      return node;
+    } else if (type is InterfaceType) {
+      List<DartType> typeArguments = type.typeArguments;
+      List<TypeName> argumentNodes = typeArguments.every((a) => a.isDynamic)
+          ? null
+          : typeArguments.map(_buildTypeAst).toList();
+      TypeName node = AstFactory.typeName4(type.name, argumentNodes);
+      node.type = type;
+      (node.name as SimpleIdentifier).staticElement = type.element;
+      return node;
+    }
+    throw new StateError('Unsupported type $type');
+  }
+
+  InterpolationElement _newInterpolationElement(Expression expr) {
+    if (expr is SimpleStringLiteral) {
+      return new InterpolationString(expr.literal, expr.value);
+    } else {
+      return new InterpolationExpression(
+          TokenFactory.tokenFromType(TokenType.STRING_INTERPOLATION_EXPRESSION),
+          expr,
+          TokenFactory.tokenFromType(TokenType.CLOSE_CURLY_BRACKET));
+    }
+  }
+
+  /**
+   * Convert the next reference to the [DartType] and return the AST
+   * corresponding to this type.
+   */
+  TypeName _newTypeName() {
+    EntityRef typeRef = uc.references[refPtr++];
+    DartType type = resynthesizer.buildType(typeRef);
+    return _buildTypeAst(type);
+  }
+
+  Expression _pop() => stack.removeLast();
+
+  void _push(Expression expr) {
+    stack.add(expr);
+  }
+
+  void _pushBinary(TokenType operator) {
+    Expression right = _pop();
+    Expression left = _pop();
+    _push(AstFactory.binaryExpression(left, operator, right));
+  }
+
+  void _pushInstanceCreation() {
+    EntityRef ref = uc.references[refPtr++];
+    _ReferenceInfo info = resynthesizer.referenceInfos[ref.reference];
+    // prepare ConstructorElement
+    TypeName typeNode;
+    String constructorName;
+    ConstructorElement constructorElement;
+    if (info.element != null) {
+      if (info.element is ConstructorElement) {
+        constructorName = info.name;
+      } else if (info.element is ClassElement) {
+        constructorName = null;
+      } else {
+        throw new StateError('Unsupported element for invokeConstructor '
+            '${info.element?.runtimeType}');
+      }
+      InterfaceType definingType =
+          resynthesizer._createConstructorDefiningType(info, ref.typeArguments);
+      constructorElement =
+          resynthesizer._createConstructorElement(definingType, info);
+      typeNode = _buildTypeAst(definingType);
+    } else {
+      if (info.enclosing != null) {
+        if (info.enclosing.enclosing != null) {
+          PrefixedIdentifier typeName = AstFactory.identifier5(
+              info.enclosing.enclosing.name, info.enclosing.name);
+          typeName.prefix.staticElement = info.enclosing.enclosing.element;
+          typeName.identifier.staticElement = info.enclosing.element;
+          typeName.identifier.staticType = info.enclosing.type;
+          typeNode = AstFactory.typeName3(typeName);
+          typeNode.type = info.enclosing.type;
+          constructorName = info.name;
+        } else if (info.enclosing.element != null) {
+          SimpleIdentifier typeName =
+              AstFactory.identifier3(info.enclosing.name);
+          typeName.staticElement = info.enclosing.element;
+          typeName.staticType = info.enclosing.type;
+          typeNode = AstFactory.typeName3(typeName);
+          typeNode.type = info.enclosing.type;
+          constructorName = info.name;
+        } else {
+          typeNode = AstFactory.typeName3(
+              AstFactory.identifier5(info.enclosing.name, info.name));
+          constructorName = null;
+        }
+      } else {
+        typeNode = AstFactory.typeName4(info.name);
+      }
+    }
+    // prepare arguments
+    List<Expression> arguments;
+    {
+      int numNamedArgs = uc.ints[intPtr++];
+      int numPositionalArgs = uc.ints[intPtr++];
+      int numArgs = numNamedArgs + numPositionalArgs;
+      arguments = _removeTopItems(numArgs);
+      // add names to the named arguments
+      for (int i = 0; i < numNamedArgs; i++) {
+        String name = uc.strings[stringPtr++];
+        int index = numPositionalArgs + i;
+        arguments[index] = AstFactory.namedExpression2(name, arguments[index]);
+      }
+    }
+    // create ConstructorName
+    ConstructorName constructorNode;
+    if (constructorName != null) {
+      constructorNode = AstFactory.constructorName(typeNode, constructorName);
+      constructorNode.name.staticElement = constructorElement;
+    } else {
+      constructorNode = AstFactory.constructorName(typeNode, null);
+    }
+    constructorNode.staticElement = constructorElement;
+    // create InstanceCreationExpression
+    InstanceCreationExpression instanceCreation = AstFactory
+        .instanceCreationExpression(Keyword.CONST, constructorNode, arguments);
+    instanceCreation.staticElement = constructorElement;
+    _push(instanceCreation);
+  }
+
+  void _pushList(TypeArgumentList typeArguments) {
+    int count = uc.ints[intPtr++];
+    List<Expression> elements = <Expression>[];
+    for (int i = 0; i < count; i++) {
+      elements.insert(0, _pop());
+    }
+    _push(AstFactory.listLiteral2(Keyword.CONST, typeArguments, elements));
+  }
+
+  void _pushMap(TypeArgumentList typeArguments) {
+    int count = uc.ints[intPtr++];
+    List<MapLiteralEntry> entries = <MapLiteralEntry>[];
+    for (int i = 0; i < count; i++) {
+      Expression value = _pop();
+      Expression key = _pop();
+      entries.insert(0, AstFactory.mapLiteralEntry2(key, value));
+    }
+    _push(AstFactory.mapLiteral(Keyword.CONST, typeArguments, entries));
+  }
+
+  void _pushPrefix(TokenType operator) {
+    Expression operand = _pop();
+    _push(AstFactory.prefixExpression(operator, operand));
+  }
+
+  List<Expression> _removeTopItems(int count) {
+    int start = stack.length - count;
+    int end = stack.length;
+    List<Expression> items = stack.getRange(start, end).toList();
+    stack.removeRange(start, end);
+    return items;
+  }
+}
+
+/**
+ * The constructor element that has been resynthesized from a summary.  The
+ * actual element won't be constructed until it is requested.  But properties
+ * [displayName], [enclosingElement] and [name] can be used without creating
+ * the actual element.
+ */
+class _DeferredConstructorElement extends ConstructorElementHandle {
+  /**
+   * The type defining this constructor element.  If [_isMember] is `false`,
+   * then the type parameters of [_definingType] are not guaranteed to be
+   * valid.
+   */
+  final InterfaceType _definingType;
+
+  /**
+   * The constructor name.
+   */
+  final String name;
+
+  factory _DeferredConstructorElement(InterfaceType definingType, String name) {
+    List<String> components = definingType.element.location.components.toList();
+    components.add(name);
+    ElementLocationImpl location = new ElementLocationImpl.con3(components);
+    return new _DeferredConstructorElement._(definingType, name, location);
+  }
+
+  _DeferredConstructorElement._(
+      this._definingType, this.name, ElementLocation location)
+      : super(null, location);
+
+  @override
+  Element get actualElement => enclosingElement.getNamedConstructor(name);
+
+  @override
+  AnalysisContext get context => _definingType.element.context;
+
+  @override
+  String get displayName => name;
+
+  @override
+  ClassElement get enclosingElement {
+    return _definingType.element;
+  }
+}
+
+/**
+ * Local function element representing the intializer for a variable that has
+ * been resynthesized from a summary.  The actual element won't be constructed
+ * until it is requested.  But properties [context] and [enclosingElement] can
+ * be used without creating the actual element.
+ */
+class _DeferredInitializerElement extends FunctionElementHandle {
+  /**
+   * The variable element containing this element.
+   */
+  @override
+  final VariableElement enclosingElement;
+
+  _DeferredInitializerElement(this.enclosingElement) : super(null, null);
+
+  @override
+  FunctionElement get actualElement => enclosingElement.initializer;
+
+  @override
+  AnalysisContext get context => enclosingElement.context;
+
+  @override
+  ElementLocation get location => actualElement.location;
+}
+
+/**
+ * Local function element that has been resynthesized from a summary.  The
+ * actual element won't be constructed until it is requested.  But properties
+ * [context] and [enclosingElement] can be used without creating the actual
+ * element.
+ */
+class _DeferredLocalFunctionElement extends FunctionElementHandle {
+  /**
+   * The executable element containing this element.
+   */
+  @override
+  final ExecutableElement enclosingElement;
+
+  /**
+   * The index of this function within [ExecutableElement.functions].
+   */
+  final int _localIndex;
+
+  _DeferredLocalFunctionElement(this.enclosingElement, this._localIndex)
+      : super(null, null);
+
+  @override
+  FunctionElement get actualElement {
+    ExecutableElement enclosingElement = this.enclosingElement;
+    if (enclosingElement is PropertyAccessorElement &&
+        enclosingElement.isSynthetic) {
+      return enclosingElement.variable.initializer;
+    } else {
+      return enclosingElement.functions[_localIndex];
+    }
+  }
+
+  @override
+  AnalysisContext get context => enclosingElement.context;
+
+  @override
+  ElementLocation get location => actualElement.location;
+}
+
+/**
+ * Local variable element that has been resynthesized from a summary.  The
+ * actual element won't be constructed until it is requested.  But properties
+ * [context] and [enclosingElement] can be used without creating the actual
+ * element.
+ */
+class _DeferredLocalVariableElement extends LocalVariableElementHandle {
+  /**
+   * The executable element containing this element.
+   */
+  @override
+  final ExecutableElement enclosingElement;
+
+  /**
+   * The index of this variable within [ExecutableElement.localVariables].
+   */
+  final int _localIndex;
+
+  _DeferredLocalVariableElement(this.enclosingElement, this._localIndex)
+      : super(null, null);
+
+  @override
+  LocalVariableElement get actualElement =>
+      enclosingElement.localVariables[_localIndex];
+
+  @override
+  AnalysisContext get context => enclosingElement.context;
+
+  @override
+  ElementLocation get location => actualElement.location;
 }
 
 /**
@@ -149,9 +796,9 @@
   final SummaryResynthesizer summaryResynthesizer;
 
   /**
-   * Prelinked summary of the library to be resynthesized.
+   * Linked summary of the library to be resynthesized.
    */
-  final PrelinkedLibrary prelinkedLibrary;
+  final LinkedLibrary linkedLibrary;
 
   /**
    * Unlinked compilation units constituting the library to be resynthesized.
@@ -182,9 +829,9 @@
   ElementHolder unitHolder;
 
   /**
-   * The [PrelinkedUnit] from which elements are currently being resynthesized.
+   * The [LinkedUnit] from which elements are currently being resynthesized.
    */
-  PrelinkedUnit prelinkedUnit;
+  LinkedUnit linkedUnit;
 
   /**
    * The [UnlinkedUnit] from which elements are currently being resynthesized.
@@ -192,107 +839,187 @@
   UnlinkedUnit unlinkedUnit;
 
   /**
+   * Map from slot id to the corresponding [EntityRef] object for linked types
+   * (i.e. propagated and inferred types).
+   */
+  Map<int, EntityRef> linkedTypeMap;
+
+  /**
+   * The [CompilationUnitElementImpl] for the compilation unit currently being
+   * resynthesized.
+   */
+  CompilationUnitElementImpl currentCompilationUnit;
+
+  /**
+   * The [ConstructorElementImpl] for the constructor currently being
+   * resynthesized.
+   */
+  ConstructorElementImpl currentConstructor;
+
+  /**
+   * Map of compilation unit elements that have been resynthesized so far.  The
+   * key is the URI of the compilation unit.
+   */
+  final Map<String, CompilationUnitElement> resynthesizedUnits =
+      <String, CompilationUnitElement>{};
+
+  /**
    * Map of top level elements that have been resynthesized so far.  The first
    * key is the URI of the compilation unit; the second is the name of the top
    * level element.
    */
-  final Map<String, Map<String, Element>> resummarizedElements =
+  final Map<String, Map<String, Element>> resynthesizedElements =
       <String, Map<String, Element>>{};
 
   /**
    * Type parameters for the generic class, typedef, or executable currently
-   * being resynthesized, if any.  If multiple entities with type parameters
-   * are nested (e.g. a generic executable inside a generic class), this is the
-   * concatenation of all type parameters from all declarations currently in
-   * force, with the outermost declaration appearing first.  If there are no
-   * type parameters, or we are not currently resynthesizing a class, typedef,
-   * or executable, then this is an empty list.
+   * being resynthesized, if any.  This is a list of lists; if multiple
+   * entities with type parameters are nested (e.g. a generic executable inside
+   * a generic class), then the zeroth element of [currentTypeParameters]
+   * contains the type parameters for the outermost nested entity, and further
+   * elements contain the type parameters for entities that are more deeply
+   * nested.  If we are not currently resynthesizing a class, typedef, or
+   * executable, then this is an empty list.
    */
-  List<TypeParameterElement> currentTypeParameters = <TypeParameterElement>[];
+  final List<List<TypeParameterElement>> currentTypeParameters =
+      <List<TypeParameterElement>>[];
 
-  _LibraryResynthesizer(this.summaryResynthesizer, this.prelinkedLibrary,
+  /**
+   * If a class is currently being resynthesized, map from field name to the
+   * corresponding field element.  This is used when resynthesizing
+   * initializing formal parameters.
+   */
+  Map<String, FieldElementImpl> fields;
+
+  /**
+   * If a class is currently being resynthesized, map from constructor name to
+   * the corresponding constructor element.  This is used when resynthesizing
+   * constructor initializers.
+   */
+  Map<String, ConstructorElementImpl> constructors;
+
+  /**
+   * List of [_ReferenceInfo] objects describing the references in the current
+   * compilation unit.
+   */
+  List<_ReferenceInfo> referenceInfos;
+
+  _LibraryResynthesizer(this.summaryResynthesizer, this.linkedLibrary,
       this.unlinkedUnits, this.librarySource) {
     isCoreLibrary = librarySource.uri.toString() == 'dart:core';
   }
 
   /**
-   * Return a list of type arguments corresponding to [currentTypeParameters].
+   * Build the annotations for the given [element].
    */
-  List<TypeParameterType> get currentTypeArguments => currentTypeParameters
-      ?.map((TypeParameterElement param) => param.type)
-      ?.toList();
+  void buildAnnotations(
+      ElementImpl element, List<UnlinkedConst> serializedAnnotations) {
+    if (serializedAnnotations.isNotEmpty) {
+      element.metadata = serializedAnnotations.map((UnlinkedConst a) {
+        ElementAnnotationImpl elementAnnotation =
+            new ElementAnnotationImpl(this.currentCompilationUnit);
+        Expression constExpr = _buildConstExpression(a);
+        if (constExpr is Identifier) {
+          elementAnnotation.element = constExpr.staticElement;
+          elementAnnotation.annotationAst = AstFactory.annotation(constExpr);
+        } else if (constExpr is InstanceCreationExpression) {
+          elementAnnotation.element = constExpr.staticElement;
+          Identifier typeName = constExpr.constructorName.type.name;
+          SimpleIdentifier constructorName = constExpr.constructorName.name;
+          if (typeName is SimpleIdentifier && constructorName != null) {
+            // E.g. `@cls.ctor()`.  Since `cls.ctor` would have been parsed as
+            // a PrefixedIdentifier, we need to resynthesize it as one.
+            typeName = AstFactory.identifier(typeName, constructorName);
+            constructorName = null;
+          }
+          elementAnnotation.annotationAst = AstFactory.annotation2(
+              typeName, constructorName, constExpr.argumentList);
+        } else {
+          throw new StateError(
+              'Unexpected annotation type: ${constExpr.runtimeType}');
+        }
+        return elementAnnotation;
+      }).toList();
+    }
+  }
 
   /**
    * Resynthesize a [ClassElement] and place it in [unitHolder].
    */
   void buildClass(UnlinkedClass serializedClass) {
-    try {
-      currentTypeParameters =
-          serializedClass.typeParameters.map(buildTypeParameter).toList();
-      for (int i = 0; i < serializedClass.typeParameters.length; i++) {
-        finishTypeParameter(
-            serializedClass.typeParameters[i], currentTypeParameters[i]);
+    ClassElementImpl classElement =
+        new ClassElementImpl(serializedClass.name, serializedClass.nameOffset);
+    classElement.hasBeenInferred = summaryResynthesizer.strongMode;
+    classElement.typeParameters =
+        buildTypeParameters(serializedClass.typeParameters);
+    classElement.abstract = serializedClass.isAbstract;
+    classElement.mixinApplication = serializedClass.isMixinApplication;
+    InterfaceTypeImpl correspondingType = new InterfaceTypeImpl(classElement);
+    if (serializedClass.supertype != null) {
+      classElement.supertype = buildType(serializedClass.supertype);
+    } else if (!serializedClass.hasNoSupertype) {
+      if (isCoreLibrary) {
+        delayedObjectSubclasses.add(classElement);
+      } else {
+        classElement.supertype = summaryResynthesizer.typeProvider.objectType;
       }
-      ClassElementImpl classElement = new ClassElementImpl(
-          serializedClass.name, serializedClass.nameOffset);
-      classElement.mixinApplication = serializedClass.isMixinApplication;
-      InterfaceTypeImpl correspondingType = new InterfaceTypeImpl(classElement);
-      if (serializedClass.supertype != null) {
-        classElement.supertype = buildType(serializedClass.supertype);
-      } else if (!serializedClass.hasNoSupertype) {
-        if (isCoreLibrary) {
-          delayedObjectSubclasses.add(classElement);
-        } else {
-          classElement.supertype = summaryResynthesizer.typeProvider.objectType;
-        }
-      }
-      classElement.interfaces =
-          serializedClass.interfaces.map(buildType).toList();
-      classElement.mixins = serializedClass.mixins.map(buildType).toList();
-      classElement.typeParameters = currentTypeParameters;
-      ElementHolder memberHolder = new ElementHolder();
-      bool constructorFound = false;
-      for (UnlinkedExecutable serializedExecutable
-          in serializedClass.executables) {
-        switch (serializedExecutable.kind) {
-          case UnlinkedExecutableKind.constructor:
-            constructorFound = true;
-            buildConstructor(
-                serializedExecutable, memberHolder, correspondingType);
-            break;
-          case UnlinkedExecutableKind.functionOrMethod:
-          case UnlinkedExecutableKind.getter:
-          case UnlinkedExecutableKind.setter:
-            buildExecutable(serializedExecutable, memberHolder);
-            break;
-        }
-      }
-      for (UnlinkedVariable serializedVariable in serializedClass.fields) {
-        buildVariable(serializedVariable, memberHolder);
-      }
-      if (!serializedClass.isMixinApplication) {
-        if (!constructorFound) {
-          // Synthesize implicit constructors.
-          ConstructorElementImpl constructor =
-              new ConstructorElementImpl('', -1);
-          constructor.synthetic = true;
-          constructor.returnType = correspondingType;
-          constructor.type = new FunctionTypeImpl.elementWithNameAndArgs(
-              constructor, null, currentTypeArguments, false);
-          memberHolder.addConstructor(constructor);
-        }
-        classElement.constructors = memberHolder.constructors;
-      }
-      classElement.accessors = memberHolder.accessors;
-      classElement.fields = memberHolder.fields;
-      classElement.methods = memberHolder.methods;
-      correspondingType.typeArguments = currentTypeArguments;
-      classElement.type = correspondingType;
-      buildDocumentation(classElement, serializedClass.documentationComment);
-      unitHolder.addType(classElement);
-    } finally {
-      currentTypeParameters = <TypeParameterElement>[];
     }
+    classElement.interfaces =
+        serializedClass.interfaces.map(buildType).toList();
+    classElement.mixins = serializedClass.mixins.map(buildType).toList();
+    ElementHolder memberHolder = new ElementHolder();
+    fields = <String, FieldElementImpl>{};
+    for (UnlinkedVariable serializedVariable in serializedClass.fields) {
+      buildVariable(serializedVariable, memberHolder);
+    }
+    bool constructorFound = false;
+    constructors = <String, ConstructorElementImpl>{};
+    for (UnlinkedExecutable serializedExecutable
+        in serializedClass.executables) {
+      switch (serializedExecutable.kind) {
+        case UnlinkedExecutableKind.constructor:
+          constructorFound = true;
+          buildConstructor(
+              serializedExecutable, memberHolder, correspondingType);
+          break;
+        case UnlinkedExecutableKind.functionOrMethod:
+        case UnlinkedExecutableKind.getter:
+        case UnlinkedExecutableKind.setter:
+          if (serializedExecutable.isStatic) {
+            currentTypeParameters.removeLast();
+          }
+          buildExecutable(serializedExecutable, memberHolder);
+          if (serializedExecutable.isStatic) {
+            currentTypeParameters.add(classElement.typeParameters);
+          }
+          break;
+      }
+    }
+    if (!serializedClass.isMixinApplication) {
+      if (!constructorFound) {
+        // Synthesize implicit constructors.
+        ConstructorElementImpl constructor = new ConstructorElementImpl('', -1);
+        constructor.synthetic = true;
+        constructor.returnType = correspondingType;
+        constructor.type = new FunctionTypeImpl.elementWithNameAndArgs(
+            constructor, null, getCurrentTypeArguments(), false);
+        memberHolder.addConstructor(constructor);
+      }
+      classElement.constructors = memberHolder.constructors;
+    }
+    classElement.accessors = memberHolder.accessors;
+    classElement.fields = memberHolder.fields;
+    classElement.methods = memberHolder.methods;
+    correspondingType.typeArguments = getCurrentTypeArguments();
+    classElement.type = correspondingType;
+    buildDocumentation(classElement, serializedClass.documentationComment);
+    buildAnnotations(classElement, serializedClass.annotations);
+    resolveConstructorInitializers(classElement);
+    unitHolder.addType(classElement);
+    currentTypeParameters.removeLast();
+    assert(currentTypeParameters.isEmpty);
+    fields = null;
+    constructors = null;
   }
 
   /**
@@ -304,6 +1031,8 @@
       // Note: we call toList() so that we don't retain a reference to the
       // deserialized data structure.
       combinator.shownNames = serializedCombinator.shows.toList();
+      combinator.offset = serializedCombinator.offset;
+      combinator.end = serializedCombinator.end;
       return combinator;
     } else {
       HideElementCombinatorImpl combinator = new HideElementCombinatorImpl();
@@ -315,6 +1044,29 @@
   }
 
   /**
+   * Resynthesize the [ConstructorInitializer] in context of
+   * [currentConstructor], which is used to resolve constructor parameter names.
+   */
+  ConstructorInitializer buildConstantInitializer(
+      UnlinkedConstructorInitializer serialized) {
+    UnlinkedConstructorInitializerKind kind = serialized.kind;
+    String name = serialized.name;
+    List<Expression> arguments =
+        serialized.arguments.map(_buildConstExpression).toList();
+    switch (kind) {
+      case UnlinkedConstructorInitializerKind.field:
+        return AstFactory.constructorFieldInitializer(
+            false, name, _buildConstExpression(serialized.expression));
+      case UnlinkedConstructorInitializerKind.superInvocation:
+        return AstFactory.superConstructorInvocation2(
+            name.isNotEmpty ? name : null, arguments);
+      case UnlinkedConstructorInitializerKind.thisInvocation:
+        return AstFactory.redirectingConstructorInvocation2(
+            name.isNotEmpty ? name : null, arguments);
+    }
+  }
+
+  /**
    * Resynthesize a [ConstructorElement] and place it in the given [holder].
    * [classType] is the type of the class for which this element is a
    * constructor.
@@ -322,13 +1074,46 @@
   void buildConstructor(UnlinkedExecutable serializedExecutable,
       ElementHolder holder, InterfaceType classType) {
     assert(serializedExecutable.kind == UnlinkedExecutableKind.constructor);
-    ConstructorElementImpl constructorElement = new ConstructorElementImpl(
+    currentConstructor = new ConstructorElementImpl(
         serializedExecutable.name, serializedExecutable.nameOffset);
-    constructorElement.returnType = classType;
-    buildExecutableCommonParts(constructorElement, serializedExecutable);
-    constructorElement.factory = serializedExecutable.isFactory;
-    constructorElement.const2 = serializedExecutable.isConst;
-    holder.addConstructor(constructorElement);
+    if (serializedExecutable.name.isEmpty) {
+      currentConstructor.nameEnd =
+          serializedExecutable.nameOffset + classType.name.length;
+    } else {
+      currentConstructor.nameEnd = serializedExecutable.nameEnd;
+      currentConstructor.periodOffset = serializedExecutable.periodOffset;
+    }
+    constructors[serializedExecutable.name] = currentConstructor;
+    currentConstructor.returnType = classType;
+    buildExecutableCommonParts(currentConstructor, serializedExecutable);
+    currentConstructor.factory = serializedExecutable.isFactory;
+    currentConstructor.const2 = serializedExecutable.isConst;
+    currentConstructor.constantInitializers = serializedExecutable
+        .constantInitializers
+        .map(buildConstantInitializer)
+        .toList();
+    if (serializedExecutable.isRedirectedConstructor) {
+      if (serializedExecutable.isFactory) {
+        EntityRef redirectedConstructor =
+            serializedExecutable.redirectedConstructor;
+        _ReferenceInfo info = referenceInfos[redirectedConstructor.reference];
+        List<EntityRef> typeArguments = redirectedConstructor.typeArguments;
+        currentConstructor.redirectedConstructor = _createConstructorElement(
+            _createConstructorDefiningType(info, typeArguments), info);
+      } else {
+        List<String> locationComponents =
+            currentCompilationUnit.location.components.toList();
+        locationComponents.add(classType.name);
+        locationComponents.add(serializedExecutable.redirectedConstructorName);
+        currentConstructor.redirectedConstructor =
+            new _DeferredConstructorElement._(
+                classType,
+                serializedExecutable.redirectedConstructorName,
+                new ElementLocationImpl.con3(locationComponents));
+      }
+    }
+    holder.addConstructor(currentConstructor);
+    currentConstructor = null;
   }
 
   /**
@@ -350,7 +1135,6 @@
    */
   void buildEnum(UnlinkedEnum serializedEnum) {
     assert(!isCoreLibrary);
-    // TODO(paulberry): add offset support (for this element type and others)
     ClassElementImpl classElement =
         new ClassElementImpl(serializedEnum.name, serializedEnum.nameOffset);
     classElement.enum2 = true;
@@ -358,13 +1142,16 @@
     classElement.type = enumType;
     classElement.supertype = summaryResynthesizer.typeProvider.objectType;
     buildDocumentation(classElement, serializedEnum.documentationComment);
+    buildAnnotations(classElement, serializedEnum.annotations);
     ElementHolder memberHolder = new ElementHolder();
+    // Build the 'index' field.
     FieldElementImpl indexField = new FieldElementImpl('index', -1);
     indexField.final2 = true;
     indexField.synthetic = true;
     indexField.type = summaryResynthesizer.typeProvider.intType;
     memberHolder.addField(indexField);
     buildImplicitAccessors(indexField, memberHolder);
+    // Build the 'values' field.
     FieldElementImpl valuesField = new ConstFieldElementImpl('values', -1);
     valuesField.synthetic = true;
     valuesField.const3 = true;
@@ -373,15 +1160,34 @@
         .substitute4(<DartType>[enumType]);
     memberHolder.addField(valuesField);
     buildImplicitAccessors(valuesField, memberHolder);
-    for (UnlinkedEnumValue serializedEnumValue in serializedEnum.values) {
-      ConstFieldElementImpl valueField = new ConstFieldElementImpl(
-          serializedEnumValue.name, serializedEnumValue.nameOffset);
-      valueField.const3 = true;
-      valueField.static = true;
-      valueField.type = enumType;
-      memberHolder.addField(valueField);
-      buildImplicitAccessors(valueField, memberHolder);
+    // Build fields for all enum constants.
+    List<DartObjectImpl> constantValues = <DartObjectImpl>[];
+    for (int i = 0; i < serializedEnum.values.length; i++) {
+      UnlinkedEnumValue serializedEnumValue = serializedEnum.values[i];
+      String fieldName = serializedEnumValue.name;
+      ConstFieldElementImpl field =
+          new ConstFieldElementImpl(fieldName, serializedEnumValue.nameOffset);
+      buildDocumentation(field, serializedEnumValue.documentationComment);
+      field.const3 = true;
+      field.static = true;
+      field.type = enumType;
+      // Create a value for the constant.
+      Map<String, DartObjectImpl> fieldMap = <String, DartObjectImpl>{
+        fieldName: new DartObjectImpl(
+            summaryResynthesizer.typeProvider.intType, new IntState(i))
+      };
+      DartObjectImpl value =
+          new DartObjectImpl(enumType, new GenericState(fieldMap));
+      constantValues.add(value);
+      field.evaluationResult = new EvaluationResultImpl(value);
+      // Add the field.
+      memberHolder.addField(field);
+      buildImplicitAccessors(field, memberHolder);
     }
+    // Build the value of the 'values' field.
+    valuesField.evaluationResult = new EvaluationResultImpl(
+        new DartObjectImpl(valuesField.type, new ListState(constantValues)));
+    // done
     classElement.fields = memberHolder.fields;
     classElement.accessors = memberHolder.accessors;
     classElement.constructors = <ConstructorElement>[];
@@ -413,6 +1219,7 @@
         } else {
           MethodElementImpl executableElement =
               new MethodElementImpl(name, serializedExecutable.nameOffset);
+          executableElement.abstract = serializedExecutable.isAbstract;
           buildExecutableCommonParts(executableElement, serializedExecutable);
           executableElement.static = serializedExecutable.isStatic;
           holder.addMethod(executableElement);
@@ -427,6 +1234,7 @@
           executableElement.static = true;
         } else {
           executableElement.static = serializedExecutable.isStatic;
+          executableElement.abstract = serializedExecutable.isAbstract;
         }
         buildExecutableCommonParts(executableElement, serializedExecutable);
         DartType type;
@@ -438,9 +1246,6 @@
           type = executableElement.parameters[0].type;
         }
         holder.addAccessor(executableElement);
-        // TODO(paulberry): consider removing implicit variables from the
-        // element model; the spec doesn't call for them, and they cause
-        // trouble when getters/setters exist in different parts.
         PropertyInducingElementImpl implicitVariable;
         if (isTopLevel) {
           implicitVariable = buildImplicitTopLevelVariable(name, kind, holder);
@@ -455,8 +1260,6 @@
         } else {
           implicitVariable.setter = executableElement;
         }
-        // TODO(paulberry): do the right thing when getter and setter are in
-        // different units.
         break;
       default:
         // The only other executable type is a constructor, and that is handled
@@ -472,32 +1275,36 @@
    */
   void buildExecutableCommonParts(ExecutableElementImpl executableElement,
       UnlinkedExecutable serializedExecutable) {
-    List<TypeParameterType> oldTypeArguments = currentTypeArguments;
-    int oldTypeParametersLength = currentTypeParameters.length;
-    if (serializedExecutable.typeParameters.isNotEmpty) {
-      executableElement.typeParameters =
-          serializedExecutable.typeParameters.map(buildTypeParameter).toList();
-      currentTypeParameters.addAll(executableElement.typeParameters);
-    }
+    executableElement.typeParameters =
+        buildTypeParameters(serializedExecutable.typeParameters);
     executableElement.parameters =
         serializedExecutable.parameters.map(buildParameter).toList();
-    if (serializedExecutable.returnType != null) {
-      executableElement.returnType = buildType(serializedExecutable.returnType);
-    } else if (serializedExecutable.kind ==
-        UnlinkedExecutableKind.constructor) {
-      // Return type was set by the caller.
+    if (serializedExecutable.kind == UnlinkedExecutableKind.constructor) {
+      // Caller handles setting the return type.
+      assert(serializedExecutable.returnType == null);
     } else {
-      executableElement.returnType = VoidTypeImpl.instance;
+      bool isSetter =
+          serializedExecutable.kind == UnlinkedExecutableKind.setter;
+      executableElement.returnType =
+          buildLinkedType(serializedExecutable.inferredReturnTypeSlot) ??
+              buildType(serializedExecutable.returnType,
+                  defaultVoid: isSetter && summaryResynthesizer.strongMode);
+      executableElement.hasImplicitReturnType =
+          serializedExecutable.returnType == null;
     }
     executableElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
-        executableElement, null, oldTypeArguments, false);
-    executableElement.hasImplicitReturnType =
-        serializedExecutable.hasImplicitReturnType;
+        executableElement, null, getCurrentTypeArguments(skipLevels: 1), false);
     executableElement.external = serializedExecutable.isExternal;
-    currentTypeParameters.removeRange(
-        oldTypeParametersLength, currentTypeParameters.length);
     buildDocumentation(
         executableElement, serializedExecutable.documentationComment);
+    buildAnnotations(executableElement, serializedExecutable.annotations);
+    executableElement.functions =
+        serializedExecutable.localFunctions.map(buildLocalFunction).toList();
+    executableElement.labels =
+        serializedExecutable.localLabels.map(buildLocalLabel).toList();
+    executableElement.localVariables =
+        serializedExecutable.localVariables.map(buildLocalVariable).toList();
+    currentTypeParameters.removeLast();
   }
 
   /**
@@ -519,18 +1326,65 @@
         serializedExportPublic.combinators.map(buildCombinator).toList();
     exportElement.uriOffset = serializedExportNonPublic.uriOffset;
     exportElement.uriEnd = serializedExportNonPublic.uriEnd;
+    buildAnnotations(exportElement, serializedExportNonPublic.annotations);
     return exportElement;
   }
 
   /**
-   * Resynthesize a [FieldElement].
+   * Build an [ElementHandle] referring to the entity referred to by the given
+   * [exportName].
    */
-  FieldElement buildField(UnlinkedVariable serializedField) {
-    FieldElementImpl fieldElement =
-        new FieldElementImpl(serializedField.name, -1);
-    fieldElement.type = buildType(serializedField.type);
-    fieldElement.const3 = serializedField.isConst;
-    return fieldElement;
+  ElementHandle buildExportName(LinkedExportName exportName) {
+    String name = exportName.name;
+    if (exportName.kind == ReferenceKind.topLevelPropertyAccessor &&
+        !name.endsWith('=')) {
+      name += '?';
+    }
+    ElementLocationImpl location = new ElementLocationImpl.con3(
+        getReferencedLocationComponents(
+            exportName.dependency, exportName.unit, name));
+    switch (exportName.kind) {
+      case ReferenceKind.classOrEnum:
+        return new ClassElementHandle(summaryResynthesizer, location);
+      case ReferenceKind.typedef:
+        return new FunctionTypeAliasElementHandle(
+            summaryResynthesizer, location);
+      case ReferenceKind.topLevelFunction:
+        return new FunctionElementHandle(summaryResynthesizer, location);
+      case ReferenceKind.topLevelPropertyAccessor:
+        return new PropertyAccessorElementHandle(
+            summaryResynthesizer, location);
+      case ReferenceKind.constructor:
+      case ReferenceKind.function:
+      case ReferenceKind.propertyAccessor:
+      case ReferenceKind.method:
+      case ReferenceKind.length:
+      case ReferenceKind.prefix:
+      case ReferenceKind.unresolved:
+      case ReferenceKind.variable:
+        // Should never happen.  Exported names never refer to import prefixes,
+        // and they always refer to defined top-level entities.
+        throw new StateError('Unexpected export name kind: ${exportName.kind}');
+    }
+  }
+
+  /**
+   * Build the export namespace for the library by aggregating together its
+   * [publicNamespace] and [exportNames].
+   */
+  Namespace buildExportNamespace(
+      Namespace publicNamespace, List<LinkedExportName> exportNames) {
+    HashMap<String, Element> definedNames = new HashMap<String, Element>();
+    // Start by populating all the public names from [publicNamespace].
+    publicNamespace.definedNames.forEach((String name, Element element) {
+      definedNames[name] = element;
+    });
+    // Add all the names from [exportNames].
+    for (LinkedExportName exportName in exportNames) {
+      definedNames.putIfAbsent(
+          exportName.name, () => buildExportName(exportName));
+    }
+    return new Namespace(definedNames);
   }
 
   /**
@@ -618,13 +1472,10 @@
    */
   ImportElement buildImport(UnlinkedImport serializedImport, int dependency) {
     bool isSynthetic = serializedImport.isImplicit;
-    // TODO(paulberry): it seems problematic for the offset to be 0 for
-    // non-synthetic imports, since it is used to disambiguate location.
     ImportElementImpl importElement =
         new ImportElementImpl(isSynthetic ? -1 : serializedImport.offset);
     String absoluteUri = summaryResynthesizer.sourceFactory
-        .resolveUri(
-            librarySource, prelinkedLibrary.dependencies[dependency].uri)
+        .resolveUri(librarySource, linkedLibrary.dependencies[dependency].uri)
         .uri
         .toString();
     importElement.importedLibrary = new LibraryElementHandle(
@@ -636,7 +1487,10 @@
       importElement.uri = serializedImport.uri;
       importElement.uriOffset = serializedImport.uriOffset;
       importElement.uriEnd = serializedImport.uriEnd;
+      importElement.deferred = serializedImport.isDeferred;
+      buildAnnotations(importElement, serializedImport.annotations);
     }
+    importElement.prefixOffset = serializedImport.prefixOffset;
     if (serializedImport.prefixReference != 0) {
       UnlinkedReference serializedPrefix =
           unlinkedUnits[0].references[serializedImport.prefixReference];
@@ -652,37 +1506,38 @@
    * Main entry point.  Resynthesize the [LibraryElement] and return it.
    */
   LibraryElement buildLibrary() {
+    CompilationUnitElementImpl definingCompilationUnit =
+        new CompilationUnitElementImpl(librarySource.shortName);
+    prepareUnit(definingCompilationUnit, 0);
     bool hasName = unlinkedUnits[0].libraryName.isNotEmpty;
-    LibraryElementImpl libraryElement = new LibraryElementImpl(
+    LibraryElementImpl library = new LibraryElementImpl(
         summaryResynthesizer.context,
         unlinkedUnits[0].libraryName,
         hasName ? unlinkedUnits[0].libraryNameOffset : -1,
         unlinkedUnits[0].libraryNameLength);
-    buildDocumentation(
-        libraryElement, unlinkedUnits[0].libraryDocumentationComment);
-    CompilationUnitElementImpl definingCompilationUnit =
-        new CompilationUnitElementImpl(librarySource.shortName);
-    libraryElement.definingCompilationUnit = definingCompilationUnit;
+    buildDocumentation(library, unlinkedUnits[0].libraryDocumentationComment);
+    buildAnnotations(library, unlinkedUnits[0].libraryAnnotations);
+    library.definingCompilationUnit = definingCompilationUnit;
     definingCompilationUnit.source = librarySource;
     definingCompilationUnit.librarySource = librarySource;
     List<CompilationUnitElement> parts = <CompilationUnitElement>[];
     UnlinkedUnit unlinkedDefiningUnit = unlinkedUnits[0];
     assert(unlinkedDefiningUnit.publicNamespace.parts.length + 1 ==
-        prelinkedLibrary.units.length);
-    for (int i = 1; i < prelinkedLibrary.units.length; i++) {
+        linkedLibrary.units.length);
+    for (int i = 1; i < linkedLibrary.units.length; i++) {
       CompilationUnitElementImpl part = buildPart(
           unlinkedDefiningUnit.publicNamespace.parts[i - 1],
           unlinkedDefiningUnit.parts[i - 1],
           unlinkedUnits[i]);
       parts.add(part);
     }
-    libraryElement.parts = parts;
+    library.parts = parts;
     List<ImportElement> imports = <ImportElement>[];
     for (int i = 0; i < unlinkedDefiningUnit.imports.length; i++) {
       imports.add(buildImport(unlinkedDefiningUnit.imports[i],
-          prelinkedLibrary.importDependencies[i]));
+          linkedLibrary.importDependencies[i]));
     }
-    libraryElement.imports = imports;
+    library.imports = imports;
     List<ExportElement> exports = <ExportElement>[];
     assert(unlinkedDefiningUnit.exports.length ==
         unlinkedDefiningUnit.publicNamespace.exports.length);
@@ -690,40 +1545,160 @@
       exports.add(buildExport(unlinkedDefiningUnit.publicNamespace.exports[i],
           unlinkedDefiningUnit.exports[i]));
     }
-    libraryElement.exports = exports;
+    library.exports = exports;
     populateUnit(definingCompilationUnit, 0);
+    finishUnit();
     for (int i = 0; i < parts.length; i++) {
+      prepareUnit(parts[i], i + 1);
       populateUnit(parts[i], i + 1);
+      finishUnit();
     }
+    BuildLibraryElementUtils.patchTopLevelAccessors(library);
+    // Update delayed Object class references.
     if (isCoreLibrary) {
-      ClassElement objectElement = libraryElement.getType('Object');
+      ClassElement objectElement = library.getType('Object');
       assert(objectElement != null);
       for (ClassElementImpl classElement in delayedObjectSubclasses) {
         classElement.supertype = objectElement.type;
       }
     }
     // Compute namespaces.
-    libraryElement.publicNamespace =
-        new NamespaceBuilder().createPublicNamespaceForLibrary(libraryElement);
-    // TODO(paulberry): compute the export namespace from prelinked data, so
-    // that exported libraries won't be unnecessarily resynthesized.
-    libraryElement.exportNamespace =
-        new NamespaceBuilder().createExportNamespaceForLibrary(libraryElement);
-    // Find the entry point.
-    libraryElement.entryPoint =
-        libraryElement.exportNamespace.definedNames.values.firstWhere(
-            (element) => element is FunctionElement && element.isEntryPoint,
-            orElse: () => null);
+    library.publicNamespace =
+        new NamespaceBuilder().createPublicNamespaceForLibrary(library);
+    library.exportNamespace = buildExportNamespace(
+        library.publicNamespace, linkedLibrary.exportNames);
+    // Find the entry point.  Note: we can't use element.isEntryPoint because
+    // that will trigger resynthesis of exported libraries.
+    Element entryPoint =
+        library.exportNamespace.get(FunctionElement.MAIN_FUNCTION_NAME);
+    if (entryPoint is FunctionElement) {
+      library.entryPoint = entryPoint;
+    }
+    // Create the synthetic element for `loadLibrary`.
+    // Until the client received dart:core and dart:async, we cannot do this,
+    // because the TypeProvider is not fully initialized. So, it is up to the
+    // Dart SDK client to initialize TypeProvider and finish the dart:core and
+    // dart:async libraries creation.
+    if (library.name != 'dart.core' && library.name != 'dart.async') {
+      library.createLoadLibraryFunction(summaryResynthesizer.typeProvider);
+    }
     // Done.
-    return libraryElement;
+    return library;
+  }
+
+  /**
+   * Build the appropriate [DartType] object corresponding to a slot id in the
+   * [LinkedUnit.types] table.
+   */
+  DartType buildLinkedType(int slot) {
+    if (slot == 0) {
+      // A slot id of 0 means there is no [DartType] object to build.
+      return null;
+    }
+    EntityRef type = linkedTypeMap[slot];
+    if (type == null) {
+      // A missing entry in [LinkedUnit.types] means there is no [DartType]
+      // stored in this slot.
+      return null;
+    }
+    return buildType(type);
+  }
+
+  /**
+   * Resynthesize a local [FunctionElement].
+   */
+  FunctionElementImpl buildLocalFunction(
+      UnlinkedExecutable serializedExecutable) {
+    FunctionElementImpl element = new FunctionElementImpl(
+        serializedExecutable.name, serializedExecutable.nameOffset);
+    if (serializedExecutable.visibleOffset != 0) {
+      element.setVisibleRange(serializedExecutable.visibleOffset,
+          serializedExecutable.visibleLength);
+    }
+    buildExecutableCommonParts(element, serializedExecutable);
+    return element;
+  }
+
+  /**
+   * Resynthesize a [LabelElement].
+   */
+  LabelElement buildLocalLabel(UnlinkedLabel serializedLabel) {
+    return new LabelElementImpl(
+        serializedLabel.name,
+        serializedLabel.nameOffset,
+        serializedLabel.isOnSwitchStatement,
+        serializedLabel.isOnSwitchMember);
+  }
+
+  /**
+   * Resynthesize a [LocalVariableElement].
+   */
+  LocalVariableElement buildLocalVariable(UnlinkedVariable serializedVariable) {
+    LocalVariableElementImpl element;
+    if (serializedVariable.constExpr != null) {
+      ConstLocalVariableElementImpl constElement =
+          new ConstLocalVariableElementImpl(
+              serializedVariable.name, serializedVariable.nameOffset);
+      element = constElement;
+      constElement.constantInitializer =
+          _buildConstExpression(serializedVariable.constExpr);
+    } else {
+      element = new LocalVariableElementImpl(
+          serializedVariable.name, serializedVariable.nameOffset);
+    }
+    if (serializedVariable.visibleOffset != 0) {
+      element.setVisibleRange(
+          serializedVariable.visibleOffset, serializedVariable.visibleLength);
+    }
+    buildVariableCommonParts(element, serializedVariable);
+    return element;
   }
 
   /**
    * Resynthesize a [ParameterElement].
    */
-  ParameterElement buildParameter(UnlinkedParam serializedParameter) {
-    ParameterElementImpl parameterElement = new ParameterElementImpl(
-        serializedParameter.name, serializedParameter.nameOffset);
+  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, nameOffset);
+      } else {
+        DefaultFieldFormalParameterElementImpl defaultParameter =
+            new DefaultFieldFormalParameterElementImpl(
+                serializedParameter.name, nameOffset);
+        initializingParameter = defaultParameter;
+        if (serializedParameter.defaultValue != null) {
+          defaultParameter.constantInitializer =
+              _buildConstExpression(serializedParameter.defaultValue);
+          defaultParameter.defaultValueCode =
+              serializedParameter.defaultValueCode;
+        }
+      }
+      parameterElement = initializingParameter;
+      initializingParameter.field = fields[serializedParameter.name];
+    } else {
+      if (serializedParameter.kind == UnlinkedParamKind.required) {
+        parameterElement =
+            new ParameterElementImpl(serializedParameter.name, nameOffset);
+      } else {
+        DefaultParameterElementImpl defaultParameter =
+            new DefaultParameterElementImpl(
+                serializedParameter.name, nameOffset);
+        parameterElement = defaultParameter;
+        if (serializedParameter.defaultValue != null) {
+          defaultParameter.constantInitializer =
+              _buildConstExpression(serializedParameter.defaultValue);
+          defaultParameter.defaultValueCode =
+              serializedParameter.defaultValueCode;
+        }
+      }
+    }
+    parameterElement.synthetic = synthetic;
+    buildAnnotations(parameterElement, serializedParameter.annotations);
     if (serializedParameter.isFunctionTyped) {
       FunctionElementImpl parameterTypeElement =
           new FunctionElementImpl('', -1);
@@ -732,17 +1707,23 @@
           serializedParameter.parameters.map(buildParameter).toList();
       parameterTypeElement.enclosingElement = parameterElement;
       parameterTypeElement.shareParameters(parameterElement.parameters);
-      if (serializedParameter.type != null) {
-        parameterTypeElement.returnType = buildType(serializedParameter.type);
-      } else {
-        parameterTypeElement.returnType = VoidTypeImpl.instance;
-      }
+      parameterTypeElement.returnType = buildType(serializedParameter.type);
       parameterElement.type = new FunctionTypeImpl.elementWithNameAndArgs(
-          parameterTypeElement, null, currentTypeArguments, false);
+          parameterTypeElement, null, getCurrentTypeArguments(), false);
     } else {
-      parameterElement.type = buildType(serializedParameter.type);
-      parameterElement.hasImplicitType = serializedParameter.hasImplicitType;
+      if (serializedParameter.isInitializingFormal &&
+          serializedParameter.type == null) {
+        // The type is inherited from the matching field.
+        parameterElement.type = fields[serializedParameter.name]?.type ??
+            summaryResynthesizer.typeProvider.dynamicType;
+      } else {
+        parameterElement.type =
+            buildLinkedType(serializedParameter.inferredTypeSlot) ??
+                buildType(serializedParameter.type);
+      }
+      parameterElement.hasImplicitType = serializedParameter.type == null;
     }
+    buildVariableInitializer(parameterElement, serializedParameter.initializer);
     switch (serializedParameter.kind) {
       case UnlinkedParamKind.named:
         parameterElement.parameterKind = ParameterKind.NAMED;
@@ -754,6 +1735,10 @@
         parameterElement.parameterKind = ParameterKind.REQUIRED;
         break;
     }
+    if (serializedParameter.visibleOffset != 0) {
+      parameterElement.setVisibleRange(
+          serializedParameter.visibleOffset, serializedParameter.visibleLength);
+    }
     return parameterElement;
   }
 
@@ -772,100 +1757,59 @@
     partUnit.source = unitSource;
     partUnit.librarySource = librarySource;
     partUnit.uri = uri;
+    buildAnnotations(partUnit, partDecl.annotations);
     return partUnit;
   }
 
   /**
-   * Build a [DartType] object based on an [UnlinkedTypeRef].  This [DartType]
+   * Handle the parts that are common to top level variables and fields.
+   */
+  void buildPropertyIntroducingElementCommonParts(
+      PropertyInducingElementImpl element,
+      UnlinkedVariable serializedVariable) {
+    buildVariableCommonParts(element, serializedVariable);
+    element.propagatedType =
+        buildLinkedType(serializedVariable.propagatedTypeSlot);
+  }
+
+  /**
+   * Build a [DartType] object based on a [EntityRef].  This [DartType]
    * may refer to elements in other libraries than the library being
    * deserialized, so handles are used to avoid having to deserialize other
    * libraries in the process.
    */
-  DartType buildType(UnlinkedTypeRef type) {
-    if (type.paramReference != 0) {
-      // TODO(paulberry): make this work for generic methods.
-      return currentTypeParameters[
-              currentTypeParameters.length - type.paramReference]
-          .type;
-    } else {
-      // TODO(paulberry): handle references to things other than classes (note:
-      // this should only occur in the case of erroneous code).
-      // TODO(paulberry): test reference to something inside a part.
-      // TODO(paulberry): test reference to something inside a part of the
-      // current lib.
-      UnlinkedReference reference = unlinkedUnit.references[type.reference];
-      PrelinkedReference referenceResolution =
-          prelinkedUnit.references[type.reference];
-      String referencedLibraryUri;
-      String partUri;
-      if (referenceResolution.dependency != 0) {
-        PrelinkedDependency dependency =
-            prelinkedLibrary.dependencies[referenceResolution.dependency];
-        Source referencedLibrarySource = summaryResynthesizer.sourceFactory
-            .resolveUri(librarySource, dependency.uri);
-        referencedLibraryUri = referencedLibrarySource.uri.toString();
-        // TODO(paulberry): consider changing Location format so that this is
-        // not necessary (2nd string in location should just be the unit
-        // number).
-        if (referenceResolution.unit != 0) {
-          UnlinkedUnit referencedLibraryDefiningUnit =
-              summaryResynthesizer.getUnlinkedSummary(referencedLibraryUri);
-          String uri = referencedLibraryDefiningUnit.publicNamespace.parts[
-              referenceResolution.unit - 1];
-          Source partSource = summaryResynthesizer.sourceFactory
-              .resolveUri(referencedLibrarySource, uri);
-          partUri = partSource.uri.toString();
-        } else {
-          partUri = referencedLibraryUri;
-        }
-      } else if (referenceResolution.kind ==
-          PrelinkedReferenceKind.unresolved) {
-        return summaryResynthesizer.typeProvider.undefinedType;
-      } else if (reference.name.isEmpty) {
-        return summaryResynthesizer.typeProvider.dynamicType;
+  DartType buildType(EntityRef type, {bool defaultVoid: false}) {
+    if (type == null) {
+      if (defaultVoid) {
+        return VoidTypeImpl.instance;
       } else {
-        referencedLibraryUri = librarySource.uri.toString();
-        if (referenceResolution.unit != 0) {
-          String uri = unlinkedUnits[0].publicNamespace.parts[
-              referenceResolution.unit - 1];
-          Source partSource =
-              summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
-          partUri = partSource.uri.toString();
+        return summaryResynthesizer.typeProvider.dynamicType;
+      }
+    }
+    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) {
+          return buildType(type.typeArguments[i]);
         } else {
-          partUri = referencedLibraryUri;
+          return summaryResynthesizer.typeProvider.dynamicType;
         }
       }
-      ElementLocationImpl location = new ElementLocationImpl.con3(
-          <String>[referencedLibraryUri, partUri, reference.name]);
-      List<DartType> typeArguments = const <DartType>[];
-      if (referenceResolution.numTypeParameters != 0) {
-        typeArguments = <DartType>[];
-        for (int i = 0; i < referenceResolution.numTypeParameters; i++) {
-          if (i < type.typeArguments.length) {
-            typeArguments.add(buildType(type.typeArguments[i]));
-          } else {
-            typeArguments.add(summaryResynthesizer.typeProvider.dynamicType);
-          }
-        }
-      }
-      switch (referenceResolution.kind) {
-        case PrelinkedReferenceKind.classOrEnum:
-          return new InterfaceTypeImpl.elementWithNameAndArgs(
-              new ClassElementHandle(summaryResynthesizer, location),
-              reference.name,
-              typeArguments);
-        case PrelinkedReferenceKind.typedef:
-          return new FunctionTypeImpl.elementWithNameAndArgs(
-              new FunctionTypeAliasElementHandle(
-                  summaryResynthesizer, location),
-              reference.name,
-              typeArguments,
-              typeArguments.isNotEmpty);
-        default:
-          // TODO(paulberry): figure out how to handle this case (which should
-          // only occur in the event of erroneous code).
-          throw new UnimplementedError();
-      }
+      _ReferenceInfo referenceInfo = referenceInfos[type.reference];
+      return referenceInfo.buildType(
+          getTypeArgument, type.implicitFunctionTypeIndices);
     }
   }
 
@@ -874,33 +1818,23 @@
    * [unitHolder].
    */
   void buildTypedef(UnlinkedTypedef serializedTypedef) {
-    try {
-      currentTypeParameters =
-          serializedTypedef.typeParameters.map(buildTypeParameter).toList();
-      for (int i = 0; i < serializedTypedef.typeParameters.length; i++) {
-        finishTypeParameter(
-            serializedTypedef.typeParameters[i], currentTypeParameters[i]);
-      }
-      FunctionTypeAliasElementImpl functionTypeAliasElement =
-          new FunctionTypeAliasElementImpl(
-              serializedTypedef.name, serializedTypedef.nameOffset);
-      functionTypeAliasElement.parameters =
-          serializedTypedef.parameters.map(buildParameter).toList();
-      if (serializedTypedef.returnType != null) {
-        functionTypeAliasElement.returnType =
-            buildType(serializedTypedef.returnType);
-      } else {
-        functionTypeAliasElement.returnType = VoidTypeImpl.instance;
-      }
-      functionTypeAliasElement.type =
-          new FunctionTypeImpl.forTypedef(functionTypeAliasElement);
-      functionTypeAliasElement.typeParameters = currentTypeParameters;
-      buildDocumentation(
-          functionTypeAliasElement, serializedTypedef.documentationComment);
-      unitHolder.addTypeAlias(functionTypeAliasElement);
-    } finally {
-      currentTypeParameters = <TypeParameterElement>[];
-    }
+    FunctionTypeAliasElementImpl functionTypeAliasElement =
+        new FunctionTypeAliasElementImpl(
+            serializedTypedef.name, serializedTypedef.nameOffset);
+    functionTypeAliasElement.typeParameters =
+        buildTypeParameters(serializedTypedef.typeParameters);
+    functionTypeAliasElement.parameters =
+        serializedTypedef.parameters.map(buildParameter).toList();
+    functionTypeAliasElement.returnType =
+        buildType(serializedTypedef.returnType);
+    functionTypeAliasElement.type =
+        new FunctionTypeImpl.forTypedef(functionTypeAliasElement);
+    buildDocumentation(
+        functionTypeAliasElement, serializedTypedef.documentationComment);
+    buildAnnotations(functionTypeAliasElement, serializedTypedef.annotations);
+    unitHolder.addTypeAlias(functionTypeAliasElement);
+    currentTypeParameters.removeLast();
+    assert(currentTypeParameters.isEmpty);
   }
 
   /**
@@ -917,39 +1851,95 @@
         new TypeParameterElementImpl(
             serializedTypeParameter.name, serializedTypeParameter.nameOffset);
     typeParameterElement.type = new TypeParameterTypeImpl(typeParameterElement);
+    buildAnnotations(typeParameterElement, serializedTypeParameter.annotations);
     return typeParameterElement;
   }
 
   /**
+   * Build [TypeParameterElement]s corresponding to the type parameters in
+   * [serializedTypeParameters] and store them in [currentTypeParameters].
+   * Also return them.
+   */
+  List<TypeParameterElement> buildTypeParameters(
+      List<UnlinkedTypeParam> serializedTypeParameters) {
+    List<TypeParameterElement> typeParameters =
+        serializedTypeParameters.map(buildTypeParameter).toList();
+    currentTypeParameters.add(typeParameters);
+    for (int i = 0; i < serializedTypeParameters.length; i++) {
+      finishTypeParameter(serializedTypeParameters[i], typeParameters[i]);
+    }
+    return typeParameters;
+  }
+
+  /**
    * Resynthesize a [TopLevelVariableElement] or [FieldElement].
    */
   void buildVariable(UnlinkedVariable serializedVariable,
       [ElementHolder holder]) {
     if (holder == null) {
-      TopLevelVariableElementImpl element = new TopLevelVariableElementImpl(
-          serializedVariable.name, serializedVariable.nameOffset);
-      buildVariableCommonParts(element, serializedVariable);
+      TopLevelVariableElementImpl element;
+      if (serializedVariable.constExpr != null) {
+        ConstTopLevelVariableElementImpl constElement =
+            new ConstTopLevelVariableElementImpl(
+                serializedVariable.name, serializedVariable.nameOffset);
+        element = constElement;
+        constElement.constantInitializer =
+            _buildConstExpression(serializedVariable.constExpr);
+      } else {
+        element = new TopLevelVariableElementImpl(
+            serializedVariable.name, serializedVariable.nameOffset);
+      }
+      buildPropertyIntroducingElementCommonParts(element, serializedVariable);
       unitHolder.addTopLevelVariable(element);
       buildImplicitAccessors(element, unitHolder);
     } else {
-      FieldElementImpl element = new FieldElementImpl(
-          serializedVariable.name, serializedVariable.nameOffset);
-      buildVariableCommonParts(element, serializedVariable);
+      FieldElementImpl element;
+      if (serializedVariable.constExpr != null) {
+        ConstFieldElementImpl constElement = new ConstFieldElementImpl(
+            serializedVariable.name, serializedVariable.nameOffset);
+        element = constElement;
+        constElement.constantInitializer =
+            _buildConstExpression(serializedVariable.constExpr);
+      } else {
+        element = new FieldElementImpl(
+            serializedVariable.name, serializedVariable.nameOffset);
+      }
+      buildPropertyIntroducingElementCommonParts(element, serializedVariable);
       element.static = serializedVariable.isStatic;
       holder.addField(element);
       buildImplicitAccessors(element, holder);
+      fields[element.name] = element;
     }
   }
 
   /**
-   * Handle the parts that are common to top level variables and fields.
+   * Handle the parts that are common to variables.
    */
-  void buildVariableCommonParts(PropertyInducingElementImpl element,
-      UnlinkedVariable serializedVariable) {
-    element.type = buildType(serializedVariable.type);
+  void buildVariableCommonParts(
+      VariableElementImpl element, UnlinkedVariable serializedVariable) {
+    element.type = buildLinkedType(serializedVariable.inferredTypeSlot) ??
+        buildType(serializedVariable.type);
     element.const3 = serializedVariable.isConst;
-    element.hasImplicitType = serializedVariable.hasImplicitType;
+    element.final2 = serializedVariable.isFinal;
+    element.hasImplicitType = serializedVariable.type == null;
+    buildVariableInitializer(element, serializedVariable.initializer);
     buildDocumentation(element, serializedVariable.documentationComment);
+    buildAnnotations(element, serializedVariable.annotations);
+  }
+
+  /**
+   * If the given [serializedInitializer] is not `null`, create the
+   * corresponding [FunctionElementImpl] and set it for the [variable].
+   */
+  void buildVariableInitializer(
+      VariableElementImpl variable, UnlinkedExecutable serializedInitializer) {
+    if (serializedInitializer == null) {
+      return null;
+    }
+    FunctionElementImpl initializerElement =
+        buildLocalFunction(serializedInitializer);
+    initializerElement.synthetic = true;
+    variable.initializer = initializerElement;
   }
 
   /**
@@ -963,13 +1953,214 @@
   }
 
   /**
+   * Tear down data structures used during deserialization of a compilation
+   * unit.
+   */
+  void finishUnit() {
+    unitHolder = null;
+    linkedUnit = null;
+    unlinkedUnit = null;
+    linkedTypeMap = null;
+    referenceInfos = null;
+    currentCompilationUnit = null;
+  }
+
+  /**
+   * Return a list of type arguments corresponding to [currentTypeParameters],
+   * skipping the innermost [skipLevels] nesting levels.
+   *
+   * Type parameters are listed in nesting order from innermost to outermost,
+   * and then in declaration order.  So for instance if we are resynthesizing a
+   * method declared as `class C<T, U> { void m<V, W>() { ... } }`, then the
+   * type parameters will be returned in the order `[V, W, T, U]`.
+   */
+  List<DartType> getCurrentTypeArguments({int skipLevels: 0}) {
+    assert(currentTypeParameters.length >= skipLevels);
+    List<DartType> result = <DartType>[];
+    for (int i = currentTypeParameters.length - 1 - skipLevels; i >= 0; i--) {
+      result.addAll(currentTypeParameters[i]
+          .map((TypeParameterElement param) => param.type));
+    }
+    return result;
+  }
+
+  /**
+   * Build the components of an [ElementLocationImpl] for the entity in the
+   * given [unit] of the dependency located at [dependencyIndex], and having
+   * the given [name].
+   */
+  List<String> getReferencedLocationComponents(
+      int dependencyIndex, int unit, String name) {
+    if (dependencyIndex == 0) {
+      String referencedLibraryUri = librarySource.uri.toString();
+      String partUri;
+      if (unit != 0) {
+        String uri = unlinkedUnits[0].publicNamespace.parts[unit - 1];
+        Source partSource =
+            summaryResynthesizer.sourceFactory.resolveUri(librarySource, uri);
+        partUri = partSource.uri.toString();
+      } else {
+        partUri = referencedLibraryUri;
+      }
+      return <String>[referencedLibraryUri, partUri, name];
+    }
+    LinkedDependency dependency = linkedLibrary.dependencies[dependencyIndex];
+    Source referencedLibrarySource = summaryResynthesizer.sourceFactory
+        .resolveUri(librarySource, dependency.uri);
+    String referencedLibraryUri = referencedLibrarySource.uri.toString();
+    String partUri;
+    if (unit != 0) {
+      String uri = dependency.parts[unit - 1];
+      Source partSource = summaryResynthesizer.sourceFactory
+          .resolveUri(referencedLibrarySource, uri);
+      partUri = partSource.uri.toString();
+    } else {
+      partUri = referencedLibraryUri;
+    }
+    return <String>[referencedLibraryUri, partUri, name];
+  }
+
+  /**
+   * Get the type parameter from the surrounding scope whose De Bruijn index is
+   * [index].
+   */
+  DartType getTypeParameterFromScope(int index) {
+    for (int i = currentTypeParameters.length - 1; i >= 0; i--) {
+      List<TypeParameterElement> paramsAtThisNestingLevel =
+          currentTypeParameters[i];
+      int numParamsAtThisNestingLevel = paramsAtThisNestingLevel.length;
+      if (index <= numParamsAtThisNestingLevel) {
+        return paramsAtThisNestingLevel[numParamsAtThisNestingLevel - index]
+            .type;
+      }
+      index -= numParamsAtThisNestingLevel;
+    }
+    throw new StateError('Type parameter not found');
+  }
+
+  /**
+   * Populate [referenceInfos] with the correct information for the current
+   * compilation unit.
+   */
+  void populateReferenceInfos() {
+    int numLinkedReferences = linkedUnit.references.length;
+    int numUnlinkedReferences = unlinkedUnit.references.length;
+    referenceInfos = new List<_ReferenceInfo>(numLinkedReferences);
+    for (int i = 0; i < numLinkedReferences; i++) {
+      LinkedReference linkedReference = linkedUnit.references[i];
+      String name;
+      int containingReference;
+      if (i < numUnlinkedReferences) {
+        name = unlinkedUnit.references[i].name;
+        containingReference = unlinkedUnit.references[i].prefixReference;
+      } else {
+        name = linkedUnit.references[i].name;
+        containingReference = linkedUnit.references[i].containingReference;
+      }
+      _ReferenceInfo enclosingInfo =
+          containingReference != 0 ? referenceInfos[containingReference] : null;
+      Element element;
+      DartType type;
+      int numTypeParameters = linkedReference.numTypeParameters;
+      if (linkedReference.kind == ReferenceKind.unresolved) {
+        type = summaryResynthesizer.typeProvider.undefinedType;
+        element = null;
+      } else if (name == 'dynamic') {
+        type = summaryResynthesizer.typeProvider.dynamicType;
+        element = type.element;
+      } else if (name == 'void') {
+        type = VoidTypeImpl.instance;
+        element = type.element;
+      } else if (name == '*bottom*') {
+        type = BottomTypeImpl.instance;
+        element = null;
+      } else {
+        List<String> locationComponents;
+        if (enclosingInfo != null && enclosingInfo.element is ClassElement) {
+          String identifier = _getElementIdentifier(name, linkedReference.kind);
+          locationComponents =
+              enclosingInfo.element.location.components.toList();
+          locationComponents.add(identifier);
+        } else {
+          String identifier = _getElementIdentifier(name, linkedReference.kind);
+          locationComponents = getReferencedLocationComponents(
+              linkedReference.dependency, linkedReference.unit, identifier);
+        }
+        ElementLocation location =
+            new ElementLocationImpl.con3(locationComponents);
+        if (enclosingInfo != null) {
+          numTypeParameters += enclosingInfo.numTypeParameters;
+        }
+        switch (linkedReference.kind) {
+          case ReferenceKind.classOrEnum:
+            element = new ClassElementHandle(summaryResynthesizer, location);
+            break;
+          case ReferenceKind.constructor:
+            assert(location.components.length == 4);
+            element =
+                new ConstructorElementHandle(summaryResynthesizer, location);
+            break;
+          case ReferenceKind.length:
+            element = _buildStringLengthPropertyAccessorElement();
+            break;
+          case ReferenceKind.method:
+            assert(location.components.length == 4);
+            element = new MethodElementHandle(summaryResynthesizer, location);
+            break;
+          case ReferenceKind.propertyAccessor:
+            assert(location.components.length == 4);
+            element = new PropertyAccessorElementHandle(
+                summaryResynthesizer, location);
+            break;
+          case ReferenceKind.topLevelFunction:
+            assert(location.components.length == 3);
+            element = new FunctionElementHandle(summaryResynthesizer, location);
+            break;
+          case ReferenceKind.topLevelPropertyAccessor:
+            element = new PropertyAccessorElementHandle(
+                summaryResynthesizer, location);
+            break;
+          case ReferenceKind.typedef:
+            element = new FunctionTypeAliasElementHandle(
+                summaryResynthesizer, location);
+            break;
+          case ReferenceKind.variable:
+            Element enclosingElement = enclosingInfo.element;
+            if (enclosingElement is ExecutableElement) {
+              element = new _DeferredLocalVariableElement(
+                  enclosingElement, linkedReference.localIndex);
+            } else {
+              throw new StateError('Unexpected element enclosing variable:'
+                  ' ${enclosingElement.runtimeType}');
+            }
+            break;
+          case ReferenceKind.function:
+            Element enclosingElement = enclosingInfo.element;
+            if (enclosingElement is VariableElement) {
+              element = new _DeferredInitializerElement(enclosingElement);
+            } else if (enclosingElement is ExecutableElement) {
+              element = new _DeferredLocalFunctionElement(
+                  enclosingElement, linkedReference.localIndex);
+            } else {
+              throw new StateError('Unexpected element enclosing function:'
+                  ' ${enclosingElement.runtimeType}');
+            }
+            break;
+          case ReferenceKind.prefix:
+          case ReferenceKind.unresolved:
+            break;
+        }
+      }
+      referenceInfos[i] = new _ReferenceInfo(
+          enclosingInfo, name, element, type, numTypeParameters);
+    }
+  }
+
+  /**
    * Populate a [CompilationUnitElement] by deserializing all the elements
    * contained in it.
    */
   void populateUnit(CompilationUnitElementImpl unit, int unitNum) {
-    prelinkedUnit = prelinkedLibrary.units[unitNum];
-    unlinkedUnit = unlinkedUnits[unitNum];
-    unitHolder = new ElementHolder();
     unlinkedUnit.classes.forEach(buildClass);
     unlinkedUnit.enums.forEach(buildEnum);
     unlinkedUnit.executables.forEach(buildExecutable);
@@ -998,9 +2189,268 @@
     for (FunctionTypeAliasElement typeAlias in unit.functionTypeAliases) {
       elementMap[typeAlias.name] = typeAlias;
     }
-    resummarizedElements[absoluteUri] = elementMap;
-    unitHolder = null;
-    prelinkedUnit = null;
-    unlinkedUnit = null;
+    for (FunctionElement function in unit.functions) {
+      elementMap[function.name] = function;
+    }
+    for (PropertyAccessorElementImpl accessor in unit.accessors) {
+      elementMap[accessor.identifier] = accessor;
+    }
+    resynthesizedUnits[absoluteUri] = unit;
+    resynthesizedElements[absoluteUri] = elementMap;
+    assert(currentTypeParameters.isEmpty);
+  }
+
+  /**
+   * Set up data structures for deserializing a compilation unit.
+   */
+  void prepareUnit(CompilationUnitElementImpl unit, int unitNum) {
+    linkedUnit = linkedLibrary.units[unitNum];
+    unlinkedUnit = unlinkedUnits[unitNum];
+    linkedTypeMap = <int, EntityRef>{};
+    currentCompilationUnit = unit;
+    for (EntityRef t in linkedUnit.types) {
+      linkedTypeMap[t.slot] = t;
+    }
+    populateReferenceInfos();
+    unitHolder = new ElementHolder();
+  }
+
+  /**
+   * Constructor initializers can reference fields and other constructors of
+   * the same class, including forward references. So, we need to delay
+   * resolution until after class elements are built.
+   */
+  void resolveConstructorInitializers(ClassElementImpl classElement) {
+    for (ConstructorElementImpl constructor in constructors.values) {
+      for (ConstructorInitializer initializer
+          in constructor.constantInitializers) {
+        if (initializer is ConstructorFieldInitializer) {
+          SimpleIdentifier nameNode = initializer.fieldName;
+          nameNode.staticElement = fields[nameNode.name];
+        } else if (initializer is SuperConstructorInvocation) {
+          SimpleIdentifier nameNode = initializer.constructorName;
+          ConstructorElement element = new _DeferredConstructorElement(
+              classElement.supertype, nameNode?.name ?? '');
+          initializer.staticElement = element;
+          nameNode?.staticElement = element;
+        } else if (initializer is RedirectingConstructorInvocation) {
+          SimpleIdentifier nameNode = initializer.constructorName;
+          ConstructorElement element = constructors[nameNode?.name ?? ''];
+          initializer.staticElement = element;
+          nameNode?.staticElement = element;
+        }
+      }
+    }
+  }
+
+  Expression _buildConstExpression(UnlinkedConst uc) {
+    return new _ConstExprBuilder(this, uc).build();
+  }
+
+  /**
+   * Return the new handle of the `String.length` getter element.
+   */
+  PropertyAccessorElementHandle _buildStringLengthPropertyAccessorElement() =>
+      new PropertyAccessorElementHandle(
+          summaryResynthesizer,
+          new ElementLocationImpl.con3(
+              <String>['dart:core', 'dart:core', 'String', 'length?']));
+
+  /**
+   * Return the defining type for a [ConstructorElement] by applying
+   * [typeArgumentRefs] to the given linked [info].
+   */
+  InterfaceType _createConstructorDefiningType(
+      _ReferenceInfo info, List<EntityRef> typeArgumentRefs) {
+    bool isClass = info.element is ClassElement;
+    _ReferenceInfo classInfo = isClass ? info : info.enclosing;
+    List<DartType> typeArguments = typeArgumentRefs.map(buildType).toList();
+    return classInfo.buildType((i) {
+      if (i < typeArguments.length) {
+        return typeArguments[i];
+      } else {
+        return DynamicTypeImpl.instance;
+      }
+    }, const <int>[]);
+  }
+
+  /**
+   * Return the [ConstructorElement] corresponding to the given linked [info],
+   * using the [classType] which has already been computed (e.g. by
+   * [_createConstructorDefiningType]).  Both cases when [info] is a
+   * [ClassElement] and [ConstructorElement] are supported.
+   */
+  ConstructorElement _createConstructorElement(
+      InterfaceType classType, _ReferenceInfo info) {
+    bool isClass = info.element is ClassElement;
+    String name = isClass ? '' : info.name;
+    _DeferredConstructorElement element =
+        new _DeferredConstructorElement(classType, name);
+    if (info.numTypeParameters != 0) {
+      return new ConstructorMember(element, classType);
+    } else {
+      return element;
+    }
+  }
+
+  /**
+   * If the given [kind] is a top-level or class member property accessor, and
+   * the given [name] does not end with `=`, i.e. does not denote a setter,
+   * return the getter identifier by appending `?`.
+   */
+  static String _getElementIdentifier(String name, ReferenceKind kind) {
+    if (kind == ReferenceKind.topLevelPropertyAccessor ||
+        kind == ReferenceKind.propertyAccessor) {
+      if (!name.endsWith('=')) {
+        return name + '?';
+      }
+    }
+    return name;
+  }
+}
+
+/**
+ * Data structure used during resynthesis to record all the information that is
+ * known about how to resynthesize a single entry in [LinkedUnit.references]
+ * (and its associated entry in [UnlinkedUnit.references], if it exists).
+ */
+class _ReferenceInfo {
+  /**
+   * The enclosing [_ReferenceInfo], or `null` for top-level elements.
+   */
+  final _ReferenceInfo enclosing;
+
+  /**
+   * The name of the entity referred to by this reference.
+   */
+  final String name;
+
+  /**
+   * The element referred to by this reference, or `null` if there is no
+   * associated element (e.g. because it is a reference to an undefined
+   * entity).
+   */
+  final Element element;
+
+  /**
+   * If this reference refers to a non-generic type, the type it refers to.
+   * Otherwise `null`.
+   */
+  DartType type;
+
+  /**
+   * The number of type parameters accepted by the entity referred to by this
+   * reference, or zero if it doesn't accept any type parameters.
+   */
+  final int numTypeParameters;
+
+  /**
+   * Create a new [_ReferenceInfo] object referring to an element called [name]
+   * via the element handle [element], and having [numTypeParameters] type
+   * parameters.
+   *
+   * For the special types `dynamic` and `void`, [specialType] should point to
+   * the type itself.  Otherwise, pass `null` and the type will be computed
+   * when appropriate.
+   */
+  _ReferenceInfo(this.enclosing, this.name, this.element, DartType specialType,
+      this.numTypeParameters) {
+    if (specialType != null) {
+      type = specialType;
+    } else {
+      type = _buildType((_) => DynamicTypeImpl.instance, const []);
+    }
+  }
+
+  /**
+   * Build a [DartType] corresponding to the result of applying some type
+   * arguments to the entity referred to by this [_ReferenceInfo].  The type
+   * arguments are retrieved by calling [getTypeArgument].
+   *
+   * If [implicitFunctionTypeIndices] is not empty, a [DartType] should be
+   * created which refers to a function type implicitly defined by one of the
+   * element's parameters.  [implicitFunctionTypeIndices] is interpreted as in
+   * [EntityRef.implicitFunctionTypeIndices].
+   *
+   * If the entity referred to by this [_ReferenceInfo] is not a type, `null`
+   * is returned.
+   */
+  DartType buildType(
+      DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
+    DartType result =
+        (numTypeParameters == 0 && implicitFunctionTypeIndices.isEmpty)
+            ? type
+            : _buildType(getTypeArgument, implicitFunctionTypeIndices);
+    if (result == null) {
+      // TODO(paulberry): figure out how to handle this case (which should
+      // only occur in the event of erroneous code).
+      throw new UnimplementedError();
+    }
+    return result;
+  }
+
+  /**
+   * If this reference refers to a type, build a [DartType] which instantiates
+   * it with type arguments returned by [getTypeArgument].  Otherwise return
+   * `null`.
+   *
+   * If [implicitFunctionTypeIndices] is not null, a [DartType] should be
+   * created which refers to a function type implicitly defined by one of the
+   * element's parameters.  [implicitFunctionTypeIndices] is interpreted as in
+   * [EntityRef.implicitFunctionTypeIndices].
+   */
+  DartType _buildType(
+      DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
+    ElementHandle element = this.element; // To allow type promotion
+    if (element is ClassElementHandle) {
+      return new InterfaceTypeImpl.elementWithNameAndArgs(element, name,
+          _buildTypeArguments(numTypeParameters, getTypeArgument));
+    } else if (element is FunctionTypeAliasElementHandle) {
+      return new FunctionTypeImpl.elementWithNameAndArgs(
+          element,
+          name,
+          _buildTypeArguments(numTypeParameters, getTypeArgument),
+          numTypeParameters != 0);
+    } else if (element is FunctionTypedElement) {
+      int numTypeArguments;
+      FunctionTypedElementComputer computer;
+      if (implicitFunctionTypeIndices.isNotEmpty) {
+        numTypeArguments = numTypeParameters;
+        computer = () {
+          FunctionTypedElement element = this.element;
+          for (int index in implicitFunctionTypeIndices) {
+            element = element.parameters[index].type.element;
+          }
+          return element;
+        };
+      } else {
+        // For a type that refers to a generic executable, the type arguments are
+        // not supposed to include the arguments to the executable itself.
+        numTypeArguments = enclosing == null ? 0 : enclosing.numTypeParameters;
+        computer = () => this.element;
+      }
+      // TODO(paulberry): Is it a bug that we have to pass `false` for
+      // isInstantiated?
+      return new DeferredFunctionTypeImpl(computer, null,
+          _buildTypeArguments(numTypeArguments, getTypeArgument), false);
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Build a list of type arguments having length [numTypeArguments] where each
+   * type argument is obtained by calling [getTypeArgument].
+   */
+  List<DartType> _buildTypeArguments(
+      int numTypeArguments, DartType getTypeArgument(int i)) {
+    List<DartType> typeArguments = const <DartType>[];
+    if (numTypeArguments != 0) {
+      typeArguments = <DartType>[];
+      for (int i = 0; i < numTypeArguments; i++) {
+        typeArguments.add(getTypeArgument(i));
+      }
+    }
+    return typeArguments;
   }
 }
diff --git a/pkg/analyzer/lib/src/summary/summarize_ast.dart b/pkg/analyzer/lib/src/summary/summarize_ast.dart
new file mode 100644
index 0000000..cd9ff61
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/summarize_ast.dart
@@ -0,0 +1,1136 @@
+// 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 serialization.summarize_ast;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/public_namespace_computer.dart';
+import 'package:analyzer/src/summary/summarize_const_expr.dart';
+
+/**
+ * Serialize all the declarations in [compilationUnit] to an unlinked summary.
+ */
+UnlinkedUnitBuilder serializeAstUnlinked(CompilationUnit compilationUnit) {
+  return new _SummarizeAstVisitor().serializeCompilationUnit(compilationUnit);
+}
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single constant [Expression].
+ */
+class _ConstExprSerializer extends AbstractConstExprSerializer {
+  final _SummarizeAstVisitor visitor;
+
+  /**
+   * If a constructor initializer expression is being serialized, the names of
+   * the constructor parameters.  Otherwise `null`.
+   */
+  final Set<String> constructorParameterNames;
+
+  _ConstExprSerializer(this.visitor, this.constructorParameterNames);
+
+  @override
+  bool isConstructorParameterName(String name) {
+    return constructorParameterNames?.contains(name) ?? false;
+  }
+
+  @override
+  void serializeAnnotation(Annotation annotation) {
+    if (annotation.arguments == null) {
+      assert(annotation.constructorName == null);
+      serialize(annotation.name);
+    } else {
+      Identifier name = annotation.name;
+      EntityRefBuilder constructor;
+      if (name is PrefixedIdentifier && annotation.constructorName == null) {
+        constructor = serializeConstructorName(
+            new TypeName(name.prefix, null), name.identifier);
+      } else {
+        constructor = serializeConstructorName(
+            new TypeName(annotation.name, null), annotation.constructorName);
+      }
+      serializeInstanceCreation(constructor, annotation.arguments);
+    }
+  }
+
+  @override
+  EntityRefBuilder serializeConstructorName(
+      TypeName type, SimpleIdentifier name) {
+    EntityRefBuilder typeBuilder = serializeType(type);
+    if (name == null) {
+      return typeBuilder;
+    } else {
+      int nameRef =
+          visitor.serializeReference(typeBuilder.reference, name.name);
+      return new EntityRefBuilder(
+          reference: nameRef, typeArguments: typeBuilder.typeArguments);
+    }
+  }
+
+  EntityRefBuilder serializeIdentifier(Identifier identifier) {
+    EntityRefBuilder b = new EntityRefBuilder();
+    if (identifier is SimpleIdentifier) {
+      b.reference = visitor.serializeSimpleReference(identifier.name);
+    } else if (identifier is PrefixedIdentifier) {
+      int prefix = visitor.serializeSimpleReference(identifier.prefix.name);
+      b.reference =
+          visitor.serializeReference(prefix, identifier.identifier.name);
+    } else {
+      throw new StateError(
+          'Unexpected identifier type: ${identifier.runtimeType}');
+    }
+    return b;
+  }
+
+  @override
+  EntityRefBuilder serializePropertyAccess(PropertyAccess access) {
+    Expression target = access.target;
+    if (target is Identifier) {
+      EntityRefBuilder targetRef = serializeIdentifier(target);
+      return new EntityRefBuilder(
+          reference: visitor.serializeReference(
+              targetRef.reference, access.propertyName.name));
+    } else {
+      // TODO(scheglov) should we handle other targets in malformed constants?
+      throw new StateError('Unexpected target type: ${target.runtimeType}');
+    }
+  }
+
+  @override
+  EntityRefBuilder serializeType(TypeName node) {
+    return visitor.serializeTypeName(node);
+  }
+}
+
+/**
+ * A [_Scope] represents a set of name/value pairs defined locally within a
+ * limited span of a compilation unit.  (Note that the spec also uses the term
+ * "scope" to refer to the set of names defined at top level within a
+ * compilation unit, but we do not use [_Scope] for that purpose).
+ */
+class _Scope {
+  /**
+   * Names defined in this scope, and their meanings.
+   */
+  Map<String, _ScopedEntity> _definedNames = <String, _ScopedEntity>{};
+
+  /**
+   * Look up the meaning associated with the given [name], and return it.  If
+   * [name] is not defined in this scope, return `null`.
+   */
+  _ScopedEntity operator [](String name) => _definedNames[name];
+
+  /**
+   * Let the given [name] refer to [entity] within this scope.
+   */
+  void operator []=(String name, _ScopedEntity entity) {
+    _definedNames[name] = entity;
+  }
+}
+
+/**
+ * A [_ScopedClassMember] is a [_ScopedEntity] refers to a member of a class.
+ */
+class _ScopedClassMember extends _ScopedEntity {
+  /**
+   * The name of the class.
+   */
+  final String className;
+
+  _ScopedClassMember(this.className);
+}
+
+/**
+ * Base class for entities that can live inside a scope.
+ */
+abstract class _ScopedEntity {}
+
+/**
+ * A [_ScopedTypeParameter] is a [_ScopedEntity] that refers to a type
+ * parameter of a class, typedef, or executable.
+ */
+class _ScopedTypeParameter extends _ScopedEntity {
+  /**
+   * Index of the type parameter within this scope.  Since summaries use De
+   * Bruijn indices to refer to type parameters, which count upwards from the
+   * innermost bound name, the last type parameter in the scope has an index of
+   * 1, and each preceding type parameter has the next higher index.
+   */
+  final int index;
+
+  _ScopedTypeParameter(this.index);
+}
+
+/**
+ * Visitor used to create a summary from an AST.
+ */
+class _SummarizeAstVisitor extends RecursiveAstVisitor {
+  /**
+   * List of objects which should be written to [UnlinkedUnit.classes].
+   */
+  final List<UnlinkedClassBuilder> classes = <UnlinkedClassBuilder>[];
+
+  /**
+   * List of objects which should be written to [UnlinkedUnit.enums].
+   */
+  final List<UnlinkedEnumBuilder> enums = <UnlinkedEnumBuilder>[];
+
+  /**
+   * List of objects which should be written to [UnlinkedUnit.executables],
+   * [UnlinkedClass.executables] or [UnlinkedExecutable.localFunctions].
+   */
+  List<UnlinkedExecutableBuilder> executables = <UnlinkedExecutableBuilder>[];
+
+  /**
+   * List of objects which should be written to [UnlinkedUnit.exports].
+   */
+  final List<UnlinkedExportNonPublicBuilder> exports =
+      <UnlinkedExportNonPublicBuilder>[];
+
+  /**
+   * List of objects which should be written to
+   * [UnlinkedExecutable.localLabels].
+   */
+  List<UnlinkedLabelBuilder> labels = <UnlinkedLabelBuilder>[];
+
+  /**
+   * List of objects which should be written to [UnlinkedUnit.parts].
+   */
+  final List<UnlinkedPartBuilder> parts = <UnlinkedPartBuilder>[];
+
+  /**
+   * List of objects which should be written to [UnlinkedUnit.typedefs].
+   */
+  final List<UnlinkedTypedefBuilder> typedefs = <UnlinkedTypedefBuilder>[];
+
+  /**
+   * List of objects which should be written to [UnlinkedUnit.variables],
+   * [UnlinkedClass.fields] or [UnlinkedExecutable.localVariables].
+   */
+  List<UnlinkedVariableBuilder> variables = <UnlinkedVariableBuilder>[];
+
+  /**
+   * The unlinked portion of the "imports table".  This is the list of objects
+   * which should be written to [UnlinkedUnit.imports].
+   */
+  final List<UnlinkedImportBuilder> unlinkedImports = <UnlinkedImportBuilder>[];
+
+  /**
+   * The unlinked portion of the "references table".  This is the list of
+   * objects which should be written to [UnlinkedUnit.references].
+   */
+  final List<UnlinkedReferenceBuilder> unlinkedReferences =
+      <UnlinkedReferenceBuilder>[new UnlinkedReferenceBuilder()];
+
+  /**
+   * Map associating names used as prefixes in this compilation unit with their
+   * associated indices into [UnlinkedUnit.references].
+   */
+  final Map<String, int> prefixIndices = <String, int>{};
+
+  /**
+   * List of [_Scope]s currently in effect.  This is used to resolve type names
+   * to type parameters within classes, typedefs, and executables, as well as
+   * references to class members.
+   */
+  final List<_Scope> scopes = <_Scope>[];
+
+  /**
+   * True if 'dart:core' has been explicitly imported.
+   */
+  bool hasCoreBeenImported = false;
+
+  /**
+   * Names referenced by this compilation unit.  Structured as a map from
+   * prefix index to (map from name to reference table index), where "prefix
+   * index" means the index into [UnlinkedUnit.references] of the prefix (or
+   * `null` if there is no prefix), and "reference table index" means the index
+   * into [UnlinkedUnit.references] for the name itself.
+   */
+  final Map<int, Map<String, int>> nameToReference = <int, Map<String, int>>{};
+
+  /**
+   * If the library has a library directive, the library name derived from it.
+   * Otherwise `null`.
+   */
+  String libraryName;
+
+  /**
+   * If the library has a library directive, the offset of the library name.
+   * Otherwise `null`.
+   */
+  int libraryNameOffset;
+
+  /**
+   * If the library has a library directive, the length of the library name, as
+   * it appears in the source file.  Otherwise `null`.
+   */
+  int libraryNameLength;
+
+  /**
+   * If the library has a library directive, the documentation comment for it
+   * (if any).  Otherwise `null`.
+   */
+  UnlinkedDocumentationCommentBuilder libraryDocumentationComment;
+
+  /**
+   * If the library has a library directive, the annotations for it (if any).
+   * Otherwise `null`.
+   */
+  List<UnlinkedConst> libraryAnnotations = const <UnlinkedConstBuilder>[];
+
+  /**
+   * The number of slot ids which have been assigned to this compilation unit.
+   */
+  int numSlots = 0;
+
+  /**
+   * The [Block] that is being visited now, or `null` for non-local contexts.
+   */
+  Block enclosingBlock = null;
+
+  /**
+   * Create a slot id for storing a propagated or inferred type.
+   */
+  int assignTypeSlot() => ++numSlots;
+
+  /**
+   * Build a [_Scope] object containing the names defined within the body of a
+   * class declaration.
+   */
+  _Scope buildClassMemberScope(
+      String className, NodeList<ClassMember> members) {
+    _Scope scope = new _Scope();
+    for (ClassMember member in members) {
+      if (member is MethodDeclaration) {
+        if (member.isSetter || member.isOperator) {
+          // We don't have to handle setters or operators because the only
+          // things we look up are type names and identifiers.
+        } else {
+          scope[member.name.name] = new _ScopedClassMember(className);
+        }
+      } else if (member is FieldDeclaration) {
+        for (VariableDeclaration field in member.fields.variables) {
+          // A field declaration introduces two names, one with a trailing `=`.
+          // We don't have to worry about the one with a trailing `=` because
+          // the only things we look up are type names and identifiers.
+          scope[field.name.name] = new _ScopedClassMember(className);
+        }
+      }
+    }
+    return scope;
+  }
+
+  /**
+   * Serialize the given list of [annotations].  If there are no annotations,
+   * the empty list is returned.
+   */
+  List<UnlinkedConstBuilder> serializeAnnotations(
+      NodeList<Annotation> annotations) {
+    if (annotations == null || annotations.isEmpty) {
+      return const <UnlinkedConstBuilder>[];
+    }
+    return annotations.map((Annotation a) {
+      _ConstExprSerializer serializer = new _ConstExprSerializer(this, null);
+      serializer.serializeAnnotation(a);
+      return serializer.toBuilder();
+    }).toList();
+  }
+
+  /**
+   * Serialize a [ClassDeclaration] or [ClassTypeAlias] into an [UnlinkedClass]
+   * and store the result in [classes].
+   */
+  void serializeClass(
+      Token abstractKeyword,
+      String name,
+      int nameOffset,
+      TypeParameterList typeParameters,
+      TypeName superclass,
+      WithClause withClause,
+      ImplementsClause implementsClause,
+      NodeList<ClassMember> members,
+      bool isMixinApplication,
+      Comment documentationComment,
+      NodeList<Annotation> annotations) {
+    int oldScopesLength = scopes.length;
+    List<UnlinkedExecutableBuilder> oldExecutables = executables;
+    executables = <UnlinkedExecutableBuilder>[];
+    List<UnlinkedVariableBuilder> oldVariables = variables;
+    variables = <UnlinkedVariableBuilder>[];
+    _TypeParameterScope typeParameterScope = new _TypeParameterScope();
+    scopes.add(typeParameterScope);
+    UnlinkedClassBuilder b = new UnlinkedClassBuilder();
+    b.name = name;
+    b.nameOffset = nameOffset;
+    b.isMixinApplication = isMixinApplication;
+    b.typeParameters =
+        serializeTypeParameters(typeParameters, typeParameterScope);
+    if (superclass != null) {
+      b.supertype = serializeTypeName(superclass);
+    }
+    if (withClause != null) {
+      b.mixins = withClause.mixinTypes.map(serializeTypeName).toList();
+    }
+    if (implementsClause != null) {
+      b.interfaces =
+          implementsClause.interfaces.map(serializeTypeName).toList();
+    }
+    if (members != null) {
+      scopes.add(buildClassMemberScope(name, members));
+      for (ClassMember member in members) {
+        member.accept(this);
+      }
+      scopes.removeLast();
+    }
+    b.executables = executables;
+    b.fields = variables;
+    b.isAbstract = abstractKeyword != null;
+    b.documentationComment = serializeDocumentation(documentationComment);
+    b.annotations = serializeAnnotations(annotations);
+    classes.add(b);
+    scopes.removeLast();
+    assert(scopes.length == oldScopesLength);
+    executables = oldExecutables;
+    variables = oldVariables;
+  }
+
+  /**
+   * Serialize a [Combinator] into an [UnlinkedCombinator].
+   */
+  UnlinkedCombinatorBuilder serializeCombinator(Combinator combinator) {
+    UnlinkedCombinatorBuilder b = new UnlinkedCombinatorBuilder();
+    if (combinator is ShowCombinator) {
+      b.shows =
+          combinator.shownNames.map((SimpleIdentifier id) => id.name).toList();
+      b.offset = combinator.offset;
+      b.end = combinator.end;
+    } else if (combinator is HideCombinator) {
+      b.hides =
+          combinator.hiddenNames.map((SimpleIdentifier id) => id.name).toList();
+    } else {
+      throw new StateError(
+          'Unexpected combinator type: ${combinator.runtimeType}');
+    }
+    return b;
+  }
+
+  /**
+   * Main entry point for serializing an AST.
+   */
+  UnlinkedUnitBuilder serializeCompilationUnit(
+      CompilationUnit compilationUnit) {
+    compilationUnit.directives.accept(this);
+    if (!hasCoreBeenImported) {
+      unlinkedImports.add(new UnlinkedImportBuilder(isImplicit: true));
+    }
+    compilationUnit.declarations.accept(this);
+    UnlinkedUnitBuilder b = new UnlinkedUnitBuilder();
+    b.libraryName = libraryName;
+    b.libraryNameOffset = libraryNameOffset;
+    b.libraryNameLength = libraryNameLength;
+    b.libraryDocumentationComment = libraryDocumentationComment;
+    b.libraryAnnotations = libraryAnnotations;
+    b.classes = classes;
+    b.enums = enums;
+    b.executables = executables;
+    b.exports = exports;
+    b.imports = unlinkedImports;
+    b.parts = parts;
+    b.references = unlinkedReferences;
+    b.typedefs = typedefs;
+    b.variables = variables;
+    b.publicNamespace = computePublicNamespace(compilationUnit);
+    return b;
+  }
+
+  /**
+   * Serialize the given [expression], creating an [UnlinkedConstBuilder].
+   */
+  UnlinkedConstBuilder serializeConstExpr(Expression expression,
+      [Set<String> constructorParameterNames]) {
+    _ConstExprSerializer serializer =
+        new _ConstExprSerializer(this, constructorParameterNames);
+    serializer.serialize(expression);
+    return serializer.toBuilder();
+  }
+
+  /**
+   * Serialize a [Comment] node into an [UnlinkedDocumentationComment] object.
+   */
+  UnlinkedDocumentationCommentBuilder serializeDocumentation(
+      Comment documentationComment) {
+    if (documentationComment == null) {
+      return null;
+    }
+    String text = documentationComment.tokens
+        .map((Token t) => t.toString())
+        .join()
+        .replaceAll('\r\n', '\n');
+    return new UnlinkedDocumentationCommentBuilder(
+        text: text,
+        offset: documentationComment.offset,
+        length: documentationComment.length);
+  }
+
+  /**
+   * Serialize a [FunctionDeclaration] or [MethodDeclaration] into an
+   * [UnlinkedExecutable].
+   */
+  UnlinkedExecutableBuilder serializeExecutable(
+      String name,
+      int nameOffset,
+      bool isGetter,
+      bool isSetter,
+      TypeName returnType,
+      FormalParameterList formalParameters,
+      FunctionBody body,
+      bool isTopLevel,
+      bool isDeclaredStatic,
+      Comment documentationComment,
+      NodeList<Annotation> annotations,
+      TypeParameterList typeParameters,
+      bool isExternal) {
+    int oldScopesLength = scopes.length;
+    _TypeParameterScope typeParameterScope = new _TypeParameterScope();
+    scopes.add(typeParameterScope);
+    UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder();
+    String nameString = name;
+    if (isGetter) {
+      b.kind = UnlinkedExecutableKind.getter;
+    } else if (isSetter) {
+      b.kind = UnlinkedExecutableKind.setter;
+      nameString = '$nameString=';
+    } else {
+      b.kind = UnlinkedExecutableKind.functionOrMethod;
+    }
+    b.isAbstract = body is EmptyFunctionBody;
+    b.name = nameString;
+    b.nameOffset = nameOffset;
+    b.typeParameters =
+        serializeTypeParameters(typeParameters, typeParameterScope);
+    if (!isTopLevel) {
+      b.isStatic = isDeclaredStatic;
+    }
+    b.returnType = serializeTypeName(returnType);
+    b.isExternal = isExternal;
+    bool isSemanticallyStatic = isTopLevel || isDeclaredStatic;
+    if (formalParameters != null) {
+      b.parameters = formalParameters.parameters
+          .map((FormalParameter p) => p.accept(this))
+          .toList();
+      if (!isSemanticallyStatic) {
+        for (int i = 0; i < formalParameters.parameters.length; i++) {
+          if (!b.parameters[i].isFunctionTyped &&
+              b.parameters[i].type == null) {
+            b.parameters[i].inferredTypeSlot = assignTypeSlot();
+          }
+        }
+      }
+    }
+    b.documentationComment = serializeDocumentation(documentationComment);
+    b.annotations = serializeAnnotations(annotations);
+    if (returnType == null && !isSemanticallyStatic) {
+      b.inferredReturnTypeSlot = assignTypeSlot();
+    }
+    b.visibleOffset = enclosingBlock?.offset;
+    b.visibleLength = enclosingBlock?.length;
+    serializeFunctionBody(b, body);
+    scopes.removeLast();
+    assert(scopes.length == oldScopesLength);
+    return b;
+  }
+
+  /**
+   * Record local functions and variables into the given executable. The given
+   * [body] is usually an actual [FunctionBody], but may be an [Expression]
+   * when we process a synthetic variable initializer function.
+   */
+  void serializeFunctionBody(UnlinkedExecutableBuilder b, AstNode body) {
+    if (body is BlockFunctionBody || body is ExpressionFunctionBody) {
+      for (UnlinkedParamBuilder parameter in b.parameters) {
+        parameter.visibleOffset = body.offset;
+        parameter.visibleLength = body.length;
+      }
+    }
+    List<UnlinkedExecutableBuilder> oldExecutables = executables;
+    List<UnlinkedLabelBuilder> oldLabels = labels;
+    List<UnlinkedVariableBuilder> oldVariables = variables;
+    executables = <UnlinkedExecutableBuilder>[];
+    labels = <UnlinkedLabelBuilder>[];
+    variables = <UnlinkedVariableBuilder>[];
+    body.accept(this);
+    b.localFunctions = executables;
+    b.localLabels = labels;
+    b.localVariables = variables;
+    executables = oldExecutables;
+    labels = oldLabels;
+    variables = oldVariables;
+  }
+
+  /**
+   * Serialize the return type and parameters of a function-typed formal
+   * parameter and store them in [b].
+   */
+  void serializeFunctionTypedParameterDetails(UnlinkedParamBuilder b,
+      TypeName returnType, FormalParameterList parameters) {
+    EntityRefBuilder serializedReturnType = serializeTypeName(returnType);
+    if (serializedReturnType != null) {
+      b.type = serializedReturnType;
+    }
+    b.parameters = parameters.parameters
+        .map((FormalParameter p) => p.accept(this))
+        .toList();
+  }
+
+  /**
+   * If the given [expression] is not `null`, serialize it as an
+   * [UnlinkedExecutableBuilder], otherwise return `null`.
+   */
+  UnlinkedExecutableBuilder serializeInitializerFunction(
+      Expression expression) {
+    if (expression == null) {
+      return null;
+    }
+    UnlinkedExecutableBuilder initializer =
+        new UnlinkedExecutableBuilder(nameOffset: expression.offset);
+    serializeFunctionBody(initializer, expression);
+    initializer.inferredReturnTypeSlot = assignTypeSlot();
+    return initializer;
+  }
+
+  /**
+   * Serialize a [FieldFormalParameter], [FunctionTypedFormalParameter], or
+   * [SimpleFormalParameter] into an [UnlinkedParam].
+   */
+  UnlinkedParamBuilder serializeParameter(NormalFormalParameter node) {
+    UnlinkedParamBuilder b = new UnlinkedParamBuilder();
+    b.name = node.identifier.name;
+    b.nameOffset = node.identifier.offset;
+    b.annotations = serializeAnnotations(node.metadata);
+    switch (node.kind) {
+      case ParameterKind.REQUIRED:
+        b.kind = UnlinkedParamKind.required;
+        break;
+      case ParameterKind.POSITIONAL:
+        b.kind = UnlinkedParamKind.positional;
+        break;
+      case ParameterKind.NAMED:
+        b.kind = UnlinkedParamKind.named;
+        break;
+      default:
+        throw new StateError('Unexpected parameter kind: ${node.kind}');
+    }
+    return b;
+  }
+
+  /**
+   * Serialize a reference to a top level name declared elsewhere, by adding an
+   * entry to the references table if necessary.  If [prefixIndex] is not null,
+   * the reference is associated with the prefix having the given index in the
+   * references table.
+   */
+  int serializeReference(int prefixIndex, String name) => nameToReference
+          .putIfAbsent(prefixIndex, () => <String, int>{})
+          .putIfAbsent(name, () {
+        int index = unlinkedReferences.length;
+        unlinkedReferences.add(new UnlinkedReferenceBuilder(
+            prefixReference: prefixIndex, name: name));
+        return index;
+      });
+
+  /**
+   * Serialize a reference to a name declared either at top level or in a
+   * nested scope.
+   */
+  int serializeSimpleReference(String name) {
+    for (int i = scopes.length - 1; i >= 0; i--) {
+      _Scope scope = scopes[i];
+      _ScopedEntity entity = scope[name];
+      if (entity != null) {
+        if (entity is _ScopedClassMember) {
+          return serializeReference(
+              serializeReference(null, entity.className), name);
+        } else {
+          // Invalid reference to a type parameter.  Should never happen in
+          // legal Dart code.
+          // TODO(paulberry): could this exception ever be uncaught in illegal
+          // code?
+          throw new StateError('Invalid identifier reference');
+        }
+      }
+    }
+    return serializeReference(null, name);
+  }
+
+  /**
+   * Serialize a type name (which might be defined in a nested scope, at top
+   * level within this library, or at top level within an imported library) to
+   * a [EntityRef].  Note that this method does the right thing if the
+   * name doesn't refer to an entity other than a type (e.g. a class member).
+   */
+  EntityRefBuilder serializeTypeName(TypeName node) {
+    if (node == null) {
+      return null;
+    } else {
+      EntityRefBuilder b = new EntityRefBuilder();
+      Identifier identifier = node.name;
+      if (identifier is SimpleIdentifier) {
+        String name = identifier.name;
+        int indexOffset = 0;
+        for (int i = scopes.length - 1; i >= 0; i--) {
+          _Scope scope = scopes[i];
+          _ScopedEntity entity = scope[name];
+          if (entity != null) {
+            if (entity is _ScopedTypeParameter) {
+              b.paramReference = indexOffset + entity.index;
+              return b;
+            } else {
+              // None of the other things that can be declared in local scopes
+              // are types, so this is an error and should be treated as a
+              // reference to `dynamic`.
+              b.reference = serializeReference(null, 'dynamic');
+              return b;
+            }
+          }
+          if (scope is _TypeParameterScope) {
+            indexOffset += scope.length;
+          }
+        }
+        b.reference = serializeReference(null, name);
+      } else if (identifier is PrefixedIdentifier) {
+        int prefixIndex = prefixIndices.putIfAbsent(identifier.prefix.name,
+            () => serializeSimpleReference(identifier.prefix.name));
+        b.reference =
+            serializeReference(prefixIndex, identifier.identifier.name);
+      } else {
+        throw new StateError(
+            'Unexpected identifier type: ${identifier.runtimeType}');
+      }
+      if (node.typeArguments != null) {
+        // Trailing type arguments of type 'dynamic' should be omitted.
+        NodeList<TypeName> args = node.typeArguments.arguments;
+        int numArgsToSerialize = args.length;
+        while (
+            numArgsToSerialize > 0 && isDynamic(args[numArgsToSerialize - 1])) {
+          --numArgsToSerialize;
+        }
+        if (numArgsToSerialize > 0) {
+          List<EntityRefBuilder> serializedArguments = <EntityRefBuilder>[];
+          for (int i = 0; i < numArgsToSerialize; i++) {
+            serializedArguments.add(serializeTypeName(args[i]));
+          }
+          b.typeArguments = serializedArguments;
+        }
+      }
+      return b;
+    }
+  }
+
+  /**
+   * Serialize the given [typeParameters] into a list of [UnlinkedTypeParam]s,
+   * and also store them in [typeParameterScope].
+   */
+  List<UnlinkedTypeParamBuilder> serializeTypeParameters(
+      TypeParameterList typeParameters,
+      _TypeParameterScope typeParameterScope) {
+    if (typeParameters != null) {
+      for (int i = 0; i < typeParameters.typeParameters.length; i++) {
+        TypeParameter typeParameter = typeParameters.typeParameters[i];
+        typeParameterScope[typeParameter.name.name] =
+            new _ScopedTypeParameter(typeParameters.typeParameters.length - i);
+      }
+      return typeParameters.typeParameters.map(visitTypeParameter).toList();
+    }
+    return const <UnlinkedTypeParamBuilder>[];
+  }
+
+  /**
+   * Serialize the given [variables] into [UnlinkedVariable]s, and store them
+   * in [this.variables].
+   */
+  void serializeVariables(
+      VariableDeclarationList variables,
+      bool isDeclaredStatic,
+      Comment documentationComment,
+      NodeList<Annotation> annotations,
+      bool isField) {
+    for (VariableDeclaration variable in variables.variables) {
+      UnlinkedVariableBuilder b = new UnlinkedVariableBuilder();
+      b.isFinal = variables.isFinal;
+      b.isConst = variables.isConst;
+      b.isStatic = isDeclaredStatic;
+      b.name = variable.name.name;
+      b.nameOffset = variable.name.offset;
+      b.type = serializeTypeName(variables.type);
+      b.documentationComment = serializeDocumentation(documentationComment);
+      b.annotations = serializeAnnotations(annotations);
+      if (variable.isConst ||
+          variable.isFinal && isField && !isDeclaredStatic) {
+        Expression initializer = variable.initializer;
+        if (initializer != null) {
+          b.constExpr = serializeConstExpr(initializer);
+        }
+      }
+      if (variable.initializer != null &&
+          (variables.isFinal || variables.isConst)) {
+        b.propagatedTypeSlot = assignTypeSlot();
+      }
+      bool isSemanticallyStatic = !isField || isDeclaredStatic;
+      if (variables.type == null &&
+          (variable.initializer != null || !isSemanticallyStatic)) {
+        b.inferredTypeSlot = assignTypeSlot();
+      }
+      b.visibleOffset = enclosingBlock?.offset;
+      b.visibleLength = enclosingBlock?.length;
+      b.initializer = serializeInitializerFunction(variable.initializer);
+      this.variables.add(b);
+    }
+  }
+
+  @override
+  void visitBlock(Block node) {
+    Block oldBlock = enclosingBlock;
+    enclosingBlock = node;
+    super.visitBlock(node);
+    enclosingBlock = oldBlock;
+  }
+
+  @override
+  void visitClassDeclaration(ClassDeclaration node) {
+    TypeName superclass =
+        node.extendsClause == null ? null : node.extendsClause.superclass;
+    serializeClass(
+        node.abstractKeyword,
+        node.name.name,
+        node.name.offset,
+        node.typeParameters,
+        superclass,
+        node.withClause,
+        node.implementsClause,
+        node.members,
+        false,
+        node.documentationComment,
+        node.metadata);
+  }
+
+  @override
+  void visitClassTypeAlias(ClassTypeAlias node) {
+    serializeClass(
+        node.abstractKeyword,
+        node.name.name,
+        node.name.offset,
+        node.typeParameters,
+        node.superclass,
+        node.withClause,
+        node.implementsClause,
+        null,
+        true,
+        node.documentationComment,
+        node.metadata);
+  }
+
+  @override
+  void visitConstructorDeclaration(ConstructorDeclaration node) {
+    UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder();
+    if (node.name != null) {
+      b.name = node.name.name;
+      b.nameOffset = node.name.offset;
+      b.periodOffset = node.period.offset;
+      b.nameEnd = node.name.end;
+    } else {
+      b.nameOffset = node.returnType.offset;
+    }
+    b.parameters = node.parameters.parameters
+        .map((FormalParameter p) => p.accept(this))
+        .toList();
+    b.kind = UnlinkedExecutableKind.constructor;
+    if (node.factoryKeyword != null) {
+      b.isFactory = true;
+      if (node.redirectedConstructor != null) {
+        b.isRedirectedConstructor = true;
+        b.redirectedConstructor = new _ConstExprSerializer(this, null)
+            .serializeConstructorName(node.redirectedConstructor.type,
+                node.redirectedConstructor.name);
+      }
+    } else {
+      for (ConstructorInitializer initializer in node.initializers) {
+        if (initializer is RedirectingConstructorInvocation) {
+          b.isRedirectedConstructor = true;
+          b.redirectedConstructorName = initializer.constructorName?.name;
+        }
+      }
+    }
+    b.isConst = node.constKeyword != null;
+    b.isExternal = node.externalKeyword != null;
+    b.documentationComment = serializeDocumentation(node.documentationComment);
+    b.annotations = serializeAnnotations(node.metadata);
+    if (node.constKeyword != null) {
+      Set<String> constructorParameterNames =
+          node.parameters.parameters.map((p) => p.identifier.name).toSet();
+      b.constantInitializers = node.initializers
+          .map((ConstructorInitializer initializer) =>
+              serializeConstructorInitializer(initializer, (Expression expr) {
+                return serializeConstExpr(expr, constructorParameterNames);
+              }))
+          .toList();
+    }
+    serializeFunctionBody(b, node.body);
+    executables.add(b);
+  }
+
+  @override
+  UnlinkedParamBuilder visitDefaultFormalParameter(
+      DefaultFormalParameter node) {
+    UnlinkedParamBuilder b = node.parameter.accept(this);
+    if (node.defaultValue != null) {
+      b.defaultValue = serializeConstExpr(node.defaultValue);
+      b.defaultValueCode = node.defaultValue.toSource();
+    }
+    b.initializer = serializeInitializerFunction(node.defaultValue);
+    return b;
+  }
+
+  @override
+  void visitEnumDeclaration(EnumDeclaration node) {
+    UnlinkedEnumBuilder b = new UnlinkedEnumBuilder();
+    b.name = node.name.name;
+    b.nameOffset = node.name.offset;
+    b.values = node.constants
+        .map((EnumConstantDeclaration value) => new UnlinkedEnumValueBuilder(
+            documentationComment:
+                serializeDocumentation(value.documentationComment),
+            name: value.name.name,
+            nameOffset: value.name.offset))
+        .toList();
+    b.documentationComment = serializeDocumentation(node.documentationComment);
+    b.annotations = serializeAnnotations(node.metadata);
+    enums.add(b);
+  }
+
+  @override
+  void visitExportDirective(ExportDirective node) {
+    UnlinkedExportNonPublicBuilder b = new UnlinkedExportNonPublicBuilder(
+        uriOffset: node.uri.offset, uriEnd: node.uri.end, offset: node.offset);
+    b.annotations = serializeAnnotations(node.metadata);
+    exports.add(b);
+  }
+
+  @override
+  void visitFieldDeclaration(FieldDeclaration node) {
+    serializeVariables(node.fields, node.staticKeyword != null,
+        node.documentationComment, node.metadata, true);
+  }
+
+  @override
+  UnlinkedParamBuilder visitFieldFormalParameter(FieldFormalParameter node) {
+    UnlinkedParamBuilder b = serializeParameter(node);
+    b.isInitializingFormal = true;
+    if (node.type != null || node.parameters != null) {
+      b.isFunctionTyped = node.parameters != null;
+      if (node.parameters != null) {
+        serializeFunctionTypedParameterDetails(b, node.type, node.parameters);
+      } else {
+        b.type = serializeTypeName(node.type);
+      }
+    }
+    return b;
+  }
+
+  @override
+  void visitFunctionDeclaration(FunctionDeclaration node) {
+    executables.add(serializeExecutable(
+        node.name.name,
+        node.name.offset,
+        node.isGetter,
+        node.isSetter,
+        node.returnType,
+        node.functionExpression.parameters,
+        node.functionExpression.body,
+        true,
+        false,
+        node.documentationComment,
+        node.metadata,
+        node.functionExpression.typeParameters,
+        node.externalKeyword != null));
+  }
+
+  @override
+  void visitFunctionExpression(FunctionExpression node) {
+    if (node.parent is! FunctionDeclaration) {
+      executables.add(serializeExecutable(
+          null,
+          node.offset,
+          false,
+          false,
+          null,
+          node.parameters,
+          node.body,
+          false,
+          false,
+          null,
+          null,
+          node.typeParameters,
+          false));
+    }
+  }
+
+  @override
+  void visitFunctionTypeAlias(FunctionTypeAlias node) {
+    int oldScopesLength = scopes.length;
+    _TypeParameterScope typeParameterScope = new _TypeParameterScope();
+    scopes.add(typeParameterScope);
+    UnlinkedTypedefBuilder b = new UnlinkedTypedefBuilder();
+    b.name = node.name.name;
+    b.nameOffset = node.name.offset;
+    b.typeParameters =
+        serializeTypeParameters(node.typeParameters, typeParameterScope);
+    EntityRefBuilder serializedReturnType = serializeTypeName(node.returnType);
+    if (serializedReturnType != null) {
+      b.returnType = serializedReturnType;
+    }
+    b.parameters = node.parameters.parameters
+        .map((FormalParameter p) => p.accept(this))
+        .toList();
+    b.documentationComment = serializeDocumentation(node.documentationComment);
+    b.annotations = serializeAnnotations(node.metadata);
+    typedefs.add(b);
+    scopes.removeLast();
+    assert(scopes.length == oldScopesLength);
+  }
+
+  @override
+  UnlinkedParamBuilder visitFunctionTypedFormalParameter(
+      FunctionTypedFormalParameter node) {
+    UnlinkedParamBuilder b = serializeParameter(node);
+    b.isFunctionTyped = true;
+    serializeFunctionTypedParameterDetails(b, node.returnType, node.parameters);
+    return b;
+  }
+
+  @override
+  void visitImportDirective(ImportDirective node) {
+    UnlinkedImportBuilder b = new UnlinkedImportBuilder();
+    b.annotations = serializeAnnotations(node.metadata);
+    if (node.uri.stringValue == 'dart:core') {
+      hasCoreBeenImported = true;
+    }
+    b.offset = node.offset;
+    b.combinators = node.combinators.map(serializeCombinator).toList();
+    if (node.prefix != null) {
+      b.prefixReference = serializeReference(null, node.prefix.name);
+      b.prefixOffset = node.prefix.offset;
+    }
+    b.isDeferred = node.deferredKeyword != null;
+    b.uri = node.uri.stringValue;
+    b.uriOffset = node.uri.offset;
+    b.uriEnd = node.uri.end;
+    unlinkedImports.add(b);
+  }
+
+  @override
+  void visitLabel(Label node) {
+    AstNode parent = node.parent;
+    labels.add(new UnlinkedLabelBuilder(
+        name: node.label.name,
+        nameOffset: node.offset,
+        isOnSwitchMember: parent is SwitchMember,
+        isOnSwitchStatement:
+            parent is LabeledStatement && parent.statement is SwitchStatement));
+  }
+
+  @override
+  void visitLibraryDirective(LibraryDirective node) {
+    libraryName =
+        node.name.components.map((SimpleIdentifier id) => id.name).join('.');
+    libraryNameOffset = node.name.offset;
+    libraryNameLength = node.name.length;
+    libraryDocumentationComment =
+        serializeDocumentation(node.documentationComment);
+    libraryAnnotations = serializeAnnotations(node.metadata);
+  }
+
+  @override
+  void visitMethodDeclaration(MethodDeclaration node) {
+    executables.add(serializeExecutable(
+        node.name.name,
+        node.name.offset,
+        node.isGetter,
+        node.isSetter,
+        node.returnType,
+        node.parameters,
+        node.body,
+        false,
+        node.isStatic,
+        node.documentationComment,
+        node.metadata,
+        node.typeParameters,
+        node.externalKeyword != null));
+  }
+
+  @override
+  void visitPartDirective(PartDirective node) {
+    parts.add(new UnlinkedPartBuilder(
+        uriOffset: node.uri.offset,
+        uriEnd: node.uri.end,
+        annotations: serializeAnnotations(node.metadata)));
+  }
+
+  @override
+  void visitPartOfDirective(PartOfDirective node) {}
+
+  @override
+  UnlinkedParamBuilder visitSimpleFormalParameter(SimpleFormalParameter node) {
+    UnlinkedParamBuilder b = serializeParameter(node);
+    b.type = serializeTypeName(node.type);
+    return b;
+  }
+
+  @override
+  void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+    serializeVariables(
+        node.variables, false, node.documentationComment, node.metadata, false);
+  }
+
+  @override
+  UnlinkedTypeParamBuilder visitTypeParameter(TypeParameter node) {
+    UnlinkedTypeParamBuilder b = new UnlinkedTypeParamBuilder();
+    b.name = node.name.name;
+    b.nameOffset = node.name.offset;
+    if (node.bound != null) {
+      b.bound = serializeTypeName(node.bound);
+    }
+    b.annotations = serializeAnnotations(node.metadata);
+    return b;
+  }
+
+  @override
+  void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
+    serializeVariables(node.variables, false, null, null, false);
+  }
+
+  /**
+   * Helper method to determine if a given [typeName] refers to `dynamic`.
+   */
+  static bool isDynamic(TypeName typeName) {
+    Identifier name = typeName.name;
+    return name is SimpleIdentifier && name.name == 'dynamic';
+  }
+}
+
+/**
+ * A [_TypeParameterScope] is a [_Scope] which defines [_ScopedTypeParameter]s.
+ */
+class _TypeParameterScope extends _Scope {
+  /**
+   * Get the number of [_ScopedTypeParameter]s defined in this
+   * [_TypeParameterScope].
+   */
+  int get length => _definedNames.length;
+}
diff --git a/pkg/analyzer/lib/src/summary/summarize_const_expr.dart b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
new file mode 100644
index 0000000..9e63ff8
--- /dev/null
+++ b/pkg/analyzer/lib/src/summary/summarize_const_expr.dart
@@ -0,0 +1,372 @@
+// 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 serialization.summarize_const_expr;
+
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/idl.dart';
+
+/**
+ * Serialize the given constructor initializer [node].
+ */
+UnlinkedConstructorInitializer serializeConstructorInitializer(
+    ConstructorInitializer node,
+    UnlinkedConstBuilder serializeConstExpr(Expression expr)) {
+  if (node is ConstructorFieldInitializer) {
+    return new UnlinkedConstructorInitializerBuilder(
+        kind: UnlinkedConstructorInitializerKind.field,
+        name: node.fieldName.name,
+        expression: serializeConstExpr(node.expression));
+  }
+  if (node is RedirectingConstructorInvocation) {
+    return new UnlinkedConstructorInitializerBuilder(
+        kind: UnlinkedConstructorInitializerKind.thisInvocation,
+        name: node?.constructorName?.name,
+        arguments:
+            node.argumentList.arguments.map(serializeConstExpr).toList());
+  }
+  if (node is SuperConstructorInvocation) {
+    return new UnlinkedConstructorInitializerBuilder(
+        kind: UnlinkedConstructorInitializerKind.superInvocation,
+        name: node?.constructorName?.name,
+        arguments:
+            node.argumentList.arguments.map(serializeConstExpr).toList());
+  }
+  throw new StateError('Unexpected initializer type ${node.runtimeType}');
+}
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single constant [Expression].
+ */
+abstract class AbstractConstExprSerializer {
+  /**
+   * See [UnlinkedConstBuilder.isInvalid].
+   */
+  bool isInvalid = false;
+
+  /**
+   * See [UnlinkedConstBuilder.operations].
+   */
+  final List<UnlinkedConstOperation> operations = <UnlinkedConstOperation>[];
+
+  /**
+   * See [UnlinkedConstBuilder.ints].
+   */
+  final List<int> ints = <int>[];
+
+  /**
+   * See [UnlinkedConstBuilder.doubles].
+   */
+  final List<double> doubles = <double>[];
+
+  /**
+   * See [UnlinkedConstBuilder.strings].
+   */
+  final List<String> strings = <String>[];
+
+  /**
+   * See [UnlinkedConstBuilder.references].
+   */
+  final List<EntityRefBuilder> references = <EntityRefBuilder>[];
+
+  /**
+   * Return `true` if a constructor initializer expression is being serialized
+   * and the given [name] is a constructor parameter reference.
+   */
+  bool isConstructorParameterName(String name);
+
+  /**
+   * Serialize the given [expr] expression into this serializer state.
+   */
+  void serialize(Expression expr) {
+    try {
+      _serialize(expr);
+    } on StateError {
+      isInvalid = true;
+    }
+  }
+
+  /**
+   * Serialize the given [annotation] into this serializer state.
+   */
+  void serializeAnnotation(Annotation annotation);
+
+  /**
+   * Return [EntityRefBuilder] that corresponds to the constructor having name
+   * [name] in the class identified by [type].
+   */
+  EntityRefBuilder serializeConstructorName(
+      TypeName type, SimpleIdentifier name);
+
+  /**
+   * Return [EntityRefBuilder] that corresponds to the given [identifier].
+   */
+  EntityRefBuilder serializeIdentifier(Identifier identifier);
+
+  void serializeInstanceCreation(
+      EntityRefBuilder constructor, ArgumentList argumentList) {
+    List<Expression> arguments = argumentList.arguments;
+    // Serialize the arguments.
+    List<String> argumentNames = <String>[];
+    arguments.forEach((arg) {
+      if (arg is NamedExpression) {
+        argumentNames.add(arg.name.label.name);
+        _serialize(arg.expression);
+      } else {
+        _serialize(arg);
+      }
+    });
+    // Add the op-code and numbers of named and positional arguments.
+    operations.add(UnlinkedConstOperation.invokeConstructor);
+    ints.add(argumentNames.length);
+    strings.addAll(argumentNames);
+    ints.add(arguments.length - argumentNames.length);
+    // Serialize the reference.
+    references.add(constructor);
+  }
+
+  /**
+   * Return [EntityRefBuilder] that corresponds to the given [access].
+   */
+  EntityRefBuilder serializePropertyAccess(PropertyAccess access);
+
+  /**
+   * Return [EntityRefBuilder] that corresponds to the given [type].
+   */
+  EntityRefBuilder serializeType(TypeName type);
+
+  /**
+   * Return the [UnlinkedConstBuilder] that corresponds to the state of this
+   * serializer.
+   */
+  UnlinkedConstBuilder toBuilder() {
+    if (isInvalid) {
+      return new UnlinkedConstBuilder(isInvalid: true);
+    }
+    return new UnlinkedConstBuilder(
+        operations: operations,
+        ints: ints,
+        doubles: doubles,
+        strings: strings,
+        references: references);
+  }
+
+  void _pushInt(int value) {
+    assert(value >= 0);
+    if (value >= (1 << 32)) {
+      int numOfComponents = 0;
+      ints.add(numOfComponents);
+      void pushComponents(int value) {
+        if (value >= (1 << 32)) {
+          pushComponents(value >> 32);
+        }
+        numOfComponents++;
+        ints.add(value & 0xFFFFFFFF);
+      }
+      pushComponents(value);
+      ints[ints.length - 1 - numOfComponents] = numOfComponents;
+      operations.add(UnlinkedConstOperation.pushLongInt);
+    } else {
+      operations.add(UnlinkedConstOperation.pushInt);
+      ints.add(value);
+    }
+  }
+
+  /**
+   * Serialize the given [expr] expression into this serializer state.
+   */
+  void _serialize(Expression expr) {
+    if (expr is IntegerLiteral) {
+      _pushInt(expr.value);
+    } else if (expr is DoubleLiteral) {
+      operations.add(UnlinkedConstOperation.pushDouble);
+      doubles.add(expr.value);
+    } else if (expr is BooleanLiteral) {
+      if (expr.value) {
+        operations.add(UnlinkedConstOperation.pushTrue);
+      } else {
+        operations.add(UnlinkedConstOperation.pushFalse);
+      }
+    } else if (expr is StringLiteral) {
+      _serializeString(expr);
+    } else if (expr is SymbolLiteral) {
+      strings.add(expr.components.map((token) => token.lexeme).join('.'));
+      operations.add(UnlinkedConstOperation.makeSymbol);
+    } else if (expr is NullLiteral) {
+      operations.add(UnlinkedConstOperation.pushNull);
+    } else if (expr is Identifier) {
+      if (expr is SimpleIdentifier && isConstructorParameterName(expr.name)) {
+        strings.add(expr.name);
+        operations.add(UnlinkedConstOperation.pushConstructorParameter);
+      } else {
+        references.add(serializeIdentifier(expr));
+        operations.add(UnlinkedConstOperation.pushReference);
+      }
+    } else if (expr is InstanceCreationExpression) {
+      serializeInstanceCreation(
+          serializeConstructorName(
+              expr.constructorName.type, expr.constructorName.name),
+          expr.argumentList);
+    } else if (expr is ListLiteral) {
+      _serializeListLiteral(expr);
+    } else if (expr is MapLiteral) {
+      _serializeMapLiteral(expr);
+    } else if (expr is MethodInvocation) {
+      String name = expr.methodName.name;
+      if (name != 'identical') {
+        throw new StateError('Only "identity" function invocation is allowed.');
+      }
+      if (expr.argumentList == null ||
+          expr.argumentList.arguments.length != 2) {
+        throw new StateError(
+            'The function "identity" requires exactly 2 arguments.');
+      }
+      expr.argumentList.arguments.forEach(_serialize);
+      operations.add(UnlinkedConstOperation.identical);
+    } else if (expr is BinaryExpression) {
+      _serializeBinaryExpression(expr);
+    } else if (expr is ConditionalExpression) {
+      _serialize(expr.condition);
+      _serialize(expr.thenExpression);
+      _serialize(expr.elseExpression);
+      operations.add(UnlinkedConstOperation.conditional);
+    } else if (expr is PrefixExpression) {
+      _serializePrefixExpression(expr);
+    } else if (expr is PropertyAccess) {
+      if (expr.target is! PrefixedIdentifier &&
+          expr.propertyName.name == 'length') {
+        _serialize(expr.target);
+        operations.add(UnlinkedConstOperation.length);
+      } else {
+        references.add(serializePropertyAccess(expr));
+        operations.add(UnlinkedConstOperation.pushReference);
+      }
+    } else if (expr is ParenthesizedExpression) {
+      _serialize(expr.expression);
+    } else {
+      throw new StateError('Unknown expression type: $expr');
+    }
+  }
+
+  void _serializeBinaryExpression(BinaryExpression expr) {
+    _serialize(expr.leftOperand);
+    _serialize(expr.rightOperand);
+    TokenType operator = expr.operator.type;
+    if (operator == TokenType.EQ_EQ) {
+      operations.add(UnlinkedConstOperation.equal);
+    } else if (operator == TokenType.BANG_EQ) {
+      operations.add(UnlinkedConstOperation.notEqual);
+    } else if (operator == TokenType.AMPERSAND_AMPERSAND) {
+      operations.add(UnlinkedConstOperation.and);
+    } else if (operator == TokenType.BAR_BAR) {
+      operations.add(UnlinkedConstOperation.or);
+    } else if (operator == TokenType.CARET) {
+      operations.add(UnlinkedConstOperation.bitXor);
+    } else if (operator == TokenType.AMPERSAND) {
+      operations.add(UnlinkedConstOperation.bitAnd);
+    } else if (operator == TokenType.BAR) {
+      operations.add(UnlinkedConstOperation.bitOr);
+    } else if (operator == TokenType.GT_GT) {
+      operations.add(UnlinkedConstOperation.bitShiftRight);
+    } else if (operator == TokenType.LT_LT) {
+      operations.add(UnlinkedConstOperation.bitShiftLeft);
+    } else if (operator == TokenType.PLUS) {
+      operations.add(UnlinkedConstOperation.add);
+    } else if (operator == TokenType.MINUS) {
+      operations.add(UnlinkedConstOperation.subtract);
+    } else if (operator == TokenType.STAR) {
+      operations.add(UnlinkedConstOperation.multiply);
+    } else if (operator == TokenType.SLASH) {
+      operations.add(UnlinkedConstOperation.divide);
+    } else if (operator == TokenType.TILDE_SLASH) {
+      operations.add(UnlinkedConstOperation.floorDivide);
+    } else if (operator == TokenType.GT) {
+      operations.add(UnlinkedConstOperation.greater);
+    } else if (operator == TokenType.LT) {
+      operations.add(UnlinkedConstOperation.less);
+    } else if (operator == TokenType.GT_EQ) {
+      operations.add(UnlinkedConstOperation.greaterEqual);
+    } else if (operator == TokenType.LT_EQ) {
+      operations.add(UnlinkedConstOperation.lessEqual);
+    } else if (operator == TokenType.PERCENT) {
+      operations.add(UnlinkedConstOperation.modulo);
+    } else {
+      throw new StateError('Unknown operator: $operator');
+    }
+  }
+
+  void _serializeListLiteral(ListLiteral expr) {
+    List<Expression> elements = expr.elements;
+    elements.forEach(_serialize);
+    ints.add(elements.length);
+    if (expr.typeArguments != null &&
+        expr.typeArguments.arguments.length == 1) {
+      references.add(serializeType(expr.typeArguments.arguments[0]));
+      operations.add(UnlinkedConstOperation.makeTypedList);
+    } else {
+      operations.add(UnlinkedConstOperation.makeUntypedList);
+    }
+  }
+
+  void _serializeMapLiteral(MapLiteral expr) {
+    for (MapLiteralEntry entry in expr.entries) {
+      _serialize(entry.key);
+      _serialize(entry.value);
+    }
+    ints.add(expr.entries.length);
+    if (expr.typeArguments != null &&
+        expr.typeArguments.arguments.length == 2) {
+      references.add(serializeType(expr.typeArguments.arguments[0]));
+      references.add(serializeType(expr.typeArguments.arguments[1]));
+      operations.add(UnlinkedConstOperation.makeTypedMap);
+    } else {
+      operations.add(UnlinkedConstOperation.makeUntypedMap);
+    }
+  }
+
+  void _serializePrefixExpression(PrefixExpression expr) {
+    _serialize(expr.operand);
+    TokenType operator = expr.operator.type;
+    if (operator == TokenType.BANG) {
+      operations.add(UnlinkedConstOperation.not);
+    } else if (operator == TokenType.MINUS) {
+      operations.add(UnlinkedConstOperation.negate);
+    } else if (operator == TokenType.TILDE) {
+      operations.add(UnlinkedConstOperation.complement);
+    } else {
+      throw new StateError('Unknown operator: $operator');
+    }
+  }
+
+  void _serializeString(StringLiteral expr) {
+    if (expr is AdjacentStrings) {
+      if (expr.strings.every((string) => string is SimpleStringLiteral)) {
+        operations.add(UnlinkedConstOperation.pushString);
+        strings.add(expr.stringValue);
+      } else {
+        expr.strings.forEach(_serializeString);
+        operations.add(UnlinkedConstOperation.concatenate);
+        ints.add(expr.strings.length);
+      }
+    } else if (expr is SimpleStringLiteral) {
+      operations.add(UnlinkedConstOperation.pushString);
+      strings.add(expr.value);
+    } else {
+      StringInterpolation interpolation = expr as StringInterpolation;
+      for (InterpolationElement element in interpolation.elements) {
+        if (element is InterpolationString) {
+          operations.add(UnlinkedConstOperation.pushString);
+          strings.add(element.value);
+        } else {
+          _serialize((element as InterpolationExpression).expression);
+        }
+      }
+      operations.add(UnlinkedConstOperation.concatenate);
+      ints.add(interpolation.elements.length);
+    }
+  }
+}
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index 0eac910..3d9896b 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -4,34 +4,87 @@
 
 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';
+import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/summary/format.dart';
+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
  * for building the summary, and using [typeProvider] to find built-in types.
  */
 LibrarySerializationResult serializeLibrary(
-    LibraryElement lib, TypeProvider typeProvider) {
-  var serializer = new _LibrarySerializer(lib, typeProvider);
-  PrelinkedLibraryBuilder prelinked = serializer.serializeLibrary();
-  return new LibrarySerializationResult(
-      prelinked, serializer.unlinkedUnits, serializer.unitUris);
+    LibraryElement lib, TypeProvider typeProvider, bool strongMode) {
+  _LibrarySerializer serializer =
+      new _LibrarySerializer(lib, typeProvider, strongMode);
+  LinkedLibraryBuilder linked = serializer.serializeLibrary();
+  return new LibrarySerializationResult(linked, serializer.unlinkedUnits,
+      serializer.unitUris, serializer.unitSources);
 }
 
+ReferenceKind _getReferenceKind(Element element) {
+  if (element == null ||
+      element is ClassElement ||
+      element is DynamicElementImpl) {
+    return ReferenceKind.classOrEnum;
+  } else if (element is ConstructorElement) {
+    return ReferenceKind.constructor;
+  } else if (element is FunctionElement) {
+    if (element.enclosingElement is CompilationUnitElement) {
+      return ReferenceKind.topLevelFunction;
+    }
+    return ReferenceKind.function;
+  } else if (element is FunctionTypeAliasElement) {
+    return ReferenceKind.typedef;
+  } else if (element is PropertyAccessorElement) {
+    if (element.enclosingElement is ClassElement) {
+      return ReferenceKind.propertyAccessor;
+    }
+    return ReferenceKind.topLevelPropertyAccessor;
+  } else if (element is MethodElement) {
+    return ReferenceKind.method;
+  } else if (element is TopLevelVariableElement) {
+    // Summaries don't need to distinguish between references to a variable and
+    // references to its getter.
+    return ReferenceKind.topLevelPropertyAccessor;
+  } else if (element is LocalVariableElement) {
+    return ReferenceKind.variable;
+  } else if (element is FieldElement) {
+    // Summaries don't need to distinguish between references to a field and
+    // references to its getter.
+    return ReferenceKind.propertyAccessor;
+  } else {
+    throw new Exception('Unexpected element kind: ${element.runtimeType}');
+  }
+}
+
+/**
+ * Type of closures used by [_LibrarySerializer] to defer generation of
+ * [EntityRefBuilder] objects until the end of serialization of a
+ * compilation unit.
+ */
+typedef EntityRefBuilder _SerializeTypeRef();
+
 /**
  * Data structure holding the result of serializing a [LibraryElement].
  */
 class LibrarySerializationResult {
   /**
-   * Pre-linked information the given library.
+   * Linked information the given library.
    */
-  final PrelinkedLibraryBuilder prelinked;
+  final LinkedLibraryBuilder linked;
 
   /**
    * Unlinked information for the compilation units constituting the library.
@@ -46,58 +99,122 @@
    */
   final List<String> unitUris;
 
-  LibrarySerializationResult(this.prelinked, this.unlinkedUnits, this.unitUris);
+  /**
+   * Source object corresponding to each compilation unit appearing in the
+   * library.
+   */
+  final List<Source> unitSources;
+
+  LibrarySerializationResult(
+      this.linked, this.unlinkedUnits, this.unitUris, this.unitSources);
+}
+
+/**
+ * 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 library.`
+ * serialization of a single compilation unit.
  */
-class _LibrarySerializer {
+class _CompilationUnitSerializer {
   /**
-   * The library to be serialized.
+   * The [_LibrarySerializer] which is serializing the library of which
+   * [compilationUnit] is a part.
    */
-  final LibraryElement libraryElement;
+  final _LibrarySerializer librarySerializer;
 
   /**
-   * The type provider.  This is used to locate the library for `dart:core`.
+   * The [CompilationUnitElement] being serialized.
    */
-  final TypeProvider typeProvider;
+  final CompilationUnitElement compilationUnit;
 
   /**
-   * List of objects which should be written to [PrelinkedLibrary.units].
+   * The ordinal index of [compilationUnit] within the library, where 0
+   * represents the defining compilation unit.
    */
-  final List<PrelinkedUnitBuilder> prelinkedUnits = <PrelinkedUnitBuilder>[];
+  final int unitNum;
 
   /**
-   * List of unlinked units corresponding to the pre-linked units in
-   * [prelinkedUnits],
+   * The final linked summary of the compilation unit.
    */
-  final List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
+  final LinkedUnitBuilder linkedUnit = new LinkedUnitBuilder();
 
   /**
-   * List of absolute URIs of the compilation units in the library.
+   * The final unlinked summary of the compilation unit.
    */
-  final List<String> unitUris = <String>[];
+  final UnlinkedUnitBuilder unlinkedUnit = new UnlinkedUnitBuilder();
 
   /**
-   * Map from [LibraryElement] to the index of the entry in the "dependency
-   * table" that refers to it.
+   * Absolute URI of the compilation unit.
    */
-  final Map<LibraryElement, int> dependencyMap = <LibraryElement, int>{};
-
-  /**
-   * The "dependency table".  This is the list of objects which should be
-   * written to [PrelinkedLibrary.dependencies].
-   */
-  final List<PrelinkedDependencyBuilder> dependencies =
-      <PrelinkedDependencyBuilder>[];
-
-  /**
-   * The prelinked portion of the "imports table".  This is the list of ints
-   * which should be written to [PrelinkedLibrary.imports].
-   */
-  final List<int> prelinkedImports = <int>[];
+  String unitUri;
 
   /**
    * Map from [Element] to the index of the entry in the "references table"
@@ -112,12 +229,21 @@
   List<UnlinkedReferenceBuilder> unlinkedReferences;
 
   /**
-   * The prelinked portion of the "references table".  This is the list of
-   * objects which should be written to [PrelinkedUnit.references].
+   * The linked portion of the "references table".  This is the list of
+   * objects which should be written to [LinkedUnit.references].
    */
-  List<PrelinkedReferenceBuilder> prelinkedReferences;
+  List<LinkedReferenceBuilder> linkedReferences;
 
-  //final Map<String, int> prefixIndices = <String, int>{};
+  /**
+   * The number of slot ids which have been assigned to this compilation unit.
+   */
+  int numSlots = 0;
+
+  /**
+   * List of closures which should be invoked at the end of serialization of a
+   * compilation unit, to produce [LinkedUnit.types].
+   */
+  final List<_SerializeTypeRef> deferredLinkedTypes = <_SerializeTypeRef>[];
 
   /**
    * Index into the "references table" representing an unresolved reference, if
@@ -127,98 +253,106 @@
   int unresolvedReferenceIndex = null;
 
   /**
-   * Set of libraries which have been seen so far while visiting the transitive
-   * closure of exports.
+   * Index into the "references table" representing the "bottom" type, if such
+   * an index exists.  `null` if no such entry has been made in the references
+   * table yet.
    */
-  final Set<LibraryElement> librariesAddedToTransitiveExportClosure =
-      new Set<LibraryElement>();
+  int bottomReferenceIndex = null;
 
   /**
-   * Map from imported element to the prefix which may be used to refer to that
-   * element; elements for which no prefix is needed are absent from this map.
+   * If `true`, we are currently generating linked references, so new
+   * references will be not stored in [unlinkedReferences].
    */
-  final Map<Element, PrefixElement> prefixMap = <Element, PrefixElement>{};
+  bool buildingLinkedReferences = false;
 
-  _LibrarySerializer(this.libraryElement, this.typeProvider) {
-    dependencies.add(encodePrelinkedDependency());
-    dependencyMap[libraryElement] = 0;
-  }
+  _CompilationUnitSerializer(
+      this.librarySerializer, this.compilationUnit, this.unitNum);
 
   /**
-   * Retrieve the library element for `dart:core`.
+   * Source object for the compilation unit.
    */
-  LibraryElement get coreLibrary => typeProvider.objectType.element.library;
+  Source get unitSource => compilationUnit.source;
 
   /**
    * Add all classes, enums, typedefs, executables, and top level variables
-   * from the given compilation unit [element] to the library summary.
+   * from the given compilation unit [element] to the compilation unit summary.
    * [unitNum] indicates the ordinal position of this compilation unit in the
    * library.
    */
-  void addCompilationUnitElements(CompilationUnitElement element, int unitNum) {
-    UnlinkedUnitBuilder b = new UnlinkedUnitBuilder();
-    referenceMap.clear();
-    unlinkedReferences = <UnlinkedReferenceBuilder>[encodeUnlinkedReference()];
-    prelinkedReferences = <PrelinkedReferenceBuilder>[
-      encodePrelinkedReference(kind: PrelinkedReferenceKind.classOrEnum)
+  void addCompilationUnitElements() {
+    unlinkedReferences = <UnlinkedReferenceBuilder>[
+      new UnlinkedReferenceBuilder()
+    ];
+    linkedReferences = <LinkedReferenceBuilder>[
+      new LinkedReferenceBuilder(kind: ReferenceKind.classOrEnum)
     ];
     List<UnlinkedPublicNameBuilder> names = <UnlinkedPublicNameBuilder>[];
-    for (PropertyAccessorElement accessor in element.accessors) {
+    for (PropertyAccessorElement accessor in compilationUnit.accessors) {
       if (accessor.isPublic) {
-        names.add(encodeUnlinkedPublicName(
-            kind: PrelinkedReferenceKind.other,
+        names.add(new UnlinkedPublicNameBuilder(
+            kind: ReferenceKind.topLevelPropertyAccessor,
             name: accessor.name,
             numTypeParameters: accessor.typeParameters.length));
       }
     }
-    for (ClassElement cls in element.types) {
+    for (ClassElement cls in compilationUnit.types) {
       if (cls.isPublic) {
-        names.add(encodeUnlinkedPublicName(
-            kind: PrelinkedReferenceKind.classOrEnum,
+        names.add(new UnlinkedPublicNameBuilder(
+            kind: ReferenceKind.classOrEnum,
             name: cls.name,
-            numTypeParameters: cls.typeParameters.length));
+            numTypeParameters: cls.typeParameters.length,
+            members: serializeClassConstMembers(cls)));
       }
     }
-    for (ClassElement enm in element.enums) {
+    for (ClassElement enm in compilationUnit.enums) {
       if (enm.isPublic) {
-        names.add(encodeUnlinkedPublicName(
-            kind: PrelinkedReferenceKind.classOrEnum, name: enm.name));
+        names.add(new UnlinkedPublicNameBuilder(
+            kind: ReferenceKind.classOrEnum, name: enm.name));
       }
     }
-    for (FunctionElement function in element.functions) {
+    for (FunctionElement function in compilationUnit.functions) {
       if (function.isPublic) {
-        names.add(encodeUnlinkedPublicName(
-            kind: PrelinkedReferenceKind.other,
+        names.add(new UnlinkedPublicNameBuilder(
+            kind: ReferenceKind.topLevelFunction,
             name: function.name,
             numTypeParameters: function.typeParameters.length));
       }
     }
-    for (FunctionTypeAliasElement typedef in element.functionTypeAliases) {
+    for (FunctionTypeAliasElement typedef
+        in compilationUnit.functionTypeAliases) {
       if (typedef.isPublic) {
-        names.add(encodeUnlinkedPublicName(
-            kind: PrelinkedReferenceKind.typedef,
+        names.add(new UnlinkedPublicNameBuilder(
+            kind: ReferenceKind.typedef,
             name: typedef.name,
             numTypeParameters: typedef.typeParameters.length));
       }
     }
     if (unitNum == 0) {
+      LibraryElement libraryElement = librarySerializer.libraryElement;
       if (libraryElement.name.isNotEmpty) {
-        b.libraryName = libraryElement.name;
-        b.libraryNameOffset = libraryElement.nameOffset;
-        b.libraryNameLength = libraryElement.nameLength;
-        b.libraryDocumentationComment = serializeDocumentation(libraryElement);
+        LibraryElement libraryElement = librarySerializer.libraryElement;
+        unlinkedUnit.libraryName = libraryElement.name;
+        unlinkedUnit.libraryNameOffset = libraryElement.nameOffset;
+        unlinkedUnit.libraryNameLength = libraryElement.nameLength;
+        unlinkedUnit.libraryDocumentationComment =
+            serializeDocumentation(libraryElement);
+        unlinkedUnit.libraryAnnotations = serializeAnnotations(libraryElement);
       }
-      b.publicNamespace = encodeUnlinkedPublicNamespace(
+      unlinkedUnit.publicNamespace = new UnlinkedPublicNamespaceBuilder(
           exports: libraryElement.exports.map(serializeExportPublic).toList(),
           parts: libraryElement.parts
               .map((CompilationUnitElement e) => e.uri)
               .toList(),
           names: names);
-      b.exports = libraryElement.exports.map(serializeExportNonPublic).toList();
-      b.imports = libraryElement.imports.map(serializeImport).toList();
-      b.parts = libraryElement.parts
-          .map((CompilationUnitElement e) =>
-              encodeUnlinkedPart(uriOffset: e.uriOffset, uriEnd: e.uriEnd))
+      unlinkedUnit.exports =
+          libraryElement.exports.map(serializeExportNonPublic).toList();
+      unlinkedUnit.imports =
+          libraryElement.imports.map(serializeImport).toList();
+      unlinkedUnit.parts = libraryElement.parts
+          .map((CompilationUnitElement e) => new UnlinkedPartBuilder(
+              uriOffset: e.uriOffset,
+              uriEnd: e.uriEnd,
+              annotations: serializeAnnotations(e)))
           .toList();
     } else {
       // TODO(paulberry): we need to figure out a way to record library, part,
@@ -227,21 +361,23 @@
       // language), so that if the user makes code changes that cause a
       // non-defining compilation unit to become a defining compilation unit,
       // we can create a correct summary by simply re-linking.
-      b.publicNamespace = encodeUnlinkedPublicNamespace(names: names);
+      unlinkedUnit.publicNamespace =
+          new UnlinkedPublicNamespaceBuilder(names: names);
     }
-    b.classes = element.types.map(serializeClass).toList();
-    b.enums = element.enums.map(serializeEnum).toList();
-    b.typedefs = element.functionTypeAliases.map(serializeTypedef).toList();
+    unlinkedUnit.classes = compilationUnit.types.map(serializeClass).toList();
+    unlinkedUnit.enums = compilationUnit.enums.map(serializeEnum).toList();
+    unlinkedUnit.typedefs =
+        compilationUnit.functionTypeAliases.map(serializeTypedef).toList();
     List<UnlinkedExecutableBuilder> executables =
-        element.functions.map(serializeExecutable).toList();
-    for (PropertyAccessorElement accessor in element.accessors) {
+        compilationUnit.functions.map(serializeExecutable).toList();
+    for (PropertyAccessorElement accessor in compilationUnit.accessors) {
       if (!accessor.isSynthetic) {
         executables.add(serializeExecutable(accessor));
       }
     }
-    b.executables = executables;
+    unlinkedUnit.executables = executables;
     List<UnlinkedVariableBuilder> variables = <UnlinkedVariableBuilder>[];
-    for (PropertyAccessorElement accessor in element.accessors) {
+    for (PropertyAccessorElement accessor in compilationUnit.accessors) {
       if (accessor.isSynthetic && accessor.isGetter) {
         PropertyInducingElement variable = accessor.variable;
         if (variable != null) {
@@ -250,45 +386,22 @@
         }
       }
     }
-    b.variables = variables;
-    b.references = unlinkedReferences;
-    unlinkedUnits.add(b);
-    prelinkedUnits.add(encodePrelinkedUnit(references: prelinkedReferences));
-    unitUris.add(element.source.uri.toString());
-    unlinkedReferences = null;
-    prelinkedReferences = null;
+    unlinkedUnit.variables = variables;
+    unlinkedUnit.references = unlinkedReferences;
+    linkedUnit.references = linkedReferences;
+    unitUri = compilationUnit.source.uri.toString();
   }
 
   /**
-   * Add [exportedLibrary] (and the transitive closure of all libraries it
-   * exports) to the dependency table ([PrelinkedLibrary.dependencies]).
+   * Create the [LinkedUnit.types] table based on deferred types that were
+   * found during [addCompilationUnitElements].
    */
-  void addTransitiveExportClosure(LibraryElement exportedLibrary) {
-    if (librariesAddedToTransitiveExportClosure.add(exportedLibrary)) {
-      serializeDependency(exportedLibrary);
-      for (LibraryElement transitiveExport
-          in exportedLibrary.exportedLibraries) {
-        addTransitiveExportClosure(transitiveExport);
-      }
-    }
-  }
-
-  /**
-   * Fill in [prefixMap] using information from [libraryElement.imports].
-   */
-  void computePrefixMap() {
-    for (ImportElement import in libraryElement.imports) {
-      if (import.prefix == null) {
-        continue;
-      }
-      import.importedLibrary.exportNamespace.definedNames
-          .forEach((String name, Element e) {
-        if (new NameFilter.forNamespaceCombinators(import.combinators)
-            .accepts(name)) {
-          prefixMap[e] = import.prefix;
-        }
-      });
-    }
+  void createLinkedTypes() {
+    buildingLinkedReferences = true;
+    linkedUnit.types = deferredLinkedTypes
+        .map((_SerializeTypeRef closure) => closure())
+        .toList();
+    buildingLinkedReferences = false;
   }
 
   /**
@@ -296,6 +409,7 @@
    * parameter [type].
    */
   int findTypeParameterIndex(TypeParameterType type, Element context) {
+    Element originalContext = context;
     int index = 0;
     while (context != null) {
       List<TypeParameterElement> typeParameters;
@@ -317,7 +431,57 @@
       }
       context = context.enclosingElement;
     }
-    throw new StateError('Unbound type parameter $type');
+    throw new StateError(
+        'Unbound type parameter $type (${originalContext?.location})');
+  }
+
+  /**
+   * Get the type arguments for the given [type], or `null` if the type has no
+   * type arguments.
+   *
+   * TODO(paulberry): consider adding an abstract getter to [DartType] to do
+   * this.
+   */
+  List<DartType> getTypeArguments(DartType type) {
+    if (type is InterfaceType) {
+      return type.typeArguments;
+    } else if (type is FunctionType) {
+      return type.typeArguments;
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Serialize annotations from the given [element].  If [element] has no
+   * annotations, the empty list is returned.
+   */
+  List<UnlinkedConstBuilder> serializeAnnotations(Element element) {
+    if (element.metadata.isEmpty) {
+      return const <UnlinkedConstBuilder>[];
+    }
+    return element.metadata.map((ElementAnnotationImpl a) {
+      _ConstExprSerializer serializer = new _ConstExprSerializer(this, null);
+      serializer.serializeAnnotation(a.annotationAst);
+      return serializer.toBuilder();
+    }).toList();
+  }
+
+  /**
+   * Return the index of the entry in the references table
+   * ([LinkedLibrary.references]) used for the "bottom" type.  A new entry is
+   * added to the table if necessary to satisfy the request.
+   */
+  int serializeBottomReference() {
+    if (bottomReferenceIndex == null) {
+      // References to the "bottom" type are always implicit, since there is no
+      // way to explicitly refer to the "bottom" type.  Therefore they should
+      // be stored only in the linked references table.
+      bottomReferenceIndex = linkedReferences.length;
+      linkedReferences.add(new LinkedReferenceBuilder(
+          name: '*bottom*', kind: ReferenceKind.classOrEnum));
+    }
+    return bottomReferenceIndex;
   }
 
   /**
@@ -365,10 +529,57 @@
     b.isAbstract = classElement.isAbstract;
     b.isMixinApplication = classElement.isMixinApplication;
     b.documentationComment = serializeDocumentation(classElement);
+    b.annotations = serializeAnnotations(classElement);
     return b;
   }
 
   /**
+   * If [cls] is a class, return the list of its members available for
+   * constants - static constant fields, static methods and constructors.
+   * Otherwise return `null`.
+   */
+  List<UnlinkedPublicNameBuilder> serializeClassConstMembers(ClassElement cls) {
+    if (cls.isMixinApplication) {
+      // Mixin application members can't be determined directly from the AST so
+      // we can't store them in UnlinkedPublicName.
+      // TODO(paulberry): find somewhere else to store them.
+      return null;
+    }
+    if (cls.kind == ElementKind.CLASS) {
+      List<UnlinkedPublicNameBuilder> bs = <UnlinkedPublicNameBuilder>[];
+      for (FieldElement field in cls.fields) {
+        if (field.isStatic && field.isConst && field.isPublic) {
+          // TODO(paulberry): should numTypeParameters include class params?
+          bs.add(new UnlinkedPublicNameBuilder(
+              name: field.name,
+              kind: ReferenceKind.propertyAccessor,
+              numTypeParameters: 0));
+        }
+      }
+      for (MethodElement method in cls.methods) {
+        if (method.isStatic && method.isPublic) {
+          // TODO(paulberry): should numTypeParameters include class params?
+          bs.add(new UnlinkedPublicNameBuilder(
+              name: method.name,
+              kind: ReferenceKind.method,
+              numTypeParameters: method.typeParameters.length));
+        }
+      }
+      for (ConstructorElement constructor in cls.constructors) {
+        if (constructor.isPublic && constructor.name.isNotEmpty) {
+          // TODO(paulberry): should numTypeParameters include class params?
+          bs.add(new UnlinkedPublicNameBuilder(
+              name: constructor.name,
+              kind: ReferenceKind.constructor,
+              numTypeParameters: 0));
+        }
+      }
+      return bs;
+    }
+    return null;
+  }
+
+  /**
    * Serialize the given [combinator] into an [UnlinkedCombinator].
    */
   UnlinkedCombinatorBuilder serializeCombinator(
@@ -376,6 +587,8 @@
     UnlinkedCombinatorBuilder b = new UnlinkedCombinatorBuilder();
     if (combinator is ShowElementCombinator) {
       b.shows = combinator.shownNames;
+      b.offset = combinator.offset;
+      b.end = combinator.end;
     } else if (combinator is HideElementCombinator) {
       b.hides = combinator.hiddenNames;
     }
@@ -383,20 +596,14 @@
   }
 
   /**
-   * Return the index of the entry in the dependency table
-   * ([PrelinkedLibrary.dependencies]) for the given [dependentLibrary].  A new
-   * entry is added to the table if necessary to satisfy the request.
+   * Serialize the given [expression], creating an [UnlinkedConstBuilder].
    */
-  int serializeDependency(LibraryElement dependentLibrary) {
-    return dependencyMap.putIfAbsent(dependentLibrary, () {
-      int index = dependencies.length;
-      List<String> parts = dependentLibrary.parts
-          .map((CompilationUnitElement e) => e.source.uri.toString())
-          .toList();
-      dependencies.add(encodePrelinkedDependency(
-          uri: dependentLibrary.source.uri.toString(), parts: parts));
-      return index;
-    });
+  UnlinkedConstBuilder serializeConstExpr(Expression expression,
+      [Set<String> constructorParameterNames]) {
+    _ConstExprSerializer serializer =
+        new _ConstExprSerializer(this, constructorParameterNames);
+    serializer.serialize(expression);
+    return serializer.toBuilder();
   }
 
   /**
@@ -409,20 +616,13 @@
     if (element.documentationComment == null) {
       return null;
     }
-    return encodeUnlinkedDocumentationComment(
+    return new UnlinkedDocumentationCommentBuilder(
         text: element.documentationComment,
         offset: element.docRange.offset,
         length: element.docRange.length);
   }
 
   /**
-   * Return the index of the entry in the references table
-   * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references])
-   * representing the pseudo-type `dynamic`.
-   */
-  int serializeDynamicReference() => 0;
-
-  /**
    * Serialize the given [enumElement], creating an [UnlinkedEnum].
    */
   UnlinkedEnumBuilder serializeEnum(ClassElement enumElement) {
@@ -432,7 +632,7 @@
     List<UnlinkedEnumValueBuilder> values = <UnlinkedEnumValueBuilder>[];
     for (FieldElement field in enumElement.fields) {
       if (field.isConst && field.type.element == enumElement) {
-        values.add(encodeUnlinkedEnumValue(
+        values.add(new UnlinkedEnumValueBuilder(
             name: field.name,
             nameOffset: field.nameOffset,
             documentationComment: serializeDocumentation(field)));
@@ -440,6 +640,7 @@
     }
     b.values = values;
     b.documentationComment = serializeDocumentation(enumElement);
+    b.annotations = serializeAnnotations(enumElement);
     return b;
   }
 
@@ -451,10 +652,19 @@
     UnlinkedExecutableBuilder b = new UnlinkedExecutableBuilder();
     b.name = executableElement.name;
     b.nameOffset = executableElement.nameOffset;
-    if (executableElement is! ConstructorElement &&
-        !executableElement.type.returnType.isVoid) {
-      b.returnType = serializeTypeRef(
-          executableElement.type.returnType, executableElement);
+    if (executableElement is ConstructorElement) {
+      if (executableElement.name.isNotEmpty) {
+        b.nameEnd = executableElement.nameEnd;
+        b.periodOffset = executableElement.periodOffset;
+      }
+    } else {
+      if (!executableElement.hasImplicitReturnType) {
+        b.returnType = serializeTypeRef(
+            executableElement.type.returnType, executableElement);
+      } else if (!executableElement.isStatic) {
+        b.inferredReturnTypeSlot =
+            storeInferredType(executableElement.returnType, executableElement);
+      }
     }
     b.typeParameters =
         executableElement.typeParameters.map(serializeTypeParam).toList();
@@ -466,19 +676,69 @@
       } else {
         b.kind = UnlinkedExecutableKind.setter;
       }
-    } else if (executableElement is ConstructorElement) {
+    } else if (executableElement is ConstructorElementImpl) {
       b.kind = UnlinkedExecutableKind.constructor;
       b.isConst = executableElement.isConst;
       b.isFactory = executableElement.isFactory;
+      ConstructorElement redirectedConstructor =
+          executableElement.redirectedConstructor;
+      if (redirectedConstructor != null) {
+        b.isRedirectedConstructor = true;
+        if (executableElement.isFactory) {
+          InterfaceType returnType = redirectedConstructor is ConstructorMember
+              ? redirectedConstructor.definingType
+              : redirectedConstructor.enclosingElement.type;
+          EntityRefBuilder typeRef =
+              serializeTypeRef(returnType, executableElement);
+          if (redirectedConstructor.name.isNotEmpty) {
+            String name = redirectedConstructor.name;
+            int typeId = typeRef.reference;
+            LinkedReference typeLinkedRef = linkedReferences[typeId];
+            int refId = serializeUnlinkedReference(
+                name, ReferenceKind.constructor,
+                unit: typeLinkedRef.unit, prefixReference: typeId);
+            b.redirectedConstructor = new EntityRefBuilder(
+                reference: refId, typeArguments: typeRef.typeArguments);
+          } else {
+            b.redirectedConstructor = typeRef;
+          }
+        } else {
+          b.redirectedConstructorName = redirectedConstructor.name;
+        }
+      }
+      if (executableElement.isConst &&
+          executableElement.constantInitializers != null) {
+        Set<String> constructorParameterNames =
+            executableElement.parameters.map((p) => p.name).toSet();
+        b.constantInitializers = executableElement.constantInitializers
+            .map((ConstructorInitializer initializer) =>
+                serializeConstructorInitializer(
+                    initializer,
+                    (expr) =>
+                        serializeConstExpr(expr, constructorParameterNames)))
+            .toList();
+      }
     } else {
       b.kind = UnlinkedExecutableKind.functionOrMethod;
     }
     b.isAbstract = executableElement.isAbstract;
     b.isStatic = executableElement.isStatic &&
         executableElement.enclosingElement is ClassElement;
-    b.hasImplicitReturnType = executableElement.hasImplicitReturnType;
     b.isExternal = executableElement.isExternal;
     b.documentationComment = serializeDocumentation(executableElement);
+    b.annotations = serializeAnnotations(executableElement);
+    if (executableElement is FunctionElement) {
+      SourceRange visibleRange = executableElement.visibleRange;
+      if (visibleRange != null) {
+        b.visibleOffset = visibleRange.offset;
+        b.visibleLength = visibleRange.length;
+      }
+    }
+    b.localFunctions =
+        executableElement.functions.map(serializeExecutable).toList();
+    b.localLabels = executableElement.labels.map(serializeLabel).toList();
+    b.localVariables =
+        executableElement.localVariables.map(serializeVariable).toList();
     return b;
   }
 
@@ -491,6 +751,7 @@
     b.offset = exportElement.nameOffset;
     b.uriOffset = exportElement.uriOffset;
     b.uriEnd = exportElement.uriEnd;
+    b.annotations = serializeAnnotations(exportElement);
     return b;
   }
 
@@ -507,12 +768,12 @@
 
   /**
    * Serialize the given [importElement] yielding an [UnlinkedImportBuilder].
-   * Also, add pre-linked information about it to the [prelinkedImports] list.
+   * Also, add linked information about it to the [linkedImports] list.
    */
   UnlinkedImportBuilder serializeImport(ImportElement importElement) {
     UnlinkedImportBuilder b = new UnlinkedImportBuilder();
+    b.annotations = serializeAnnotations(importElement);
     b.isDeferred = importElement.isDeferred;
-    b.offset = importElement.nameOffset;
     b.combinators = importElement.combinators.map(serializeCombinator).toList();
     if (importElement.prefix != null) {
       b.prefixReference = serializePrefix(importElement.prefix);
@@ -521,33 +782,24 @@
     if (importElement.isSynthetic) {
       b.isImplicit = true;
     } else {
+      b.offset = importElement.nameOffset;
       b.uri = importElement.uri;
       b.uriOffset = importElement.uriOffset;
       b.uriEnd = importElement.uriEnd;
     }
-    addTransitiveExportClosure(importElement.importedLibrary);
-    prelinkedImports.add(serializeDependency(importElement.importedLibrary));
     return b;
   }
 
   /**
-   * Serialize the whole library element into a [PrelinkedLibrary].  Should be
-   * called exactly once for each instance of [_LibrarySerializer].
-   *
-   * The unlinked compilation units are stored in [unlinkedUnits], and their
-   * absolute URIs are stored in [unitUris].
+   * Serialize the given [label], creating an [UnlinkedLabelBuilder].
    */
-  PrelinkedLibraryBuilder serializeLibrary() {
-    computePrefixMap();
-    PrelinkedLibraryBuilder pb = new PrelinkedLibraryBuilder();
-    addCompilationUnitElements(libraryElement.definingCompilationUnit, 0);
-    for (int i = 0; i < libraryElement.parts.length; i++) {
-      addCompilationUnitElements(libraryElement.parts[i], i + 1);
-    }
-    pb.units = prelinkedUnits;
-    pb.dependencies = dependencies;
-    pb.importDependencies = prelinkedImports;
-    return pb;
+  UnlinkedLabelBuilder serializeLabel(LabelElementImpl label) {
+    UnlinkedLabelBuilder b = new UnlinkedLabelBuilder();
+    b.name = label.name;
+    b.nameOffset = label.nameOffset;
+    b.isOnSwitchMember = label.isOnSwitchMember;
+    b.isOnSwitchStatement = label.isOnSwitchStatement;
+    return b;
   }
 
   /**
@@ -558,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;
@@ -570,19 +822,46 @@
         b.kind = UnlinkedParamKind.named;
         break;
     }
+    b.annotations = serializeAnnotations(parameter);
     b.isInitializingFormal = parameter.isInitializingFormal;
     DartType type = parameter.type;
-    if (type is FunctionType) {
-      b.isFunctionTyped = true;
-      if (!type.returnType.isVoid) {
-        b.type = serializeTypeRef(type.returnType, parameter);
+    if (parameter.hasImplicitType) {
+      Element contextParent = context.enclosingElement;
+      if (!parameter.isInitializingFormal &&
+          contextParent is ExecutableElement &&
+          !contextParent.isStatic &&
+          contextParent is! ConstructorElement) {
+        b.inferredTypeSlot = storeInferredType(type, context);
       }
-      b.parameters = type.parameters
-          .map((parameter) => serializeParam(parameter, context))
-          .toList();
     } else {
-      b.type = serializeTypeRef(type, context);
-      b.hasImplicitType = parameter.hasImplicitType;
+      if (type is FunctionType && type.element.isSynthetic) {
+        b.isFunctionTyped = true;
+        b.type = serializeTypeRef(type.returnType, parameter);
+        b.parameters = type.parameters
+            .map((parameter) => serializeParam(parameter, context))
+            .toList();
+      } else {
+        b.type = serializeTypeRef(type, context);
+      }
+    }
+    if (parameter is ConstVariableElement) {
+      ConstVariableElement constParameter = parameter as ConstVariableElement;
+      Expression initializer = constParameter.constantInitializer;
+      if (initializer != null) {
+        b.defaultValue = serializeConstExpr(initializer);
+        b.defaultValueCode = parameter.defaultValueCode;
+      }
+    }
+    // TODO(scheglov) VariableMember.initializer is not implemented
+    if (parameter is! VariableMember && parameter.initializer != null) {
+      b.initializer = serializeExecutable(parameter.initializer);
+    }
+    {
+      SourceRange visibleRange = parameter.visibleRange;
+      if (visibleRange != null) {
+        b.visibleOffset = visibleRange.offset;
+        b.visibleLength = visibleRange.length;
+      }
     }
     return b;
   }
@@ -591,14 +870,32 @@
    * Serialize the given [prefix] into an index into the references table.
    */
   int serializePrefix(PrefixElement element) {
-    return referenceMap.putIfAbsent(element, () {
-      assert(unlinkedReferences.length == prelinkedReferences.length);
-      int index = unlinkedReferences.length;
-      unlinkedReferences.add(encodeUnlinkedReference(name: element.name));
-      prelinkedReferences
-          .add(encodePrelinkedReference(kind: PrelinkedReferenceKind.prefix));
-      return index;
-    });
+    return referenceMap.putIfAbsent(element,
+        () => serializeUnlinkedReference(element.name, ReferenceKind.prefix));
+  }
+
+  /**
+   * Compute the reference index which should be stored in a [EntityRef].
+   */
+  int serializeReferenceForType(DartType type) {
+    Element element = type.element;
+    LibraryElement dependentLibrary = element?.library;
+    if (dependentLibrary == null) {
+      if (type.isBottom) {
+        // 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(buildingLinkedReferences);
+        return serializeBottomReference();
+      }
+      assert(type.isDynamic || type.isVoid);
+      if (type is UndefinedTypeImpl) {
+        return serializeUnresolvedReference();
+      }
+      // Note: for a type which is truly `dynamic` or `void`, fall through to
+      // use [_getElementReferenceId].
+    }
+    return _getElementReferenceId(element);
   }
 
   /**
@@ -611,12 +908,10 @@
     b.nameOffset = typedefElement.nameOffset;
     b.typeParameters =
         typedefElement.typeParameters.map(serializeTypeParam).toList();
-    if (!typedefElement.returnType.isVoid) {
-      b.returnType =
-          serializeTypeRef(typedefElement.returnType, typedefElement);
-    }
+    b.returnType = serializeTypeRef(typedefElement.returnType, typedefElement);
     b.parameters = typedefElement.parameters.map(serializeParam).toList();
     b.documentationComment = serializeDocumentation(typedefElement);
+    b.annotations = serializeAnnotations(typedefElement);
     return b;
   }
 
@@ -631,79 +926,106 @@
     if (typeParameter.bound != null) {
       b.bound = serializeTypeRef(typeParameter.bound, typeParameter);
     }
+    b.annotations = serializeAnnotations(typeParameter);
     return b;
   }
 
   /**
-   * Serialize the given [type] into an [UnlinkedTypeRef].
+   * Serialize the given [type] into a [EntityRef].  If [slot] is provided,
+   * 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.
    */
-  UnlinkedTypeRefBuilder serializeTypeRef(DartType type, Element context) {
-    UnlinkedTypeRefBuilder b = new UnlinkedTypeRefBuilder();
+  EntityRefBuilder serializeTypeRef(DartType type, Element context,
+      {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 {
-      Element element = type.element;
-      LibraryElement dependentLibrary = element.library;
-      if (dependentLibrary == null) {
-        assert(type.isDynamic);
-        if (type is UndefinedTypeImpl) {
-          b.reference = serializeUnresolvedReference();
-        } else {
-          b.reference = serializeDynamicReference();
+      if (type is FunctionType &&
+          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(buildingLinkedReferences);
+        ParameterElement parameterElement = typeElement.enclosingElement;
+        while (true) {
+          Element parent = parameterElement.enclosingElement;
+          if (parent is ExecutableElement) {
+            Element grandParent = parent.enclosingElement;
+            b.implicitFunctionTypeIndices
+                .insert(0, parent.parameters.indexOf(parameterElement));
+            if (grandParent is ParameterElement) {
+              // Function-typed parameter inside a function-typed parameter.
+              parameterElement = grandParent;
+              continue;
+            } else {
+              // Function-typed parameter inside a top level function or method.
+              b.reference = _getElementReferenceId(parent);
+              break;
+            }
+          } else {
+            throw new StateError(
+                'Unexpected element enclosing parameter: ${parent.runtimeType}');
+          }
         }
       } else {
-        b.reference = referenceMap.putIfAbsent(element, () {
-          assert(unlinkedReferences.length == prelinkedReferences.length);
-          CompilationUnitElement unitElement =
-              element.getAncestor((Element e) => e is CompilationUnitElement);
-          int unit = dependentLibrary.units.indexOf(unitElement);
-          assert(unit != -1);
-          int numTypeParameters = 0;
-          if (element is TypeParameterizedElement) {
-            numTypeParameters = element.typeParameters.length;
-          }
-          // Figure out a prefix that may be used to refer to the given type.
-          // TODO(paulberry): to avoid subtle relinking inconsistencies we
-          // should use the actual prefix from the AST (a given type may be
-          // reachable via multiple prefixes), but sadly, this information is
-          // not recorded in the element model.
-          int prefixReference = 0;
-          PrefixElement prefix = prefixMap[element];
-          if (prefix != null) {
-            prefixReference = serializePrefix(prefix);
-          }
-          int index = unlinkedReferences.length;
-          unlinkedReferences.add(encodeUnlinkedReference(
-              name: element.name, prefixReference: prefixReference));
-          prelinkedReferences.add(encodePrelinkedReference(
-              dependency: serializeDependency(dependentLibrary),
-              kind: element is FunctionTypeAliasElement
-                  ? PrelinkedReferenceKind.typedef
-                  : PrelinkedReferenceKind.classOrEnum,
-              unit: unit,
-              numTypeParameters: numTypeParameters));
-          return index;
-        });
+        b.reference = serializeReferenceForType(type);
       }
-      List<DartType> typeArguments;
-      if (type is InterfaceType) {
-        typeArguments = type.typeArguments;
-      } else if (type is FunctionType) {
-        typeArguments = type.typeArguments;
-      }
-      if (typeArguments != null &&
-          typeArguments.any((DartType argument) => !argument.isDynamic)) {
-        b.typeArguments = typeArguments
-            .map((DartType t) => serializeTypeRef(t, context))
-            .toList();
+      List<DartType> typeArguments = getTypeArguments(type);
+      if (typeArguments != null) {
+        // Trailing type arguments of type 'dynamic' should be omitted.
+        int numArgsToSerialize = typeArguments.length;
+        while (numArgsToSerialize > 0 &&
+            typeArguments[numArgsToSerialize - 1].isDynamic) {
+          --numArgsToSerialize;
+        }
+        if (numArgsToSerialize > 0) {
+          List<EntityRefBuilder> serializedArguments = <EntityRefBuilder>[];
+          for (int i = 0; i < numArgsToSerialize; i++) {
+            serializedArguments
+                .add(serializeTypeRef(typeArguments[i], context));
+          }
+          b.typeArguments = serializedArguments;
+        }
       }
     }
     return b;
   }
 
   /**
+   * Create a new entry in the references table ([UnlinkedLibrary.references]
+   * and [LinkedLibrary.references]) representing an entity having the given
+   * [name] and [kind].  If [unit] is given, it is the index of the compilation
+   * unit containing the entity being referred to.  If [prefixReference] is
+   * given, it indicates the entry in the references table for the prefix.
+   */
+  int serializeUnlinkedReference(String name, ReferenceKind kind,
+      {int unit: 0, int prefixReference: 0}) {
+    assert(unlinkedReferences.length == linkedReferences.length);
+    int index = unlinkedReferences.length;
+    unlinkedReferences.add(new UnlinkedReferenceBuilder(
+        name: name, prefixReference: prefixReference));
+    linkedReferences.add(new LinkedReferenceBuilder(kind: kind, unit: unit));
+    return index;
+  }
+
+  /**
    * Return the index of the entry in the references table
-   * ([UnlinkedLibrary.references] and [PrelinkedLibrary.references]) used for
+   * ([UnlinkedLibrary.references] and [LinkedLibrary.references]) used for
    * unresolved references.  A new entry is added to the table if necessary to
    * satisfy the request.
    */
@@ -713,11 +1035,8 @@
     // the element model.  For the moment we use a name that can't possibly
     // ever exist.
     if (unresolvedReferenceIndex == null) {
-      assert(unlinkedReferences.length == prelinkedReferences.length);
-      unresolvedReferenceIndex = unlinkedReferences.length;
-      unlinkedReferences.add(encodeUnlinkedReference(name: '*unresolved*'));
-      prelinkedReferences.add(
-          encodePrelinkedReference(kind: PrelinkedReferenceKind.unresolved));
+      unresolvedReferenceIndex =
+          serializeUnlinkedReference('*unresolved*', ReferenceKind.unresolved);
     }
     return unresolvedReferenceIndex;
   }
@@ -725,16 +1044,509 @@
   /**
    * Serialize the given [variable], creating an [UnlinkedVariable].
    */
-  UnlinkedVariableBuilder serializeVariable(PropertyInducingElement variable) {
+  UnlinkedVariableBuilder serializeVariable(VariableElement variable) {
     UnlinkedVariableBuilder b = new UnlinkedVariableBuilder();
     b.name = variable.name;
     b.nameOffset = variable.nameOffset;
-    b.type = serializeTypeRef(variable.type, variable);
+    if (!variable.hasImplicitType) {
+      b.type = serializeTypeRef(variable.type, variable);
+    }
     b.isStatic = variable.isStatic && variable.enclosingElement is ClassElement;
     b.isFinal = variable.isFinal;
     b.isConst = variable.isConst;
-    b.hasImplicitType = variable.hasImplicitType;
     b.documentationComment = serializeDocumentation(variable);
+    b.annotations = serializeAnnotations(variable);
+    if (variable is ConstVariableElement) {
+      ConstVariableElement constVariable = variable as ConstVariableElement;
+      Expression initializer = constVariable.constantInitializer;
+      if (initializer != null) {
+        b.constExpr = serializeConstExpr(initializer);
+      }
+    }
+    if (variable is PropertyInducingElement) {
+      if (b.isFinal || b.isConst) {
+        b.propagatedTypeSlot =
+            storeLinkedType(variable.propagatedType, variable);
+      } else {
+        // Variable is not propagable.
+        assert(variable.propagatedType == null);
+      }
+    }
+    if (variable.hasImplicitType &&
+        (variable.initializer != null || !variable.isStatic)) {
+      b.inferredTypeSlot = storeInferredType(variable.type, variable);
+    }
+    if (variable is LocalVariableElement) {
+      SourceRange visibleRange = variable.visibleRange;
+      if (visibleRange != null) {
+        b.visibleOffset = visibleRange.offset;
+        b.visibleLength = visibleRange.length;
+      }
+    }
+    // TODO(scheglov) VariableMember.initializer is not implemented
+    if (variable is! VariableMember && variable.initializer != null) {
+      b.initializer = serializeExecutable(variable.initializer);
+    }
     return b;
   }
+
+  /**
+   * Create a slot id for the given [type] (which is an inferred type).  If
+   * [type] is not `dynamic`, it is stored in [linkedTypes] so that once the
+   * compilation unit has been fully visited, it will be serialized into
+   * [LinkedUnit.types].
+   *
+   * [context] is the element within which the slot id will appear; this is
+   * used to serialize type parameters.
+   */
+  int storeInferredType(DartType type, Element context) {
+    return storeLinkedType(type.isDynamic ? null : type, context);
+  }
+
+  /**
+   * Create a slot id for the given [type] (which may be either a propagated
+   * type or an inferred type).  If [type] is not `null`, it is stored in
+   * [linkedTypes] so that once the compilation unit has been fully visited,
+   * it will be serialized to [LinkedUnit.types].
+   *
+   * [context] is the element within which the slot id will appear; this is
+   * used to serialize type parameters.
+   */
+  int storeLinkedType(DartType type, Element context) {
+    int slot = ++numSlots;
+    if (type != null) {
+      deferredLinkedTypes
+          .add(() => serializeTypeRef(type, context, slot: slot));
+    }
+    return slot;
+  }
+
+  int _getElementReferenceId(Element element) {
+    return referenceMap.putIfAbsent(element, () {
+      LibraryElement dependentLibrary = librarySerializer.libraryElement;
+      int unit = 0;
+      Element enclosingElement;
+      if (element != null) {
+        enclosingElement = element.enclosingElement;
+        if (enclosingElement is CompilationUnitElement) {
+          dependentLibrary = enclosingElement.library;
+          unit = dependentLibrary.units.indexOf(enclosingElement);
+          assert(unit != -1);
+        }
+      }
+      ReferenceKind kind = _getReferenceKind(element);
+      String name = element == null ? 'void' : element.name;
+      int index;
+      LinkedReferenceBuilder linkedReference;
+      if (buildingLinkedReferences) {
+        linkedReference =
+            new LinkedReferenceBuilder(kind: kind, unit: unit, name: name);
+        if (enclosingElement != null &&
+            enclosingElement is! CompilationUnitElement) {
+          linkedReference.containingReference =
+              _getElementReferenceId(enclosingElement);
+          if (enclosingElement is ClassElement) {
+            // Nothing to do.
+          } else if (enclosingElement is ExecutableElement) {
+            if (element is FunctionElement) {
+              assert(enclosingElement.functions.contains(element));
+              linkedReference.localIndex =
+                  enclosingElement.functions.indexOf(element);
+            } else if (element is LocalVariableElement) {
+              assert(enclosingElement.localVariables.contains(element));
+              linkedReference.localIndex =
+                  enclosingElement.localVariables.indexOf(element);
+            } else {
+              throw new StateError(
+                  'Unexpected enclosed element type: ${element.runtimeType}');
+            }
+          } else if (enclosingElement is VariableElement) {
+            assert(identical(enclosingElement.initializer, element));
+          } else {
+            throw new StateError(
+                'Unexpected enclosing element type: ${enclosingElement.runtimeType}');
+          }
+        }
+        index = linkedReferences.length;
+        linkedReferences.add(linkedReference);
+      } else {
+        assert(unlinkedReferences.length == linkedReferences.length);
+        int prefixReference = 0;
+        Element enclosing = element?.enclosingElement;
+        if (enclosing == null || enclosing is CompilationUnitElement) {
+          // Figure out a prefix that may be used to refer to the given element.
+          // TODO(paulberry): to avoid subtle relinking inconsistencies we
+          // should use the actual prefix from the AST (a given type may be
+          // reachable via multiple prefixes), but sadly, this information is
+          // not recorded in the element model.
+          PrefixElement prefix = librarySerializer.prefixMap[element];
+          if (prefix != null) {
+            prefixReference = serializePrefix(prefix);
+          }
+        } else {
+          prefixReference = _getElementReferenceId(enclosing);
+        }
+        index = serializeUnlinkedReference(name, kind,
+            prefixReference: prefixReference, unit: unit);
+        linkedReference = linkedReferences[index];
+      }
+      linkedReference.dependency =
+          librarySerializer.serializeDependency(dependentLibrary);
+      if (element is TypeParameterizedElement) {
+        linkedReference.numTypeParameters += element.typeParameters.length;
+      }
+      return index;
+    });
+  }
+
+  int _getLengthPropertyReference(int prefix) {
+    return serializeUnlinkedReference('length', ReferenceKind.length,
+        prefixReference: prefix);
+  }
+}
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single constant [Expression].
+ */
+class _ConstExprSerializer extends AbstractConstExprSerializer {
+  final _CompilationUnitSerializer serializer;
+
+  /**
+   * If a constructor initializer expression is being serialized, the names of
+   * the constructor parameters.  Otherwise `null`.
+   */
+  final Set<String> constructorParameterNames;
+
+  _ConstExprSerializer(this.serializer, this.constructorParameterNames);
+
+  @override
+  bool isConstructorParameterName(String name) {
+    return constructorParameterNames?.contains(name) ?? false;
+  }
+
+  @override
+  void serializeAnnotation(Annotation annotation) {
+    if (annotation.arguments == null) {
+      assert(annotation.constructorName == null);
+      serialize(annotation.name);
+    } else {
+      Identifier name = annotation.name;
+      Element nameElement = name.staticElement;
+      EntityRefBuilder constructor;
+      if (nameElement is ConstructorElement && name is PrefixedIdentifier) {
+        assert(annotation.constructorName == null);
+        constructor = serializeConstructorName(
+            new TypeName(name.prefix, null)..type = nameElement.returnType,
+            name.identifier);
+      } else if (nameElement is TypeDefiningElement) {
+        constructor = serializeConstructorName(
+            new TypeName(annotation.name, null)..type = nameElement.type,
+            annotation.constructorName);
+      } else {
+        throw new StateError('Unexpected annotation nameElement type:'
+            ' ${nameElement.runtimeType}');
+      }
+      serializeInstanceCreation(constructor, annotation.arguments);
+    }
+  }
+
+  @override
+  EntityRefBuilder serializeConstructorName(
+      TypeName type, SimpleIdentifier name) {
+    EntityRefBuilder typeRef = serializeType(type);
+    if (name == null) {
+      return typeRef;
+    } else {
+      LinkedReference typeLinkedRef =
+          serializer.linkedReferences[typeRef.reference];
+      int refId = serializer.serializeUnlinkedReference(
+          name.name,
+          name.staticElement != null
+              ? ReferenceKind.constructor
+              : ReferenceKind.unresolved,
+          prefixReference: typeRef.reference,
+          unit: typeLinkedRef.unit);
+      return new EntityRefBuilder(
+          reference: refId, typeArguments: typeRef.typeArguments);
+    }
+  }
+
+  EntityRefBuilder serializeIdentifier(Identifier identifier,
+      {int prefixReference: 0}) {
+    Element element = identifier.staticElement;
+    // Unresolved identifier.
+    if (element == null) {
+      int reference;
+      if (identifier is PrefixedIdentifier) {
+        int prefix = serializeIdentifier(identifier.prefix).reference;
+        reference = serializer.serializeUnlinkedReference(
+            identifier.identifier.name, ReferenceKind.unresolved,
+            prefixReference: prefix);
+      } else {
+        reference = serializer.serializeUnlinkedReference(
+            identifier.name, ReferenceKind.unresolved,
+            prefixReference: prefixReference);
+      }
+      return new EntityRefBuilder(reference: reference);
+    }
+    // The only supported instance property accessor - `length`.
+    if (identifier is PrefixedIdentifier &&
+        element is PropertyAccessorElement &&
+        !element.isStatic) {
+      if (element.name != 'length') {
+        throw new StateError('Only "length" property is allowed in constants.');
+      }
+      Element prefixElement = identifier.prefix.staticElement;
+      int prefixRef = serializer._getElementReferenceId(prefixElement);
+      int lengthRef = serializer._getLengthPropertyReference(prefixRef);
+      return new EntityRefBuilder(reference: lengthRef);
+    }
+    if (element is TypeParameterElement) {
+      throw new StateError('Constants may not refer to type parameters.');
+    }
+    return new EntityRefBuilder(
+        reference: serializer._getElementReferenceId(element));
+  }
+
+  @override
+  EntityRefBuilder serializePropertyAccess(PropertyAccess access) {
+    Element element = access.propertyName.staticElement;
+    // Unresolved property access.
+    if (element == null) {
+      Expression target = access.target;
+      if (target is Identifier) {
+        EntityRefBuilder targetRef = serializeIdentifier(target);
+        EntityRefBuilder propertyRef = serializeIdentifier(access.propertyName,
+            prefixReference: targetRef.reference);
+        return new EntityRefBuilder(reference: propertyRef.reference);
+      } else {
+        // TODO(scheglov) should we handle other targets in malformed constants?
+        throw new StateError('Unexpected target type: ${target.runtimeType}');
+      }
+    }
+    // The only supported instance property accessor - `length`.
+    Expression target = access.target;
+    if (target is Identifier &&
+        element is PropertyAccessorElement &&
+        !element.isStatic) {
+      assert(element.name == 'length');
+      Element prefixElement = target.staticElement;
+      int prefixRef = serializer._getElementReferenceId(prefixElement);
+      int lengthRef = serializer._getLengthPropertyReference(prefixRef);
+      return new EntityRefBuilder(reference: lengthRef);
+    }
+    return new EntityRefBuilder(
+        reference: serializer._getElementReferenceId(element));
+  }
+
+  @override
+  EntityRefBuilder serializeType(TypeName typeName) {
+    if (typeName != null) {
+      DartType type = typeName.type;
+      if (type == null || type.isUndefined) {
+        return serializeIdentifier(typeName.name);
+      }
+    }
+    DartType type = typeName != null ? typeName.type : DynamicTypeImpl.instance;
+    return serializer.serializeTypeRef(type, null);
+  }
+}
+
+/**
+ * Instances of this class keep track of intermediate state during
+ * serialization of a single library.
+ */
+class _LibrarySerializer {
+  /**
+   * The library to be serialized.
+   */
+  final LibraryElement libraryElement;
+
+  /**
+   * The type provider.  This is used to locate the library for `dart:core`.
+   */
+  final TypeProvider typeProvider;
+
+  /**
+   * Indicates whether the element model being serialized was analyzed using
+   * strong mode.
+   */
+  final bool strongMode;
+
+  /**
+   * Map from [LibraryElement] to the index of the entry in the "dependency
+   * table" that refers to it.
+   */
+  final Map<LibraryElement, int> dependencyMap = <LibraryElement, int>{};
+
+  /**
+   * The "dependency table".  This is the list of objects which should be
+   * written to [LinkedLibrary.dependencies].
+   */
+  final List<LinkedDependencyBuilder> dependencies =
+      <LinkedDependencyBuilder>[];
+
+  /**
+   * The linked portion of the "imports table".  This is the list of ints
+   * which should be written to [LinkedLibrary.imports].
+   */
+  final List<int> linkedImports = <int>[];
+
+  /**
+   * Set of libraries which have been seen so far while visiting the transitive
+   * closure of exports.
+   */
+  final Set<LibraryElement> librariesAddedToTransitiveExportClosure =
+      new Set<LibraryElement>();
+
+  /**
+   * Map from imported element to the prefix which may be used to refer to that
+   * element; elements for which no prefix is needed are absent from this map.
+   */
+  final Map<Element, PrefixElement> prefixMap = <Element, PrefixElement>{};
+
+  /**
+   * List of serializers for the compilation units constituting this library.
+   */
+  final List<_CompilationUnitSerializer> compilationUnitSerializers =
+      <_CompilationUnitSerializer>[];
+
+  _LibrarySerializer(this.libraryElement, this.typeProvider, this.strongMode) {
+    dependencies.add(new LinkedDependencyBuilder());
+    dependencyMap[libraryElement] = 0;
+  }
+
+  /**
+   * Retrieve a list of the Sources for the compilation units in the library.
+   */
+  List<Source> get unitSources => compilationUnitSerializers
+      .map((_CompilationUnitSerializer s) => s.unitSource)
+      .toList();
+
+  /**
+   * Retrieve a list of the URIs for the compilation units in the library.
+   */
+  List<String> get unitUris => compilationUnitSerializers
+      .map((_CompilationUnitSerializer s) => s.unitUri)
+      .toList();
+
+  /**
+   * Retrieve a list of the [UnlinkedUnitBuilder]s for the compilation units in
+   * the library.
+   */
+  List<UnlinkedUnitBuilder> get unlinkedUnits => compilationUnitSerializers
+      .map((_CompilationUnitSerializer s) => s.unlinkedUnit)
+      .toList();
+
+  /**
+   * Add [exportedLibrary] (and the transitive closure of all libraries it
+   * exports) to the dependency table ([LinkedLibrary.dependencies]).
+   */
+  void addTransitiveExportClosure(LibraryElement exportedLibrary) {
+    if (librariesAddedToTransitiveExportClosure.add(exportedLibrary)) {
+      serializeDependency(exportedLibrary);
+      for (LibraryElement transitiveExport
+          in exportedLibrary.exportedLibraries) {
+        addTransitiveExportClosure(transitiveExport);
+      }
+    }
+  }
+
+  /**
+   * Fill in [prefixMap] using information from [libraryElement.imports].
+   */
+  void computePrefixMap() {
+    for (ImportElement import in libraryElement.imports) {
+      if (import.prefix == null) {
+        continue;
+      }
+      import.importedLibrary.exportNamespace.definedNames
+          .forEach((String name, Element e) {
+        if (new NameFilter.forNamespaceCombinators(import.combinators)
+            .accepts(name)) {
+          prefixMap[e] = import.prefix;
+        }
+      });
+    }
+  }
+
+  /**
+   * Return the index of the entry in the dependency table
+   * ([LinkedLibrary.dependencies]) for the given [dependentLibrary].  A new
+   * entry is added to the table if necessary to satisfy the request.
+   */
+  int serializeDependency(LibraryElement dependentLibrary) {
+    return dependencyMap.putIfAbsent(dependentLibrary, () {
+      int index = dependencies.length;
+      List<String> parts = dependentLibrary.parts
+          .map((CompilationUnitElement e) => e.source.uri.toString())
+          .toList();
+      dependencies.add(new LinkedDependencyBuilder(
+          uri: dependentLibrary.source.uri.toString(), parts: parts));
+      return index;
+    });
+  }
+
+  /**
+   * Serialize the whole library element into a [LinkedLibrary].  Should be
+   * called exactly once for each instance of [_LibrarySerializer].
+   *
+   * The unlinked compilation units are stored in [unlinkedUnits], and their
+   * absolute URIs are stored in [unitUris].
+   */
+  LinkedLibraryBuilder serializeLibrary() {
+    computePrefixMap();
+    LinkedLibraryBuilder pb = new LinkedLibraryBuilder();
+    for (ExportElement exportElement in libraryElement.exports) {
+      addTransitiveExportClosure(exportElement.exportedLibrary);
+    }
+    for (ImportElement importElement in libraryElement.imports) {
+      addTransitiveExportClosure(importElement.importedLibrary);
+      linkedImports.add(serializeDependency(importElement.importedLibrary));
+    }
+    compilationUnitSerializers.add(new _CompilationUnitSerializer(
+        this, libraryElement.definingCompilationUnit, 0));
+    for (int i = 0; i < libraryElement.parts.length; i++) {
+      compilationUnitSerializers.add(
+          new _CompilationUnitSerializer(this, libraryElement.parts[i], i + 1));
+    }
+    for (_CompilationUnitSerializer compilationUnitSerializer
+        in compilationUnitSerializers) {
+      compilationUnitSerializer.addCompilationUnitElements();
+    }
+    pb.units = compilationUnitSerializers
+        .map((_CompilationUnitSerializer s) => s.linkedUnit)
+        .toList();
+    pb.dependencies = dependencies;
+    pb.numPrelinkedDependencies = dependencies.length;
+    for (_CompilationUnitSerializer compilationUnitSerializer
+        in compilationUnitSerializers) {
+      compilationUnitSerializer.createLinkedTypes();
+    }
+    pb.importDependencies = linkedImports;
+    List<String> exportedNames =
+        libraryElement.exportNamespace.definedNames.keys.toList();
+    exportedNames.sort();
+    List<LinkedExportNameBuilder> exportNames = <LinkedExportNameBuilder>[];
+    for (String name in exportedNames) {
+      if (libraryElement.publicNamespace.definedNames.containsKey(name)) {
+        continue;
+      }
+      Element element = libraryElement.exportNamespace.get(name);
+      LibraryElement dependentLibrary = element.library;
+      CompilationUnitElement unitElement =
+          element.getAncestor((Element e) => e is CompilationUnitElement);
+      int unit = dependentLibrary.units.indexOf(unitElement);
+      assert(unit != -1);
+      ReferenceKind kind = _getReferenceKind(element);
+      exportNames.add(new LinkedExportNameBuilder(
+          name: name,
+          dependency: serializeDependency(dependentLibrary),
+          unit: unit,
+          kind: kind));
+    }
+    pb.exportNames = exportNames;
+    return pb;
+  }
 }
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 4d9b9fe..ad422ca 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -8,56 +8,55 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/context/cache.dart' show CacheEntry;
 import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source.dart' show Source, SourceKind;
-import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/generated/source.dart'
+    show DartUriResolver, Source, SourceFactory, SourceKind;
+import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/resynthesize.dart';
-import 'package:analyzer/src/task/dart.dart'
-    show
-        LIBRARY_ELEMENT1,
-        LIBRARY_ELEMENT2,
-        LIBRARY_ELEMENT3,
-        LIBRARY_ELEMENT4,
-        LIBRARY_ELEMENT5,
-        LIBRARY_ELEMENT6,
-        LIBRARY_ELEMENT7,
-        LIBRARY_ELEMENT8,
-        READY_LIBRARY_ELEMENT2,
-        READY_LIBRARY_ELEMENT5,
-        READY_LIBRARY_ELEMENT6,
-        TYPE_PROVIDER;
+import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/task/dart.dart';
 import 'package:analyzer/task/model.dart'
     show AnalysisTarget, ResultDescriptor, TargetedResult;
 
-/**
- * An [SdkAnalysisContext] for Dart SDK with a summary [SdkBundle].
- */
-class SummarySdkAnalysisContext extends SdkAnalysisContext {
-  final SdkBundle bundle;
+class SdkSummaryResultProvider implements SummaryResultProvider {
+  final InternalAnalysisContext context;
+  final PackageBundle bundle;
   final SummaryTypeProvider typeProvider = new SummaryTypeProvider();
 
+  @override
   SummaryResynthesizer resynthesizer;
 
-  SummarySdkAnalysisContext(this.bundle);
+  SdkSummaryResultProvider(this.context, this.bundle) {
+    resynthesizer = new SdkSummaryResynthesizer(
+        context, typeProvider, context.sourceFactory, bundle);
+    _buildCoreLibrary();
+    _buildAsyncLibrary();
+    resynthesizer.finalizeCoreAsyncLibraries();
+    context.typeProvider = typeProvider;
+  }
 
   @override
-  bool aboutToComputeResult(CacheEntry entry, ResultDescriptor result) {
-    if (resynthesizer == null) {
-      resynthesizer = new SummaryResynthesizer(this, typeProvider,
-          _getPrelinkedSummary, _getUnlinkedSummary, sourceFactory);
-      _buildCoreLibrary();
-      _buildAsyncLibrary();
-    }
+  bool compute(CacheEntry entry, ResultDescriptor result) {
     if (result == TYPE_PROVIDER) {
       entry.setValue(result, typeProvider, TargetedResult.EMPTY_LIST);
       return true;
     }
     AnalysisTarget target = entry.target;
-//    print('SummarySdkAnalysisContext: $result of $target');
-    if (target is Source && target.isInSystemLibrary) {
+    // Only SDK sources after this point.
+    if (target.source == null || !target.source.isInSystemLibrary) {
+      return false;
+    }
+    // Constant expressions are always resolved in summaries.
+    if (result == CONSTANT_EXPRESSION_RESOLVED &&
+        target is ConstantEvaluationTarget) {
+      entry.setValue(result, true, TargetedResult.EMPTY_LIST);
+      return true;
+    }
+    if (target is Source) {
       if (result == LIBRARY_ELEMENT1 ||
           result == LIBRARY_ELEMENT2 ||
           result == LIBRARY_ELEMENT3 ||
@@ -80,12 +79,9 @@
         return true;
       } else if (result == SOURCE_KIND) {
         String uri = target.uri.toString();
-        if (bundle.prelinkedLibraryUris.contains(uri)) {
-          entry.setValue(result, SourceKind.LIBRARY, TargetedResult.EMPTY_LIST);
-          return true;
-        }
-        if (bundle.unlinkedUnitUris.contains(uri)) {
-          entry.setValue(result, SourceKind.PART, TargetedResult.EMPTY_LIST);
+        SourceKind kind = _getSourceKind(uri);
+        if (kind != null) {
+          entry.setValue(result, kind, TargetedResult.EMPTY_LIST);
           return true;
         }
         return false;
@@ -93,6 +89,21 @@
 //        throw new UnimplementedError('$result of $target');
       }
     }
+    if (target is LibrarySpecificUnit) {
+      if (target.library == null || !target.library.isInSystemLibrary) {
+        return false;
+      }
+      if (result == COMPILATION_UNIT_ELEMENT) {
+        String libraryUri = target.library.uri.toString();
+        String unitUri = target.unit.uri.toString();
+        CompilationUnitElement unit = resynthesizer.getElement(
+            new ElementLocationImpl.con3(<String>[libraryUri, unitUri]));
+        if (unit != null) {
+          entry.setValue(result, unit, TargetedResult.EMPTY_LIST);
+          return true;
+        }
+      }
+    }
     return false;
   }
 
@@ -106,23 +117,65 @@
     typeProvider.initializeCore(library);
   }
 
-  PrelinkedLibrary _getPrelinkedSummary(String uri) {
-    for (int i = 0; i < bundle.prelinkedLibraryUris.length; i++) {
-      if (bundle.prelinkedLibraryUris[i] == uri) {
-        return bundle.prelinkedLibraries[i];
-      }
+  /**
+   * Return the [SourceKind] of the given [uri] or `null` if it is unknown.
+   */
+  SourceKind _getSourceKind(String uri) {
+    if (bundle.linkedLibraryUris.contains(uri)) {
+      return SourceKind.LIBRARY;
     }
-    throw new StateError('Unable to find prelinked summary for $uri');
+    if (bundle.unlinkedUnitUris.contains(uri)) {
+      return SourceKind.PART;
+    }
+    return null;
+  }
+}
+
+/**
+ * The implementation of [SummaryResynthesizer] for Dart SDK.
+ */
+class SdkSummaryResynthesizer extends SummaryResynthesizer {
+  final PackageBundle bundle;
+  final Map<String, UnlinkedUnit> unlinkedSummaries = <String, UnlinkedUnit>{};
+  final Map<String, LinkedLibrary> linkedSummaries = <String, LinkedLibrary>{};
+
+  SdkSummaryResynthesizer(AnalysisContext context, TypeProvider typeProvider,
+      SourceFactory sourceFactory, this.bundle)
+      : super(null, context, typeProvider, sourceFactory, false) {
+    // TODO(paulberry): we always resynthesize the summary in weak mode.  Is
+    // this ok?
+    for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
+      unlinkedSummaries[bundle.unlinkedUnitUris[i]] = bundle.unlinkedUnits[i];
+    }
+    for (int i = 0; i < bundle.linkedLibraryUris.length; i++) {
+      linkedSummaries[bundle.linkedLibraryUris[i]] = bundle.linkedLibraries[i];
+    }
   }
 
-  UnlinkedUnit _getUnlinkedSummary(String uri) {
-    for (int i = 0; i < bundle.unlinkedUnitUris.length; i++) {
-      if (bundle.unlinkedUnitUris[i] == uri) {
-        return bundle.unlinkedUnits[i];
-      }
-    }
-    throw new StateError('Unable to find unlinked summary for $uri');
+  @override
+  LinkedLibrary getLinkedSummary(String uri) {
+    return linkedSummaries[uri];
   }
+
+  @override
+  UnlinkedUnit getUnlinkedSummary(String uri) {
+    return unlinkedSummaries[uri];
+  }
+
+  @override
+  bool hasLibrarySummary(String uri) {
+    return uri.startsWith('dart:');
+  }
+}
+
+/**
+ * Provider for analysis results.
+ */
+abstract class SummaryResultProvider extends ResultProvider {
+  /**
+   * The [SummaryResynthesizer] of this context, maybe `null`.
+   */
+  SummaryResynthesizer get resynthesizer;
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index df4e7ac..b94806d 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -6,11 +6,18 @@
 
 import 'dart:collection';
 
+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/dart/element/type.dart';
 import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -19,10 +26,9 @@
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/visitors.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/plugin/engine_plugin.dart';
 import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/driver.dart';
@@ -113,6 +119,17 @@
         'CONSTANT_DEPENDENCIES', const <ConstantEvaluationTarget>[]);
 
 /**
+ * The flag specifying that the target constant element expression AST is
+ * resolved, i.e. identifiers have all required elements set.
+ *
+ * The result is only available for targets representing a
+ * [ConstantEvaluationTarget] (i.e. a constant variable declaration, a constant
+ * constructor, or a parameter element with a default value).
+ */
+final ResultDescriptor<bool> CONSTANT_EXPRESSION_RESOLVED =
+    new ResultDescriptor<bool>('CONSTANT_EXPRESSION_RESOLVED', false);
+
+/**
  * The list of [ConstantEvaluationTarget]s on which constant expressions of a
  * unit depend.
  *
@@ -557,24 +574,6 @@
     new ResultDescriptor<bool>('READY_RESOLVED_UNIT', false);
 
 /**
- * The flag specifying that [RESOLVED_UNIT10] is ready for all of the units of a
- * library and its import/export closure.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ResultDescriptor<bool> READY_RESOLVED_UNIT10 =
-    new ResultDescriptor<bool>('READY_RESOLVED_UNIT10', false);
-
-/**
- * The flag specifying that [RESOLVED_UNIT11] is ready for all of the units of a
- * library and its import/export closure.
- *
- * The result is only available for [Source]s representing a library.
- */
-final ResultDescriptor<bool> READY_RESOLVED_UNIT11 =
-    new ResultDescriptor<bool>('READY_RESOLVED_UNIT11', false);
-
-/**
  * The names (resolved and not) referenced by a unit.
  *
  * The result is only available for [Source]s representing a compilation unit.
@@ -870,13 +869,24 @@
     Source source = getRequiredSource();
     CompilationUnit unit = getRequiredInput(PARSED_UNIT_INPUT_NAME);
     //
+    // Try to get the existing CompilationUnitElement.
+    //
+    CompilationUnitElement element;
+    {
+      InternalAnalysisContext internalContext =
+          context as InternalAnalysisContext;
+      AnalysisCache analysisCache = internalContext.analysisCache;
+      CacheEntry cacheEntry = internalContext.getCacheEntry(target);
+      element = analysisCache.getValue(target, COMPILATION_UNIT_ELEMENT);
+      if (element == null &&
+          internalContext.aboutToComputeResult(
+              cacheEntry, COMPILATION_UNIT_ELEMENT)) {
+        element = analysisCache.getValue(target, COMPILATION_UNIT_ELEMENT);
+      }
+    }
+    //
     // Build or reuse CompilationUnitElement.
     //
-//    unit = AstCloner.clone(unit);
-    AnalysisCache analysisCache =
-        (context as InternalAnalysisContext).analysisCache;
-    CompilationUnitElement element =
-        analysisCache.getValue(target, COMPILATION_UNIT_ELEMENT);
     if (element == null) {
       CompilationUnitBuilder builder = new CompilationUnitBuilder();
       element = builder.buildCompilationUnit(
@@ -980,7 +990,6 @@
 
   @override
   void internalPerform() {
-    List<AnalysisError> errors = <AnalysisError>[];
     //
     // Prepare inputs.
     //
@@ -994,114 +1003,17 @@
         getRequiredInput(IMPORTS_SOURCE_KIND_INPUT_NAME);
     Map<Source, SourceKind> exportSourceKindMap =
         getRequiredInput(EXPORTS_SOURCE_KIND_INPUT_NAME);
-    Source librarySource = libraryElement.source;
     //
-    // Resolve directives.
+    // Build elements.
     //
-    HashMap<String, PrefixElementImpl> nameToPrefixMap =
-        new HashMap<String, PrefixElementImpl>();
-    List<ImportElement> imports = <ImportElement>[];
-    List<ExportElement> exports = <ExportElement>[];
-    bool explicitlyImportsCore = false;
-    for (Directive directive in libraryUnit.directives) {
-      if (directive is ImportDirective) {
-        ImportDirective importDirective = directive;
-        String uriContent = importDirective.uriContent;
-        if (DartUriResolver.isDartExtUri(uriContent)) {
-          libraryElement.hasExtUri = true;
-        }
-        Source importedSource = importDirective.source;
-        if (importedSource != null && context.exists(importedSource)) {
-          // The imported source will be null if the URI in the import
-          // directive was invalid.
-          LibraryElement importedLibrary = importLibraryMap[importedSource];
-          if (importedLibrary != null) {
-            if (importedLibrary.isDartCore) {
-              explicitlyImportsCore = true;
-            }
-            ImportElementImpl importElement =
-                new ImportElementImpl(directive.offset);
-            StringLiteral uriLiteral = importDirective.uri;
-            if (uriLiteral != null) {
-              importElement.uriOffset = uriLiteral.offset;
-              importElement.uriEnd = uriLiteral.end;
-            }
-            importElement.uri = uriContent;
-            importElement.deferred = importDirective.deferredKeyword != null;
-            importElement.combinators = _buildCombinators(importDirective);
-            importElement.importedLibrary = importedLibrary;
-            _setDoc(importElement, importDirective);
-            SimpleIdentifier prefixNode = directive.prefix;
-            if (prefixNode != null) {
-              importElement.prefixOffset = prefixNode.offset;
-              String prefixName = prefixNode.name;
-              PrefixElementImpl prefix = nameToPrefixMap[prefixName];
-              if (prefix == null) {
-                prefix = new PrefixElementImpl.forNode(prefixNode);
-                nameToPrefixMap[prefixName] = prefix;
-              }
-              importElement.prefix = prefix;
-              prefixNode.staticElement = prefix;
-            }
-            directive.element = importElement;
-            imports.add(importElement);
-            if (importSourceKindMap[importedSource] != SourceKind.LIBRARY) {
-              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()]));
-            }
-          }
-        }
-      } else if (directive is ExportDirective) {
-        ExportDirective exportDirective = directive;
-        Source exportedSource = exportDirective.source;
-        if (exportedSource != null && context.exists(exportedSource)) {
-          // The exported source will be null if the URI in the export
-          // directive was invalid.
-          LibraryElement exportedLibrary = exportLibraryMap[exportedSource];
-          if (exportedLibrary != null) {
-            ExportElementImpl exportElement =
-                new ExportElementImpl(directive.offset);
-            StringLiteral uriLiteral = exportDirective.uri;
-            if (uriLiteral != null) {
-              exportElement.uriOffset = uriLiteral.offset;
-              exportElement.uriEnd = uriLiteral.end;
-            }
-            exportElement.uri = exportDirective.uriContent;
-            exportElement.combinators = _buildCombinators(exportDirective);
-            exportElement.exportedLibrary = exportedLibrary;
-            _setDoc(exportElement, exportDirective);
-            directive.element = exportElement;
-            exports.add(exportElement);
-            if (exportSourceKindMap[exportedSource] != SourceKind.LIBRARY) {
-              errors.add(new AnalysisError(
-                  exportedSource,
-                  uriLiteral.offset,
-                  uriLiteral.length,
-                  CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
-                  [uriLiteral.toSource()]));
-            }
-          }
-        }
-      }
-    }
-    //
-    // Ensure "dart:core" import.
-    //
-    Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE);
-    if (!explicitlyImportsCore && coreLibrarySource != librarySource) {
-      ImportElementImpl importElement = new ImportElementImpl(-1);
-      importElement.importedLibrary = importLibraryMap[coreLibrarySource];
-      importElement.synthetic = true;
-      imports.add(importElement);
-    }
-    //
-    // Populate the library element.
-    //
-    libraryElement.imports = imports;
-    libraryElement.exports = exports;
+    DirectiveElementBuilder builder = new DirectiveElementBuilder(
+        context,
+        libraryElement,
+        importLibraryMap,
+        importSourceKindMap,
+        exportLibraryMap,
+        exportSourceKindMap);
+    libraryUnit.accept(builder);
     // See commentary in the computation of the LIBRARY_CYCLE result
     // for details on library cycle invalidation.
     libraryElement.invalidateLibraryCycles();
@@ -1109,20 +1021,7 @@
     // Record outputs.
     //
     outputs[LIBRARY_ELEMENT2] = libraryElement;
-    outputs[BUILD_DIRECTIVES_ERRORS] = errors;
-  }
-
-  /**
-   * If the given [node] has a documentation comment, remember its content
-   * and range into the given [element].
-   */
-  void _setDoc(ElementImpl element, AnnotatedNode node) {
-    Comment comment = node.documentationComment;
-    if (comment != null && comment.isDocumentation) {
-      element.documentationComment =
-          comment.tokens.map((Token t) => t.lexeme).join('\n');
-      element.setDocRange(comment.offset, comment.length);
-    }
+    outputs[BUILD_DIRECTIVES_ERRORS] = builder.errors;
   }
 
   /**
@@ -1155,36 +1054,6 @@
       AnalysisContext context, AnalysisTarget target) {
     return new BuildDirectiveElementsTask(context, target);
   }
-
-  /**
-   * Build the element model representing the combinators declared by
-   * the given [directive].
-   */
-  static List<NamespaceCombinator> _buildCombinators(
-      NamespaceDirective directive) {
-    List<NamespaceCombinator> combinators = <NamespaceCombinator>[];
-    for (Combinator combinator in directive.combinators) {
-      if (combinator is ShowCombinator) {
-        ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
-        show.offset = combinator.offset;
-        show.end = combinator.end;
-        show.shownNames = _getIdentifiers(combinator.shownNames);
-        combinators.add(show);
-      } else if (combinator is HideCombinator) {
-        HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
-        hide.hiddenNames = _getIdentifiers(combinator.hiddenNames);
-        combinators.add(hide);
-      }
-    }
-    return combinators;
-  }
-
-  /**
-   * Return the lexical identifiers associated with the given [identifiers].
-   */
-  static List<String> _getIdentifiers(NodeList<SimpleIdentifier> identifiers) {
-    return identifiers.map((identifier) => identifier.name).toList();
-  }
 }
 
 /**
@@ -1226,10 +1095,24 @@
     TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
     //
+    // Build the enum members if they have not already been created.
+    //
+    EnumDeclaration findFirstEnum() {
+      for (CompilationUnitMember member in unit.declarations) {
+        if (member is EnumDeclaration) {
+          return member;
+        }
+      }
+      return null;
+    }
+    EnumDeclaration firstEnum = findFirstEnum();
+    if (firstEnum != null && firstEnum.element.accessors.isEmpty) {
+      EnumMemberBuilder builder = new EnumMemberBuilder(typeProvider);
+      unit.accept(builder);
+    }
+    //
     // Record outputs.
     //
-    EnumMemberBuilder builder = new EnumMemberBuilder(typeProvider);
-    unit.accept(builder);
     outputs[CREATED_RESOLVED_UNIT2] = true;
     outputs[RESOLVED_UNIT2] = unit;
   }
@@ -1288,8 +1171,8 @@
     //
     // Compute export namespace.
     //
-    ExportNamespaceBuilder builder = new ExportNamespaceBuilder();
-    Namespace namespace = builder.build(library);
+    NamespaceBuilder builder = new NamespaceBuilder();
+    Namespace namespace = builder.createExportNamespaceForLibrary(library);
     library.exportNamespace = namespace;
     //
     // Update entry point.
@@ -1395,7 +1278,6 @@
     //
     // Update "part" directives.
     //
-    LibraryDirective libraryDirective = null;
     LibraryIdentifier libraryNameNode = null;
     String partsLibraryName = _UNKNOWN_LIBRARY_NAME;
     bool hasPartDirective = false;
@@ -1406,11 +1288,8 @@
         <CompilationUnitElementImpl>[];
     for (Directive directive in definingCompilationUnit.directives) {
       if (directive is LibraryDirective) {
-        if (libraryDirective == null) {
-          libraryDirective = directive;
-          libraryNameNode = directive.name;
-          directivesToResolve.add(directive);
-        }
+        libraryNameNode = directive.name;
+        directivesToResolve.add(directive);
       } else if (directive is PartDirective) {
         PartDirective partDirective = directive;
         StringLiteral partUri = partDirective.uri;
@@ -1480,19 +1359,40 @@
       InternalAnalysisContext internalContext = context;
       owningContext = internalContext.getContextFor(librarySource);
     }
-    LibraryElementImpl libraryElement =
-        new LibraryElementImpl.forNode(owningContext, libraryNameNode);
-    libraryElement.definingCompilationUnit = definingCompilationUnitElement;
-    libraryElement.entryPoint = entryPoint;
-    libraryElement.parts = sourcedCompilationUnits;
-    for (Directive directive in directivesToResolve) {
-      directive.element = libraryElement;
+    //
+    // Try to get the existing LibraryElement.
+    //
+    LibraryElementImpl libraryElement;
+    {
+      InternalAnalysisContext internalContext =
+          context as InternalAnalysisContext;
+      AnalysisCache analysisCache = internalContext.analysisCache;
+      CacheEntry cacheEntry = internalContext.getCacheEntry(target);
+      libraryElement = analysisCache.getValue(target, LIBRARY_ELEMENT1);
+      if (libraryElement == null &&
+          internalContext.aboutToComputeResult(cacheEntry, LIBRARY_ELEMENT1)) {
+        libraryElement = analysisCache.getValue(target, LIBRARY_ELEMENT1);
+      }
     }
-    if (sourcedCompilationUnits.isNotEmpty) {
-      _patchTopLevelAccessors(libraryElement);
-    }
-    if (libraryDirective != null) {
-      _setDoc(libraryElement, libraryDirective);
+    //
+    // Create a new LibraryElement.
+    //
+    if (libraryElement == null) {
+      libraryElement =
+          new LibraryElementImpl.forNode(owningContext, libraryNameNode);
+      libraryElement.definingCompilationUnit = definingCompilationUnitElement;
+      libraryElement.entryPoint = entryPoint;
+      libraryElement.parts = sourcedCompilationUnits;
+      for (Directive directive in directivesToResolve) {
+        directive.element = libraryElement;
+      }
+      BuildLibraryElementUtils.patchTopLevelAccessors(libraryElement);
+      // set the library documentation to the docs associated with the first
+      // directive in the compilation unit.
+      if (definingCompilationUnit.directives.isNotEmpty) {
+        setElementDocumentationComment(
+            libraryElement, definingCompilationUnit.directives.first);
+      }
     }
     //
     // Record outputs.
@@ -1503,25 +1403,6 @@
   }
 
   /**
-   * Add all of the non-synthetic [getters] and [setters] defined in the given
-   * [unit] that have no corresponding accessor to one of the given collections.
-   */
-  void _collectAccessors(Map<String, PropertyAccessorElement> getters,
-      List<PropertyAccessorElement> setters, CompilationUnitElement unit) {
-    for (PropertyAccessorElement accessor in unit.accessors) {
-      if (accessor.isGetter) {
-        if (!accessor.isSynthetic && accessor.correspondingSetter == null) {
-          getters[accessor.displayName] = accessor;
-        }
-      } else {
-        if (!accessor.isSynthetic && accessor.correspondingGetter == null) {
-          setters.add(accessor);
-        }
-      }
-    }
-  }
-
-  /**
    * Return the top-level [FunctionElement] entry point, or `null` if the given
    * [element] does not define an entry point.
    */
@@ -1553,46 +1434,6 @@
   }
 
   /**
-   * Look through all of the compilation units defined for the given [library],
-   * looking for getters and setters that are defined in different compilation
-   * units but that have the same names. If any are found, make sure that they
-   * have the same variable element.
-   */
-  void _patchTopLevelAccessors(LibraryElementImpl library) {
-    HashMap<String, PropertyAccessorElement> getters =
-        new HashMap<String, PropertyAccessorElement>();
-    List<PropertyAccessorElement> setters = <PropertyAccessorElement>[];
-    _collectAccessors(getters, setters, library.definingCompilationUnit);
-    for (CompilationUnitElement unit in library.parts) {
-      _collectAccessors(getters, setters, unit);
-    }
-    for (PropertyAccessorElement setter in setters) {
-      PropertyAccessorElement getter = getters[setter.displayName];
-      if (getter != null) {
-        TopLevelVariableElementImpl variable = getter.variable;
-        TopLevelVariableElementImpl setterVariable = setter.variable;
-        CompilationUnitElementImpl setterUnit = setterVariable.enclosingElement;
-        setterUnit.replaceTopLevelVariable(setterVariable, variable);
-        variable.setter = setter;
-        (setter as PropertyAccessorElementImpl).variable = variable;
-      }
-    }
-  }
-
-  /**
-   * If the given [node] has a documentation comment, remember its content
-   * and range into the given [element].
-   */
-  void _setDoc(ElementImpl element, AnnotatedNode node) {
-    Comment comment = node.documentationComment;
-    if (comment != null && comment.isDocumentation) {
-      element.documentationComment =
-          comment.tokens.map((Token t) => t.lexeme).join('\n');
-      element.setDocRange(comment.offset, comment.length);
-    }
-  }
-
-  /**
    * Return a map from the names of the inputs of this kind of task to the task
    * input descriptors describing those inputs for a task with the given
    * [libSource].
@@ -1646,7 +1487,8 @@
   @override
   void internalPerform() {
     LibraryElementImpl library = getRequiredInput(LIBRARY_INPUT);
-    library.publicNamespace = new PublicNamespaceBuilder().build(library);
+    NamespaceBuilder builder = new NamespaceBuilder();
+    library.publicNamespace = builder.createPublicNamespaceForLibrary(library);
     outputs[LIBRARY_ELEMENT3] = library;
   }
 
@@ -1759,12 +1601,21 @@
   @override
   void internalPerform() {
     LibraryElement coreLibrary = getRequiredInput(CORE_INPUT);
-    LibraryElement asyncLibrary = getRequiredInput(ASYNC_INPUT);
+    LibraryElement asyncLibrary = getOptionalInput(ASYNC_INPUT);
+    if (asyncLibrary == null) {
+      asyncLibrary =
+          (context as AnalysisContextImpl).createMockAsyncLib(coreLibrary);
+    }
     Namespace coreNamespace = coreLibrary.publicNamespace;
     Namespace asyncNamespace = asyncLibrary.publicNamespace;
     //
     // Record outputs.
     //
+    if (!context.analysisOptions.enableAsync) {
+      AnalysisContextImpl contextImpl = context;
+      asyncLibrary = contextImpl.createMockAsyncLib(coreLibrary);
+      asyncNamespace = asyncLibrary.publicNamespace;
+    }
     TypeProvider typeProvider =
         new TypeProviderImpl.forNamespaces(coreNamespace, asyncNamespace);
     (context as InternalAnalysisContext).typeProvider = typeProvider;
@@ -1776,6 +1627,9 @@
     SourceFactory sourceFactory = contextTarget.context.sourceFactory;
     Source coreSource = sourceFactory.forUri(DartSdk.DART_CORE);
     Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
+    if (asyncSource == null) {
+      return <String, TaskInput>{CORE_INPUT: LIBRARY_ELEMENT3.of(coreSource)};
+    }
     return <String, TaskInput>{
       CORE_INPUT: LIBRARY_ELEMENT3.of(coreSource),
       ASYNC_INPUT: LIBRARY_ELEMENT3.of(asyncSource)
@@ -1839,30 +1693,8 @@
    * given [target].
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
-    //
-    // TODO(brianwilkerson) I believe that this does not properly guarantee that
-    // all of the constructor initializers that we might encounter have been
-    // copied into the element model. We tried forcing the computation of the
-    // RESOLVED_UNIT9 for each unit reachable from the target's library, but
-    // that had too big a performance impact. We could potentially mitigate the
-    // impact by computing a more accurate list of the sources containing
-    // constructors that are actually referenced, but other approaches should
-    // be considered.
-    //
-    Source librarySource;
-    if (target is Element) {
-      CompilationUnitElementImpl unit = target
-          .getAncestor((Element element) => element is CompilationUnitElement);
-      librarySource = unit.librarySource;
-    } else if (target is ConstantEvaluationTarget_Annotation) {
-      librarySource = target.librarySource;
-    } else {
-      throw new AnalysisException(
-          'Cannot build inputs for a ${target.runtimeType}');
-    }
     return <String, TaskInput>{
-      'resolvedUnit': RESOLVED_UNIT10
-          .of(new LibrarySpecificUnit(librarySource, target.source)),
+      'constantExpressionResolved': CONSTANT_EXPRESSION_RESOLVED.of(target),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
     };
   }
@@ -2106,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>();
@@ -2422,6 +2254,19 @@
   static final TaskDescriptor DESCRIPTOR = new TaskDescriptor('DartErrorsTask',
       createTask, buildInputs, <ResultDescriptor>[DART_ERRORS]);
 
+  /**
+   * The name of the [LINE_INFO_INPUT] input.
+   */
+  static const String LINE_INFO_INPUT = 'LINE_INFO_INPUT';
+
+  /**
+   * The name of the [PARSED_UNIT_INPUT] input.
+   */
+  static const String PARSED_UNIT_INPUT = 'PARSED_UNIT_INPUT';
+
+  // Prefix for comments ignoring error codes.
+  static const String _normalizedIgnorePrefix = '//ignore:';
+
   DartErrorsTask(InternalAnalysisContext context, AnalysisTarget target)
       : super(context, target);
 
@@ -2446,12 +2291,86 @@
         errorLists.add(errors);
       }
     }
+
+    //
+    // Filter ignored errors.
+    //
+    List<AnalysisError> errors =
+        _filterIgnores(AnalysisError.mergeLists(errorLists));
+
     //
     // Record outputs.
     //
-    outputs[DART_ERRORS] = AnalysisError.mergeLists(errorLists);
+    outputs[DART_ERRORS] = errors;
   }
 
+  List<AnalysisError> _filterIgnores(List<AnalysisError> errors) {
+    if (errors.isEmpty) {
+      return errors;
+    }
+
+    List<AnalysisError> filtered = <AnalysisError>[];
+
+    // Sort errors.
+    errors.sort((AnalysisError e1, AnalysisError e2) => e1.offset - e2.offset);
+
+    CompilationUnit cu = getRequiredInput(PARSED_UNIT_INPUT);
+    Token token = cu.beginToken;
+    LineInfo lineInfo = getRequiredInput(LINE_INFO_INPUT);
+
+    int errorIndex = 0;
+
+    // Step through tokens looking for comments.
+    while (errorIndex < errors.length && token.type != TokenType.EOF) {
+      // Find leading comment.
+      Token comments = token.precedingComments;
+      while (comments?.next != null) {
+        comments = comments.next;
+      }
+
+      // Normalize content.
+      String comment =
+          comments?.lexeme?.toLowerCase()?.replaceAll(new RegExp(r'\s+'), '');
+
+      // Check for ignores.
+      if (comment != null && comment.startsWith(_normalizedIgnorePrefix)) {
+        int affectedLine = lineInfo.getLocation(token.offset).lineNumber;
+
+        // Process all affected errors.
+        while (errorIndex < errors.length) {
+          AnalysisError currentError = errors[errorIndex++];
+          int errorLine = lineInfo.getLocation(currentError.offset).lineNumber;
+          if (errorLine < affectedLine) {
+            filtered.add(currentError);
+          } else if (errorLine == affectedLine) {
+            // Check for an ignore.
+            if (!_isIgnoredBy(currentError, comment)) {
+              filtered.add(currentError);
+            }
+          } else {
+            // Back up index and break.
+            --errorIndex;
+            break;
+          }
+        }
+      }
+
+      token = token.next;
+    }
+
+    // Add remaining errors.
+    if (errorIndex < errors.length) {
+      filtered.addAll(errors.sublist(errorIndex));
+    }
+
+    return filtered;
+  }
+
+  bool _isIgnoredBy(AnalysisError error, String comment) => comment
+      .substring(_normalizedIgnorePrefix.length)
+      .split(',')
+      .contains(error.errorCode.name.toLowerCase());
+
   /**
    * Return a map from the names of the inputs of this kind of task to the task
    * input descriptors describing those inputs for a task with the
@@ -2460,6 +2379,8 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     Source source = target;
     Map<String, TaskInput> inputs = <String, TaskInput>{};
+    inputs[LINE_INFO_INPUT] = LINE_INFO.of(source);
+    inputs[PARSED_UNIT_INPUT] = PARSED_UNIT.of(source);
     EnginePlugin enginePlugin = AnalysisEngine.instance.enginePlugin;
     // for Source
     for (ResultDescriptor result in enginePlugin.dartErrorsForSource) {
@@ -2554,109 +2475,6 @@
 }
 
 /**
- * The helper for building the export [Namespace] of a [LibraryElement].
- */
-class ExportNamespaceBuilder {
-  /**
-   * Build the export [Namespace] of the given [LibraryElement].
-   */
-  Namespace build(LibraryElement library) {
-    return new Namespace(
-        _createExportMapping(library, new HashSet<LibraryElement>()));
-  }
-
-  /**
-   * Create a mapping table representing the export namespace of the given
-   * [library].
-   *
-   * The given [visitedElements] a set of libraries that do not need to be
-   * visited when processing the export directives of the given library because
-   * all of the names defined by them will be added by another library.
-   */
-  HashMap<String, Element> _createExportMapping(
-      LibraryElement library, HashSet<LibraryElement> visitedElements) {
-    visitedElements.add(library);
-    try {
-      HashMap<String, Element> definedNames = new HashMap<String, Element>();
-      // Add names of the export directives.
-      for (ExportElement element in library.exports) {
-        LibraryElement exportedLibrary = element.exportedLibrary;
-        if (exportedLibrary != null &&
-            !visitedElements.contains(exportedLibrary)) {
-          //
-          // The exported library will be null if the URI does not reference a
-          // valid library.
-          //
-          HashMap<String, Element> exportedNames =
-              _createExportMapping(exportedLibrary, visitedElements);
-          exportedNames = _applyCombinators(exportedNames, element.combinators);
-          definedNames.addAll(exportedNames);
-        }
-      }
-      // Add names of the public namespace.
-      {
-        Namespace publicNamespace = library.publicNamespace;
-        if (publicNamespace != null) {
-          definedNames.addAll(publicNamespace.definedNames);
-        }
-      }
-      return definedNames;
-    } finally {
-      visitedElements.remove(library);
-    }
-  }
-
-  /**
-   * Apply the given [combinators] to all of the names in [definedNames].
-   */
-  static HashMap<String, Element> _applyCombinators(
-      HashMap<String, Element> definedNames,
-      List<NamespaceCombinator> combinators) {
-    for (NamespaceCombinator combinator in combinators) {
-      if (combinator is HideElementCombinator) {
-        _hide(definedNames, combinator.hiddenNames);
-      } else if (combinator is ShowElementCombinator) {
-        definedNames = _show(definedNames, combinator.shownNames);
-      }
-    }
-    return definedNames;
-  }
-
-  /**
-   * Hide all of the [hiddenNames] by removing them from the given
-   * [definedNames].
-   */
-  static void _hide(
-      HashMap<String, Element> definedNames, List<String> hiddenNames) {
-    for (String name in hiddenNames) {
-      definedNames.remove(name);
-      definedNames.remove('$name=');
-    }
-  }
-
-  /**
-   * Show only the given [shownNames] by removing all other names from the given
-   * [definedNames].
-   */
-  static HashMap<String, Element> _show(
-      HashMap<String, Element> definedNames, List<String> shownNames) {
-    HashMap<String, Element> newNames = new HashMap<String, Element>();
-    for (String name in shownNames) {
-      Element element = definedNames[name];
-      if (element != null) {
-        newNames[name] = element;
-      }
-      String setterName = '$name=';
-      element = definedNames[setterName];
-      if (element != null) {
-        newNames[setterName] = element;
-      }
-    }
-    return newNames;
-  }
-}
-
-/**
  * A task that builds [USED_IMPORTED_ELEMENTS] for a unit.
  */
 class GatherUsedImportedElementsTask extends SourceBasedAnalysisTask {
@@ -3257,14 +3075,7 @@
       if (newType == null || newType.isBottom) {
         newType = typeProvider.dynamicType;
       }
-      variable.type = newType;
-      (variable.initializer as ExecutableElementImpl).returnType = newType;
-      if (variable is PropertyInducingElementImpl) {
-        setReturnType(variable.getter, newType);
-        if (!variable.isFinal && !variable.isConst) {
-          setParameterType(variable.setter, newType);
-        }
-      }
+      setFieldType(variable, newType);
     } else {
       // TODO(brianwilkerson) For now we simply don't infer any type for
       // variables or fields involved in a cycle. We could try to be smarter
@@ -3553,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;
@@ -3591,6 +3403,16 @@
     HashSet<Source> importedSourceSet =
         new HashSet.from(explicitlyImportedSourceSet);
     Source coreLibrarySource = context.sourceFactory.forUri(DartSdk.DART_CORE);
+    if (coreLibrarySource == null) {
+      String message;
+      DartSdk sdk = context.sourceFactory.dartSdk;
+      if (sdk == null) {
+        message = 'Could not resolve "dart:core": SDK not defined';
+      } else {
+        message = 'Could not resolve "dart:core": SDK incorrectly configured';
+      }
+      throw new AnalysisException(message);
+    }
     importedSourceSet.add(coreLibrarySource);
     //
     // Compute kind.
@@ -4067,45 +3889,6 @@
 }
 
 /**
- * The helper for building the public [Namespace] of a [LibraryElement].
- */
-class PublicNamespaceBuilder {
-  final HashMap<String, Element> definedNames = new HashMap<String, Element>();
-
-  /**
-   * Build a public [Namespace] of the given [library].
-   */
-  Namespace build(LibraryElement library) {
-    definedNames.clear();
-    _addPublicNames(library.definingCompilationUnit);
-    library.parts.forEach(_addPublicNames);
-    return new Namespace(definedNames);
-  }
-
-  /**
-   * Add the given [element] if it has a publicly visible name.
-   */
-  void _addIfPublic(Element element) {
-    String name = element.name;
-    if (name != null && !Scope.isPrivateName(name)) {
-      definedNames[name] = element;
-    }
-  }
-
-  /**
-   * Add all of the public top-level names that are defined in the given
-   * [compilationUnit].
-   */
-  void _addPublicNames(CompilationUnitElement compilationUnit) {
-    compilationUnit.accessors.forEach(_addIfPublic);
-    compilationUnit.enums.forEach(_addIfPublic);
-    compilationUnit.functions.forEach(_addIfPublic);
-    compilationUnit.functionTypeAliases.forEach(_addIfPublic);
-    compilationUnit.types.forEach(_addIfPublic);
-  }
-}
-
-/**
  * A task that ensures that [LIBRARY_ELEMENT2] is ready for the target library
  * source and its import/export closure.
  */
@@ -4235,94 +4018,6 @@
 }
 
 /**
- * A task that ensures that [RESOLVED_UNIT10] is ready for every unit of the
- * target library source and its import/export closure.
- */
-class ReadyResolvedUnit10Task extends SourceBasedAnalysisTask {
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
-      'ReadyResolvedUnit10Task',
-      createTask,
-      buildInputs,
-      <ResultDescriptor>[READY_RESOLVED_UNIT10]);
-
-  ReadyResolvedUnit10Task(
-      InternalAnalysisContext context, AnalysisTarget target)
-      : super(context, target);
-
-  @override
-  TaskDescriptor get descriptor => DESCRIPTOR;
-
-  @override
-  bool get handlesDependencyCycles => true;
-
-  @override
-  void internalPerform() {
-    outputs[READY_RESOLVED_UNIT10] = true;
-  }
-
-  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
-    Source source = target;
-    return <String, TaskInput>{
-      'thisLibraryUnitsReady':
-          LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT10),
-      'directlyImportedLibrariesReady':
-          IMPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT10),
-      'directlyExportedLibrariesReady':
-          EXPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT10),
-    };
-  }
-
-  static ReadyResolvedUnit10Task createTask(
-      AnalysisContext context, AnalysisTarget target) {
-    return new ReadyResolvedUnit10Task(context, target);
-  }
-}
-
-/**
- * A task that ensures that [RESOLVED_UNIT11] is ready for every unit of the
- * target library source and its import/export closure.
- */
-class ReadyResolvedUnit11Task extends SourceBasedAnalysisTask {
-  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
-      'ReadyResolvedUnit11Task',
-      createTask,
-      buildInputs,
-      <ResultDescriptor>[READY_RESOLVED_UNIT11]);
-
-  ReadyResolvedUnit11Task(
-      InternalAnalysisContext context, AnalysisTarget target)
-      : super(context, target);
-
-  @override
-  TaskDescriptor get descriptor => DESCRIPTOR;
-
-  @override
-  bool get handlesDependencyCycles => true;
-
-  @override
-  void internalPerform() {
-    outputs[READY_RESOLVED_UNIT11] = true;
-  }
-
-  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
-    Source source = target;
-    return <String, TaskInput>{
-      'thisLibraryUnitsReady':
-          LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT11),
-      'directlyImportedLibrariesReady':
-          IMPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT11),
-      'directlyExportedLibrariesReady':
-          EXPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT11),
-    };
-  }
-
-  static ReadyResolvedUnit11Task createTask(
-      AnalysisContext context, AnalysisTarget target) {
-    return new ReadyResolvedUnit11Task(context, target);
-  }
-}
-
-/**
  * A task that ensures that [RESOLVED_UNIT] is ready for every unit of the
  * target library source and its import/export closure.
  */
@@ -4460,6 +4155,65 @@
 }
 
 /**
+ * A task that ensures that the expression AST for a constant is resolved and
+ * sets the [CONSTANT_EXPRESSION_RESOLVED] result.
+ */
+class ResolveConstantExpressionTask extends ConstantEvaluationAnalysisTask {
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'ResolveConstantExpressionTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[CONSTANT_EXPRESSION_RESOLVED]);
+
+  ResolveConstantExpressionTask(
+      InternalAnalysisContext context, ConstantEvaluationTarget constant)
+      : super(context, constant);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    //
+    // Record outputs.
+    //
+    outputs[CONSTANT_EXPRESSION_RESOLVED] = true;
+  }
+
+  /**
+   * Return a map from the names of the inputs of this kind of task to the task
+   * input descriptors describing those inputs for a task with the
+   * given [target].
+   */
+  static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+    Source librarySource;
+    if (target is Element) {
+      CompilationUnitElementImpl unit = target
+          .getAncestor((Element element) => element is CompilationUnitElement);
+      librarySource = unit.librarySource;
+    } else if (target is ElementAnnotationImpl) {
+      librarySource = target.librarySource;
+    } else {
+      throw new AnalysisException(
+          'Cannot build inputs for a ${target.runtimeType}');
+    }
+    return <String, TaskInput>{
+      'createdResolvedUnit': CREATED_RESOLVED_UNIT10
+          .of(new LibrarySpecificUnit(librarySource, target.source))
+    };
+  }
+
+  /**
+   * Create a [ResolveConstantExpressionTask] based on the given [target] in
+   * the given [context].
+   */
+  static ResolveConstantExpressionTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new ResolveConstantExpressionTask(context, target);
+  }
+}
+
+/**
  * A task that ensures that all of the inferable instance members in a
  * compilation unit have had their right hand sides re-resolved
  */
@@ -5087,7 +4841,8 @@
       'ScanDartTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM]);
+      <ResultDescriptor>[LINE_INFO, SCAN_ERRORS, TOKEN_STREAM],
+      suitabilityFor: suitabilityFor);
 
   /**
    * Initialize a newly created task to access the content of the source
@@ -5183,6 +4938,21 @@
       AnalysisContext context, AnalysisTarget target) {
     return new ScanDartTask(context, target);
   }
+
+  /**
+   * Return an indication of how suitable this task is for the given [target].
+   */
+  static TaskSuitability suitabilityFor(AnalysisTarget target) {
+    if (target is Source) {
+      if (target.shortName.endsWith(AnalysisEngine.SUFFIX_DART)) {
+        return TaskSuitability.HIGHEST;
+      }
+      return TaskSuitability.LOWEST;
+    } else if (target is DartScript) {
+      return TaskSuitability.HIGHEST;
+    }
+    return TaskSuitability.NONE;
+  }
 }
 
 /**
@@ -5225,9 +4995,11 @@
     //
     TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
     CompilationUnit unit = getRequiredInput(UNIT_INPUT);
-    if (context.analysisOptions.strongMode) {
+    AnalysisOptionsImpl options = context.analysisOptions;
+    if (options.strongMode) {
       unit.accept(new CodeChecker(
-          typeProvider, new StrongTypeSystemImpl(), errorListener));
+          typeProvider, new StrongTypeSystemImpl(), errorListener,
+          hints: options.strongModeHints));
     }
     //
     // Record outputs.
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index db9cd1d..a041729 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -154,7 +154,7 @@
   /**
    * Create a work order that will produce the given [result] for the given
    * [target]. Return the work order that was created, or `null` if the result
-   * has already been computed.
+   * has either already been computed or cannot be computed.
    */
   WorkOrder createWorkOrderForResult(
       AnalysisTarget target, ResultDescriptor result) {
@@ -166,6 +166,9 @@
       return null;
     }
     TaskDescriptor taskDescriptor = taskManager.findTask(target, result);
+    if (taskDescriptor == null) {
+      return null;
+    }
     try {
       WorkItem workItem =
           new WorkItem(context, target, taskDescriptor, result, 0, null);
@@ -709,11 +712,21 @@
           try {
             TaskDescriptor descriptor =
                 taskManager.findTask(inputTarget, inputResult);
+            if (descriptor == null) {
+              throw new AnalysisException(
+                  'Cannot find task to build $inputResult for $inputTarget');
+            }
             return new WorkItem(context, inputTarget, descriptor, inputResult,
                 level + 1, workOrder);
           } on AnalysisException catch (exception, stackTrace) {
             this.exception = new CaughtException(exception, stackTrace);
             return null;
+          } catch (exception, stackTrace) {
+            this.exception = new CaughtException(exception, stackTrace);
+            throw new AnalysisException(
+                'Cannot create work order to build $inputResult for $inputTarget',
+                this.exception);
+            return null;
           }
         }
       } else {
diff --git a/pkg/analyzer/lib/src/task/html.dart b/pkg/analyzer/lib/src/task/html.dart
index b6a771a..90e78bd 100644
--- a/pkg/analyzer/lib/src/task/html.dart
+++ b/pkg/analyzer/lib/src/task/html.dart
@@ -7,10 +7,10 @@
 import 'dart:collection';
 
 import 'package:analyzer/src/context/cache.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_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/plugin/engine_plugin.dart';
 import 'package:analyzer/src/task/general.dart';
@@ -279,7 +279,8 @@
       'ParseHtmlTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[HTML_DOCUMENT, HTML_DOCUMENT_ERRORS, LINE_INFO]);
+      <ResultDescriptor>[HTML_DOCUMENT, HTML_DOCUMENT_ERRORS, LINE_INFO],
+      suitabilityFor: suitabilityFor);
 
   /**
    * Initialize a newly created task to access the content of the source
@@ -358,6 +359,20 @@
   }
 
   /**
+   * Return an indication of how suitable this task is for the given [target].
+   */
+  static TaskSuitability suitabilityFor(AnalysisTarget target) {
+    if (target is Source) {
+      String name = target.shortName;
+      if (name.endsWith(AnalysisEngine.SUFFIX_HTML) ||
+          name.endsWith(AnalysisEngine.SUFFIX_HTM)) {
+        return TaskSuitability.HIGHEST;
+      }
+    }
+    return TaskSuitability.NONE;
+  }
+
+  /**
    * Compute [LineInfo] for the given [content].
    */
   static LineInfo _computeLineInfo(String content) {
diff --git a/pkg/analyzer/lib/src/task/incremental_element_builder.dart b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
index 07550c5..b3b3512 100644
--- a/pkg/analyzer/lib/src/task/incremental_element_builder.dart
+++ b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
@@ -6,12 +6,15 @@
 
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 
 /**
diff --git a/pkg/analyzer/lib/src/task/manager.dart b/pkg/analyzer/lib/src/task/manager.dart
index eebc084..c8252fa 100644
--- a/pkg/analyzer/lib/src/task/manager.dart
+++ b/pkg/analyzer/lib/src/task/manager.dart
@@ -83,7 +83,7 @@
       throw new AnalysisException(
           'No tasks registered to compute $result for $target');
     }
-    return _findBestTask(descriptors);
+    return _findBestTask(descriptors, target);
   }
 
   /**
@@ -104,11 +104,20 @@
 
   /**
    * Given a list of task [descriptors] that can be used to compute some
-   * unspecified result, return the descriptor that will compute the result with
-   * the least amount of work.
+   * unspecified result for the given [target], return the descriptor that
+   * should be used to compute the result.
    */
-  TaskDescriptor _findBestTask(List<TaskDescriptor> descriptors) {
-    // TODO(brianwilkerson) Improve this implementation.
-    return descriptors[0];
+  TaskDescriptor _findBestTask(
+      List<TaskDescriptor> descriptors, AnalysisTarget target) {
+    TaskDescriptor best = null;
+    for (TaskDescriptor descriptor in descriptors) {
+      TaskSuitability suitability = descriptor.suitabilityFor(target);
+      if (suitability == TaskSuitability.HIGHEST) {
+        return descriptor;
+      } else if (best == null && suitability == TaskSuitability.LOWEST) {
+        best = descriptor;
+      }
+    }
+    return best;
   }
 }
diff --git a/pkg/analyzer/lib/src/task/model.dart b/pkg/analyzer/lib/src/task/model.dart
index 8eaa838..56e2827 100644
--- a/pkg/analyzer/lib/src/task/model.dart
+++ b/pkg/analyzer/lib/src/task/model.dart
@@ -126,13 +126,23 @@
   final List<ResultDescriptor> results;
 
   /**
+   * The function used to determine whether the described task is suitable for
+   * a given target.
+   */
+  final SuitabilityFor _suitabilityFor;
+
+  /**
    * Initialize a newly created task descriptor to have the given [name] and to
-   * describe a task that takes the inputs built using the given [createTaskInputs],
-   * and produces the given [results]. The [buildTask] will be used to create
-   * the instance of [AnalysisTask] thusly described.
+   * describe a task that takes the inputs built using the given [inputBuilder],
+   * and produces the given [results]. The [buildTask] function will be used to
+   * create the instance of [AnalysisTask] being described. If provided, the
+   * [isAppropriateFor] function will be used to determine whether the task can
+   * be used on a specific target.
    */
   TaskDescriptorImpl(
-      this.name, this.buildTask, this.createTaskInputs, this.results);
+      this.name, this.buildTask, this.createTaskInputs, this.results,
+      {SuitabilityFor suitabilityFor})
+      : _suitabilityFor = suitabilityFor ?? _defaultSuitability;
 
   @override
   AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
@@ -143,5 +153,16 @@
   }
 
   @override
+  TaskSuitability suitabilityFor(AnalysisTarget target) =>
+      _suitabilityFor(target);
+
+  @override
   String toString() => name;
+
+  /**
+   * The function that will be used to determine the suitability of a task if no
+   * other function is provided.
+   */
+  static TaskSuitability _defaultSuitability(AnalysisTarget target) =>
+      TaskSuitability.LOWEST;
 }
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 6775408..e598910 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -30,6 +30,11 @@
 
 final _OptionsProcessor _processor = new _OptionsProcessor();
 
+void applyToAnalysisOptions(
+    AnalysisOptionsImpl options, Map<String, Object> optionMap) {
+  _processor.applyToAnalysisOptions(options, optionMap);
+}
+
 /// Configure this [context] based on configuration details specified in
 /// the given [options].  If [options] is `null`, default values are applied.
 void configureContextOptions(
@@ -42,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';
@@ -74,7 +81,8 @@
   static const List<String> languageOptions = const [
     enableAsync,
     enableGenericMethods,
-    enableSuperMixins
+    enableSuperMixins,
+    enableConditionalDirectives,
   ];
 }
 
@@ -202,7 +210,8 @@
       'GenerateOptionsErrorsTask',
       createTask,
       buildInputs,
-      <ResultDescriptor>[ANALYSIS_OPTIONS_ERRORS, LINE_INFO]);
+      <ResultDescriptor>[ANALYSIS_OPTIONS_ERRORS, LINE_INFO],
+      suitabilityFor: suitabilityFor);
 
   final AnalysisOptionsProvider optionsProvider = new AnalysisOptionsProvider();
 
@@ -257,6 +266,17 @@
   static GenerateOptionsErrorsTask createTask(
           AnalysisContext context, AnalysisTarget target) =>
       new GenerateOptionsErrorsTask(context, target);
+
+  /**
+   * Return an indication of how suitable this task is for the given [target].
+   */
+  static TaskSuitability suitabilityFor(AnalysisTarget target) {
+    if (target is Source &&
+        target.shortName == AnalysisEngine.ANALYSIS_OPTIONS_FILE) {
+      return TaskSuitability.HIGHEST;
+    }
+    return TaskSuitability.NONE;
+  }
 }
 
 /// Validates `analyzer` language configuration options.
@@ -400,6 +420,28 @@
 class _OptionsProcessor {
   static final Map<String, Object> defaults = {'analyzer': {}};
 
+  /**
+   * Apply the options in the given [optionMap] to the given analysis [options].
+   */
+  void applyToAnalysisOptions(
+      AnalysisOptionsImpl options, Map<String, Object> optionMap) {
+    if (optionMap == null) {
+      return;
+    }
+    var analyzer = optionMap[AnalyzerOptions.analyzer];
+    if (analyzer is! Map) {
+      return;
+    }
+    // Process strong mode option.
+    var strongMode = analyzer[AnalyzerOptions.strong_mode];
+    if (strongMode is bool) {
+      options.strongMode = strongMode;
+    }
+    // Process language options.
+    var language = analyzer[AnalyzerOptions.language];
+    _applyLanguageOptions(options, language);
+  }
+
   /// Configure [context] based on the given [options] (which can be `null`
   /// to restore [defaults]).
   void configure(AnalysisContext context, Map<String, Object> options) {
@@ -451,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) {
@@ -481,4 +531,34 @@
       context.analysisOptions = options;
     }
   }
+
+  void _applyLanguageOption(
+      AnalysisOptionsImpl options, Object feature, Object value) {
+    bool boolValue = toBool(value);
+    if (boolValue != null) {
+      if (feature == AnalyzerOptions.enableAsync) {
+        options.enableAsync = boolValue;
+      }
+      if (feature == AnalyzerOptions.enableSuperMixins) {
+        options.enableSuperMixins = boolValue;
+      }
+      if (feature == AnalyzerOptions.enableGenericMethods) {
+        options.enableGenericMethods = boolValue;
+      }
+    }
+  }
+
+  void _applyLanguageOptions(AnalysisOptionsImpl options, Object configs) {
+    if (configs is YamlMap) {
+      configs.nodes.forEach((key, value) {
+        if (key is YamlScalar && value is YamlScalar) {
+          String feature = key.value?.toString();
+          _applyLanguageOption(options, feature, value.value);
+        }
+      });
+    } else if (configs is Map) {
+      configs
+          .forEach((key, value) => _applyLanguageOption(options, key, value));
+    }
+  }
 }
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 29857b0..8f0c9de 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -7,12 +7,14 @@
 library analyzer.src.task.strong.checker;
 
 import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
+import 'package:analyzer/dart/ast/visitor.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/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
-import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType;
 import 'package:analyzer/src/generated/type_system.dart';
 
 import 'info.dart';
@@ -129,14 +131,9 @@
       Expression arg = list[i];
       ParameterElement element = arg.staticParameterElement;
       if (element == null) {
-        if (type.parameters.length < len) {
-          // We found an argument mismatch, the analyzer will report this too,
-          // so no need to insert an error for this here.
-          continue;
-        }
-        element = type.parameters[i];
-        // TODO(vsm): When can this happen?
-        assert(element != null);
+        // We found an argument mismatch, the analyzer will report this too,
+        // so no need to insert an error for this here.
+        continue;
       }
       DartType expectedType = _elementType(element);
       if (expectedType == null) expectedType = DynamicTypeImpl.instance;
@@ -569,19 +566,11 @@
   }
 
   StaticInfo _checkAssignment(Expression expr, DartType toT) {
-    final fromT = expr.staticType ?? DynamicTypeImpl.instance;
+    final fromT = _getStaticType(expr);
     final Coercion c = _coerceTo(fromT, toT);
     if (c is Identity) return null;
     if (c is CoercionError) return new StaticTypeError(rules, expr, toT);
-    var reason = null;
-
-    var errors = <String>[];
-
-    var ok = _inferExpression(expr, toT, errors);
-    if (ok) return InferredType.create(rules, expr, toT);
-    reason = (errors.isNotEmpty) ? errors.first : null;
-
-    if (c is Cast) return DownCast.create(rules, expr, c, reason: reason);
+    if (c is Cast) return DownCast.create(rules, expr, c);
     assert(false);
     return null;
   }
@@ -782,7 +771,63 @@
   }
 
   DartType _getStaticType(Expression expr) {
-    return expr.staticType ?? DynamicTypeImpl.instance;
+    DartType t = expr.staticType ?? DynamicTypeImpl.instance;
+
+    // Remove fuzzy arrow if possible.
+    if (t is FunctionType && StaticInfo.isKnownFunction(expr)) {
+      t = _removeFuzz(t);
+    }
+
+    return t;
+  }
+
+  /// Remove "fuzzy arrow" in this function type.
+  ///
+  /// Normally we treat dynamically typed parameters as bottom for function
+  /// types. This allows type tests such as `if (f is SingleArgFunction)`.
+  /// It also requires a dynamic check on the parameter type to call these
+  /// functions.
+  ///
+  /// When we convert to a strict arrow, dynamically typed parameters become
+  /// top. This is safe to do for known functions, like top-level or local
+  /// functions and static methods. Those functions must already be essentially
+  /// treating dynamic as top.
+  ///
+  /// Only the outer-most arrow can be strict. Any others must be fuzzy, because
+  /// we don't know what function value will be passed there.
+  // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function
+  // type? That would allow us to implement this in the subtype relation.
+  // TODO(jmesserly): we'll need to factor this differently if we want to
+  // move CodeChecker's functionality into existing analyzer. Likely we can
+  // let the Expression have a strict arrow, then in places were we do
+  // inference, convert back to a fuzzy arrow.
+  FunctionType _removeFuzz(FunctionType t) {
+    bool foundFuzz = false;
+    List<ParameterElement> parameters = <ParameterElement>[];
+    for (ParameterElement p in t.parameters) {
+      ParameterElement newP = _removeParameterFuzz(p);
+      parameters.add(newP);
+      if (p != newP) foundFuzz = true;
+    }
+    if (!foundFuzz) {
+      return t;
+    }
+
+    FunctionElementImpl function = new FunctionElementImpl("", -1);
+    function.synthetic = true;
+    function.returnType = t.returnType;
+    function.shareTypeParameters(t.typeFormals);
+    function.shareParameters(parameters);
+    return function.type = new FunctionTypeImpl(function);
+  }
+
+  /// Removes fuzzy arrow, see [_removeFuzz].
+  ParameterElement _removeParameterFuzz(ParameterElement p) {
+    if (p.type.isDynamic) {
+      return new ParameterElementImpl.synthetic(
+          p.name, typeProvider.objectType, p.parameterKind);
+    }
+    return p;
   }
 
   /// Given an expression, return its type assuming it is
@@ -804,17 +849,6 @@
     return null;
   }
 
-  /// Checks if we can perform downwards inference on [e] tp get type [t].
-  /// If it is not possible, this will add a message to [errors].
-  bool _inferExpression(Expression e, DartType t, List<String> errors) {
-    DartType staticType = e.staticType ?? DynamicTypeImpl.instance;
-    if (rules.isSubtypeOf(staticType, t)) {
-      return true;
-    }
-    errors.add("$e cannot be typed as $t");
-    return false;
-  }
-
   /// Returns `true` if the expression is a dynamic function call or method
   /// invocation.
   bool _isDynamicCall(Expression call) {
diff --git a/pkg/analyzer/lib/src/task/strong/info.dart b/pkg/analyzer/lib/src/task/strong/info.dart
index cf4f822..6169815 100644
--- a/pkg/analyzer/lib/src/task/strong/info.dart
+++ b/pkg/analyzer/lib/src/task/strong/info.dart
@@ -8,10 +8,10 @@
 // refactored to fit into analyzer.
 library analyzer.src.task.strong.info;
 
+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/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/type_system.dart';
 
@@ -95,18 +95,19 @@
             baseType.isAssignableTo(_cast.toType)));
   }
 
-  @override List<Object> get arguments => [node, baseType, convertedType];
+  @override
+  List<Object> get arguments => [baseType, convertedType];
 
   Cast get cast => _cast;
 
   DartType get convertedType => _cast.toType;
-  @override String get message => '{0} ({1}) will need runtime check '
-      'to cast to type {2}';
+
+  @override
+  String get message => 'Unsound implicit cast from {0} to {1}';
 
   // Factory to create correct DownCast variant.
   static StaticInfo create(
-      StrongTypeSystemImpl rules, Expression expression, Cast cast,
-      {String reason}) {
+      StrongTypeSystemImpl rules, Expression expression, Cast cast) {
     final fromT = cast.fromType;
     final toT = cast.toType;
 
@@ -122,20 +123,23 @@
     }
 
     // Inference "casts":
-    if (expression is Literal) {
+    if (expression is Literal || expression is FunctionExpression) {
       // fromT should be an exact type - this will almost certainly fail at
       // runtime.
-      return new StaticTypeError(rules, expression, toT, reason: reason);
+      return new StaticTypeError(rules, expression, toT);
     }
-    if (expression is FunctionExpression) {
-      // fromT should be an exact type - this will almost certainly fail at
-      // runtime.
-      return new UninferredClosure(rules, expression, cast);
-    }
+
     if (expression is InstanceCreationExpression) {
-      // fromT should be an exact type - this will almost certainly fail at
-      // runtime.
-      return new StaticTypeError(rules, expression, toT, reason: reason);
+      ConstructorElement e = expression.staticElement;
+      if (e == null || !e.isFactory) {
+        // fromT should be an exact type - this will almost certainly fail at
+        // runtime.
+        return new StaticTypeError(rules, expression, toT);
+      }
+    }
+
+    if (StaticInfo.isKnownFunction(expression)) {
+      return new StaticTypeError(rules, expression, toT);
     }
 
     // TODO(vsm): Change this to an assert when we have generic methods and
@@ -292,9 +296,11 @@
       TypeSystem rules, Expression expression, this._type)
       : super(rules, expression);
 
-  @override List get arguments => [node, type];
+  @override
+  List get arguments => [node, type];
   DartType get convertedType => type;
-  @override String get message => '{0} has inferred type {1}';
+  @override
+  String get message => '{0} has inferred type {1}';
   DartType get type => _type;
 
   toErrorCode() => new HintCode(name, message);
@@ -370,7 +376,8 @@
         fromMixin = node.parent is WithClause,
         super(node);
 
-  @override List<Object> get arguments =>
+  @override
+  List<Object> get arguments =>
       [parent.name, element.name, subType, base, baseType];
 
   ClassElement get parent => element.enclosingElement;
@@ -392,8 +399,10 @@
       TypeSystem rules, FormalParameter declaration, this.expectedType)
       : super(declaration);
 
-  @override List<Object> get arguments => [node, expectedType];
-  @override String get message => 'Type check failed: {0} is not of type {1}';
+  @override
+  List<Object> get arguments => [node, expectedType];
+  @override
+  String get message => 'Type check failed: {0} is not of type {1}';
   @override
   String get name => 'STRONG_MODE_INVALID_PARAMETER_DECLARATION';
 }
@@ -424,14 +433,15 @@
 /// could be if initializers have side effects.
 ///
 /// Better to have `super` at the end, as required by the Dart style guide:
-/// <http://goo.gl/q1T4BB>
+/// <https://goo.gl/EY6hDP>
 ///
 /// For now this is the only pattern we support.
 class InvalidSuperInvocation extends StaticError {
   InvalidSuperInvocation(SuperConstructorInvocation node) : super(node);
 
-  @override String get message => "super call must be last in an initializer "
-      "list (see http://goo.gl/q1T4BB): {0}";
+  @override
+  String get message => "super call must be last in an initializer "
+      "list (see https://goo.gl/EY6hDP): {0}";
 
   @override
   String get name => 'STRONG_MODE_INVALID_SUPER_INVOCATION';
@@ -444,8 +454,10 @@
       TypeSystem rules, AstNode declaration, this.expectedType)
       : super(declaration);
 
-  @override List<Object> get arguments => [expectedType];
-  @override String get message => 'Type check failed: null is not of type {0}';
+  @override
+  List<Object> get arguments => [expectedType];
+  @override
+  String get message => 'Type check failed: null is not of type {0}';
 
   @override
   String get name => 'STRONG_MODE_INVALID_VARIABLE_DECLARATION';
@@ -459,7 +471,8 @@
     assert(node is IsExpression || node is AsExpression);
   }
 
-  @override List<Object> get arguments => [type];
+  @override
+  List<Object> get arguments => [type];
   String get message =>
       "Runtime check on non-ground type {0} may throw StrongModeError";
 
@@ -529,43 +542,34 @@
   // TODO(jmesserly): review the usage of error codes. We probably want our own,
   // as well as some DDC specific [ErrorType]s.
   ErrorCode toErrorCode();
+
+  static bool isKnownFunction(Expression expression) {
+    Element element = null;
+    if (expression is PropertyAccess) {
+      element = expression.propertyName.staticElement;
+    } else if (expression is Identifier) {
+      element = expression.staticElement;
+    }
+    // First class functions and static methods, where we know the original
+    // declaration, will have an exact type, so we know a downcast will fail.
+    return element is FunctionElement ||
+        element is MethodElement && element.isStatic;
+  }
 }
 
 class StaticTypeError extends StaticError {
   final DartType baseType;
   final DartType expectedType;
-  String reason = null;
 
-  StaticTypeError(TypeSystem rules, Expression expression, this.expectedType,
-      {this.reason})
+  StaticTypeError(TypeSystem rules, Expression expression, this.expectedType)
       : baseType = expression.staticType ?? DynamicTypeImpl.instance,
         super(expression);
 
-  @override List<Object> get arguments => [node, baseType, expectedType];
-  @override String get message =>
-      'Type check failed: {0} ({1}) is not of type {2}' +
-      ((reason == null) ? '' : ' because $reason');
+  @override
+  List<Object> get arguments => [node, baseType, expectedType];
+  @override
+  String get message => 'Type check failed: {0} ({1}) is not of type {2}';
 
   @override
   String get name => 'STRONG_MODE_STATIC_TYPE_ERROR';
 }
-
-//
-// Temporary "casts" of allocation sites - literals, constructor invocations,
-// and closures.  These should be handled by contextual inference.  In most
-// cases, inference will be sufficient, though in some it may unmask an actual
-// error: e.g.,
-//   List<int> l = [1, 2, 3]; // Inference succeeds
-//   List<String> l = [1, 2, 3]; // Inference reveals static type error
-// We're marking all as warnings for now.
-//
-// TODO(vsm,leafp): Remove this.
-class UninferredClosure extends DownCast {
-  UninferredClosure(TypeSystem rules, FunctionExpression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  @override
-  String get name => 'STRONG_MODE_UNINFERRED_CLOSURE';
-
-  toErrorCode() => new StaticTypeWarningCode(name, message);
-}
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index 46b84e0..b106dee 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -6,67 +6,31 @@
 
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.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/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/resolver.dart'
     show TypeProvider, InheritanceManager;
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:analyzer/src/dart/element/type.dart';
 
 /**
- * Set the type of the sole parameter of the given [element] to the given [type].
+ * Sets the type of the field. This is stored in the field itself, and the
+ * synthetic getter/setter types.
  */
-void setParameterType(PropertyAccessorElement element, DartType type) {
-  if (element is PropertyAccessorElementImpl) {
-    ParameterElement parameter = _getParameter(element);
-    if (parameter is ParameterElementImpl) {
-      //
-      // Update the type of the parameter.
-      //
-      parameter.type = type;
-      //
-      // Update the type of the setter to reflect the new parameter type.
-      //
-      // TODO(jmesserly): why is this necessary? The function type should always
-      // delegate to the orginal element.
-      FunctionType functionType = element.type;
-      if (functionType is FunctionTypeImpl) {
-        element.type = new FunctionTypeImpl(element);
-      } else {
-        assert(false);
-      }
-    } else {
-      assert(false);
-    }
-  } else {
-    throw new StateError('element is an instance of ${element.runtimeType}');
-    assert(false);
+void setFieldType(VariableElement field, DartType newType) {
+  (field as VariableElementImpl).type = newType;
+  if (field.initializer != null) {
+    (field.initializer as ExecutableElementImpl).returnType = newType;
   }
-}
-
-/**
- * Set the return type of the given [element] to the given [type].
- */
-void setReturnType(ExecutableElement element, DartType type) {
-  if (element is ExecutableElementImpl) {
-    //
-    // Update the return type of the element, which is stored in two places:
-    // directly in the element and indirectly in the type of the element.
-    //
-    // TODO(jmesserly): why is this necessary? The function type should always
-    // delegate to the orginal element.
-    element.returnType = type;
-    FunctionType functionType = element.type;
-    if (functionType is FunctionTypeImpl) {
-      element.type = new FunctionTypeImpl(element);
-    } else {
-      assert(false);
+  if (field is PropertyInducingElementImpl) {
+    (field.getter as ExecutableElementImpl).returnType = newType;
+    if (!field.isFinal && !field.isConst) {
+      (field.setter.parameters[0] as ParameterElementImpl).type = newType;
     }
-  } else {
-    assert(false);
   }
 }
 
@@ -158,49 +122,42 @@
    * the parameter types.
    */
   DartType _computeParameterType(ParameterElement parameter, int index,
-      List<ExecutableElement> overriddenMethods) {
+      List<FunctionType> overriddenTypes) {
     DartType parameterType = null;
-    int length = overriddenMethods.length;
+    int length = overriddenTypes.length;
     for (int i = 0; i < length; i++) {
       DartType type = _getTypeOfCorrespondingParameter(
-          parameter, index, overriddenMethods[i]);
+          parameter, index, overriddenTypes[i].parameters);
       if (parameterType == null) {
         parameterType = type;
       } else if (parameterType != type) {
         return typeProvider.dynamicType;
       }
     }
-    return parameterType == null ? typeProvider.dynamicType : parameterType;
+    return parameterType ?? typeProvider.dynamicType;
   }
 
   /**
    * Compute the best return type for a method that must be compatible with the
-   * return types of each of the given [overriddenMethods].
+   * return types of each of the given [overriddenReturnTypes].
    *
    * At the moment, this method will only return a type other than 'dynamic' if
    * the return types of all of the methods are the same. In the future we might
    * want to be smarter about it.
    */
-  DartType _computeReturnType(List<ExecutableElement> overriddenMethods) {
+  DartType _computeReturnType(Iterable<DartType> overriddenReturnTypes) {
     DartType returnType = null;
-    int length = overriddenMethods.length;
-    for (int i = 0; i < length; i++) {
-      DartType type = _getReturnType(overriddenMethods[i]);
+    for (DartType type in overriddenReturnTypes) {
+      if (type == null) {
+        type = typeProvider.dynamicType;
+      }
       if (returnType == null) {
         returnType = type;
       } else if (returnType != type) {
         return typeProvider.dynamicType;
       }
     }
-    return returnType == null ? typeProvider.dynamicType : returnType;
-  }
-
-  DartType _getReturnType(ExecutableElement element) {
-    DartType returnType = element.returnType;
-    if (returnType == null) {
-      return typeProvider.dynamicType;
-    }
-    return returnType;
+    return returnType ?? typeProvider.dynamicType;
   }
 
   /**
@@ -209,12 +166,11 @@
    * it appears at the given [index] in its enclosing element's list of
    * parameters.
    */
-  DartType _getTypeOfCorrespondingParameter(
-      ParameterElement parameter, int index, ExecutableElement method) {
+  DartType _getTypeOfCorrespondingParameter(ParameterElement parameter,
+      int index, List<ParameterElement> methodParameters) {
     //
     // Find the corresponding parameter.
     //
-    List<ParameterElement> methodParameters = method.parameters;
     ParameterElement matchingParameter = null;
     if (parameter.parameterKind == ParameterKind.NAMED) {
       //
@@ -306,18 +262,41 @@
     if (element.isSynthetic || element.isStatic) {
       return;
     }
-    List<ExecutableElement> overriddenMethods = null;
+    List<ExecutableElement> overriddenMethods = inheritanceManager
+        .lookupOverrides(element.enclosingElement, element.name);
+    if (overriddenMethods.isEmpty ||
+        !_allSameElementKind(element, overriddenMethods)) {
+      return;
+    }
+
+    //
+    // Overridden methods must have the same number of generic type parameters
+    // as this method, or none.
+    //
+    // If we do have generic type parameters on the element we're inferring,
+    // we must express its parameter and return types in terms of its own
+    // parameters. For example, given `m<T>(t)` overriding `m<S>(S s)` we
+    // should infer this as `m<T>(T t)`.
+    //
+    List<DartType> typeFormals =
+        TypeParameterTypeImpl.getTypes(element.type.typeFormals);
+
+    List<FunctionType> overriddenTypes = new List<FunctionType>();
+    for (ExecutableElement overriddenMethod in overriddenMethods) {
+      FunctionType overriddenType = overriddenMethod.type;
+      if (overriddenType.typeFormals.isNotEmpty &&
+          overriddenType.typeFormals.length != typeFormals.length) {
+        return;
+      }
+      overriddenTypes.add(overriddenType.instantiate(typeFormals));
+    }
+
     //
     // Infer the return type.
     //
     if (element.hasImplicitReturnType) {
-      overriddenMethods = inheritanceManager.lookupOverrides(
-          element.enclosingElement, element.name);
-      if (overriddenMethods.isEmpty ||
-          !_allSameElementKind(element, overriddenMethods)) {
-        return;
-      }
-      setReturnType(element, _computeReturnType(overriddenMethods));
+      (element as ExecutableElementImpl).returnType =
+          _computeReturnType(overriddenTypes.map((t) => t.returnType));
       if (element is PropertyAccessorElement) {
         _updateSyntheticVariableType(element);
       }
@@ -330,15 +309,7 @@
     for (int i = 0; i < length; ++i) {
       ParameterElement parameter = parameters[i];
       if (parameter is ParameterElementImpl && parameter.hasImplicitType) {
-        if (overriddenMethods == null) {
-          overriddenMethods = inheritanceManager.lookupOverrides(
-              element.enclosingElement, element.name);
-        }
-        if (overriddenMethods.isEmpty ||
-            !_allSameElementKind(element, overriddenMethods)) {
-          return;
-        }
-        parameter.type = _computeParameterType(parameter, i, overriddenMethods);
+        parameter.type = _computeParameterType(parameter, i, overriddenTypes);
         if (element is PropertyAccessorElement) {
           _updateSyntheticVariableType(element);
         }
@@ -361,7 +332,8 @@
           .lookupOverrides(fieldElement.enclosingElement, fieldElement.name);
       DartType newType = null;
       if (overriddenGetters.isNotEmpty && _onlyGetters(overriddenGetters)) {
-        newType = _computeReturnType(overriddenGetters);
+        newType =
+            _computeReturnType(overriddenGetters.map((e) => e.returnType));
         List<ExecutableElement> overriddenSetters =
             inheritanceManager.lookupOverrides(
                 fieldElement.enclosingElement, fieldElement.name + '=');
@@ -387,11 +359,7 @@
       if (newType == null || newType.isBottom) {
         newType = typeProvider.dynamicType;
       }
-      (fieldElement as FieldElementImpl).type = newType;
-      setReturnType(fieldElement.getter, newType);
-      if (!fieldElement.isFinal && !fieldElement.isConst) {
-        setParameterType(fieldElement.setter, newType);
-      }
+      setFieldType(fieldElement, newType);
     }
   }
 
diff --git a/pkg/analyzer/lib/src/task/yaml.dart b/pkg/analyzer/lib/src/task/yaml.dart
new file mode 100644
index 0000000..1e1951c
--- /dev/null
+++ b/pkg/analyzer/lib/src/task/yaml.dart
@@ -0,0 +1,155 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.src.task.yaml;
+
+import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/general.dart';
+import 'package:analyzer/task/general.dart';
+import 'package:analyzer/task/model.dart';
+import 'package:analyzer/task/yaml.dart';
+import 'package:source_span/source_span.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * A task that scans the content of a YAML file, producing a YAML document.
+ */
+class ParseYamlTask extends SourceBasedAnalysisTask {
+  /**
+   * The name of the input whose value is the content of the file.
+   */
+  static const String CONTENT_INPUT_NAME = 'CONTENT_INPUT_NAME';
+
+  /**
+   * The task descriptor describing this kind of task.
+   */
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'ParseYamlTask',
+      createTask,
+      buildInputs,
+      <ResultDescriptor>[YAML_DOCUMENT, YAML_ERRORS, LINE_INFO],
+      suitabilityFor: suitabilityFor);
+
+  /**
+   * Initialize a newly created task to access the content of the source
+   * associated with the given [target] in the given [context].
+   */
+  ParseYamlTask(InternalAnalysisContext context, AnalysisTarget target)
+      : super(context, target);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    Source source = target.source;
+    String uri = source.uri.toString();
+    String content = getRequiredInput(CONTENT_INPUT_NAME);
+
+    if (context.getModificationStamp(source) < 0) {
+      String message = 'Content could not be read';
+      if (context is InternalAnalysisContext) {
+        CacheEntry entry =
+            (context as InternalAnalysisContext).getCacheEntry(target);
+        CaughtException exception = entry.exception;
+        if (exception != null) {
+          message = exception.toString();
+        }
+      }
+      //
+      // Record outputs.
+      //
+      outputs[YAML_DOCUMENT] = loadYamlDocument('', sourceUrl: uri);
+      outputs[YAML_ERRORS] = <AnalysisError>[
+        new AnalysisError(
+            source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message])
+      ];
+      outputs[LINE_INFO] = new LineInfo(<int>[0]);
+    } else {
+      YamlDocument document;
+      List<AnalysisError> errors = <AnalysisError>[];
+      try {
+        document = loadYamlDocument(content, sourceUrl: uri);
+      } on YamlException catch (exception) {
+        SourceSpan span = exception.span;
+        int offset = span.start.offset;
+        int length = span.end.offset - offset;
+        errors.add(new AnalysisError(source, offset, length,
+            YamlErrorCode.PARSE_ERROR, [exception.message]));
+      } catch (exception, stackTrace) {
+        throw new AnalysisException('Error while parsing ${source.fullName}',
+            new CaughtException(exception, stackTrace));
+      }
+      //
+      // Record outputs.
+      //
+      outputs[YAML_DOCUMENT] = document;
+      outputs[YAML_ERRORS] = errors;
+      outputs[LINE_INFO] = new LineInfo.fromContent(content);
+    }
+  }
+
+  /**
+   * Return a map from the names of the inputs of this kind of task to the task
+   * input descriptors describing those inputs for a task with the given
+   * [source].
+   */
+  static Map<String, TaskInput> buildInputs(Source source) {
+    return <String, TaskInput>{CONTENT_INPUT_NAME: CONTENT.of(source)};
+  }
+
+  /**
+   * Create a [ParseYamlTask] based on the given [target] in the given [context].
+   */
+  static ParseYamlTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new ParseYamlTask(context, target);
+  }
+
+  /**
+   * Return an indication of how suitable this task is for the given [target].
+   */
+  static TaskSuitability suitabilityFor(AnalysisTarget target) {
+    if (target is Source && target.shortName.endsWith('.yaml')) {
+      return TaskSuitability.HIGHEST;
+    }
+    return TaskSuitability.NONE;
+  }
+}
+
+/**
+ * The error codes used for errors in YAML files.
+ */
+class YamlErrorCode extends ErrorCode {
+  // TODO(brianwilkerson) Move this class to error.dart.
+
+  /**
+   * An error code indicating that there is a syntactic error in the file.
+   *
+   * Parameters:
+   * 0: the error message from the parse error
+   */
+  static const YamlErrorCode PARSE_ERROR =
+      const YamlErrorCode('PARSE_ERROR', '{0}');
+
+  /**
+   * Initialize a newly created error code to have the given [name]. The message
+   * associated with the error will be created from the given [message]
+   * template. The correction associated with the error will be created from the
+   * given [correction] template.
+   */
+  const YamlErrorCode(String name, String message, [String correction])
+      : super(name, message, correction);
+
+  @override
+  ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
+
+  @override
+  ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
+}
diff --git a/pkg/analyzer/lib/task/dart.dart b/pkg/analyzer/lib/task/dart.dart
index 27258c3..3dbea46 100644
--- a/pkg/analyzer/lib/task/dart.dart
+++ b/pkg/analyzer/lib/task/dart.dart
@@ -4,10 +4,10 @@
 
 library analyzer.task.dart;
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 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/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_general.dart';
 import 'package:analyzer/src/task/dart.dart';
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index c320659..8144f17 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -36,6 +36,14 @@
 typedef Map<String, TaskInput> CreateTaskInputs(AnalysisTarget target);
 
 /**
+ * A function that takes the target for which a task will produce results and
+ * returns an indication of how suitable the task is for the target. Such
+ * functions are passed to a [TaskDescriptor] to be used to determine their
+ * suitability for computing results.
+ */
+typedef TaskSuitability SuitabilityFor(AnalysisTarget target);
+
+/**
  * A function that converts an object of the type [B] into a [TaskInput].
  * This is used, for example, by a [ListTaskInput] to create task inputs
  * for each value in a list of values.
@@ -163,6 +171,17 @@
   bool get handlesDependencyCycles => false;
 
   /**
+   * Return the value of the input with the given [name], or `null` if the input
+   * value is not defined.
+   */
+  Object getOptionalInput(String name) {
+    if (inputs == null || !inputs.containsKey(name)) {
+      return null;
+    }
+    return inputs[name];
+  }
+
+  /**
    * Return the value of the input with the given [name]. Throw an exception if
    * the input value is not defined.
    */
@@ -355,37 +374,36 @@
    * Return a task input that can be used to compute a flatten list whose
    * elements are combined [subListResult]'s associated with those elements.
    */
-  ListTaskInput /*<V>*/ toFlattenListOf /*<V>*/ (
-      ListResultDescriptor /*<V>*/ subListResult);
+  ListTaskInput/*<V>*/ toFlattenListOf/*<V>*/(
+      ListResultDescriptor/*<V>*/ subListResult);
 
   /**
    * Return a task input that can be used to compute a list whose elements are
    * the result of passing the elements of this input to the [mapper] function.
    */
-  ListTaskInput /*<V>*/ toList /*<V>*/ (
-      UnaryFunction<E, dynamic /*<=V>*/ > mapper);
+  ListTaskInput/*<V>*/ toList/*<V>*/(UnaryFunction<E, dynamic/*<=V>*/ > mapper);
 
   /**
    * Return a task input that can be used to compute a list whose elements are
    * [valueResult]'s associated with those elements.
    */
-  ListTaskInput /*<V>*/ toListOf /*<V>*/ (ResultDescriptor /*<V>*/ valueResult);
+  ListTaskInput/*<V>*/ toListOf/*<V>*/(ResultDescriptor/*<V>*/ valueResult);
 
   /**
    * Return a task input that can be used to compute a map whose keys are the
    * elements of this input and whose values are the result of passing the
    * corresponding key to the [mapper] function.
    */
-  MapTaskInput<E, dynamic /*=V*/ > toMap /*<V>*/ (
-      UnaryFunction<E, dynamic /*=V*/ > mapper);
+  MapTaskInput<E, dynamic/*=V*/ > toMap/*<V>*/(
+      UnaryFunction<E, dynamic/*=V*/ > mapper);
 
   /**
    * Return a task input that can be used to compute a map whose keys are the
    * elements of this input and whose values are the [valueResult]'s associated
    * with those elements.
    */
-  MapTaskInput<AnalysisTarget, dynamic /*=V*/ > toMapOf /*<V>*/ (
-      ResultDescriptor /*<V>*/ valueResult);
+  MapTaskInput<AnalysisTarget, dynamic/*=V*/ > toMapOf/*<V>*/(
+      ResultDescriptor/*<V>*/ valueResult);
 }
 
 /**
@@ -400,8 +418,8 @@
    * the result of passing keys [K] and the corresponding elements of [V] to
    * the [mapper] function.
    */
-  TaskInput<List /*<E>*/ > toFlattenList /*<E>*/ (
-      BinaryFunction<K, dynamic /*element of V*/, dynamic /*=E*/ > mapper);
+  TaskInput<List/*<E>*/ > toFlattenList/*<E>*/(
+      BinaryFunction<K, dynamic /*element of V*/, dynamic/*=E*/ > mapper);
 }
 
 /**
@@ -523,14 +541,14 @@
   /**
    * Initialize a newly created task descriptor to have the given [name] and to
    * describe a task that takes the inputs built using the given [inputBuilder],
-   * and produces the given [results]. The [buildTask] will be used to create
-   * the instance of [AnalysisTask] thusly described.
+   * and produces the given [results]. The [buildTask] function will be used to
+   * create the instance of [AnalysisTask] being described. If provided, the
+   * [isAppropriateFor] function will be used to determine whether the task can
+   * be used on a specific target.
    */
-  factory TaskDescriptor(
-      String name,
-      BuildTask buildTask,
-      CreateTaskInputs inputBuilder,
-      List<ResultDescriptor> results) = TaskDescriptorImpl;
+  factory TaskDescriptor(String name, BuildTask buildTask,
+      CreateTaskInputs inputBuilder, List<ResultDescriptor> results,
+      {SuitabilityFor suitabilityFor}) = TaskDescriptorImpl;
 
   /**
    * Return the builder used to build the inputs to the task.
@@ -553,6 +571,11 @@
    */
   AnalysisTask createTask(AnalysisContext context, AnalysisTarget target,
       Map<String, dynamic> inputs);
+
+  /**
+   * Return an indication of how suitable this task is for the given [target].
+   */
+  TaskSuitability suitabilityFor(AnalysisTarget target);
 }
 
 /**
@@ -571,7 +594,7 @@
    * Return a task input that can be used to compute a list whose elements are
    * the result of passing the result of this input to the [mapper] function.
    */
-  ListTaskInput /*<E>*/ mappedToList /*<E>*/ (List /*<E>*/ mapper(V value));
+  ListTaskInput/*<E>*/ mappedToList/*<E>*/(List/*<E>*/ mapper(V value));
 }
 
 /**
@@ -651,6 +674,11 @@
 }
 
 /**
+ * An indication of how suitable a task is for a given target.
+ */
+enum TaskSuitability { NONE, LOWEST, HIGHEST }
+
+/**
  * [WorkManager]s are used to drive analysis.
  *
  * They know specific of the targets and results they care about,
diff --git a/pkg/analyzer/lib/task/yaml.dart b/pkg/analyzer/lib/task/yaml.dart
new file mode 100644
index 0000000..1795d8f
--- /dev/null
+++ b/pkg/analyzer/lib/task/yaml.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.task.yaml;
+
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/task/model.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * The result of parsing a YAML file.
+ */
+final ResultDescriptor<YamlDocument> YAML_DOCUMENT =
+    new ResultDescriptor<YamlDocument>('YAML_DOCUMENT', null);
+
+/**
+ * The analysis errors associated with a [Source] representing a YAML file.
+ */
+final ListResultDescriptor<AnalysisError> YAML_ERRORS =
+    new ListResultDescriptor<AnalysisError>(
+        'YAML_ERRORS', AnalysisError.NO_ERRORS);
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 607b92c..fb6756b 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.27.1+2
+version: 0.27.3-alpha.0
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
@@ -7,6 +7,7 @@
   sdk: '>=1.12.0 <2.0.0'
 dependencies:
   args: '>=0.12.1 <0.14.0'
+  crypto: ^0.9.0
   glob: ^1.0.3
   html: ^0.12.0
   package_config: ^0.1.1
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
new file mode 100644
index 0000000..7be2b72
--- /dev/null
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -0,0 +1,1308 @@
+// 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 analyzer.test.dart.ast.ast_test;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
+import 'package:analyzer/src/generated/testing/token_factory.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../generated/parser_test.dart' show ParserTestCase;
+import '../../generated/test_support.dart';
+import '../../reflective_tests.dart';
+import '../../utils.dart';
+
+main() {
+  initializeTestEnvironment();
+  runReflectiveTests(ClassDeclarationTest);
+  runReflectiveTests(ClassTypeAliasTest);
+  runReflectiveTests(ConstructorDeclarationTest);
+  runReflectiveTests(FieldFormalParameterTest);
+  runReflectiveTests(IndexExpressionTest);
+  runReflectiveTests(NodeListTest);
+  runReflectiveTests(SimpleIdentifierTest);
+  runReflectiveTests(SimpleStringLiteralTest);
+  runReflectiveTests(StringInterpolationTest);
+  runReflectiveTests(VariableDeclarationTest);
+}
+
+@reflectiveTest
+class ClassDeclarationTest extends ParserTestCase {
+  void test_getConstructor() {
+    List<ConstructorInitializer> initializers =
+        new List<ConstructorInitializer>();
+    ConstructorDeclaration defaultConstructor =
+        AstFactory.constructorDeclaration(AstFactory.identifier3("Test"), null,
+            AstFactory.formalParameterList(), initializers);
+    ConstructorDeclaration aConstructor = AstFactory.constructorDeclaration(
+        AstFactory.identifier3("Test"),
+        "a",
+        AstFactory.formalParameterList(),
+        initializers);
+    ConstructorDeclaration bConstructor = AstFactory.constructorDeclaration(
+        AstFactory.identifier3("Test"),
+        "b",
+        AstFactory.formalParameterList(),
+        initializers);
+    ClassDeclaration clazz = AstFactory.classDeclaration(null, "Test", null,
+        null, null, null, [defaultConstructor, aConstructor, bConstructor]);
+    expect(clazz.getConstructor(null), same(defaultConstructor));
+    expect(clazz.getConstructor("a"), same(aConstructor));
+    expect(clazz.getConstructor("b"), same(bConstructor));
+    expect(clazz.getConstructor("noSuchConstructor"), same(null));
+  }
+
+  void test_getField() {
+    VariableDeclaration aVar = AstFactory.variableDeclaration("a");
+    VariableDeclaration bVar = AstFactory.variableDeclaration("b");
+    VariableDeclaration cVar = AstFactory.variableDeclaration("c");
+    ClassDeclaration clazz =
+        AstFactory.classDeclaration(null, "Test", null, null, null, null, [
+      AstFactory.fieldDeclaration2(false, null, [aVar]),
+      AstFactory.fieldDeclaration2(false, null, [bVar, cVar])
+    ]);
+    expect(clazz.getField("a"), same(aVar));
+    expect(clazz.getField("b"), same(bVar));
+    expect(clazz.getField("c"), same(cVar));
+    expect(clazz.getField("noSuchField"), same(null));
+  }
+
+  void test_getMethod() {
+    MethodDeclaration aMethod = AstFactory.methodDeclaration(null, null, null,
+        null, AstFactory.identifier3("a"), AstFactory.formalParameterList());
+    MethodDeclaration bMethod = AstFactory.methodDeclaration(null, null, null,
+        null, AstFactory.identifier3("b"), AstFactory.formalParameterList());
+    ClassDeclaration clazz = AstFactory.classDeclaration(
+        null, "Test", null, null, null, null, [aMethod, bMethod]);
+    expect(clazz.getMethod("a"), same(aMethod));
+    expect(clazz.getMethod("b"), same(bMethod));
+    expect(clazz.getMethod("noSuchMethod"), same(null));
+  }
+
+  void test_isAbstract() {
+    expect(
+        AstFactory
+            .classDeclaration(null, "A", null, null, null, null)
+            .isAbstract,
+        isFalse);
+    expect(
+        AstFactory
+            .classDeclaration(Keyword.ABSTRACT, "B", null, null, null, null)
+            .isAbstract,
+        isTrue);
+  }
+}
+
+@reflectiveTest
+class ClassTypeAliasTest extends ParserTestCase {
+  void test_isAbstract() {
+    expect(
+        AstFactory.classTypeAlias("A", null, null, null, null, null).isAbstract,
+        isFalse);
+    expect(
+        AstFactory
+            .classTypeAlias("B", null, Keyword.ABSTRACT, null, null, null)
+            .isAbstract,
+        isTrue);
+  }
+}
+
+@reflectiveTest
+class ConstructorDeclarationTest extends EngineTestCase {
+  void test_firstTokenAfterCommentAndMetadata_all_inverted() {
+    Token externalKeyword = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
+    externalKeyword.offset = 14;
+    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+        Keyword.CONST,
+        Keyword.FACTORY,
+        AstFactory.identifier3('int'),
+        null,
+        null,
+        null,
+        null);
+    declaration.externalKeyword = externalKeyword;
+    declaration.constKeyword.offset = 8;
+    Token factoryKeyword = declaration.factoryKeyword;
+    factoryKeyword.offset = 0;
+    expect(declaration.firstTokenAfterCommentAndMetadata, factoryKeyword);
+  }
+
+  void test_firstTokenAfterCommentAndMetadata_all_normal() {
+    Token token = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
+    token.offset = 0;
+    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+        Keyword.CONST,
+        Keyword.FACTORY,
+        AstFactory.identifier3('int'),
+        null,
+        null,
+        null,
+        null);
+    declaration.externalKeyword = token;
+    declaration.constKeyword.offset = 9;
+    declaration.factoryKeyword.offset = 15;
+    expect(declaration.firstTokenAfterCommentAndMetadata, token);
+  }
+
+  void test_firstTokenAfterCommentAndMetadata_constOnly() {
+    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+        Keyword.CONST,
+        null,
+        AstFactory.identifier3('int'),
+        null,
+        null,
+        null,
+        null);
+    expect(declaration.firstTokenAfterCommentAndMetadata,
+        declaration.constKeyword);
+  }
+
+  void test_firstTokenAfterCommentAndMetadata_externalOnly() {
+    Token externalKeyword = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
+    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+        null, null, AstFactory.identifier3('int'), null, null, null, null);
+    declaration.externalKeyword = externalKeyword;
+    expect(declaration.firstTokenAfterCommentAndMetadata, externalKeyword);
+  }
+
+  void test_firstTokenAfterCommentAndMetadata_factoryOnly() {
+    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
+        null,
+        Keyword.FACTORY,
+        AstFactory.identifier3('int'),
+        null,
+        null,
+        null,
+        null);
+    expect(declaration.firstTokenAfterCommentAndMetadata,
+        declaration.factoryKeyword);
+  }
+}
+
+@reflectiveTest
+class FieldFormalParameterTest extends EngineTestCase {
+  void test_endToken_noParameters() {
+    FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('field');
+    expect(parameter.endToken, parameter.identifier.endToken);
+  }
+
+  void test_endToken_parameters() {
+    FieldFormalParameter parameter = AstFactory.fieldFormalParameter(
+        null, null, 'field', AstFactory.formalParameterList([]));
+    expect(parameter.endToken, parameter.parameters.endToken);
+  }
+}
+
+@reflectiveTest
+class IndexExpressionTest extends EngineTestCase {
+  void test_inGetterContext_assignment_compound_left() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // a[b] += c
+    AstFactory.assignmentExpression(
+        expression, TokenType.PLUS_EQ, AstFactory.identifier3("c"));
+    expect(expression.inGetterContext(), isTrue);
+  }
+
+  void test_inGetterContext_assignment_simple_left() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // a[b] = c
+    AstFactory.assignmentExpression(
+        expression, TokenType.EQ, AstFactory.identifier3("c"));
+    expect(expression.inGetterContext(), isFalse);
+  }
+
+  void test_inGetterContext_nonAssignment() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // a[b] + c
+    AstFactory.binaryExpression(
+        expression, TokenType.PLUS, AstFactory.identifier3("c"));
+    expect(expression.inGetterContext(), isTrue);
+  }
+
+  void test_inSetterContext_assignment_compound_left() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // a[b] += c
+    AstFactory.assignmentExpression(
+        expression, TokenType.PLUS_EQ, AstFactory.identifier3("c"));
+    expect(expression.inSetterContext(), isTrue);
+  }
+
+  void test_inSetterContext_assignment_compound_right() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // c += a[b]
+    AstFactory.assignmentExpression(
+        AstFactory.identifier3("c"), TokenType.PLUS_EQ, expression);
+    expect(expression.inSetterContext(), isFalse);
+  }
+
+  void test_inSetterContext_assignment_simple_left() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // a[b] = c
+    AstFactory.assignmentExpression(
+        expression, TokenType.EQ, AstFactory.identifier3("c"));
+    expect(expression.inSetterContext(), isTrue);
+  }
+
+  void test_inSetterContext_assignment_simple_right() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // c = a[b]
+    AstFactory.assignmentExpression(
+        AstFactory.identifier3("c"), TokenType.EQ, expression);
+    expect(expression.inSetterContext(), isFalse);
+  }
+
+  void test_inSetterContext_nonAssignment() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    AstFactory.binaryExpression(
+        expression, TokenType.PLUS, AstFactory.identifier3("c"));
+    // a[b] + cc
+    expect(expression.inSetterContext(), isFalse);
+  }
+
+  void test_inSetterContext_postfix() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    AstFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
+    // a[b]++
+    expect(expression.inSetterContext(), isTrue);
+  }
+
+  void test_inSetterContext_prefix_bang() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // !a[b]
+    AstFactory.prefixExpression(TokenType.BANG, expression);
+    expect(expression.inSetterContext(), isFalse);
+  }
+
+  void test_inSetterContext_prefix_minusMinus() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // --a[b]
+    AstFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
+    expect(expression.inSetterContext(), isTrue);
+  }
+
+  void test_inSetterContext_prefix_plusPlus() {
+    IndexExpression expression = AstFactory.indexExpression(
+        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
+    // ++a[b]
+    AstFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
+    expect(expression.inSetterContext(), isTrue);
+  }
+}
+
+@reflectiveTest
+class NodeListTest extends EngineTestCase {
+  void test_add() {
+    AstNode parent = AstFactory.argumentList();
+    AstNode firstNode = AstFactory.booleanLiteral(true);
+    AstNode secondNode = AstFactory.booleanLiteral(false);
+    NodeList<AstNode> list = new NodeList<AstNode>(parent);
+    list.insert(0, secondNode);
+    list.insert(0, firstNode);
+    expect(list, hasLength(2));
+    expect(list[0], same(firstNode));
+    expect(list[1], same(secondNode));
+    expect(firstNode.parent, same(parent));
+    expect(secondNode.parent, same(parent));
+    AstNode thirdNode = AstFactory.booleanLiteral(false);
+    list.insert(1, thirdNode);
+    expect(list, hasLength(3));
+    expect(list[0], same(firstNode));
+    expect(list[1], same(thirdNode));
+    expect(list[2], same(secondNode));
+    expect(firstNode.parent, same(parent));
+    expect(secondNode.parent, same(parent));
+    expect(thirdNode.parent, same(parent));
+  }
+
+  void test_add_negative() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    try {
+      list.insert(-1, AstFactory.booleanLiteral(true));
+      fail("Expected IndexOutOfBoundsException");
+    } on RangeError {
+      // Expected
+    }
+  }
+
+  void test_add_tooBig() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    try {
+      list.insert(1, AstFactory.booleanLiteral(true));
+      fail("Expected IndexOutOfBoundsException");
+    } on RangeError {
+      // Expected
+    }
+  }
+
+  void test_addAll() {
+    AstNode parent = AstFactory.argumentList();
+    List<AstNode> firstNodes = new List<AstNode>();
+    AstNode firstNode = AstFactory.booleanLiteral(true);
+    AstNode secondNode = AstFactory.booleanLiteral(false);
+    firstNodes.add(firstNode);
+    firstNodes.add(secondNode);
+    NodeList<AstNode> list = new NodeList<AstNode>(parent);
+    list.addAll(firstNodes);
+    expect(list, hasLength(2));
+    expect(list[0], same(firstNode));
+    expect(list[1], same(secondNode));
+    expect(firstNode.parent, same(parent));
+    expect(secondNode.parent, same(parent));
+    List<AstNode> secondNodes = new List<AstNode>();
+    AstNode thirdNode = AstFactory.booleanLiteral(true);
+    AstNode fourthNode = AstFactory.booleanLiteral(false);
+    secondNodes.add(thirdNode);
+    secondNodes.add(fourthNode);
+    list.addAll(secondNodes);
+    expect(list, hasLength(4));
+    expect(list[0], same(firstNode));
+    expect(list[1], same(secondNode));
+    expect(list[2], same(thirdNode));
+    expect(list[3], same(fourthNode));
+    expect(firstNode.parent, same(parent));
+    expect(secondNode.parent, same(parent));
+    expect(thirdNode.parent, same(parent));
+    expect(fourthNode.parent, same(parent));
+  }
+
+  void test_creation() {
+    AstNode owner = AstFactory.argumentList();
+    NodeList<AstNode> list = new NodeList<AstNode>(owner);
+    expect(list, isNotNull);
+    expect(list, hasLength(0));
+    expect(list.owner, same(owner));
+  }
+
+  void test_get_negative() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    try {
+      list[-1];
+      fail("Expected IndexOutOfBoundsException");
+    } on RangeError {
+      // Expected
+    }
+  }
+
+  void test_get_tooBig() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    try {
+      list[1];
+      fail("Expected IndexOutOfBoundsException");
+    } on RangeError {
+      // Expected
+    }
+  }
+
+  void test_getBeginToken_empty() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    expect(list.beginToken, isNull);
+  }
+
+  void test_getBeginToken_nonEmpty() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    AstNode node =
+        AstFactory.parenthesizedExpression(AstFactory.booleanLiteral(true));
+    list.add(node);
+    expect(list.beginToken, same(node.beginToken));
+  }
+
+  void test_getEndToken_empty() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    expect(list.endToken, isNull);
+  }
+
+  void test_getEndToken_nonEmpty() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    AstNode node =
+        AstFactory.parenthesizedExpression(AstFactory.booleanLiteral(true));
+    list.add(node);
+    expect(list.endToken, same(node.endToken));
+  }
+
+  void test_indexOf() {
+    List<AstNode> nodes = new List<AstNode>();
+    AstNode firstNode = AstFactory.booleanLiteral(true);
+    AstNode secondNode = AstFactory.booleanLiteral(false);
+    AstNode thirdNode = AstFactory.booleanLiteral(true);
+    AstNode fourthNode = AstFactory.booleanLiteral(false);
+    nodes.add(firstNode);
+    nodes.add(secondNode);
+    nodes.add(thirdNode);
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    list.addAll(nodes);
+    expect(list, hasLength(3));
+    expect(list.indexOf(firstNode), 0);
+    expect(list.indexOf(secondNode), 1);
+    expect(list.indexOf(thirdNode), 2);
+    expect(list.indexOf(fourthNode), -1);
+    expect(list.indexOf(null), -1);
+  }
+
+  void test_remove() {
+    List<AstNode> nodes = new List<AstNode>();
+    AstNode firstNode = AstFactory.booleanLiteral(true);
+    AstNode secondNode = AstFactory.booleanLiteral(false);
+    AstNode thirdNode = AstFactory.booleanLiteral(true);
+    nodes.add(firstNode);
+    nodes.add(secondNode);
+    nodes.add(thirdNode);
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    list.addAll(nodes);
+    expect(list, hasLength(3));
+    expect(list.removeAt(1), same(secondNode));
+    expect(list, hasLength(2));
+    expect(list[0], same(firstNode));
+    expect(list[1], same(thirdNode));
+  }
+
+  void test_remove_negative() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    try {
+      list.removeAt(-1);
+      fail("Expected IndexOutOfBoundsException");
+    } on RangeError {
+      // Expected
+    }
+  }
+
+  void test_remove_tooBig() {
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    try {
+      list.removeAt(1);
+      fail("Expected IndexOutOfBoundsException");
+    } on RangeError {
+      // Expected
+    }
+  }
+
+  void test_set() {
+    List<AstNode> nodes = new List<AstNode>();
+    AstNode firstNode = AstFactory.booleanLiteral(true);
+    AstNode secondNode = AstFactory.booleanLiteral(false);
+    AstNode thirdNode = AstFactory.booleanLiteral(true);
+    nodes.add(firstNode);
+    nodes.add(secondNode);
+    nodes.add(thirdNode);
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    list.addAll(nodes);
+    expect(list, hasLength(3));
+    AstNode fourthNode = AstFactory.integer(0);
+    list[1] = fourthNode;
+    expect(list, hasLength(3));
+    expect(list[0], same(firstNode));
+    expect(list[1], same(fourthNode));
+    expect(list[2], same(thirdNode));
+  }
+
+  void test_set_negative() {
+    AstNode node = AstFactory.booleanLiteral(true);
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    try {
+      list[-1] = node;
+      fail("Expected IndexOutOfBoundsException");
+    } on RangeError {
+      // Expected
+    }
+  }
+
+  void test_set_tooBig() {
+    AstNode node = AstFactory.booleanLiteral(true);
+    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
+    try {
+      list[1] = node;
+      fail("Expected IndexOutOfBoundsException");
+    } on RangeError {
+      // Expected
+    }
+  }
+}
+
+@reflectiveTest
+class SimpleIdentifierTest extends ParserTestCase {
+  void test_inDeclarationContext_catch_exception() {
+    SimpleIdentifier identifier =
+        AstFactory.catchClause("e").exceptionParameter;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_catch_stack() {
+    SimpleIdentifier identifier =
+        AstFactory.catchClause2("e", "s").stackTraceParameter;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_classDeclaration() {
+    SimpleIdentifier identifier =
+        AstFactory.classDeclaration(null, "C", null, null, null, null).name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_classTypeAlias() {
+    SimpleIdentifier identifier =
+        AstFactory.classTypeAlias("C", null, null, null, null, null).name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_constructorDeclaration() {
+    SimpleIdentifier identifier = AstFactory
+        .constructorDeclaration(AstFactory.identifier3("C"), "c", null, null)
+        .name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_declaredIdentifier() {
+    DeclaredIdentifier declaredIdentifier = AstFactory.declaredIdentifier3("v");
+    SimpleIdentifier identifier = declaredIdentifier.identifier;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_enumConstantDeclaration() {
+    EnumDeclaration enumDeclaration =
+        AstFactory.enumDeclaration2('MyEnum', ['CONST']);
+    SimpleIdentifier identifier = enumDeclaration.constants[0].name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_enumDeclaration() {
+    EnumDeclaration enumDeclaration =
+        AstFactory.enumDeclaration2('MyEnum', ['A', 'B', 'C']);
+    SimpleIdentifier identifier = enumDeclaration.name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_fieldFormalParameter() {
+    SimpleIdentifier identifier =
+        AstFactory.fieldFormalParameter2("p").identifier;
+    expect(identifier.inDeclarationContext(), isFalse);
+  }
+
+  void test_inDeclarationContext_functionDeclaration() {
+    SimpleIdentifier identifier =
+        AstFactory.functionDeclaration(null, null, "f", null).name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_functionTypeAlias() {
+    SimpleIdentifier identifier =
+        AstFactory.typeAlias(null, "F", null, null).name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_label_false() {
+    SimpleIdentifier identifier =
+        AstFactory.namedExpression2("l", AstFactory.integer(0)).name.label;
+    expect(identifier.inDeclarationContext(), isFalse);
+  }
+
+  void test_inDeclarationContext_label_true() {
+    Label label = AstFactory.label2("l");
+    SimpleIdentifier identifier = label.label;
+    AstFactory.labeledStatement([label], AstFactory.emptyStatement());
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_methodDeclaration() {
+    SimpleIdentifier identifier = AstFactory.identifier3("m");
+    AstFactory.methodDeclaration2(
+        null, null, null, null, identifier, null, null);
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_prefix() {
+    SimpleIdentifier identifier =
+        AstFactory.importDirective3("uri", "pref").prefix;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_simpleFormalParameter() {
+    SimpleIdentifier identifier =
+        AstFactory.simpleFormalParameter3("p").identifier;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_typeParameter_bound() {
+    TypeName bound = AstFactory.typeName4("A");
+    SimpleIdentifier identifier = bound.name as SimpleIdentifier;
+    AstFactory.typeParameter2("E", bound);
+    expect(identifier.inDeclarationContext(), isFalse);
+  }
+
+  void test_inDeclarationContext_typeParameter_name() {
+    SimpleIdentifier identifier = AstFactory.typeParameter("E").name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inDeclarationContext_variableDeclaration() {
+    SimpleIdentifier identifier = AstFactory.variableDeclaration("v").name;
+    expect(identifier.inDeclarationContext(), isTrue);
+  }
+
+  void test_inGetterContext() {
+    for (_WrapperKind wrapper in _WrapperKind.values) {
+      for (_AssignmentKind assignment in _AssignmentKind.values) {
+        SimpleIdentifier identifier = _createIdentifier(wrapper, assignment);
+        if (assignment == _AssignmentKind.SIMPLE_LEFT &&
+            wrapper != _WrapperKind.PREFIXED_LEFT &&
+            wrapper != _WrapperKind.PROPERTY_LEFT) {
+          if (identifier.inGetterContext()) {
+            fail("Expected ${_topMostNode(identifier).toSource()} to be false");
+          }
+        } else {
+          if (!identifier.inGetterContext()) {
+            fail("Expected ${_topMostNode(identifier).toSource()} to be true");
+          }
+        }
+      }
+    }
+  }
+
+  void test_inGetterContext_forEachLoop() {
+    SimpleIdentifier identifier = AstFactory.identifier3("a");
+    Expression iterator = AstFactory.listLiteral();
+    Statement body = AstFactory.block();
+    AstFactory.forEachStatement2(identifier, iterator, body);
+    expect(identifier.inGetterContext(), isFalse);
+  }
+
+  void test_inReferenceContext() {
+    SimpleIdentifier identifier = AstFactory.identifier3("id");
+    AstFactory.namedExpression(
+        AstFactory.label(identifier), AstFactory.identifier3("_"));
+    expect(identifier.inGetterContext(), isFalse);
+    expect(identifier.inSetterContext(), isFalse);
+  }
+
+  void test_inSetterContext() {
+    for (_WrapperKind wrapper in _WrapperKind.values) {
+      for (_AssignmentKind assignment in _AssignmentKind.values) {
+        SimpleIdentifier identifier = _createIdentifier(wrapper, assignment);
+        if (wrapper == _WrapperKind.PREFIXED_LEFT ||
+            wrapper == _WrapperKind.PROPERTY_LEFT ||
+            assignment == _AssignmentKind.BINARY ||
+            assignment == _AssignmentKind.COMPOUND_RIGHT ||
+            assignment == _AssignmentKind.PREFIX_NOT ||
+            assignment == _AssignmentKind.SIMPLE_RIGHT ||
+            assignment == _AssignmentKind.NONE) {
+          if (identifier.inSetterContext()) {
+            fail("Expected ${_topMostNode(identifier).toSource()} to be false");
+          }
+        } else {
+          if (!identifier.inSetterContext()) {
+            fail("Expected ${_topMostNode(identifier).toSource()} to be true");
+          }
+        }
+      }
+    }
+  }
+
+  void test_inSetterContext_forEachLoop() {
+    SimpleIdentifier identifier = AstFactory.identifier3("a");
+    Expression iterator = AstFactory.listLiteral();
+    Statement body = AstFactory.block();
+    AstFactory.forEachStatement2(identifier, iterator, body);
+    expect(identifier.inSetterContext(), isTrue);
+  }
+
+  void test_isQualified_inMethodInvocation_noTarget() {
+    MethodInvocation invocation =
+        AstFactory.methodInvocation2("test", [AstFactory.identifier3("arg0")]);
+    SimpleIdentifier identifier = invocation.methodName;
+    expect(identifier.isQualified, isFalse);
+  }
+
+  void test_isQualified_inMethodInvocation_withTarget() {
+    MethodInvocation invocation = AstFactory.methodInvocation(
+        AstFactory.identifier3("target"),
+        "test",
+        [AstFactory.identifier3("arg0")]);
+    SimpleIdentifier identifier = invocation.methodName;
+    expect(identifier.isQualified, isTrue);
+  }
+
+  void test_isQualified_inPrefixedIdentifier_name() {
+    SimpleIdentifier identifier = AstFactory.identifier3("test");
+    AstFactory.identifier4("prefix", identifier);
+    expect(identifier.isQualified, isTrue);
+  }
+
+  void test_isQualified_inPrefixedIdentifier_prefix() {
+    SimpleIdentifier identifier = AstFactory.identifier3("test");
+    AstFactory.identifier(identifier, AstFactory.identifier3("name"));
+    expect(identifier.isQualified, isFalse);
+  }
+
+  void test_isQualified_inPropertyAccess_name() {
+    SimpleIdentifier identifier = AstFactory.identifier3("test");
+    AstFactory.propertyAccess(AstFactory.identifier3("target"), identifier);
+    expect(identifier.isQualified, isTrue);
+  }
+
+  void test_isQualified_inPropertyAccess_target() {
+    SimpleIdentifier identifier = AstFactory.identifier3("test");
+    AstFactory.propertyAccess(identifier, AstFactory.identifier3("name"));
+    expect(identifier.isQualified, isFalse);
+  }
+
+  void test_isQualified_inReturnStatement() {
+    SimpleIdentifier identifier = AstFactory.identifier3("test");
+    AstFactory.returnStatement2(identifier);
+    expect(identifier.isQualified, isFalse);
+  }
+
+  SimpleIdentifier _createIdentifier(
+      _WrapperKind wrapper, _AssignmentKind assignment) {
+    SimpleIdentifier identifier = AstFactory.identifier3("a");
+    Expression expression = identifier;
+    while (true) {
+      if (wrapper == _WrapperKind.PREFIXED_LEFT) {
+        expression =
+            AstFactory.identifier(identifier, AstFactory.identifier3("_"));
+      } else if (wrapper == _WrapperKind.PREFIXED_RIGHT) {
+        expression =
+            AstFactory.identifier(AstFactory.identifier3("_"), identifier);
+      } else if (wrapper == _WrapperKind.PROPERTY_LEFT) {
+        expression = AstFactory.propertyAccess2(expression, "_");
+      } else if (wrapper == _WrapperKind.PROPERTY_RIGHT) {
+        expression =
+            AstFactory.propertyAccess(AstFactory.identifier3("_"), identifier);
+      } else if (wrapper == _WrapperKind.NONE) {}
+      break;
+    }
+    while (true) {
+      if (assignment == _AssignmentKind.BINARY) {
+        AstFactory.binaryExpression(
+            expression, TokenType.PLUS, AstFactory.identifier3("_"));
+      } else if (assignment == _AssignmentKind.COMPOUND_LEFT) {
+        AstFactory.assignmentExpression(
+            expression, TokenType.PLUS_EQ, AstFactory.identifier3("_"));
+      } else if (assignment == _AssignmentKind.COMPOUND_RIGHT) {
+        AstFactory.assignmentExpression(
+            AstFactory.identifier3("_"), TokenType.PLUS_EQ, expression);
+      } else if (assignment == _AssignmentKind.POSTFIX_INC) {
+        AstFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
+      } else if (assignment == _AssignmentKind.PREFIX_DEC) {
+        AstFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
+      } else if (assignment == _AssignmentKind.PREFIX_INC) {
+        AstFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
+      } else if (assignment == _AssignmentKind.PREFIX_NOT) {
+        AstFactory.prefixExpression(TokenType.BANG, expression);
+      } else if (assignment == _AssignmentKind.SIMPLE_LEFT) {
+        AstFactory.assignmentExpression(
+            expression, TokenType.EQ, AstFactory.identifier3("_"));
+      } else if (assignment == _AssignmentKind.SIMPLE_RIGHT) {
+        AstFactory.assignmentExpression(
+            AstFactory.identifier3("_"), TokenType.EQ, expression);
+      } else if (assignment == _AssignmentKind.NONE) {}
+      break;
+    }
+    return identifier;
+  }
+
+  /**
+   * Return the top-most node in the AST structure containing the given identifier.
+   *
+   * @param identifier the identifier in the AST structure being traversed
+   * @return the root of the AST structure containing the identifier
+   */
+  AstNode _topMostNode(SimpleIdentifier identifier) {
+    AstNode child = identifier;
+    AstNode parent = identifier.parent;
+    while (parent != null) {
+      child = parent;
+      parent = parent.parent;
+    }
+    return child;
+  }
+}
+
+@reflectiveTest
+class SimpleStringLiteralTest extends ParserTestCase {
+  void test_contentsEnd() {
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
+            .contentsEnd,
+        2);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString('"X"'), "X")
+            .contentsEnd,
+        2);
+
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString('"""X"""'), "X")
+            .contentsEnd,
+        4);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
+            .contentsEnd,
+        4);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("'''  \nX'''"), "X")
+            .contentsEnd,
+        7);
+
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
+            .contentsEnd,
+        3);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString('r"X"'), "X")
+            .contentsEnd,
+        3);
+
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString('r"""X"""'), "X")
+            .contentsEnd,
+        5);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
+            .contentsEnd,
+        5);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("r'''  \nX'''"), "X")
+            .contentsEnd,
+        8);
+  }
+
+  void test_contentsOffset() {
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
+            .contentsOffset,
+        1);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
+            .contentsOffset,
+        1);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X")
+            .contentsOffset,
+        3);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
+            .contentsOffset,
+        3);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
+            .contentsOffset,
+        2);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
+            .contentsOffset,
+        2);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X")
+            .contentsOffset,
+        4);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
+            .contentsOffset,
+        4);
+    // leading whitespace
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("''' \ \nX''"), "X")
+            .contentsOffset,
+        6);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString('r""" \ \nX"""'), "X")
+            .contentsOffset,
+        7);
+  }
+
+  void test_isMultiline() {
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
+            .isMultiline,
+        isFalse);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
+            .isMultiline,
+        isFalse);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
+            .isMultiline,
+        isFalse);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
+            .isMultiline,
+        isFalse);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
+            .isMultiline,
+        isTrue);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
+            .isMultiline,
+        isTrue);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X")
+            .isMultiline,
+        isTrue);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X")
+            .isMultiline,
+        isTrue);
+  }
+
+  void test_isRaw() {
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X").isRaw,
+        isFalse);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
+            .isRaw,
+        isFalse);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X")
+            .isRaw,
+        isFalse);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
+            .isRaw,
+        isFalse);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
+            .isRaw,
+        isTrue);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
+            .isRaw,
+        isTrue);
+    expect(
+        new SimpleStringLiteral(
+                TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X")
+            .isRaw,
+        isTrue);
+    expect(
+        new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
+            .isRaw,
+        isTrue);
+  }
+
+  void test_isSingleQuoted() {
+    // '
+    {
+      var token = TokenFactory.tokenFromString("'X'");
+      var node = new SimpleStringLiteral(token, null);
+      expect(node.isSingleQuoted, isTrue);
+    }
+    // '''
+    {
+      var token = TokenFactory.tokenFromString("'''X'''");
+      var node = new SimpleStringLiteral(token, null);
+      expect(node.isSingleQuoted, isTrue);
+    }
+    // "
+    {
+      var token = TokenFactory.tokenFromString('"X"');
+      var node = new SimpleStringLiteral(token, null);
+      expect(node.isSingleQuoted, isFalse);
+    }
+    // """
+    {
+      var token = TokenFactory.tokenFromString('"""X"""');
+      var node = new SimpleStringLiteral(token, null);
+      expect(node.isSingleQuoted, isFalse);
+    }
+  }
+
+  void test_isSingleQuoted_raw() {
+    // r'
+    {
+      var token = TokenFactory.tokenFromString("r'X'");
+      var node = new SimpleStringLiteral(token, null);
+      expect(node.isSingleQuoted, isTrue);
+    }
+    // r'''
+    {
+      var token = TokenFactory.tokenFromString("r'''X'''");
+      var node = new SimpleStringLiteral(token, null);
+      expect(node.isSingleQuoted, isTrue);
+    }
+    // r"
+    {
+      var token = TokenFactory.tokenFromString('r"X"');
+      var node = new SimpleStringLiteral(token, null);
+      expect(node.isSingleQuoted, isFalse);
+    }
+    // r"""
+    {
+      var token = TokenFactory.tokenFromString('r"""X"""');
+      var node = new SimpleStringLiteral(token, null);
+      expect(node.isSingleQuoted, isFalse);
+    }
+  }
+
+  void test_simple() {
+    Token token = TokenFactory.tokenFromString("'value'");
+    SimpleStringLiteral stringLiteral = new SimpleStringLiteral(token, "value");
+    expect(stringLiteral.literal, same(token));
+    expect(stringLiteral.beginToken, same(token));
+    expect(stringLiteral.endToken, same(token));
+    expect(stringLiteral.value, "value");
+  }
+}
+
+@reflectiveTest
+class StringInterpolationTest extends ParserTestCase {
+  void test_contentsOffsetEnd() {
+    AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
+    // 'a${bb}ccc'
+    {
+      var ae = AstFactory.interpolationString("'a", "a");
+      var cToken = new StringToken(TokenType.STRING, "ccc'", 10);
+      var cElement = new InterpolationString(cToken, 'ccc');
+      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+      expect(node.contentsOffset, 1);
+      expect(node.contentsEnd, 10 + 4 - 1);
+    }
+    // '''a${bb}ccc'''
+    {
+      var ae = AstFactory.interpolationString("'''a", "a");
+      var cToken = new StringToken(TokenType.STRING, "ccc'''", 10);
+      var cElement = new InterpolationString(cToken, 'ccc');
+      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+      expect(node.contentsOffset, 3);
+      expect(node.contentsEnd, 10 + 4 - 1);
+    }
+    // """a${bb}ccc"""
+    {
+      var ae = AstFactory.interpolationString('"""a', "a");
+      var cToken = new StringToken(TokenType.STRING, 'ccc"""', 10);
+      var cElement = new InterpolationString(cToken, 'ccc');
+      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+      expect(node.contentsOffset, 3);
+      expect(node.contentsEnd, 10 + 4 - 1);
+    }
+    // r'a${bb}ccc'
+    {
+      var ae = AstFactory.interpolationString("r'a", "a");
+      var cToken = new StringToken(TokenType.STRING, "ccc'", 10);
+      var cElement = new InterpolationString(cToken, 'ccc');
+      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+      expect(node.contentsOffset, 2);
+      expect(node.contentsEnd, 10 + 4 - 1);
+    }
+    // r'''a${bb}ccc'''
+    {
+      var ae = AstFactory.interpolationString("r'''a", "a");
+      var cToken = new StringToken(TokenType.STRING, "ccc'''", 10);
+      var cElement = new InterpolationString(cToken, 'ccc');
+      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+      expect(node.contentsOffset, 4);
+      expect(node.contentsEnd, 10 + 4 - 1);
+    }
+    // r"""a${bb}ccc"""
+    {
+      var ae = AstFactory.interpolationString('r"""a', "a");
+      var cToken = new StringToken(TokenType.STRING, 'ccc"""', 10);
+      var cElement = new InterpolationString(cToken, 'ccc');
+      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
+      expect(node.contentsOffset, 4);
+      expect(node.contentsEnd, 10 + 4 - 1);
+    }
+  }
+
+  void test_isMultiline() {
+    var b = AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
+    // '
+    {
+      var a = AstFactory.interpolationString("'a", "a");
+      var c = AstFactory.interpolationString("ccc'", "ccc");
+      StringInterpolation node = AstFactory.string([a, b, c]);
+      expect(node.isMultiline, isFalse);
+    }
+    // '''
+    {
+      var a = AstFactory.interpolationString("'''a", "a");
+      var c = AstFactory.interpolationString("ccc'''", "ccc");
+      StringInterpolation node = AstFactory.string([a, b, c]);
+      expect(node.isMultiline, isTrue);
+    }
+    // "
+    {
+      var a = AstFactory.interpolationString('"a', "a");
+      var c = AstFactory.interpolationString('ccc"', "ccc");
+      StringInterpolation node = AstFactory.string([a, b, c]);
+      expect(node.isMultiline, isFalse);
+    }
+    // """
+    {
+      var a = AstFactory.interpolationString('"""a', "a");
+      var c = AstFactory.interpolationString('ccc"""', "ccc");
+      StringInterpolation node = AstFactory.string([a, b, c]);
+      expect(node.isMultiline, isTrue);
+    }
+  }
+
+  void test_isRaw() {
+    StringInterpolation node = AstFactory.string();
+    expect(node.isRaw, isFalse);
+  }
+
+  void test_isSingleQuoted() {
+    var b = AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
+    // "
+    {
+      var a = AstFactory.interpolationString('"a', "a");
+      var c = AstFactory.interpolationString('ccc"', "ccc");
+      StringInterpolation node = AstFactory.string([a, b, c]);
+      expect(node.isSingleQuoted, isFalse);
+    }
+    // """
+    {
+      var a = AstFactory.interpolationString('"""a', "a");
+      var c = AstFactory.interpolationString('ccc"""', "ccc");
+      StringInterpolation node = AstFactory.string([a, b, c]);
+      expect(node.isSingleQuoted, isFalse);
+    }
+    // '
+    {
+      var a = AstFactory.interpolationString("'a", "a");
+      var c = AstFactory.interpolationString("ccc'", "ccc");
+      StringInterpolation node = AstFactory.string([a, b, c]);
+      expect(node.isSingleQuoted, isTrue);
+    }
+    // '''
+    {
+      var a = AstFactory.interpolationString("'''a", "a");
+      var c = AstFactory.interpolationString("ccc'''", "ccc");
+      StringInterpolation node = AstFactory.string([a, b, c]);
+      expect(node.isSingleQuoted, isTrue);
+    }
+  }
+}
+
+@reflectiveTest
+class VariableDeclarationTest extends ParserTestCase {
+  void test_getDocumentationComment_onGrandParent() {
+    VariableDeclaration varDecl = AstFactory.variableDeclaration("a");
+    TopLevelVariableDeclaration decl =
+        AstFactory.topLevelVariableDeclaration2(Keyword.VAR, [varDecl]);
+    Comment comment = Comment.createDocumentationComment(new List<Token>(0));
+    expect(varDecl.documentationComment, isNull);
+    decl.documentationComment = comment;
+    expect(varDecl.documentationComment, isNotNull);
+    expect(decl.documentationComment, isNotNull);
+  }
+
+  void test_getDocumentationComment_onNode() {
+    VariableDeclaration decl = AstFactory.variableDeclaration("a");
+    Comment comment = Comment.createDocumentationComment(new List<Token>(0));
+    decl.documentationComment = comment;
+    expect(decl.documentationComment, isNotNull);
+  }
+}
+
+class _AssignmentKind {
+  static const _AssignmentKind BINARY = const _AssignmentKind('BINARY', 0);
+
+  static const _AssignmentKind COMPOUND_LEFT =
+      const _AssignmentKind('COMPOUND_LEFT', 1);
+
+  static const _AssignmentKind COMPOUND_RIGHT =
+      const _AssignmentKind('COMPOUND_RIGHT', 2);
+
+  static const _AssignmentKind POSTFIX_INC =
+      const _AssignmentKind('POSTFIX_INC', 3);
+
+  static const _AssignmentKind PREFIX_DEC =
+      const _AssignmentKind('PREFIX_DEC', 4);
+
+  static const _AssignmentKind PREFIX_INC =
+      const _AssignmentKind('PREFIX_INC', 5);
+
+  static const _AssignmentKind PREFIX_NOT =
+      const _AssignmentKind('PREFIX_NOT', 6);
+
+  static const _AssignmentKind SIMPLE_LEFT =
+      const _AssignmentKind('SIMPLE_LEFT', 7);
+
+  static const _AssignmentKind SIMPLE_RIGHT =
+      const _AssignmentKind('SIMPLE_RIGHT', 8);
+
+  static const _AssignmentKind NONE = const _AssignmentKind('NONE', 9);
+
+  static const List<_AssignmentKind> values = const [
+    BINARY,
+    COMPOUND_LEFT,
+    COMPOUND_RIGHT,
+    POSTFIX_INC,
+    PREFIX_DEC,
+    PREFIX_INC,
+    PREFIX_NOT,
+    SIMPLE_LEFT,
+    SIMPLE_RIGHT,
+    NONE
+  ];
+
+  final String name;
+
+  final int ordinal;
+
+  const _AssignmentKind(this.name, this.ordinal);
+
+  int get hashCode => ordinal;
+
+  int compareTo(_AssignmentKind other) => ordinal - other.ordinal;
+
+  String toString() => name;
+}
+
+class _WrapperKind {
+  static const _WrapperKind PREFIXED_LEFT =
+      const _WrapperKind('PREFIXED_LEFT', 0);
+
+  static const _WrapperKind PREFIXED_RIGHT =
+      const _WrapperKind('PREFIXED_RIGHT', 1);
+
+  static const _WrapperKind PROPERTY_LEFT =
+      const _WrapperKind('PROPERTY_LEFT', 2);
+
+  static const _WrapperKind PROPERTY_RIGHT =
+      const _WrapperKind('PROPERTY_RIGHT', 3);
+
+  static const _WrapperKind NONE = const _WrapperKind('NONE', 4);
+
+  static const List<_WrapperKind> values = const [
+    PREFIXED_LEFT,
+    PREFIXED_RIGHT,
+    PROPERTY_LEFT,
+    PROPERTY_RIGHT,
+    NONE
+  ];
+
+  final String name;
+
+  final int ordinal;
+
+  const _WrapperKind(this.name, this.ordinal);
+
+  int get hashCode => ordinal;
+
+  int compareTo(_WrapperKind other) => ordinal - other.ordinal;
+
+  String toString() => name;
+}
diff --git a/pkg/analyzer/test/dart/ast/test_all.dart b/pkg/analyzer/test/dart/ast/test_all.dart
new file mode 100644
index 0000000..64f8170
--- /dev/null
+++ b/pkg/analyzer/test/dart/ast/test_all.dart
@@ -0,0 +1,20 @@
+// 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 analyzer.test.dart.ast.test_all;
+
+import 'package:unittest/unittest.dart';
+
+import '../../utils.dart';
+import 'ast_test.dart' as ast;
+import 'visitor_test.dart' as visitor;
+
+/// Utility for manually running all tests.
+main() {
+  initializeTestEnvironment();
+  group('ast tests', () {
+    ast.main();
+    visitor.main();
+  });
+}
diff --git a/pkg/analyzer/test/dart/ast/visitor_test.dart b/pkg/analyzer/test/dart/ast/visitor_test.dart
new file mode 100644
index 0000000..1645daa
--- /dev/null
+++ b/pkg/analyzer/test/dart/ast/visitor_test.dart
@@ -0,0 +1,79 @@
+// 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 analyzer.test.dart.ast.visitor_test;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../generated/parser_test.dart' show ParserTestCase;
+import '../../generated/test_support.dart';
+import '../../reflective_tests.dart';
+import '../../utils.dart';
+
+main() {
+  initializeTestEnvironment();
+  runReflectiveTests(BreadthFirstVisitorTest);
+}
+
+@reflectiveTest
+class BreadthFirstVisitorTest extends ParserTestCase {
+  void test_it() {
+    String source = r'''
+class A {
+  bool get g => true;
+}
+class B {
+  int f() {
+    num q() {
+      return 3;
+    }
+  return q() + 4;
+  }
+}
+A f(var p) {
+  if ((p as A).g) {
+    return p;
+  } else {
+    return null;
+  }
+}''';
+    CompilationUnit unit = ParserTestCase.parseCompilationUnit(source);
+    List<AstNode> nodes = new List<AstNode>();
+    BreadthFirstVisitor<Object> visitor =
+        new _BreadthFirstVisitorTestHelper(nodes);
+    visitor.visitAllNodes(unit);
+    expect(nodes, hasLength(59));
+    EngineTestCase.assertInstanceOf(
+        (obj) => obj is CompilationUnit, CompilationUnit, nodes[0]);
+    EngineTestCase.assertInstanceOf(
+        (obj) => obj is ClassDeclaration, ClassDeclaration, nodes[2]);
+    EngineTestCase.assertInstanceOf(
+        (obj) => obj is FunctionDeclaration, FunctionDeclaration, nodes[3]);
+    EngineTestCase.assertInstanceOf(
+        (obj) => obj is FunctionDeclarationStatement,
+        FunctionDeclarationStatement,
+        nodes[27]);
+    EngineTestCase.assertInstanceOf(
+        (obj) => obj is IntegerLiteral, IntegerLiteral, nodes[58]);
+    //3
+  }
+}
+
+/**
+ * A helper class used to collect the nodes that were visited and to preserve
+ * the order in which they were visited.
+ */
+class _BreadthFirstVisitorTestHelper extends BreadthFirstVisitor<Object> {
+  List<AstNode> nodes;
+
+  _BreadthFirstVisitorTestHelper(this.nodes) : super();
+
+  @override
+  Object visitNode(AstNode node) {
+    nodes.add(node);
+    return super.visitNode(node);
+  }
+}
diff --git a/pkg/analyzer/test/dart/element/test_all.dart b/pkg/analyzer/test/dart/element/test_all.dart
index 392c06a..5dac037 100644
--- a/pkg/analyzer/test/dart/element/test_all.dart
+++ b/pkg/analyzer/test/dart/element/test_all.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analyzer.test.generated.test_all;
+library analyzer.test.dart.element.test_all;
 
 import 'package:unittest/unittest.dart';
 
@@ -12,7 +12,7 @@
 /// Utility for manually running all tests.
 main() {
   initializeTestEnvironment();
-  group('generated tests', () {
+  group('element tests', () {
     element.main();
   });
 }
diff --git a/pkg/analyzer/test/dart/test_all.dart b/pkg/analyzer/test/dart/test_all.dart
index 669b706..df7ff55 100644
--- a/pkg/analyzer/test/dart/test_all.dart
+++ b/pkg/analyzer/test/dart/test_all.dart
@@ -7,12 +7,14 @@
 import 'package:unittest/unittest.dart';
 
 import '../utils.dart';
+import 'ast/test_all.dart' as ast;
 import 'element/test_all.dart' as element;
 
 /// Utility for manually running all tests.
 main() {
   initializeTestEnvironment();
   group('dart tests', () {
+    ast.main();
     element.main();
   });
 }
diff --git a/pkg/analyzer/test/enum_test.dart b/pkg/analyzer/test/enum_test.dart
index 625cf40..0ba5a98 100644
--- a/pkg/analyzer/test/enum_test.dart
+++ b/pkg/analyzer/test/enum_test.dart
@@ -7,6 +7,7 @@
 import 'dart:mirrors';
 
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_core.dart';
@@ -15,7 +16,6 @@
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:unittest/unittest.dart';
 
-import 'generated/ast_test.dart';
 import 'reflective_tests.dart';
 import 'utils.dart';
 
@@ -32,12 +32,6 @@
       ..check_explicit_values();
   }
 
-  void test_AssignmentKind() {
-    new EnumTester<AssignmentKind>()
-      ..check_getters()
-      ..check_explicit_values();
-  }
-
   void test_CacheState() {
     new EnumTester<CacheState>()
       ..check_getters()
@@ -75,7 +69,8 @@
   }
 
   void test_Modifier() {
-    new EnumTester<Modifier>()
+    new EnumTester<Modifier>(
+        ignoreGetters: ["persistedValues", "transientValues"])
       ..check_getters()
       ..check_explicit_values();
   }
@@ -103,12 +98,6 @@
       ..check_getters()
       ..check_explicit_values();
   }
-
-  void test_WrapperKind() {
-    new EnumTester<WrapperKind>()
-      ..check_getters()
-      ..check_explicit_values();
-  }
 }
 
 /**
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index f8ca1dc..b7ed4b3 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -4,19 +4,21 @@
 
 library analyzer.test.generated.all_the_rest_test;
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart' hide ConstantEvaluator;
+import 'package:analyzer/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
-import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine_io.dart';
 import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/sdk_io.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -25,31 +27,22 @@
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 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_collection.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:analyzer/src/task/dart.dart';
 import 'package:path/path.dart';
 import 'package:source_span/source_span.dart';
 import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
 import '../utils.dart';
-import 'engine_test.dart';
 import 'parser_test.dart';
 import 'resolver_test.dart';
 import 'test_support.dart';
 
 main() {
   initializeTestEnvironment();
-  runReflectiveTests(ConstantEvaluatorTest);
-  runReflectiveTests(ConstantFinderTest);
-  runReflectiveTests(ConstantValueComputerTest);
-  runReflectiveTests(ConstantVisitorTest);
   runReflectiveTests(ContentCacheTest);
   runReflectiveTests(CustomUriResolverTest);
-  runReflectiveTests(DartObjectImplTest);
   runReflectiveTests(DartUriResolverTest);
-  runReflectiveTests(DeclaredVariablesTest);
   runReflectiveTests(DirectoryBasedDartSdkTest);
   runReflectiveTests(DirectoryBasedSourceContainerTest);
   runReflectiveTests(ElementBuilderTest);
@@ -61,2120 +54,10 @@
   runReflectiveTests(ExitDetectorTest2);
   runReflectiveTests(FileBasedSourceTest);
   runReflectiveTests(FileUriResolverTest);
-  runReflectiveTests(ReferenceFinderTest);
   runReflectiveTests(SDKLibrariesReaderTest);
   runReflectiveTests(UriKindTest);
 }
 
-/**
- * Implementation of [ConstantEvaluationValidator] used during unit tests;
- * verifies that any nodes referenced during constant evaluation are present in
- * the dependency graph.
- */
-class ConstantEvaluationValidator_ForTest
-    implements ConstantEvaluationValidator {
-  ConstantValueComputer computer;
-
-  ConstantEvaluationTarget _nodeBeingEvaluated;
-
-  @override
-  void beforeComputeValue(ConstantEvaluationTarget constant) {
-    _nodeBeingEvaluated = constant;
-  }
-
-  @override
-  void beforeGetConstantInitializers(ConstructorElement constructor) {
-    // Make sure we properly recorded the dependency.
-    expect(
-        computer.referenceGraph.containsPath(_nodeBeingEvaluated, constructor),
-        isTrue);
-  }
-
-  @override
-  void beforeGetEvaluationResult(ConstantEvaluationTarget constant) {
-    // Make sure we properly recorded the dependency.
-    expect(computer.referenceGraph.containsPath(_nodeBeingEvaluated, constant),
-        isTrue);
-  }
-
-  @override
-  void beforeGetFieldEvaluationResult(FieldElementImpl field) {
-    // Make sure we properly recorded the dependency.
-    expect(computer.referenceGraph.containsPath(_nodeBeingEvaluated, field),
-        isTrue);
-  }
-
-  @override
-  void beforeGetParameterDefault(ParameterElement parameter) {
-    // Make sure we properly recorded the dependency.
-    expect(computer.referenceGraph.containsPath(_nodeBeingEvaluated, parameter),
-        isTrue);
-  }
-}
-
-@reflectiveTest
-class ConstantEvaluatorTest extends ResolverTestCase {
-  void fail_constructor() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_identifier_class() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_identifier_function() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_identifier_static() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_identifier_staticMethod() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_identifier_topLevel() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_identifier_typeParameter() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_prefixedIdentifier_invalid() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_prefixedIdentifier_valid() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_propertyAccess_invalid() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_propertyAccess_valid() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_simpleIdentifier_invalid() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void fail_simpleIdentifier_valid() {
-    EvaluationResult result = _getExpressionValue("?");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value, null);
-  }
-
-  void test_bitAnd_int_int() {
-    _assertValue3(74 & 42, "74 & 42");
-  }
-
-  void test_bitNot() {
-    _assertValue3(~42, "~42");
-  }
-
-  void test_bitOr_int_int() {
-    _assertValue3(74 | 42, "74 | 42");
-  }
-
-  void test_bitXor_int_int() {
-    _assertValue3(74 ^ 42, "74 ^ 42");
-  }
-
-  void test_divide_double_double() {
-    _assertValue2(3.2 / 2.3, "3.2 / 2.3");
-  }
-
-  void test_divide_double_double_byZero() {
-    EvaluationResult result = _getExpressionValue("3.2 / 0.0");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value.type.name, "double");
-    expect(value.toDoubleValue().isInfinite, isTrue);
-  }
-
-  void test_divide_int_int() {
-    _assertValue2(1.5, "3 / 2");
-  }
-
-  void test_divide_int_int_byZero() {
-    EvaluationResult result = _getExpressionValue("3 / 0");
-    expect(result.isValid, isTrue);
-  }
-
-  void test_equal_boolean_boolean() {
-    _assertValue(false, "true == false");
-  }
-
-  void test_equal_int_int() {
-    _assertValue(false, "2 == 3");
-  }
-
-  void test_equal_invalidLeft() {
-    EvaluationResult result = _getExpressionValue("a == 3");
-    expect(result.isValid, isFalse);
-  }
-
-  void test_equal_invalidRight() {
-    EvaluationResult result = _getExpressionValue("2 == a");
-    expect(result.isValid, isFalse);
-  }
-
-  void test_equal_string_string() {
-    _assertValue(false, "'a' == 'b'");
-  }
-
-  void test_greaterThan_int_int() {
-    _assertValue(false, "2 > 3");
-  }
-
-  void test_greaterThanOrEqual_int_int() {
-    _assertValue(false, "2 >= 3");
-  }
-
-  void test_leftShift_int_int() {
-    _assertValue3(64, "16 << 2");
-  }
-
-  void test_lessThan_int_int() {
-    _assertValue(true, "2 < 3");
-  }
-
-  void test_lessThanOrEqual_int_int() {
-    _assertValue(true, "2 <= 3");
-  }
-
-  void test_literal_boolean_false() {
-    _assertValue(false, "false");
-  }
-
-  void test_literal_boolean_true() {
-    _assertValue(true, "true");
-  }
-
-  void test_literal_list() {
-    EvaluationResult result = _getExpressionValue("const ['a', 'b', 'c']");
-    expect(result.isValid, isTrue);
-  }
-
-  void test_literal_map() {
-    EvaluationResult result =
-        _getExpressionValue("const {'a' : 'm', 'b' : 'n', 'c' : 'o'}");
-    expect(result.isValid, isTrue);
-  }
-
-  void test_literal_null() {
-    EvaluationResult result = _getExpressionValue("null");
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value.isNull, isTrue);
-  }
-
-  void test_literal_number_double() {
-    _assertValue2(3.45, "3.45");
-  }
-
-  void test_literal_number_integer() {
-    _assertValue3(42, "42");
-  }
-
-  void test_literal_string_adjacent() {
-    _assertValue4("abcdef", "'abc' 'def'");
-  }
-
-  void test_literal_string_interpolation_invalid() {
-    EvaluationResult result = _getExpressionValue("'a\${f()}c'");
-    expect(result.isValid, isFalse);
-  }
-
-  void test_literal_string_interpolation_valid() {
-    _assertValue4("a3c", "'a\${3}c'");
-  }
-
-  void test_literal_string_simple() {
-    _assertValue4("abc", "'abc'");
-  }
-
-  void test_logicalAnd() {
-    _assertValue(false, "true && false");
-  }
-
-  void test_logicalNot() {
-    _assertValue(false, "!true");
-  }
-
-  void test_logicalOr() {
-    _assertValue(true, "true || false");
-  }
-
-  void test_minus_double_double() {
-    _assertValue2(3.2 - 2.3, "3.2 - 2.3");
-  }
-
-  void test_minus_int_int() {
-    _assertValue3(1, "3 - 2");
-  }
-
-  void test_negated_boolean() {
-    EvaluationResult result = _getExpressionValue("-true");
-    expect(result.isValid, isFalse);
-  }
-
-  void test_negated_double() {
-    _assertValue2(-42.3, "-42.3");
-  }
-
-  void test_negated_integer() {
-    _assertValue3(-42, "-42");
-  }
-
-  void test_notEqual_boolean_boolean() {
-    _assertValue(true, "true != false");
-  }
-
-  void test_notEqual_int_int() {
-    _assertValue(true, "2 != 3");
-  }
-
-  void test_notEqual_invalidLeft() {
-    EvaluationResult result = _getExpressionValue("a != 3");
-    expect(result.isValid, isFalse);
-  }
-
-  void test_notEqual_invalidRight() {
-    EvaluationResult result = _getExpressionValue("2 != a");
-    expect(result.isValid, isFalse);
-  }
-
-  void test_notEqual_string_string() {
-    _assertValue(true, "'a' != 'b'");
-  }
-
-  void test_parenthesizedExpression() {
-    _assertValue4("a", "('a')");
-  }
-
-  void test_plus_double_double() {
-    _assertValue2(2.3 + 3.2, "2.3 + 3.2");
-  }
-
-  void test_plus_int_int() {
-    _assertValue3(5, "2 + 3");
-  }
-
-  void test_plus_string_string() {
-    _assertValue4("ab", "'a' + 'b'");
-  }
-
-  void test_remainder_double_double() {
-    _assertValue2(3.2 % 2.3, "3.2 % 2.3");
-  }
-
-  void test_remainder_int_int() {
-    _assertValue3(2, "8 % 3");
-  }
-
-  void test_rightShift() {
-    _assertValue3(16, "64 >> 2");
-  }
-
-  void test_stringLength_complex() {
-    _assertValue3(6, "('qwe' + 'rty').length");
-  }
-
-  void test_stringLength_simple() {
-    _assertValue3(6, "'Dvorak'.length");
-  }
-
-  void test_times_double_double() {
-    _assertValue2(2.3 * 3.2, "2.3 * 3.2");
-  }
-
-  void test_times_int_int() {
-    _assertValue3(6, "2 * 3");
-  }
-
-  void test_truncatingDivide_double_double() {
-    _assertValue3(1, "3.2 ~/ 2.3");
-  }
-
-  void test_truncatingDivide_int_int() {
-    _assertValue3(3, "10 ~/ 3");
-  }
-
-  void _assertValue(bool expectedValue, String contents) {
-    EvaluationResult result = _getExpressionValue(contents);
-    DartObject value = result.value;
-    expect(value.type.name, "bool");
-    expect(value.toBoolValue(), expectedValue);
-  }
-
-  void _assertValue2(double expectedValue, String contents) {
-    EvaluationResult result = _getExpressionValue(contents);
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value.type.name, "double");
-    expect(value.toDoubleValue(), expectedValue);
-  }
-
-  void _assertValue3(int expectedValue, String contents) {
-    EvaluationResult result = _getExpressionValue(contents);
-    expect(result.isValid, isTrue);
-    DartObject value = result.value;
-    expect(value.type.name, "int");
-    expect(value.toIntValue(), expectedValue);
-  }
-
-  void _assertValue4(String expectedValue, String contents) {
-    EvaluationResult result = _getExpressionValue(contents);
-    DartObject value = result.value;
-    expect(value, isNotNull);
-    ParameterizedType type = value.type;
-    expect(type, isNotNull);
-    expect(type.name, "String");
-    expect(value.toStringValue(), expectedValue);
-  }
-
-  EvaluationResult _getExpressionValue(String contents) {
-    Source source = addSource("var x = $contents;");
-    LibraryElement library = resolve2(source);
-    CompilationUnit unit =
-        analysisContext.resolveCompilationUnit(source, library);
-    expect(unit, isNotNull);
-    NodeList<CompilationUnitMember> declarations = unit.declarations;
-    expect(declarations, hasLength(1));
-    CompilationUnitMember declaration = declarations[0];
-    EngineTestCase.assertInstanceOf((obj) => obj is TopLevelVariableDeclaration,
-        TopLevelVariableDeclaration, declaration);
-    NodeList<VariableDeclaration> variables =
-        (declaration as TopLevelVariableDeclaration).variables.variables;
-    expect(variables, hasLength(1));
-    ConstantEvaluator evaluator = new ConstantEvaluator(
-        source, analysisContext.typeProvider,
-        typeSystem: analysisContext.typeSystem);
-    return evaluator.evaluate(variables[0].initializer);
-  }
-}
-
-@reflectiveTest
-class ConstantFinderTest {
-  AstNode _node;
-  TypeProvider _typeProvider;
-  AnalysisContext _context;
-  Source _source;
-
-  void setUp() {
-    _typeProvider = new TestTypeProvider();
-    _context = new TestAnalysisContext_ConstantFinderTest();
-    _source = new TestSource();
-  }
-
-  /**
-   * Test an annotation that consists solely of an identifier (and hence
-   * represents a reference to a compile-time constant variable).
-   */
-  void test_visitAnnotation_constantVariable() {
-    _node = AstFactory.annotation(AstFactory.identifier3('x'));
-    expect(_findAnnotations(), contains(_node));
-  }
-
-  /**
-   * Test an annotation that represents the invocation of a constant
-   * constructor.
-   */
-  void test_visitAnnotation_invocation() {
-    _node = AstFactory.annotation2(
-        AstFactory.identifier3('A'), null, AstFactory.argumentList());
-    expect(_findAnnotations(), contains(_node));
-  }
-
-  void test_visitConstructorDeclaration_const() {
-    ConstructorElement element = _setupConstructorDeclaration("A", true);
-    expect(_findConstants(), contains(element));
-  }
-
-  void test_visitConstructorDeclaration_nonConst() {
-    _setupConstructorDeclaration("A", false);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_const() {
-    VariableElement element = _setupVariableDeclaration("v", true, true);
-    expect(_findConstants(), contains(element));
-  }
-
-  void test_visitVariableDeclaration_final_inClass() {
-    _setupFieldDeclaration('C', 'f', Keyword.FINAL);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_final_inClassWithConstConstructor() {
-    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
-        hasConstConstructor: true);
-    expect(_findConstants(), contains(field.element));
-  }
-
-  void test_visitVariableDeclaration_final_outsideClass() {
-    _setupVariableDeclaration('v', false, true, isFinal: true);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_noInitializer() {
-    _setupVariableDeclaration("v", true, false);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_nonConst() {
-    _setupVariableDeclaration("v", false, true);
-    expect(_findConstants(), isEmpty);
-  }
-
-  void test_visitVariableDeclaration_static_const_inClass() {
-    VariableDeclaration field =
-        _setupFieldDeclaration('C', 'f', Keyword.CONST, isStatic: true);
-    expect(_findConstants(), contains(field.element));
-  }
-
-  void test_visitVariableDeclaration_static_const_inClassWithConstConstructor() {
-    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.CONST,
-        isStatic: true, hasConstConstructor: true);
-    expect(_findConstants(), contains(field.element));
-  }
-
-  void test_visitVariableDeclaration_static_final_inClassWithConstConstructor() {
-    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
-        isStatic: true, hasConstConstructor: true);
-    expect(_findConstants(), isNot(contains(field.element)));
-  }
-
-  void test_visitVariableDeclaration_uninitialized_final_inClassWithConstConstructor() {
-    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
-        isInitialized: false, hasConstConstructor: true);
-    expect(_findConstants(), isNot(contains(field.element)));
-  }
-
-  void test_visitVariableDeclaration_uninitialized_static_const_inClass() {
-    _setupFieldDeclaration('C', 'f', Keyword.CONST,
-        isStatic: true, isInitialized: false);
-    expect(_findConstants(), isEmpty);
-  }
-
-  List<Annotation> _findAnnotations() {
-    Set<Annotation> annotations = new Set<Annotation>();
-    for (ConstantEvaluationTarget target in _findConstants()) {
-      if (target is ConstantEvaluationTarget_Annotation) {
-        expect(target.context, same(_context));
-        expect(target.source, same(_source));
-        annotations.add(target.annotation);
-      }
-    }
-    return new List<Annotation>.from(annotations);
-  }
-
-  Set<ConstantEvaluationTarget> _findConstants() {
-    ConstantFinder finder = new ConstantFinder(_context, _source, _source);
-    _node.accept(finder);
-    Set<ConstantEvaluationTarget> constants = finder.constantsToCompute;
-    expect(constants, isNotNull);
-    return constants;
-  }
-
-  ConstructorElement _setupConstructorDeclaration(String name, bool isConst) {
-    Keyword constKeyword = isConst ? Keyword.CONST : null;
-    ConstructorDeclaration constructorDeclaration = AstFactory
-        .constructorDeclaration2(
-            constKeyword,
-            null,
-            null,
-            name,
-            AstFactory.formalParameterList(),
-            null,
-            AstFactory.blockFunctionBody2());
-    ClassElement classElement = ElementFactory.classElement2(name);
-    ConstructorElement element =
-        ElementFactory.constructorElement(classElement, name, isConst);
-    constructorDeclaration.element = element;
-    _node = constructorDeclaration;
-    return element;
-  }
-
-  VariableDeclaration _setupFieldDeclaration(
-      String className, String fieldName, Keyword keyword,
-      {bool isInitialized: true,
-      bool isStatic: false,
-      bool hasConstConstructor: false}) {
-    VariableDeclaration variableDeclaration = isInitialized
-        ? AstFactory.variableDeclaration2(fieldName, AstFactory.integer(0))
-        : AstFactory.variableDeclaration(fieldName);
-    VariableElement fieldElement = ElementFactory.fieldElement(
-        fieldName,
-        isStatic,
-        keyword == Keyword.FINAL,
-        keyword == Keyword.CONST,
-        _typeProvider.intType);
-    variableDeclaration.name.staticElement = fieldElement;
-    FieldDeclaration fieldDeclaration = AstFactory.fieldDeclaration2(
-        isStatic, keyword, <VariableDeclaration>[variableDeclaration]);
-    ClassDeclaration classDeclaration =
-        AstFactory.classDeclaration(null, className, null, null, null, null);
-    classDeclaration.members.add(fieldDeclaration);
-    _node = classDeclaration;
-    ClassElementImpl classElement = ElementFactory.classElement2(className);
-    classElement.fields = <FieldElement>[fieldElement];
-    classDeclaration.name.staticElement = classElement;
-    if (hasConstConstructor) {
-      ConstructorDeclaration constructorDeclaration = AstFactory
-          .constructorDeclaration2(
-              Keyword.CONST,
-              null,
-              AstFactory.identifier3(className),
-              null,
-              AstFactory.formalParameterList(),
-              null,
-              AstFactory.blockFunctionBody2());
-      classDeclaration.members.add(constructorDeclaration);
-      ConstructorElement constructorElement =
-          ElementFactory.constructorElement(classElement, '', true);
-      constructorDeclaration.element = constructorElement;
-      classElement.constructors = <ConstructorElement>[constructorElement];
-    } else {
-      classElement.constructors = ConstructorElement.EMPTY_LIST;
-    }
-    return variableDeclaration;
-  }
-
-  VariableElement _setupVariableDeclaration(
-      String name, bool isConst, bool isInitialized,
-      {isFinal: false}) {
-    VariableDeclaration variableDeclaration = isInitialized
-        ? AstFactory.variableDeclaration2(name, AstFactory.integer(0))
-        : AstFactory.variableDeclaration(name);
-    SimpleIdentifier identifier = variableDeclaration.name;
-    VariableElement element = ElementFactory.localVariableElement(identifier);
-    identifier.staticElement = element;
-    Keyword keyword = isConst ? Keyword.CONST : isFinal ? Keyword.FINAL : null;
-    AstFactory.variableDeclarationList2(keyword, [variableDeclaration]);
-    _node = variableDeclaration;
-    return element;
-  }
-}
-
-@reflectiveTest
-class ConstantValueComputerTest extends ResolverTestCase {
-  void test_annotation_constConstructor() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A {
-  final int i;
-  const A(this.i);
-}
-
-class C {
-  @A(5)
-  f() {}
-}
-''');
-    EvaluationResultImpl result =
-        _evaluateAnnotation(compilationUnit, "C", "f");
-    Map<String, DartObjectImpl> annotationFields = _assertType(result, 'A');
-    _assertIntField(annotationFields, 'i', 5);
-  }
-
-  void test_annotation_constConstructor_named() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A {
-  final int i;
-  const A.named(this.i);
-}
-
-class C {
-  @A.named(5)
-  f() {}
-}
-''');
-    EvaluationResultImpl result =
-        _evaluateAnnotation(compilationUnit, "C", "f");
-    Map<String, DartObjectImpl> annotationFields = _assertType(result, 'A');
-    _assertIntField(annotationFields, 'i', 5);
-  }
-
-  void test_annotation_constConstructor_noArgs() {
-    // Failing to pass arguments to an annotation which is a constant
-    // constructor is illegal, but shouldn't crash analysis.
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A {
-  final int i;
-  const A(this.i);
-}
-
-class C {
-  @A
-  f() {}
-}
-''');
-    _evaluateAnnotation(compilationUnit, "C", "f");
-  }
-
-  void test_annotation_constConstructor_noArgs_named() {
-    // Failing to pass arguments to an annotation which is a constant
-    // constructor is illegal, but shouldn't crash analysis.
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A {
-  final int i;
-  const A.named(this.i);
-}
-
-class C {
-  @A.named
-  f() {}
-}
-''');
-    _evaluateAnnotation(compilationUnit, "C", "f");
-  }
-
-  void test_annotation_nonConstConstructor() {
-    // Calling a non-const constructor from an annotation that is illegal, but
-    // shouldn't crash analysis.
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A {
-  final int i;
-  A(this.i);
-}
-
-class C {
-  @A(5)
-  f() {}
-}
-''');
-    _evaluateAnnotation(compilationUnit, "C", "f");
-  }
-
-  void test_annotation_staticConst() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-class C {
-  static const int i = 5;
-
-  @i
-  f() {}
-}
-''');
-    EvaluationResultImpl result =
-        _evaluateAnnotation(compilationUnit, "C", "f");
-    expect(_assertValidInt(result), 5);
-  }
-
-  void test_annotation_staticConst_args() {
-    // Applying arguments to an annotation that is a static const is
-    // illegal, but shouldn't crash analysis.
-    CompilationUnit compilationUnit = resolveSource(r'''
-class C {
-  static const int i = 5;
-
-  @i(1)
-  f() {}
-}
-''');
-    _evaluateAnnotation(compilationUnit, "C", "f");
-  }
-
-  void test_annotation_staticConst_otherClass() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A {
-  static const int i = 5;
-}
-
-class C {
-  @A.i
-  f() {}
-}
-''');
-    EvaluationResultImpl result =
-        _evaluateAnnotation(compilationUnit, "C", "f");
-    expect(_assertValidInt(result), 5);
-  }
-
-  void test_annotation_staticConst_otherClass_args() {
-    // Applying arguments to an annotation that is a static const is
-    // illegal, but shouldn't crash analysis.
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A {
-  static const int i = 5;
-}
-
-class C {
-  @A.i(1)
-  f() {}
-}
-''');
-    _evaluateAnnotation(compilationUnit, "C", "f");
-  }
-
-  void test_annotation_toplevelVariable() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const int i = 5;
-class C {
-  @i
-  f() {}
-}
-''');
-    EvaluationResultImpl result =
-        _evaluateAnnotation(compilationUnit, "C", "f");
-    expect(_assertValidInt(result), 5);
-  }
-
-  void test_annotation_toplevelVariable_args() {
-    // Applying arguments to an annotation that is a toplevel variable is
-    // illegal, but shouldn't crash analysis.
-    CompilationUnit compilationUnit = resolveSource(r'''
-const int i = 5;
-class C {
-  @i(1)
-  f() {}
-}
-''');
-    _evaluateAnnotation(compilationUnit, "C", "f");
-  }
-
-  void test_computeValues_cycle() {
-    TestLogger logger = new TestLogger();
-    AnalysisEngine.instance.logger = logger;
-    try {
-      Source librarySource = addSource(r'''
-  const int a = c;
-  const int b = a;
-  const int c = b;''');
-      LibraryElement libraryElement = resolve2(librarySource);
-      CompilationUnit unit =
-          analysisContext.resolveCompilationUnit(librarySource, libraryElement);
-      analysisContext.computeErrors(librarySource);
-      expect(unit, isNotNull);
-      ConstantValueComputer computer = _makeConstantValueComputer();
-      computer.add(unit, librarySource, librarySource);
-      computer.computeValues();
-      NodeList<CompilationUnitMember> members = unit.declarations;
-      expect(members, hasLength(3));
-      _validate(false, (members[0] as TopLevelVariableDeclaration).variables);
-      _validate(false, (members[1] as TopLevelVariableDeclaration).variables);
-      _validate(false, (members[2] as TopLevelVariableDeclaration).variables);
-    } finally {
-      AnalysisEngine.instance.logger = Logger.NULL;
-    }
-  }
-
-  void test_computeValues_dependentVariables() {
-    Source librarySource = addSource(r'''
-const int b = a;
-const int a = 0;''');
-    LibraryElement libraryElement = resolve2(librarySource);
-    CompilationUnit unit =
-        analysisContext.resolveCompilationUnit(librarySource, libraryElement);
-    expect(unit, isNotNull);
-    ConstantValueComputer computer = _makeConstantValueComputer();
-    computer.add(unit, librarySource, librarySource);
-    computer.computeValues();
-    NodeList<CompilationUnitMember> members = unit.declarations;
-    expect(members, hasLength(2));
-    _validate(true, (members[0] as TopLevelVariableDeclaration).variables);
-    _validate(true, (members[1] as TopLevelVariableDeclaration).variables);
-  }
-
-  void test_computeValues_empty() {
-    ConstantValueComputer computer = _makeConstantValueComputer();
-    computer.computeValues();
-  }
-
-  void test_computeValues_multipleSources() {
-    Source librarySource = addNamedSource(
-        "/lib.dart",
-        r'''
-library lib;
-part 'part.dart';
-const int c = b;
-const int a = 0;''');
-    Source partSource = addNamedSource(
-        "/part.dart",
-        r'''
-part of lib;
-const int b = a;
-const int d = c;''');
-    LibraryElement libraryElement = resolve2(librarySource);
-    CompilationUnit libraryUnit =
-        analysisContext.resolveCompilationUnit(librarySource, libraryElement);
-    expect(libraryUnit, isNotNull);
-    CompilationUnit partUnit =
-        analysisContext.resolveCompilationUnit(partSource, libraryElement);
-    expect(partUnit, isNotNull);
-    ConstantValueComputer computer = _makeConstantValueComputer();
-    computer.add(libraryUnit, librarySource, librarySource);
-    computer.add(partUnit, partSource, librarySource);
-    computer.computeValues();
-    NodeList<CompilationUnitMember> libraryMembers = libraryUnit.declarations;
-    expect(libraryMembers, hasLength(2));
-    _validate(
-        true, (libraryMembers[0] as TopLevelVariableDeclaration).variables);
-    _validate(
-        true, (libraryMembers[1] as TopLevelVariableDeclaration).variables);
-    NodeList<CompilationUnitMember> partMembers = libraryUnit.declarations;
-    expect(partMembers, hasLength(2));
-    _validate(true, (partMembers[0] as TopLevelVariableDeclaration).variables);
-    _validate(true, (partMembers[1] as TopLevelVariableDeclaration).variables);
-  }
-
-  void test_computeValues_singleVariable() {
-    Source librarySource = addSource("const int a = 0;");
-    LibraryElement libraryElement = resolve2(librarySource);
-    CompilationUnit unit =
-        analysisContext.resolveCompilationUnit(librarySource, libraryElement);
-    expect(unit, isNotNull);
-    ConstantValueComputer computer = _makeConstantValueComputer();
-    computer.add(unit, librarySource, librarySource);
-    computer.computeValues();
-    NodeList<CompilationUnitMember> members = unit.declarations;
-    expect(members, hasLength(1));
-    _validate(true, (members[0] as TopLevelVariableDeclaration).variables);
-  }
-
-  void test_computeValues_value_depends_on_enum() {
-    Source librarySource = addSource('''
-enum E { id0, id1 }
-const E e = E.id0;
-''');
-    LibraryElement libraryElement = resolve2(librarySource);
-    CompilationUnit unit =
-        analysisContext.resolveCompilationUnit(librarySource, libraryElement);
-    expect(unit, isNotNull);
-    ConstantValueComputer computer = _makeConstantValueComputer();
-    computer.add(unit, librarySource, librarySource);
-    computer.computeValues();
-    TopLevelVariableDeclaration declaration = unit.declarations
-        .firstWhere((member) => member is TopLevelVariableDeclaration);
-    _validate(true, declaration.variables);
-  }
-
-  void test_dependencyOnConstructor() {
-    // x depends on "const A()"
-    _assertProperDependencies(r'''
-class A {
-  const A();
-}
-const x = const A();''');
-  }
-
-  void test_dependencyOnConstructorArgument() {
-    // "const A(x)" depends on x
-    _assertProperDependencies(r'''
-class A {
-  const A(this.next);
-  final A next;
-}
-const A x = const A(null);
-const A y = const A(x);''');
-  }
-
-  void test_dependencyOnConstructorArgument_unresolvedConstructor() {
-    // "const A.a(x)" depends on x even if the constructor A.a can't be found.
-    _assertProperDependencies(
-        r'''
-class A {
-}
-const int x = 1;
-const A y = const A.a(x);''',
-        [CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR]);
-  }
-
-  void test_dependencyOnConstructorInitializer() {
-    // "const A()" depends on x
-    _assertProperDependencies(r'''
-const int x = 1;
-class A {
-  const A() : v = x;
-  final int v;
-}''');
-  }
-
-  void test_dependencyOnExplicitSuperConstructor() {
-    // b depends on B() depends on A()
-    _assertProperDependencies(r'''
-class A {
-  const A(this.x);
-  final int x;
-}
-class B extends A {
-  const B() : super(5);
-}
-const B b = const B();''');
-  }
-
-  void test_dependencyOnExplicitSuperConstructorParameters() {
-    // b depends on B() depends on i
-    _assertProperDependencies(r'''
-class A {
-  const A(this.x);
-  final int x;
-}
-class B extends A {
-  const B() : super(i);
-}
-const B b = const B();
-const int i = 5;''');
-  }
-
-  void test_dependencyOnFactoryRedirect() {
-    // a depends on A.foo() depends on A.bar()
-    _assertProperDependencies(r'''
-const A a = const A.foo();
-class A {
-  factory const A.foo() = A.bar;
-  const A.bar();
-}''');
-  }
-
-  void test_dependencyOnFactoryRedirectWithTypeParams() {
-    _assertProperDependencies(r'''
-class A {
-  const factory A(var a) = B<int>;
-}
-
-class B<T> implements A {
-  final T x;
-  const B(this.x);
-}
-
-const A a = const A(10);''');
-  }
-
-  void test_dependencyOnImplicitSuperConstructor() {
-    // b depends on B() depends on A()
-    _assertProperDependencies(r'''
-class A {
-  const A() : x = 5;
-  final int x;
-}
-class B extends A {
-  const B();
-}
-const B b = const B();''');
-  }
-
-  void test_dependencyOnInitializedFinal() {
-    // a depends on A() depends on A.x
-    _assertProperDependencies('''
-class A {
-  const A();
-  final int x = 1;
-}
-const A a = const A();
-''');
-  }
-
-  void test_dependencyOnInitializedNonStaticConst() {
-    // Even though non-static consts are not allowed by the language, we need
-    // to handle them for error recovery purposes.
-    // a depends on A() depends on A.x
-    _assertProperDependencies(
-        '''
-class A {
-  const A();
-  const int x = 1;
-}
-const A a = const A();
-''',
-        [CompileTimeErrorCode.CONST_INSTANCE_FIELD]);
-  }
-
-  void test_dependencyOnNonFactoryRedirect() {
-    // a depends on A.foo() depends on A.bar()
-    _assertProperDependencies(r'''
-const A a = const A.foo();
-class A {
-  const A.foo() : this.bar();
-  const A.bar();
-}''');
-  }
-
-  void test_dependencyOnNonFactoryRedirect_arg() {
-    // a depends on A.foo() depends on b
-    _assertProperDependencies(r'''
-const A a = const A.foo();
-const int b = 1;
-class A {
-  const A.foo() : this.bar(b);
-  const A.bar(x) : y = x;
-  final int y;
-}''');
-  }
-
-  void test_dependencyOnNonFactoryRedirect_defaultValue() {
-    // a depends on A.foo() depends on A.bar() depends on b
-    _assertProperDependencies(r'''
-const A a = const A.foo();
-const int b = 1;
-class A {
-  const A.foo() : this.bar();
-  const A.bar([x = b]) : y = x;
-  final int y;
-}''');
-  }
-
-  void test_dependencyOnNonFactoryRedirect_toMissing() {
-    // a depends on A.foo() which depends on nothing, since A.bar() is
-    // missing.
-    _assertProperDependencies(
-        r'''
-const A a = const A.foo();
-class A {
-  const A.foo() : this.bar();
-}''',
-        [CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR]);
-  }
-
-  void test_dependencyOnNonFactoryRedirect_toNonConst() {
-    // a depends on A.foo() which depends on nothing, since A.bar() is
-    // non-const.
-    _assertProperDependencies(r'''
-const A a = const A.foo();
-class A {
-  const A.foo() : this.bar();
-  A.bar();
-}''');
-  }
-
-  void test_dependencyOnNonFactoryRedirect_unnamed() {
-    // a depends on A.foo() depends on A()
-    _assertProperDependencies(r'''
-const A a = const A.foo();
-class A {
-  const A.foo() : this();
-  const A();
-}''');
-  }
-
-  void test_dependencyOnOptionalParameterDefault() {
-    // a depends on A() depends on B()
-    _assertProperDependencies(r'''
-class A {
-  const A([x = const B()]) : b = x;
-  final B b;
-}
-class B {
-  const B();
-}
-const A a = const A();''');
-  }
-
-  void test_dependencyOnVariable() {
-    // x depends on y
-    _assertProperDependencies(r'''
-const x = y + 1;
-const y = 2;''');
-  }
-
-  void test_final_initialized_at_declaration() {
-    CompilationUnit compilationUnit = resolveSource('''
-class A {
-  final int i = 123;
-  const A();
-}
-
-const A a = const A();
-''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, 'a');
-    Map<String, DartObjectImpl> fields = _assertType(result, "A");
-    expect(fields, hasLength(1));
-    _assertIntField(fields, "i", 123);
-  }
-
-  void test_fromEnvironment_bool_default_false() {
-    expect(_assertValidBool(_check_fromEnvironment_bool(null, "false")), false);
-  }
-
-  void test_fromEnvironment_bool_default_overridden() {
-    expect(
-        _assertValidBool(_check_fromEnvironment_bool("false", "true")), false);
-  }
-
-  void test_fromEnvironment_bool_default_parseError() {
-    expect(_assertValidBool(_check_fromEnvironment_bool("parseError", "true")),
-        true);
-  }
-
-  void test_fromEnvironment_bool_default_true() {
-    expect(_assertValidBool(_check_fromEnvironment_bool(null, "true")), true);
-  }
-
-  void test_fromEnvironment_bool_false() {
-    expect(_assertValidBool(_check_fromEnvironment_bool("false", null)), false);
-  }
-
-  void test_fromEnvironment_bool_parseError() {
-    expect(_assertValidBool(_check_fromEnvironment_bool("parseError", null)),
-        false);
-  }
-
-  void test_fromEnvironment_bool_true() {
-    expect(_assertValidBool(_check_fromEnvironment_bool("true", null)), true);
-  }
-
-  void test_fromEnvironment_bool_undeclared() {
-    _assertValidUnknown(_check_fromEnvironment_bool(null, null));
-  }
-
-  void test_fromEnvironment_int_default_overridden() {
-    expect(_assertValidInt(_check_fromEnvironment_int("234", "123")), 234);
-  }
-
-  void test_fromEnvironment_int_default_parseError() {
-    expect(
-        _assertValidInt(_check_fromEnvironment_int("parseError", "123")), 123);
-  }
-
-  void test_fromEnvironment_int_default_undeclared() {
-    expect(_assertValidInt(_check_fromEnvironment_int(null, "123")), 123);
-  }
-
-  void test_fromEnvironment_int_ok() {
-    expect(_assertValidInt(_check_fromEnvironment_int("234", null)), 234);
-  }
-
-  void test_fromEnvironment_int_parseError() {
-    _assertValidNull(_check_fromEnvironment_int("parseError", null));
-  }
-
-  void test_fromEnvironment_int_parseError_nullDefault() {
-    _assertValidNull(_check_fromEnvironment_int("parseError", "null"));
-  }
-
-  void test_fromEnvironment_int_undeclared() {
-    _assertValidUnknown(_check_fromEnvironment_int(null, null));
-  }
-
-  void test_fromEnvironment_int_undeclared_nullDefault() {
-    _assertValidNull(_check_fromEnvironment_int(null, "null"));
-  }
-
-  void test_fromEnvironment_string_default_overridden() {
-    expect(_assertValidString(_check_fromEnvironment_string("abc", "'def'")),
-        "abc");
-  }
-
-  void test_fromEnvironment_string_default_undeclared() {
-    expect(_assertValidString(_check_fromEnvironment_string(null, "'def'")),
-        "def");
-  }
-
-  void test_fromEnvironment_string_empty() {
-    expect(_assertValidString(_check_fromEnvironment_string("", null)), "");
-  }
-
-  void test_fromEnvironment_string_ok() {
-    expect(
-        _assertValidString(_check_fromEnvironment_string("abc", null)), "abc");
-  }
-
-  void test_fromEnvironment_string_undeclared() {
-    _assertValidUnknown(_check_fromEnvironment_string(null, null));
-  }
-
-  void test_fromEnvironment_string_undeclared_nullDefault() {
-    _assertValidNull(_check_fromEnvironment_string(null, "null"));
-  }
-
-  void test_instanceCreationExpression_computedField() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(4, 5);
-class A {
-  const A(int i, int j) : k = 2 * i + j;
-  final int k;
-}''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "foo");
-    Map<String, DartObjectImpl> fields = _assertType(result, "A");
-    expect(fields, hasLength(1));
-    _assertIntField(fields, "k", 13);
-  }
-
-  void test_instanceCreationExpression_computedField_namedOptionalWithDefault() {
-    _checkInstanceCreationOptionalParams(false, true, true);
-  }
-
-  void test_instanceCreationExpression_computedField_namedOptionalWithoutDefault() {
-    _checkInstanceCreationOptionalParams(false, true, false);
-  }
-
-  void test_instanceCreationExpression_computedField_unnamedOptionalWithDefault() {
-    _checkInstanceCreationOptionalParams(false, false, true);
-  }
-
-  void test_instanceCreationExpression_computedField_unnamedOptionalWithoutDefault() {
-    _checkInstanceCreationOptionalParams(false, false, false);
-  }
-
-  void test_instanceCreationExpression_computedField_usesConstConstructor() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(3);
-class A {
-  const A(int i) : b = const B(4);
-  final int b;
-}
-class B {
-  const B(this.k);
-  final int k;
-}''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "foo");
-    Map<String, DartObjectImpl> fieldsOfA = _assertType(result, "A");
-    expect(fieldsOfA, hasLength(1));
-    Map<String, DartObjectImpl> fieldsOfB =
-        _assertFieldType(fieldsOfA, "b", "B");
-    expect(fieldsOfB, hasLength(1));
-    _assertIntField(fieldsOfB, "k", 4);
-  }
-
-  void test_instanceCreationExpression_computedField_usesStaticConst() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(3);
-class A {
-  const A(int i) : k = i + B.bar;
-  final int k;
-}
-class B {
-  static const bar = 4;
-}''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "foo");
-    Map<String, DartObjectImpl> fields = _assertType(result, "A");
-    expect(fields, hasLength(1));
-    _assertIntField(fields, "k", 7);
-  }
-
-  void test_instanceCreationExpression_computedField_usesToplevelConst() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(3);
-const bar = 4;
-class A {
-  const A(int i) : k = i + bar;
-  final int k;
-}''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "foo");
-    Map<String, DartObjectImpl> fields = _assertType(result, "A");
-    expect(fields, hasLength(1));
-    _assertIntField(fields, "k", 7);
-  }
-
-  void test_instanceCreationExpression_explicitSuper() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const B(4, 5);
-class A {
-  const A(this.x);
-  final int x;
-}
-class B extends A {
-  const B(int x, this.y) : super(x * 2);
-  final int y;
-}''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "foo");
-    Map<String, DartObjectImpl> fields = _assertType(result, "B");
-    expect(fields, hasLength(2));
-    _assertIntField(fields, "y", 5);
-    Map<String, DartObjectImpl> superclassFields =
-        _assertFieldType(fields, GenericState.SUPERCLASS_FIELD, "A");
-    expect(superclassFields, hasLength(1));
-    _assertIntField(superclassFields, "x", 8);
-  }
-
-  void test_instanceCreationExpression_fieldFormalParameter() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A(42);
-class A {
-  int x;
-  const A(this.x)
-}''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "foo");
-    Map<String, DartObjectImpl> fields = _assertType(result, "A");
-    expect(fields, hasLength(1));
-    _assertIntField(fields, "x", 42);
-  }
-
-  void test_instanceCreationExpression_fieldFormalParameter_namedOptionalWithDefault() {
-    _checkInstanceCreationOptionalParams(true, true, true);
-  }
-
-  void test_instanceCreationExpression_fieldFormalParameter_namedOptionalWithoutDefault() {
-    _checkInstanceCreationOptionalParams(true, true, false);
-  }
-
-  void test_instanceCreationExpression_fieldFormalParameter_unnamedOptionalWithDefault() {
-    _checkInstanceCreationOptionalParams(true, false, true);
-  }
-
-  void test_instanceCreationExpression_fieldFormalParameter_unnamedOptionalWithoutDefault() {
-    _checkInstanceCreationOptionalParams(true, false, false);
-  }
-
-  void test_instanceCreationExpression_implicitSuper() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const B(4);
-class A {
-  const A() : x = 3;
-  final int x;
-}
-class B extends A {
-  const B(this.y);
-  final int y;
-}''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "foo");
-    Map<String, DartObjectImpl> fields = _assertType(result, "B");
-    expect(fields, hasLength(2));
-    _assertIntField(fields, "y", 4);
-    Map<String, DartObjectImpl> superclassFields =
-        _assertFieldType(fields, GenericState.SUPERCLASS_FIELD, "A");
-    expect(superclassFields, hasLength(1));
-    _assertIntField(superclassFields, "x", 3);
-  }
-
-  void test_instanceCreationExpression_nonFactoryRedirect() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
-  const A.a1() : this.a2();
-  const A.a2() : x = 5;
-  final int x;
-}''');
-    Map<String, DartObjectImpl> aFields =
-        _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
-    _assertIntField(aFields, 'x', 5);
-  }
-
-  void test_instanceCreationExpression_nonFactoryRedirect_arg() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1(1);
-class A {
-  const A.a1(x) : this.a2(x + 100);
-  const A.a2(x) : y = x + 10;
-  final int y;
-}''');
-    Map<String, DartObjectImpl> aFields =
-        _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
-    _assertIntField(aFields, 'y', 111);
-  }
-
-  void test_instanceCreationExpression_nonFactoryRedirect_cycle() {
-    // It is an error to have a cycle in non-factory redirects; however, we
-    // need to make sure that even if the error occurs, attempting to evaluate
-    // the constant will terminate.
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
-  const A() : this.b();
-  const A.b() : this();
-}''');
-    _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
-  }
-
-  void test_instanceCreationExpression_nonFactoryRedirect_defaultArg() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
-  const A.a1() : this.a2();
-  const A.a2([x = 100]) : y = x + 10;
-  final int y;
-}''');
-    Map<String, DartObjectImpl> aFields =
-        _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
-    _assertIntField(aFields, 'y', 110);
-  }
-
-  void test_instanceCreationExpression_nonFactoryRedirect_toMissing() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
-  const A.a1() : this.a2();
-}''');
-    // We don't care what value foo evaluates to (since there is a compile
-    // error), but we shouldn't crash, and we should figure
-    // out that it evaluates to an instance of class A.
-    _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
-  }
-
-  void test_instanceCreationExpression_nonFactoryRedirect_toNonConst() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
-  const A.a1() : this.a2();
-  A.a2();
-}''');
-    // We don't care what value foo evaluates to (since there is a compile
-    // error), but we shouldn't crash, and we should figure
-    // out that it evaluates to an instance of class A.
-    _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
-  }
-
-  void test_instanceCreationExpression_nonFactoryRedirect_unnamed() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A.a1();
-class A {
-  const A.a1() : this();
-  const A() : x = 5;
-  final int x;
-}''');
-    Map<String, DartObjectImpl> aFields =
-        _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
-    _assertIntField(aFields, 'x', 5);
-  }
-
-  void test_instanceCreationExpression_redirect() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
-  const factory A() = B;
-}
-class B implements A {
-  const B();
-}''');
-    _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "B");
-  }
-
-  void test_instanceCreationExpression_redirect_cycle() {
-    // It is an error to have a cycle in factory redirects; however, we need
-    // to make sure that even if the error occurs, attempting to evaluate the
-    // constant will terminate.
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
-  const factory A() = A.b;
-  const factory A.b() = A;
-}''');
-    _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
-  }
-
-  void test_instanceCreationExpression_redirect_extern() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
-  external const factory A();
-}''');
-    _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
-  }
-
-  void test_instanceCreationExpression_redirect_nonConst() {
-    // It is an error for a const factory constructor redirect to a non-const
-    // constructor; however, we need to make sure that even if the error
-    // attempting to evaluate the constant won't cause a crash.
-    CompilationUnit compilationUnit = resolveSource(r'''
-const foo = const A();
-class A {
-  const factory A() = A.b;
-  A.b();
-}''');
-    _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
-  }
-
-  void test_instanceCreationExpression_redirectWithTypeParams() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A {
-  const factory A(var a) = B<int>;
-}
-
-class B<T> implements A {
-  final T x;
-  const B(this.x);
-}
-
-const A a = const A(10);''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "a");
-    Map<String, DartObjectImpl> fields = _assertType(result, "B<int>");
-    expect(fields, hasLength(1));
-    _assertIntField(fields, "x", 10);
-  }
-
-  void test_instanceCreationExpression_redirectWithTypeSubstitution() {
-    // To evaluate the redirection of A<int>,
-    // A's template argument (T=int) must be substituted
-    // into B's template argument (B<U> where U=T) to get B<int>.
-    CompilationUnit compilationUnit = resolveSource(r'''
-class A<T> {
-  const factory A(var a) = B<T>;
-}
-
-class B<U> implements A {
-  final U x;
-  const B(this.x);
-}
-
-const A<int> a = const A<int>(10);''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, "a");
-    Map<String, DartObjectImpl> fields = _assertType(result, "B<int>");
-    expect(fields, hasLength(1));
-    _assertIntField(fields, "x", 10);
-  }
-
-  void test_instanceCreationExpression_symbol() {
-    CompilationUnit compilationUnit =
-        resolveSource("const foo = const Symbol('a');");
-    EvaluationResultImpl evaluationResult =
-        _evaluateTopLevelVariable(compilationUnit, "foo");
-    expect(evaluationResult.value, isNotNull);
-    DartObjectImpl value = evaluationResult.value;
-    expect(value.type, typeProvider.symbolType);
-    expect(value.toSymbolValue(), "a");
-  }
-
-  void test_instanceCreationExpression_withSupertypeParams_explicit() {
-    _checkInstanceCreation_withSupertypeParams(true);
-  }
-
-  void test_instanceCreationExpression_withSupertypeParams_implicit() {
-    _checkInstanceCreation_withSupertypeParams(false);
-  }
-
-  void test_instanceCreationExpression_withTypeParams() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-class C<E> {
-  const C();
-}
-const c_int = const C<int>();
-const c_num = const C<num>();''');
-    EvaluationResultImpl c_int =
-        _evaluateTopLevelVariable(compilationUnit, "c_int");
-    _assertType(c_int, "C<int>");
-    DartObjectImpl c_int_value = c_int.value;
-    EvaluationResultImpl c_num =
-        _evaluateTopLevelVariable(compilationUnit, "c_num");
-    _assertType(c_num, "C<num>");
-    DartObjectImpl c_num_value = c_num.value;
-    expect(c_int_value == c_num_value, isFalse);
-  }
-
-  void test_isValidSymbol() {
-    expect(ConstantEvaluationEngine.isValidPublicSymbol(""), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.bar"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo\$"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo\$bar"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("iff"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("gif"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("if\$"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("\$if"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo="), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.bar="), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.+"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("void"), isTrue);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("_foo"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("_foo.bar"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo._bar"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("if"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("if.foo"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.if"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo=.bar"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo."), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("+.foo"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("void.foo"), isFalse);
-    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.void"), isFalse);
-  }
-
-  void test_length_of_improperly_typed_string_expression() {
-    // Since type annotations are ignored in unchecked mode, the improper
-    // types on s1 and s2 shouldn't prevent us from evaluating i to
-    // 'alpha'.length.
-    CompilationUnit compilationUnit = resolveSource('''
-const int s1 = 'alpha';
-const int s2 = 'beta';
-const int i = (true ? s1 : s2).length;
-''');
-    ConstTopLevelVariableElementImpl element =
-        findTopLevelDeclaration(compilationUnit, 'i').element;
-    EvaluationResultImpl result = element.evaluationResult;
-    expect(_assertValidInt(result), 5);
-  }
-
-  void test_length_of_improperly_typed_string_identifier() {
-    // Since type annotations are ignored in unchecked mode, the improper type
-    // on s shouldn't prevent us from evaluating i to 'alpha'.length.
-    CompilationUnit compilationUnit = resolveSource('''
-const int s = 'alpha';
-const int i = s.length;
-''');
-    ConstTopLevelVariableElementImpl element =
-        findTopLevelDeclaration(compilationUnit, 'i').element;
-    EvaluationResultImpl result = element.evaluationResult;
-    expect(_assertValidInt(result), 5);
-  }
-
-  void test_non_static_const_initialized_at_declaration() {
-    // Even though non-static consts are not allowed by the language, we need
-    // to handle them for error recovery purposes.
-    CompilationUnit compilationUnit = resolveSource('''
-class A {
-  const int i = 123;
-  const A();
-}
-
-const A a = const A();
-''');
-    EvaluationResultImpl result =
-        _evaluateTopLevelVariable(compilationUnit, 'a');
-    Map<String, DartObjectImpl> fields = _assertType(result, "A");
-    expect(fields, hasLength(1));
-    _assertIntField(fields, "i", 123);
-  }
-
-  void test_symbolLiteral_void() {
-    CompilationUnit compilationUnit =
-        resolveSource("const voidSymbol = #void;");
-    VariableDeclaration voidSymbol =
-        findTopLevelDeclaration(compilationUnit, "voidSymbol");
-    EvaluationResultImpl voidSymbolResult =
-        (voidSymbol.element as VariableElementImpl).evaluationResult;
-    DartObjectImpl value = voidSymbolResult.value;
-    expect(value.type, typeProvider.symbolType);
-    expect(value.toSymbolValue(), "void");
-  }
-
-  Map<String, DartObjectImpl> _assertFieldType(
-      Map<String, DartObjectImpl> fields,
-      String fieldName,
-      String expectedType) {
-    DartObjectImpl field = fields[fieldName];
-    expect(field.type.displayName, expectedType);
-    return field.fields;
-  }
-
-  void _assertIntField(
-      Map<String, DartObjectImpl> fields, String fieldName, int expectedValue) {
-    DartObjectImpl field = fields[fieldName];
-    expect(field.type.name, "int");
-    expect(field.toIntValue(), expectedValue);
-  }
-
-  void _assertNullField(Map<String, DartObjectImpl> fields, String fieldName) {
-    DartObjectImpl field = fields[fieldName];
-    expect(field.isNull, isTrue);
-  }
-
-  void _assertProperDependencies(String sourceText,
-      [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
-    Source source = addSource(sourceText);
-    LibraryElement element = resolve2(source);
-    CompilationUnit unit =
-        analysisContext.resolveCompilationUnit(source, element);
-    expect(unit, isNotNull);
-    ConstantValueComputer computer = _makeConstantValueComputer();
-    computer.add(unit, source, source);
-    computer.computeValues();
-    assertErrors(source, expectedErrorCodes);
-  }
-
-  Map<String, DartObjectImpl> _assertType(
-      EvaluationResultImpl result, String typeName) {
-    expect(result.value, isNotNull);
-    DartObjectImpl value = result.value;
-    expect(value.type.displayName, typeName);
-    return value.fields;
-  }
-
-  bool _assertValidBool(EvaluationResultImpl result) {
-    expect(result.value, isNotNull);
-    DartObjectImpl value = result.value;
-    expect(value.type, typeProvider.boolType);
-    bool boolValue = value.toBoolValue();
-    expect(boolValue, isNotNull);
-    return boolValue;
-  }
-
-  int _assertValidInt(EvaluationResultImpl result) {
-    expect(result.value, isNotNull);
-    DartObjectImpl value = result.value;
-    expect(value.type, typeProvider.intType);
-    return value.toIntValue();
-  }
-
-  void _assertValidNull(EvaluationResultImpl result) {
-    expect(result.value, isNotNull);
-    DartObjectImpl value = result.value;
-    expect(value.type, typeProvider.nullType);
-  }
-
-  String _assertValidString(EvaluationResultImpl result) {
-    expect(result.value, isNotNull);
-    DartObjectImpl value = result.value;
-    expect(value.type, typeProvider.stringType);
-    return value.toStringValue();
-  }
-
-  void _assertValidUnknown(EvaluationResultImpl result) {
-    expect(result.value, isNotNull);
-    DartObjectImpl value = result.value;
-    expect(value.isUnknown, isTrue);
-  }
-
-  EvaluationResultImpl _check_fromEnvironment_bool(
-      String valueInEnvironment, String defaultExpr) {
-    String envVarName = "x";
-    String varName = "foo";
-    if (valueInEnvironment != null) {
-      analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
-    }
-    String defaultArg =
-        defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
-    CompilationUnit compilationUnit = resolveSource(
-        "const $varName = const bool.fromEnvironment('$envVarName'$defaultArg);");
-    return _evaluateTopLevelVariable(compilationUnit, varName);
-  }
-
-  EvaluationResultImpl _check_fromEnvironment_int(
-      String valueInEnvironment, String defaultExpr) {
-    String envVarName = "x";
-    String varName = "foo";
-    if (valueInEnvironment != null) {
-      analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
-    }
-    String defaultArg =
-        defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
-    CompilationUnit compilationUnit = resolveSource(
-        "const $varName = const int.fromEnvironment('$envVarName'$defaultArg);");
-    return _evaluateTopLevelVariable(compilationUnit, varName);
-  }
-
-  EvaluationResultImpl _check_fromEnvironment_string(
-      String valueInEnvironment, String defaultExpr) {
-    String envVarName = "x";
-    String varName = "foo";
-    if (valueInEnvironment != null) {
-      analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
-    }
-    String defaultArg =
-        defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
-    CompilationUnit compilationUnit = resolveSource(
-        "const $varName = const String.fromEnvironment('$envVarName'$defaultArg);");
-    return _evaluateTopLevelVariable(compilationUnit, varName);
-  }
-
-  void _checkInstanceCreation_withSupertypeParams(bool isExplicit) {
-    String superCall = isExplicit ? " : super()" : "";
-    CompilationUnit compilationUnit = resolveSource("""
-class A<T> {
-  const A();
-}
-class B<T, U> extends A<T> {
-  const B()$superCall;
-}
-class C<T, U> extends A<U> {
-  const C()$superCall;
-}
-const b_int_num = const B<int, num>();
-const c_int_num = const C<int, num>();""");
-    EvaluationResultImpl b_int_num =
-        _evaluateTopLevelVariable(compilationUnit, "b_int_num");
-    Map<String, DartObjectImpl> b_int_num_fields =
-        _assertType(b_int_num, "B<int, num>");
-    _assertFieldType(b_int_num_fields, GenericState.SUPERCLASS_FIELD, "A<int>");
-    EvaluationResultImpl c_int_num =
-        _evaluateTopLevelVariable(compilationUnit, "c_int_num");
-    Map<String, DartObjectImpl> c_int_num_fields =
-        _assertType(c_int_num, "C<int, num>");
-    _assertFieldType(c_int_num_fields, GenericState.SUPERCLASS_FIELD, "A<num>");
-  }
-
-  void _checkInstanceCreationOptionalParams(
-      bool isFieldFormal, bool isNamed, bool hasDefault) {
-    String fieldName = "j";
-    String paramName = isFieldFormal ? fieldName : "i";
-    String formalParam =
-        "${isFieldFormal ? "this." : "int "}$paramName${hasDefault ? " = 3" : ""}";
-    CompilationUnit compilationUnit = resolveSource("""
-const x = const A();
-const y = const A(${isNamed ? '$paramName: ' : ''}10);
-class A {
-  const A(${isNamed ? "{$formalParam}" : "[$formalParam]"})${isFieldFormal ? "" : " : $fieldName = $paramName"};
-  final int $fieldName;
-}""");
-    EvaluationResultImpl x = _evaluateTopLevelVariable(compilationUnit, "x");
-    Map<String, DartObjectImpl> fieldsOfX = _assertType(x, "A");
-    expect(fieldsOfX, hasLength(1));
-    if (hasDefault) {
-      _assertIntField(fieldsOfX, fieldName, 3);
-    } else {
-      _assertNullField(fieldsOfX, fieldName);
-    }
-    EvaluationResultImpl y = _evaluateTopLevelVariable(compilationUnit, "y");
-    Map<String, DartObjectImpl> fieldsOfY = _assertType(y, "A");
-    expect(fieldsOfY, hasLength(1));
-    _assertIntField(fieldsOfY, fieldName, 10);
-  }
-
-  /**
-   * Search [compilationUnit] for a class named [className], containing a
-   * method [methodName], with exactly one annotation.  Return the constant
-   * value of the annotation.
-   */
-  EvaluationResultImpl _evaluateAnnotation(
-      CompilationUnit compilationUnit, String className, String memberName) {
-    for (CompilationUnitMember member in compilationUnit.declarations) {
-      if (member is ClassDeclaration && member.name.name == className) {
-        for (ClassMember classMember in member.members) {
-          if (classMember is MethodDeclaration &&
-              classMember.name.name == memberName) {
-            expect(classMember.metadata, hasLength(1));
-            ElementAnnotationImpl elementAnnotation =
-                classMember.metadata[0].elementAnnotation;
-            return elementAnnotation.evaluationResult;
-          }
-        }
-      }
-    }
-    fail('Class member not found');
-    return null;
-  }
-
-  EvaluationResultImpl _evaluateTopLevelVariable(
-      CompilationUnit compilationUnit, String name) {
-    VariableDeclaration varDecl =
-        findTopLevelDeclaration(compilationUnit, name);
-    ConstTopLevelVariableElementImpl varElement = varDecl.element;
-    return varElement.evaluationResult;
-  }
-
-  ConstantValueComputer _makeConstantValueComputer() {
-    ConstantEvaluationValidator_ForTest validator =
-        new ConstantEvaluationValidator_ForTest();
-    validator.computer = new ConstantValueComputer(
-        analysisContext2,
-        analysisContext2.typeProvider,
-        analysisContext2.declaredVariables,
-        validator,
-        analysisContext2.typeSystem);
-    return validator.computer;
-  }
-
-  void _validate(bool shouldBeValid, VariableDeclarationList declarationList) {
-    for (VariableDeclaration declaration in declarationList.variables) {
-      VariableElementImpl element = declaration.element as VariableElementImpl;
-      expect(element, isNotNull);
-      EvaluationResultImpl result = element.evaluationResult;
-      if (shouldBeValid) {
-        expect(result.value, isNotNull);
-      } else {
-        expect(result.value, isNull);
-      }
-    }
-  }
-}
-
-@reflectiveTest
-class ConstantVisitorTest extends ResolverTestCase {
-  void test_visitConditionalExpression_false() {
-    Expression thenExpression = AstFactory.integer(1);
-    Expression elseExpression = AstFactory.integer(0);
-    ConditionalExpression expression = AstFactory.conditionalExpression(
-        AstFactory.booleanLiteral(false), thenExpression, elseExpression);
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ErrorReporter errorReporter =
-        new ErrorReporter(errorListener, _dummySource());
-    _assertValue(
-        0,
-        expression.accept(new ConstantVisitor(
-            new ConstantEvaluationEngine(
-                new TestTypeProvider(), new DeclaredVariables(),
-                typeSystem: new TypeSystemImpl()),
-            errorReporter)));
-    errorListener.assertNoErrors();
-  }
-
-  void test_visitConditionalExpression_nonBooleanCondition() {
-    Expression thenExpression = AstFactory.integer(1);
-    Expression elseExpression = AstFactory.integer(0);
-    NullLiteral conditionExpression = AstFactory.nullLiteral();
-    ConditionalExpression expression = AstFactory.conditionalExpression(
-        conditionExpression, thenExpression, elseExpression);
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ErrorReporter errorReporter =
-        new ErrorReporter(errorListener, _dummySource());
-    DartObjectImpl result = expression.accept(new ConstantVisitor(
-        new ConstantEvaluationEngine(
-            new TestTypeProvider(), new DeclaredVariables(),
-            typeSystem: new TypeSystemImpl()),
-        errorReporter));
-    expect(result, isNull);
-    errorListener
-        .assertErrorsWithCodes([CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL]);
-  }
-
-  void test_visitConditionalExpression_nonConstantElse() {
-    Expression thenExpression = AstFactory.integer(1);
-    Expression elseExpression = AstFactory.identifier3("x");
-    ConditionalExpression expression = AstFactory.conditionalExpression(
-        AstFactory.booleanLiteral(true), thenExpression, elseExpression);
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ErrorReporter errorReporter =
-        new ErrorReporter(errorListener, _dummySource());
-    DartObjectImpl result = expression.accept(new ConstantVisitor(
-        new ConstantEvaluationEngine(
-            new TestTypeProvider(), new DeclaredVariables(),
-            typeSystem: new TypeSystemImpl()),
-        errorReporter));
-    expect(result, isNull);
-    errorListener
-        .assertErrorsWithCodes([CompileTimeErrorCode.INVALID_CONSTANT]);
-  }
-
-  void test_visitConditionalExpression_nonConstantThen() {
-    Expression thenExpression = AstFactory.identifier3("x");
-    Expression elseExpression = AstFactory.integer(0);
-    ConditionalExpression expression = AstFactory.conditionalExpression(
-        AstFactory.booleanLiteral(true), thenExpression, elseExpression);
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ErrorReporter errorReporter =
-        new ErrorReporter(errorListener, _dummySource());
-    DartObjectImpl result = expression.accept(new ConstantVisitor(
-        new ConstantEvaluationEngine(
-            new TestTypeProvider(), new DeclaredVariables(),
-            typeSystem: new TypeSystemImpl()),
-        errorReporter));
-    expect(result, isNull);
-    errorListener
-        .assertErrorsWithCodes([CompileTimeErrorCode.INVALID_CONSTANT]);
-  }
-
-  void test_visitConditionalExpression_true() {
-    Expression thenExpression = AstFactory.integer(1);
-    Expression elseExpression = AstFactory.integer(0);
-    ConditionalExpression expression = AstFactory.conditionalExpression(
-        AstFactory.booleanLiteral(true), thenExpression, elseExpression);
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ErrorReporter errorReporter =
-        new ErrorReporter(errorListener, _dummySource());
-    _assertValue(
-        1,
-        expression.accept(new ConstantVisitor(
-            new ConstantEvaluationEngine(
-                new TestTypeProvider(), new DeclaredVariables(),
-                typeSystem: new TypeSystemImpl()),
-            errorReporter)));
-    errorListener.assertNoErrors();
-  }
-
-  void test_visitSimpleIdentifier_className() {
-    CompilationUnit compilationUnit = resolveSource('''
-const a = C;
-class C {}
-''');
-    DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
-    expect(result.type, typeProvider.typeType);
-    expect(result.toTypeValue().name, 'C');
-  }
-
-  void test_visitSimpleIdentifier_dynamic() {
-    CompilationUnit compilationUnit = resolveSource('''
-const a = dynamic;
-''');
-    DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
-    expect(result.type, typeProvider.typeType);
-    expect(result.toTypeValue(), typeProvider.dynamicType);
-  }
-
-  void test_visitSimpleIdentifier_inEnvironment() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const a = b;
-const b = 3;''');
-    Map<String, DartObjectImpl> environment = new Map<String, DartObjectImpl>();
-    DartObjectImpl six =
-        new DartObjectImpl(typeProvider.intType, new IntState(6));
-    environment["b"] = six;
-    _assertValue(6, _evaluateConstant(compilationUnit, "a", environment));
-  }
-
-  void test_visitSimpleIdentifier_notInEnvironment() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const a = b;
-const b = 3;''');
-    Map<String, DartObjectImpl> environment = new Map<String, DartObjectImpl>();
-    DartObjectImpl six =
-        new DartObjectImpl(typeProvider.intType, new IntState(6));
-    environment["c"] = six;
-    _assertValue(3, _evaluateConstant(compilationUnit, "a", environment));
-  }
-
-  void test_visitSimpleIdentifier_withoutEnvironment() {
-    CompilationUnit compilationUnit = resolveSource(r'''
-const a = b;
-const b = 3;''');
-    _assertValue(3, _evaluateConstant(compilationUnit, "a", null));
-  }
-
-  void _assertValue(int expectedValue, DartObjectImpl result) {
-    expect(result, isNotNull);
-    expect(result.type.name, "int");
-    expect(result.toIntValue(), expectedValue);
-  }
-
-  NonExistingSource _dummySource() {
-    String path = '/test.dart';
-    return new NonExistingSource(path, toUri(path), UriKind.FILE_URI);
-  }
-
-  DartObjectImpl _evaluateConstant(CompilationUnit compilationUnit, String name,
-      Map<String, DartObjectImpl> lexicalEnvironment) {
-    Source source = compilationUnit.element.source;
-    Expression expression =
-        findTopLevelConstantExpression(compilationUnit, name);
-    GatheringErrorListener errorListener = new GatheringErrorListener();
-    ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
-    DartObjectImpl result = expression.accept(new ConstantVisitor(
-        new ConstantEvaluationEngine(typeProvider, new DeclaredVariables(),
-            typeSystem: typeSystem),
-        errorReporter,
-        lexicalEnvironment: lexicalEnvironment));
-    errorListener.assertNoErrors();
-    return result;
-  }
-}
-
 @reflectiveTest
 class ContentCacheTest {
   void test_setContents() {
@@ -2220,2130 +103,6 @@
 }
 
 @reflectiveTest
-class DartObjectImplTest extends EngineTestCase {
-  TypeProvider _typeProvider = new TestTypeProvider();
-
-  void test_add_knownDouble_knownDouble() {
-    _assertAdd(_doubleValue(3.0), _doubleValue(1.0), _doubleValue(2.0));
-  }
-
-  void test_add_knownDouble_knownInt() {
-    _assertAdd(_doubleValue(3.0), _doubleValue(1.0), _intValue(2));
-  }
-
-  void test_add_knownDouble_unknownDouble() {
-    _assertAdd(_doubleValue(null), _doubleValue(1.0), _doubleValue(null));
-  }
-
-  void test_add_knownDouble_unknownInt() {
-    _assertAdd(_doubleValue(null), _doubleValue(1.0), _intValue(null));
-  }
-
-  void test_add_knownInt_knownInt() {
-    _assertAdd(_intValue(3), _intValue(1), _intValue(2));
-  }
-
-  void test_add_knownInt_knownString() {
-    _assertAdd(null, _intValue(1), _stringValue("2"));
-  }
-
-  void test_add_knownInt_unknownDouble() {
-    _assertAdd(_doubleValue(null), _intValue(1), _doubleValue(null));
-  }
-
-  void test_add_knownInt_unknownInt() {
-    _assertAdd(_intValue(null), _intValue(1), _intValue(null));
-  }
-
-  void test_add_knownString_knownInt() {
-    _assertAdd(null, _stringValue("1"), _intValue(2));
-  }
-
-  void test_add_knownString_knownString() {
-    _assertAdd(_stringValue("ab"), _stringValue("a"), _stringValue("b"));
-  }
-
-  void test_add_knownString_unknownString() {
-    _assertAdd(_stringValue(null), _stringValue("a"), _stringValue(null));
-  }
-
-  void test_add_unknownDouble_knownDouble() {
-    _assertAdd(_doubleValue(null), _doubleValue(null), _doubleValue(2.0));
-  }
-
-  void test_add_unknownDouble_knownInt() {
-    _assertAdd(_doubleValue(null), _doubleValue(null), _intValue(2));
-  }
-
-  void test_add_unknownInt_knownDouble() {
-    _assertAdd(_doubleValue(null), _intValue(null), _doubleValue(2.0));
-  }
-
-  void test_add_unknownInt_knownInt() {
-    _assertAdd(_intValue(null), _intValue(null), _intValue(2));
-  }
-
-  void test_add_unknownString_knownString() {
-    _assertAdd(_stringValue(null), _stringValue(null), _stringValue("b"));
-  }
-
-  void test_add_unknownString_unknownString() {
-    _assertAdd(_stringValue(null), _stringValue(null), _stringValue(null));
-  }
-
-  void test_bitAnd_knownInt_knownInt() {
-    _assertBitAnd(_intValue(2), _intValue(6), _intValue(3));
-  }
-
-  void test_bitAnd_knownInt_knownString() {
-    _assertBitAnd(null, _intValue(6), _stringValue("3"));
-  }
-
-  void test_bitAnd_knownInt_unknownInt() {
-    _assertBitAnd(_intValue(null), _intValue(6), _intValue(null));
-  }
-
-  void test_bitAnd_knownString_knownInt() {
-    _assertBitAnd(null, _stringValue("6"), _intValue(3));
-  }
-
-  void test_bitAnd_unknownInt_knownInt() {
-    _assertBitAnd(_intValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_bitAnd_unknownInt_unknownInt() {
-    _assertBitAnd(_intValue(null), _intValue(null), _intValue(null));
-  }
-
-  void test_bitNot_knownInt() {
-    _assertBitNot(_intValue(-4), _intValue(3));
-  }
-
-  void test_bitNot_knownString() {
-    _assertBitNot(null, _stringValue("6"));
-  }
-
-  void test_bitNot_unknownInt() {
-    _assertBitNot(_intValue(null), _intValue(null));
-  }
-
-  void test_bitOr_knownInt_knownInt() {
-    _assertBitOr(_intValue(7), _intValue(6), _intValue(3));
-  }
-
-  void test_bitOr_knownInt_knownString() {
-    _assertBitOr(null, _intValue(6), _stringValue("3"));
-  }
-
-  void test_bitOr_knownInt_unknownInt() {
-    _assertBitOr(_intValue(null), _intValue(6), _intValue(null));
-  }
-
-  void test_bitOr_knownString_knownInt() {
-    _assertBitOr(null, _stringValue("6"), _intValue(3));
-  }
-
-  void test_bitOr_unknownInt_knownInt() {
-    _assertBitOr(_intValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_bitOr_unknownInt_unknownInt() {
-    _assertBitOr(_intValue(null), _intValue(null), _intValue(null));
-  }
-
-  void test_bitXor_knownInt_knownInt() {
-    _assertBitXor(_intValue(5), _intValue(6), _intValue(3));
-  }
-
-  void test_bitXor_knownInt_knownString() {
-    _assertBitXor(null, _intValue(6), _stringValue("3"));
-  }
-
-  void test_bitXor_knownInt_unknownInt() {
-    _assertBitXor(_intValue(null), _intValue(6), _intValue(null));
-  }
-
-  void test_bitXor_knownString_knownInt() {
-    _assertBitXor(null, _stringValue("6"), _intValue(3));
-  }
-
-  void test_bitXor_unknownInt_knownInt() {
-    _assertBitXor(_intValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_bitXor_unknownInt_unknownInt() {
-    _assertBitXor(_intValue(null), _intValue(null), _intValue(null));
-  }
-
-  void test_concatenate_knownInt_knownString() {
-    _assertConcatenate(null, _intValue(2), _stringValue("def"));
-  }
-
-  void test_concatenate_knownString_knownInt() {
-    _assertConcatenate(null, _stringValue("abc"), _intValue(3));
-  }
-
-  void test_concatenate_knownString_knownString() {
-    _assertConcatenate(
-        _stringValue("abcdef"), _stringValue("abc"), _stringValue("def"));
-  }
-
-  void test_concatenate_knownString_unknownString() {
-    _assertConcatenate(
-        _stringValue(null), _stringValue("abc"), _stringValue(null));
-  }
-
-  void test_concatenate_unknownString_knownString() {
-    _assertConcatenate(
-        _stringValue(null), _stringValue(null), _stringValue("def"));
-  }
-
-  void test_divide_knownDouble_knownDouble() {
-    _assertDivide(_doubleValue(3.0), _doubleValue(6.0), _doubleValue(2.0));
-  }
-
-  void test_divide_knownDouble_knownInt() {
-    _assertDivide(_doubleValue(3.0), _doubleValue(6.0), _intValue(2));
-  }
-
-  void test_divide_knownDouble_unknownDouble() {
-    _assertDivide(_doubleValue(null), _doubleValue(6.0), _doubleValue(null));
-  }
-
-  void test_divide_knownDouble_unknownInt() {
-    _assertDivide(_doubleValue(null), _doubleValue(6.0), _intValue(null));
-  }
-
-  void test_divide_knownInt_knownInt() {
-    _assertDivide(_doubleValue(3.0), _intValue(6), _intValue(2));
-  }
-
-  void test_divide_knownInt_knownString() {
-    _assertDivide(null, _intValue(6), _stringValue("2"));
-  }
-
-  void test_divide_knownInt_unknownDouble() {
-    _assertDivide(_doubleValue(null), _intValue(6), _doubleValue(null));
-  }
-
-  void test_divide_knownInt_unknownInt() {
-    _assertDivide(_doubleValue(null), _intValue(6), _intValue(null));
-  }
-
-  void test_divide_knownString_knownInt() {
-    _assertDivide(null, _stringValue("6"), _intValue(2));
-  }
-
-  void test_divide_unknownDouble_knownDouble() {
-    _assertDivide(_doubleValue(null), _doubleValue(null), _doubleValue(2.0));
-  }
-
-  void test_divide_unknownDouble_knownInt() {
-    _assertDivide(_doubleValue(null), _doubleValue(null), _intValue(2));
-  }
-
-  void test_divide_unknownInt_knownDouble() {
-    _assertDivide(_doubleValue(null), _intValue(null), _doubleValue(2.0));
-  }
-
-  void test_divide_unknownInt_knownInt() {
-    _assertDivide(_doubleValue(null), _intValue(null), _intValue(2));
-  }
-
-  void test_equalEqual_bool_false() {
-    _assertEqualEqual(_boolValue(false), _boolValue(false), _boolValue(true));
-  }
-
-  void test_equalEqual_bool_true() {
-    _assertEqualEqual(_boolValue(true), _boolValue(true), _boolValue(true));
-  }
-
-  void test_equalEqual_bool_unknown() {
-    _assertEqualEqual(_boolValue(null), _boolValue(null), _boolValue(false));
-  }
-
-  void test_equalEqual_double_false() {
-    _assertEqualEqual(_boolValue(false), _doubleValue(2.0), _doubleValue(4.0));
-  }
-
-  void test_equalEqual_double_true() {
-    _assertEqualEqual(_boolValue(true), _doubleValue(2.0), _doubleValue(2.0));
-  }
-
-  void test_equalEqual_double_unknown() {
-    _assertEqualEqual(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
-  }
-
-  void test_equalEqual_int_false() {
-    _assertEqualEqual(_boolValue(false), _intValue(-5), _intValue(5));
-  }
-
-  void test_equalEqual_int_true() {
-    _assertEqualEqual(_boolValue(true), _intValue(5), _intValue(5));
-  }
-
-  void test_equalEqual_int_unknown() {
-    _assertEqualEqual(_boolValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_equalEqual_list_empty() {
-    _assertEqualEqual(null, _listValue(), _listValue());
-  }
-
-  void test_equalEqual_list_false() {
-    _assertEqualEqual(null, _listValue(), _listValue());
-  }
-
-  void test_equalEqual_map_empty() {
-    _assertEqualEqual(null, _mapValue(), _mapValue());
-  }
-
-  void test_equalEqual_map_false() {
-    _assertEqualEqual(null, _mapValue(), _mapValue());
-  }
-
-  void test_equalEqual_null() {
-    _assertEqualEqual(_boolValue(true), _nullValue(), _nullValue());
-  }
-
-  void test_equalEqual_string_false() {
-    _assertEqualEqual(
-        _boolValue(false), _stringValue("abc"), _stringValue("def"));
-  }
-
-  void test_equalEqual_string_true() {
-    _assertEqualEqual(
-        _boolValue(true), _stringValue("abc"), _stringValue("abc"));
-  }
-
-  void test_equalEqual_string_unknown() {
-    _assertEqualEqual(
-        _boolValue(null), _stringValue(null), _stringValue("def"));
-  }
-
-  void test_equals_list_false_differentSizes() {
-    expect(
-        _listValue([_boolValue(true)]) ==
-            _listValue([_boolValue(true), _boolValue(false)]),
-        isFalse);
-  }
-
-  void test_equals_list_false_sameSize() {
-    expect(_listValue([_boolValue(true)]) == _listValue([_boolValue(false)]),
-        isFalse);
-  }
-
-  void test_equals_list_true_empty() {
-    expect(_listValue(), _listValue());
-  }
-
-  void test_equals_list_true_nonEmpty() {
-    expect(_listValue([_boolValue(true)]), _listValue([_boolValue(true)]));
-  }
-
-  void test_equals_map_true_empty() {
-    expect(_mapValue(), _mapValue());
-  }
-
-  void test_equals_symbol_false() {
-    expect(_symbolValue("a") == _symbolValue("b"), isFalse);
-  }
-
-  void test_equals_symbol_true() {
-    expect(_symbolValue("a"), _symbolValue("a"));
-  }
-
-  void test_getValue_bool_false() {
-    expect(_boolValue(false).toBoolValue(), false);
-  }
-
-  void test_getValue_bool_true() {
-    expect(_boolValue(true).toBoolValue(), true);
-  }
-
-  void test_getValue_bool_unknown() {
-    expect(_boolValue(null).toBoolValue(), isNull);
-  }
-
-  void test_getValue_double_known() {
-    double value = 2.3;
-    expect(_doubleValue(value).toDoubleValue(), value);
-  }
-
-  void test_getValue_double_unknown() {
-    expect(_doubleValue(null).toDoubleValue(), isNull);
-  }
-
-  void test_getValue_int_known() {
-    int value = 23;
-    expect(_intValue(value).toIntValue(), value);
-  }
-
-  void test_getValue_int_unknown() {
-    expect(_intValue(null).toIntValue(), isNull);
-  }
-
-  void test_getValue_list_empty() {
-    Object result = _listValue().toListValue();
-    _assertInstanceOfObjectArray(result);
-    List<Object> array = result as List<Object>;
-    expect(array, hasLength(0));
-  }
-
-  void test_getValue_list_valid() {
-    Object result = _listValue([_intValue(23)]).toListValue();
-    _assertInstanceOfObjectArray(result);
-    List<Object> array = result as List<Object>;
-    expect(array, hasLength(1));
-  }
-
-  void test_getValue_map_empty() {
-    Object result = _mapValue().toMapValue();
-    EngineTestCase.assertInstanceOf((obj) => obj is Map, Map, result);
-    Map map = result as Map;
-    expect(map, hasLength(0));
-  }
-
-  void test_getValue_map_valid() {
-    Object result =
-        _mapValue([_stringValue("key"), _stringValue("value")]).toMapValue();
-    EngineTestCase.assertInstanceOf((obj) => obj is Map, Map, result);
-    Map map = result as Map;
-    expect(map, hasLength(1));
-  }
-
-  void test_getValue_null() {
-    expect(_nullValue().isNull, isTrue);
-  }
-
-  void test_getValue_string_known() {
-    String value = "twenty-three";
-    expect(_stringValue(value).toStringValue(), value);
-  }
-
-  void test_getValue_string_unknown() {
-    expect(_stringValue(null).toStringValue(), isNull);
-  }
-
-  void test_greaterThan_knownDouble_knownDouble_false() {
-    _assertGreaterThan(_boolValue(false), _doubleValue(1.0), _doubleValue(2.0));
-  }
-
-  void test_greaterThan_knownDouble_knownDouble_true() {
-    _assertGreaterThan(_boolValue(true), _doubleValue(2.0), _doubleValue(1.0));
-  }
-
-  void test_greaterThan_knownDouble_knownInt_false() {
-    _assertGreaterThan(_boolValue(false), _doubleValue(1.0), _intValue(2));
-  }
-
-  void test_greaterThan_knownDouble_knownInt_true() {
-    _assertGreaterThan(_boolValue(true), _doubleValue(2.0), _intValue(1));
-  }
-
-  void test_greaterThan_knownDouble_unknownDouble() {
-    _assertGreaterThan(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
-  }
-
-  void test_greaterThan_knownDouble_unknownInt() {
-    _assertGreaterThan(_boolValue(null), _doubleValue(1.0), _intValue(null));
-  }
-
-  void test_greaterThan_knownInt_knownInt_false() {
-    _assertGreaterThan(_boolValue(false), _intValue(1), _intValue(2));
-  }
-
-  void test_greaterThan_knownInt_knownInt_true() {
-    _assertGreaterThan(_boolValue(true), _intValue(2), _intValue(1));
-  }
-
-  void test_greaterThan_knownInt_knownString() {
-    _assertGreaterThan(null, _intValue(1), _stringValue("2"));
-  }
-
-  void test_greaterThan_knownInt_unknownDouble() {
-    _assertGreaterThan(_boolValue(null), _intValue(1), _doubleValue(null));
-  }
-
-  void test_greaterThan_knownInt_unknownInt() {
-    _assertGreaterThan(_boolValue(null), _intValue(1), _intValue(null));
-  }
-
-  void test_greaterThan_knownString_knownInt() {
-    _assertGreaterThan(null, _stringValue("1"), _intValue(2));
-  }
-
-  void test_greaterThan_unknownDouble_knownDouble() {
-    _assertGreaterThan(_boolValue(null), _doubleValue(null), _doubleValue(2.0));
-  }
-
-  void test_greaterThan_unknownDouble_knownInt() {
-    _assertGreaterThan(_boolValue(null), _doubleValue(null), _intValue(2));
-  }
-
-  void test_greaterThan_unknownInt_knownDouble() {
-    _assertGreaterThan(_boolValue(null), _intValue(null), _doubleValue(2.0));
-  }
-
-  void test_greaterThan_unknownInt_knownInt() {
-    _assertGreaterThan(_boolValue(null), _intValue(null), _intValue(2));
-  }
-
-  void test_greaterThanOrEqual_knownDouble_knownDouble_false() {
-    _assertGreaterThanOrEqual(
-        _boolValue(false), _doubleValue(1.0), _doubleValue(2.0));
-  }
-
-  void test_greaterThanOrEqual_knownDouble_knownDouble_true() {
-    _assertGreaterThanOrEqual(
-        _boolValue(true), _doubleValue(2.0), _doubleValue(1.0));
-  }
-
-  void test_greaterThanOrEqual_knownDouble_knownInt_false() {
-    _assertGreaterThanOrEqual(
-        _boolValue(false), _doubleValue(1.0), _intValue(2));
-  }
-
-  void test_greaterThanOrEqual_knownDouble_knownInt_true() {
-    _assertGreaterThanOrEqual(
-        _boolValue(true), _doubleValue(2.0), _intValue(1));
-  }
-
-  void test_greaterThanOrEqual_knownDouble_unknownDouble() {
-    _assertGreaterThanOrEqual(
-        _boolValue(null), _doubleValue(1.0), _doubleValue(null));
-  }
-
-  void test_greaterThanOrEqual_knownDouble_unknownInt() {
-    _assertGreaterThanOrEqual(
-        _boolValue(null), _doubleValue(1.0), _intValue(null));
-  }
-
-  void test_greaterThanOrEqual_knownInt_knownInt_false() {
-    _assertGreaterThanOrEqual(_boolValue(false), _intValue(1), _intValue(2));
-  }
-
-  void test_greaterThanOrEqual_knownInt_knownInt_true() {
-    _assertGreaterThanOrEqual(_boolValue(true), _intValue(2), _intValue(2));
-  }
-
-  void test_greaterThanOrEqual_knownInt_knownString() {
-    _assertGreaterThanOrEqual(null, _intValue(1), _stringValue("2"));
-  }
-
-  void test_greaterThanOrEqual_knownInt_unknownDouble() {
-    _assertGreaterThanOrEqual(
-        _boolValue(null), _intValue(1), _doubleValue(null));
-  }
-
-  void test_greaterThanOrEqual_knownInt_unknownInt() {
-    _assertGreaterThanOrEqual(_boolValue(null), _intValue(1), _intValue(null));
-  }
-
-  void test_greaterThanOrEqual_knownString_knownInt() {
-    _assertGreaterThanOrEqual(null, _stringValue("1"), _intValue(2));
-  }
-
-  void test_greaterThanOrEqual_unknownDouble_knownDouble() {
-    _assertGreaterThanOrEqual(
-        _boolValue(null), _doubleValue(null), _doubleValue(2.0));
-  }
-
-  void test_greaterThanOrEqual_unknownDouble_knownInt() {
-    _assertGreaterThanOrEqual(
-        _boolValue(null), _doubleValue(null), _intValue(2));
-  }
-
-  void test_greaterThanOrEqual_unknownInt_knownDouble() {
-    _assertGreaterThanOrEqual(
-        _boolValue(null), _intValue(null), _doubleValue(2.0));
-  }
-
-  void test_greaterThanOrEqual_unknownInt_knownInt() {
-    _assertGreaterThanOrEqual(_boolValue(null), _intValue(null), _intValue(2));
-  }
-
-  void test_hasKnownValue_bool_false() {
-    expect(_boolValue(false).hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_bool_true() {
-    expect(_boolValue(true).hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_bool_unknown() {
-    expect(_boolValue(null).hasKnownValue, isFalse);
-  }
-
-  void test_hasKnownValue_double_known() {
-    expect(_doubleValue(2.3).hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_double_unknown() {
-    expect(_doubleValue(null).hasKnownValue, isFalse);
-  }
-
-  void test_hasKnownValue_dynamic() {
-    expect(_dynamicValue().hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_int_known() {
-    expect(_intValue(23).hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_int_unknown() {
-    expect(_intValue(null).hasKnownValue, isFalse);
-  }
-
-  void test_hasKnownValue_list_empty() {
-    expect(_listValue().hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_list_invalidElement() {
-    expect(_listValue([_dynamicValue]).hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_list_valid() {
-    expect(_listValue([_intValue(23)]).hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_map_empty() {
-    expect(_mapValue().hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_map_invalidKey() {
-    expect(_mapValue([_dynamicValue(), _stringValue("value")]).hasKnownValue,
-        isTrue);
-  }
-
-  void test_hasKnownValue_map_invalidValue() {
-    expect(_mapValue([_stringValue("key"), _dynamicValue()]).hasKnownValue,
-        isTrue);
-  }
-
-  void test_hasKnownValue_map_valid() {
-    expect(
-        _mapValue([_stringValue("key"), _stringValue("value")]).hasKnownValue,
-        isTrue);
-  }
-
-  void test_hasKnownValue_null() {
-    expect(_nullValue().hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_num() {
-    expect(_numValue().hasKnownValue, isFalse);
-  }
-
-  void test_hasKnownValue_string_known() {
-    expect(_stringValue("twenty-three").hasKnownValue, isTrue);
-  }
-
-  void test_hasKnownValue_string_unknown() {
-    expect(_stringValue(null).hasKnownValue, isFalse);
-  }
-
-  void test_identical_bool_false() {
-    _assertIdentical(_boolValue(false), _boolValue(false), _boolValue(true));
-  }
-
-  void test_identical_bool_true() {
-    _assertIdentical(_boolValue(true), _boolValue(true), _boolValue(true));
-  }
-
-  void test_identical_bool_unknown() {
-    _assertIdentical(_boolValue(null), _boolValue(null), _boolValue(false));
-  }
-
-  void test_identical_double_false() {
-    _assertIdentical(_boolValue(false), _doubleValue(2.0), _doubleValue(4.0));
-  }
-
-  void test_identical_double_true() {
-    _assertIdentical(_boolValue(true), _doubleValue(2.0), _doubleValue(2.0));
-  }
-
-  void test_identical_double_unknown() {
-    _assertIdentical(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
-  }
-
-  void test_identical_int_false() {
-    _assertIdentical(_boolValue(false), _intValue(-5), _intValue(5));
-  }
-
-  void test_identical_int_true() {
-    _assertIdentical(_boolValue(true), _intValue(5), _intValue(5));
-  }
-
-  void test_identical_int_unknown() {
-    _assertIdentical(_boolValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_identical_list_empty() {
-    _assertIdentical(_boolValue(true), _listValue(), _listValue());
-  }
-
-  void test_identical_list_false() {
-    _assertIdentical(
-        _boolValue(false), _listValue(), _listValue([_intValue(3)]));
-  }
-
-  void test_identical_map_empty() {
-    _assertIdentical(_boolValue(true), _mapValue(), _mapValue());
-  }
-
-  void test_identical_map_false() {
-    _assertIdentical(_boolValue(false), _mapValue(),
-        _mapValue([_intValue(1), _intValue(2)]));
-  }
-
-  void test_identical_null() {
-    _assertIdentical(_boolValue(true), _nullValue(), _nullValue());
-  }
-
-  void test_identical_string_false() {
-    _assertIdentical(
-        _boolValue(false), _stringValue("abc"), _stringValue("def"));
-  }
-
-  void test_identical_string_true() {
-    _assertIdentical(
-        _boolValue(true), _stringValue("abc"), _stringValue("abc"));
-  }
-
-  void test_identical_string_unknown() {
-    _assertIdentical(_boolValue(null), _stringValue(null), _stringValue("def"));
-  }
-
-  void test_integerDivide_knownDouble_knownDouble() {
-    _assertIntegerDivide(_intValue(3), _doubleValue(6.0), _doubleValue(2.0));
-  }
-
-  void test_integerDivide_knownDouble_knownInt() {
-    _assertIntegerDivide(_intValue(3), _doubleValue(6.0), _intValue(2));
-  }
-
-  void test_integerDivide_knownDouble_unknownDouble() {
-    _assertIntegerDivide(
-        _intValue(null), _doubleValue(6.0), _doubleValue(null));
-  }
-
-  void test_integerDivide_knownDouble_unknownInt() {
-    _assertIntegerDivide(_intValue(null), _doubleValue(6.0), _intValue(null));
-  }
-
-  void test_integerDivide_knownInt_knownInt() {
-    _assertIntegerDivide(_intValue(3), _intValue(6), _intValue(2));
-  }
-
-  void test_integerDivide_knownInt_knownString() {
-    _assertIntegerDivide(null, _intValue(6), _stringValue("2"));
-  }
-
-  void test_integerDivide_knownInt_unknownDouble() {
-    _assertIntegerDivide(_intValue(null), _intValue(6), _doubleValue(null));
-  }
-
-  void test_integerDivide_knownInt_unknownInt() {
-    _assertIntegerDivide(_intValue(null), _intValue(6), _intValue(null));
-  }
-
-  void test_integerDivide_knownString_knownInt() {
-    _assertIntegerDivide(null, _stringValue("6"), _intValue(2));
-  }
-
-  void test_integerDivide_unknownDouble_knownDouble() {
-    _assertIntegerDivide(
-        _intValue(null), _doubleValue(null), _doubleValue(2.0));
-  }
-
-  void test_integerDivide_unknownDouble_knownInt() {
-    _assertIntegerDivide(_intValue(null), _doubleValue(null), _intValue(2));
-  }
-
-  void test_integerDivide_unknownInt_knownDouble() {
-    _assertIntegerDivide(_intValue(null), _intValue(null), _doubleValue(2.0));
-  }
-
-  void test_integerDivide_unknownInt_knownInt() {
-    _assertIntegerDivide(_intValue(null), _intValue(null), _intValue(2));
-  }
-
-  void test_isBoolNumStringOrNull_bool_false() {
-    expect(_boolValue(false).isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_bool_true() {
-    expect(_boolValue(true).isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_bool_unknown() {
-    expect(_boolValue(null).isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_double_known() {
-    expect(_doubleValue(2.3).isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_double_unknown() {
-    expect(_doubleValue(null).isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_dynamic() {
-    expect(_dynamicValue().isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_int_known() {
-    expect(_intValue(23).isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_int_unknown() {
-    expect(_intValue(null).isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_list() {
-    expect(_listValue().isBoolNumStringOrNull, isFalse);
-  }
-
-  void test_isBoolNumStringOrNull_null() {
-    expect(_nullValue().isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_num() {
-    expect(_numValue().isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_string_known() {
-    expect(_stringValue("twenty-three").isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_isBoolNumStringOrNull_string_unknown() {
-    expect(_stringValue(null).isBoolNumStringOrNull, isTrue);
-  }
-
-  void test_lessThan_knownDouble_knownDouble_false() {
-    _assertLessThan(_boolValue(false), _doubleValue(2.0), _doubleValue(1.0));
-  }
-
-  void test_lessThan_knownDouble_knownDouble_true() {
-    _assertLessThan(_boolValue(true), _doubleValue(1.0), _doubleValue(2.0));
-  }
-
-  void test_lessThan_knownDouble_knownInt_false() {
-    _assertLessThan(_boolValue(false), _doubleValue(2.0), _intValue(1));
-  }
-
-  void test_lessThan_knownDouble_knownInt_true() {
-    _assertLessThan(_boolValue(true), _doubleValue(1.0), _intValue(2));
-  }
-
-  void test_lessThan_knownDouble_unknownDouble() {
-    _assertLessThan(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
-  }
-
-  void test_lessThan_knownDouble_unknownInt() {
-    _assertLessThan(_boolValue(null), _doubleValue(1.0), _intValue(null));
-  }
-
-  void test_lessThan_knownInt_knownInt_false() {
-    _assertLessThan(_boolValue(false), _intValue(2), _intValue(1));
-  }
-
-  void test_lessThan_knownInt_knownInt_true() {
-    _assertLessThan(_boolValue(true), _intValue(1), _intValue(2));
-  }
-
-  void test_lessThan_knownInt_knownString() {
-    _assertLessThan(null, _intValue(1), _stringValue("2"));
-  }
-
-  void test_lessThan_knownInt_unknownDouble() {
-    _assertLessThan(_boolValue(null), _intValue(1), _doubleValue(null));
-  }
-
-  void test_lessThan_knownInt_unknownInt() {
-    _assertLessThan(_boolValue(null), _intValue(1), _intValue(null));
-  }
-
-  void test_lessThan_knownString_knownInt() {
-    _assertLessThan(null, _stringValue("1"), _intValue(2));
-  }
-
-  void test_lessThan_unknownDouble_knownDouble() {
-    _assertLessThan(_boolValue(null), _doubleValue(null), _doubleValue(2.0));
-  }
-
-  void test_lessThan_unknownDouble_knownInt() {
-    _assertLessThan(_boolValue(null), _doubleValue(null), _intValue(2));
-  }
-
-  void test_lessThan_unknownInt_knownDouble() {
-    _assertLessThan(_boolValue(null), _intValue(null), _doubleValue(2.0));
-  }
-
-  void test_lessThan_unknownInt_knownInt() {
-    _assertLessThan(_boolValue(null), _intValue(null), _intValue(2));
-  }
-
-  void test_lessThanOrEqual_knownDouble_knownDouble_false() {
-    _assertLessThanOrEqual(
-        _boolValue(false), _doubleValue(2.0), _doubleValue(1.0));
-  }
-
-  void test_lessThanOrEqual_knownDouble_knownDouble_true() {
-    _assertLessThanOrEqual(
-        _boolValue(true), _doubleValue(1.0), _doubleValue(2.0));
-  }
-
-  void test_lessThanOrEqual_knownDouble_knownInt_false() {
-    _assertLessThanOrEqual(_boolValue(false), _doubleValue(2.0), _intValue(1));
-  }
-
-  void test_lessThanOrEqual_knownDouble_knownInt_true() {
-    _assertLessThanOrEqual(_boolValue(true), _doubleValue(1.0), _intValue(2));
-  }
-
-  void test_lessThanOrEqual_knownDouble_unknownDouble() {
-    _assertLessThanOrEqual(
-        _boolValue(null), _doubleValue(1.0), _doubleValue(null));
-  }
-
-  void test_lessThanOrEqual_knownDouble_unknownInt() {
-    _assertLessThanOrEqual(
-        _boolValue(null), _doubleValue(1.0), _intValue(null));
-  }
-
-  void test_lessThanOrEqual_knownInt_knownInt_false() {
-    _assertLessThanOrEqual(_boolValue(false), _intValue(2), _intValue(1));
-  }
-
-  void test_lessThanOrEqual_knownInt_knownInt_true() {
-    _assertLessThanOrEqual(_boolValue(true), _intValue(1), _intValue(2));
-  }
-
-  void test_lessThanOrEqual_knownInt_knownString() {
-    _assertLessThanOrEqual(null, _intValue(1), _stringValue("2"));
-  }
-
-  void test_lessThanOrEqual_knownInt_unknownDouble() {
-    _assertLessThanOrEqual(_boolValue(null), _intValue(1), _doubleValue(null));
-  }
-
-  void test_lessThanOrEqual_knownInt_unknownInt() {
-    _assertLessThanOrEqual(_boolValue(null), _intValue(1), _intValue(null));
-  }
-
-  void test_lessThanOrEqual_knownString_knownInt() {
-    _assertLessThanOrEqual(null, _stringValue("1"), _intValue(2));
-  }
-
-  void test_lessThanOrEqual_unknownDouble_knownDouble() {
-    _assertLessThanOrEqual(
-        _boolValue(null), _doubleValue(null), _doubleValue(2.0));
-  }
-
-  void test_lessThanOrEqual_unknownDouble_knownInt() {
-    _assertLessThanOrEqual(_boolValue(null), _doubleValue(null), _intValue(2));
-  }
-
-  void test_lessThanOrEqual_unknownInt_knownDouble() {
-    _assertLessThanOrEqual(
-        _boolValue(null), _intValue(null), _doubleValue(2.0));
-  }
-
-  void test_lessThanOrEqual_unknownInt_knownInt() {
-    _assertLessThanOrEqual(_boolValue(null), _intValue(null), _intValue(2));
-  }
-
-  void test_logicalAnd_false_false() {
-    _assertLogicalAnd(_boolValue(false), _boolValue(false), _boolValue(false));
-  }
-
-  void test_logicalAnd_false_null() {
-    try {
-      _assertLogicalAnd(_boolValue(false), _boolValue(false), _nullValue());
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalAnd_false_string() {
-    try {
-      _assertLogicalAnd(
-          _boolValue(false), _boolValue(false), _stringValue("false"));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalAnd_false_true() {
-    _assertLogicalAnd(_boolValue(false), _boolValue(false), _boolValue(true));
-  }
-
-  void test_logicalAnd_null_false() {
-    try {
-      _assertLogicalAnd(_boolValue(false), _nullValue(), _boolValue(false));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalAnd_null_true() {
-    try {
-      _assertLogicalAnd(_boolValue(false), _nullValue(), _boolValue(true));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalAnd_string_false() {
-    try {
-      _assertLogicalAnd(
-          _boolValue(false), _stringValue("true"), _boolValue(false));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalAnd_string_true() {
-    try {
-      _assertLogicalAnd(
-          _boolValue(false), _stringValue("false"), _boolValue(true));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalAnd_true_false() {
-    _assertLogicalAnd(_boolValue(false), _boolValue(true), _boolValue(false));
-  }
-
-  void test_logicalAnd_true_null() {
-    _assertLogicalAnd(null, _boolValue(true), _nullValue());
-  }
-
-  void test_logicalAnd_true_string() {
-    try {
-      _assertLogicalAnd(
-          _boolValue(false), _boolValue(true), _stringValue("true"));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalAnd_true_true() {
-    _assertLogicalAnd(_boolValue(true), _boolValue(true), _boolValue(true));
-  }
-
-  void test_logicalNot_false() {
-    _assertLogicalNot(_boolValue(true), _boolValue(false));
-  }
-
-  void test_logicalNot_null() {
-    _assertLogicalNot(null, _nullValue());
-  }
-
-  void test_logicalNot_string() {
-    try {
-      _assertLogicalNot(_boolValue(true), _stringValue(null));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalNot_true() {
-    _assertLogicalNot(_boolValue(false), _boolValue(true));
-  }
-
-  void test_logicalNot_unknown() {
-    _assertLogicalNot(_boolValue(null), _boolValue(null));
-  }
-
-  void test_logicalOr_false_false() {
-    _assertLogicalOr(_boolValue(false), _boolValue(false), _boolValue(false));
-  }
-
-  void test_logicalOr_false_null() {
-    _assertLogicalOr(null, _boolValue(false), _nullValue());
-  }
-
-  void test_logicalOr_false_string() {
-    try {
-      _assertLogicalOr(
-          _boolValue(false), _boolValue(false), _stringValue("false"));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalOr_false_true() {
-    _assertLogicalOr(_boolValue(true), _boolValue(false), _boolValue(true));
-  }
-
-  void test_logicalOr_null_false() {
-    try {
-      _assertLogicalOr(_boolValue(false), _nullValue(), _boolValue(false));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalOr_null_true() {
-    try {
-      _assertLogicalOr(_boolValue(true), _nullValue(), _boolValue(true));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalOr_string_false() {
-    try {
-      _assertLogicalOr(
-          _boolValue(false), _stringValue("true"), _boolValue(false));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalOr_string_true() {
-    try {
-      _assertLogicalOr(
-          _boolValue(true), _stringValue("false"), _boolValue(true));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalOr_true_false() {
-    _assertLogicalOr(_boolValue(true), _boolValue(true), _boolValue(false));
-  }
-
-  void test_logicalOr_true_null() {
-    try {
-      _assertLogicalOr(_boolValue(true), _boolValue(true), _nullValue());
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalOr_true_string() {
-    try {
-      _assertLogicalOr(
-          _boolValue(true), _boolValue(true), _stringValue("true"));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_logicalOr_true_true() {
-    _assertLogicalOr(_boolValue(true), _boolValue(true), _boolValue(true));
-  }
-
-  void test_minus_knownDouble_knownDouble() {
-    _assertMinus(_doubleValue(1.0), _doubleValue(4.0), _doubleValue(3.0));
-  }
-
-  void test_minus_knownDouble_knownInt() {
-    _assertMinus(_doubleValue(1.0), _doubleValue(4.0), _intValue(3));
-  }
-
-  void test_minus_knownDouble_unknownDouble() {
-    _assertMinus(_doubleValue(null), _doubleValue(4.0), _doubleValue(null));
-  }
-
-  void test_minus_knownDouble_unknownInt() {
-    _assertMinus(_doubleValue(null), _doubleValue(4.0), _intValue(null));
-  }
-
-  void test_minus_knownInt_knownInt() {
-    _assertMinus(_intValue(1), _intValue(4), _intValue(3));
-  }
-
-  void test_minus_knownInt_knownString() {
-    _assertMinus(null, _intValue(4), _stringValue("3"));
-  }
-
-  void test_minus_knownInt_unknownDouble() {
-    _assertMinus(_doubleValue(null), _intValue(4), _doubleValue(null));
-  }
-
-  void test_minus_knownInt_unknownInt() {
-    _assertMinus(_intValue(null), _intValue(4), _intValue(null));
-  }
-
-  void test_minus_knownString_knownInt() {
-    _assertMinus(null, _stringValue("4"), _intValue(3));
-  }
-
-  void test_minus_unknownDouble_knownDouble() {
-    _assertMinus(_doubleValue(null), _doubleValue(null), _doubleValue(3.0));
-  }
-
-  void test_minus_unknownDouble_knownInt() {
-    _assertMinus(_doubleValue(null), _doubleValue(null), _intValue(3));
-  }
-
-  void test_minus_unknownInt_knownDouble() {
-    _assertMinus(_doubleValue(null), _intValue(null), _doubleValue(3.0));
-  }
-
-  void test_minus_unknownInt_knownInt() {
-    _assertMinus(_intValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_negated_double_known() {
-    _assertNegated(_doubleValue(2.0), _doubleValue(-2.0));
-  }
-
-  void test_negated_double_unknown() {
-    _assertNegated(_doubleValue(null), _doubleValue(null));
-  }
-
-  void test_negated_int_known() {
-    _assertNegated(_intValue(-3), _intValue(3));
-  }
-
-  void test_negated_int_unknown() {
-    _assertNegated(_intValue(null), _intValue(null));
-  }
-
-  void test_negated_string() {
-    _assertNegated(null, _stringValue(null));
-  }
-
-  void test_notEqual_bool_false() {
-    _assertNotEqual(_boolValue(false), _boolValue(true), _boolValue(true));
-  }
-
-  void test_notEqual_bool_true() {
-    _assertNotEqual(_boolValue(true), _boolValue(false), _boolValue(true));
-  }
-
-  void test_notEqual_bool_unknown() {
-    _assertNotEqual(_boolValue(null), _boolValue(null), _boolValue(false));
-  }
-
-  void test_notEqual_double_false() {
-    _assertNotEqual(_boolValue(false), _doubleValue(2.0), _doubleValue(2.0));
-  }
-
-  void test_notEqual_double_true() {
-    _assertNotEqual(_boolValue(true), _doubleValue(2.0), _doubleValue(4.0));
-  }
-
-  void test_notEqual_double_unknown() {
-    _assertNotEqual(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
-  }
-
-  void test_notEqual_int_false() {
-    _assertNotEqual(_boolValue(false), _intValue(5), _intValue(5));
-  }
-
-  void test_notEqual_int_true() {
-    _assertNotEqual(_boolValue(true), _intValue(-5), _intValue(5));
-  }
-
-  void test_notEqual_int_unknown() {
-    _assertNotEqual(_boolValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_notEqual_null() {
-    _assertNotEqual(_boolValue(false), _nullValue(), _nullValue());
-  }
-
-  void test_notEqual_string_false() {
-    _assertNotEqual(
-        _boolValue(false), _stringValue("abc"), _stringValue("abc"));
-  }
-
-  void test_notEqual_string_true() {
-    _assertNotEqual(_boolValue(true), _stringValue("abc"), _stringValue("def"));
-  }
-
-  void test_notEqual_string_unknown() {
-    _assertNotEqual(_boolValue(null), _stringValue(null), _stringValue("def"));
-  }
-
-  void test_performToString_bool_false() {
-    _assertPerformToString(_stringValue("false"), _boolValue(false));
-  }
-
-  void test_performToString_bool_true() {
-    _assertPerformToString(_stringValue("true"), _boolValue(true));
-  }
-
-  void test_performToString_bool_unknown() {
-    _assertPerformToString(_stringValue(null), _boolValue(null));
-  }
-
-  void test_performToString_double_known() {
-    _assertPerformToString(_stringValue("2.0"), _doubleValue(2.0));
-  }
-
-  void test_performToString_double_unknown() {
-    _assertPerformToString(_stringValue(null), _doubleValue(null));
-  }
-
-  void test_performToString_int_known() {
-    _assertPerformToString(_stringValue("5"), _intValue(5));
-  }
-
-  void test_performToString_int_unknown() {
-    _assertPerformToString(_stringValue(null), _intValue(null));
-  }
-
-  void test_performToString_null() {
-    _assertPerformToString(_stringValue("null"), _nullValue());
-  }
-
-  void test_performToString_string_known() {
-    _assertPerformToString(_stringValue("abc"), _stringValue("abc"));
-  }
-
-  void test_performToString_string_unknown() {
-    _assertPerformToString(_stringValue(null), _stringValue(null));
-  }
-
-  void test_remainder_knownDouble_knownDouble() {
-    _assertRemainder(_doubleValue(1.0), _doubleValue(7.0), _doubleValue(2.0));
-  }
-
-  void test_remainder_knownDouble_knownInt() {
-    _assertRemainder(_doubleValue(1.0), _doubleValue(7.0), _intValue(2));
-  }
-
-  void test_remainder_knownDouble_unknownDouble() {
-    _assertRemainder(_doubleValue(null), _doubleValue(7.0), _doubleValue(null));
-  }
-
-  void test_remainder_knownDouble_unknownInt() {
-    _assertRemainder(_doubleValue(null), _doubleValue(6.0), _intValue(null));
-  }
-
-  void test_remainder_knownInt_knownInt() {
-    _assertRemainder(_intValue(1), _intValue(7), _intValue(2));
-  }
-
-  void test_remainder_knownInt_knownString() {
-    _assertRemainder(null, _intValue(7), _stringValue("2"));
-  }
-
-  void test_remainder_knownInt_unknownDouble() {
-    _assertRemainder(_doubleValue(null), _intValue(7), _doubleValue(null));
-  }
-
-  void test_remainder_knownInt_unknownInt() {
-    _assertRemainder(_intValue(null), _intValue(7), _intValue(null));
-  }
-
-  void test_remainder_knownString_knownInt() {
-    _assertRemainder(null, _stringValue("7"), _intValue(2));
-  }
-
-  void test_remainder_unknownDouble_knownDouble() {
-    _assertRemainder(_doubleValue(null), _doubleValue(null), _doubleValue(2.0));
-  }
-
-  void test_remainder_unknownDouble_knownInt() {
-    _assertRemainder(_doubleValue(null), _doubleValue(null), _intValue(2));
-  }
-
-  void test_remainder_unknownInt_knownDouble() {
-    _assertRemainder(_doubleValue(null), _intValue(null), _doubleValue(2.0));
-  }
-
-  void test_remainder_unknownInt_knownInt() {
-    _assertRemainder(_intValue(null), _intValue(null), _intValue(2));
-  }
-
-  void test_shiftLeft_knownInt_knownInt() {
-    _assertShiftLeft(_intValue(48), _intValue(6), _intValue(3));
-  }
-
-  void test_shiftLeft_knownInt_knownString() {
-    _assertShiftLeft(null, _intValue(6), _stringValue(null));
-  }
-
-  void test_shiftLeft_knownInt_tooLarge() {
-    _assertShiftLeft(
-        _intValue(null),
-        _intValue(6),
-        new DartObjectImpl(
-            _typeProvider.intType, new IntState(LONG_MAX_VALUE)));
-  }
-
-  void test_shiftLeft_knownInt_unknownInt() {
-    _assertShiftLeft(_intValue(null), _intValue(6), _intValue(null));
-  }
-
-  void test_shiftLeft_knownString_knownInt() {
-    _assertShiftLeft(null, _stringValue(null), _intValue(3));
-  }
-
-  void test_shiftLeft_unknownInt_knownInt() {
-    _assertShiftLeft(_intValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_shiftLeft_unknownInt_unknownInt() {
-    _assertShiftLeft(_intValue(null), _intValue(null), _intValue(null));
-  }
-
-  void test_shiftRight_knownInt_knownInt() {
-    _assertShiftRight(_intValue(6), _intValue(48), _intValue(3));
-  }
-
-  void test_shiftRight_knownInt_knownString() {
-    _assertShiftRight(null, _intValue(48), _stringValue(null));
-  }
-
-  void test_shiftRight_knownInt_tooLarge() {
-    _assertShiftRight(
-        _intValue(null),
-        _intValue(48),
-        new DartObjectImpl(
-            _typeProvider.intType, new IntState(LONG_MAX_VALUE)));
-  }
-
-  void test_shiftRight_knownInt_unknownInt() {
-    _assertShiftRight(_intValue(null), _intValue(48), _intValue(null));
-  }
-
-  void test_shiftRight_knownString_knownInt() {
-    _assertShiftRight(null, _stringValue(null), _intValue(3));
-  }
-
-  void test_shiftRight_unknownInt_knownInt() {
-    _assertShiftRight(_intValue(null), _intValue(null), _intValue(3));
-  }
-
-  void test_shiftRight_unknownInt_unknownInt() {
-    _assertShiftRight(_intValue(null), _intValue(null), _intValue(null));
-  }
-
-  void test_stringLength_int() {
-    try {
-      _assertStringLength(_intValue(null), _intValue(0));
-      fail("Expected EvaluationException");
-    } on EvaluationException {}
-  }
-
-  void test_stringLength_knownString() {
-    _assertStringLength(_intValue(3), _stringValue("abc"));
-  }
-
-  void test_stringLength_unknownString() {
-    _assertStringLength(_intValue(null), _stringValue(null));
-  }
-
-  void test_times_knownDouble_knownDouble() {
-    _assertTimes(_doubleValue(6.0), _doubleValue(2.0), _doubleValue(3.0));
-  }
-
-  void test_times_knownDouble_knownInt() {
-    _assertTimes(_doubleValue(6.0), _doubleValue(2.0), _intValue(3));
-  }
-
-  void test_times_knownDouble_unknownDouble() {
-    _assertTimes(_doubleValue(null), _doubleValue(2.0), _doubleValue(null));
-  }
-
-  void test_times_knownDouble_unknownInt() {
-    _assertTimes(_doubleValue(null), _doubleValue(2.0), _intValue(null));
-  }
-
-  void test_times_knownInt_knownInt() {
-    _assertTimes(_intValue(6), _intValue(2), _intValue(3));
-  }
-
-  void test_times_knownInt_knownString() {
-    _assertTimes(null, _intValue(2), _stringValue("3"));
-  }
-
-  void test_times_knownInt_unknownDouble() {
-    _assertTimes(_doubleValue(null), _intValue(2), _doubleValue(null));
-  }
-
-  void test_times_knownInt_unknownInt() {
-    _assertTimes(_intValue(null), _intValue(2), _intValue(null));
-  }
-
-  void test_times_knownString_knownInt() {
-    _assertTimes(null, _stringValue("2"), _intValue(3));
-  }
-
-  void test_times_unknownDouble_knownDouble() {
-    _assertTimes(_doubleValue(null), _doubleValue(null), _doubleValue(3.0));
-  }
-
-  void test_times_unknownDouble_knownInt() {
-    _assertTimes(_doubleValue(null), _doubleValue(null), _intValue(3));
-  }
-
-  void test_times_unknownInt_knownDouble() {
-    _assertTimes(_doubleValue(null), _intValue(null), _doubleValue(3.0));
-  }
-
-  void test_times_unknownInt_knownInt() {
-    _assertTimes(_intValue(null), _intValue(null), _intValue(3));
-  }
-
-  /**
-   * Assert that the result of adding the left and right operands is the expected value, or that the
-   * operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertAdd(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.add(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.add(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of bit-anding the left and right operands is the expected value, or that
-   * the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertBitAnd(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.bitAnd(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.bitAnd(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the bit-not of the operand is the expected value, or that the operation throws an
-   * exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param operand the operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertBitNot(DartObjectImpl expected, DartObjectImpl operand) {
-    if (expected == null) {
-      try {
-        operand.bitNot(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = operand.bitNot(_typeProvider);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of bit-oring the left and right operands is the expected value, or that
-   * the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertBitOr(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.bitOr(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.bitOr(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of bit-xoring the left and right operands is the expected value, or that
-   * the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertBitXor(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.bitXor(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.bitXor(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of concatenating the left and right operands is the expected value, or
-   * that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertConcatenate(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.concatenate(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.concatenate(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of dividing the left and right operands is the expected value, or that
-   * the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertDivide(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.divide(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.divide(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of comparing the left and right operands for equality is the expected
-   * value, or that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertEqualEqual(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.equalEqual(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.equalEqual(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of comparing the left and right operands is the expected value, or that
-   * the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertGreaterThan(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.greaterThan(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.greaterThan(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of comparing the left and right operands is the expected value, or that
-   * the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertGreaterThanOrEqual(DartObjectImpl expected,
-      DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.greaterThanOrEqual(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.greaterThanOrEqual(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of comparing the left and right operands using
-   * identical() is the expected value.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   */
-  void _assertIdentical(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    DartObjectImpl result =
-        leftOperand.isIdentical(_typeProvider, rightOperand);
-    expect(result, isNotNull);
-    expect(result, expected);
-  }
-
-  void _assertInstanceOfObjectArray(Object result) {
-    // TODO(scheglov) implement
-  }
-
-  /**
-   * Assert that the result of dividing the left and right operands as integers is the expected
-   * value, or that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertIntegerDivide(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.integerDivide(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.integerDivide(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of comparing the left and right operands is the expected value, or that
-   * the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertLessThan(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.lessThan(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.lessThan(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of comparing the left and right operands is the expected value, or that
-   * the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertLessThanOrEqual(DartObjectImpl expected,
-      DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.lessThanOrEqual(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.lessThanOrEqual(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of logical-anding the left and right operands is the expected value, or
-   * that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertLogicalAnd(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.logicalAnd(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.logicalAnd(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the logical-not of the operand is the expected value, or that the operation throws
-   * an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param operand the operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertLogicalNot(DartObjectImpl expected, DartObjectImpl operand) {
-    if (expected == null) {
-      try {
-        operand.logicalNot(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = operand.logicalNot(_typeProvider);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of logical-oring the left and right operands is the expected value, or
-   * that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertLogicalOr(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.logicalOr(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.logicalOr(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of subtracting the left and right operands is the expected value, or
-   * that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertMinus(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.minus(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.minus(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the negation of the operand is the expected value, or that the operation throws an
-   * exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param operand the operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertNegated(DartObjectImpl expected, DartObjectImpl operand) {
-    if (expected == null) {
-      try {
-        operand.negated(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = operand.negated(_typeProvider);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of comparing the left and right operands for inequality is the expected
-   * value, or that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertNotEqual(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.notEqual(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.notEqual(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that converting the operand to a string is the expected value, or that the operation
-   * throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param operand the operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertPerformToString(DartObjectImpl expected, DartObjectImpl operand) {
-    if (expected == null) {
-      try {
-        operand.performToString(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = operand.performToString(_typeProvider);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of taking the remainder of the left and right operands is the expected
-   * value, or that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertRemainder(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.remainder(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.remainder(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of multiplying the left and right operands is the expected value, or
-   * that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertShiftLeft(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.shiftLeft(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.shiftLeft(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of multiplying the left and right operands is the expected value, or
-   * that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertShiftRight(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.shiftRight(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result =
-          leftOperand.shiftRight(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the length of the operand is the expected value, or that the operation throws an
-   * exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param operand the operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertStringLength(DartObjectImpl expected, DartObjectImpl operand) {
-    if (expected == null) {
-      try {
-        operand.stringLength(_typeProvider);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = operand.stringLength(_typeProvider);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  /**
-   * Assert that the result of multiplying the left and right operands is the expected value, or
-   * that the operation throws an exception if the expected value is `null`.
-   *
-   * @param expected the expected result of the operation
-   * @param leftOperand the left operand to the operation
-   * @param rightOperand the left operand to the operation
-   * @throws EvaluationException if the result is an exception when it should not be
-   */
-  void _assertTimes(DartObjectImpl expected, DartObjectImpl leftOperand,
-      DartObjectImpl rightOperand) {
-    if (expected == null) {
-      try {
-        leftOperand.times(_typeProvider, rightOperand);
-        fail("Expected an EvaluationException");
-      } on EvaluationException {}
-    } else {
-      DartObjectImpl result = leftOperand.times(_typeProvider, rightOperand);
-      expect(result, isNotNull);
-      expect(result, expected);
-    }
-  }
-
-  DartObjectImpl _boolValue(bool value) {
-    if (value == null) {
-      return new DartObjectImpl(
-          _typeProvider.boolType, BoolState.UNKNOWN_VALUE);
-    } else if (identical(value, false)) {
-      return new DartObjectImpl(_typeProvider.boolType, BoolState.FALSE_STATE);
-    } else if (identical(value, true)) {
-      return new DartObjectImpl(_typeProvider.boolType, BoolState.TRUE_STATE);
-    }
-    fail("Invalid boolean value used in test");
-    return null;
-  }
-
-  DartObjectImpl _doubleValue(double value) {
-    if (value == null) {
-      return new DartObjectImpl(
-          _typeProvider.doubleType, DoubleState.UNKNOWN_VALUE);
-    } else {
-      return new DartObjectImpl(
-          _typeProvider.doubleType, new DoubleState(value));
-    }
-  }
-
-  DartObjectImpl _dynamicValue() {
-    return new DartObjectImpl(
-        _typeProvider.nullType, DynamicState.DYNAMIC_STATE);
-  }
-
-  DartObjectImpl _intValue(int value) {
-    if (value == null) {
-      return new DartObjectImpl(_typeProvider.intType, IntState.UNKNOWN_VALUE);
-    } else {
-      return new DartObjectImpl(_typeProvider.intType, new IntState(value));
-    }
-  }
-
-  DartObjectImpl _listValue(
-      [List<DartObjectImpl> elements = DartObjectImpl.EMPTY_LIST]) {
-    return new DartObjectImpl(_typeProvider.listType, new ListState(elements));
-  }
-
-  DartObjectImpl _mapValue(
-      [List<DartObjectImpl> keyElementPairs = DartObjectImpl.EMPTY_LIST]) {
-    Map<DartObjectImpl, DartObjectImpl> map =
-        new Map<DartObjectImpl, DartObjectImpl>();
-    int count = keyElementPairs.length;
-    for (int i = 0; i < count;) {
-      map[keyElementPairs[i++]] = keyElementPairs[i++];
-    }
-    return new DartObjectImpl(_typeProvider.mapType, new MapState(map));
-  }
-
-  DartObjectImpl _nullValue() {
-    return new DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE);
-  }
-
-  DartObjectImpl _numValue() {
-    return new DartObjectImpl(_typeProvider.nullType, NumState.UNKNOWN_VALUE);
-  }
-
-  DartObjectImpl _stringValue(String value) {
-    if (value == null) {
-      return new DartObjectImpl(
-          _typeProvider.stringType, StringState.UNKNOWN_VALUE);
-    } else {
-      return new DartObjectImpl(
-          _typeProvider.stringType, new StringState(value));
-    }
-  }
-
-  DartObjectImpl _symbolValue(String value) {
-    return new DartObjectImpl(_typeProvider.symbolType, new SymbolState(value));
-  }
-}
-
-@reflectiveTest
 class DartUriResolverTest {
   void test_creation() {
     JavaFile sdkDirectory = DirectoryBasedDartSdk.defaultSdkDirectory;
@@ -4389,102 +148,6 @@
 }
 
 @reflectiveTest
-class DeclaredVariablesTest extends EngineTestCase {
-  void test_getBool_false() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = new DeclaredVariables();
-    variables.define(variableName, "false");
-    DartObject object = variables.getBool(typeProvider, variableName);
-    expect(object, isNotNull);
-    expect(object.toBoolValue(), false);
-  }
-
-  void test_getBool_invalid() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = new DeclaredVariables();
-    variables.define(variableName, "not true");
-    _assertNullDartObject(
-        typeProvider, variables.getBool(typeProvider, variableName));
-  }
-
-  void test_getBool_true() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = new DeclaredVariables();
-    variables.define(variableName, "true");
-    DartObject object = variables.getBool(typeProvider, variableName);
-    expect(object, isNotNull);
-    expect(object.toBoolValue(), true);
-  }
-
-  void test_getBool_undefined() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = new DeclaredVariables();
-    _assertUnknownDartObject(
-        typeProvider.boolType, variables.getBool(typeProvider, variableName));
-  }
-
-  void test_getInt_invalid() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = new DeclaredVariables();
-    variables.define(variableName, "four score and seven years");
-    _assertNullDartObject(
-        typeProvider, variables.getInt(typeProvider, variableName));
-  }
-
-  void test_getInt_undefined() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = new DeclaredVariables();
-    _assertUnknownDartObject(
-        typeProvider.intType, variables.getInt(typeProvider, variableName));
-  }
-
-  void test_getInt_valid() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = new DeclaredVariables();
-    variables.define(variableName, "23");
-    DartObject object = variables.getInt(typeProvider, variableName);
-    expect(object, isNotNull);
-    expect(object.toIntValue(), 23);
-  }
-
-  void test_getString_defined() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    String value = "value";
-    DeclaredVariables variables = new DeclaredVariables();
-    variables.define(variableName, value);
-    DartObject object = variables.getString(typeProvider, variableName);
-    expect(object, isNotNull);
-    expect(object.toStringValue(), value);
-  }
-
-  void test_getString_undefined() {
-    TestTypeProvider typeProvider = new TestTypeProvider();
-    String variableName = "var";
-    DeclaredVariables variables = new DeclaredVariables();
-    _assertUnknownDartObject(typeProvider.stringType,
-        variables.getString(typeProvider, variableName));
-  }
-
-  void _assertNullDartObject(TestTypeProvider typeProvider, DartObject result) {
-    expect(result.type, typeProvider.nullType);
-  }
-
-  void _assertUnknownDartObject(
-      ParameterizedType expectedType, DartObject result) {
-    expect((result as DartObjectImpl).isUnknown, isTrue);
-    expect(result.type, expectedType);
-  }
-}
-
-@reflectiveTest
 class DirectoryBasedDartSdkTest {
   void fail_getDocFileFor() {
     DirectoryBasedDartSdk sdk = _createDartSdk();
@@ -4513,6 +176,31 @@
     expect(source.uri.toString(), "dart:core");
   }
 
+  void test_fromFile_library_firstExact() {
+    DirectoryBasedDartSdk sdk = _createDartSdk();
+    JavaFile dirHtml = new JavaFile.relative(sdk.libraryDirectory, "html");
+    JavaFile dirDartium = new JavaFile.relative(dirHtml, "dartium");
+    JavaFile file = new JavaFile.relative(dirDartium, "html_dartium.dart");
+    expect(file.isFile(), isTrue);
+    Source source = sdk.fromFileUri(file.toURI());
+    expect(source, isNotNull);
+    expect(source.isInSystemLibrary, isTrue);
+    expect(source.uri.toString(), "dart:html");
+  }
+
+  void test_fromFile_library_html_common_dart2js() {
+    DirectoryBasedDartSdk sdk = _createDartSdk();
+    JavaFile dirHtml = new JavaFile.relative(sdk.libraryDirectory, "html");
+    JavaFile dirCommon = new JavaFile.relative(dirHtml, "html_common");
+    JavaFile file =
+        new JavaFile.relative(dirCommon, "html_common_dart2js.dart");
+    expect(file.isFile(), isTrue);
+    Source source = sdk.fromFileUri(file.toURI());
+    expect(source, isNotNull);
+    expect(source.isInSystemLibrary, isTrue);
+    expect(source.uri.toString(), "dart:html_common/html_common_dart2js.dart");
+  }
+
   void test_fromFile_part() {
     DirectoryBasedDartSdk sdk = _createDartSdk();
     Source source = sdk.fromFileUri(new JavaFile.relative(
@@ -4603,11 +291,274 @@
 }
 
 @reflectiveTest
-class ElementBuilderTest extends EngineTestCase {
+class ElementBuilderTest extends ParserTestCase {
+  CompilationUnitElement compilationUnitElement;
+  CompilationUnit compilationUnit;
+
+  /**
+   * Parse the given [code], pass it through [ElementBuilder], and return the
+   * resulting [ElementHolder].
+   */
+  ElementHolder buildElementsForText(String code) {
+    TestLogger logger = new TestLogger();
+    AnalysisEngine.instance.logger = logger;
+    try {
+      compilationUnit = ParserTestCase.parseCompilationUnit(code);
+      ElementHolder holder = new ElementHolder();
+      ElementBuilder builder =
+          new ElementBuilder(holder, compilationUnitElement);
+      compilationUnit.accept(builder);
+      return holder;
+    } finally {
+      expect(logger.log, hasLength(0));
+      AnalysisEngine.instance.logger = Logger.NULL;
+    }
+  }
+
+  /**
+   * Verify that the given [metadata] has exactly one annotation, and that its
+   * [ElementAnnotationImpl] is unresolved.
+   */
+  void checkAnnotation(NodeList<Annotation> metadata) {
+    expect(metadata, hasLength(1));
+    expect(metadata[0], new isInstanceOf<AnnotationImpl>());
+    AnnotationImpl annotation = metadata[0];
+    expect(annotation.elementAnnotation,
+        new isInstanceOf<ElementAnnotationImpl>());
+    ElementAnnotationImpl elementAnnotation = annotation.elementAnnotation;
+    expect(elementAnnotation.element, isNull); // Not yet resolved
+    expect(elementAnnotation.compilationUnit, isNotNull);
+    expect(elementAnnotation.compilationUnit, compilationUnitElement);
+  }
+
+  /**
+   * Verify that the given [element] has exactly one annotation, and that its
+   * [ElementAnnotationImpl] is unresolved.
+   */
+  void checkMetadata(Element element) {
+    expect(element.metadata, hasLength(1));
+    expect(element.metadata[0], new isInstanceOf<ElementAnnotationImpl>());
+    ElementAnnotationImpl elementAnnotation = element.metadata[0];
+    expect(elementAnnotation.element, isNull); // Not yet resolved
+    expect(elementAnnotation.compilationUnit, isNotNull);
+    expect(elementAnnotation.compilationUnit, compilationUnitElement);
+  }
+
+  void fail_visitMethodDeclaration_setter_duplicate() {
+    // https://github.com/dart-lang/sdk/issues/25601
+    String code = r'''
+class C {
+  set zzz(x) {}
+  set zzz(y) {}
+}
+''';
+    ClassElement classElement = buildElementsForText(code).types[0];
+    for (PropertyAccessorElement accessor in classElement.accessors) {
+      expect(accessor.variable.setter, same(accessor));
+    }
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    compilationUnitElement = new CompilationUnitElementImpl('test.dart');
+  }
+
+  void test_metadata_fieldDeclaration() {
+    List<FieldElement> fields =
+        buildElementsForText('class C { @a int x, y; }').types[0].fields;
+    checkMetadata(fields[0]);
+    checkMetadata(fields[1]);
+    expect(fields[0].metadata, same(fields[1].metadata));
+  }
+
+  void test_metadata_localVariableDeclaration() {
+    List<LocalVariableElement> localVariables =
+        buildElementsForText('f() { @a int x, y; }')
+            .functions[0]
+            .localVariables;
+    checkMetadata(localVariables[0]);
+    checkMetadata(localVariables[1]);
+    expect(localVariables[0].metadata, same(localVariables[1].metadata));
+  }
+
+  void test_metadata_topLevelVariableDeclaration() {
+    List<TopLevelVariableElement> topLevelVariables =
+        buildElementsForText('@a int x, y;').topLevelVariables;
+    checkMetadata(topLevelVariables[0]);
+    checkMetadata(topLevelVariables[1]);
+    expect(topLevelVariables[0].metadata, same(topLevelVariables[1].metadata));
+  }
+
+  void test_metadata_visitClassDeclaration() {
+    ClassElement classElement = buildElementsForText('@a class C {}').types[0];
+    checkMetadata(classElement);
+  }
+
+  void test_metadata_visitClassTypeAlias() {
+    ClassElement classElement =
+        buildElementsForText('@a class C = D with E;').types[0];
+    checkMetadata(classElement);
+  }
+
+  void test_metadata_visitConstructorDeclaration() {
+    ConstructorElement constructorElement =
+        buildElementsForText('class C { @a C(); }').types[0].constructors[0];
+    checkMetadata(constructorElement);
+  }
+
+  void test_metadata_visitDeclaredIdentifier() {
+    LocalVariableElement localVariableElement =
+        buildElementsForText('f() { for (@a var x in y) {} }')
+            .functions[0]
+            .localVariables[0];
+    checkMetadata(localVariableElement);
+  }
+
+  void test_metadata_visitDefaultFormalParameter_fieldFormalParameter() {
+    ParameterElement parameterElement =
+        buildElementsForText('class C { var x; C([@a this.x = null]); }')
+            .types[0]
+            .constructors[0]
+            .parameters[0];
+    checkMetadata(parameterElement);
+  }
+
+  void
+      test_metadata_visitDefaultFormalParameter_functionTypedFormalParameter() {
+    ParameterElement parameterElement =
+        buildElementsForText('f([@a g() = null]) {}').functions[0].parameters[
+            0];
+    checkMetadata(parameterElement);
+  }
+
+  void test_metadata_visitDefaultFormalParameter_simpleFormalParameter() {
+    ParameterElement parameterElement =
+        buildElementsForText('f([@a gx = null]) {}').functions[0].parameters[0];
+    checkMetadata(parameterElement);
+  }
+
+  void test_metadata_visitEnumDeclaration() {
+    ClassElement classElement =
+        buildElementsForText('@a enum E { v }').enums[0];
+    checkMetadata(classElement);
+  }
+
+  void test_metadata_visitExportDirective() {
+    buildElementsForText('@a export "foo.dart";');
+    expect(compilationUnit.directives[0], new isInstanceOf<ExportDirective>());
+    ExportDirective exportDirective = compilationUnit.directives[0];
+    checkAnnotation(exportDirective.metadata);
+  }
+
+  void test_metadata_visitFieldFormalParameter() {
+    ParameterElement parameterElement =
+        buildElementsForText('class C { var x; C(@a this.x); }')
+            .types[0]
+            .constructors[0]
+            .parameters[0];
+    checkMetadata(parameterElement);
+  }
+
+  void test_metadata_visitFunctionDeclaration_function() {
+    FunctionElement functionElement =
+        buildElementsForText('@a f() {}').functions[0];
+    checkMetadata(functionElement);
+  }
+
+  void test_metadata_visitFunctionDeclaration_getter() {
+    PropertyAccessorElement propertyAccessorElement =
+        buildElementsForText('@a get f => null;').accessors[0];
+    checkMetadata(propertyAccessorElement);
+  }
+
+  void test_metadata_visitFunctionDeclaration_setter() {
+    PropertyAccessorElement propertyAccessorElement =
+        buildElementsForText('@a set f(value) {}').accessors[0];
+    checkMetadata(propertyAccessorElement);
+  }
+
+  void test_metadata_visitFunctionTypeAlias() {
+    FunctionTypeAliasElement functionTypeAliasElement =
+        buildElementsForText('@a typedef F();').typeAliases[0];
+    checkMetadata(functionTypeAliasElement);
+  }
+
+  void test_metadata_visitFunctionTypedFormalParameter() {
+    ParameterElement parameterElement =
+        buildElementsForText('f(@a g()) {}').functions[0].parameters[0];
+    checkMetadata(parameterElement);
+  }
+
+  void test_metadata_visitImportDirective() {
+    buildElementsForText('@a import "foo.dart";');
+    expect(compilationUnit.directives[0], new isInstanceOf<ImportDirective>());
+    ImportDirective importDirective = compilationUnit.directives[0];
+    checkAnnotation(importDirective.metadata);
+  }
+
+  void test_metadata_visitLibraryDirective() {
+    buildElementsForText('@a library L;');
+    expect(compilationUnit.directives[0], new isInstanceOf<LibraryDirective>());
+    LibraryDirective libraryDirective = compilationUnit.directives[0];
+    checkAnnotation(libraryDirective.metadata);
+  }
+
+  void test_metadata_visitMethodDeclaration_getter() {
+    PropertyAccessorElement propertyAccessorElement =
+        buildElementsForText('class C { @a get m => null; }')
+            .types[0]
+            .accessors[0];
+    checkMetadata(propertyAccessorElement);
+  }
+
+  void test_metadata_visitMethodDeclaration_method() {
+    MethodElement methodElement =
+        buildElementsForText('class C { @a m() {} }').types[0].methods[0];
+    checkMetadata(methodElement);
+  }
+
+  void test_metadata_visitMethodDeclaration_setter() {
+    PropertyAccessorElement propertyAccessorElement =
+        buildElementsForText('class C { @a set f(value) {} }')
+            .types[0]
+            .accessors[0];
+    checkMetadata(propertyAccessorElement);
+  }
+
+  void test_metadata_visitPartDirective() {
+    buildElementsForText('@a part "foo.dart";');
+    expect(compilationUnit.directives[0], new isInstanceOf<PartDirective>());
+    PartDirective partDirective = compilationUnit.directives[0];
+    checkAnnotation(partDirective.metadata);
+  }
+
+  void test_metadata_visitPartOfDirective() {
+    // We don't build ElementAnnotation objects for `part of` directives, since
+    // analyzer ignores them in favor of annotations on the library directive.
+    buildElementsForText('@a part of L;');
+    expect(compilationUnit.directives[0], new isInstanceOf<PartOfDirective>());
+    PartOfDirective partOfDirective = compilationUnit.directives[0];
+    expect(partOfDirective.metadata, hasLength(1));
+    expect(partOfDirective.metadata[0].elementAnnotation, isNull);
+  }
+
+  void test_metadata_visitSimpleFormalParameter() {
+    ParameterElement parameterElement =
+        buildElementsForText('f(@a x) {}').functions[0].parameters[0];
+    checkMetadata(parameterElement);
+  }
+
+  void test_metadata_visitTypeParameter() {
+    TypeParameterElement typeParameterElement =
+        buildElementsForText('class C<@a T> {}').types[0].typeParameters[0];
+    checkMetadata(typeParameterElement);
+  }
+
   void test_visitCatchClause() {
     // } catch (e, s) {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String exceptionParameterName = "e";
     String stackParameterName = "s";
     CatchClause clause =
@@ -4636,7 +587,7 @@
   void test_visitCatchClause_withType() {
     // } on E catch (e) {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String exceptionParameterName = "e";
     CatchClause clause = AstFactory.catchClause4(
         AstFactory.typeName4('E'), exceptionParameterName);
@@ -4652,7 +603,7 @@
 
   void test_visitClassDeclaration_abstract() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "C";
     ClassDeclaration classDeclaration = AstFactory.classDeclaration(
         Keyword.ABSTRACT, className, null, null, null, null);
@@ -4669,14 +620,47 @@
     expect(type.isSynthetic, isFalse);
   }
 
+  void test_visitClassDeclaration_invalidFunctionInAnnotation_class() {
+    // https://github.com/dart-lang/sdk/issues/25696
+    String code = r'''
+class A {
+  const A({f});
+}
+
+@A(f: () {})
+class C {}
+''';
+    buildElementsForText(code);
+  }
+
+  void test_visitClassDeclaration_invalidFunctionInAnnotation_method() {
+    String code = r'''
+class A {
+  const A({f});
+}
+
+class C {
+  @A(f: () {})
+  void m() {}
+}
+''';
+    ElementHolder holder = buildElementsForText(code);
+    ClassElement elementC = holder.types[1];
+    expect(elementC, isNotNull);
+    MethodElement methodM = elementC.methods[0];
+    expect(methodM, isNotNull);
+    expect(methodM.functions, isEmpty);
+  }
+
   void test_visitClassDeclaration_minimal() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "C";
     ClassDeclaration classDeclaration =
         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));
@@ -4688,12 +672,14 @@
     expect(type.isAbstract, isFalse);
     expect(type.isMixinApplication, isFalse);
     expect(type.isSynthetic, isFalse);
+    expect(type.documentationComment, '/// aaa');
     _assertHasDocRange(type, 50, 7);
+    _assertHasCodeRange(type, 50, 31);
   }
 
   void test_visitClassDeclaration_parameterized() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "C";
     String firstVariableName = "E";
     String secondVariableName = "F";
@@ -4721,7 +707,7 @@
 
   void test_visitClassDeclaration_withMembers() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "C";
     String typeParameterName = "E";
     String fieldName = "f";
@@ -4775,7 +761,7 @@
     // class M {}
     // class C = B with M
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     ClassElementImpl classB = ElementFactory.classElement2('B', []);
     ConstructorElementImpl constructorB =
         ElementFactory.constructorElement2(classB, '', []);
@@ -4805,7 +791,7 @@
     // class M {}
     // abstract class C = B with M
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     ClassElementImpl classB = ElementFactory.classElement2('B', []);
     ConstructorElementImpl constructorB =
         ElementFactory.constructorElement2(classB, '', []);
@@ -4829,7 +815,7 @@
     // class M {}
     // class C<T> = B with M
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     ClassElementImpl classB = ElementFactory.classElement2('B', []);
     ConstructorElementImpl constructorB =
         ElementFactory.constructorElement2(classB, '', []);
@@ -4853,12 +839,32 @@
     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 = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
-    ConstructorDeclaration constructorDeclaration = AstFactory
-        .constructorDeclaration2(
+    ConstructorDeclaration constructorDeclaration =
+        AstFactory.constructorDeclaration2(
             null,
             null,
             AstFactory.identifier3(className),
@@ -4884,10 +890,10 @@
 
   void test_visitConstructorDeclaration_factory() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
-    ConstructorDeclaration constructorDeclaration = AstFactory
-        .constructorDeclaration2(
+    ConstructorDeclaration constructorDeclaration =
+        AstFactory.constructorDeclaration2(
             null,
             Keyword.FACTORY,
             AstFactory.identifier3(className),
@@ -4911,10 +917,10 @@
 
   void test_visitConstructorDeclaration_minimal() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
-    ConstructorDeclaration constructorDeclaration = AstFactory
-        .constructorDeclaration2(
+    ConstructorDeclaration constructorDeclaration =
+        AstFactory.constructorDeclaration2(
             null,
             null,
             AstFactory.identifier3(className),
@@ -4925,12 +931,15 @@
     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);
     expect(constructor.isFactory, isFalse);
@@ -4943,11 +952,11 @@
 
   void test_visitConstructorDeclaration_named() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
     String constructorName = "c";
-    ConstructorDeclaration constructorDeclaration = AstFactory
-        .constructorDeclaration2(
+    ConstructorDeclaration constructorDeclaration =
+        AstFactory.constructorDeclaration2(
             null,
             null,
             AstFactory.identifier3(className),
@@ -4973,10 +982,10 @@
 
   void test_visitConstructorDeclaration_unnamed() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String className = "A";
-    ConstructorDeclaration constructorDeclaration = AstFactory
-        .constructorDeclaration2(
+    ConstructorDeclaration constructorDeclaration =
+        AstFactory.constructorDeclaration2(
             null,
             null,
             AstFactory.identifier3(className),
@@ -5002,17 +1011,20 @@
   void test_visitDeclaredIdentifier_noType() {
     // var i
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     var variableName = 'i';
     DeclaredIdentifier identifier =
         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);
@@ -5028,18 +1040,21 @@
   void test_visitDeclaredIdentifier_type() {
     // E i
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     var variableName = 'i';
     DeclaredIdentifier identifier =
         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);
@@ -5054,18 +1069,24 @@
   void test_visitDefaultFormalParameter_noType() {
     // p = 0
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String parameterName = 'p';
-    DefaultFormalParameter formalParameter = AstFactory
-        .positionalFormalParameter(
+    DefaultFormalParameter formalParameter =
+        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);
+    expect(parameter.initializer.hasImplicitReturnType, isTrue);
     expect(parameter.isConst, isFalse);
     expect(parameter.isDeprecated, isFalse);
     expect(parameter.isFinal, isFalse);
@@ -5080,7 +1101,7 @@
   void test_visitDefaultFormalParameter_type() {
     // E p = 0
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String parameterName = 'p';
     DefaultFormalParameter formalParameter = AstFactory.namedFormalParameter(
         AstFactory.simpleFormalParameter4(
@@ -5092,6 +1113,9 @@
     expect(parameters, hasLength(1));
     ParameterElement parameter = parameters[0];
     expect(parameter.hasImplicitType, isFalse);
+    expect(parameter.initializer, isNotNull);
+    expect(parameter.initializer.type, isNotNull);
+    expect(parameter.initializer.hasImplicitReturnType, isTrue);
     expect(parameter.isConst, isFalse);
     expect(parameter.isDeprecated, isFalse);
     expect(parameter.isFinal, isFalse);
@@ -5105,24 +1129,27 @@
 
   void test_visitEnumDeclaration() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String enumName = "E";
     EnumDeclaration enumDeclaration =
         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);
   }
 
   void test_visitFieldDeclaration() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String firstFieldName = "x";
     String secondFieldName = "y";
     FieldDeclaration fieldDeclaration =
@@ -5132,6 +1159,7 @@
     ]);
     fieldDeclaration.documentationComment = AstFactory.documentationComment(
         [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
+    fieldDeclaration.endToken.offset = 110;
     fieldDeclaration.accept(builder);
 
     List<FieldElement> fields = holder.fields;
@@ -5139,6 +1167,8 @@
 
     FieldElement firstField = fields[0];
     expect(firstField, isNotNull);
+    _assertHasCodeRange(firstField, 50, 61);
+    expect(firstField.documentationComment, '/// aaa');
     _assertHasDocRange(firstField, 50, 7);
     expect(firstField.name, firstFieldName);
     expect(firstField.initializer, isNull);
@@ -5148,6 +1178,8 @@
 
     FieldElement secondField = fields[1];
     expect(secondField, isNotNull);
+    _assertHasCodeRange(secondField, 50, 61);
+    expect(secondField.documentationComment, '/// aaa');
     _assertHasDocRange(secondField, 50, 7);
     expect(secondField.name, secondFieldName);
     expect(secondField.initializer, isNull);
@@ -5158,15 +1190,18 @@
 
   void test_visitFieldFormalParameter() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     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);
@@ -5176,9 +1211,9 @@
     expect(parameter.parameters, hasLength(0));
   }
 
-  void test_visitFieldFormalParameter_funtionTyped() {
+  void test_visitFieldFormalParameter_functionTyped() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String parameterName = "p";
     FieldFormalParameter formalParameter = AstFactory.fieldFormalParameter(
         null,
@@ -5202,7 +1237,7 @@
 
   void test_visitFormalParameterList() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String firstParameterName = "a";
     String secondParameterName = "b";
     FormalParameterList parameterList = AstFactory.formalParameterList([
@@ -5219,7 +1254,7 @@
   void test_visitFunctionDeclaration_external() {
     // external f();
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String functionName = "f";
     FunctionDeclaration declaration = AstFactory.functionDeclaration(
         null,
@@ -5247,7 +1282,7 @@
   void test_visitFunctionDeclaration_getter() {
     // get f() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String functionName = "f";
     FunctionDeclaration declaration = AstFactory.functionDeclaration(
         null,
@@ -5257,12 +1292,15 @@
             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);
     expect(declaration.element, same(accessor));
@@ -5282,7 +1320,7 @@
   void test_visitFunctionDeclaration_plain() {
     // T f() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String functionName = "f";
     FunctionDeclaration declaration = AstFactory.functionDeclaration(
         AstFactory.typeName4('T'),
@@ -5292,12 +1330,15 @@
             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);
     expect(function.name, functionName);
@@ -5311,7 +1352,7 @@
   void test_visitFunctionDeclaration_setter() {
     // set f() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String functionName = "f";
     FunctionDeclaration declaration = AstFactory.functionDeclaration(
         null,
@@ -5321,12 +1362,15 @@
             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);
     expect(accessor.name, "$functionName=");
@@ -5346,7 +1390,7 @@
   void test_visitFunctionDeclaration_typeParameters() {
     // f<E>() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String functionName = 'f';
     String typeParameterName = 'E';
     FunctionExpression expression = AstFactory.functionExpression3(
@@ -5376,7 +1420,7 @@
 
   void test_visitFunctionExpression() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     FunctionExpression expression = AstFactory.functionExpression2(
         AstFactory.formalParameterList(), AstFactory.blockFunctionBody2());
     expression.accept(builder);
@@ -5392,19 +1436,22 @@
 
   void test_visitFunctionTypeAlias() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String aliasName = "F";
     String parameterName = "E";
     FunctionTypeAlias aliasNode = AstFactory.typeAlias(
         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);
     expect(alias.parameters, hasLength(0));
@@ -5417,7 +1464,7 @@
 
   void test_visitFunctionTypedFormalParameter() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String parameterName = "p";
     FunctionTypedFormalParameter formalParameter =
         AstFactory.functionTypedFormalParameter(null, parameterName);
@@ -5440,7 +1487,7 @@
 
   void test_visitFunctionTypedFormalParameter_withTypeParameters() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String parameterName = "p";
     FunctionTypedFormalParameter formalParameter =
         AstFactory.functionTypedFormalParameter(null, parameterName);
@@ -5465,7 +1512,7 @@
 
   void test_visitLabeledStatement() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String labelName = "l";
     LabeledStatement statement = AstFactory.labeledStatement(
         [AstFactory.label2(labelName)], AstFactory.breakStatement());
@@ -5481,7 +1528,7 @@
   void test_visitMethodDeclaration_abstract() {
     // m();
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5513,7 +1560,7 @@
   void test_visitMethodDeclaration_external() {
     // external m();
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5547,7 +1594,7 @@
   void test_visitMethodDeclaration_getter() {
     // get m() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5559,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;
@@ -5570,6 +1618,8 @@
     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);
     expect(getter.isAbstract, isFalse);
@@ -5587,7 +1637,7 @@
   void test_visitMethodDeclaration_getter_abstract() {
     // get m();
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5624,7 +1674,7 @@
   void test_visitMethodDeclaration_getter_external() {
     // external get m();
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration(
         null,
@@ -5662,7 +1712,7 @@
   void test_visitMethodDeclaration_minimal() {
     // T m() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5674,12 +1724,15 @@
         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);
     expect(method.name, methodName);
@@ -5697,7 +1750,7 @@
   void test_visitMethodDeclaration_operator() {
     // operator +(addend) {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "+";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5730,7 +1783,7 @@
   void test_visitMethodDeclaration_setter() {
     // set m() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5742,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;
@@ -5754,6 +1808,8 @@
 
     PropertyAccessorElement setter = field.setter;
     expect(setter, isNotNull);
+    _assertHasCodeRange(setter, 50, 31);
+    expect(setter.documentationComment, '/// aaa');
     _assertHasDocRange(setter, 50, 7);
     expect(setter.hasImplicitReturnType, isTrue);
     expect(setter.isAbstract, isFalse);
@@ -5772,7 +1828,7 @@
   void test_visitMethodDeclaration_setter_abstract() {
     // set m();
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5810,7 +1866,7 @@
   void test_visitMethodDeclaration_setter_external() {
     // external m();
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration(
         null,
@@ -5849,7 +1905,7 @@
   void test_visitMethodDeclaration_static() {
     // static m() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         Keyword.STATIC,
@@ -5880,7 +1936,7 @@
   void test_visitMethodDeclaration_typeParameters() {
     // m<E>() {}
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     MethodDeclaration methodDeclaration = AstFactory.methodDeclaration2(
         null,
@@ -5913,7 +1969,7 @@
   void test_visitMethodDeclaration_withMembers() {
     // m(p) { var v; try { l: return; } catch (e) {} }
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String methodName = "m";
     String parameterName = "p";
     String localVariableName = "v";
@@ -5976,17 +2032,20 @@
 
   void test_visitNamedFormalParameter() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String parameterName = "p";
     DefaultFormalParameter formalParameter = AstFactory.namedFormalParameter(
         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);
@@ -6001,12 +2060,13 @@
     FunctionElement initializer = parameter.initializer;
     expect(initializer, isNotNull);
     expect(initializer.isSynthetic, isTrue);
+    expect(initializer.hasImplicitReturnType, isTrue);
   }
 
   void test_visitSimpleFormalParameter_noType() {
     // p
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String parameterName = "p";
     SimpleFormalParameter formalParameter =
         AstFactory.simpleFormalParameter3(parameterName);
@@ -6033,7 +2093,7 @@
   void test_visitSimpleFormalParameter_type() {
     // T p
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String parameterName = "p";
     SimpleFormalParameter formalParameter = AstFactory.simpleFormalParameter4(
         AstFactory.typeName4('T'), parameterName);
@@ -6059,7 +2119,7 @@
 
   void test_visitTypeAlias_minimal() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String aliasName = "F";
     TypeAlias typeAlias = AstFactory.typeAlias(null, aliasName, null, null);
     typeAlias.accept(builder);
@@ -6074,7 +2134,7 @@
 
   void test_visitTypeAlias_withFormalParameters() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String aliasName = "F";
     String firstParameterName = "x";
     String secondParameterName = "y";
@@ -6086,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);
@@ -6105,7 +2168,7 @@
 
   void test_visitTypeAlias_withTypeParameters() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String aliasName = "F";
     String firstTypeParameterName = "A";
     String secondTypeParameterName = "B";
@@ -6134,14 +2197,16 @@
 
   void test_visitTypeParameter() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    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);
@@ -6149,15 +2214,15 @@
 
   void test_visitVariableDeclaration_inConstructor() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     //
     // C() {var v;}
     //
     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,
@@ -6166,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;
@@ -6174,13 +2241,14 @@
         constructors[0].localVariables;
     expect(variableElements, hasLength(1));
     LocalVariableElement variableElement = variableElements[0];
+    _assertHasCodeRange(variableElement, 50, 31);
     expect(variableElement.hasImplicitType, isTrue);
     expect(variableElement.name, variableName);
   }
 
   void test_visitVariableDeclaration_inMethod() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     //
     // m() {T v;}
     //
@@ -6210,7 +2278,7 @@
 
   void test_visitVariableDeclaration_localNestedInFunction() {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     //
     // var f = () {var v;};
     //
@@ -6235,6 +2303,7 @@
     expect(fieldElement, isNotNull);
     FunctionElement initializerElement = fieldElement.initializer;
     expect(initializerElement, isNotNull);
+    expect(initializerElement.hasImplicitReturnType, isTrue);
     List<FunctionElement> functionElements = initializerElement.functions;
     expect(functionElements, hasLength(1));
     List<LocalVariableElement> variableElements =
@@ -6251,7 +2320,7 @@
   void test_visitVariableDeclaration_noInitializer() {
     // var v;
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String variableName = "v";
     VariableDeclaration variableDeclaration =
         AstFactory.variableDeclaration2(variableName, null);
@@ -6275,7 +2344,7 @@
   void test_visitVariableDeclaration_top_const_hasInitializer() {
     // const v = 42;
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String variableName = "v";
     VariableDeclaration variableDeclaration =
         AstFactory.variableDeclaration2(variableName, AstFactory.integer(42));
@@ -6287,6 +2356,8 @@
     TopLevelVariableElement variable = variables[0];
     expect(variable, new isInstanceOf<ConstTopLevelVariableElementImpl>());
     expect(variable.initializer, isNotNull);
+    expect(variable.initializer.type, isNotNull);
+    expect(variable.initializer.hasImplicitReturnType, isTrue);
     expect(variable.name, variableName);
     expect(variable.hasImplicitType, isTrue);
     expect(variable.isConst, isTrue);
@@ -6299,7 +2370,7 @@
   void test_visitVariableDeclaration_top_docRange() {
     // final a, b;
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     VariableDeclaration variableDeclaration1 =
         AstFactory.variableDeclaration('a');
     VariableDeclaration variableDeclaration2 =
@@ -6317,17 +2388,19 @@
 
     TopLevelVariableElement variable1 = variables[0];
     expect(variable1, isNotNull);
+    expect(variable1.documentationComment, '/// aaa');
     _assertHasDocRange(variable1, 50, 7);
 
     TopLevelVariableElement variable2 = variables[1];
     expect(variable2, isNotNull);
+    expect(variable2.documentationComment, '/// aaa');
     _assertHasDocRange(variable2, 50, 7);
   }
 
   void test_visitVariableDeclaration_top_final() {
     // final v;
     ElementHolder holder = new ElementHolder();
-    ElementBuilder builder = new ElementBuilder(holder);
+    ElementBuilder builder = _makeBuilder(holder);
     String variableName = "v";
     VariableDeclaration variableDeclaration =
         AstFactory.variableDeclaration2(variableName, null);
@@ -6347,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.
@@ -6356,6 +2435,9 @@
     expect(docRange.length, expectedLength);
   }
 
+  ElementBuilder _makeBuilder(ElementHolder holder) =>
+      new ElementBuilder(holder, new CompilationUnitElementImpl('test.dart'));
+
   void _useParameterInMethod(
       FormalParameter formalParameter, int blockOffset, int blockEnd) {
     Block block = AstFactory.block();
@@ -6462,7 +2544,8 @@
         (obj) => obj is FunctionElement, FunctionElement, element);
   }
 
-  void test_locate_Identifier_annotationClass_namedConstructor_forSimpleFormalParameter() {
+  void
+      test_locate_Identifier_annotationClass_namedConstructor_forSimpleFormalParameter() {
     AstNode id = _findNodeIndexedIn(
         "Class",
         2,
@@ -6477,7 +2560,8 @@
         (obj) => obj is ClassElement, ClassElement, element);
   }
 
-  void test_locate_Identifier_annotationClass_unnamedConstructor_forSimpleFormalParameter() {
+  void
+      test_locate_Identifier_annotationClass_unnamedConstructor_forSimpleFormalParameter() {
     AstNode id = _findNodeIndexedIn(
         "Class",
         2,
@@ -6532,7 +2616,7 @@
         (obj) => obj is FieldElement, FieldElement, element);
   }
 
-  void test_locate_Identifier_propertAccess() {
+  void test_locate_Identifier_propertyAccess() {
     AstNode id = _findNodeIn(
         "length",
         r'''
@@ -6584,8 +2668,8 @@
     SimpleIdentifier identifier = AstFactory.identifier3("A");
     PrefixedIdentifier prefixedIdentifier =
         AstFactory.identifier4("pref", identifier);
-    InstanceCreationExpression creation = AstFactory
-        .instanceCreationExpression2(
+    InstanceCreationExpression creation =
+        AstFactory.instanceCreationExpression2(
             Keyword.NEW, AstFactory.typeName3(prefixedIdentifier));
     // set ClassElement
     ClassElement classElement = ElementFactory.classElement2("A");
@@ -6602,8 +2686,8 @@
   void test_locate_InstanceCreationExpression_type_simpleIdentifier() {
     // prepare: new A()
     SimpleIdentifier identifier = AstFactory.identifier3("A");
-    InstanceCreationExpression creation = AstFactory
-        .instanceCreationExpression2(
+    InstanceCreationExpression creation =
+        AstFactory.instanceCreationExpression2(
             Keyword.NEW, AstFactory.typeName3(identifier));
     // set ClassElement
     ClassElement classElement = ElementFactory.classElement2("A");
@@ -6859,6 +2943,9 @@
     String firstName = "ONE";
     EnumDeclaration enumDeclaration =
         AstFactory.enumDeclaration2("E", [firstName]);
+    enumDeclaration.constants[0].documentationComment = AstFactory
+        .documentationComment(
+            [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
 
     ClassElement enumElement = _buildElement(enumDeclaration);
     List<FieldElement> fields = enumElement.fields;
@@ -6884,6 +2971,9 @@
     expect(constant.name, firstName);
     expect(constant.isStatic, isTrue);
     expect((constant as FieldElementImpl).evaluationResult, isNotNull);
+    expect(constant.documentationComment, '/// aaa');
+    expect(constant.docRange.offset, 50);
+    expect(constant.docRange.length, 7);
     _assertGetter(constant);
   }
 
@@ -6896,7 +2986,7 @@
 
   ClassElement _buildElement(EnumDeclaration enumDeclaration) {
     ElementHolder holder = new ElementHolder();
-    ElementBuilder elementBuilder = new ElementBuilder(holder);
+    ElementBuilder elementBuilder = _makeBuilder(holder);
     enumDeclaration.accept(elementBuilder);
     EnumMemberBuilder memberBuilder =
         new EnumMemberBuilder(new TestTypeProvider());
@@ -6905,6 +2995,9 @@
     expect(enums, hasLength(1));
     return enums[0];
   }
+
+  ElementBuilder _makeBuilder(ElementHolder holder) =>
+      new ElementBuilder(holder, new CompilationUnitElementImpl('test.dart'));
 }
 
 @reflectiveTest
@@ -8025,124 +4118,6 @@
   }
 }
 
-/**
- * Instances of the class `MockDartSdk` implement a [DartSdk].
- */
-class MockDartSdk implements DartSdk {
-  @override
-  AnalysisContext get context => null;
-
-  @override
-  List<SdkLibrary> get sdkLibraries => null;
-
-  @override
-  String get sdkVersion => null;
-
-  @override
-  List<String> get uris => null;
-
-  @override
-  Source fromFileUri(Uri uri) => null;
-
-  @override
-  SdkLibrary getSdkLibrary(String dartUri) => null;
-
-  @override
-  Source mapDartUri(String dartUri) => null;
-}
-
-@reflectiveTest
-class ReferenceFinderTest {
-  DirectedGraph<ConstantEvaluationTarget> _referenceGraph;
-  VariableElement _head;
-  Element _tail;
-
-  void setUp() {
-    _referenceGraph = new DirectedGraph<ConstantEvaluationTarget>();
-    _head = ElementFactory.topLevelVariableElement2("v1");
-  }
-
-  void test_visitSimpleIdentifier_const() {
-    _visitNode(_makeTailVariable("v2", true));
-    _assertOneArc(_tail);
-  }
-
-  void test_visitSimpleIdentifier_nonConst() {
-    _visitNode(_makeTailVariable("v2", false));
-    _assertOneArc(_tail);
-  }
-
-  void test_visitSuperConstructorInvocation_const() {
-    _visitNode(_makeTailSuperConstructorInvocation("A", true));
-    _assertOneArc(_tail);
-  }
-
-  void test_visitSuperConstructorInvocation_nonConst() {
-    _visitNode(_makeTailSuperConstructorInvocation("A", false));
-    _assertOneArc(_tail);
-  }
-
-  void test_visitSuperConstructorInvocation_unresolved() {
-    SuperConstructorInvocation superConstructorInvocation =
-        AstFactory.superConstructorInvocation();
-    _visitNode(superConstructorInvocation);
-    _assertNoArcs();
-  }
-
-  void _assertNoArcs() {
-    Set<ConstantEvaluationTarget> tails = _referenceGraph.getTails(_head);
-    expect(tails, hasLength(0));
-  }
-
-  void _assertOneArc(Element tail) {
-    Set<ConstantEvaluationTarget> tails = _referenceGraph.getTails(_head);
-    expect(tails, hasLength(1));
-    expect(tails.first, same(tail));
-  }
-
-  ReferenceFinder _createReferenceFinder(ConstantEvaluationTarget source) =>
-      new ReferenceFinder((ConstantEvaluationTarget dependency) {
-        _referenceGraph.addEdge(source, dependency);
-      });
-  SuperConstructorInvocation _makeTailSuperConstructorInvocation(
-      String name, bool isConst) {
-    List<ConstructorInitializer> initializers =
-        new List<ConstructorInitializer>();
-    ConstructorDeclaration constructorDeclaration = AstFactory
-        .constructorDeclaration(AstFactory.identifier3(name), null,
-            AstFactory.formalParameterList(), initializers);
-    if (isConst) {
-      constructorDeclaration.constKeyword = new KeywordToken(Keyword.CONST, 0);
-    }
-    ClassElementImpl classElement = ElementFactory.classElement2(name);
-    SuperConstructorInvocation superConstructorInvocation =
-        AstFactory.superConstructorInvocation();
-    ConstructorElementImpl constructorElement =
-        ElementFactory.constructorElement(classElement, name, isConst);
-    _tail = constructorElement;
-    superConstructorInvocation.staticElement = constructorElement;
-    return superConstructorInvocation;
-  }
-
-  SimpleIdentifier _makeTailVariable(String name, bool isConst) {
-    VariableDeclaration variableDeclaration =
-        AstFactory.variableDeclaration(name);
-    ConstLocalVariableElementImpl variableElement =
-        ElementFactory.constLocalVariableElement(name);
-    _tail = variableElement;
-    variableElement.const3 = isConst;
-    AstFactory.variableDeclarationList2(
-        isConst ? Keyword.CONST : Keyword.VAR, [variableDeclaration]);
-    SimpleIdentifier identifier = AstFactory.identifier3(name);
-    identifier.staticElement = variableElement;
-    return identifier;
-  }
-
-  void _visitNode(AstNode node) {
-    node.accept(_createReferenceFinder(_head));
-  }
-}
-
 @reflectiveTest
 class SDKLibrariesReaderTest extends EngineTestCase {
   void test_readFrom_dart2js() {
@@ -8218,16 +4193,6 @@
   }
 }
 
-class TestAnalysisContext_ConstantFinderTest extends TestAnalysisContext {
-  bool invoked = false;
-  TestAnalysisContext_ConstantFinderTest();
-
-  @override
-  InternalAnalysisContext getContextFor(Source source) {
-    return this;
-  }
-}
-
 @reflectiveTest
 class UriKindTest {
   void test_fromEncoding() {
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 5f2abf5..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();
@@ -897,7 +899,8 @@
     // TODO(paulberry): the error CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE is
     // redundant and ought to be suppressed.
     assertErrors(source, [
-      CompileTimeErrorCode.CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
+      CompileTimeErrorCode
+          .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
       CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
     ]);
     verify([source]);
@@ -1265,6 +1268,20 @@
     verify([source]);
   }
 
+  void test_constInitializedWithNonConstValue_finalField() {
+    // Regression test for bug #25526 which previously
+    // caused two errors to be reported.
+    Source source = addSource(r'''
+class Foo {
+  final field = [];
+  foo([int x = field]) {}
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE]);
+    verify([source]);
+  }
+
   void test_constInitializedWithNonConstValue_missingConstInListLiteral() {
     Source source = addSource("const List L = [0];");
     computeLibrarySourceErrors(source);
@@ -1291,7 +1308,8 @@
 import 'lib1.dart' deferred as a;
 const B = a.V;'''
     ], <ErrorCode>[
-      CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY
+      CompileTimeErrorCode
+          .CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY
     ]);
   }
 
@@ -1305,7 +1323,8 @@
 import 'lib1.dart' deferred as a;
 const B = a.V + 1;'''
     ], <ErrorCode>[
-      CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY
+      CompileTimeErrorCode
+          .CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY
     ]);
   }
 
@@ -1445,6 +1464,23 @@
     verify([source]);
   }
 
+  void test_constWithNonConst_with() {
+    Source source = addSource(r'''
+class B {
+  const B();
+}
+class C = B with M;
+class M {}
+const x = const C();
+main() {
+  print(x);
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [CompileTimeErrorCode.CONST_WITH_NON_CONST]);
+    verify([source]);
+  }
+
   void test_constWithNonConstantArgument_annotation() {
     Source source = addSource(r'''
 class A {
@@ -1652,24 +1688,6 @@
     verify([librarySource, sourceA, sourceB]);
   }
 
-  void test_duplicateDefinition_inPart() {
-    Source librarySource = addNamedSource(
-        "/lib.dart",
-        r'''
-library test;
-part 'a.dart';
-class A {}''');
-    Source sourceA = addNamedSource(
-        "/a.dart",
-        r'''
-part of test;
-class A {}''');
-    computeLibrarySourceErrors(librarySource);
-    assertErrors(sourceA, [CompileTimeErrorCode.DUPLICATE_DEFINITION]);
-    assertNoErrors(librarySource);
-    verify([librarySource, sourceA]);
-  }
-
   void test_duplicateDefinition_catch() {
     Source source = addSource(r'''
 main() {
@@ -1713,6 +1731,24 @@
     verify([source]);
   }
 
+  void test_duplicateDefinition_inPart() {
+    Source librarySource = addNamedSource(
+        "/lib.dart",
+        r'''
+library test;
+part 'a.dart';
+class A {}''');
+    Source sourceA = addNamedSource(
+        "/a.dart",
+        r'''
+part of test;
+class A {}''');
+    computeLibrarySourceErrors(librarySource);
+    assertErrors(sourceA, [CompileTimeErrorCode.DUPLICATE_DEFINITION]);
+    assertNoErrors(librarySource);
+    verify([librarySource, sourceA]);
+  }
+
   void test_duplicateDefinition_locals_inCase() {
     Source source = addSource(r'''
 main() {
@@ -1827,7 +1863,8 @@
     verify([source]);
   }
 
-  void test_duplicateDefinitionInheritance_instanceGetterAbstract_staticGetter() {
+  void
+      test_duplicateDefinitionInheritance_instanceGetterAbstract_staticGetter() {
     Source source = addSource(r'''
 abstract class A {
   int get x;
@@ -1855,7 +1892,8 @@
     verify([source]);
   }
 
-  void test_duplicateDefinitionInheritance_instanceMethodAbstract_staticMethod() {
+  void
+      test_duplicateDefinitionInheritance_instanceMethodAbstract_staticMethod() {
     Source source = addSource(r'''
 abstract class A {
   x();
@@ -1883,7 +1921,8 @@
     verify([source]);
   }
 
-  void test_duplicateDefinitionInheritance_instanceSetterAbstract_staticSetter() {
+  void
+      test_duplicateDefinitionInheritance_instanceSetterAbstract_staticSetter() {
     Source source = addSource(r'''
 abstract class A {
   set x(value);
@@ -1967,9 +2006,7 @@
   void test_extendsDisallowedClass_class_double() {
     Source source = addSource("class A extends double {}");
     computeLibrarySourceErrors(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS
-    ]);
+    assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
     verify([source]);
   }
 
@@ -1996,9 +2033,7 @@
   void test_extendsDisallowedClass_class_num() {
     Source source = addSource("class A extends num {}");
     computeLibrarySourceErrors(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS
-    ]);
+    assertErrors(source, [CompileTimeErrorCode.EXTENDS_DISALLOWED_CLASS]);
     verify([source]);
   }
 
@@ -2638,7 +2673,8 @@
     verify([source]);
   }
 
-  void test_implicitThisReferenceInInitializer_redirectingConstructorInvocation() {
+  void
+      test_implicitThisReferenceInInitializer_redirectingConstructorInvocation() {
     Source source = addSource(r'''
 class A {
   A(p) {}
@@ -3004,7 +3040,8 @@
     verify([source]);
   }
 
-  void test_invalidAnnotation_importWithPrefix_notVariableOrConstructorInvocation() {
+  void
+      test_invalidAnnotation_importWithPrefix_notVariableOrConstructorInvocation() {
     addNamedSource(
         "/lib.dart",
         r'''
@@ -3529,24 +3566,6 @@
     verify([source]);
   }
 
-  void test_missingEnumConstantInSwitch() {
-    Source source = addSource(r'''
-enum E { ONE, TWO, THREE, FOUR }
-bool odd(E e) {
-  switch (e) {
-    case E.ONE:
-    case E.THREE: return true;
-  }
-  return false;
-}''');
-    computeLibrarySourceErrors(source);
-    assertErrors(source, [
-      CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
-      CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH
-    ]);
-    verify([source]);
-  }
-
   void test_mixinDeclaresConstructor_classDeclaration() {
     Source source = addSource(r'''
 class A {
@@ -4653,7 +4672,8 @@
   const A() : x = a.c;
 }'''
     ], <ErrorCode>[
-      CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
+      CompileTimeErrorCode
+          .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
     ]);
   }
 
@@ -4670,7 +4690,8 @@
   const A() : x = a.c + 1;
 }'''
     ], <ErrorCode>[
-      CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
+      CompileTimeErrorCode
+          .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
     ]);
   }
 
@@ -4687,7 +4708,8 @@
   const A() : this.named(a.c);
 }'''
     ], <ErrorCode>[
-      CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
+      CompileTimeErrorCode
+          .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
     ]);
   }
 
@@ -4706,7 +4728,8 @@
   const B() : super(a.c);
 }'''
     ], <ErrorCode>[
-      CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
+      CompileTimeErrorCode
+          .NON_CONSTANT_VALUE_IN_INITIALIZER_FROM_DEFERRED_LIBRARY
     ]);
   }
 
@@ -6022,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/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
new file mode 100644
index 0000000..bb9ba02
--- /dev/null
+++ b/pkg/analyzer/test/generated/constant_test.dart
@@ -0,0 +1,4541 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.constant_test;
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
+import 'package:analyzer/src/generated/testing/element_factory.dart';
+import 'package:analyzer/src/generated/testing/test_type_provider.dart';
+import 'package:analyzer/src/generated/utilities_collection.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:path/path.dart';
+import 'package:unittest/unittest.dart';
+
+import '../reflective_tests.dart';
+import '../utils.dart';
+import 'engine_test.dart';
+import 'resolver_test.dart';
+import 'test_support.dart';
+
+main() {
+  initializeTestEnvironment();
+  runReflectiveTests(ConstantEvaluatorTest);
+  runReflectiveTests(ConstantFinderTest);
+  runReflectiveTests(ConstantValueComputerTest);
+  runReflectiveTests(ConstantVisitorTest);
+  runReflectiveTests(DartObjectImplTest);
+  runReflectiveTests(DeclaredVariablesTest);
+  runReflectiveTests(ReferenceFinderTest);
+}
+
+const int LONG_MAX_VALUE = 0x7fffffffffffffff;
+
+/**
+ * Implementation of [ConstantEvaluationValidator] used during unit tests;
+ * verifies that any nodes referenced during constant evaluation are present in
+ * the dependency graph.
+ */
+class ConstantEvaluationValidator_ForTest
+    implements ConstantEvaluationValidator {
+  final InternalAnalysisContext context;
+  ConstantValueComputer computer;
+  ConstantEvaluationTarget _nodeBeingEvaluated;
+
+  ConstantEvaluationValidator_ForTest(this.context);
+
+  @override
+  void beforeComputeValue(ConstantEvaluationTarget constant) {
+    _nodeBeingEvaluated = constant;
+  }
+
+  @override
+  void beforeGetConstantInitializers(ConstructorElement constructor) =>
+      _checkPathTo(constructor);
+
+  @override
+  void beforeGetEvaluationResult(ConstantEvaluationTarget constant) =>
+      _checkPathTo(constant);
+
+  @override
+  void beforeGetFieldEvaluationResult(FieldElementImpl field) =>
+      _checkPathTo(field);
+
+  @override
+  void beforeGetParameterDefault(ParameterElement parameter) =>
+      _checkPathTo(parameter);
+
+  void _checkPathTo(ConstantEvaluationTarget target) {
+    if (computer.referenceGraph.containsPath(_nodeBeingEvaluated, target)) {
+      return; // pass
+    }
+    // print a nice error message on failure
+    StringBuffer out = new StringBuffer();
+    out.writeln("missing path in constant dependency graph");
+    out.writeln("from $_nodeBeingEvaluated to $target");
+    for (var s in context.analysisCache.sources) {
+      String text = context.getContents(s).data;
+      if (text != "") {
+        out.writeln('''
+=== ${s.shortName}
+$text''');
+      }
+    }
+    fail(out.toString());
+  }
+}
+
+@reflectiveTest
+class ConstantEvaluatorTest extends ResolverTestCase {
+  void fail_constructor() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_identifier_class() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_identifier_function() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_identifier_static() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_identifier_staticMethod() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_identifier_topLevel() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_identifier_typeParameter() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_prefixedIdentifier_invalid() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_prefixedIdentifier_valid() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_propertyAccess_invalid() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_propertyAccess_valid() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_simpleIdentifier_invalid() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void fail_simpleIdentifier_valid() {
+    EvaluationResult result = _getExpressionValue("?");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value, null);
+  }
+
+  void test_bitAnd_int_int() {
+    _assertValue3(74 & 42, "74 & 42");
+  }
+
+  void test_bitNot() {
+    _assertValue3(~42, "~42");
+  }
+
+  void test_bitOr_int_int() {
+    _assertValue3(74 | 42, "74 | 42");
+  }
+
+  void test_bitXor_int_int() {
+    _assertValue3(74 ^ 42, "74 ^ 42");
+  }
+
+  void test_divide_double_double() {
+    _assertValue2(3.2 / 2.3, "3.2 / 2.3");
+  }
+
+  void test_divide_double_double_byZero() {
+    EvaluationResult result = _getExpressionValue("3.2 / 0.0");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value.type.name, "double");
+    expect(value.toDoubleValue().isInfinite, isTrue);
+  }
+
+  void test_divide_int_int() {
+    _assertValue2(1.5, "3 / 2");
+  }
+
+  void test_divide_int_int_byZero() {
+    EvaluationResult result = _getExpressionValue("3 / 0");
+    expect(result.isValid, isTrue);
+  }
+
+  void test_equal_boolean_boolean() {
+    _assertValue(false, "true == false");
+  }
+
+  void test_equal_int_int() {
+    _assertValue(false, "2 == 3");
+  }
+
+  void test_equal_invalidLeft() {
+    EvaluationResult result = _getExpressionValue("a == 3");
+    expect(result.isValid, isFalse);
+  }
+
+  void test_equal_invalidRight() {
+    EvaluationResult result = _getExpressionValue("2 == a");
+    expect(result.isValid, isFalse);
+  }
+
+  void test_equal_string_string() {
+    _assertValue(false, "'a' == 'b'");
+  }
+
+  void test_greaterThan_int_int() {
+    _assertValue(false, "2 > 3");
+  }
+
+  void test_greaterThanOrEqual_int_int() {
+    _assertValue(false, "2 >= 3");
+  }
+
+  void test_leftShift_int_int() {
+    _assertValue3(64, "16 << 2");
+  }
+
+  void test_lessThan_int_int() {
+    _assertValue(true, "2 < 3");
+  }
+
+  void test_lessThanOrEqual_int_int() {
+    _assertValue(true, "2 <= 3");
+  }
+
+  void test_literal_boolean_false() {
+    _assertValue(false, "false");
+  }
+
+  void test_literal_boolean_true() {
+    _assertValue(true, "true");
+  }
+
+  void test_literal_list() {
+    EvaluationResult result = _getExpressionValue("const ['a', 'b', 'c']");
+    expect(result.isValid, isTrue);
+  }
+
+  void test_literal_map() {
+    EvaluationResult result =
+        _getExpressionValue("const {'a' : 'm', 'b' : 'n', 'c' : 'o'}");
+    expect(result.isValid, isTrue);
+    Map<DartObject, DartObject> map = result.value.toMapValue();
+    expect(map.keys.map((k) => k.toStringValue()), ['a', 'b', 'c']);
+  }
+
+  void test_literal_null() {
+    EvaluationResult result = _getExpressionValue("null");
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value.isNull, isTrue);
+  }
+
+  void test_literal_number_double() {
+    _assertValue2(3.45, "3.45");
+  }
+
+  void test_literal_number_integer() {
+    _assertValue3(42, "42");
+  }
+
+  void test_literal_string_adjacent() {
+    _assertValue4("abcdef", "'abc' 'def'");
+  }
+
+  void test_literal_string_interpolation_invalid() {
+    EvaluationResult result = _getExpressionValue("'a\${f()}c'");
+    expect(result.isValid, isFalse);
+  }
+
+  void test_literal_string_interpolation_valid() {
+    _assertValue4("a3c", "'a\${3}c'");
+  }
+
+  void test_literal_string_simple() {
+    _assertValue4("abc", "'abc'");
+  }
+
+  void test_logicalAnd() {
+    _assertValue(false, "true && false");
+  }
+
+  void test_logicalNot() {
+    _assertValue(false, "!true");
+  }
+
+  void test_logicalOr() {
+    _assertValue(true, "true || false");
+  }
+
+  void test_minus_double_double() {
+    _assertValue2(3.2 - 2.3, "3.2 - 2.3");
+  }
+
+  void test_minus_int_int() {
+    _assertValue3(1, "3 - 2");
+  }
+
+  void test_negated_boolean() {
+    EvaluationResult result = _getExpressionValue("-true");
+    expect(result.isValid, isFalse);
+  }
+
+  void test_negated_double() {
+    _assertValue2(-42.3, "-42.3");
+  }
+
+  void test_negated_integer() {
+    _assertValue3(-42, "-42");
+  }
+
+  void test_notEqual_boolean_boolean() {
+    _assertValue(true, "true != false");
+  }
+
+  void test_notEqual_int_int() {
+    _assertValue(true, "2 != 3");
+  }
+
+  void test_notEqual_invalidLeft() {
+    EvaluationResult result = _getExpressionValue("a != 3");
+    expect(result.isValid, isFalse);
+  }
+
+  void test_notEqual_invalidRight() {
+    EvaluationResult result = _getExpressionValue("2 != a");
+    expect(result.isValid, isFalse);
+  }
+
+  void test_notEqual_string_string() {
+    _assertValue(true, "'a' != 'b'");
+  }
+
+  void test_parenthesizedExpression() {
+    _assertValue4("a", "('a')");
+  }
+
+  void test_plus_double_double() {
+    _assertValue2(2.3 + 3.2, "2.3 + 3.2");
+  }
+
+  void test_plus_int_int() {
+    _assertValue3(5, "2 + 3");
+  }
+
+  void test_plus_string_string() {
+    _assertValue4("ab", "'a' + 'b'");
+  }
+
+  void test_remainder_double_double() {
+    _assertValue2(3.2 % 2.3, "3.2 % 2.3");
+  }
+
+  void test_remainder_int_int() {
+    _assertValue3(2, "8 % 3");
+  }
+
+  void test_rightShift() {
+    _assertValue3(16, "64 >> 2");
+  }
+
+  void test_stringLength_complex() {
+    _assertValue3(6, "('qwe' + 'rty').length");
+  }
+
+  void test_stringLength_simple() {
+    _assertValue3(6, "'Dvorak'.length");
+  }
+
+  void test_times_double_double() {
+    _assertValue2(2.3 * 3.2, "2.3 * 3.2");
+  }
+
+  void test_times_int_int() {
+    _assertValue3(6, "2 * 3");
+  }
+
+  void test_truncatingDivide_double_double() {
+    _assertValue3(1, "3.2 ~/ 2.3");
+  }
+
+  void test_truncatingDivide_int_int() {
+    _assertValue3(3, "10 ~/ 3");
+  }
+
+  void _assertValue(bool expectedValue, String contents) {
+    EvaluationResult result = _getExpressionValue(contents);
+    DartObject value = result.value;
+    expect(value.type.name, "bool");
+    expect(value.toBoolValue(), expectedValue);
+  }
+
+  void _assertValue2(double expectedValue, String contents) {
+    EvaluationResult result = _getExpressionValue(contents);
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value.type.name, "double");
+    expect(value.toDoubleValue(), expectedValue);
+  }
+
+  void _assertValue3(int expectedValue, String contents) {
+    EvaluationResult result = _getExpressionValue(contents);
+    expect(result.isValid, isTrue);
+    DartObject value = result.value;
+    expect(value.type.name, "int");
+    expect(value.toIntValue(), expectedValue);
+  }
+
+  void _assertValue4(String expectedValue, String contents) {
+    EvaluationResult result = _getExpressionValue(contents);
+    DartObject value = result.value;
+    expect(value, isNotNull);
+    ParameterizedType type = value.type;
+    expect(type, isNotNull);
+    expect(type.name, "String");
+    expect(value.toStringValue(), expectedValue);
+  }
+
+  EvaluationResult _getExpressionValue(String contents) {
+    Source source = addSource("var x = $contents;");
+    LibraryElement library = resolve2(source);
+    CompilationUnit unit =
+        analysisContext.resolveCompilationUnit(source, library);
+    expect(unit, isNotNull);
+    NodeList<CompilationUnitMember> declarations = unit.declarations;
+    expect(declarations, hasLength(1));
+    CompilationUnitMember declaration = declarations[0];
+    EngineTestCase.assertInstanceOf((obj) => obj is TopLevelVariableDeclaration,
+        TopLevelVariableDeclaration, declaration);
+    NodeList<VariableDeclaration> variables =
+        (declaration as TopLevelVariableDeclaration).variables.variables;
+    expect(variables, hasLength(1));
+    ConstantEvaluator evaluator = new ConstantEvaluator(
+        source, analysisContext.typeProvider,
+        typeSystem: analysisContext.typeSystem);
+    return evaluator.evaluate(variables[0].initializer);
+  }
+}
+
+@reflectiveTest
+class ConstantFinderTest {
+  AstNode _node;
+  TypeProvider _typeProvider;
+  AnalysisContext _context;
+  Source _source;
+
+  void setUp() {
+    _typeProvider = new TestTypeProvider();
+    _context = new _TestAnalysisContext();
+    _source = new TestSource();
+  }
+
+  /**
+   * Test an annotation that consists solely of an identifier (and hence
+   * represents a reference to a compile-time constant variable).
+   */
+  void test_visitAnnotation_constantVariable() {
+    CompilationUnitElement compilationUnitElement =
+        ElementFactory.compilationUnit('/test.dart', _source)..source = _source;
+    ElementFactory.library(_context, 'L').definingCompilationUnit =
+        compilationUnitElement;
+    ElementAnnotationImpl elementAnnotation =
+        new ElementAnnotationImpl(compilationUnitElement);
+    _node = elementAnnotation.annotationAst = AstFactory.annotation(
+        AstFactory.identifier3('x'))..elementAnnotation = elementAnnotation;
+    expect(_findAnnotations(), contains(_node));
+  }
+
+  /**
+   * Test an annotation that represents the invocation of a constant
+   * constructor.
+   */
+  void test_visitAnnotation_invocation() {
+    CompilationUnitElement compilationUnitElement =
+        ElementFactory.compilationUnit('/test.dart', _source)..source = _source;
+    ElementFactory.library(_context, 'L').definingCompilationUnit =
+        compilationUnitElement;
+    ElementAnnotationImpl elementAnnotation =
+        new ElementAnnotationImpl(compilationUnitElement);
+    _node = elementAnnotation.annotationAst = AstFactory.annotation2(
+        AstFactory.identifier3('A'), null, AstFactory.argumentList())
+      ..elementAnnotation = elementAnnotation;
+    expect(_findAnnotations(), contains(_node));
+  }
+
+  void test_visitAnnotation_partOf() {
+    // Analyzer ignores annotations on "part of" directives.
+    Annotation annotation = AstFactory.annotation2(
+        AstFactory.identifier3('A'), null, AstFactory.argumentList());
+    _node = AstFactory.partOfDirective2(
+        <Annotation>[annotation], AstFactory.libraryIdentifier2(<String>['L']));
+    expect(_findConstants(), isEmpty);
+  }
+
+  void test_visitConstructorDeclaration_const() {
+    ConstructorElement element = _setupConstructorDeclaration("A", true);
+    expect(_findConstants(), contains(element));
+  }
+
+  void test_visitConstructorDeclaration_nonConst() {
+    _setupConstructorDeclaration("A", false);
+    expect(_findConstants(), isEmpty);
+  }
+
+  void test_visitVariableDeclaration_const() {
+    VariableElement element = _setupVariableDeclaration("v", true, true);
+    expect(_findConstants(), contains(element));
+  }
+
+  void test_visitVariableDeclaration_final_inClass() {
+    _setupFieldDeclaration('C', 'f', Keyword.FINAL);
+    expect(_findConstants(), isEmpty);
+  }
+
+  void test_visitVariableDeclaration_final_inClassWithConstConstructor() {
+    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
+        hasConstConstructor: true);
+    expect(_findConstants(), contains(field.element));
+  }
+
+  void test_visitVariableDeclaration_final_outsideClass() {
+    _setupVariableDeclaration('v', false, true, isFinal: true);
+    expect(_findConstants(), isEmpty);
+  }
+
+  void test_visitVariableDeclaration_noInitializer() {
+    _setupVariableDeclaration("v", true, false);
+    expect(_findConstants(), isEmpty);
+  }
+
+  void test_visitVariableDeclaration_nonConst() {
+    _setupVariableDeclaration("v", false, true);
+    expect(_findConstants(), isEmpty);
+  }
+
+  void test_visitVariableDeclaration_static_const_inClass() {
+    VariableDeclaration field =
+        _setupFieldDeclaration('C', 'f', Keyword.CONST, isStatic: true);
+    expect(_findConstants(), contains(field.element));
+  }
+
+  void
+      test_visitVariableDeclaration_static_const_inClassWithConstConstructor() {
+    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.CONST,
+        isStatic: true, hasConstConstructor: true);
+    expect(_findConstants(), contains(field.element));
+  }
+
+  void
+      test_visitVariableDeclaration_static_final_inClassWithConstConstructor() {
+    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
+        isStatic: true, hasConstConstructor: true);
+    expect(_findConstants(), isNot(contains(field.element)));
+  }
+
+  void
+      test_visitVariableDeclaration_uninitialized_final_inClassWithConstConstructor() {
+    VariableDeclaration field = _setupFieldDeclaration('C', 'f', Keyword.FINAL,
+        isInitialized: false, hasConstConstructor: true);
+    expect(_findConstants(), isNot(contains(field.element)));
+  }
+
+  void test_visitVariableDeclaration_uninitialized_static_const_inClass() {
+    _setupFieldDeclaration('C', 'f', Keyword.CONST,
+        isStatic: true, isInitialized: false);
+    expect(_findConstants(), isEmpty);
+  }
+
+  List<Annotation> _findAnnotations() {
+    Set<Annotation> annotations = new Set<Annotation>();
+    for (ConstantEvaluationTarget target in _findConstants()) {
+      if (target is ElementAnnotationImpl) {
+        expect(target.context, same(_context));
+        expect(target.source, same(_source));
+        annotations.add(target.annotationAst);
+      }
+    }
+    return new List<Annotation>.from(annotations);
+  }
+
+  List<ConstantEvaluationTarget> _findConstants() {
+    ConstantFinder finder = new ConstantFinder(_context, _source, _source);
+    _node.accept(finder);
+    List<ConstantEvaluationTarget> constants = finder.constantsToCompute;
+    expect(constants, isNotNull);
+    return constants;
+  }
+
+  ConstructorElement _setupConstructorDeclaration(String name, bool isConst) {
+    Keyword constKeyword = isConst ? Keyword.CONST : null;
+    ConstructorDeclaration constructorDeclaration =
+        AstFactory.constructorDeclaration2(
+            constKeyword,
+            null,
+            null,
+            name,
+            AstFactory.formalParameterList(),
+            null,
+            AstFactory.blockFunctionBody2());
+    ClassElement classElement = ElementFactory.classElement2(name);
+    ConstructorElement element =
+        ElementFactory.constructorElement(classElement, name, isConst);
+    constructorDeclaration.element = element;
+    _node = constructorDeclaration;
+    return element;
+  }
+
+  VariableDeclaration _setupFieldDeclaration(
+      String className, String fieldName, Keyword keyword,
+      {bool isInitialized: true,
+      bool isStatic: false,
+      bool hasConstConstructor: false}) {
+    VariableDeclaration variableDeclaration = isInitialized
+        ? AstFactory.variableDeclaration2(fieldName, AstFactory.integer(0))
+        : AstFactory.variableDeclaration(fieldName);
+    VariableElement fieldElement = ElementFactory.fieldElement(
+        fieldName,
+        isStatic,
+        keyword == Keyword.FINAL,
+        keyword == Keyword.CONST,
+        _typeProvider.intType);
+    variableDeclaration.name.staticElement = fieldElement;
+    FieldDeclaration fieldDeclaration = AstFactory.fieldDeclaration2(
+        isStatic, keyword, <VariableDeclaration>[variableDeclaration]);
+    ClassDeclaration classDeclaration =
+        AstFactory.classDeclaration(null, className, null, null, null, null);
+    classDeclaration.members.add(fieldDeclaration);
+    _node = classDeclaration;
+    ClassElementImpl classElement = ElementFactory.classElement2(className);
+    classElement.fields = <FieldElement>[fieldElement];
+    classDeclaration.name.staticElement = classElement;
+    if (hasConstConstructor) {
+      ConstructorDeclaration constructorDeclaration =
+          AstFactory.constructorDeclaration2(
+              Keyword.CONST,
+              null,
+              AstFactory.identifier3(className),
+              null,
+              AstFactory.formalParameterList(),
+              null,
+              AstFactory.blockFunctionBody2());
+      classDeclaration.members.add(constructorDeclaration);
+      ConstructorElement constructorElement =
+          ElementFactory.constructorElement(classElement, '', true);
+      constructorDeclaration.element = constructorElement;
+      classElement.constructors = <ConstructorElement>[constructorElement];
+    } else {
+      classElement.constructors = ConstructorElement.EMPTY_LIST;
+    }
+    return variableDeclaration;
+  }
+
+  VariableElement _setupVariableDeclaration(
+      String name, bool isConst, bool isInitialized,
+      {isFinal: false}) {
+    VariableDeclaration variableDeclaration = isInitialized
+        ? AstFactory.variableDeclaration2(name, AstFactory.integer(0))
+        : AstFactory.variableDeclaration(name);
+    SimpleIdentifier identifier = variableDeclaration.name;
+    VariableElement element = ElementFactory.localVariableElement(identifier);
+    identifier.staticElement = element;
+    Keyword keyword = isConst ? Keyword.CONST : isFinal ? Keyword.FINAL : null;
+    AstFactory.variableDeclarationList2(keyword, [variableDeclaration]);
+    _node = variableDeclaration;
+    return element;
+  }
+}
+
+@reflectiveTest
+class ConstantValueComputerTest extends ResolverTestCase {
+  void test_annotation_constConstructor() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+  final int i;
+  const A(this.i);
+}
+
+class C {
+  @A(5)
+  f() {}
+}
+''');
+    EvaluationResultImpl result =
+        _evaluateAnnotation(compilationUnit, "C", "f");
+    Map<String, DartObjectImpl> annotationFields = _assertType(result, 'A');
+    _assertIntField(annotationFields, 'i', 5);
+  }
+
+  void test_annotation_constConstructor_named() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+  final int i;
+  const A.named(this.i);
+}
+
+class C {
+  @A.named(5)
+  f() {}
+}
+''');
+    EvaluationResultImpl result =
+        _evaluateAnnotation(compilationUnit, "C", "f");
+    Map<String, DartObjectImpl> annotationFields = _assertType(result, 'A');
+    _assertIntField(annotationFields, 'i', 5);
+  }
+
+  void test_annotation_constConstructor_noArgs() {
+    // Failing to pass arguments to an annotation which is a constant
+    // constructor is illegal, but shouldn't crash analysis.
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+  final int i;
+  const A(this.i);
+}
+
+class C {
+  @A
+  f() {}
+}
+''');
+    _evaluateAnnotation(compilationUnit, "C", "f");
+  }
+
+  void test_annotation_constConstructor_noArgs_named() {
+    // Failing to pass arguments to an annotation which is a constant
+    // constructor is illegal, but shouldn't crash analysis.
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+  final int i;
+  const A.named(this.i);
+}
+
+class C {
+  @A.named
+  f() {}
+}
+''');
+    _evaluateAnnotation(compilationUnit, "C", "f");
+  }
+
+  void test_annotation_nonConstConstructor() {
+    // Calling a non-const constructor from an annotation that is illegal, but
+    // shouldn't crash analysis.
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+  final int i;
+  A(this.i);
+}
+
+class C {
+  @A(5)
+  f() {}
+}
+''');
+    _evaluateAnnotation(compilationUnit, "C", "f");
+  }
+
+  void test_annotation_staticConst() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+class C {
+  static const int i = 5;
+
+  @i
+  f() {}
+}
+''');
+    EvaluationResultImpl result =
+        _evaluateAnnotation(compilationUnit, "C", "f");
+    expect(_assertValidInt(result), 5);
+  }
+
+  void test_annotation_staticConst_args() {
+    // Applying arguments to an annotation that is a static const is
+    // illegal, but shouldn't crash analysis.
+    CompilationUnit compilationUnit = resolveSource(r'''
+class C {
+  static const int i = 5;
+
+  @i(1)
+  f() {}
+}
+''');
+    _evaluateAnnotation(compilationUnit, "C", "f");
+  }
+
+  void test_annotation_staticConst_otherClass() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+  static const int i = 5;
+}
+
+class C {
+  @A.i
+  f() {}
+}
+''');
+    EvaluationResultImpl result =
+        _evaluateAnnotation(compilationUnit, "C", "f");
+    expect(_assertValidInt(result), 5);
+  }
+
+  void test_annotation_staticConst_otherClass_args() {
+    // Applying arguments to an annotation that is a static const is
+    // illegal, but shouldn't crash analysis.
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+  static const int i = 5;
+}
+
+class C {
+  @A.i(1)
+  f() {}
+}
+''');
+    _evaluateAnnotation(compilationUnit, "C", "f");
+  }
+
+  void test_annotation_topLevelVariable() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const int i = 5;
+class C {
+  @i
+  f() {}
+}
+''');
+    EvaluationResultImpl result =
+        _evaluateAnnotation(compilationUnit, "C", "f");
+    expect(_assertValidInt(result), 5);
+  }
+
+  void test_annotation_topLevelVariable_args() {
+    // Applying arguments to an annotation that is a top-level variable is
+    // illegal, but shouldn't crash analysis.
+    CompilationUnit compilationUnit = resolveSource(r'''
+const int i = 5;
+class C {
+  @i(1)
+  f() {}
+}
+''');
+    _evaluateAnnotation(compilationUnit, "C", "f");
+  }
+
+  void test_computeValues_cycle() {
+    TestLogger logger = new TestLogger();
+    AnalysisEngine.instance.logger = logger;
+    try {
+      Source source = addSource(r'''
+  const int a = c;
+  const int b = a;
+  const int c = b;''');
+      LibraryElement libraryElement = resolve2(source);
+      CompilationUnit unit =
+          analysisContext.resolveCompilationUnit(source, libraryElement);
+      analysisContext.computeErrors(source);
+      expect(unit, isNotNull);
+      ConstantValueComputer computer = _makeConstantValueComputer();
+      computer.add(unit, source, source);
+      computer.computeValues();
+      NodeList<CompilationUnitMember> members = unit.declarations;
+      expect(members, hasLength(3));
+      _validate(false, (members[0] as TopLevelVariableDeclaration).variables);
+      _validate(false, (members[1] as TopLevelVariableDeclaration).variables);
+      _validate(false, (members[2] as TopLevelVariableDeclaration).variables);
+    } finally {
+      AnalysisEngine.instance.logger = Logger.NULL;
+    }
+  }
+
+  void test_computeValues_dependentVariables() {
+    Source source = addSource(r'''
+const int b = a;
+const int a = 0;''');
+    LibraryElement libraryElement = resolve2(source);
+    CompilationUnit unit =
+        analysisContext.resolveCompilationUnit(source, libraryElement);
+    expect(unit, isNotNull);
+    ConstantValueComputer computer = _makeConstantValueComputer();
+    computer.add(unit, source, source);
+    computer.computeValues();
+    NodeList<CompilationUnitMember> members = unit.declarations;
+    expect(members, hasLength(2));
+    _validate(true, (members[0] as TopLevelVariableDeclaration).variables);
+    _validate(true, (members[1] as TopLevelVariableDeclaration).variables);
+  }
+
+  void test_computeValues_empty() {
+    ConstantValueComputer computer = _makeConstantValueComputer();
+    computer.computeValues();
+  }
+
+  void test_computeValues_multipleSources() {
+    Source librarySource = addNamedSource(
+        "/lib.dart",
+        r'''
+library lib;
+part 'part.dart';
+const int c = b;
+const int a = 0;''');
+    Source partSource = addNamedSource(
+        "/part.dart",
+        r'''
+part of lib;
+const int b = a;
+const int d = c;''');
+    LibraryElement libraryElement = resolve2(librarySource);
+    CompilationUnit libraryUnit =
+        analysisContext.resolveCompilationUnit(librarySource, libraryElement);
+    expect(libraryUnit, isNotNull);
+    CompilationUnit partUnit =
+        analysisContext.resolveCompilationUnit(partSource, libraryElement);
+    expect(partUnit, isNotNull);
+    ConstantValueComputer computer = _makeConstantValueComputer();
+    computer.add(libraryUnit, librarySource, librarySource);
+    computer.add(partUnit, partSource, librarySource);
+    computer.computeValues();
+    NodeList<CompilationUnitMember> libraryMembers = libraryUnit.declarations;
+    expect(libraryMembers, hasLength(2));
+    _validate(
+        true, (libraryMembers[0] as TopLevelVariableDeclaration).variables);
+    _validate(
+        true, (libraryMembers[1] as TopLevelVariableDeclaration).variables);
+    NodeList<CompilationUnitMember> partMembers = libraryUnit.declarations;
+    expect(partMembers, hasLength(2));
+    _validate(true, (partMembers[0] as TopLevelVariableDeclaration).variables);
+    _validate(true, (partMembers[1] as TopLevelVariableDeclaration).variables);
+  }
+
+  void test_computeValues_singleVariable() {
+    Source source = addSource("const int a = 0;");
+    LibraryElement libraryElement = resolve2(source);
+    CompilationUnit unit =
+        analysisContext.resolveCompilationUnit(source, libraryElement);
+    expect(unit, isNotNull);
+    ConstantValueComputer computer = _makeConstantValueComputer();
+    computer.add(unit, source, source);
+    computer.computeValues();
+    NodeList<CompilationUnitMember> members = unit.declarations;
+    expect(members, hasLength(1));
+    _validate(true, (members[0] as TopLevelVariableDeclaration).variables);
+  }
+
+  void test_computeValues_value_depends_on_enum() {
+    Source source = addSource('''
+enum E { id0, id1 }
+const E e = E.id0;
+''');
+    LibraryElement libraryElement = resolve2(source);
+    CompilationUnit unit =
+        analysisContext.resolveCompilationUnit(source, libraryElement);
+    expect(unit, isNotNull);
+    ConstantValueComputer computer = _makeConstantValueComputer();
+    computer.add(unit, source, source);
+    computer.computeValues();
+    TopLevelVariableDeclaration declaration = unit.declarations
+        .firstWhere((member) => member is TopLevelVariableDeclaration);
+    _validate(true, declaration.variables);
+  }
+
+  void test_dependencyOnConstructor() {
+    // x depends on "const A()"
+    _assertProperDependencies(r'''
+class A {
+  const A();
+}
+const x = const A();''');
+  }
+
+  void test_dependencyOnConstructorArgument() {
+    // "const A(x)" depends on x
+    _assertProperDependencies(r'''
+class A {
+  const A(this.next);
+  final A next;
+}
+const A x = const A(null);
+const A y = const A(x);''');
+  }
+
+  void test_dependencyOnConstructorArgument_unresolvedConstructor() {
+    // "const A.a(x)" depends on x even if the constructor A.a can't be found.
+    _assertProperDependencies(
+        r'''
+class A {
+}
+const int x = 1;
+const A y = const A.a(x);''',
+        [CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR]);
+  }
+
+  void test_dependencyOnConstructorInitializer() {
+    // "const A()" depends on x
+    _assertProperDependencies(r'''
+const int x = 1;
+class A {
+  const A() : v = x;
+  final int v;
+}''');
+  }
+
+  void test_dependencyOnExplicitSuperConstructor() {
+    // b depends on B() depends on A()
+    _assertProperDependencies(r'''
+class A {
+  const A(this.x);
+  final int x;
+}
+class B extends A {
+  const B() : super(5);
+}
+const B b = const B();''');
+  }
+
+  void test_dependencyOnExplicitSuperConstructorParameters() {
+    // b depends on B() depends on i
+    _assertProperDependencies(r'''
+class A {
+  const A(this.x);
+  final int x;
+}
+class B extends A {
+  const B() : super(i);
+}
+const B b = const B();
+const int i = 5;''');
+  }
+
+  void test_dependencyOnFactoryRedirect() {
+    // a depends on A.foo() depends on A.bar()
+    _assertProperDependencies(r'''
+const A a = const A.foo();
+class A {
+  factory const A.foo() = A.bar;
+  const A.bar();
+}''');
+  }
+
+  void test_dependencyOnFactoryRedirectWithTypeParams() {
+    _assertProperDependencies(r'''
+class A {
+  const factory A(var a) = B<int>;
+}
+
+class B<T> implements A {
+  final T x;
+  const B(this.x);
+}
+
+const A a = const A(10);''');
+  }
+
+  void test_dependencyOnImplicitSuperConstructor() {
+    // b depends on B() depends on A()
+    _assertProperDependencies(r'''
+class A {
+  const A() : x = 5;
+  final int x;
+}
+class B extends A {
+  const B();
+}
+const B b = const B();''');
+  }
+
+  void test_dependencyOnInitializedFinal() {
+    // a depends on A() depends on A.x
+    _assertProperDependencies('''
+class A {
+  const A();
+  final int x = 1;
+}
+const A a = const A();
+''');
+  }
+
+  void test_dependencyOnInitializedNonStaticConst() {
+    // Even though non-static consts are not allowed by the language, we need
+    // to handle them for error recovery purposes.
+    // a depends on A() depends on A.x
+    _assertProperDependencies(
+        '''
+class A {
+  const A();
+  const int x = 1;
+}
+const A a = const A();
+''',
+        [CompileTimeErrorCode.CONST_INSTANCE_FIELD]);
+  }
+
+  void test_dependencyOnNonFactoryRedirect() {
+    // a depends on A.foo() depends on A.bar()
+    _assertProperDependencies(r'''
+const A a = const A.foo();
+class A {
+  const A.foo() : this.bar();
+  const A.bar();
+}''');
+  }
+
+  void test_dependencyOnNonFactoryRedirect_arg() {
+    // a depends on A.foo() depends on b
+    _assertProperDependencies(r'''
+const A a = const A.foo();
+const int b = 1;
+class A {
+  const A.foo() : this.bar(b);
+  const A.bar(x) : y = x;
+  final int y;
+}''');
+  }
+
+  void test_dependencyOnNonFactoryRedirect_defaultValue() {
+    // a depends on A.foo() depends on A.bar() depends on b
+    _assertProperDependencies(r'''
+const A a = const A.foo();
+const int b = 1;
+class A {
+  const A.foo() : this.bar();
+  const A.bar([x = b]) : y = x;
+  final int y;
+}''');
+  }
+
+  void test_dependencyOnNonFactoryRedirect_toMissing() {
+    // a depends on A.foo() which depends on nothing, since A.bar() is
+    // missing.
+    _assertProperDependencies(
+        r'''
+const A a = const A.foo();
+class A {
+  const A.foo() : this.bar();
+}''',
+        [CompileTimeErrorCode.REDIRECT_GENERATIVE_TO_MISSING_CONSTRUCTOR]);
+  }
+
+  void test_dependencyOnNonFactoryRedirect_toNonConst() {
+    // a depends on A.foo() which depends on nothing, since A.bar() is
+    // non-const.
+    _assertProperDependencies(r'''
+const A a = const A.foo();
+class A {
+  const A.foo() : this.bar();
+  A.bar();
+}''');
+  }
+
+  void test_dependencyOnNonFactoryRedirect_unnamed() {
+    // a depends on A.foo() depends on A()
+    _assertProperDependencies(r'''
+const A a = const A.foo();
+class A {
+  const A.foo() : this();
+  const A();
+}''');
+  }
+
+  void test_dependencyOnOptionalParameterDefault() {
+    // a depends on A() depends on B()
+    _assertProperDependencies(r'''
+class A {
+  const A([x = const B()]) : b = x;
+  final B b;
+}
+class B {
+  const B();
+}
+const A a = const A();''');
+  }
+
+  void test_dependencyOnVariable() {
+    // x depends on y
+    _assertProperDependencies(r'''
+const x = y + 1;
+const y = 2;''');
+  }
+
+  void test_final_initialized_at_declaration() {
+    CompilationUnit compilationUnit = resolveSource('''
+class A {
+  final int i = 123;
+  const A();
+}
+
+const A a = const A();
+''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, 'a');
+    Map<String, DartObjectImpl> fields = _assertType(result, "A");
+    expect(fields, hasLength(1));
+    _assertIntField(fields, "i", 123);
+  }
+
+  void test_fromEnvironment_bool_default_false() {
+    expect(_assertValidBool(_check_fromEnvironment_bool(null, "false")), false);
+  }
+
+  void test_fromEnvironment_bool_default_overridden() {
+    expect(
+        _assertValidBool(_check_fromEnvironment_bool("false", "true")), false);
+  }
+
+  void test_fromEnvironment_bool_default_parseError() {
+    expect(_assertValidBool(_check_fromEnvironment_bool("parseError", "true")),
+        true);
+  }
+
+  void test_fromEnvironment_bool_default_true() {
+    expect(_assertValidBool(_check_fromEnvironment_bool(null, "true")), true);
+  }
+
+  void test_fromEnvironment_bool_false() {
+    expect(_assertValidBool(_check_fromEnvironment_bool("false", null)), false);
+  }
+
+  void test_fromEnvironment_bool_parseError() {
+    expect(_assertValidBool(_check_fromEnvironment_bool("parseError", null)),
+        false);
+  }
+
+  void test_fromEnvironment_bool_true() {
+    expect(_assertValidBool(_check_fromEnvironment_bool("true", null)), true);
+  }
+
+  void test_fromEnvironment_bool_undeclared() {
+    _assertValidUnknown(_check_fromEnvironment_bool(null, null));
+  }
+
+  void test_fromEnvironment_int_default_overridden() {
+    expect(_assertValidInt(_check_fromEnvironment_int("234", "123")), 234);
+  }
+
+  void test_fromEnvironment_int_default_parseError() {
+    expect(
+        _assertValidInt(_check_fromEnvironment_int("parseError", "123")), 123);
+  }
+
+  void test_fromEnvironment_int_default_undeclared() {
+    expect(_assertValidInt(_check_fromEnvironment_int(null, "123")), 123);
+  }
+
+  void test_fromEnvironment_int_ok() {
+    expect(_assertValidInt(_check_fromEnvironment_int("234", null)), 234);
+  }
+
+  void test_fromEnvironment_int_parseError() {
+    _assertValidNull(_check_fromEnvironment_int("parseError", null));
+  }
+
+  void test_fromEnvironment_int_parseError_nullDefault() {
+    _assertValidNull(_check_fromEnvironment_int("parseError", "null"));
+  }
+
+  void test_fromEnvironment_int_undeclared() {
+    _assertValidUnknown(_check_fromEnvironment_int(null, null));
+  }
+
+  void test_fromEnvironment_int_undeclared_nullDefault() {
+    _assertValidNull(_check_fromEnvironment_int(null, "null"));
+  }
+
+  void test_fromEnvironment_string_default_overridden() {
+    expect(_assertValidString(_check_fromEnvironment_string("abc", "'def'")),
+        "abc");
+  }
+
+  void test_fromEnvironment_string_default_undeclared() {
+    expect(_assertValidString(_check_fromEnvironment_string(null, "'def'")),
+        "def");
+  }
+
+  void test_fromEnvironment_string_empty() {
+    expect(_assertValidString(_check_fromEnvironment_string("", null)), "");
+  }
+
+  void test_fromEnvironment_string_ok() {
+    expect(
+        _assertValidString(_check_fromEnvironment_string("abc", null)), "abc");
+  }
+
+  void test_fromEnvironment_string_undeclared() {
+    _assertValidUnknown(_check_fromEnvironment_string(null, null));
+  }
+
+  void test_fromEnvironment_string_undeclared_nullDefault() {
+    _assertValidNull(_check_fromEnvironment_string(null, "null"));
+  }
+
+  void test_instanceCreationExpression_computedField() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(4, 5);
+class A {
+  const A(int i, int j) : k = 2 * i + j;
+  final int k;
+}''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "foo");
+    Map<String, DartObjectImpl> fields = _assertType(result, "A");
+    expect(fields, hasLength(1));
+    _assertIntField(fields, "k", 13);
+  }
+
+  void
+      test_instanceCreationExpression_computedField_namedOptionalWithDefault() {
+    _checkInstanceCreationOptionalParams(false, true, true);
+  }
+
+  void
+      test_instanceCreationExpression_computedField_namedOptionalWithoutDefault() {
+    _checkInstanceCreationOptionalParams(false, true, false);
+  }
+
+  void
+      test_instanceCreationExpression_computedField_unnamedOptionalWithDefault() {
+    _checkInstanceCreationOptionalParams(false, false, true);
+  }
+
+  void
+      test_instanceCreationExpression_computedField_unnamedOptionalWithoutDefault() {
+    _checkInstanceCreationOptionalParams(false, false, false);
+  }
+
+  void test_instanceCreationExpression_computedField_usesConstConstructor() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(3);
+class A {
+  const A(int i) : b = const B(4);
+  final int b;
+}
+class B {
+  const B(this.k);
+  final int k;
+}''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "foo");
+    Map<String, DartObjectImpl> fieldsOfA = _assertType(result, "A");
+    expect(fieldsOfA, hasLength(1));
+    Map<String, DartObjectImpl> fieldsOfB =
+        _assertFieldType(fieldsOfA, "b", "B");
+    expect(fieldsOfB, hasLength(1));
+    _assertIntField(fieldsOfB, "k", 4);
+  }
+
+  void test_instanceCreationExpression_computedField_usesStaticConst() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(3);
+class A {
+  const A(int i) : k = i + B.bar;
+  final int k;
+}
+class B {
+  static const bar = 4;
+}''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "foo");
+    Map<String, DartObjectImpl> fields = _assertType(result, "A");
+    expect(fields, hasLength(1));
+    _assertIntField(fields, "k", 7);
+  }
+
+  void test_instanceCreationExpression_computedField_usesTopLevelConst() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(3);
+const bar = 4;
+class A {
+  const A(int i) : k = i + bar;
+  final int k;
+}''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "foo");
+    Map<String, DartObjectImpl> fields = _assertType(result, "A");
+    expect(fields, hasLength(1));
+    _assertIntField(fields, "k", 7);
+  }
+
+  void test_instanceCreationExpression_explicitSuper() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const B(4, 5);
+class A {
+  const A(this.x);
+  final int x;
+}
+class B extends A {
+  const B(int x, this.y) : super(x * 2);
+  final int y;
+}''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "foo");
+    Map<String, DartObjectImpl> fields = _assertType(result, "B");
+    expect(fields, hasLength(2));
+    _assertIntField(fields, "y", 5);
+    Map<String, DartObjectImpl> superclassFields =
+        _assertFieldType(fields, GenericState.SUPERCLASS_FIELD, "A");
+    expect(superclassFields, hasLength(1));
+    _assertIntField(superclassFields, "x", 8);
+  }
+
+  void test_instanceCreationExpression_fieldFormalParameter() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A(42);
+class A {
+  int x;
+  const A(this.x)
+}''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "foo");
+    Map<String, DartObjectImpl> fields = _assertType(result, "A");
+    expect(fields, hasLength(1));
+    _assertIntField(fields, "x", 42);
+  }
+
+  void
+      test_instanceCreationExpression_fieldFormalParameter_namedOptionalWithDefault() {
+    _checkInstanceCreationOptionalParams(true, true, true);
+  }
+
+  void
+      test_instanceCreationExpression_fieldFormalParameter_namedOptionalWithoutDefault() {
+    _checkInstanceCreationOptionalParams(true, true, false);
+  }
+
+  void
+      test_instanceCreationExpression_fieldFormalParameter_unnamedOptionalWithDefault() {
+    _checkInstanceCreationOptionalParams(true, false, true);
+  }
+
+  void
+      test_instanceCreationExpression_fieldFormalParameter_unnamedOptionalWithoutDefault() {
+    _checkInstanceCreationOptionalParams(true, false, false);
+  }
+
+  void test_instanceCreationExpression_implicitSuper() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const B(4);
+class A {
+  const A() : x = 3;
+  final int x;
+}
+class B extends A {
+  const B(this.y);
+  final int y;
+}''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "foo");
+    Map<String, DartObjectImpl> fields = _assertType(result, "B");
+    expect(fields, hasLength(2));
+    _assertIntField(fields, "y", 4);
+    Map<String, DartObjectImpl> superclassFields =
+        _assertFieldType(fields, GenericState.SUPERCLASS_FIELD, "A");
+    expect(superclassFields, hasLength(1));
+    _assertIntField(superclassFields, "x", 3);
+  }
+
+  void test_instanceCreationExpression_nonFactoryRedirect() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+  const A.a1() : this.a2();
+  const A.a2() : x = 5;
+  final int x;
+}''');
+    Map<String, DartObjectImpl> aFields =
+        _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+    _assertIntField(aFields, 'x', 5);
+  }
+
+  void test_instanceCreationExpression_nonFactoryRedirect_arg() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1(1);
+class A {
+  const A.a1(x) : this.a2(x + 100);
+  const A.a2(x) : y = x + 10;
+  final int y;
+}''');
+    Map<String, DartObjectImpl> aFields =
+        _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+    _assertIntField(aFields, 'y', 111);
+  }
+
+  void test_instanceCreationExpression_nonFactoryRedirect_cycle() {
+    // It is an error to have a cycle in non-factory redirects; however, we
+    // need to make sure that even if the error occurs, attempting to evaluate
+    // the constant will terminate.
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+  const A() : this.b();
+  const A.b() : this();
+}''');
+    _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
+  }
+
+  void test_instanceCreationExpression_nonFactoryRedirect_defaultArg() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+  const A.a1() : this.a2();
+  const A.a2([x = 100]) : y = x + 10;
+  final int y;
+}''');
+    Map<String, DartObjectImpl> aFields =
+        _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+    _assertIntField(aFields, 'y', 110);
+  }
+
+  void test_instanceCreationExpression_nonFactoryRedirect_toMissing() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+  const A.a1() : this.a2();
+}''');
+    // We don't care what value foo evaluates to (since there is a compile
+    // error), but we shouldn't crash, and we should figure
+    // out that it evaluates to an instance of class A.
+    _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+  }
+
+  void test_instanceCreationExpression_nonFactoryRedirect_toNonConst() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+  const A.a1() : this.a2();
+  A.a2();
+}''');
+    // We don't care what value foo evaluates to (since there is a compile
+    // error), but we shouldn't crash, and we should figure
+    // out that it evaluates to an instance of class A.
+    _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+  }
+
+  void test_instanceCreationExpression_nonFactoryRedirect_unnamed() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A.a1();
+class A {
+  const A.a1() : this();
+  const A() : x = 5;
+  final int x;
+}''');
+    Map<String, DartObjectImpl> aFields =
+        _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "A");
+    _assertIntField(aFields, 'x', 5);
+  }
+
+  void test_instanceCreationExpression_redirect() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+  const factory A() = B;
+}
+class B implements A {
+  const B();
+}''');
+    _assertType(_evaluateTopLevelVariable(compilationUnit, "foo"), "B");
+  }
+
+  void test_instanceCreationExpression_redirect_cycle() {
+    // It is an error to have a cycle in factory redirects; however, we need
+    // to make sure that even if the error occurs, attempting to evaluate the
+    // constant will terminate.
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+  const factory A() = A.b;
+  const factory A.b() = A;
+}''');
+    _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
+  }
+
+  void test_instanceCreationExpression_redirect_external() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+  external const factory A();
+}''');
+    _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
+  }
+
+  void test_instanceCreationExpression_redirect_nonConst() {
+    // It is an error for a const factory constructor redirect to a non-const
+    // constructor; however, we need to make sure that even if the error
+    // attempting to evaluate the constant won't cause a crash.
+    CompilationUnit compilationUnit = resolveSource(r'''
+const foo = const A();
+class A {
+  const factory A() = A.b;
+  A.b();
+}''');
+    _assertValidUnknown(_evaluateTopLevelVariable(compilationUnit, "foo"));
+  }
+
+  void test_instanceCreationExpression_redirectWithTypeParams() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A {
+  const factory A(var a) = B<int>;
+}
+
+class B<T> implements A {
+  final T x;
+  const B(this.x);
+}
+
+const A a = const A(10);''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "a");
+    Map<String, DartObjectImpl> fields = _assertType(result, "B<int>");
+    expect(fields, hasLength(1));
+    _assertIntField(fields, "x", 10);
+  }
+
+  void test_instanceCreationExpression_redirectWithTypeSubstitution() {
+    // To evaluate the redirection of A<int>,
+    // A's template argument (T=int) must be substituted
+    // into B's template argument (B<U> where U=T) to get B<int>.
+    CompilationUnit compilationUnit = resolveSource(r'''
+class A<T> {
+  const factory A(var a) = B<T>;
+}
+
+class B<U> implements A {
+  final U x;
+  const B(this.x);
+}
+
+const A<int> a = const A<int>(10);''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, "a");
+    Map<String, DartObjectImpl> fields = _assertType(result, "B<int>");
+    expect(fields, hasLength(1));
+    _assertIntField(fields, "x", 10);
+  }
+
+  void test_instanceCreationExpression_symbol() {
+    CompilationUnit compilationUnit =
+        resolveSource("const foo = const Symbol('a');");
+    EvaluationResultImpl evaluationResult =
+        _evaluateTopLevelVariable(compilationUnit, "foo");
+    expect(evaluationResult.value, isNotNull);
+    DartObjectImpl value = evaluationResult.value;
+    expect(value.type, typeProvider.symbolType);
+    expect(value.toSymbolValue(), "a");
+  }
+
+  void test_instanceCreationExpression_withSupertypeParams_explicit() {
+    _checkInstanceCreation_withSupertypeParams(true);
+  }
+
+  void test_instanceCreationExpression_withSupertypeParams_implicit() {
+    _checkInstanceCreation_withSupertypeParams(false);
+  }
+
+  void test_instanceCreationExpression_withTypeParams() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+class C<E> {
+  const C();
+}
+const c_int = const C<int>();
+const c_num = const C<num>();''');
+    EvaluationResultImpl c_int =
+        _evaluateTopLevelVariable(compilationUnit, "c_int");
+    _assertType(c_int, "C<int>");
+    DartObjectImpl c_int_value = c_int.value;
+    EvaluationResultImpl c_num =
+        _evaluateTopLevelVariable(compilationUnit, "c_num");
+    _assertType(c_num, "C<num>");
+    DartObjectImpl c_num_value = c_num.value;
+    expect(c_int_value == c_num_value, isFalse);
+  }
+
+  void test_isValidSymbol() {
+    expect(ConstantEvaluationEngine.isValidPublicSymbol(""), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.bar"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo\$"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo\$bar"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("iff"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("gif"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("if\$"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("\$if"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo="), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.bar="), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.+"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("void"), isTrue);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("_foo"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("_foo.bar"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo._bar"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("if"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("if.foo"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.if"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo=.bar"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo."), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("+.foo"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("void.foo"), isFalse);
+    expect(ConstantEvaluationEngine.isValidPublicSymbol("foo.void"), isFalse);
+  }
+
+  void test_length_of_improperly_typed_string_expression() {
+    // Since type annotations are ignored in unchecked mode, the improper
+    // types on s1 and s2 shouldn't prevent us from evaluating i to
+    // 'alpha'.length.
+    CompilationUnit compilationUnit = resolveSource('''
+const int s1 = 'alpha';
+const int s2 = 'beta';
+const int i = (true ? s1 : s2).length;
+''');
+    ConstTopLevelVariableElementImpl element =
+        findTopLevelDeclaration(compilationUnit, 'i').element;
+    EvaluationResultImpl result = element.evaluationResult;
+    expect(_assertValidInt(result), 5);
+  }
+
+  void test_length_of_improperly_typed_string_identifier() {
+    // Since type annotations are ignored in unchecked mode, the improper type
+    // on s shouldn't prevent us from evaluating i to 'alpha'.length.
+    CompilationUnit compilationUnit = resolveSource('''
+const int s = 'alpha';
+const int i = s.length;
+''');
+    ConstTopLevelVariableElementImpl element =
+        findTopLevelDeclaration(compilationUnit, 'i').element;
+    EvaluationResultImpl result = element.evaluationResult;
+    expect(_assertValidInt(result), 5);
+  }
+
+  void test_non_static_const_initialized_at_declaration() {
+    // Even though non-static consts are not allowed by the language, we need
+    // to handle them for error recovery purposes.
+    CompilationUnit compilationUnit = resolveSource('''
+class A {
+  const int i = 123;
+  const A();
+}
+
+const A a = const A();
+''');
+    EvaluationResultImpl result =
+        _evaluateTopLevelVariable(compilationUnit, 'a');
+    Map<String, DartObjectImpl> fields = _assertType(result, "A");
+    expect(fields, hasLength(1));
+    _assertIntField(fields, "i", 123);
+  }
+
+  void test_symbolLiteral_void() {
+    CompilationUnit compilationUnit =
+        resolveSource("const voidSymbol = #void;");
+    VariableDeclaration voidSymbol =
+        findTopLevelDeclaration(compilationUnit, "voidSymbol");
+    EvaluationResultImpl voidSymbolResult =
+        (voidSymbol.element as VariableElementImpl).evaluationResult;
+    DartObjectImpl value = voidSymbolResult.value;
+    expect(value.type, typeProvider.symbolType);
+    expect(value.toSymbolValue(), "void");
+  }
+
+  Map<String, DartObjectImpl> _assertFieldType(
+      Map<String, DartObjectImpl> fields,
+      String fieldName,
+      String expectedType) {
+    DartObjectImpl field = fields[fieldName];
+    expect(field.type.displayName, expectedType);
+    return field.fields;
+  }
+
+  void _assertIntField(
+      Map<String, DartObjectImpl> fields, String fieldName, int expectedValue) {
+    DartObjectImpl field = fields[fieldName];
+    expect(field.type.name, "int");
+    expect(field.toIntValue(), expectedValue);
+  }
+
+  void _assertNullField(Map<String, DartObjectImpl> fields, String fieldName) {
+    DartObjectImpl field = fields[fieldName];
+    expect(field.isNull, isTrue);
+  }
+
+  void _assertProperDependencies(String sourceText,
+      [List<ErrorCode> expectedErrorCodes = ErrorCode.EMPTY_LIST]) {
+    Source source = addSource(sourceText);
+    LibraryElement element = resolve2(source);
+    CompilationUnit unit =
+        analysisContext.resolveCompilationUnit(source, element);
+    expect(unit, isNotNull);
+    ConstantValueComputer computer = _makeConstantValueComputer();
+    computer.add(unit, source, source);
+    computer.computeValues();
+    assertErrors(source, expectedErrorCodes);
+  }
+
+  Map<String, DartObjectImpl> _assertType(
+      EvaluationResultImpl result, String typeName) {
+    expect(result.value, isNotNull);
+    DartObjectImpl value = result.value;
+    expect(value.type.displayName, typeName);
+    return value.fields;
+  }
+
+  bool _assertValidBool(EvaluationResultImpl result) {
+    expect(result.value, isNotNull);
+    DartObjectImpl value = result.value;
+    expect(value.type, typeProvider.boolType);
+    bool boolValue = value.toBoolValue();
+    expect(boolValue, isNotNull);
+    return boolValue;
+  }
+
+  int _assertValidInt(EvaluationResultImpl result) {
+    expect(result, isNotNull);
+    expect(result.value, isNotNull);
+    DartObjectImpl value = result.value;
+    expect(value.type, typeProvider.intType);
+    return value.toIntValue();
+  }
+
+  void _assertValidNull(EvaluationResultImpl result) {
+    expect(result.value, isNotNull);
+    DartObjectImpl value = result.value;
+    expect(value.type, typeProvider.nullType);
+  }
+
+  String _assertValidString(EvaluationResultImpl result) {
+    expect(result.value, isNotNull);
+    DartObjectImpl value = result.value;
+    expect(value.type, typeProvider.stringType);
+    return value.toStringValue();
+  }
+
+  void _assertValidUnknown(EvaluationResultImpl result) {
+    expect(result.value, isNotNull);
+    DartObjectImpl value = result.value;
+    expect(value.isUnknown, isTrue);
+  }
+
+  EvaluationResultImpl _check_fromEnvironment_bool(
+      String valueInEnvironment, String defaultExpr) {
+    String envVarName = "x";
+    String varName = "foo";
+    if (valueInEnvironment != null) {
+      analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
+    }
+    String defaultArg =
+        defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
+    CompilationUnit compilationUnit = resolveSource(
+        "const $varName = const bool.fromEnvironment('$envVarName'$defaultArg);");
+    return _evaluateTopLevelVariable(compilationUnit, varName);
+  }
+
+  EvaluationResultImpl _check_fromEnvironment_int(
+      String valueInEnvironment, String defaultExpr) {
+    String envVarName = "x";
+    String varName = "foo";
+    if (valueInEnvironment != null) {
+      analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
+    }
+    String defaultArg =
+        defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
+    CompilationUnit compilationUnit = resolveSource(
+        "const $varName = const int.fromEnvironment('$envVarName'$defaultArg);");
+    return _evaluateTopLevelVariable(compilationUnit, varName);
+  }
+
+  EvaluationResultImpl _check_fromEnvironment_string(
+      String valueInEnvironment, String defaultExpr) {
+    String envVarName = "x";
+    String varName = "foo";
+    if (valueInEnvironment != null) {
+      analysisContext2.declaredVariables.define(envVarName, valueInEnvironment);
+    }
+    String defaultArg =
+        defaultExpr == null ? "" : ", defaultValue: $defaultExpr";
+    CompilationUnit compilationUnit = resolveSource(
+        "const $varName = const String.fromEnvironment('$envVarName'$defaultArg);");
+    return _evaluateTopLevelVariable(compilationUnit, varName);
+  }
+
+  void _checkInstanceCreation_withSupertypeParams(bool isExplicit) {
+    String superCall = isExplicit ? " : super()" : "";
+    CompilationUnit compilationUnit = resolveSource("""
+class A<T> {
+  const A();
+}
+class B<T, U> extends A<T> {
+  const B()$superCall;
+}
+class C<T, U> extends A<U> {
+  const C()$superCall;
+}
+const b_int_num = const B<int, num>();
+const c_int_num = const C<int, num>();""");
+    EvaluationResultImpl b_int_num =
+        _evaluateTopLevelVariable(compilationUnit, "b_int_num");
+    Map<String, DartObjectImpl> b_int_num_fields =
+        _assertType(b_int_num, "B<int, num>");
+    _assertFieldType(b_int_num_fields, GenericState.SUPERCLASS_FIELD, "A<int>");
+    EvaluationResultImpl c_int_num =
+        _evaluateTopLevelVariable(compilationUnit, "c_int_num");
+    Map<String, DartObjectImpl> c_int_num_fields =
+        _assertType(c_int_num, "C<int, num>");
+    _assertFieldType(c_int_num_fields, GenericState.SUPERCLASS_FIELD, "A<num>");
+  }
+
+  void _checkInstanceCreationOptionalParams(
+      bool isFieldFormal, bool isNamed, bool hasDefault) {
+    String fieldName = "j";
+    String paramName = isFieldFormal ? fieldName : "i";
+    String formalParam =
+        "${isFieldFormal ? "this." : "int "}$paramName${hasDefault ? " = 3" : ""}";
+    CompilationUnit compilationUnit = resolveSource("""
+const x = const A();
+const y = const A(${isNamed ? '$paramName: ' : ''}10);
+class A {
+  const A(${isNamed ? "{$formalParam}" : "[$formalParam]"})${isFieldFormal ? "" : " : $fieldName = $paramName"};
+  final int $fieldName;
+}""");
+    EvaluationResultImpl x = _evaluateTopLevelVariable(compilationUnit, "x");
+    Map<String, DartObjectImpl> fieldsOfX = _assertType(x, "A");
+    expect(fieldsOfX, hasLength(1));
+    if (hasDefault) {
+      _assertIntField(fieldsOfX, fieldName, 3);
+    } else {
+      _assertNullField(fieldsOfX, fieldName);
+    }
+    EvaluationResultImpl y = _evaluateTopLevelVariable(compilationUnit, "y");
+    Map<String, DartObjectImpl> fieldsOfY = _assertType(y, "A");
+    expect(fieldsOfY, hasLength(1));
+    _assertIntField(fieldsOfY, fieldName, 10);
+  }
+
+  /**
+   * Search [compilationUnit] for a class named [className], containing a
+   * method [methodName], with exactly one annotation.  Return the constant
+   * value of the annotation.
+   */
+  EvaluationResultImpl _evaluateAnnotation(
+      CompilationUnit compilationUnit, String className, String memberName) {
+    for (CompilationUnitMember member in compilationUnit.declarations) {
+      if (member is ClassDeclaration && member.name.name == className) {
+        for (ClassMember classMember in member.members) {
+          if (classMember is MethodDeclaration &&
+              classMember.name.name == memberName) {
+            expect(classMember.metadata, hasLength(1));
+            ElementAnnotationImpl elementAnnotation =
+                classMember.metadata[0].elementAnnotation;
+            return elementAnnotation.evaluationResult;
+          }
+        }
+      }
+    }
+    fail('Class member not found');
+    return null;
+  }
+
+  EvaluationResultImpl _evaluateTopLevelVariable(
+      CompilationUnit compilationUnit, String name) {
+    VariableDeclaration varDecl =
+        findTopLevelDeclaration(compilationUnit, name);
+    ConstTopLevelVariableElementImpl varElement = varDecl.element;
+    return varElement.evaluationResult;
+  }
+
+  ConstantValueComputer _makeConstantValueComputer() {
+    ConstantEvaluationValidator_ForTest validator =
+        new ConstantEvaluationValidator_ForTest(analysisContext2);
+    validator.computer = new ConstantValueComputer(
+        analysisContext2,
+        analysisContext2.typeProvider,
+        analysisContext2.declaredVariables,
+        validator,
+        analysisContext2.typeSystem);
+    return validator.computer;
+  }
+
+  void _validate(bool shouldBeValid, VariableDeclarationList declarationList) {
+    for (VariableDeclaration declaration in declarationList.variables) {
+      VariableElementImpl element = declaration.element as VariableElementImpl;
+      expect(element, isNotNull);
+      EvaluationResultImpl result = element.evaluationResult;
+      if (shouldBeValid) {
+        expect(result.value, isNotNull);
+      } else {
+        expect(result.value, isNull);
+      }
+    }
+  }
+}
+
+@reflectiveTest
+class ConstantVisitorTest extends ResolverTestCase {
+  void test_visitBinaryExpression_questionQuestion_notNull_notNull() {
+    Expression left = AstFactory.string2('a');
+    Expression right = AstFactory.string2('b');
+    Expression expression =
+        AstFactory.binaryExpression(left, TokenType.QUESTION_QUESTION, right);
+
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter =
+        new ErrorReporter(errorListener, _dummySource());
+    DartObjectImpl result = _evaluate(expression, errorReporter);
+    expect(result, isNotNull);
+    expect(result.isNull, isFalse);
+    expect(result.toStringValue(), 'a');
+    errorListener.assertNoErrors();
+  }
+
+  void test_visitBinaryExpression_questionQuestion_null_notNull() {
+    Expression left = AstFactory.nullLiteral();
+    Expression right = AstFactory.string2('b');
+    Expression expression =
+        AstFactory.binaryExpression(left, TokenType.QUESTION_QUESTION, right);
+
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter =
+        new ErrorReporter(errorListener, _dummySource());
+    DartObjectImpl result = _evaluate(expression, errorReporter);
+    expect(result, isNotNull);
+    expect(result.isNull, isFalse);
+    expect(result.toStringValue(), 'b');
+    errorListener.assertNoErrors();
+  }
+
+  void test_visitBinaryExpression_questionQuestion_null_null() {
+    Expression left = AstFactory.nullLiteral();
+    Expression right = AstFactory.nullLiteral();
+    Expression expression =
+        AstFactory.binaryExpression(left, TokenType.QUESTION_QUESTION, right);
+
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter =
+        new ErrorReporter(errorListener, _dummySource());
+    DartObjectImpl result = _evaluate(expression, errorReporter);
+    expect(result, isNotNull);
+    expect(result.isNull, isTrue);
+    errorListener.assertNoErrors();
+  }
+
+  void test_visitConditionalExpression_false() {
+    Expression thenExpression = AstFactory.integer(1);
+    Expression elseExpression = AstFactory.integer(0);
+    ConditionalExpression expression = AstFactory.conditionalExpression(
+        AstFactory.booleanLiteral(false), thenExpression, elseExpression);
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter =
+        new ErrorReporter(errorListener, _dummySource());
+    _assertValue(0, _evaluate(expression, errorReporter));
+    errorListener.assertNoErrors();
+  }
+
+  void test_visitConditionalExpression_nonBooleanCondition() {
+    Expression thenExpression = AstFactory.integer(1);
+    Expression elseExpression = AstFactory.integer(0);
+    NullLiteral conditionExpression = AstFactory.nullLiteral();
+    ConditionalExpression expression = AstFactory.conditionalExpression(
+        conditionExpression, thenExpression, elseExpression);
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter =
+        new ErrorReporter(errorListener, _dummySource());
+    DartObjectImpl result = _evaluate(expression, errorReporter);
+    expect(result, isNull);
+    errorListener
+        .assertErrorsWithCodes([CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL]);
+  }
+
+  void test_visitConditionalExpression_nonConstantElse() {
+    Expression thenExpression = AstFactory.integer(1);
+    Expression elseExpression = AstFactory.identifier3("x");
+    ConditionalExpression expression = AstFactory.conditionalExpression(
+        AstFactory.booleanLiteral(true), thenExpression, elseExpression);
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter =
+        new ErrorReporter(errorListener, _dummySource());
+    DartObjectImpl result = _evaluate(expression, errorReporter);
+    expect(result, isNull);
+    errorListener
+        .assertErrorsWithCodes([CompileTimeErrorCode.INVALID_CONSTANT]);
+  }
+
+  void test_visitConditionalExpression_nonConstantThen() {
+    Expression thenExpression = AstFactory.identifier3("x");
+    Expression elseExpression = AstFactory.integer(0);
+    ConditionalExpression expression = AstFactory.conditionalExpression(
+        AstFactory.booleanLiteral(true), thenExpression, elseExpression);
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter =
+        new ErrorReporter(errorListener, _dummySource());
+    DartObjectImpl result = _evaluate(expression, errorReporter);
+    expect(result, isNull);
+    errorListener
+        .assertErrorsWithCodes([CompileTimeErrorCode.INVALID_CONSTANT]);
+  }
+
+  void test_visitConditionalExpression_true() {
+    Expression thenExpression = AstFactory.integer(1);
+    Expression elseExpression = AstFactory.integer(0);
+    ConditionalExpression expression = AstFactory.conditionalExpression(
+        AstFactory.booleanLiteral(true), thenExpression, elseExpression);
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter =
+        new ErrorReporter(errorListener, _dummySource());
+    _assertValue(1, _evaluate(expression, errorReporter));
+    errorListener.assertNoErrors();
+  }
+
+  void test_visitSimpleIdentifier_className() {
+    CompilationUnit compilationUnit = resolveSource('''
+const a = C;
+class C {}
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
+    expect(result.type, typeProvider.typeType);
+    expect(result.toTypeValue().name, 'C');
+  }
+
+  void test_visitSimpleIdentifier_dynamic() {
+    CompilationUnit compilationUnit = resolveSource('''
+const a = dynamic;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'a', null);
+    expect(result.type, typeProvider.typeType);
+    expect(result.toTypeValue(), typeProvider.dynamicType);
+  }
+
+  void test_visitSimpleIdentifier_inEnvironment() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const a = b;
+const b = 3;''');
+    Map<String, DartObjectImpl> environment = new Map<String, DartObjectImpl>();
+    DartObjectImpl six =
+        new DartObjectImpl(typeProvider.intType, new IntState(6));
+    environment["b"] = six;
+    _assertValue(6, _evaluateConstant(compilationUnit, "a", environment));
+  }
+
+  void test_visitSimpleIdentifier_notInEnvironment() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const a = b;
+const b = 3;''');
+    Map<String, DartObjectImpl> environment = new Map<String, DartObjectImpl>();
+    DartObjectImpl six =
+        new DartObjectImpl(typeProvider.intType, new IntState(6));
+    environment["c"] = six;
+    _assertValue(3, _evaluateConstant(compilationUnit, "a", environment));
+  }
+
+  void test_visitSimpleIdentifier_withoutEnvironment() {
+    CompilationUnit compilationUnit = resolveSource(r'''
+const a = b;
+const b = 3;''');
+    _assertValue(3, _evaluateConstant(compilationUnit, "a", null));
+  }
+
+  void _assertValue(int expectedValue, DartObjectImpl result) {
+    expect(result, isNotNull);
+    expect(result.type.name, "int");
+    expect(result.toIntValue(), expectedValue);
+  }
+
+  NonExistingSource _dummySource() {
+    String path = '/test.dart';
+    return new NonExistingSource(path, toUri(path), UriKind.FILE_URI);
+  }
+
+  DartObjectImpl _evaluate(Expression expression, ErrorReporter errorReporter) {
+    return expression.accept(new ConstantVisitor(
+        new ConstantEvaluationEngine(
+            new TestTypeProvider(), new DeclaredVariables(),
+            typeSystem: new TypeSystemImpl()),
+        errorReporter));
+  }
+
+  DartObjectImpl _evaluateConstant(CompilationUnit compilationUnit, String name,
+      Map<String, DartObjectImpl> lexicalEnvironment) {
+    Source source = compilationUnit.element.source;
+    Expression expression =
+        findTopLevelConstantExpression(compilationUnit, name);
+    GatheringErrorListener errorListener = new GatheringErrorListener();
+    ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
+    DartObjectImpl result = expression.accept(new ConstantVisitor(
+        new ConstantEvaluationEngine(typeProvider, new DeclaredVariables(),
+            typeSystem: typeSystem),
+        errorReporter,
+        lexicalEnvironment: lexicalEnvironment));
+    errorListener.assertNoErrors();
+    return result;
+  }
+}
+
+@reflectiveTest
+class DartObjectImplTest extends EngineTestCase {
+  TypeProvider _typeProvider = new TestTypeProvider();
+
+  void test_add_knownDouble_knownDouble() {
+    _assertAdd(_doubleValue(3.0), _doubleValue(1.0), _doubleValue(2.0));
+  }
+
+  void test_add_knownDouble_knownInt() {
+    _assertAdd(_doubleValue(3.0), _doubleValue(1.0), _intValue(2));
+  }
+
+  void test_add_knownDouble_unknownDouble() {
+    _assertAdd(_doubleValue(null), _doubleValue(1.0), _doubleValue(null));
+  }
+
+  void test_add_knownDouble_unknownInt() {
+    _assertAdd(_doubleValue(null), _doubleValue(1.0), _intValue(null));
+  }
+
+  void test_add_knownInt_knownInt() {
+    _assertAdd(_intValue(3), _intValue(1), _intValue(2));
+  }
+
+  void test_add_knownInt_knownString() {
+    _assertAdd(null, _intValue(1), _stringValue("2"));
+  }
+
+  void test_add_knownInt_unknownDouble() {
+    _assertAdd(_doubleValue(null), _intValue(1), _doubleValue(null));
+  }
+
+  void test_add_knownInt_unknownInt() {
+    _assertAdd(_intValue(null), _intValue(1), _intValue(null));
+  }
+
+  void test_add_knownString_knownInt() {
+    _assertAdd(null, _stringValue("1"), _intValue(2));
+  }
+
+  void test_add_knownString_knownString() {
+    _assertAdd(_stringValue("ab"), _stringValue("a"), _stringValue("b"));
+  }
+
+  void test_add_knownString_unknownString() {
+    _assertAdd(_stringValue(null), _stringValue("a"), _stringValue(null));
+  }
+
+  void test_add_unknownDouble_knownDouble() {
+    _assertAdd(_doubleValue(null), _doubleValue(null), _doubleValue(2.0));
+  }
+
+  void test_add_unknownDouble_knownInt() {
+    _assertAdd(_doubleValue(null), _doubleValue(null), _intValue(2));
+  }
+
+  void test_add_unknownInt_knownDouble() {
+    _assertAdd(_doubleValue(null), _intValue(null), _doubleValue(2.0));
+  }
+
+  void test_add_unknownInt_knownInt() {
+    _assertAdd(_intValue(null), _intValue(null), _intValue(2));
+  }
+
+  void test_add_unknownString_knownString() {
+    _assertAdd(_stringValue(null), _stringValue(null), _stringValue("b"));
+  }
+
+  void test_add_unknownString_unknownString() {
+    _assertAdd(_stringValue(null), _stringValue(null), _stringValue(null));
+  }
+
+  void test_bitAnd_knownInt_knownInt() {
+    _assertBitAnd(_intValue(2), _intValue(6), _intValue(3));
+  }
+
+  void test_bitAnd_knownInt_knownString() {
+    _assertBitAnd(null, _intValue(6), _stringValue("3"));
+  }
+
+  void test_bitAnd_knownInt_unknownInt() {
+    _assertBitAnd(_intValue(null), _intValue(6), _intValue(null));
+  }
+
+  void test_bitAnd_knownString_knownInt() {
+    _assertBitAnd(null, _stringValue("6"), _intValue(3));
+  }
+
+  void test_bitAnd_unknownInt_knownInt() {
+    _assertBitAnd(_intValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_bitAnd_unknownInt_unknownInt() {
+    _assertBitAnd(_intValue(null), _intValue(null), _intValue(null));
+  }
+
+  void test_bitNot_knownInt() {
+    _assertBitNot(_intValue(-4), _intValue(3));
+  }
+
+  void test_bitNot_knownString() {
+    _assertBitNot(null, _stringValue("6"));
+  }
+
+  void test_bitNot_unknownInt() {
+    _assertBitNot(_intValue(null), _intValue(null));
+  }
+
+  void test_bitOr_knownInt_knownInt() {
+    _assertBitOr(_intValue(7), _intValue(6), _intValue(3));
+  }
+
+  void test_bitOr_knownInt_knownString() {
+    _assertBitOr(null, _intValue(6), _stringValue("3"));
+  }
+
+  void test_bitOr_knownInt_unknownInt() {
+    _assertBitOr(_intValue(null), _intValue(6), _intValue(null));
+  }
+
+  void test_bitOr_knownString_knownInt() {
+    _assertBitOr(null, _stringValue("6"), _intValue(3));
+  }
+
+  void test_bitOr_unknownInt_knownInt() {
+    _assertBitOr(_intValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_bitOr_unknownInt_unknownInt() {
+    _assertBitOr(_intValue(null), _intValue(null), _intValue(null));
+  }
+
+  void test_bitXor_knownInt_knownInt() {
+    _assertBitXor(_intValue(5), _intValue(6), _intValue(3));
+  }
+
+  void test_bitXor_knownInt_knownString() {
+    _assertBitXor(null, _intValue(6), _stringValue("3"));
+  }
+
+  void test_bitXor_knownInt_unknownInt() {
+    _assertBitXor(_intValue(null), _intValue(6), _intValue(null));
+  }
+
+  void test_bitXor_knownString_knownInt() {
+    _assertBitXor(null, _stringValue("6"), _intValue(3));
+  }
+
+  void test_bitXor_unknownInt_knownInt() {
+    _assertBitXor(_intValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_bitXor_unknownInt_unknownInt() {
+    _assertBitXor(_intValue(null), _intValue(null), _intValue(null));
+  }
+
+  void test_concatenate_knownInt_knownString() {
+    _assertConcatenate(null, _intValue(2), _stringValue("def"));
+  }
+
+  void test_concatenate_knownString_knownInt() {
+    _assertConcatenate(null, _stringValue("abc"), _intValue(3));
+  }
+
+  void test_concatenate_knownString_knownString() {
+    _assertConcatenate(
+        _stringValue("abcdef"), _stringValue("abc"), _stringValue("def"));
+  }
+
+  void test_concatenate_knownString_unknownString() {
+    _assertConcatenate(
+        _stringValue(null), _stringValue("abc"), _stringValue(null));
+  }
+
+  void test_concatenate_unknownString_knownString() {
+    _assertConcatenate(
+        _stringValue(null), _stringValue(null), _stringValue("def"));
+  }
+
+  void test_divide_knownDouble_knownDouble() {
+    _assertDivide(_doubleValue(3.0), _doubleValue(6.0), _doubleValue(2.0));
+  }
+
+  void test_divide_knownDouble_knownInt() {
+    _assertDivide(_doubleValue(3.0), _doubleValue(6.0), _intValue(2));
+  }
+
+  void test_divide_knownDouble_unknownDouble() {
+    _assertDivide(_doubleValue(null), _doubleValue(6.0), _doubleValue(null));
+  }
+
+  void test_divide_knownDouble_unknownInt() {
+    _assertDivide(_doubleValue(null), _doubleValue(6.0), _intValue(null));
+  }
+
+  void test_divide_knownInt_knownInt() {
+    _assertDivide(_doubleValue(3.0), _intValue(6), _intValue(2));
+  }
+
+  void test_divide_knownInt_knownString() {
+    _assertDivide(null, _intValue(6), _stringValue("2"));
+  }
+
+  void test_divide_knownInt_unknownDouble() {
+    _assertDivide(_doubleValue(null), _intValue(6), _doubleValue(null));
+  }
+
+  void test_divide_knownInt_unknownInt() {
+    _assertDivide(_doubleValue(null), _intValue(6), _intValue(null));
+  }
+
+  void test_divide_knownString_knownInt() {
+    _assertDivide(null, _stringValue("6"), _intValue(2));
+  }
+
+  void test_divide_unknownDouble_knownDouble() {
+    _assertDivide(_doubleValue(null), _doubleValue(null), _doubleValue(2.0));
+  }
+
+  void test_divide_unknownDouble_knownInt() {
+    _assertDivide(_doubleValue(null), _doubleValue(null), _intValue(2));
+  }
+
+  void test_divide_unknownInt_knownDouble() {
+    _assertDivide(_doubleValue(null), _intValue(null), _doubleValue(2.0));
+  }
+
+  void test_divide_unknownInt_knownInt() {
+    _assertDivide(_doubleValue(null), _intValue(null), _intValue(2));
+  }
+
+  void test_equalEqual_bool_false() {
+    _assertEqualEqual(_boolValue(false), _boolValue(false), _boolValue(true));
+  }
+
+  void test_equalEqual_bool_true() {
+    _assertEqualEqual(_boolValue(true), _boolValue(true), _boolValue(true));
+  }
+
+  void test_equalEqual_bool_unknown() {
+    _assertEqualEqual(_boolValue(null), _boolValue(null), _boolValue(false));
+  }
+
+  void test_equalEqual_double_false() {
+    _assertEqualEqual(_boolValue(false), _doubleValue(2.0), _doubleValue(4.0));
+  }
+
+  void test_equalEqual_double_true() {
+    _assertEqualEqual(_boolValue(true), _doubleValue(2.0), _doubleValue(2.0));
+  }
+
+  void test_equalEqual_double_unknown() {
+    _assertEqualEqual(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
+  }
+
+  void test_equalEqual_int_false() {
+    _assertEqualEqual(_boolValue(false), _intValue(-5), _intValue(5));
+  }
+
+  void test_equalEqual_int_true() {
+    _assertEqualEqual(_boolValue(true), _intValue(5), _intValue(5));
+  }
+
+  void test_equalEqual_int_unknown() {
+    _assertEqualEqual(_boolValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_equalEqual_list_empty() {
+    _assertEqualEqual(null, _listValue(), _listValue());
+  }
+
+  void test_equalEqual_list_false() {
+    _assertEqualEqual(null, _listValue(), _listValue());
+  }
+
+  void test_equalEqual_map_empty() {
+    _assertEqualEqual(null, _mapValue(), _mapValue());
+  }
+
+  void test_equalEqual_map_false() {
+    _assertEqualEqual(null, _mapValue(), _mapValue());
+  }
+
+  void test_equalEqual_null() {
+    _assertEqualEqual(_boolValue(true), _nullValue(), _nullValue());
+  }
+
+  void test_equalEqual_string_false() {
+    _assertEqualEqual(
+        _boolValue(false), _stringValue("abc"), _stringValue("def"));
+  }
+
+  void test_equalEqual_string_true() {
+    _assertEqualEqual(
+        _boolValue(true), _stringValue("abc"), _stringValue("abc"));
+  }
+
+  void test_equalEqual_string_unknown() {
+    _assertEqualEqual(
+        _boolValue(null), _stringValue(null), _stringValue("def"));
+  }
+
+  void test_equals_list_false_differentSizes() {
+    expect(
+        _listValue([_boolValue(true)]) ==
+            _listValue([_boolValue(true), _boolValue(false)]),
+        isFalse);
+  }
+
+  void test_equals_list_false_sameSize() {
+    expect(_listValue([_boolValue(true)]) == _listValue([_boolValue(false)]),
+        isFalse);
+  }
+
+  void test_equals_list_true_empty() {
+    expect(_listValue(), _listValue());
+  }
+
+  void test_equals_list_true_nonEmpty() {
+    expect(_listValue([_boolValue(true)]), _listValue([_boolValue(true)]));
+  }
+
+  void test_equals_map_true_empty() {
+    expect(_mapValue(), _mapValue());
+  }
+
+  void test_equals_symbol_false() {
+    expect(_symbolValue("a") == _symbolValue("b"), isFalse);
+  }
+
+  void test_equals_symbol_true() {
+    expect(_symbolValue("a"), _symbolValue("a"));
+  }
+
+  void test_getValue_bool_false() {
+    expect(_boolValue(false).toBoolValue(), false);
+  }
+
+  void test_getValue_bool_true() {
+    expect(_boolValue(true).toBoolValue(), true);
+  }
+
+  void test_getValue_bool_unknown() {
+    expect(_boolValue(null).toBoolValue(), isNull);
+  }
+
+  void test_getValue_double_known() {
+    double value = 2.3;
+    expect(_doubleValue(value).toDoubleValue(), value);
+  }
+
+  void test_getValue_double_unknown() {
+    expect(_doubleValue(null).toDoubleValue(), isNull);
+  }
+
+  void test_getValue_int_known() {
+    int value = 23;
+    expect(_intValue(value).toIntValue(), value);
+  }
+
+  void test_getValue_int_unknown() {
+    expect(_intValue(null).toIntValue(), isNull);
+  }
+
+  void test_getValue_list_empty() {
+    Object result = _listValue().toListValue();
+    _assertInstanceOfObjectArray(result);
+    List<Object> array = result as List<Object>;
+    expect(array, hasLength(0));
+  }
+
+  void test_getValue_list_valid() {
+    Object result = _listValue([_intValue(23)]).toListValue();
+    _assertInstanceOfObjectArray(result);
+    List<Object> array = result as List<Object>;
+    expect(array, hasLength(1));
+  }
+
+  void test_getValue_map_empty() {
+    Object result = _mapValue().toMapValue();
+    EngineTestCase.assertInstanceOf((obj) => obj is Map, Map, result);
+    Map map = result as Map;
+    expect(map, hasLength(0));
+  }
+
+  void test_getValue_map_valid() {
+    Object result =
+        _mapValue([_stringValue("key"), _stringValue("value")]).toMapValue();
+    EngineTestCase.assertInstanceOf((obj) => obj is Map, Map, result);
+    Map map = result as Map;
+    expect(map, hasLength(1));
+  }
+
+  void test_getValue_null() {
+    expect(_nullValue().isNull, isTrue);
+  }
+
+  void test_getValue_string_known() {
+    String value = "twenty-three";
+    expect(_stringValue(value).toStringValue(), value);
+  }
+
+  void test_getValue_string_unknown() {
+    expect(_stringValue(null).toStringValue(), isNull);
+  }
+
+  void test_greaterThan_knownDouble_knownDouble_false() {
+    _assertGreaterThan(_boolValue(false), _doubleValue(1.0), _doubleValue(2.0));
+  }
+
+  void test_greaterThan_knownDouble_knownDouble_true() {
+    _assertGreaterThan(_boolValue(true), _doubleValue(2.0), _doubleValue(1.0));
+  }
+
+  void test_greaterThan_knownDouble_knownInt_false() {
+    _assertGreaterThan(_boolValue(false), _doubleValue(1.0), _intValue(2));
+  }
+
+  void test_greaterThan_knownDouble_knownInt_true() {
+    _assertGreaterThan(_boolValue(true), _doubleValue(2.0), _intValue(1));
+  }
+
+  void test_greaterThan_knownDouble_unknownDouble() {
+    _assertGreaterThan(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
+  }
+
+  void test_greaterThan_knownDouble_unknownInt() {
+    _assertGreaterThan(_boolValue(null), _doubleValue(1.0), _intValue(null));
+  }
+
+  void test_greaterThan_knownInt_knownInt_false() {
+    _assertGreaterThan(_boolValue(false), _intValue(1), _intValue(2));
+  }
+
+  void test_greaterThan_knownInt_knownInt_true() {
+    _assertGreaterThan(_boolValue(true), _intValue(2), _intValue(1));
+  }
+
+  void test_greaterThan_knownInt_knownString() {
+    _assertGreaterThan(null, _intValue(1), _stringValue("2"));
+  }
+
+  void test_greaterThan_knownInt_unknownDouble() {
+    _assertGreaterThan(_boolValue(null), _intValue(1), _doubleValue(null));
+  }
+
+  void test_greaterThan_knownInt_unknownInt() {
+    _assertGreaterThan(_boolValue(null), _intValue(1), _intValue(null));
+  }
+
+  void test_greaterThan_knownString_knownInt() {
+    _assertGreaterThan(null, _stringValue("1"), _intValue(2));
+  }
+
+  void test_greaterThan_unknownDouble_knownDouble() {
+    _assertGreaterThan(_boolValue(null), _doubleValue(null), _doubleValue(2.0));
+  }
+
+  void test_greaterThan_unknownDouble_knownInt() {
+    _assertGreaterThan(_boolValue(null), _doubleValue(null), _intValue(2));
+  }
+
+  void test_greaterThan_unknownInt_knownDouble() {
+    _assertGreaterThan(_boolValue(null), _intValue(null), _doubleValue(2.0));
+  }
+
+  void test_greaterThan_unknownInt_knownInt() {
+    _assertGreaterThan(_boolValue(null), _intValue(null), _intValue(2));
+  }
+
+  void test_greaterThanOrEqual_knownDouble_knownDouble_false() {
+    _assertGreaterThanOrEqual(
+        _boolValue(false), _doubleValue(1.0), _doubleValue(2.0));
+  }
+
+  void test_greaterThanOrEqual_knownDouble_knownDouble_true() {
+    _assertGreaterThanOrEqual(
+        _boolValue(true), _doubleValue(2.0), _doubleValue(1.0));
+  }
+
+  void test_greaterThanOrEqual_knownDouble_knownInt_false() {
+    _assertGreaterThanOrEqual(
+        _boolValue(false), _doubleValue(1.0), _intValue(2));
+  }
+
+  void test_greaterThanOrEqual_knownDouble_knownInt_true() {
+    _assertGreaterThanOrEqual(
+        _boolValue(true), _doubleValue(2.0), _intValue(1));
+  }
+
+  void test_greaterThanOrEqual_knownDouble_unknownDouble() {
+    _assertGreaterThanOrEqual(
+        _boolValue(null), _doubleValue(1.0), _doubleValue(null));
+  }
+
+  void test_greaterThanOrEqual_knownDouble_unknownInt() {
+    _assertGreaterThanOrEqual(
+        _boolValue(null), _doubleValue(1.0), _intValue(null));
+  }
+
+  void test_greaterThanOrEqual_knownInt_knownInt_false() {
+    _assertGreaterThanOrEqual(_boolValue(false), _intValue(1), _intValue(2));
+  }
+
+  void test_greaterThanOrEqual_knownInt_knownInt_true() {
+    _assertGreaterThanOrEqual(_boolValue(true), _intValue(2), _intValue(2));
+  }
+
+  void test_greaterThanOrEqual_knownInt_knownString() {
+    _assertGreaterThanOrEqual(null, _intValue(1), _stringValue("2"));
+  }
+
+  void test_greaterThanOrEqual_knownInt_unknownDouble() {
+    _assertGreaterThanOrEqual(
+        _boolValue(null), _intValue(1), _doubleValue(null));
+  }
+
+  void test_greaterThanOrEqual_knownInt_unknownInt() {
+    _assertGreaterThanOrEqual(_boolValue(null), _intValue(1), _intValue(null));
+  }
+
+  void test_greaterThanOrEqual_knownString_knownInt() {
+    _assertGreaterThanOrEqual(null, _stringValue("1"), _intValue(2));
+  }
+
+  void test_greaterThanOrEqual_unknownDouble_knownDouble() {
+    _assertGreaterThanOrEqual(
+        _boolValue(null), _doubleValue(null), _doubleValue(2.0));
+  }
+
+  void test_greaterThanOrEqual_unknownDouble_knownInt() {
+    _assertGreaterThanOrEqual(
+        _boolValue(null), _doubleValue(null), _intValue(2));
+  }
+
+  void test_greaterThanOrEqual_unknownInt_knownDouble() {
+    _assertGreaterThanOrEqual(
+        _boolValue(null), _intValue(null), _doubleValue(2.0));
+  }
+
+  void test_greaterThanOrEqual_unknownInt_knownInt() {
+    _assertGreaterThanOrEqual(_boolValue(null), _intValue(null), _intValue(2));
+  }
+
+  void test_hasKnownValue_bool_false() {
+    expect(_boolValue(false).hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_bool_true() {
+    expect(_boolValue(true).hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_bool_unknown() {
+    expect(_boolValue(null).hasKnownValue, isFalse);
+  }
+
+  void test_hasKnownValue_double_known() {
+    expect(_doubleValue(2.3).hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_double_unknown() {
+    expect(_doubleValue(null).hasKnownValue, isFalse);
+  }
+
+  void test_hasKnownValue_dynamic() {
+    expect(_dynamicValue().hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_int_known() {
+    expect(_intValue(23).hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_int_unknown() {
+    expect(_intValue(null).hasKnownValue, isFalse);
+  }
+
+  void test_hasKnownValue_list_empty() {
+    expect(_listValue().hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_list_invalidElement() {
+    expect(_listValue([_dynamicValue]).hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_list_valid() {
+    expect(_listValue([_intValue(23)]).hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_map_empty() {
+    expect(_mapValue().hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_map_invalidKey() {
+    expect(_mapValue([_dynamicValue(), _stringValue("value")]).hasKnownValue,
+        isTrue);
+  }
+
+  void test_hasKnownValue_map_invalidValue() {
+    expect(_mapValue([_stringValue("key"), _dynamicValue()]).hasKnownValue,
+        isTrue);
+  }
+
+  void test_hasKnownValue_map_valid() {
+    expect(
+        _mapValue([_stringValue("key"), _stringValue("value")]).hasKnownValue,
+        isTrue);
+  }
+
+  void test_hasKnownValue_null() {
+    expect(_nullValue().hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_num() {
+    expect(_numValue().hasKnownValue, isFalse);
+  }
+
+  void test_hasKnownValue_string_known() {
+    expect(_stringValue("twenty-three").hasKnownValue, isTrue);
+  }
+
+  void test_hasKnownValue_string_unknown() {
+    expect(_stringValue(null).hasKnownValue, isFalse);
+  }
+
+  void test_identical_bool_false() {
+    _assertIdentical(_boolValue(false), _boolValue(false), _boolValue(true));
+  }
+
+  void test_identical_bool_true() {
+    _assertIdentical(_boolValue(true), _boolValue(true), _boolValue(true));
+  }
+
+  void test_identical_bool_unknown() {
+    _assertIdentical(_boolValue(null), _boolValue(null), _boolValue(false));
+  }
+
+  void test_identical_double_false() {
+    _assertIdentical(_boolValue(false), _doubleValue(2.0), _doubleValue(4.0));
+  }
+
+  void test_identical_double_true() {
+    _assertIdentical(_boolValue(true), _doubleValue(2.0), _doubleValue(2.0));
+  }
+
+  void test_identical_double_unknown() {
+    _assertIdentical(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
+  }
+
+  void test_identical_int_false() {
+    _assertIdentical(_boolValue(false), _intValue(-5), _intValue(5));
+  }
+
+  void test_identical_int_true() {
+    _assertIdentical(_boolValue(true), _intValue(5), _intValue(5));
+  }
+
+  void test_identical_int_unknown() {
+    _assertIdentical(_boolValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_identical_list_empty() {
+    _assertIdentical(_boolValue(true), _listValue(), _listValue());
+  }
+
+  void test_identical_list_false() {
+    _assertIdentical(
+        _boolValue(false), _listValue(), _listValue([_intValue(3)]));
+  }
+
+  void test_identical_map_empty() {
+    _assertIdentical(_boolValue(true), _mapValue(), _mapValue());
+  }
+
+  void test_identical_map_false() {
+    _assertIdentical(_boolValue(false), _mapValue(),
+        _mapValue([_intValue(1), _intValue(2)]));
+  }
+
+  void test_identical_null() {
+    _assertIdentical(_boolValue(true), _nullValue(), _nullValue());
+  }
+
+  void test_identical_string_false() {
+    _assertIdentical(
+        _boolValue(false), _stringValue("abc"), _stringValue("def"));
+  }
+
+  void test_identical_string_true() {
+    _assertIdentical(
+        _boolValue(true), _stringValue("abc"), _stringValue("abc"));
+  }
+
+  void test_identical_string_unknown() {
+    _assertIdentical(_boolValue(null), _stringValue(null), _stringValue("def"));
+  }
+
+  void test_integerDivide_knownDouble_knownDouble() {
+    _assertIntegerDivide(_intValue(3), _doubleValue(6.0), _doubleValue(2.0));
+  }
+
+  void test_integerDivide_knownDouble_knownInt() {
+    _assertIntegerDivide(_intValue(3), _doubleValue(6.0), _intValue(2));
+  }
+
+  void test_integerDivide_knownDouble_unknownDouble() {
+    _assertIntegerDivide(
+        _intValue(null), _doubleValue(6.0), _doubleValue(null));
+  }
+
+  void test_integerDivide_knownDouble_unknownInt() {
+    _assertIntegerDivide(_intValue(null), _doubleValue(6.0), _intValue(null));
+  }
+
+  void test_integerDivide_knownInt_knownInt() {
+    _assertIntegerDivide(_intValue(3), _intValue(6), _intValue(2));
+  }
+
+  void test_integerDivide_knownInt_knownString() {
+    _assertIntegerDivide(null, _intValue(6), _stringValue("2"));
+  }
+
+  void test_integerDivide_knownInt_unknownDouble() {
+    _assertIntegerDivide(_intValue(null), _intValue(6), _doubleValue(null));
+  }
+
+  void test_integerDivide_knownInt_unknownInt() {
+    _assertIntegerDivide(_intValue(null), _intValue(6), _intValue(null));
+  }
+
+  void test_integerDivide_knownString_knownInt() {
+    _assertIntegerDivide(null, _stringValue("6"), _intValue(2));
+  }
+
+  void test_integerDivide_unknownDouble_knownDouble() {
+    _assertIntegerDivide(
+        _intValue(null), _doubleValue(null), _doubleValue(2.0));
+  }
+
+  void test_integerDivide_unknownDouble_knownInt() {
+    _assertIntegerDivide(_intValue(null), _doubleValue(null), _intValue(2));
+  }
+
+  void test_integerDivide_unknownInt_knownDouble() {
+    _assertIntegerDivide(_intValue(null), _intValue(null), _doubleValue(2.0));
+  }
+
+  void test_integerDivide_unknownInt_knownInt() {
+    _assertIntegerDivide(_intValue(null), _intValue(null), _intValue(2));
+  }
+
+  void test_isBoolNumStringOrNull_bool_false() {
+    expect(_boolValue(false).isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_bool_true() {
+    expect(_boolValue(true).isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_bool_unknown() {
+    expect(_boolValue(null).isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_double_known() {
+    expect(_doubleValue(2.3).isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_double_unknown() {
+    expect(_doubleValue(null).isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_dynamic() {
+    expect(_dynamicValue().isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_int_known() {
+    expect(_intValue(23).isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_int_unknown() {
+    expect(_intValue(null).isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_list() {
+    expect(_listValue().isBoolNumStringOrNull, isFalse);
+  }
+
+  void test_isBoolNumStringOrNull_null() {
+    expect(_nullValue().isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_num() {
+    expect(_numValue().isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_string_known() {
+    expect(_stringValue("twenty-three").isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_isBoolNumStringOrNull_string_unknown() {
+    expect(_stringValue(null).isBoolNumStringOrNull, isTrue);
+  }
+
+  void test_lessThan_knownDouble_knownDouble_false() {
+    _assertLessThan(_boolValue(false), _doubleValue(2.0), _doubleValue(1.0));
+  }
+
+  void test_lessThan_knownDouble_knownDouble_true() {
+    _assertLessThan(_boolValue(true), _doubleValue(1.0), _doubleValue(2.0));
+  }
+
+  void test_lessThan_knownDouble_knownInt_false() {
+    _assertLessThan(_boolValue(false), _doubleValue(2.0), _intValue(1));
+  }
+
+  void test_lessThan_knownDouble_knownInt_true() {
+    _assertLessThan(_boolValue(true), _doubleValue(1.0), _intValue(2));
+  }
+
+  void test_lessThan_knownDouble_unknownDouble() {
+    _assertLessThan(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
+  }
+
+  void test_lessThan_knownDouble_unknownInt() {
+    _assertLessThan(_boolValue(null), _doubleValue(1.0), _intValue(null));
+  }
+
+  void test_lessThan_knownInt_knownInt_false() {
+    _assertLessThan(_boolValue(false), _intValue(2), _intValue(1));
+  }
+
+  void test_lessThan_knownInt_knownInt_true() {
+    _assertLessThan(_boolValue(true), _intValue(1), _intValue(2));
+  }
+
+  void test_lessThan_knownInt_knownString() {
+    _assertLessThan(null, _intValue(1), _stringValue("2"));
+  }
+
+  void test_lessThan_knownInt_unknownDouble() {
+    _assertLessThan(_boolValue(null), _intValue(1), _doubleValue(null));
+  }
+
+  void test_lessThan_knownInt_unknownInt() {
+    _assertLessThan(_boolValue(null), _intValue(1), _intValue(null));
+  }
+
+  void test_lessThan_knownString_knownInt() {
+    _assertLessThan(null, _stringValue("1"), _intValue(2));
+  }
+
+  void test_lessThan_unknownDouble_knownDouble() {
+    _assertLessThan(_boolValue(null), _doubleValue(null), _doubleValue(2.0));
+  }
+
+  void test_lessThan_unknownDouble_knownInt() {
+    _assertLessThan(_boolValue(null), _doubleValue(null), _intValue(2));
+  }
+
+  void test_lessThan_unknownInt_knownDouble() {
+    _assertLessThan(_boolValue(null), _intValue(null), _doubleValue(2.0));
+  }
+
+  void test_lessThan_unknownInt_knownInt() {
+    _assertLessThan(_boolValue(null), _intValue(null), _intValue(2));
+  }
+
+  void test_lessThanOrEqual_knownDouble_knownDouble_false() {
+    _assertLessThanOrEqual(
+        _boolValue(false), _doubleValue(2.0), _doubleValue(1.0));
+  }
+
+  void test_lessThanOrEqual_knownDouble_knownDouble_true() {
+    _assertLessThanOrEqual(
+        _boolValue(true), _doubleValue(1.0), _doubleValue(2.0));
+  }
+
+  void test_lessThanOrEqual_knownDouble_knownInt_false() {
+    _assertLessThanOrEqual(_boolValue(false), _doubleValue(2.0), _intValue(1));
+  }
+
+  void test_lessThanOrEqual_knownDouble_knownInt_true() {
+    _assertLessThanOrEqual(_boolValue(true), _doubleValue(1.0), _intValue(2));
+  }
+
+  void test_lessThanOrEqual_knownDouble_unknownDouble() {
+    _assertLessThanOrEqual(
+        _boolValue(null), _doubleValue(1.0), _doubleValue(null));
+  }
+
+  void test_lessThanOrEqual_knownDouble_unknownInt() {
+    _assertLessThanOrEqual(
+        _boolValue(null), _doubleValue(1.0), _intValue(null));
+  }
+
+  void test_lessThanOrEqual_knownInt_knownInt_false() {
+    _assertLessThanOrEqual(_boolValue(false), _intValue(2), _intValue(1));
+  }
+
+  void test_lessThanOrEqual_knownInt_knownInt_true() {
+    _assertLessThanOrEqual(_boolValue(true), _intValue(1), _intValue(2));
+  }
+
+  void test_lessThanOrEqual_knownInt_knownString() {
+    _assertLessThanOrEqual(null, _intValue(1), _stringValue("2"));
+  }
+
+  void test_lessThanOrEqual_knownInt_unknownDouble() {
+    _assertLessThanOrEqual(_boolValue(null), _intValue(1), _doubleValue(null));
+  }
+
+  void test_lessThanOrEqual_knownInt_unknownInt() {
+    _assertLessThanOrEqual(_boolValue(null), _intValue(1), _intValue(null));
+  }
+
+  void test_lessThanOrEqual_knownString_knownInt() {
+    _assertLessThanOrEqual(null, _stringValue("1"), _intValue(2));
+  }
+
+  void test_lessThanOrEqual_unknownDouble_knownDouble() {
+    _assertLessThanOrEqual(
+        _boolValue(null), _doubleValue(null), _doubleValue(2.0));
+  }
+
+  void test_lessThanOrEqual_unknownDouble_knownInt() {
+    _assertLessThanOrEqual(_boolValue(null), _doubleValue(null), _intValue(2));
+  }
+
+  void test_lessThanOrEqual_unknownInt_knownDouble() {
+    _assertLessThanOrEqual(
+        _boolValue(null), _intValue(null), _doubleValue(2.0));
+  }
+
+  void test_lessThanOrEqual_unknownInt_knownInt() {
+    _assertLessThanOrEqual(_boolValue(null), _intValue(null), _intValue(2));
+  }
+
+  void test_logicalAnd_false_false() {
+    _assertLogicalAnd(_boolValue(false), _boolValue(false), _boolValue(false));
+  }
+
+  void test_logicalAnd_false_null() {
+    try {
+      _assertLogicalAnd(_boolValue(false), _boolValue(false), _nullValue());
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalAnd_false_string() {
+    try {
+      _assertLogicalAnd(
+          _boolValue(false), _boolValue(false), _stringValue("false"));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalAnd_false_true() {
+    _assertLogicalAnd(_boolValue(false), _boolValue(false), _boolValue(true));
+  }
+
+  void test_logicalAnd_null_false() {
+    try {
+      _assertLogicalAnd(_boolValue(false), _nullValue(), _boolValue(false));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalAnd_null_true() {
+    try {
+      _assertLogicalAnd(_boolValue(false), _nullValue(), _boolValue(true));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalAnd_string_false() {
+    try {
+      _assertLogicalAnd(
+          _boolValue(false), _stringValue("true"), _boolValue(false));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalAnd_string_true() {
+    try {
+      _assertLogicalAnd(
+          _boolValue(false), _stringValue("false"), _boolValue(true));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalAnd_true_false() {
+    _assertLogicalAnd(_boolValue(false), _boolValue(true), _boolValue(false));
+  }
+
+  void test_logicalAnd_true_null() {
+    _assertLogicalAnd(null, _boolValue(true), _nullValue());
+  }
+
+  void test_logicalAnd_true_string() {
+    try {
+      _assertLogicalAnd(
+          _boolValue(false), _boolValue(true), _stringValue("true"));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalAnd_true_true() {
+    _assertLogicalAnd(_boolValue(true), _boolValue(true), _boolValue(true));
+  }
+
+  void test_logicalNot_false() {
+    _assertLogicalNot(_boolValue(true), _boolValue(false));
+  }
+
+  void test_logicalNot_null() {
+    _assertLogicalNot(null, _nullValue());
+  }
+
+  void test_logicalNot_string() {
+    try {
+      _assertLogicalNot(_boolValue(true), _stringValue(null));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalNot_true() {
+    _assertLogicalNot(_boolValue(false), _boolValue(true));
+  }
+
+  void test_logicalNot_unknown() {
+    _assertLogicalNot(_boolValue(null), _boolValue(null));
+  }
+
+  void test_logicalOr_false_false() {
+    _assertLogicalOr(_boolValue(false), _boolValue(false), _boolValue(false));
+  }
+
+  void test_logicalOr_false_null() {
+    _assertLogicalOr(null, _boolValue(false), _nullValue());
+  }
+
+  void test_logicalOr_false_string() {
+    try {
+      _assertLogicalOr(
+          _boolValue(false), _boolValue(false), _stringValue("false"));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalOr_false_true() {
+    _assertLogicalOr(_boolValue(true), _boolValue(false), _boolValue(true));
+  }
+
+  void test_logicalOr_null_false() {
+    try {
+      _assertLogicalOr(_boolValue(false), _nullValue(), _boolValue(false));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalOr_null_true() {
+    try {
+      _assertLogicalOr(_boolValue(true), _nullValue(), _boolValue(true));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalOr_string_false() {
+    try {
+      _assertLogicalOr(
+          _boolValue(false), _stringValue("true"), _boolValue(false));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalOr_string_true() {
+    try {
+      _assertLogicalOr(
+          _boolValue(true), _stringValue("false"), _boolValue(true));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalOr_true_false() {
+    _assertLogicalOr(_boolValue(true), _boolValue(true), _boolValue(false));
+  }
+
+  void test_logicalOr_true_null() {
+    try {
+      _assertLogicalOr(_boolValue(true), _boolValue(true), _nullValue());
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalOr_true_string() {
+    try {
+      _assertLogicalOr(
+          _boolValue(true), _boolValue(true), _stringValue("true"));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_logicalOr_true_true() {
+    _assertLogicalOr(_boolValue(true), _boolValue(true), _boolValue(true));
+  }
+
+  void test_minus_knownDouble_knownDouble() {
+    _assertMinus(_doubleValue(1.0), _doubleValue(4.0), _doubleValue(3.0));
+  }
+
+  void test_minus_knownDouble_knownInt() {
+    _assertMinus(_doubleValue(1.0), _doubleValue(4.0), _intValue(3));
+  }
+
+  void test_minus_knownDouble_unknownDouble() {
+    _assertMinus(_doubleValue(null), _doubleValue(4.0), _doubleValue(null));
+  }
+
+  void test_minus_knownDouble_unknownInt() {
+    _assertMinus(_doubleValue(null), _doubleValue(4.0), _intValue(null));
+  }
+
+  void test_minus_knownInt_knownInt() {
+    _assertMinus(_intValue(1), _intValue(4), _intValue(3));
+  }
+
+  void test_minus_knownInt_knownString() {
+    _assertMinus(null, _intValue(4), _stringValue("3"));
+  }
+
+  void test_minus_knownInt_unknownDouble() {
+    _assertMinus(_doubleValue(null), _intValue(4), _doubleValue(null));
+  }
+
+  void test_minus_knownInt_unknownInt() {
+    _assertMinus(_intValue(null), _intValue(4), _intValue(null));
+  }
+
+  void test_minus_knownString_knownInt() {
+    _assertMinus(null, _stringValue("4"), _intValue(3));
+  }
+
+  void test_minus_unknownDouble_knownDouble() {
+    _assertMinus(_doubleValue(null), _doubleValue(null), _doubleValue(3.0));
+  }
+
+  void test_minus_unknownDouble_knownInt() {
+    _assertMinus(_doubleValue(null), _doubleValue(null), _intValue(3));
+  }
+
+  void test_minus_unknownInt_knownDouble() {
+    _assertMinus(_doubleValue(null), _intValue(null), _doubleValue(3.0));
+  }
+
+  void test_minus_unknownInt_knownInt() {
+    _assertMinus(_intValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_negated_double_known() {
+    _assertNegated(_doubleValue(2.0), _doubleValue(-2.0));
+  }
+
+  void test_negated_double_unknown() {
+    _assertNegated(_doubleValue(null), _doubleValue(null));
+  }
+
+  void test_negated_int_known() {
+    _assertNegated(_intValue(-3), _intValue(3));
+  }
+
+  void test_negated_int_unknown() {
+    _assertNegated(_intValue(null), _intValue(null));
+  }
+
+  void test_negated_string() {
+    _assertNegated(null, _stringValue(null));
+  }
+
+  void test_notEqual_bool_false() {
+    _assertNotEqual(_boolValue(false), _boolValue(true), _boolValue(true));
+  }
+
+  void test_notEqual_bool_true() {
+    _assertNotEqual(_boolValue(true), _boolValue(false), _boolValue(true));
+  }
+
+  void test_notEqual_bool_unknown() {
+    _assertNotEqual(_boolValue(null), _boolValue(null), _boolValue(false));
+  }
+
+  void test_notEqual_double_false() {
+    _assertNotEqual(_boolValue(false), _doubleValue(2.0), _doubleValue(2.0));
+  }
+
+  void test_notEqual_double_true() {
+    _assertNotEqual(_boolValue(true), _doubleValue(2.0), _doubleValue(4.0));
+  }
+
+  void test_notEqual_double_unknown() {
+    _assertNotEqual(_boolValue(null), _doubleValue(1.0), _doubleValue(null));
+  }
+
+  void test_notEqual_int_false() {
+    _assertNotEqual(_boolValue(false), _intValue(5), _intValue(5));
+  }
+
+  void test_notEqual_int_true() {
+    _assertNotEqual(_boolValue(true), _intValue(-5), _intValue(5));
+  }
+
+  void test_notEqual_int_unknown() {
+    _assertNotEqual(_boolValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_notEqual_null() {
+    _assertNotEqual(_boolValue(false), _nullValue(), _nullValue());
+  }
+
+  void test_notEqual_string_false() {
+    _assertNotEqual(
+        _boolValue(false), _stringValue("abc"), _stringValue("abc"));
+  }
+
+  void test_notEqual_string_true() {
+    _assertNotEqual(_boolValue(true), _stringValue("abc"), _stringValue("def"));
+  }
+
+  void test_notEqual_string_unknown() {
+    _assertNotEqual(_boolValue(null), _stringValue(null), _stringValue("def"));
+  }
+
+  void test_performToString_bool_false() {
+    _assertPerformToString(_stringValue("false"), _boolValue(false));
+  }
+
+  void test_performToString_bool_true() {
+    _assertPerformToString(_stringValue("true"), _boolValue(true));
+  }
+
+  void test_performToString_bool_unknown() {
+    _assertPerformToString(_stringValue(null), _boolValue(null));
+  }
+
+  void test_performToString_double_known() {
+    _assertPerformToString(_stringValue("2.0"), _doubleValue(2.0));
+  }
+
+  void test_performToString_double_unknown() {
+    _assertPerformToString(_stringValue(null), _doubleValue(null));
+  }
+
+  void test_performToString_int_known() {
+    _assertPerformToString(_stringValue("5"), _intValue(5));
+  }
+
+  void test_performToString_int_unknown() {
+    _assertPerformToString(_stringValue(null), _intValue(null));
+  }
+
+  void test_performToString_null() {
+    _assertPerformToString(_stringValue("null"), _nullValue());
+  }
+
+  void test_performToString_string_known() {
+    _assertPerformToString(_stringValue("abc"), _stringValue("abc"));
+  }
+
+  void test_performToString_string_unknown() {
+    _assertPerformToString(_stringValue(null), _stringValue(null));
+  }
+
+  void test_remainder_knownDouble_knownDouble() {
+    _assertRemainder(_doubleValue(1.0), _doubleValue(7.0), _doubleValue(2.0));
+  }
+
+  void test_remainder_knownDouble_knownInt() {
+    _assertRemainder(_doubleValue(1.0), _doubleValue(7.0), _intValue(2));
+  }
+
+  void test_remainder_knownDouble_unknownDouble() {
+    _assertRemainder(_doubleValue(null), _doubleValue(7.0), _doubleValue(null));
+  }
+
+  void test_remainder_knownDouble_unknownInt() {
+    _assertRemainder(_doubleValue(null), _doubleValue(6.0), _intValue(null));
+  }
+
+  void test_remainder_knownInt_knownInt() {
+    _assertRemainder(_intValue(1), _intValue(7), _intValue(2));
+  }
+
+  void test_remainder_knownInt_knownString() {
+    _assertRemainder(null, _intValue(7), _stringValue("2"));
+  }
+
+  void test_remainder_knownInt_unknownDouble() {
+    _assertRemainder(_doubleValue(null), _intValue(7), _doubleValue(null));
+  }
+
+  void test_remainder_knownInt_unknownInt() {
+    _assertRemainder(_intValue(null), _intValue(7), _intValue(null));
+  }
+
+  void test_remainder_knownString_knownInt() {
+    _assertRemainder(null, _stringValue("7"), _intValue(2));
+  }
+
+  void test_remainder_unknownDouble_knownDouble() {
+    _assertRemainder(_doubleValue(null), _doubleValue(null), _doubleValue(2.0));
+  }
+
+  void test_remainder_unknownDouble_knownInt() {
+    _assertRemainder(_doubleValue(null), _doubleValue(null), _intValue(2));
+  }
+
+  void test_remainder_unknownInt_knownDouble() {
+    _assertRemainder(_doubleValue(null), _intValue(null), _doubleValue(2.0));
+  }
+
+  void test_remainder_unknownInt_knownInt() {
+    _assertRemainder(_intValue(null), _intValue(null), _intValue(2));
+  }
+
+  void test_shiftLeft_knownInt_knownInt() {
+    _assertShiftLeft(_intValue(48), _intValue(6), _intValue(3));
+  }
+
+  void test_shiftLeft_knownInt_knownString() {
+    _assertShiftLeft(null, _intValue(6), _stringValue(null));
+  }
+
+  void test_shiftLeft_knownInt_tooLarge() {
+    _assertShiftLeft(
+        _intValue(null),
+        _intValue(6),
+        new DartObjectImpl(
+            _typeProvider.intType, new IntState(LONG_MAX_VALUE)));
+  }
+
+  void test_shiftLeft_knownInt_unknownInt() {
+    _assertShiftLeft(_intValue(null), _intValue(6), _intValue(null));
+  }
+
+  void test_shiftLeft_knownString_knownInt() {
+    _assertShiftLeft(null, _stringValue(null), _intValue(3));
+  }
+
+  void test_shiftLeft_unknownInt_knownInt() {
+    _assertShiftLeft(_intValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_shiftLeft_unknownInt_unknownInt() {
+    _assertShiftLeft(_intValue(null), _intValue(null), _intValue(null));
+  }
+
+  void test_shiftRight_knownInt_knownInt() {
+    _assertShiftRight(_intValue(6), _intValue(48), _intValue(3));
+  }
+
+  void test_shiftRight_knownInt_knownString() {
+    _assertShiftRight(null, _intValue(48), _stringValue(null));
+  }
+
+  void test_shiftRight_knownInt_tooLarge() {
+    _assertShiftRight(
+        _intValue(null),
+        _intValue(48),
+        new DartObjectImpl(
+            _typeProvider.intType, new IntState(LONG_MAX_VALUE)));
+  }
+
+  void test_shiftRight_knownInt_unknownInt() {
+    _assertShiftRight(_intValue(null), _intValue(48), _intValue(null));
+  }
+
+  void test_shiftRight_knownString_knownInt() {
+    _assertShiftRight(null, _stringValue(null), _intValue(3));
+  }
+
+  void test_shiftRight_unknownInt_knownInt() {
+    _assertShiftRight(_intValue(null), _intValue(null), _intValue(3));
+  }
+
+  void test_shiftRight_unknownInt_unknownInt() {
+    _assertShiftRight(_intValue(null), _intValue(null), _intValue(null));
+  }
+
+  void test_stringLength_int() {
+    try {
+      _assertStringLength(_intValue(null), _intValue(0));
+      fail("Expected EvaluationException");
+    } on EvaluationException {}
+  }
+
+  void test_stringLength_knownString() {
+    _assertStringLength(_intValue(3), _stringValue("abc"));
+  }
+
+  void test_stringLength_unknownString() {
+    _assertStringLength(_intValue(null), _stringValue(null));
+  }
+
+  void test_times_knownDouble_knownDouble() {
+    _assertTimes(_doubleValue(6.0), _doubleValue(2.0), _doubleValue(3.0));
+  }
+
+  void test_times_knownDouble_knownInt() {
+    _assertTimes(_doubleValue(6.0), _doubleValue(2.0), _intValue(3));
+  }
+
+  void test_times_knownDouble_unknownDouble() {
+    _assertTimes(_doubleValue(null), _doubleValue(2.0), _doubleValue(null));
+  }
+
+  void test_times_knownDouble_unknownInt() {
+    _assertTimes(_doubleValue(null), _doubleValue(2.0), _intValue(null));
+  }
+
+  void test_times_knownInt_knownInt() {
+    _assertTimes(_intValue(6), _intValue(2), _intValue(3));
+  }
+
+  void test_times_knownInt_knownString() {
+    _assertTimes(null, _intValue(2), _stringValue("3"));
+  }
+
+  void test_times_knownInt_unknownDouble() {
+    _assertTimes(_doubleValue(null), _intValue(2), _doubleValue(null));
+  }
+
+  void test_times_knownInt_unknownInt() {
+    _assertTimes(_intValue(null), _intValue(2), _intValue(null));
+  }
+
+  void test_times_knownString_knownInt() {
+    _assertTimes(null, _stringValue("2"), _intValue(3));
+  }
+
+  void test_times_unknownDouble_knownDouble() {
+    _assertTimes(_doubleValue(null), _doubleValue(null), _doubleValue(3.0));
+  }
+
+  void test_times_unknownDouble_knownInt() {
+    _assertTimes(_doubleValue(null), _doubleValue(null), _intValue(3));
+  }
+
+  void test_times_unknownInt_knownDouble() {
+    _assertTimes(_doubleValue(null), _intValue(null), _doubleValue(3.0));
+  }
+
+  void test_times_unknownInt_knownInt() {
+    _assertTimes(_intValue(null), _intValue(null), _intValue(3));
+  }
+
+  /**
+   * Assert that the result of adding the left and right operands is the expected value, or that the
+   * operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertAdd(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.add(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.add(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of bit-anding the left and right operands is the expected value, or that
+   * the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertBitAnd(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.bitAnd(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.bitAnd(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the bit-not of the operand is the expected value, or that the operation throws an
+   * exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param operand the operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertBitNot(DartObjectImpl expected, DartObjectImpl operand) {
+    if (expected == null) {
+      try {
+        operand.bitNot(_typeProvider);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = operand.bitNot(_typeProvider);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of bit-oring the left and right operands is the expected value, or that
+   * the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertBitOr(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.bitOr(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.bitOr(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of bit-xoring the left and right operands is the expected value, or that
+   * the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertBitXor(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.bitXor(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.bitXor(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of concatenating the left and right operands is the expected value, or
+   * that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertConcatenate(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.concatenate(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.concatenate(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of dividing the left and right operands is the expected value, or that
+   * the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertDivide(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.divide(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.divide(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of comparing the left and right operands for equality is the expected
+   * value, or that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertEqualEqual(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.equalEqual(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.equalEqual(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of comparing the left and right operands is the expected value, or that
+   * the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertGreaterThan(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.greaterThan(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.greaterThan(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of comparing the left and right operands is the expected value, or that
+   * the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertGreaterThanOrEqual(DartObjectImpl expected,
+      DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.greaterThanOrEqual(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.greaterThanOrEqual(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of comparing the left and right operands using
+   * identical() is the expected value.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   */
+  void _assertIdentical(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    DartObjectImpl result =
+        leftOperand.isIdentical(_typeProvider, rightOperand);
+    expect(result, isNotNull);
+    expect(result, expected);
+  }
+
+  void _assertInstanceOfObjectArray(Object result) {
+    // TODO(scheglov) implement
+  }
+
+  /**
+   * Assert that the result of dividing the left and right operands as integers is the expected
+   * value, or that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertIntegerDivide(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.integerDivide(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.integerDivide(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of comparing the left and right operands is the expected value, or that
+   * the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertLessThan(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.lessThan(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.lessThan(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of comparing the left and right operands is the expected value, or that
+   * the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertLessThanOrEqual(DartObjectImpl expected,
+      DartObjectImpl leftOperand, DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.lessThanOrEqual(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.lessThanOrEqual(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of logical-anding the left and right operands is the expected value, or
+   * that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertLogicalAnd(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.logicalAnd(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.logicalAnd(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the logical-not of the operand is the expected value, or that the operation throws
+   * an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param operand the operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertLogicalNot(DartObjectImpl expected, DartObjectImpl operand) {
+    if (expected == null) {
+      try {
+        operand.logicalNot(_typeProvider);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = operand.logicalNot(_typeProvider);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of logical-oring the left and right operands is the expected value, or
+   * that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertLogicalOr(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.logicalOr(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.logicalOr(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of subtracting the left and right operands is the expected value, or
+   * that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertMinus(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.minus(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.minus(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the negation of the operand is the expected value, or that the operation throws an
+   * exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param operand the operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertNegated(DartObjectImpl expected, DartObjectImpl operand) {
+    if (expected == null) {
+      try {
+        operand.negated(_typeProvider);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = operand.negated(_typeProvider);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of comparing the left and right operands for inequality is the expected
+   * value, or that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertNotEqual(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.notEqual(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.notEqual(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that converting the operand to a string is the expected value, or that the operation
+   * throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param operand the operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertPerformToString(DartObjectImpl expected, DartObjectImpl operand) {
+    if (expected == null) {
+      try {
+        operand.performToString(_typeProvider);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = operand.performToString(_typeProvider);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of taking the remainder of the left and right operands is the expected
+   * value, or that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertRemainder(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.remainder(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.remainder(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of multiplying the left and right operands is the expected value, or
+   * that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertShiftLeft(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.shiftLeft(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.shiftLeft(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of multiplying the left and right operands is the expected value, or
+   * that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the right operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertShiftRight(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.shiftRight(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result =
+          leftOperand.shiftRight(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the length of the operand is the expected value, or that the operation throws an
+   * exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param operand the operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertStringLength(DartObjectImpl expected, DartObjectImpl operand) {
+    if (expected == null) {
+      try {
+        operand.stringLength(_typeProvider);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = operand.stringLength(_typeProvider);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  /**
+   * Assert that the result of multiplying the left and right operands is the expected value, or
+   * that the operation throws an exception if the expected value is `null`.
+   *
+   * @param expected the expected result of the operation
+   * @param leftOperand the left operand to the operation
+   * @param rightOperand the left operand to the operation
+   * @throws EvaluationException if the result is an exception when it should not be
+   */
+  void _assertTimes(DartObjectImpl expected, DartObjectImpl leftOperand,
+      DartObjectImpl rightOperand) {
+    if (expected == null) {
+      try {
+        leftOperand.times(_typeProvider, rightOperand);
+        fail("Expected an EvaluationException");
+      } on EvaluationException {}
+    } else {
+      DartObjectImpl result = leftOperand.times(_typeProvider, rightOperand);
+      expect(result, isNotNull);
+      expect(result, expected);
+    }
+  }
+
+  DartObjectImpl _boolValue(bool value) {
+    if (value == null) {
+      return new DartObjectImpl(
+          _typeProvider.boolType, BoolState.UNKNOWN_VALUE);
+    } else if (identical(value, false)) {
+      return new DartObjectImpl(_typeProvider.boolType, BoolState.FALSE_STATE);
+    } else if (identical(value, true)) {
+      return new DartObjectImpl(_typeProvider.boolType, BoolState.TRUE_STATE);
+    }
+    fail("Invalid boolean value used in test");
+    return null;
+  }
+
+  DartObjectImpl _doubleValue(double value) {
+    if (value == null) {
+      return new DartObjectImpl(
+          _typeProvider.doubleType, DoubleState.UNKNOWN_VALUE);
+    } else {
+      return new DartObjectImpl(
+          _typeProvider.doubleType, new DoubleState(value));
+    }
+  }
+
+  DartObjectImpl _dynamicValue() {
+    return new DartObjectImpl(
+        _typeProvider.nullType, DynamicState.DYNAMIC_STATE);
+  }
+
+  DartObjectImpl _intValue(int value) {
+    if (value == null) {
+      return new DartObjectImpl(_typeProvider.intType, IntState.UNKNOWN_VALUE);
+    } else {
+      return new DartObjectImpl(_typeProvider.intType, new IntState(value));
+    }
+  }
+
+  DartObjectImpl _listValue(
+      [List<DartObjectImpl> elements = DartObjectImpl.EMPTY_LIST]) {
+    return new DartObjectImpl(_typeProvider.listType, new ListState(elements));
+  }
+
+  DartObjectImpl _mapValue(
+      [List<DartObjectImpl> keyElementPairs = DartObjectImpl.EMPTY_LIST]) {
+    Map<DartObjectImpl, DartObjectImpl> map =
+        new Map<DartObjectImpl, DartObjectImpl>();
+    int count = keyElementPairs.length;
+    for (int i = 0; i < count;) {
+      map[keyElementPairs[i++]] = keyElementPairs[i++];
+    }
+    return new DartObjectImpl(_typeProvider.mapType, new MapState(map));
+  }
+
+  DartObjectImpl _nullValue() {
+    return new DartObjectImpl(_typeProvider.nullType, NullState.NULL_STATE);
+  }
+
+  DartObjectImpl _numValue() {
+    return new DartObjectImpl(_typeProvider.nullType, NumState.UNKNOWN_VALUE);
+  }
+
+  DartObjectImpl _stringValue(String value) {
+    if (value == null) {
+      return new DartObjectImpl(
+          _typeProvider.stringType, StringState.UNKNOWN_VALUE);
+    } else {
+      return new DartObjectImpl(
+          _typeProvider.stringType, new StringState(value));
+    }
+  }
+
+  DartObjectImpl _symbolValue(String value) {
+    return new DartObjectImpl(_typeProvider.symbolType, new SymbolState(value));
+  }
+}
+
+@reflectiveTest
+class DeclaredVariablesTest extends EngineTestCase {
+  void test_getBool_false() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    DeclaredVariables variables = new DeclaredVariables();
+    variables.define(variableName, "false");
+    DartObject object = variables.getBool(typeProvider, variableName);
+    expect(object, isNotNull);
+    expect(object.toBoolValue(), false);
+  }
+
+  void test_getBool_invalid() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    DeclaredVariables variables = new DeclaredVariables();
+    variables.define(variableName, "not true");
+    _assertNullDartObject(
+        typeProvider, variables.getBool(typeProvider, variableName));
+  }
+
+  void test_getBool_true() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    DeclaredVariables variables = new DeclaredVariables();
+    variables.define(variableName, "true");
+    DartObject object = variables.getBool(typeProvider, variableName);
+    expect(object, isNotNull);
+    expect(object.toBoolValue(), true);
+  }
+
+  void test_getBool_undefined() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    DeclaredVariables variables = new DeclaredVariables();
+    _assertUnknownDartObject(
+        typeProvider.boolType, variables.getBool(typeProvider, variableName));
+  }
+
+  void test_getInt_invalid() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    DeclaredVariables variables = new DeclaredVariables();
+    variables.define(variableName, "four score and seven years");
+    _assertNullDartObject(
+        typeProvider, variables.getInt(typeProvider, variableName));
+  }
+
+  void test_getInt_undefined() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    DeclaredVariables variables = new DeclaredVariables();
+    _assertUnknownDartObject(
+        typeProvider.intType, variables.getInt(typeProvider, variableName));
+  }
+
+  void test_getInt_valid() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    DeclaredVariables variables = new DeclaredVariables();
+    variables.define(variableName, "23");
+    DartObject object = variables.getInt(typeProvider, variableName);
+    expect(object, isNotNull);
+    expect(object.toIntValue(), 23);
+  }
+
+  void test_getString_defined() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    String value = "value";
+    DeclaredVariables variables = new DeclaredVariables();
+    variables.define(variableName, value);
+    DartObject object = variables.getString(typeProvider, variableName);
+    expect(object, isNotNull);
+    expect(object.toStringValue(), value);
+  }
+
+  void test_getString_undefined() {
+    TestTypeProvider typeProvider = new TestTypeProvider();
+    String variableName = "var";
+    DeclaredVariables variables = new DeclaredVariables();
+    _assertUnknownDartObject(typeProvider.stringType,
+        variables.getString(typeProvider, variableName));
+  }
+
+  void _assertNullDartObject(TestTypeProvider typeProvider, DartObject result) {
+    expect(result.type, typeProvider.nullType);
+  }
+
+  void _assertUnknownDartObject(
+      ParameterizedType expectedType, DartObject result) {
+    expect((result as DartObjectImpl).isUnknown, isTrue);
+    expect(result.type, expectedType);
+  }
+}
+
+@reflectiveTest
+class ReferenceFinderTest {
+  DirectedGraph<ConstantEvaluationTarget> _referenceGraph;
+  VariableElement _head;
+  Element _tail;
+
+  void setUp() {
+    _referenceGraph = new DirectedGraph<ConstantEvaluationTarget>();
+    _head = ElementFactory.topLevelVariableElement2("v1");
+  }
+
+  void test_visitSimpleIdentifier_const() {
+    _visitNode(_makeTailVariable("v2", true));
+    _assertOneArc(_tail);
+  }
+
+  void test_visitSuperConstructorInvocation_const() {
+    _visitNode(_makeTailSuperConstructorInvocation("A", true));
+    _assertOneArc(_tail);
+  }
+
+  void test_visitSuperConstructorInvocation_nonConst() {
+    _visitNode(_makeTailSuperConstructorInvocation("A", false));
+    _assertOneArc(_tail);
+  }
+
+  void test_visitSuperConstructorInvocation_unresolved() {
+    SuperConstructorInvocation superConstructorInvocation =
+        AstFactory.superConstructorInvocation();
+    _visitNode(superConstructorInvocation);
+    _assertNoArcs();
+  }
+
+  void _assertNoArcs() {
+    Set<ConstantEvaluationTarget> tails = _referenceGraph.getTails(_head);
+    expect(tails, hasLength(0));
+  }
+
+  void _assertOneArc(Element tail) {
+    Set<ConstantEvaluationTarget> tails = _referenceGraph.getTails(_head);
+    expect(tails, hasLength(1));
+    expect(tails.first, same(tail));
+  }
+
+  ReferenceFinder _createReferenceFinder(ConstantEvaluationTarget source) =>
+      new ReferenceFinder((ConstantEvaluationTarget dependency) {
+        _referenceGraph.addEdge(source, dependency);
+      });
+  SuperConstructorInvocation _makeTailSuperConstructorInvocation(
+      String name, bool isConst) {
+    List<ConstructorInitializer> initializers =
+        new List<ConstructorInitializer>();
+    ConstructorDeclaration constructorDeclaration =
+        AstFactory.constructorDeclaration(AstFactory.identifier3(name), null,
+            AstFactory.formalParameterList(), initializers);
+    if (isConst) {
+      constructorDeclaration.constKeyword = new KeywordToken(Keyword.CONST, 0);
+    }
+    ClassElementImpl classElement = ElementFactory.classElement2(name);
+    SuperConstructorInvocation superConstructorInvocation =
+        AstFactory.superConstructorInvocation();
+    ConstructorElementImpl constructorElement =
+        ElementFactory.constructorElement(classElement, name, isConst);
+    _tail = constructorElement;
+    superConstructorInvocation.staticElement = constructorElement;
+    return superConstructorInvocation;
+  }
+
+  SimpleIdentifier _makeTailVariable(String name, bool isConst) {
+    VariableDeclaration variableDeclaration =
+        AstFactory.variableDeclaration(name);
+    ConstLocalVariableElementImpl variableElement =
+        ElementFactory.constLocalVariableElement(name);
+    _tail = variableElement;
+    variableElement.const3 = isConst;
+    AstFactory.variableDeclarationList2(
+        isConst ? Keyword.CONST : Keyword.VAR, [variableDeclaration]);
+    SimpleIdentifier identifier = AstFactory.identifier3(name);
+    identifier.staticElement = variableElement;
+    return identifier;
+  }
+
+  void _visitNode(AstNode node) {
+    node.accept(_createReferenceFinder(_head));
+  }
+}
+
+class _TestAnalysisContext extends TestAnalysisContext {
+  @override
+  InternalAnalysisContext getContextFor(Source source) => this;
+}
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
index 3dfae2b..4f0b214 100644
--- a/pkg/analyzer/test/generated/declaration_resolver_test.dart
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -4,8 +4,10 @@
 
 library engine.declaration_resolver_test;
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:unittest/unittest.dart';
@@ -17,6 +19,7 @@
 
 main() {
   initializeTestEnvironment();
+  runReflectiveTests(DeclarationResolverMetadataTest);
   runReflectiveTests(DeclarationResolverTest);
   runReflectiveTests(StrongModeDeclarationResolverTest);
 }
@@ -34,6 +37,207 @@
 }
 
 @reflectiveTest
+class DeclarationResolverMetadataTest extends ResolverTestCase {
+  String code;
+  CompilationUnit unit;
+  CompilationUnit unit2;
+
+  void checkMetadata(String search) {
+    NodeList<Annotation> metadata = _findMetadata(unit, search);
+    NodeList<Annotation> metadata2 = _findMetadata(unit2, search);
+    expect(metadata, isNotEmpty);
+    for (int i = 0; i < metadata.length; i++) {
+      expect(
+          metadata2[i].elementAnnotation, same(metadata[i].elementAnnotation));
+    }
+  }
+
+  void setupCode(String code) {
+    this.code = code;
+    unit = resolveSource(code + ' const a = null;');
+    unit2 = _cloneResolveUnit(unit);
+  }
+
+  void test_metadata_classDeclaration() {
+    setupCode('@a class C {}');
+    checkMetadata('C');
+  }
+
+  void test_metadata_classTypeAlias() {
+    setupCode('@a class C = D with E; class D {} class E {}');
+    checkMetadata('C');
+  }
+
+  void test_metadata_constructorDeclaration_named() {
+    setupCode('class C { @a C.x(); }');
+    checkMetadata('x');
+  }
+
+  void test_metadata_constructorDeclaration_unnamed() {
+    setupCode('class C { @a C(); }');
+    checkMetadata('C()');
+  }
+
+  void test_metadata_declaredIdentifier() {
+    setupCode('f(x, y) { for (@a var x in y) {} }');
+    checkMetadata('var');
+  }
+
+  void test_metadata_enumDeclaration() {
+    setupCode('@a enum E { v }');
+    checkMetadata('E');
+  }
+
+  void test_metadata_exportDirective() {
+    addNamedSource('/foo.dart', 'class C {}');
+    setupCode('@a export "foo.dart";');
+    checkMetadata('export');
+  }
+
+  void test_metadata_fieldDeclaration() {
+    setupCode('class C { @a int x; }');
+    checkMetadata('x');
+  }
+
+  void test_metadata_fieldFormalParameter() {
+    setupCode('class C { var x; C(@a this.x); }');
+    checkMetadata('this');
+  }
+
+  void test_metadata_fieldFormalParameter_withDefault() {
+    setupCode('class C { var x; C([@a this.x = null]); }');
+    checkMetadata('this');
+  }
+
+  void test_metadata_functionDeclaration_function() {
+    setupCode('@a f() {}');
+    checkMetadata('f');
+  }
+
+  void test_metadata_functionDeclaration_getter() {
+    setupCode('@a get f() => null;');
+    checkMetadata('f');
+  }
+
+  void test_metadata_functionDeclaration_setter() {
+    setupCode('@a set f(value) {}');
+    checkMetadata('f');
+  }
+
+  void test_metadata_functionTypeAlias() {
+    setupCode('@a typedef F();');
+    checkMetadata('F');
+  }
+
+  void test_metadata_functionTypedFormalParameter() {
+    setupCode('f(@a g()) {}');
+    checkMetadata('g');
+  }
+
+  void test_metadata_functionTypedFormalParameter_withDefault() {
+    setupCode('f([@a g() = null]) {}');
+    checkMetadata('g');
+  }
+
+  void test_metadata_importDirective() {
+    addNamedSource('/foo.dart', 'class C {}');
+    setupCode('@a import "foo.dart";');
+    checkMetadata('import');
+  }
+
+  void test_metadata_libraryDirective() {
+    setupCode('@a library L;');
+    checkMetadata('L');
+  }
+
+  void test_metadata_localFunctionDeclaration() {
+    setupCode('f() { @a g() {} }');
+    // Note: metadata on local function declarations is ignored by the
+    // analyzer.  TODO(paulberry): is this a bug?
+    FunctionDeclaration node = EngineTestCase.findNode(
+        unit, code, 'g', (AstNode n) => n is FunctionDeclaration);
+    expect((node as FunctionDeclarationImpl).metadata, isEmpty);
+  }
+
+  void test_metadata_localVariableDeclaration() {
+    setupCode('f() { @a int x; }');
+    checkMetadata('x');
+  }
+
+  void test_metadata_methodDeclaration_getter() {
+    setupCode('class C { @a get m => null; }');
+    checkMetadata('m');
+  }
+
+  void test_metadata_methodDeclaration_method() {
+    setupCode('class C { @a m() {} }');
+    checkMetadata('m');
+  }
+
+  void test_metadata_methodDeclaration_setter() {
+    setupCode('class C { @a set m(value) {} }');
+    checkMetadata('m');
+  }
+
+  void test_metadata_partDirective() {
+    addNamedSource('/foo.dart', 'part of L;');
+    setupCode('library L; @a part "foo.dart";');
+    checkMetadata('part');
+  }
+
+  void test_metadata_simpleFormalParameter() {
+    setupCode('f(@a x) {}) {}');
+    checkMetadata('x');
+  }
+
+  void test_metadata_simpleFormalParameter_withDefault() {
+    setupCode('f([@a x = null]) {}');
+    checkMetadata('x');
+  }
+
+  void test_metadata_topLevelVariableDeclaration() {
+    setupCode('@a int x;');
+    checkMetadata('x');
+  }
+
+  void test_metadata_typeParameter_ofClass() {
+    setupCode('class C<@a T> {}');
+    checkMetadata('T');
+  }
+
+  void test_metadata_typeParameter_ofClassTypeAlias() {
+    setupCode('class C<@a T> = D with E; class D {} class E {}');
+    checkMetadata('T');
+  }
+
+  void test_metadata_typeParameter_ofFunction() {
+    setupCode('f<@a T>() {}');
+    checkMetadata('T');
+  }
+
+  void test_metadata_typeParameter_ofTypedef() {
+    setupCode('typedef F<@a T>();');
+    checkMetadata('T');
+  }
+
+  NodeList<Annotation> _findMetadata(CompilationUnit unit, String search) {
+    AstNode node =
+        EngineTestCase.findNode(unit, code, search, (AstNode _) => true);
+    while (node != null) {
+      if (node is AnnotatedNode && node.metadata.isNotEmpty) {
+        return node.metadata;
+      }
+      if (node is NormalFormalParameter && node.metadata.isNotEmpty) {
+        return node.metadata;
+      }
+      node = node.parent;
+    }
+    fail('Node not found');
+    return null;
+  }
+}
+
+@reflectiveTest
 class DeclarationResolverTest extends ResolverTestCase {
   @override
   void setUp() {
@@ -97,6 +301,164 @@
     SimpleIdentifier setterName = _findSimpleIdentifier(unit2, code, 'zzz(x)');
     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) {
+  items.forEach((item) {});
+}
+''';
+    CompilationUnit unit = resolveSource(code);
+    // re-resolve
+    _cloneResolveUnit(unit);
+    // no other validations than built into DeclarationResolver
+  }
+
+  void test_visitImportDirective_notExistingSource() {
+    String code = r'''
+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
+    _cloneResolveUnit(unit);
+    // no other validations than built into DeclarationResolver
+  }
+
+  void test_visitMethodDeclaration_getter_duplicate() {
+    String code = r'''
+class C {
+  int get zzz => 1;
+  String get zzz => null;
+}
+''';
+    CompilationUnit unit = resolveSource(code);
+    PropertyAccessorElement firstElement =
+        _findSimpleIdentifier(unit, code, 'zzz => 1').staticElement;
+    PropertyAccessorElement secondElement =
+        _findSimpleIdentifier(unit, code, 'zzz => null').staticElement;
+    // re-resolve
+    CompilationUnit unit2 = _cloneResolveUnit(unit);
+    SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz => 1');
+    SimpleIdentifier secondName =
+        _findSimpleIdentifier(unit2, code, 'zzz => null');
+    expect(firstName.staticElement, same(firstElement));
+    expect(secondName.staticElement, same(secondElement));
+  }
+
+  void test_visitMethodDeclaration_getterSetter() {
+    String code = r'''
+class C {
+  int _field = 0;
+  int get field => _field;
+  void set field(value) {_field = value;}
+}
+''';
+    CompilationUnit unit = resolveSource(code);
+    FieldElement getterElement =
+        _findSimpleIdentifier(unit, code, 'field =').staticElement;
+    PropertyAccessorElement setterElement =
+        _findSimpleIdentifier(unit, code, 'field(').staticElement;
+    // re-resolve
+    CompilationUnit unit2 = _cloneResolveUnit(unit);
+    SimpleIdentifier getterName = _findSimpleIdentifier(unit2, code, 'field =');
+    SimpleIdentifier setterName = _findSimpleIdentifier(unit2, code, 'field(');
+    expect(getterName.staticElement, same(getterElement));
+    expect(setterName.staticElement, same(setterElement));
+  }
+
+  void test_visitMethodDeclaration_method_duplicate() {
+    String code = r'''
+class C {
+  void zzz(x) {}
+  void zzz(y) {}
+}
+''';
+    CompilationUnit unit = resolveSource(code);
+    MethodElement firstElement =
+        _findSimpleIdentifier(unit, code, 'zzz(x)').staticElement;
+    MethodElement secondElement =
+        _findSimpleIdentifier(unit, code, 'zzz(y)').staticElement;
+    // re-resolve
+    CompilationUnit unit2 = _cloneResolveUnit(unit);
+    SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz(x)');
+    SimpleIdentifier secondName = _findSimpleIdentifier(unit2, code, 'zzz(y)');
+    expect(firstName.staticElement, same(firstElement));
+    expect(secondName.staticElement, same(secondElement));
+  }
+
+  void test_visitMethodDeclaration_setter_duplicate() {
+    // https://github.com/dart-lang/sdk/issues/25601
+    String code = r'''
+class C {
+  set zzz(x) {}
+  set zzz(y) {}
+}
+''';
+    CompilationUnit unit = resolveSource(code);
+    PropertyAccessorElement firstElement =
+        _findSimpleIdentifier(unit, code, 'zzz(x)').staticElement;
+    PropertyAccessorElement secondElement =
+        _findSimpleIdentifier(unit, code, 'zzz(y)').staticElement;
+    // re-resolve
+    CompilationUnit unit2 = _cloneResolveUnit(unit);
+    SimpleIdentifier firstName = _findSimpleIdentifier(unit2, code, 'zzz(x)');
+    SimpleIdentifier secondName = _findSimpleIdentifier(unit2, code, 'zzz(y)');
+    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/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index e2b20b3..f15ece1 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -6,10 +6,12 @@
 
 import 'dart:async';
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/source/embedder.dart';
 import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/context/source.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -74,7 +76,7 @@
 
 class CompilationUnitMock extends TypedMock implements CompilationUnit {}
 
-class MockSourceFactory extends SourceFactory {
+class MockSourceFactory extends SourceFactoryImpl {
   MockSourceFactory() : super([]);
   Source resolveUri(Source containingSource, String containedUri) {
     throw new JavaIOException();
@@ -192,6 +194,9 @@
  */
 class TestAnalysisContext implements InternalAnalysisContext {
   @override
+  ResultProvider resultProvider;
+
+  @override
   AnalysisCache get analysisCache {
     fail("Unexpected invocation of analysisCache");
     return null;
diff --git a/pkg/analyzer/test/generated/error_suppression_test.dart b/pkg/analyzer/test/generated/error_suppression_test.dart
new file mode 100644
index 0000000..da6c49d
--- /dev/null
+++ b/pkg/analyzer/test/generated/error_suppression_test.dart
@@ -0,0 +1,152 @@
+// 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/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+
+import '../reflective_tests.dart';
+import '../utils.dart';
+import 'resolver_test.dart';
+
+main() {
+  initializeTestEnvironment();
+  runReflectiveTests(ErrorSuppressionTest);
+}
+
+@reflectiveTest
+class ErrorSuppressionTest extends ResolverTestCase {
+  void test_error_code_mismatch() {
+    Source source = addSource('''
+// ignore: const_initialized_with_non_constant_value
+int x = '';
+const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      StaticTypeWarningCode.INVALID_ASSIGNMENT,
+      CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+    ]);
+  }
+
+  void test_ignore_first() {
+    Source source = addSource('''
+// ignore: invalid_assignment
+int x = '';
+// ... but no ignore here ...
+const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source,
+        [CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE]);
+  }
+
+  void test_ignore_second() {
+    Source source = addSource('''
+//INVALID_ASSIGNMENT
+int x = '';
+// ignore: const_initialized_with_non_constant_value
+const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  void test_invalid_error_code() {
+    Source source = addSource('''
+// ignore: right_format_wrong_code
+int x = '';
+const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      StaticTypeWarningCode.INVALID_ASSIGNMENT,
+      CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+    ]);
+  }
+
+  void test_missing_error_codes() {
+    Source source = addSource('''
+    int x = 3;
+// ignore:
+const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      StaticTypeWarningCode.INVALID_ASSIGNMENT,
+      CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+    ]);
+  }
+
+  void test_missing_metadata_suffix() {
+    Source source = addSource('''
+// ignore invalid_assignment
+String y = 3; //INVALID_ASSIGNMENT
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  void test_multiple_comments() {
+    Source source = addSource('''
+int x = ''; //This is the first comment...
+// ignore: const_initialized_with_non_constant_value
+const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
+  void test_multiple_ignores() {
+    Source source = addSource('''
+int x = 3;
+// ignore: invalid_assignment, const_initialized_with_non_constant_value
+const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+  }
+
+  void test_multiple_ignores_whitespace_variant_1() {
+    Source source = addSource('''
+int x = 3;
+//ignore:invalid_assignment,const_initialized_with_non_constant_value
+const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+  }
+
+  void test_multiple_ignores_whitespace_variant_2() {
+    Source source = addSource('''
+int x = 3;
+//ignore: invalid_assignment,const_initialized_with_non_constant_value
+const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+  }
+
+  void test_multiple_ignores_whitespace_variant_3() {
+    Source source = addSource('''
+int x = 3;
+// ignore: invalid_assignment,const_initialized_with_non_constant_value
+const String y = x; //INVALID_ASSIGNMENT, CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+  }
+
+  void test_no_ignores() {
+    Source source = addSource('''
+int x = '';  //INVALID_ASSIGNMENT
+const y = x; //CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      StaticTypeWarningCode.INVALID_ASSIGNMENT,
+      CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 6a52fce..80e4264 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -4,24 +4,30 @@
 
 library analyzer.test.generated.incremental_resolver_test;
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.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/incremental_logger.dart' as log;
+import 'package:analyzer/src/generated/incremental_logger.dart' as logging;
 import 'package:analyzer/src/generated/incremental_resolution_validator.dart';
 import 'package:analyzer/src/generated/incremental_resolver.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
+import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/model.dart';
 import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
@@ -38,81 +44,95 @@
 
 void initializeTestEnvironment() {}
 
-void _assertEqualError(AnalysisError incrError, AnalysisError fullError) {
-  if (incrError.errorCode != fullError.errorCode ||
-      incrError.source != fullError.source ||
-      incrError.offset != fullError.offset ||
-      incrError.length != fullError.length ||
-      incrError.message != fullError.message) {
+void _assertEqualError(AnalysisError incError, AnalysisError fullError) {
+  if (incError.errorCode != fullError.errorCode ||
+      incError.source != fullError.source ||
+      incError.offset != fullError.offset ||
+      incError.length != fullError.length ||
+      incError.message != fullError.message) {
     StringBuffer buffer = new StringBuffer();
     buffer.writeln('Found error does not match expected error:');
-    if (incrError.errorCode == fullError.errorCode) {
+    if (incError.errorCode == fullError.errorCode) {
       buffer.write('  errorCode = ');
       buffer.write(fullError.errorCode.uniqueName);
     } else {
       buffer.write('  Expected errorCode = ');
       buffer.write(fullError.errorCode.uniqueName);
       buffer.write(' found ');
-      buffer.write(incrError.errorCode.uniqueName);
+      buffer.write(incError.errorCode.uniqueName);
     }
     buffer.writeln();
-    if (incrError.source == fullError.source) {
+    if (incError.source == fullError.source) {
       buffer.write('  source = ');
       buffer.write(fullError.source);
     } else {
       buffer.write('  Expected source = ');
       buffer.write(fullError.source);
       buffer.write(' found ');
-      buffer.write(incrError.source);
+      buffer.write(incError.source);
     }
     buffer.writeln();
-    if (incrError.offset == fullError.offset) {
+    if (incError.offset == fullError.offset) {
       buffer.write('  offset = ');
       buffer.write(fullError.offset);
     } else {
       buffer.write('  Expected offset = ');
       buffer.write(fullError.offset);
       buffer.write(' found ');
-      buffer.write(incrError.offset);
+      buffer.write(incError.offset);
     }
     buffer.writeln();
-    if (incrError.length == fullError.length) {
+    if (incError.length == fullError.length) {
       buffer.write('  length = ');
       buffer.write(fullError.length);
     } else {
       buffer.write('  Expected length = ');
       buffer.write(fullError.length);
       buffer.write(' found ');
-      buffer.write(incrError.length);
+      buffer.write(incError.length);
     }
     buffer.writeln();
-    if (incrError.message == fullError.message) {
+    if (incError.message == fullError.message) {
       buffer.write('  message = ');
       buffer.write(fullError.message);
     } else {
       buffer.write('  Expected message = ');
       buffer.write(fullError.message);
       buffer.write(' found ');
-      buffer.write(incrError.message);
+      buffer.write(incError.message);
     }
     fail(buffer.toString());
   }
 }
 
 void _assertEqualErrors(
-    List<AnalysisError> incrErrors, List<AnalysisError> fullErrors) {
-  expect(incrErrors, hasLength(fullErrors.length));
-  if (incrErrors.isNotEmpty) {
-    incrErrors.sort((a, b) => a.offset - b.offset);
+    List<AnalysisError> incErrors, List<AnalysisError> fullErrors) {
+  expect(incErrors, hasLength(fullErrors.length));
+  if (incErrors.isNotEmpty) {
+    incErrors.sort((a, b) => a.offset - b.offset);
   }
   if (fullErrors.isNotEmpty) {
     fullErrors.sort((a, b) => a.offset - b.offset);
   }
-  int length = incrErrors.length;
+  int length = incErrors.length;
   for (int i = 0; i < length; i++) {
-    AnalysisError incrError = incrErrors[i];
+    AnalysisError incError = incErrors[i];
     AnalysisError fullError = fullErrors[i];
-    _assertEqualError(incrError, fullError);
+    _assertEqualError(incError, fullError);
+  }
+}
+
+void _checkCacheEntries(AnalysisCache cache) {
+  Set seen = new Set();
+  MapIterator<AnalysisTarget, CacheEntry> it = cache.iterator();
+  while (it.moveNext()) {
+    AnalysisTarget key = it.key;
+    if (cache.get(key) == null) {
+      fail("cache corrupted: value of $key changed to null");
+    }
+    if (!seen.add(key)) {
+      fail("cache corrupted: $key appears more than once");
+    }
   }
 }
 
@@ -495,6 +515,20 @@
 ''');
   }
 
+  void test_false_constructor_parameters_name() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  A(int a);
+}
+''',
+        r'''
+class A {
+  A(int b);
+}
+''');
+  }
+
   void test_false_constructor_parameters_type_edit() {
     _assertDoesNotMatch(
         r'''
@@ -835,6 +869,22 @@
 ''');
   }
 
+  void test_false_fieldFormalParameter_changeName_wasUnresolvedField() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final fff;
+  A(this.unresolved);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(this.fff);
+}
+''');
+  }
+
   void test_false_fieldFormalParameter_differentField() {
     _assertDoesNotMatch(
         r'''
@@ -2506,22 +2556,6 @@
 ''');
   }
 
-  void test_true_fieldFormalParameter_changeName_wasUnresolvedField() {
-    _assertMatches(
-        r'''
-class A {
-  final fff;
-  A(this.unresolved);
-}
-''',
-        r'''
-class A {
-  final fff;
-  A(this.fff);
-}
-''');
-  }
-
   void test_true_fieldFormalParameter_function() {
     _assertMatches(
         r'''
@@ -3062,7 +3096,7 @@
     // build elements
     {
       ElementHolder holder = new ElementHolder();
-      ElementBuilder builder = new ElementBuilder(holder);
+      ElementBuilder builder = new ElementBuilder(holder, oldUnit.element);
       newUnit.accept(builder);
     }
     // match
@@ -3092,7 +3126,7 @@
   void setUp() {
     super.setUp();
     test_resolveApiChanges = true;
-    log.logger = log.NULL_LOGGER;
+    logging.logger = logging.NULL_LOGGER;
   }
 
   void test_classMemberAccessor_body() {
@@ -3105,6 +3139,21 @@
     _resolve(_editString('+', '*'), _isFunctionBody);
   }
 
+  void test_computeConstants_offsetChanged() {
+    _resolveUnit(r'''
+int f() => 0;
+main() {
+  const x1 = f();
+  const x2 = f();
+  const x3 = f();
+  const x4 = f();
+  const x5 = f();
+  print(x1 + x2 + x3 + x4 + x5 + 1);
+}
+''');
+    _resolve(_editString('x1', ' x1'), _isFunctionBody);
+  }
+
   void test_constructor_body() {
     _resolveUnit(r'''
 class A {
@@ -3170,15 +3219,6 @@
     _resolve(_editString('+', '*'), _isExpression);
   }
 
-  void test_fieldFormalParameter() {
-    _resolveUnit(r'''
-class A {
-  int xy;
-  A(this.x);
-}''');
-    _resolve(_editString('this.x', 'this.xy'), _isDeclaration);
-  }
-
   void test_function_localFunction_add() {
     _resolveUnit(r'''
 int main() {
@@ -3419,6 +3459,9 @@
         edit.replacement +
         code.substring(offset + edit.length);
     CompilationUnit newUnit = _parseUnit(newCode);
+    AnalysisCache cache = analysisContext2.analysisCache;
+    _checkCacheEntries(cache);
+
     // replace the node
     AstNode oldNode = _findNodeAt(unit, offset, predicate);
     AstNode newNode = _findNodeAt(newUnit, offset, predicate);
@@ -3430,6 +3473,10 @@
     {
       int delta = edit.replacement.length - edit.length;
       _shiftTokens(unit.beginToken, offset, delta);
+      Token oldBeginToken = oldNode.beginToken;
+      Token oldEndTokenNext = oldNode.endToken.next;
+      oldBeginToken.previous.setNext(newNode.beginToken);
+      newNode.endToken.setNext(oldEndTokenNext);
     }
     // do incremental resolution
     int updateOffset = edit.offset;
@@ -3437,11 +3484,12 @@
     int updateOldNew = updateOffset + edit.replacement.length;
     IncrementalResolver resolver;
     LibrarySpecificUnit lsu = new LibrarySpecificUnit(source, source);
-    AnalysisCache cache = analysisContext2.analysisCache;
-    resolver = new IncrementalResolver(cache.get(source), cache.get(lsu),
+    resolver = new IncrementalResolver(cache, cache.get(source), cache.get(lsu),
         unit.element, updateOffset, updateEndOld, updateOldNew);
     bool success = resolver.resolve(newNode);
     expect(success, isTrue);
+    _checkCacheEntries(cache);
+
     List<AnalysisError> newErrors = analysisContext.computeErrors(source);
     // resolve "newCode" from scratch
     CompilationUnit fullNewUnit;
@@ -3451,11 +3499,9 @@
       LibraryElement library = resolve2(source);
       fullNewUnit = resolveCompilationUnit(source, library);
     }
-    try {
-      assertSameResolution(unit, fullNewUnit);
-    } on IncrementalResolutionMismatch catch (mismatch) {
-      fail(mismatch.message);
-    }
+    _checkCacheEntries(cache);
+
+    assertSameResolution(unit, fullNewUnit);
     // errors
     List<AnalysisError> newFullErrors =
         analysisContext.getErrors(source).errors;
@@ -3470,6 +3516,7 @@
     library = resolve2(source);
     unit = resolveCompilationUnit(source, library);
     _runTasks();
+    _checkCacheEntries(analysisContext2.analysisCache);
   }
 
   void _runTasks() {
@@ -3523,6 +3570,8 @@
  */
 @reflectiveTest
 class PoorMansIncrementalResolutionTest extends ResolverTestCase {
+  final _TestLogger logger = new _TestLogger();
+
   Source source;
   String code;
   LibraryElement oldLibrary;
@@ -3560,13 +3609,15 @@
   print(x + 1);
 }
 ''');
-    _updateAndValidate(r'''
+    _updateAndValidate(
+        r'''
 int f() => 0;
 main() {
   const x = f();
   print(x + 2);
 }
-''');
+''',
+        expectCachePostConstantsValid: false);
   }
 
   void test_dartDoc_beforeField() {
@@ -3800,23 +3851,6 @@
 ''');
   }
 
-  void test_endOfLineComment_localFunction_inTopLevelVariable() {
-    _resolveUnit(r'''
-typedef int Binary(one, two, three);
-
-int Global = f((a, b, c) {
-  return 0; // Some comment
-});
-''');
-    _updateAndValidate(r'''
-typedef int Binary(one, two, three);
-
-int Global = f((a, b, c) {
-  return 0; // Some  comment
-});
-''');
-  }
-
   void test_endOfLineComment_outBody_add() {
     _resolveUnit(r'''
 main() {
@@ -3886,6 +3920,25 @@
 ''');
   }
 
+  void test_endOfLineComment_toDartDoc() {
+    _resolveUnit(r'''
+class A {
+  // text
+  main() {
+    print(42);
+  }
+}''');
+    _updateAndValidate(
+        r'''
+class A {
+  /// text
+  main() {
+    print(42);
+  }
+}''',
+        expectedSuccess: false);
+  }
+
   void test_false_constConstructor_initializer() {
     _resolveUnit(r'''
 class C {
@@ -3911,6 +3964,74 @@
         expectedSuccess: false);
   }
 
+  void test_false_constructor_initializer_damage() {
+    _resolveUnit(r'''
+class Problem {
+  final Map location;
+  final String message;
+
+  Problem(Map json)
+      : location = json["location"],
+        message = json["message"];
+}''');
+    _updateAndValidate(
+        r'''
+class Problem {
+  final Map location;
+  final String message;
+
+  Problem(Map json)
+      : location = json["location],
+        message = json["message"];
+}''',
+        expectedSuccess: false);
+  }
+
+  void test_false_constructor_initializer_remove() {
+    _resolveUnit(r'''
+class Problem {
+  final String severity;
+  final Map location;
+  final String message;
+
+  Problem(Map json)
+      : severity = json["severity"],
+        location = json["location"],
+        message = json["message"];
+}''');
+    _updateAndValidate(
+        r'''
+class Problem {
+  final String severity;
+  final Map location;
+  final String message;
+
+  Problem(Map json)
+      : severity = json["severity"],
+        message = json["message"];
+}''',
+        expectedSuccess: false);
+  }
+
+  void test_false_endOfLineComment_localFunction_inTopLevelVariable() {
+    _resolveUnit(r'''
+typedef int Binary(one, two, three);
+
+int Global = f((a, b, c) {
+  return 0; // Some comment
+});
+''');
+    _updateAndValidate(
+        r'''
+typedef int Binary(one, two, three);
+
+int Global = f((a, b, c) {
+  return 0; // Some  comment
+});
+''',
+        expectedSuccess: false);
+  }
+
   void test_false_expressionBody() {
     _resolveUnit(r'''
 class A {
@@ -3926,6 +4047,44 @@
         expectedSuccess: false);
   }
 
+  void test_false_expressionBody2() {
+    _resolveUnit(r'''
+class A {
+  int m() => 10 * 10;
+}
+''');
+    _updateAndValidate(
+        r'''
+class A {
+  int m() => 10 * 100;
+}
+''',
+        expectedSuccess: false);
+  }
+
+  void test_false_inBody_functionExpression() {
+    _resolveUnit(r'''
+class C extends D {
+  static final f = () {
+    var x = 0;
+  }();
+}
+
+class D {}
+''');
+    _updateAndValidate(
+        r'''
+class C extends D {
+  static final f = () {
+    var x = 01;
+  }();
+}
+
+class D {}
+''',
+        expectedSuccess: false);
+  }
+
   void test_false_topLevelFunction_name() {
     _resolveUnit(r'''
 a() {}
@@ -3995,6 +4154,25 @@
         expectedSuccess: false);
   }
 
+  void test_false_wholeConstructor() {
+    _resolveUnit(r'''
+class A {
+  A(int a) {
+    print(a);
+  }
+}
+''');
+    _updateAndValidate(
+        r'''
+class A {
+  A(int b) {
+    print(b);
+  }
+}
+''',
+        expectedSuccess: false);
+  }
+
   void test_fieldClassField_propagatedType() {
     _resolveUnit(r'''
 class A {
@@ -4028,6 +4206,21 @@
 ''');
   }
 
+  void test_hasElementAfter_defaultParameter() {
+    _resolveUnit(r'''
+main() {
+  print(1);
+}
+otherFunction([p = 0]) {}
+''');
+    _updateAndValidate(r'''
+main() {
+  print(2);
+}
+otherFunction([p = 0]) {}
+''');
+  }
+
   void test_inBody_expression() {
     _resolveUnit(r'''
 class A {
@@ -4045,27 +4238,6 @@
 ''');
   }
 
-  void test_inBody_functionExpression() {
-    _resolveUnit(r'''
-class C extends D {
-  static final f = () {
-    var x = 0;
-  }();
-}
-
-class D {}
-''');
-    _updateAndValidate(r'''
-class C extends D {
-  static final f = () {
-    var x = 01;
-  }();
-}
-
-class D {}
-''');
-  }
-
   void test_inBody_insertStatement() {
     _resolveUnit(r'''
 main() {
@@ -4238,23 +4410,6 @@
     _assertEqualErrors(newErrors, oldErrors);
   }
 
-  void test_true_wholeConstructor() {
-    _resolveUnit(r'''
-class A {
-  A(int a) {
-    print(a);
-  }
-}
-''');
-    _updateAndValidate(r'''
-class A {
-  A(int b) {
-    print(b);
-  }
-}
-''');
-  }
-
   void test_true_wholeConstructor_addInitializer() {
     _resolveUnit(r'''
 class A {
@@ -4404,6 +4559,21 @@
     expect(errors, isEmpty);
   }
 
+  void test_updateConstantInitializer() {
+    _resolveUnit(r'''
+main() {
+  const v = const [Unknown];
+}
+''');
+    _updateAndValidate(
+        r'''
+main() {
+   const v = const [Unknown];
+}
+''',
+        expectCachePostConstantsValid: false);
+  }
+
   void test_updateErrors_addNew_hint1() {
     _resolveUnit(r'''
 int main() {
@@ -4675,14 +4845,98 @@
     }
   }
 
-  void _assertEqualLineInfo(LineInfo incrLineInfo, LineInfo fullLineInfo) {
+  void test_updateFunctionToForLoop() {
+    _resolveUnit(r'''
+class PlayDrag {
+  final List<num> times = new List<num>();
+
+  PlayDrag.start() {}
+
+  void update(num pos) {
+    fo (int i = times.length - 2; i >= 0; i--) {}
+  }
+}
+''');
+
+    _updateAndValidate(
+        r'''
+class PlayDrag {
+  final List<num> times = new List<num>();
+
+  PlayDrag.start() {}
+
+  void update(num pos) {
+    for (int i = times.length - 2; i >= 0; i--) {}
+  }
+}
+''',
+        expectLibraryUnchanged: false);
+  }
+
+  void _assertCacheResults(
+      {bool expectLibraryUnchanged: true,
+      bool expectCachePostConstantsValid: true}) {
+    _assertCacheSourceResult(TOKEN_STREAM);
+    _assertCacheSourceResult(SCAN_ERRORS);
+    _assertCacheSourceResult(PARSED_UNIT);
+    _assertCacheSourceResult(PARSE_ERRORS);
+    if (!expectLibraryUnchanged) {
+      return;
+    }
+    _assertCacheSourceResult(LIBRARY_ELEMENT1);
+    _assertCacheSourceResult(LIBRARY_ELEMENT2);
+    _assertCacheSourceResult(LIBRARY_ELEMENT3);
+    _assertCacheSourceResult(LIBRARY_ELEMENT4);
+    _assertCacheSourceResult(LIBRARY_ELEMENT5);
+    _assertCacheSourceResult(LIBRARY_ELEMENT6);
+    _assertCacheSourceResult(LIBRARY_ELEMENT7);
+    _assertCacheSourceResult(LIBRARY_ELEMENT8);
+    if (expectCachePostConstantsValid) {
+      _assertCacheSourceResult(LIBRARY_ELEMENT);
+    }
+    _assertCacheUnitResult(RESOLVED_UNIT1);
+    _assertCacheUnitResult(RESOLVED_UNIT2);
+    _assertCacheUnitResult(RESOLVED_UNIT3);
+    _assertCacheUnitResult(RESOLVED_UNIT4);
+    _assertCacheUnitResult(RESOLVED_UNIT5);
+    _assertCacheUnitResult(RESOLVED_UNIT6);
+    _assertCacheUnitResult(RESOLVED_UNIT7);
+    _assertCacheUnitResult(RESOLVED_UNIT8);
+    _assertCacheUnitResult(RESOLVED_UNIT9);
+    _assertCacheUnitResult(RESOLVED_UNIT10);
+    if (expectCachePostConstantsValid) {
+      _assertCacheUnitResult(RESOLVED_UNIT11);
+      _assertCacheUnitResult(RESOLVED_UNIT);
+    }
+  }
+
+  /**
+   * Assert that the [result] of [source] is not INVALID.
+   */
+  void _assertCacheSourceResult(ResultDescriptor result) {
+    AnalysisCache cache = analysisContext2.analysisCache;
+    CacheState state = cache.getState(source, result);
+    expect(state, isNot(CacheState.INVALID), reason: result.toString());
+  }
+
+  /**
+   * Assert that the [result] of the defining unit [source] is not INVALID.
+   */
+  void _assertCacheUnitResult(ResultDescriptor result) {
+    AnalysisCache cache = analysisContext2.analysisCache;
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    CacheState state = cache.getState(target, result);
+    expect(state, isNot(CacheState.INVALID), reason: result.toString());
+  }
+
+  void _assertEqualLineInfo(LineInfo incLineInfo, LineInfo fullLineInfo) {
     for (int offset = 0; offset < 1000; offset++) {
-      LineInfo_Location incrLocation = incrLineInfo.getLocation(offset);
+      LineInfo_Location incLocation = incLineInfo.getLocation(offset);
       LineInfo_Location fullLocation = fullLineInfo.getLocation(offset);
-      if (incrLocation.lineNumber != fullLocation.lineNumber ||
-          incrLocation.columnNumber != fullLocation.columnNumber) {
+      if (incLocation.lineNumber != fullLocation.lineNumber ||
+          incLocation.columnNumber != fullLocation.columnNumber) {
         fail('At offset $offset ' +
-            '(${incrLocation.lineNumber}, ${incrLocation.columnNumber})' +
+            '(${incLocation.lineNumber}, ${incLocation.columnNumber})' +
             ' != ' +
             '(${fullLocation.lineNumber}, ${fullLocation.columnNumber})');
       }
@@ -4697,8 +4951,7 @@
     AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl();
     analysisOptions.incremental = enable;
     analysisOptions.incrementalApi = enable;
-//    log.logger = log.PRINT_LOGGER;
-    log.logger = log.NULL_LOGGER;
+    logging.logger = logger;
     analysisContext2.analysisOptions = analysisOptions;
   }
 
@@ -4719,6 +4972,8 @@
 
   void _updateAndValidate(String newCode,
       {bool expectedSuccess: true,
+      bool expectLibraryUnchanged: true,
+      bool expectCachePostConstantsValid: true,
       bool compareWithFull: true,
       bool runTasksBeforeIncremental: true}) {
     // Run any pending tasks tasks.
@@ -4730,6 +4985,7 @@
     _resetWithIncremental(true);
     analysisContext2.setContents(source, newCode);
     CompilationUnit newUnit = resolveCompilationUnit(source, oldLibrary);
+    logger.expectNoErrors();
     List<AnalysisError> newErrors = analysisContext.computeErrors(source);
     LineInfo newLineInfo = analysisContext.getLineInfo(source);
     // check for expected failure
@@ -4737,6 +4993,11 @@
       expect(newUnit.element, isNot(same(oldUnitElement)));
       return;
     }
+    // The cache must still have enough results to make the incremental
+    // resolution useful.
+    _assertCacheResults(
+        expectLibraryUnchanged: expectLibraryUnchanged,
+        expectCachePostConstantsValid: expectCachePostConstantsValid);
     // The existing CompilationUnit[Element] should be updated.
     expect(newUnit, same(oldUnit));
     expect(newUnit.element, same(oldUnitElement));
@@ -4769,39 +5030,40 @@
           analysisContext.getErrors(source).errors;
       _assertEqualErrors(newErrors, newFullErrors);
     }
+    _checkCacheEntries(analysisContext2.analysisCache);
   }
 
-  static void _assertEqualToken(Token incrToken, Token fullToken) {
-//    print('[${incrToken.offset}] |$incrToken| vs. [${fullToken.offset}] |$fullToken|');
-    expect(incrToken.type, fullToken.type);
-    expect(incrToken.offset, fullToken.offset);
-    expect(incrToken.length, fullToken.length);
-    expect(incrToken.lexeme, fullToken.lexeme);
+  static void _assertEqualToken(Token incToken, Token fullToken) {
+//    print('[${incToken.offset}] |$incToken| vs. [${fullToken.offset}] |$fullToken|');
+    expect(incToken.type, fullToken.type);
+    expect(incToken.offset, fullToken.offset);
+    expect(incToken.length, fullToken.length);
+    expect(incToken.lexeme, fullToken.lexeme);
   }
 
   static void _assertEqualTokens(
-      CompilationUnit incrUnit, CompilationUnit fullUnit) {
-    Token incrToken = incrUnit.beginToken;
+      CompilationUnit incUnit, CompilationUnit fullUnit) {
+    Token incToken = incUnit.beginToken;
     Token fullToken = fullUnit.beginToken;
-    while (incrToken.type != TokenType.EOF && fullToken.type != TokenType.EOF) {
-      _assertEqualToken(incrToken, fullToken);
+    while (incToken.type != TokenType.EOF && fullToken.type != TokenType.EOF) {
+      _assertEqualToken(incToken, fullToken);
       // comments
       {
-        Token incrComment = incrToken.precedingComments;
+        Token incComment = incToken.precedingComments;
         Token fullComment = fullToken.precedingComments;
         while (true) {
           if (fullComment == null) {
-            expect(incrComment, isNull);
+            expect(incComment, isNull);
             break;
           }
-          expect(incrComment, isNotNull);
-          _assertEqualToken(incrComment, fullComment);
-          incrComment = incrComment.next;
+          expect(incComment, isNotNull);
+          _assertEqualToken(incComment, fullComment);
+          incComment = incComment.next;
           fullComment = fullComment.next;
         }
       }
       // next tokens
-      incrToken = incrToken.next;
+      incToken = incToken.next;
       fullToken = fullToken.next;
     }
   }
@@ -5022,3 +5284,34 @@
   final String replacement;
   _Edit(this.offset, this.length, this.replacement);
 }
+
+class _TestLogger implements logging.Logger {
+  Object lastException;
+  Object lastStackTrace;
+
+  void expectNoErrors() {
+    if (lastException != null) {
+      fail("logged an exception:\n$lastException\n$lastStackTrace\n");
+    }
+  }
+
+  @override
+  void enter(String name) {}
+
+  @override
+  void exit() {}
+
+  @override
+  void log(Object obj) {}
+
+  @override
+  void logException(Object exception, [Object stackTrace]) {
+    lastException = exception;
+    lastStackTrace = stackTrace;
+  }
+
+  @override
+  logging.LoggingTimer startTimer() {
+    return new logging.LoggingTimer(this);
+  }
+}
diff --git a/pkg/analyzer/test/generated/incremental_scanner_test.dart b/pkg/analyzer/test/generated/incremental_scanner_test.dart
index fad6244..2c21e61 100644
--- a/pkg/analyzer/test/generated/incremental_scanner_test.dart
+++ b/pkg/analyzer/test/generated/incremental_scanner_test.dart
@@ -4,9 +4,11 @@
 
 library analyzer.test.generated.incremental_scanner_test;
 
+import 'package:analyzer/dart/ast/token.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/incremental_scanner.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analyzer/test/generated/java_core_test.dart b/pkg/analyzer/test/generated/java_core_test.dart
index 0a914ec..f98895e 100644
--- a/pkg/analyzer/test/generated/java_core_test.dart
+++ b/pkg/analyzer/test/generated/java_core_test.dart
@@ -12,30 +12,6 @@
 main() {
   initializeTestEnvironment();
   group('Character', () {
-    group('isDigit', () {
-      test('digits', () {
-        expect(Character.isDigit('0'.codeUnitAt(0)), isTrue);
-        expect(Character.isDigit('1'.codeUnitAt(0)), isTrue);
-        expect(Character.isDigit('9'.codeUnitAt(0)), isTrue);
-      });
-
-      test('letters', () {
-        expect(Character.isDigit('a'.codeUnitAt(0)), isFalse);
-        expect(Character.isDigit('b'.codeUnitAt(0)), isFalse);
-        expect(Character.isDigit('z'.codeUnitAt(0)), isFalse);
-        expect(Character.isDigit('C'.codeUnitAt(0)), isFalse);
-        expect(Character.isDigit('D'.codeUnitAt(0)), isFalse);
-        expect(Character.isDigit('Y'.codeUnitAt(0)), isFalse);
-      });
-
-      test('other', () {
-        expect(Character.isDigit(' '.codeUnitAt(0)), isFalse);
-        expect(Character.isDigit('.'.codeUnitAt(0)), isFalse);
-        expect(Character.isDigit('-'.codeUnitAt(0)), isFalse);
-        expect(Character.isDigit('+'.codeUnitAt(0)), isFalse);
-      });
-    });
-
     group('isLetter', () {
       test('digits', () {
         expect(Character.isLetter('0'.codeUnitAt(0)), isFalse);
@@ -83,73 +59,5 @@
         expect(Character.isLetterOrDigit('+'.codeUnitAt(0)), isFalse);
       });
     });
-
-    group('isLowerCase', () {
-      test('ASCII digits', () {
-        expect(Character.isLowerCase('0'.codeUnitAt(0)), isFalse);
-        expect(Character.isLowerCase('9'.codeUnitAt(0)), isFalse);
-      });
-
-      test('ASCII lower', () {
-        expect(Character.isLowerCase('a'.codeUnitAt(0)), isTrue);
-        expect(Character.isLowerCase('s'.codeUnitAt(0)), isTrue);
-        expect(Character.isLowerCase('z'.codeUnitAt(0)), isTrue);
-      });
-
-      test('ASCII upper', () {
-        expect(Character.isLowerCase('A'.codeUnitAt(0)), isFalse);
-        expect(Character.isLowerCase('S'.codeUnitAt(0)), isFalse);
-        expect(Character.isLowerCase('Z'.codeUnitAt(0)), isFalse);
-      });
-    });
-
-    group('isUpperCase', () {
-      test('ASCII digits', () {
-        expect(Character.isUpperCase('0'.codeUnitAt(0)), isFalse);
-        expect(Character.isUpperCase('9'.codeUnitAt(0)), isFalse);
-      });
-
-      test('ASCII lower', () {
-        expect(Character.isUpperCase('a'.codeUnitAt(0)), isFalse);
-        expect(Character.isUpperCase('s'.codeUnitAt(0)), isFalse);
-        expect(Character.isUpperCase('z'.codeUnitAt(0)), isFalse);
-      });
-
-      test('ASCII upper', () {
-        expect(Character.isUpperCase('A'.codeUnitAt(0)), isTrue);
-        expect(Character.isUpperCase('S'.codeUnitAt(0)), isTrue);
-        expect(Character.isUpperCase('Z'.codeUnitAt(0)), isTrue);
-      });
-    });
-
-    test('toLowerCase', () {
-      expect(Character.toLowerCase('A'.codeUnitAt(0)), 'a'.codeUnitAt(0));
-      expect(Character.toLowerCase('B'.codeUnitAt(0)), 'b'.codeUnitAt(0));
-      expect(Character.toLowerCase('Z'.codeUnitAt(0)), 'z'.codeUnitAt(0));
-      expect(Character.toLowerCase('c'.codeUnitAt(0)), 'c'.codeUnitAt(0));
-      expect(Character.toLowerCase('0'.codeUnitAt(0)), '0'.codeUnitAt(0));
-    });
-
-    test('toUpperCase', () {
-      expect(Character.toUpperCase('a'.codeUnitAt(0)), 'A'.codeUnitAt(0));
-      expect(Character.toUpperCase('b'.codeUnitAt(0)), 'B'.codeUnitAt(0));
-      expect(Character.toUpperCase('z'.codeUnitAt(0)), 'Z'.codeUnitAt(0));
-      expect(Character.toUpperCase('C'.codeUnitAt(0)), 'C'.codeUnitAt(0));
-      expect(Character.toUpperCase('0'.codeUnitAt(0)), '0'.codeUnitAt(0));
-    });
-
-    test('isWhitespace', () {
-      expect(Character.isWhitespace('\t'.codeUnitAt(0)), isTrue);
-      expect(Character.isWhitespace(' '.codeUnitAt(0)), isTrue);
-      expect(Character.isWhitespace('\n'.codeUnitAt(0)), isTrue);
-      expect(Character.isWhitespace('\r'.codeUnitAt(0)), isTrue);
-      expect(Character.isWhitespace('.'.codeUnitAt(0)), isFalse);
-      expect(Character.isWhitespace('0'.codeUnitAt(0)), isFalse);
-      expect(Character.isWhitespace('9'.codeUnitAt(0)), isFalse);
-      expect(Character.isWhitespace('a'.codeUnitAt(0)), isFalse);
-      expect(Character.isWhitespace('z'.codeUnitAt(0)), isFalse);
-      expect(Character.isWhitespace('A'.codeUnitAt(0)), isFalse);
-      expect(Character.isWhitespace('Z'.codeUnitAt(0)), isFalse);
-    });
   });
 }
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 6792467..de21885 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -4,8 +4,8 @@
 
 library analyzer.test.generated.non_error_resolver_test;
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
@@ -35,24 +35,6 @@
     verify([source]);
   }
 
-  void test_class_type_alias_documentationComment() {
-    Source source = addSource('''
-/**
- * Documentation
- */
-class C = D with E;
-
-class D {}
-class E {}''');
-    computeLibrarySourceErrors(source);
-    computeLibrarySourceErrors(source);
-    assertNoErrors(source);
-    verify([source]);
-    CompilationUnit unit = _getResolvedLibraryUnit(source);
-    ClassElement classC = unit.element.getType('C');
-    expect(classC.documentationComment, isNotNull);
-  }
-
   void test_ambiguousExport() {
     Source source = addSource(r'''
 library L;
@@ -188,6 +170,14 @@
     assertNoErrors(source);
   }
 
+  void test_annotated_partOfDeclaration() {
+    Source source = addSource('library L; part "part.dart";');
+    addNamedSource('/part.dart', '@deprecated part of L;');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_argumentTypeNotAssignable_classWithCall_Function() {
     Source source = addSource(r'''
   caller(Function callee) {
@@ -932,6 +922,24 @@
     verify([source]);
   }
 
+  void test_class_type_alias_documentationComment() {
+    Source source = addSource('''
+/**
+ * Documentation
+ */
+class C = D with E;
+
+class D {}
+class E {}''');
+    computeLibrarySourceErrors(source);
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+    CompilationUnit unit = _getResolvedLibraryUnit(source);
+    ClassElement classC = unit.element.getType('C');
+    expect(classC.documentationComment, isNotNull);
+  }
+
   void test_commentReference_beforeConstructor() {
     String code = r'''
 abstract class A {
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 5d304c7..19a2a89 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4,15 +4,20 @@
 
 library analyzer.test.generated.parser_test;
 
+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/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.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/incremental_scanner.dart';
 import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart' show Source;
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
@@ -503,6 +508,16 @@
         BinaryExpression, expression.leftOperand);
   }
 
+  void test_topLevelFunction_nestedGenericFunction() {
+    enableGenericMethods = true;
+    parseCompilationUnitWithOptions('''
+void f() {
+  void g<T>() {
+  }
+}
+''');
+  }
+
   void _validate_assignableExpression_arguments_normal_chain_typeArguments(
       String code) {
     PropertyAccess propertyAccess1 = parseExpression(code);
@@ -937,21 +952,42 @@
         [ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT]);
   }
 
+  void test_emptyEnumBody() {
+    parse3("parseEnumDeclaration", <Object>[emptyCommentAndMetadata()],
+        "enum E {}", [ParserErrorCode.EMPTY_ENUM_BODY]);
+  }
+
   void test_enableAsync_false_1() {
     parseAsync = false;
-    parse4("parseFunctionDeclarationStatement",
-        "foo() async {}", [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+    FunctionDeclarationStatement stmt = parse4(
+        "parseFunctionDeclarationStatement",
+        "foo() async {}",
+        [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+    FunctionExpression expr = stmt.functionDeclaration.functionExpression;
+    expect(expr.body.isAsynchronous, isTrue);
+    expect(expr.body.isGenerator, isFalse);
   }
 
   void test_enableAsync_false_2() {
     parseAsync = false;
-    parse4("parseFunctionDeclarationStatement",
-        "foo() sync* {}", [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+    FunctionDeclarationStatement stmt = parse4(
+        "parseFunctionDeclarationStatement",
+        "foo() async => 0;",
+        [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+    FunctionExpression expr = stmt.functionDeclaration.functionExpression;
+    expect(expr.body.isAsynchronous, isTrue);
+    expect(expr.body.isGenerator, isFalse);
   }
 
-  void test_emptyEnumBody() {
-    parse3("parseEnumDeclaration", <Object>[emptyCommentAndMetadata()],
-        "enum E {}", [ParserErrorCode.EMPTY_ENUM_BODY]);
+  void test_enableAsync_false_3() {
+    parseAsync = false;
+    FunctionDeclarationStatement stmt = parse4(
+        "parseFunctionDeclarationStatement",
+        "foo() sync* {}",
+        [ParserErrorCode.ASYNC_NOT_SUPPORTED]);
+    FunctionExpression expr = stmt.functionDeclaration.functionExpression;
+    expect(expr.body.isAsynchronous, isFalse);
+    expect(expr.body.isGenerator, isTrue);
   }
 
   void test_enumInClass() {
@@ -1474,6 +1510,49 @@
         reason: 'parser recovers what it can');
   }
 
+  void test_method_invalidTypeParameterExtends() {
+    // Regression test for https://github.com/dart-lang/sdk/issues/25739.
+
+    // TODO(jmesserly): ideally we'd be better at parser recovery here.
+    enableGenericMethods = true;
+    MethodDeclaration method = parse3(
+        "parseClassMember",
+        <Object>["C"],
+        "f<E>(E extends num p);",
+        [
+          ParserErrorCode.MISSING_IDENTIFIER, // `extends` is a keyword
+          ParserErrorCode.EXPECTED_TOKEN, // comma
+          ParserErrorCode.EXPECTED_TOKEN, // close paren
+          ParserErrorCode.MISSING_FUNCTION_BODY
+        ]);
+    expect(method.parameters.toString(), '(E, extends)',
+        reason: 'parser recovers what it can');
+  }
+
+  void test_method_invalidTypeParameterExtendsComment() {
+    // Regression test for https://github.com/dart-lang/sdk/issues/25739.
+
+    // TODO(jmesserly): ideally we'd be better at parser recovery here.
+    // Also, this behavior is slightly different from how we would parse a
+    // normal generic method, because we "discover" the comment at a different
+    // point in the parser. This has a slight effect on the AST that results
+    // from error recovery.
+    enableGenericMethodComments = true;
+    MethodDeclaration method = parse3(
+        "parseClassMember",
+        <Object>["C"],
+        "f/*<E>*/(dynamic/*=E extends num*/p);",
+        [
+          ParserErrorCode.MISSING_IDENTIFIER, // `extends` is a keyword
+          ParserErrorCode.EXPECTED_TOKEN, // comma
+          ParserErrorCode.MISSING_IDENTIFIER, // `extends` is a keyword
+          ParserErrorCode.EXPECTED_TOKEN, // close paren
+          ParserErrorCode.MISSING_FUNCTION_BODY
+        ]);
+    expect(method.parameters.toString(), '(E extends, extends)',
+        reason: 'parser recovers what it can');
+  }
+
   void test_method_invalidTypeParameters() {
     // TODO(jmesserly): ideally we'd be better at parser recovery here.
     // It doesn't try to advance past the invalid token `!` to find the
@@ -1868,6 +1947,16 @@
         [ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP]);
   }
 
+  void test_redirectingConstructorWithBody_named() {
+    parse3("parseClassMember", <Object>["C"], "C.x() : this() {}",
+        [ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY]);
+  }
+
+  void test_redirectingConstructorWithBody_unnamed() {
+    parse3("parseClassMember", <Object>["C"], "C() : this.x() {}",
+        [ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY]);
+  }
+
   void test_redirectionInNonFactoryConstructor() {
     parse3("parseClassMember", <Object>["C"], "C() = D;",
         [ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR]);
@@ -2848,6 +2937,30 @@
       parse3(methodName, _EMPTY_ARGUMENTS, source, errorCodes);
 
   /**
+   * Parse the given [source] as a compilation unit. Throw an exception if the
+   * source could not be parsed, if the compilation errors in the source do not
+   * match those that are expected, or if the result would have been `null`.
+   */
+  CompilationUnit parseCompilationUnitWithOptions(String source,
+      [List<ErrorCode> errorCodes = ErrorCode.EMPTY_LIST]) {
+    GatheringErrorListener listener = new GatheringErrorListener();
+    Scanner scanner =
+        new Scanner(null, new CharSequenceReader(source), listener);
+    listener.setLineInfo(new TestSource(), scanner.lineStarts);
+    Token token = scanner.tokenize();
+    Parser parser = createParser(listener);
+    parser.parseAsync = parseAsync;
+    parser.parseFunctionBodies = parseFunctionBodies;
+    parser.parseConditionalDirectives = enableConditionalDirectives;
+    parser.parseGenericMethods = enableGenericMethods;
+    parser.parseGenericMethodComments = enableGenericMethodComments;
+    CompilationUnit unit = parser.parseCompilationUnit(token);
+    expect(unit, isNotNull);
+    listener.assertErrorsWithCodes(errorCodes);
+    return unit;
+  }
+
+  /**
    * Parse the given source as an expression.
    *
    * @param source the source to be parsed
@@ -3687,6 +3800,55 @@
     expect(statement.toSource(), 'List<String> v;');
   }
 
+  void test_incompleteTypeArguments_field() {
+    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+        r'''
+class C {
+  final List<int f;
+}''',
+        [ParserErrorCode.EXPECTED_TOKEN]);
+    // one class
+    List<CompilationUnitMember> declarations = unit.declarations;
+    expect(declarations, hasLength(1));
+    ClassDeclaration classDecl = declarations[0] as ClassDeclaration;
+    // one field declaration
+    List<ClassMember> members = classDecl.members;
+    expect(members, hasLength(1));
+    FieldDeclaration fieldDecl = members[0] as FieldDeclaration;
+    // one field
+    VariableDeclarationList fieldList = fieldDecl.fields;
+    List<VariableDeclaration> fields = fieldList.variables;
+    expect(fields, hasLength(1));
+    VariableDeclaration field = fields[0];
+    expect(field.name.name, 'f');
+    // validate the type
+    TypeArgumentList typeArguments = fieldList.type.typeArguments;
+    expect(typeArguments.arguments, hasLength(1));
+    // synthetic '>'
+    Token token = typeArguments.endToken;
+    expect(token.type, TokenType.GT);
+    expect(token.isSynthetic, isTrue);
+  }
+
+  void test_incompleteTypeParameters() {
+    CompilationUnit unit = ParserTestCase.parseCompilationUnit(
+        r'''
+class C<K {
+}''',
+        [ParserErrorCode.EXPECTED_TOKEN]);
+    // one class
+    List<CompilationUnitMember> declarations = unit.declarations;
+    expect(declarations, hasLength(1));
+    ClassDeclaration classDecl = declarations[0] as ClassDeclaration;
+    // validate the type parameters
+    TypeParameterList typeParameters = classDecl.typeParameters;
+    expect(typeParameters.typeParameters, hasLength(1));
+    // synthetic '>'
+    Token token = typeParameters.endToken;
+    expect(token.type, TokenType.GT);
+    expect(token.isSynthetic, isTrue);
+  }
+
   void test_invalidFunctionBodyModifier() {
     ParserTestCase.parseCompilationUnit(
         "f() sync {}", [ParserErrorCode.MISSING_STAR_AFTER_SYNC]);
@@ -3854,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]);
@@ -4060,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 =
@@ -4267,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() {
@@ -4402,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() {
@@ -4686,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));
+  }
 }
 
 /**
@@ -7064,6 +7280,15 @@
     expect(declaration.functionExpression.typeParameters, isNotNull);
   }
 
+  void
+      test_parseCompilationUnitMember_function_generic_noReturnType_annotated() {
+    enableGenericMethods = true;
+    FunctionDeclaration declaration = parse("parseCompilationUnitMember",
+        <Object>[emptyCommentAndMetadata()], "f<@a E>() {}");
+    expect(declaration.returnType, isNull);
+    expect(declaration.functionExpression.typeParameters, isNotNull);
+  }
+
   void test_parseCompilationUnitMember_function_generic_returnType() {
     enableGenericMethods = true;
     FunctionDeclaration declaration = parse("parseCompilationUnitMember",
@@ -7334,6 +7559,16 @@
     expect(literal.rightBracket, isNotNull);
   }
 
+  void test_parseConstExpression_listLiteral_typed_genericComment() {
+    enableGenericMethodComments = true;
+    ListLiteral literal = parse4("parseConstExpression", "const /*<A>*/ []");
+    expect(literal.constKeyword, isNotNull);
+    expect(literal.typeArguments, isNotNull);
+    expect(literal.leftBracket, isNotNull);
+    expect(literal.elements, hasLength(0));
+    expect(literal.rightBracket, isNotNull);
+  }
+
   void test_parseConstExpression_listLiteral_untyped() {
     ListLiteral literal = parse4("parseConstExpression", "const []");
     expect(literal.constKeyword, isNotNull);
@@ -7351,6 +7586,15 @@
     expect(literal.typeArguments, isNotNull);
   }
 
+  void test_parseConstExpression_mapLiteral_typed_genericComment() {
+    enableGenericMethodComments = true;
+    MapLiteral literal = parse4("parseConstExpression", "const /*<A, B>*/ {}");
+    expect(literal.leftBracket, isNotNull);
+    expect(literal.entries, hasLength(0));
+    expect(literal.rightBracket, isNotNull);
+    expect(literal.typeArguments, isNotNull);
+  }
+
   void test_parseConstExpression_mapLiteral_untyped() {
     MapLiteral literal = parse4("parseConstExpression", "const {}");
     expect(literal.leftBracket, isNotNull);
@@ -9856,6 +10100,13 @@
     expect(literal.typeArguments.arguments, hasLength(1));
   }
 
+  void test_parsePrimaryExpression_listLiteral_typed_genericComment() {
+    enableGenericMethodComments = true;
+    ListLiteral literal = parse4("parsePrimaryExpression", "/*<A>*/[ ]");
+    expect(literal.typeArguments, isNotNull);
+    expect(literal.typeArguments.arguments, hasLength(1));
+  }
+
   void test_parsePrimaryExpression_mapLiteral() {
     MapLiteral literal = parse4("parsePrimaryExpression", "{}");
     expect(literal, isNotNull);
@@ -9867,6 +10118,13 @@
     expect(literal.typeArguments.arguments, hasLength(2));
   }
 
+  void test_parsePrimaryExpression_mapLiteral_typed_genericComment() {
+    enableGenericMethodComments = true;
+    MapLiteral literal = parse4("parsePrimaryExpression", "/*<A, B>*/{}");
+    expect(literal.typeArguments, isNotNull);
+    expect(literal.typeArguments.arguments, hasLength(2));
+  }
+
   void test_parsePrimaryExpression_new() {
     InstanceCreationExpression expression =
         parse4("parsePrimaryExpression", "new A()");
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 4722a65..41d96a5 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -6,13 +6,17 @@
 
 import 'dart:collection';
 
+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/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';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element_resolver.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -22,7 +26,6 @@
 import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/sdk_io.dart' show DirectoryBasedDartSdk;
 import 'package:analyzer/src/generated/source_io.dart';
@@ -32,7 +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/task/dart.dart';
+import 'package:analyzer/src/string_source.dart';
 import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
@@ -43,29 +46,30 @@
   initializeTestEnvironment();
   runReflectiveTests(AnalysisDeltaTest);
   runReflectiveTests(ChangeSetTest);
-  runReflectiveTests(EnclosedScopeTest);
-  runReflectiveTests(LibraryImportScopeTest);
-  runReflectiveTests(LibraryScopeTest);
-  runReflectiveTests(ScopeTest);
-  runReflectiveTests(ElementResolverTest);
-  runReflectiveTests(InheritanceManagerTest);
-  runReflectiveTests(StaticTypeAnalyzerTest);
-  runReflectiveTests(StaticTypeAnalyzer2Test);
-  runReflectiveTests(SubtypeManagerTest);
-  runReflectiveTests(TypeOverrideManagerTest);
-  runReflectiveTests(TypeProviderImplTest);
-  runReflectiveTests(TypeResolverVisitorTest);
   runReflectiveTests(CheckedModeCompileTimeErrorCodeTest);
+  runReflectiveTests(DisableAsyncTestCase);
+  runReflectiveTests(ElementResolverTest);
+  runReflectiveTests(EnclosedScopeTest);
   runReflectiveTests(ErrorResolverTest);
   runReflectiveTests(HintCodeTest);
+  runReflectiveTests(InheritanceManagerTest);
+  runReflectiveTests(LibraryImportScopeTest);
+  runReflectiveTests(LibraryScopeTest);
   runReflectiveTests(MemberMapTest);
   runReflectiveTests(NonHintCodeTest);
+  runReflectiveTests(ScopeTest);
   runReflectiveTests(SimpleResolverTest);
+  runReflectiveTests(StaticTypeAnalyzerTest);
+  runReflectiveTests(StaticTypeAnalyzer2Test);
   runReflectiveTests(StrictModeTest);
-  runReflectiveTests(TypePropagationTest);
   runReflectiveTests(StrongModeDownwardsInferenceTest);
   runReflectiveTests(StrongModeStaticTypeAnalyzer2Test);
   runReflectiveTests(StrongModeTypePropagationTest);
+  runReflectiveTests(SubtypeManagerTest);
+  runReflectiveTests(TypeOverrideManagerTest);
+  runReflectiveTests(TypePropagationTest);
+  runReflectiveTests(TypeProviderImplTest);
+  runReflectiveTests(TypeResolverVisitorTest);
 }
 
 /**
@@ -99,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.
    *
@@ -106,13 +116,23 @@
    * @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"));
-    SourceFactory sourceFactory =
-        new SourceFactory([new DartUriResolver(sdk), new FileUriResolver()]);
+        new JavaFile("/fake/sdk"),
+        enableAsync: context.analysisOptions.enableAsync);
+    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 =
+        context.analysisOptions.strongMode;
     //
     // dart:core
     //
@@ -124,8 +144,9 @@
     coreUnit.librarySource = coreUnit.source = coreSource;
     ClassElementImpl proxyClassElement = ElementFactory.classElement2("_Proxy");
     proxyClassElement.constructors = <ConstructorElement>[
-      ElementFactory.constructorElement(proxyClassElement, null, true)
+      ElementFactory.constructorElement(proxyClassElement, '', true)
         ..isCycleFree = true
+        ..constantInitializers = <ConstructorInitializer>[]
     ];
     ClassElement objectClassElement = provider.objectType.element;
     coreUnit.types = <ClassElement>[
@@ -158,11 +179,18 @@
     ConstTopLevelVariableElementImpl deprecatedTopLevelVariableElt =
         ElementFactory.topLevelVariableElement3(
             "deprecated", true, false, provider.deprecatedType);
-    deprecatedTopLevelVariableElt.constantInitializer = AstFactory
-        .instanceCreationExpression2(
-            Keyword.CONST,
-            AstFactory.typeName(provider.deprecatedType.element),
-            [AstFactory.string2('next release')]);
+    {
+      ClassElement deprecatedElement = provider.deprecatedType.element;
+      InstanceCreationExpression initializer = AstFactory
+          .instanceCreationExpression2(
+              Keyword.CONST,
+              AstFactory.typeName(deprecatedElement),
+              [AstFactory.string2('next release')]);
+      ConstructorElement constructor = deprecatedElement.constructors.single;
+      initializer.staticElement = constructor;
+      initializer.constructorName.staticElement = constructor;
+      deprecatedTopLevelVariableElt.constantInitializer = initializer;
+    }
     coreUnit.accessors = <PropertyAccessorElement>[
       proxyTopLevelVariableElt.getter,
       deprecatedTopLevelVariableElt.getter
@@ -177,89 +205,99 @@
     //
     // dart:async
     //
-    CompilationUnitElementImpl asyncUnit =
-        new CompilationUnitElementImpl("async.dart");
-    Source asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
-    coreContext.setContents(asyncSource, "");
-    asyncUnit.librarySource = asyncUnit.source = asyncSource;
-    // Future
-    ClassElementImpl futureElement =
-        ElementFactory.classElement2("Future", ["T"]);
-    //   factory Future.value([value])
-    ConstructorElementImpl futureConstructor =
-        ElementFactory.constructorElement2(futureElement, "value");
-    futureConstructor.parameters = <ParameterElement>[
-      ElementFactory.positionalParameter2("value", provider.dynamicType)
-    ];
-    futureConstructor.factory = true;
-    futureElement.constructors = <ConstructorElement>[futureConstructor];
-    //   Future then(onValue(T value), { Function onError });
-    TypeDefiningElement futureThenR = DynamicElementImpl.instance;
-    if (context.analysisOptions.strongMode) {
-      futureThenR = ElementFactory.typeParameterWithType('R');
+    Source asyncSource;
+    LibraryElementImpl asyncLibrary;
+    if (context.analysisOptions.enableAsync) {
+      asyncLibrary = new LibraryElementImpl.forNode(
+          coreContext, AstFactory.libraryIdentifier2(["dart", "async"]));
+      CompilationUnitElementImpl asyncUnit =
+          new CompilationUnitElementImpl("async.dart");
+      asyncSource = sourceFactory.forUri(DartSdk.DART_ASYNC);
+      coreContext.setContents(asyncSource, "");
+      asyncUnit.librarySource = asyncUnit.source = asyncSource;
+      asyncLibrary.definingCompilationUnit = asyncUnit;
+      // Future
+      ClassElementImpl futureElement =
+          ElementFactory.classElement2("Future", ["T"]);
+      futureElement.enclosingElement = asyncUnit;
+      //   factory Future.value([value])
+      ConstructorElementImpl futureConstructor =
+          ElementFactory.constructorElement2(futureElement, "value");
+      futureConstructor.parameters = <ParameterElement>[
+        ElementFactory.positionalParameter2("value", provider.dynamicType)
+      ];
+      futureConstructor.factory = true;
+      futureElement.constructors = <ConstructorElement>[futureConstructor];
+      //   Future then(onValue(T value), { Function onError });
+      TypeDefiningElement futureThenR = DynamicElementImpl.instance;
+      if (context.analysisOptions.strongMode) {
+        futureThenR = ElementFactory.typeParameterWithType('R');
+      }
+      FunctionElementImpl thenOnValue = ElementFactory.functionElement3(
+          'onValue', futureThenR, [futureElement.typeParameters[0]], null);
+      thenOnValue.synthetic = true;
+
+      DartType futureRType = futureElement.type.substitute4([futureThenR.type]);
+      MethodElementImpl thenMethod = ElementFactory
+          .methodElementWithParameters(futureElement, "then", futureRType, [
+        ElementFactory.requiredParameter2("onValue", thenOnValue.type),
+        ElementFactory.namedParameter2("onError", provider.functionType)
+      ]);
+      if (!futureThenR.type.isDynamic) {
+        thenMethod.typeParameters = [futureThenR];
+      }
+      thenOnValue.enclosingElement = thenMethod;
+      thenOnValue.type = new FunctionTypeImpl(thenOnValue);
+      (thenMethod.parameters[0] as ParameterElementImpl).type =
+          thenOnValue.type;
+      thenMethod.type = new FunctionTypeImpl(thenMethod);
+
+      futureElement.methods = <MethodElement>[thenMethod];
+      // Completer
+      ClassElementImpl completerElement =
+          ElementFactory.classElement2("Completer", ["T"]);
+      ConstructorElementImpl completerConstructor =
+          ElementFactory.constructorElement2(completerElement, null);
+      completerElement.constructors = <ConstructorElement>[
+        completerConstructor
+      ];
+      // StreamSubscription
+      ClassElementImpl streamSubscriptionElement =
+          ElementFactory.classElement2("StreamSubscription", ["T"]);
+      // Stream
+      ClassElementImpl streamElement =
+          ElementFactory.classElement2("Stream", ["T"]);
+      streamElement.constructors = <ConstructorElement>[
+        ElementFactory.constructorElement2(streamElement, null)
+      ];
+      DartType returnType = streamSubscriptionElement.type
+          .substitute4(streamElement.type.typeArguments);
+      FunctionElementImpl listenOnData = ElementFactory.functionElement3(
+          'onData',
+          VoidTypeImpl.instance.element,
+          <TypeDefiningElement>[streamElement.typeParameters[0]],
+          null);
+      listenOnData.synthetic = true;
+      List<DartType> parameterTypes = <DartType>[listenOnData.type,];
+      // TODO(brianwilkerson) This is missing the optional parameters.
+      MethodElementImpl listenMethod =
+          ElementFactory.methodElement('listen', returnType, parameterTypes);
+      streamElement.methods = <MethodElement>[listenMethod];
+      listenMethod.type = new FunctionTypeImpl(listenMethod);
+
+      FunctionElementImpl listenParamFunction = parameterTypes[0].element;
+      listenParamFunction.enclosingElement = listenMethod;
+      listenParamFunction.type = new FunctionTypeImpl(listenParamFunction);
+      ParameterElementImpl listenParam = listenMethod.parameters[0];
+      listenParam.type = listenParamFunction.type;
+
+      asyncUnit.types = <ClassElement>[
+        completerElement,
+        futureElement,
+        streamElement,
+        streamSubscriptionElement
+      ];
     }
-    FunctionElementImpl thenOnValue = ElementFactory.functionElement3(
-        'onValue', futureThenR, [futureElement.typeParameters[0]], null);
-
-    DartType futureRType = futureElement.type.substitute4([futureThenR.type]);
-    MethodElementImpl thenMethod = ElementFactory
-        .methodElementWithParameters(futureElement, "then", futureRType, [
-      ElementFactory.requiredParameter2("onValue", thenOnValue.type),
-      ElementFactory.namedParameter2("onError", provider.functionType)
-    ]);
-    if (!futureThenR.type.isDynamic) {
-      thenMethod.typeParameters = [futureThenR];
-    }
-    thenOnValue.enclosingElement = thenMethod;
-    thenOnValue.type = new FunctionTypeImpl(thenOnValue);
-    (thenMethod.parameters[0] as ParameterElementImpl).type = thenOnValue.type;
-    thenMethod.type = new FunctionTypeImpl(thenMethod);
-
-    futureElement.methods = <MethodElement>[thenMethod];
-    // Completer
-    ClassElementImpl completerElement =
-        ElementFactory.classElement2("Completer", ["T"]);
-    ConstructorElementImpl completerConstructor =
-        ElementFactory.constructorElement2(completerElement, null);
-    completerElement.constructors = <ConstructorElement>[completerConstructor];
-    // StreamSubscription
-    ClassElementImpl streamSubscriptionElement =
-        ElementFactory.classElement2("StreamSubscription", ["T"]);
-    // Stream
-    ClassElementImpl streamElement =
-        ElementFactory.classElement2("Stream", ["T"]);
-    streamElement.constructors = <ConstructorElement>[
-      ElementFactory.constructorElement2(streamElement, null)
-    ];
-    DartType returnType = streamSubscriptionElement.type
-        .substitute4(streamElement.type.typeArguments);
-    List<DartType> parameterTypes = <DartType>[
-      ElementFactory
-          .functionElement3('onData', VoidTypeImpl.instance.element,
-              <TypeDefiningElement>[streamElement.typeParameters[0]], null)
-          .type,
-    ];
-    // TODO(brianwilkerson) This is missing the optional parameters.
-    MethodElementImpl listenMethod =
-        ElementFactory.methodElement('listen', returnType, parameterTypes);
-    streamElement.methods = <MethodElement>[listenMethod];
-    listenMethod.type = new FunctionTypeImpl(listenMethod);
-
-    FunctionElementImpl listenParamFunction = parameterTypes[0].element;
-    listenParamFunction.enclosingElement = listenMethod;
-    listenParamFunction.type = new FunctionTypeImpl(listenParamFunction);
-    ParameterElementImpl listenParam = listenMethod.parameters[0];
-    listenParam.type = listenParamFunction.type;
-
-    asyncUnit.types = <ClassElement>[
-      completerElement,
-      futureElement,
-      streamElement,
-      streamSubscriptionElement
-    ];
-    LibraryElementImpl asyncLibrary = new LibraryElementImpl.forNode(
-        coreContext, AstFactory.libraryIdentifier2(["dart", "async"]));
-    asyncLibrary.definingCompilationUnit = asyncUnit;
     //
     // dart:html
     //
@@ -395,7 +433,9 @@
     HashMap<Source, LibraryElement> elementMap =
         new HashMap<Source, LibraryElement>();
     elementMap[coreSource] = coreLibrary;
-    elementMap[asyncSource] = asyncLibrary;
+    if (asyncSource != null) {
+      elementMap[asyncSource] = asyncLibrary;
+    }
     elementMap[htmlSource] = htmlLibrary;
     elementMap[mathSource] = mathLibrary;
     //
@@ -403,10 +443,16 @@
     // core library so public and export namespaces are the same.
     //
     for (LibraryElementImpl library in elementMap.values) {
-      library.exportNamespace =
-          library.publicNamespace = new PublicNamespaceBuilder().build(library);
+      Namespace namespace =
+          new NamespaceBuilder().createPublicNamespaceForLibrary(library);
+      library.exportNamespace = namespace;
+      library.publicNamespace = namespace;
     }
     context.recordLibraryElements(elementMap);
+    // Create the synthetic element for `loadLibrary`.
+    for (LibraryElementImpl library in elementMap.values) {
+      library.createLoadLibraryFunction(context.typeProvider);
+    }
     return context;
   }
 }
@@ -1206,6 +1252,51 @@
 }
 
 @reflectiveTest
+class DisableAsyncTestCase extends ResolverTestCase {
+  @override
+  void setUp() {
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    options.enableAsync = false;
+    resetWithOptions(options);
+  }
+
+  void test_resolve() {
+    Source source = addSource(r'''
+class C {
+  foo() {
+    bar();
+  }
+  bar() {
+    //
+  }
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, []);
+  }
+
+  void test_resolve_async() {
+    Source source = addSource(r'''
+class C {
+  Future foo() async {
+    await bar();
+    return null;
+  }
+  Future bar() {
+    return new Future.delayed(new Duration(milliseconds: 10));
+  }
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      StaticWarningCode.UNDEFINED_CLASS,
+      StaticWarningCode.UNDEFINED_CLASS,
+      StaticWarningCode.UNDEFINED_CLASS,
+      StaticWarningCode.UNDEFINED_CLASS,
+      ParserErrorCode.ASYNC_NOT_SUPPORTED
+    ]);
+  }
+}
+
+@reflectiveTest
 class ElementResolverTest extends EngineTestCase {
   /**
    * The error listener to which errors will be reported.
@@ -1417,8 +1508,8 @@
     //   break loop;
     // }
     String label = "loop";
-    LabelElementImpl labelElement =
-        new LabelElementImpl(AstFactory.identifier3(label), false, false);
+    LabelElementImpl labelElement = new LabelElementImpl.forNode(
+        AstFactory.identifier3(label), false, false);
     BreakStatement breakStatement = AstFactory.breakStatement2(label);
     Expression condition = AstFactory.booleanLiteral(true);
     WhileStatement whileStatement =
@@ -1507,8 +1598,8 @@
     //   continue loop;
     // }
     String label = "loop";
-    LabelElementImpl labelElement =
-        new LabelElementImpl(AstFactory.identifier3(label), false, false);
+    LabelElementImpl labelElement = new LabelElementImpl.forNode(
+        AstFactory.identifier3(label), false, false);
     ContinueStatement continueStatement = AstFactory.continueStatement(label);
     Expression condition = AstFactory.booleanLiteral(true);
     WhileStatement whileStatement =
@@ -1526,17 +1617,24 @@
   }
 
   void test_visitEnumDeclaration() {
+    CompilationUnitElementImpl compilationUnitElement =
+        ElementFactory.compilationUnit('foo.dart');
     ClassElementImpl enumElement =
         ElementFactory.enumElement(_typeProvider, ('E'));
+    compilationUnitElement.enums = <ClassElement>[enumElement];
     EnumDeclaration enumNode = AstFactory.enumDeclaration2('E', []);
     Annotation annotationNode =
         AstFactory.annotation(AstFactory.identifier3('a'));
     annotationNode.element = ElementFactory.classElement2('A');
+    annotationNode.elementAnnotation =
+        new ElementAnnotationImpl(compilationUnitElement);
     enumNode.metadata.add(annotationNode);
     enumNode.name.staticElement = enumElement;
+    List<ElementAnnotation> metadata = <ElementAnnotation>[
+      annotationNode.elementAnnotation
+    ];
     _resolveNode(enumNode);
-    List<ElementAnnotation> metadata = enumElement.metadata;
-    expect(metadata, hasLength(1));
+    expect(metadata[0].element, annotationNode.element);
   }
 
   void test_visitExportDirective_noCombinators() {
@@ -2272,6 +2370,42 @@
   }
 }
 
+/**
+ * Tests for generic method and function resolution that do not use strong mode.
+ */
+@reflectiveTest
+class GenericMethodResolverTest extends _StaticTypeAnalyzer2TestShared {
+  void setUp() {
+    super.setUp();
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    options.enableGenericMethods = true;
+    resetWithOptions(options);
+  }
+
+  void test_genericMethod_propagatedType_promotion() {
+    // Regression test for:
+    // https://github.com/dart-lang/sdk/issues/25340
+    //
+    // Note, after https://github.com/dart-lang/sdk/issues/25486 the original
+    // strong mode example won't work, as we now compute a static type and
+    // therefore discard the propagated type.
+    //
+    // So this test does not use strong mode.
+    _resolveTestUnit(r'''
+abstract class Iter {
+  List<S> map<S>(S f(x));
+}
+class C {}
+C toSpan(dynamic element) {
+  if (element is Iter) {
+    var y = element.map(toSpan);
+  }
+  return null;
+}''');
+    _expectIdentifierType('y = ', 'dynamic', 'List<dynamic>');
+  }
+}
+
 @reflectiveTest
 class HintCodeTest extends ResolverTestCase {
   void fail_deadCode_statementAfterRehrow() {
@@ -2349,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() {
@@ -3185,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;
@@ -6546,6 +6930,18 @@
     verify([source]);
   }
 
+  void test_deprecatedAnnotationUse_classWithConstructor() {
+    Source source = addSource(r'''
+@deprecated
+class C {
+  C();
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_divisionOptimization() {
     Source source = addSource(r'''
 f(int x, int y) {
@@ -7739,6 +8135,11 @@
     if (node.name == "void") {
       return null;
     }
+    if (node.staticType != null &&
+        node.staticType.isDynamic &&
+        node.staticElement == null) {
+      return null;
+    }
     AstNode parent = node.parent;
     if (parent is MethodInvocation) {
       MethodInvocation invocation = parent;
@@ -7871,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 ||
@@ -8095,6 +8497,7 @@
 
   @override
   void setUp() {
+    ElementFactory.flushStaticState();
     super.setUp();
     reset();
   }
@@ -9274,14 +9677,30 @@
   void test_isValidMixin_badSuperclass() {
     Source source = addSource(r'''
 class A extends B {}
-class B {}''');
+class B {}
+class C = Object with A;''');
     LibraryElement library = resolve2(source);
     expect(library, isNotNull);
     CompilationUnitElement unit = library.definingCompilationUnit;
     expect(unit, isNotNull);
-    List<ClassElement> classes = unit.types;
-    expect(classes, hasLength(2));
-    expect(classes[0].isValidMixin, isFalse);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isFalse);
+    assertErrors(source, [CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT]);
+    verify([source]);
+  }
+
+  void test_isValidMixin_badSuperclass_withSuperMixins() {
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource(r'''
+class A extends B {}
+class B {}
+class C = Object with A;''');
+    LibraryElement library = resolve2(source);
+    expect(library, isNotNull);
+    CompilationUnitElement unit = library.definingCompilationUnit;
+    expect(unit, isNotNull);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isTrue);
     assertNoErrors(source);
     verify([source]);
   }
@@ -9290,14 +9709,64 @@
     Source source = addSource(r'''
 class A {
   A() {}
-}''');
+}
+class C = Object with A;''');
     LibraryElement library = resolve2(source);
     expect(library, isNotNull);
     CompilationUnitElement unit = library.definingCompilationUnit;
     expect(unit, isNotNull);
-    List<ClassElement> classes = unit.types;
-    expect(classes, hasLength(1));
-    expect(classes[0].isValidMixin, isFalse);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isFalse);
+    assertErrors(source, [CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR]);
+    verify([source]);
+  }
+
+  void test_isValidMixin_constructor_withSuperMixins() {
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource(r'''
+class A {
+  A() {}
+}
+class C = Object with A;''');
+    LibraryElement library = resolve2(source);
+    expect(library, isNotNull);
+    CompilationUnitElement unit = library.definingCompilationUnit;
+    expect(unit, isNotNull);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isFalse);
+    assertErrors(source, [CompileTimeErrorCode.MIXIN_DECLARES_CONSTRUCTOR]);
+    verify([source]);
+  }
+
+  void test_isValidMixin_factoryConstructor() {
+    Source source = addSource(r'''
+class A {
+  factory A() => null;
+}
+class C = Object with A;''');
+    LibraryElement library = resolve2(source);
+    expect(library, isNotNull);
+    CompilationUnitElement unit = library.definingCompilationUnit;
+    expect(unit, isNotNull);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isTrue);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  void test_isValidMixin_factoryConstructor_withSuperMixins() {
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource(r'''
+class A {
+  factory A() => null;
+}
+class C = Object with A;''');
+    LibraryElement library = resolve2(source);
+    expect(library, isNotNull);
+    CompilationUnitElement unit = library.definingCompilationUnit;
+    expect(unit, isNotNull);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isTrue);
     assertNoErrors(source);
     verify([source]);
   }
@@ -9308,27 +9777,62 @@
   toString() {
     return super.toString();
   }
-}''');
+}
+class C = Object with A;''');
     LibraryElement library = resolve2(source);
     expect(library, isNotNull);
     CompilationUnitElement unit = library.definingCompilationUnit;
     expect(unit, isNotNull);
-    List<ClassElement> classes = unit.types;
-    expect(classes, hasLength(1));
-    expect(classes[0].isValidMixin, isFalse);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isFalse);
+    assertErrors(source, [CompileTimeErrorCode.MIXIN_REFERENCES_SUPER]);
+    verify([source]);
+  }
+
+  void test_isValidMixin_super_withSuperMixins() {
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource(r'''
+class A {
+  toString() {
+    return super.toString();
+  }
+}
+class C = Object with A;''');
+    LibraryElement library = resolve2(source);
+    expect(library, isNotNull);
+    CompilationUnitElement unit = library.definingCompilationUnit;
+    expect(unit, isNotNull);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isTrue);
     assertNoErrors(source);
     verify([source]);
   }
 
   void test_isValidMixin_valid() {
-    Source source = addSource("class A {}");
+    Source source = addSource('''
+class A {}
+class C = Object with A;''');
     LibraryElement library = resolve2(source);
     expect(library, isNotNull);
     CompilationUnitElement unit = library.definingCompilationUnit;
     expect(unit, isNotNull);
-    List<ClassElement> classes = unit.types;
-    expect(classes, hasLength(1));
-    expect(classes[0].isValidMixin, isTrue);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isTrue);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  void test_isValidMixin_valid_withSuperMixins() {
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource('''
+class A {}
+class C = Object with A;''');
+    LibraryElement library = resolve2(source);
+    expect(library, isNotNull);
+    CompilationUnitElement unit = library.definingCompilationUnit;
+    expect(unit, isNotNull);
+    ClassElement a = unit.getType('A');
+    expect(a.isValidMixin, isTrue);
     assertNoErrors(source);
     verify([source]);
   }
@@ -9911,11 +10415,7 @@
 }
 ''';
     _resolveTestUnit(code);
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.isDynamic, isTrue);
-    expect(declaration.initializer.propagatedType, isNull);
+    _expectInitializerType('foo', 'dynamic', isNull);
   }
 
   void test_FunctionExpressionInvocation_curried() {
@@ -9927,11 +10427,7 @@
 }
 ''';
     _resolveTestUnit(code);
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
+    _expectInitializerType('foo', 'int', isNull);
   }
 
   void test_FunctionExpressionInvocation_expression() {
@@ -9941,11 +10437,7 @@
 }
 ''';
     _resolveTestUnit(code);
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
+    _expectInitializerType('foo', 'int', isNull);
   }
 
   void test_MethodInvocation_nameType_localVariable() {
@@ -9958,9 +10450,7 @@
 """;
     _resolveTestUnit(code);
     // "foo" should be resolved to the "Foo" type
-    SimpleIdentifier identifier = _findIdentifier("foo();");
-    DartType type = identifier.staticType;
-    expect(type, new isInstanceOf<FunctionType>());
+    _expectIdentifierType("foo();", new isInstanceOf<FunctionType>());
   }
 
   void test_MethodInvocation_nameType_parameter_FunctionTypeAlias() {
@@ -9972,9 +10462,7 @@
 """;
     _resolveTestUnit(code);
     // "foo" should be resolved to the "Foo" type
-    SimpleIdentifier identifier = _findIdentifier("foo();");
-    DartType type = identifier.staticType;
-    expect(type, new isInstanceOf<FunctionType>());
+    _expectIdentifierType("foo();", new isInstanceOf<FunctionType>());
   }
 
   void test_MethodInvocation_nameType_parameter_propagatedType() {
@@ -9987,12 +10475,67 @@
 }
 """;
     _resolveTestUnit(code);
-    SimpleIdentifier identifier = _findIdentifier("p()");
-    expect(identifier.staticType, DynamicTypeImpl.instance);
+    _expectIdentifierType("p()", DynamicTypeImpl.instance,
+        predicate((type) => type.name == 'Foo'));
+  }
+
+  void test_staticMethods_classTypeParameters() {
+    String code = r'''
+class C<T> {
+  static void m() => null;
+}
+main() {
+  print(C.m);
+}
+''';
+    _resolveTestUnit(code);
+    _expectFunctionType('m);', '() → void');
+  }
+
+  void test_staticMethods_classTypeParameters_genericMethod() {
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    options.enableGenericMethods = true;
+    resetWithOptions(options);
+    String code = r'''
+class C<T> {
+  static void m<S>(S s) {
+    void f<U>(S s, U u) {}
+    print(f);
+  }
+}
+main() {
+  print(C.m);
+}
+''';
+    _resolveTestUnit(code);
+    // C - m
+    TypeParameterType typeS;
     {
-      FunctionType type = identifier.propagatedType;
-      expect(type, isNotNull);
-      expect(type.name, 'Foo');
+      _expectFunctionType('m);', '<S>(S) → void',
+          elementTypeParams: '[S]', typeFormals: '[S]');
+
+      FunctionTypeImpl type = _findIdentifier('m);').staticType;
+      typeS = type.typeFormals[0].type;
+      type = type.instantiate([DynamicTypeImpl.instance]);
+      expect(type.toString(), '(dynamic) → void');
+      expect(type.typeParameters.toString(), '[S]');
+      expect(type.typeArguments, [DynamicTypeImpl.instance]);
+      expect(type.typeFormals, isEmpty);
+    }
+    // C - m - f
+    {
+      _expectFunctionType('f);', '<U>(S, U) → void',
+          elementTypeParams: '[U]',
+          typeParams: '[S]',
+          typeArgs: '[S]',
+          typeFormals: '[U]');
+
+      FunctionTypeImpl type = _findIdentifier('f);').staticType;
+      type = type.instantiate([DynamicTypeImpl.instance]);
+      expect(type.toString(), '(S, dynamic) → void');
+      expect(type.typeParameters.toString(), '[S, U]');
+      expect(type.typeArguments, [typeS, DynamicTypeImpl.instance]);
+      expect(type.typeFormals, isEmpty);
     }
   }
 }
@@ -10019,6 +10562,11 @@
    */
   TestTypeProvider _typeProvider;
 
+  /**
+   * The type system used to analyze the test cases.
+   */
+  TypeSystem get _typeSystem => _visitor.typeSystem;
+
   void fail_visitFunctionExpressionInvocation() {
     fail("Not yet tested");
     _listener.assertNoErrors();
@@ -10038,7 +10586,6 @@
   void setUp() {
     super.setUp();
     _listener = new GatheringErrorListener();
-    _typeProvider = new TestTypeProvider();
     _analyzer = _createAnalyzer();
   }
 
@@ -11304,6 +11851,7 @@
     LibraryElementImpl definingLibrary =
         new LibraryElementImpl.forNode(context, null);
     definingLibrary.definingCompilationUnit = definingCompilationUnit;
+    _typeProvider = new TestTypeProvider(context);
     _visitor = new ResolverVisitor(
         definingLibrary, source, _typeProvider, _listener,
         nameScope: new LibraryScope(definingLibrary, _listener));
@@ -11316,8 +11864,7 @@
     }
   }
 
-  DartType _flatten(DartType type) =>
-      StaticTypeAnalyzer.flattenFutures(_typeProvider, type);
+  DartType _flatten(DartType type) => type.flattenFutures(_typeSystem);
 
   /**
    * Return a simple identifier that has been resolved to a variable element with the given type.
@@ -13030,105 +13577,6 @@
  */
 @reflectiveTest
 class StrongModeStaticTypeAnalyzer2Test extends _StaticTypeAnalyzer2TestShared {
-  void test_genericMethod_functionExpressionInvocation_explicit() {
-    _resolveTestUnit(r'''
-class C<E> {
-  /*=T*/ f/*<T>*/(/*=T*/ e) => null;
-  static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
-  static final h = g;
-}
-
-/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
-var topG = topF;
-void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
-  var c = new C<int>();
-  /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
-
-  var lambdaCall = (/*<E>*/(/*=E*/ e) => e)/*<int>*/(3);
-  var methodCall = (c.f)/*<int>*/(3);
-  var staticCall = (C.g)/*<int>*/(3);
-  var staticFieldCall = (C.h)/*<int>*/(3);
-  var topFunCall = (topF)/*<int>*/(3);
-  var topFieldCall = (topG)/*<int>*/(3);
-  var localCall = (lf)/*<int>*/(3);
-  var paramCall = (pf)/*<int>*/(3);
-}
-''');
-    expect(_findIdentifier('methodCall').staticType.toString(), "int");
-    expect(_findIdentifier('staticCall').staticType.toString(), "int");
-    expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
-    expect(_findIdentifier('topFunCall').staticType.toString(), "int");
-    expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
-    expect(_findIdentifier('localCall').staticType.toString(), "int");
-    expect(_findIdentifier('paramCall').staticType.toString(), "int");
-    expect(_findIdentifier('lambdaCall').staticType.toString(), "int");
-  }
-
-  void fail_genericMethod_functionExpressionInvocation_inferred() {
-    _resolveTestUnit(r'''
-class C<E> {
-  /*=T*/ f/*<T>*/(/*=T*/ e) => null;
-  static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
-  static final h = g;
-}
-
-/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
-var topG = topF;
-void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
-  var c = new C<int>();
-  /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
-
-  var lambdaCall = (/*<E>*/(/*=E*/ e) => e)(3);
-  var methodCall = (c.f)(3);
-  var staticCall = (C.g)(3);
-  var staticFieldCall = (C.h)(3);
-  var topFunCall = (topF)(3);
-  var topFieldCall = (topG)(3);
-  var localCall = (lf)(3);
-  var paramCall = (pf)(3);
-}
-''');
-    expect(_findIdentifier('methodCall').staticType.toString(), "int");
-    expect(_findIdentifier('staticCall').staticType.toString(), "int");
-    expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
-    expect(_findIdentifier('topFunCall').staticType.toString(), "int");
-    expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
-    expect(_findIdentifier('localCall').staticType.toString(), "int");
-    expect(_findIdentifier('paramCall').staticType.toString(), "int");
-    expect(_findIdentifier('lambdaCall').staticType.toString(), "int");
-  }
-
-  void fail_genericMethod_functionInvocation_inferred() {
-    _resolveTestUnit(r'''
-class C<E> {
-  /*=T*/ f/*<T>*/(/*=T*/ e) => null;
-  static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
-  static final h = g;
-}
-
-/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
-var topG = topF;
-void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
-  var c = new C<int>();
-  /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
-  var methodCall = c.f(3);
-  var staticCall = C.g(3);
-  var staticFieldCall = C.h(3);
-  var topFunCall = topF(3);
-  var topFieldCall = topG(3);
-  var localCall = lf(3);
-  var paramCall = pf(3);
-}
-''');
-    expect(_findIdentifier('methodCall').staticType.toString(), "int");
-    expect(_findIdentifier('staticCall').staticType.toString(), "int");
-    expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
-    expect(_findIdentifier('topFunCall').staticType.toString(), "int");
-    expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
-    expect(_findIdentifier('localCall').staticType.toString(), "int");
-    expect(_findIdentifier('paramCall').staticType.toString(), "int");
-  }
-
   void fail_genericMethod_tearoff_instantiated() {
     _resolveTestUnit(r'''
 class C<E> {
@@ -13151,20 +13599,13 @@
   var paramTearOffInst = pf/*<int>*/;
 }
 ''');
-    expect(_findIdentifier('methodTearOffInst').staticType.toString(),
-        "(int) → int");
-    expect(_findIdentifier('staticTearOffInst').staticType.toString(),
-        "(int) → int");
-    expect(_findIdentifier('staticFieldTearOffInst').staticType.toString(),
-        "(int) → int");
-    expect(_findIdentifier('topFunTearOffInst').staticType.toString(),
-        "(int) → int");
-    expect(_findIdentifier('topFieldTearOffInst').staticType.toString(),
-        "(int) → int");
-    expect(_findIdentifier('localTearOffInst').staticType.toString(),
-        "(int) → int");
-    expect(_findIdentifier('paramTearOffInst').staticType.toString(),
-        "(int) → int");
+    _expectIdentifierType('methodTearOffInst', "(int) → int");
+    _expectIdentifierType('staticTearOffInst', "(int) → int");
+    _expectIdentifierType('staticFieldTearOffInst', "(int) → int");
+    _expectIdentifierType('topFunTearOffInst', "(int) → int");
+    _expectIdentifierType('topFieldTearOffInst', "(int) → int");
+    _expectIdentifierType('localTearOffInst', "(int) → int");
+    _expectIdentifierType('paramTearOffInst', "(int) → int");
   }
 
   void setUp() {
@@ -13182,12 +13623,7 @@
 }
 ''';
     _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
+    _expectInitializerType('foo', 'int', isNull);
   }
 
   void test_dynamicObjectMethod_toString() {
@@ -13198,47 +13634,34 @@
 }
 ''';
     _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'String');
-    expect(declaration.initializer.propagatedType, isNull);
+    _expectInitializerType('foo', 'String', isNull);
   }
 
   void test_genericFunction() {
     _resolveTestUnit(r'/*=T*/ f/*<T>*/(/*=T*/ x) => null;');
+    _expectFunctionType('f', '<T>(T) → T',
+        elementTypeParams: '[T]', typeFormals: '[T]');
     SimpleIdentifier f = _findIdentifier('f');
     FunctionElementImpl e = f.staticElement;
-    expect(e.typeParameters.toString(), '[T]');
-    expect(e.type.typeFormals.toString(), '[T]');
-    expect(e.type.typeParameters.toString(), '[]');
-    expect(e.type.toString(), '<T>(T) → T');
-
     FunctionType ft = e.type.instantiate([typeProvider.stringType]);
     expect(ft.toString(), '(String) → String');
   }
 
   void test_genericFunction_bounds() {
     _resolveTestUnit(r'/*=T*/ f/*<T extends num>*/(/*=T*/ x) => null;');
-    SimpleIdentifier f = _findIdentifier('f');
-    FunctionElementImpl e = f.staticElement;
-    expect(e.typeParameters.toString(), '[T extends num]');
-    expect(e.type.typeFormals.toString(), '[T extends num]');
-    expect(e.type.typeParameters.toString(), '[]');
-    expect(e.type.toString(), '<T extends num>(T) → T');
+    _expectFunctionType('f', '<T extends num>(T) → T',
+        elementTypeParams: '[T extends num]', typeFormals: '[T extends num]');
   }
 
   void test_genericFunction_parameter() {
     _resolveTestUnit(r'''
 void g(/*=T*/ f/*<T>*/(/*=T*/ x)) {}
 ''');
+    _expectFunctionType('f', '<T>(T) → T',
+        elementTypeParams: '[T]', typeFormals: '[T]');
     SimpleIdentifier f = _findIdentifier('f');
     ParameterElementImpl e = f.staticElement;
     FunctionType type = e.type;
-    expect(e.typeParameters.toString(), '[T]');
-    expect(type.typeFormals.toString(), '[T]');
-    expect(type.toString(), '<T>(T) → T');
     FunctionType ft = type.instantiate([typeProvider.stringType]);
     expect(ft.toString(), '(String) → String');
   }
@@ -13249,17 +13672,10 @@
   static /*=T*/ f/*<T>*/(/*=T*/ x) => null;
 }
 ''');
+    _expectFunctionType('f', '<T>(T) → T',
+        elementTypeParams: '[T]', typeFormals: '[T]');
     SimpleIdentifier f = _findIdentifier('f');
     MethodElementImpl e = f.staticElement;
-    expect(e.typeParameters.toString(), '[T]');
-    expect(e.type.typeFormals.toString(), '[T]');
-    // TODO(jmesserly): we could get rid of this {E/E} substitution, but it's
-    // probably harmless, as E won't be used in the function (error verifier
-    // checks this), and {E/E} is a no-op anyway.
-    expect(e.type.typeParameters.toString(), '[E]');
-    expect(e.type.typeArguments.toString(), '[E]');
-    expect(e.type.toString(), '<T>(T) → T');
-
     FunctionType ft = e.type.instantiate([typeProvider.stringType]);
     expect(ft.toString(), '(String) → String');
   }
@@ -13297,46 +13713,18 @@
 ''';
     _resolveTestUnit(code);
 
-    {
+    checkBody(String className) {
       List<Statement> statements =
-          AstFinder.getStatementsInMethod(testUnit, "C", "g");
+          AstFinder.getStatementsInMethod(testUnit, className, "g");
 
-      ExpressionStatement exps0 = statements[1];
-      ExpressionStatement exps1 = statements[2];
-      ExpressionStatement exps2 = statements[3];
-      ExpressionStatement exps3 = statements[4];
-      ExpressionStatement exps4 = statements[5];
-      Expression exp0 = exps0.expression;
-      Expression exp1 = exps1.expression;
-      Expression exp2 = exps2.expression;
-      Expression exp3 = exps3.expression;
-      Expression exp4 = exps4.expression;
-      expect(exp0.staticType, typeProvider.dynamicType);
-      expect(exp1.staticType, typeProvider.dynamicType);
-      expect(exp2.staticType, typeProvider.dynamicType);
-      expect(exp3.staticType, typeProvider.dynamicType);
-      expect(exp4.staticType, typeProvider.dynamicType);
+      for (int i = 1; i <= 5; i++) {
+        Expression exp = (statements[i] as ExpressionStatement).expression;
+        expect(exp.staticType, typeProvider.dynamicType);
+      }
     }
-    {
-      List<Statement> statements =
-          AstFinder.getStatementsInMethod(testUnit, "D", "g");
 
-      ExpressionStatement exps0 = statements[1];
-      ExpressionStatement exps1 = statements[2];
-      ExpressionStatement exps2 = statements[3];
-      ExpressionStatement exps3 = statements[4];
-      ExpressionStatement exps4 = statements[5];
-      Expression exp0 = exps0.expression;
-      Expression exp1 = exps1.expression;
-      Expression exp2 = exps2.expression;
-      Expression exp3 = exps3.expression;
-      Expression exp4 = exps4.expression;
-      expect(exp0.staticType, typeProvider.dynamicType);
-      expect(exp1.staticType, typeProvider.dynamicType);
-      expect(exp2.staticType, typeProvider.dynamicType);
-      expect(exp3.staticType, typeProvider.dynamicType);
-      expect(exp4.staticType, typeProvider.dynamicType);
-    }
+    checkBody("C");
+    checkBody("D");
   }
 
   void test_genericMethod() {
@@ -13348,14 +13736,11 @@
   C<String> cOfString;
 }
 ''');
-    SimpleIdentifier f = _findIdentifier('f');
-    MethodElementImpl e = f.staticElement;
-    expect(e.typeParameters.toString(), '[T]');
-    expect(e.type.typeFormals.toString(), '[T]');
-    expect(e.type.typeParameters.toString(), '[E]');
-    expect(e.type.typeArguments.toString(), '[E]');
-    expect(e.type.toString(), '<T>(E) → List<T>');
-
+    _expectFunctionType('f', '<T>(E) → List<T>',
+        elementTypeParams: '[T]',
+        typeParams: '[E]',
+        typeArgs: '[E]',
+        typeFormals: '[T]');
     SimpleIdentifier c = _findIdentifier('cOfString');
     FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
     expect(ft.toString(), '<T>(String) → List<T>');
@@ -13384,6 +13769,74 @@
         typeProvider.listType.substitute4([typeProvider.intType]));
   }
 
+  void test_genericMethod_functionExpressionInvocation_explicit() {
+    _resolveTestUnit(r'''
+class C<E> {
+  /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+  static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+  static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+  var c = new C<int>();
+  /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+
+  var lambdaCall = (/*<E>*/(/*=E*/ e) => e)/*<int>*/(3);
+  var methodCall = (c.f)/*<int>*/(3);
+  var staticCall = (C.g)/*<int>*/(3);
+  var staticFieldCall = (C.h)/*<int>*/(3);
+  var topFunCall = (topF)/*<int>*/(3);
+  var topFieldCall = (topG)/*<int>*/(3);
+  var localCall = (lf)/*<int>*/(3);
+  var paramCall = (pf)/*<int>*/(3);
+}
+''');
+    _expectIdentifierType('methodCall', "int");
+    _expectIdentifierType('staticCall', "int");
+    _expectIdentifierType('staticFieldCall', "int");
+    _expectIdentifierType('topFunCall', "int");
+    _expectIdentifierType('topFieldCall', "int");
+    _expectIdentifierType('localCall', "int");
+    _expectIdentifierType('paramCall', "int");
+    _expectIdentifierType('lambdaCall', "int");
+  }
+
+  void test_genericMethod_functionExpressionInvocation_inferred() {
+    _resolveTestUnit(r'''
+class C<E> {
+  /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+  static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+  static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+  var c = new C<int>();
+  /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+
+  var lambdaCall = (/*<E>*/(/*=E*/ e) => e)(3);
+  var methodCall = (c.f)(3);
+  var staticCall = (C.g)(3);
+  var staticFieldCall = (C.h)(3);
+  var topFunCall = (topF)(3);
+  var topFieldCall = (topG)(3);
+  var localCall = (lf)(3);
+  var paramCall = (pf)(3);
+}
+''');
+    _expectIdentifierType('methodCall', "int");
+    _expectIdentifierType('staticCall', "int");
+    _expectIdentifierType('staticFieldCall', "int");
+    _expectIdentifierType('topFunCall', "int");
+    _expectIdentifierType('topFieldCall', "int");
+    _expectIdentifierType('localCall', "int");
+    _expectIdentifierType('paramCall', "int");
+    _expectIdentifierType('lambdaCall', "int");
+  }
+
   void test_genericMethod_functionInvocation_explicit() {
     _resolveTestUnit(r'''
 class C<E> {
@@ -13406,13 +13859,44 @@
   var paramCall = pf/*<int>*/(3);
 }
 ''');
-    expect(_findIdentifier('methodCall').staticType.toString(), "int");
-    expect(_findIdentifier('staticCall').staticType.toString(), "int");
-    expect(_findIdentifier('staticFieldCall').staticType.toString(), "int");
-    expect(_findIdentifier('topFunCall').staticType.toString(), "int");
-    expect(_findIdentifier('topFieldCall').staticType.toString(), "int");
-    expect(_findIdentifier('localCall').staticType.toString(), "int");
-    expect(_findIdentifier('paramCall').staticType.toString(), "int");
+    _expectIdentifierType('methodCall', "int");
+    _expectIdentifierType('staticCall', "int");
+    _expectIdentifierType('staticFieldCall', "int");
+    _expectIdentifierType('topFunCall', "int");
+    _expectIdentifierType('topFieldCall', "int");
+    _expectIdentifierType('localCall', "int");
+    _expectIdentifierType('paramCall', "int");
+  }
+
+  void test_genericMethod_functionInvocation_inferred() {
+    _resolveTestUnit(r'''
+class C<E> {
+  /*=T*/ f/*<T>*/(/*=T*/ e) => null;
+  static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
+  static final h = g;
+}
+
+/*=T*/ topF/*<T>*/(/*=T*/ e) => null;
+var topG = topF;
+void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
+  var c = new C<int>();
+  /*=T*/ lf/*<T>*/(/*=T*/ e) => null;
+  var methodCall = c.f(3);
+  var staticCall = C.g(3);
+  var staticFieldCall = C.h(3);
+  var topFunCall = topF(3);
+  var topFieldCall = topG(3);
+  var localCall = lf(3);
+  var paramCall = pf(3);
+}
+''');
+    _expectIdentifierType('methodCall', "int");
+    _expectIdentifierType('staticCall', "int");
+    _expectIdentifierType('staticFieldCall', "int");
+    _expectIdentifierType('topFunCall', "int");
+    _expectIdentifierType('topFieldCall', "int");
+    _expectIdentifierType('localCall', "int");
+    _expectIdentifierType('paramCall', "int");
   }
 
   void test_genericMethod_functionTypedParameter() {
@@ -13424,13 +13908,11 @@
   C<String> cOfString;
 }
 ''');
-    SimpleIdentifier f = _findIdentifier('f');
-    MethodElementImpl e = f.staticElement;
-    expect(e.typeParameters.toString(), '[T]');
-    expect(e.type.typeFormals.toString(), '[T]');
-    expect(e.type.typeParameters.toString(), '[E]');
-    expect(e.type.typeArguments.toString(), '[E]');
-    expect(e.type.toString(), '<T>((E) → T) → List<T>');
+    _expectFunctionType('f', '<T>((E) → T) → List<T>',
+        elementTypeParams: '[T]',
+        typeParams: '[E]',
+        typeArgs: '[E]',
+        typeFormals: '[T]');
 
     SimpleIdentifier c = _findIdentifier('cOfString');
     FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
@@ -13452,17 +13934,80 @@
   list.map((e) => e);
   list.map((e) => 3);
 }''');
+    _expectIdentifierType('map((e) => e);', '<T>((dynamic) → T) → T', isNull);
+    _expectIdentifierType('map((e) => 3);', '<T>((dynamic) → T) → T', isNull);
 
-    SimpleIdentifier map1 = _findIdentifier('map((e) => e);');
-    MethodInvocation m1 = map1.parent;
+    MethodInvocation m1 = _findIdentifier('map((e) => e);').parent;
     expect(m1.staticInvokeType.toString(), '((dynamic) → dynamic) → dynamic');
-    expect(map1.staticType, isNull);
-    expect(map1.propagatedType, isNull);
-    SimpleIdentifier map2 = _findIdentifier('map((e) => 3);');
-    MethodInvocation m2 = map2.parent;
+    MethodInvocation m2 = _findIdentifier('map((e) => 3);').parent;
     expect(m2.staticInvokeType.toString(), '((dynamic) → int) → int');
-    expect(map2.staticType, isNull);
-    expect(map2.propagatedType, isNull);
+  }
+
+  void test_genericMethod_max_doubleDouble() {
+    String code = r'''
+import 'dart:math';
+main() {
+  var foo = max(1.0, 2.0);
+}
+''';
+    _resolveTestUnit(code);
+    _expectInitializerType('foo', 'double', isNull);
+  }
+
+  void test_genericMethod_max_doubleDouble_prefixed() {
+    String code = r'''
+import 'dart:math' as math;
+main() {
+  var foo = math.max(1.0, 2.0);
+}
+''';
+    _resolveTestUnit(code);
+    _expectInitializerType('foo', 'double', isNull);
+  }
+
+  void test_genericMethod_max_doubleInt() {
+    String code = r'''
+import 'dart:math';
+main() {
+  var foo = max(1.0, 2);
+}
+''';
+    _resolveTestUnit(code);
+    _expectInitializerType('foo', 'num', isNull);
+  }
+
+  void test_genericMethod_max_intDouble() {
+    String code = r'''
+import 'dart:math';
+main() {
+  var foo = max(1, 2.0);
+}
+''';
+    _resolveTestUnit(code);
+    _expectInitializerType('foo', 'num', isNull);
+  }
+
+  void test_genericMethod_max_intInt() {
+    String code = r'''
+import 'dart:math';
+main() {
+  var foo = max(1, 2);
+}
+''';
+    _resolveTestUnit(code);
+    _expectInitializerType('foo', 'int', isNull);
+  }
+
+  void test_genericMethod_nestedBound() {
+    String code = r'''
+class Foo<T extends num> {
+  void method/*<U extends T>*/(dynamic/*=U*/ u) {
+    u.abs();
+  }
+}
+''';
+    // Just validate that there is no warning on the call to `.abs()`.
+    _resolveTestUnit(code);
   }
 
   void test_genericMethod_nestedCapture() {
@@ -13480,8 +14025,7 @@
     FunctionType ft = f.staticInvokeType;
     expect('${ft.typeArguments}/${ft.typeParameters}', '[S, int]/[T, S]');
 
-    SimpleIdentifier f2 = _findIdentifier('f;');
-    expect(f2.staticType.toString(), '<S₀>(S₀) → S');
+    _expectIdentifierType('f;', '<S₀>(S₀) → S');
   }
 
   void test_genericMethod_nestedFunctions() {
@@ -13491,10 +14035,8 @@
   return null;
 }
 ''');
-    SimpleIdentifier g = _findIdentifier('f');
-    expect(g.staticType.toString(), '<S>(S) → S');
-    SimpleIdentifier f = _findIdentifier('g');
-    expect(f.staticType.toString(), '<S>(S) → dynamic');
+    _expectIdentifierType('f', '<S>(S) → S');
+    _expectIdentifierType('g', '<S>(S) → dynamic');
   }
 
   void test_genericMethod_override() {
@@ -13506,13 +14048,11 @@
   /*=T*/ f/*<T>*/(/*=T*/ x) => null; // from D
 }
 ''');
+    _expectFunctionType('f/*<T>*/(/*=T*/ x) => null; // from D', '<T>(T) → T',
+        elementTypeParams: '[T]', typeFormals: '[T]');
     SimpleIdentifier f =
         _findIdentifier('f/*<T>*/(/*=T*/ x) => null; // from D');
     MethodElementImpl e = f.staticElement;
-    expect(e.typeParameters.toString(), '[T]');
-    expect(e.type.typeFormals.toString(), '[T]');
-    expect(e.type.toString(), '<T>(T) → T');
-
     FunctionType ft = e.type.instantiate([typeProvider.stringType]);
     expect(ft.toString(), '(String) → String');
   }
@@ -13541,6 +14081,11 @@
     // TODO(jmesserly): we can't use assertErrors because STRONG_MODE_* errors
     // from CodeChecker don't have working equality.
     List<AnalysisError> errors = analysisContext2.computeErrors(source);
+
+    // Sort errors by name.
+    errors.sort((AnalysisError e1, AnalysisError e2) =>
+        e1.errorCode.name.compareTo(e2.errorCode.name));
+
     expect(errors.map((e) => e.errorCode.name), [
       'INVALID_METHOD_OVERRIDE_RETURN_TYPE',
       'STRONG_MODE_INVALID_METHOD_OVERRIDE'
@@ -13564,10 +14109,11 @@
     // TODO(jmesserly): this is modified code from assertErrors, which we can't
     // use directly because STRONG_MODE_* errors don't have working equality.
     List<AnalysisError> errors = analysisContext2.computeErrors(source);
-    expect(errors.map((e) => e.errorCode.name), [
-      'STRONG_MODE_INVALID_METHOD_OVERRIDE',
-      'INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND'
-    ]);
+    List errorNames = errors.map((e) => e.errorCode.name).toList();
+    expect(errorNames, hasLength(2));
+    expect(errorNames, contains('STRONG_MODE_INVALID_METHOD_OVERRIDE'));
+    expect(
+        errorNames, contains('INVALID_METHOD_OVERRIDE_TYPE_PARAMETER_BOUND'));
     verify([source]);
   }
 
@@ -13589,6 +14135,28 @@
     verify([source]);
   }
 
+  void test_genericMethod_propagatedType_promotion() {
+    // Regression test for:
+    // https://github.com/dart-lang/sdk/issues/25340
+
+    // Note, after https://github.com/dart-lang/sdk/issues/25486 the original
+    // example won't work, as we now compute a static type and therefore discard
+    // the propagated type. So a new test was created that doesn't run under
+    // strong mode.
+    _resolveTestUnit(r'''
+abstract class Iter {
+  List/*<S>*/ map/*<S>*/(/*=S*/ f(x));
+}
+class C {}
+C toSpan(dynamic element) {
+  if (element is Iter) {
+    var y = element.map(toSpan);
+  }
+  return null;
+}''');
+    _expectIdentifierType('y = ', 'List<C>', isNull);
+  }
+
   void test_genericMethod_tearoff() {
     _resolveTestUnit(r'''
 class C<E> {
@@ -13611,101 +14179,16 @@
   var paramTearOff = pf;
 }
 ''');
-    expect(
-        _findIdentifier('methodTearOff').staticType.toString(), "<T>(int) → T");
-    expect(
-        _findIdentifier('staticTearOff').staticType.toString(), "<T>(T) → T");
-    expect(_findIdentifier('staticFieldTearOff').staticType.toString(),
-        "<T>(T) → T");
-    expect(
-        _findIdentifier('topFunTearOff').staticType.toString(), "<T>(T) → T");
-    expect(
-        _findIdentifier('topFieldTearOff').staticType.toString(), "<T>(T) → T");
-    expect(_findIdentifier('localTearOff').staticType.toString(), "<T>(T) → T");
-    expect(_findIdentifier('paramTearOff').staticType.toString(), "<T>(T) → T");
+    _expectIdentifierType('methodTearOff', "<T>(int) → T");
+    _expectIdentifierType('staticTearOff', "<T>(T) → T");
+    _expectIdentifierType('staticFieldTearOff', "<T>(T) → T");
+    _expectIdentifierType('topFunTearOff', "<T>(T) → T");
+    _expectIdentifierType('topFieldTearOff', "<T>(T) → T");
+    _expectIdentifierType('localTearOff', "<T>(T) → T");
+    _expectIdentifierType('paramTearOff', "<T>(T) → T");
   }
 
-  void test_pseudoGeneric_max_doubleDouble() {
-    String code = r'''
-import 'dart:math';
-main() {
-  var foo = max(1.0, 2.0);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'double');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_pseudoGeneric_max_doubleDouble_prefixed() {
-    String code = r'''
-import 'dart:math' as math;
-main() {
-  var foo = math.max(1.0, 2.0);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'double');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_pseudoGeneric_max_doubleInt() {
-    String code = r'''
-import 'dart:math';
-main() {
-  var foo = max(1.0, 2);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'num');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_pseudoGeneric_max_intDouble() {
-    String code = r'''
-import 'dart:math';
-main() {
-  var foo = max(1, 2.0);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'num');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_pseudoGeneric_max_intInt() {
-    String code = r'''
-import 'dart:math';
-main() {
-  var foo = max(1, 2);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_pseudoGeneric_then() {
+  void test_genericMethod_then() {
     String code = r'''
 import 'dart:async';
 String toString(int x) => x.toString();
@@ -13715,16 +14198,10 @@
 }
 ''';
     _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-
-    expect(declaration.initializer.staticType.toString(), "Future<String>");
-    expect(declaration.initializer.propagatedType, isNull);
+    _expectInitializerType('foo', 'Future<String>', isNull);
   }
 
-  void test_pseudoGeneric_then_prefixed() {
+  void test_genericMethod_then_prefixed() {
     String code = r'''
 import 'dart:async' as async;
 String toString(int x) => x.toString();
@@ -13734,13 +14211,21 @@
 }
 ''';
     _resolveTestUnit(code);
+    _expectInitializerType('foo', 'Future<String>', isNull);
+  }
 
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-
-    expect(declaration.initializer.staticType.toString(), "Future<String>");
-    expect(declaration.initializer.propagatedType, isNull);
+  void test_genericMethod_then_propagatedType() {
+    // Regression test for https://github.com/dart-lang/sdk/issues/25482.
+    String code = r'''
+import 'dart:async';
+void main() {
+  Future<String> p;
+  var foo = p.then((r) => new Future<String>.value(3));
+}
+''';
+    // This should produce no hints or warnings.
+    _resolveTestUnit(code);
+    _expectInitializerType('foo', 'Future<String>', isNull);
   }
 
   void test_setterWithDynamicTypeIsError() {
@@ -13823,12 +14308,7 @@
 }
 ''';
     _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
+    _expectInitializerType('foo', 'int', isNull);
   }
 
   void test_ternaryOperator_null_right() {
@@ -13838,12 +14318,7 @@
 }
 ''';
     _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
+    _expectInitializerType('foo', 'int', isNull);
   }
 }
 
@@ -14203,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() {
@@ -15747,7 +16239,7 @@
 }''';
     SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
     MethodInvocation methodInvoke = methodName.parent;
-    expect(methodName.staticType, null, reason: 'library prefix has no type');
+    expect(methodName.staticType, typeProvider.dynamicType);
     expect(methodInvoke.staticType, typeProvider.dynamicType);
   }
 
@@ -15953,11 +16445,81 @@
     expect(provider.mapType, same(mapType));
     expect(provider.objectType, same(objectType));
     expect(provider.stackTraceType, same(stackTraceType));
+    expect(provider.streamType, same(streamType));
     expect(provider.stringType, same(stringType));
     expect(provider.symbolType, same(symbolType));
     expect(provider.typeType, same(typeType));
   }
 
+  void test_creation_no_async() {
+    //
+    // Create a mock library element with the types expected to be in dart:core.
+    // We cannot use either ElementFactory or TestTypeProvider (which uses
+    // ElementFactory) because we side-effect the elements in ways that would
+    // break other tests.
+    //
+    InterfaceType objectType = _classElement("Object", null).type;
+    InterfaceType boolType = _classElement("bool", objectType).type;
+    InterfaceType numType = _classElement("num", objectType).type;
+    InterfaceType doubleType = _classElement("double", numType).type;
+    InterfaceType functionType = _classElement("Function", objectType).type;
+    InterfaceType intType = _classElement("int", numType).type;
+    InterfaceType iterableType =
+        _classElement("Iterable", objectType, ["T"]).type;
+    InterfaceType listType = _classElement("List", objectType, ["E"]).type;
+    InterfaceType mapType = _classElement("Map", objectType, ["K", "V"]).type;
+    InterfaceType stackTraceType = _classElement("StackTrace", objectType).type;
+    InterfaceType stringType = _classElement("String", objectType).type;
+    InterfaceType symbolType = _classElement("Symbol", objectType).type;
+    InterfaceType typeType = _classElement("Type", objectType).type;
+    CompilationUnitElementImpl coreUnit =
+        new CompilationUnitElementImpl("core.dart");
+    coreUnit.types = <ClassElement>[
+      boolType.element,
+      doubleType.element,
+      functionType.element,
+      intType.element,
+      iterableType.element,
+      listType.element,
+      mapType.element,
+      objectType.element,
+      stackTraceType.element,
+      stringType.element,
+      symbolType.element,
+      typeType.element
+    ];
+    AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+    LibraryElementImpl coreLibrary = new LibraryElementImpl.forNode(
+        context, AstFactory.libraryIdentifier2(["dart.core"]));
+    coreLibrary.definingCompilationUnit = coreUnit;
+
+    LibraryElementImpl mockAsyncLib =
+        (context as AnalysisContextImpl).createMockAsyncLib(coreLibrary);
+    expect(mockAsyncLib.publicNamespace, isNotNull);
+
+    //
+    // Create a type provider and ensure that it can return the expected types.
+    //
+    TypeProviderImpl provider = new TypeProviderImpl(coreLibrary, mockAsyncLib);
+    expect(provider.boolType, same(boolType));
+    expect(provider.bottomType, isNotNull);
+    expect(provider.doubleType, same(doubleType));
+    expect(provider.dynamicType, isNotNull);
+    expect(provider.functionType, same(functionType));
+    InterfaceType mockFutureType = mockAsyncLib.getType('Future').type;
+    expect(provider.futureType, same(mockFutureType));
+    expect(provider.intType, same(intType));
+    expect(provider.listType, same(listType));
+    expect(provider.mapType, same(mapType));
+    expect(provider.objectType, same(objectType));
+    expect(provider.stackTraceType, same(stackTraceType));
+    expect(provider.stringType, same(stringType));
+    expect(provider.symbolType, same(symbolType));
+    InterfaceType mockStreamType = mockAsyncLib.getType('Stream').type;
+    expect(provider.streamType, same(mockStreamType));
+    expect(provider.typeType, same(typeType));
+  }
+
   ClassElement _classElement(String typeName, InterfaceType superclassType,
       [List<String> parameterNames]) {
     ClassElementImpl element =
@@ -16515,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");
@@ -16612,12 +17198,17 @@
 
 class _AnalysisContextFactory_initContextWithCore
     extends DirectoryBasedDartSdk {
-  _AnalysisContextFactory_initContextWithCore(JavaFile arg0) : super(arg0);
+  final bool enableAsync;
+  _AnalysisContextFactory_initContextWithCore(JavaFile arg0,
+      {this.enableAsync: true})
+      : super(arg0);
 
   @override
   LibraryMap initialLibraryMap(bool useDart2jsPaths) {
     LibraryMap map = new LibraryMap();
-    _addLibrary(map, DartSdk.DART_ASYNC, false, "async.dart");
+    if (enableAsync) {
+      _addLibrary(map, DartSdk.DART_ASYNC, false, "async.dart");
+    }
     _addLibrary(map, DartSdk.DART_CORE, false, "core.dart");
     _addLibrary(map, DartSdk.DART_HTML, false, "html_dartium.dart");
     _addLibrary(map, AnalysisContextFactory._DART_MATH, false, "math.dart");
@@ -16670,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].
  */
@@ -16678,6 +17284,81 @@
   Source testSource;
   CompilationUnit testUnit;
 
+  /**
+   * Looks up the identifier with [name] and validates that its type type
+   * stringifies to [type] and that its generics match the given stringified
+   * output.
+   */
+  _expectFunctionType(String name, String type,
+      {String elementTypeParams: '[]',
+      String typeParams: '[]',
+      String typeArgs: '[]',
+      String typeFormals: '[]'}) {
+    SimpleIdentifier identifier = _findIdentifier(name);
+    // Element is either ExecutableElement or ParameterElement.
+    var element = identifier.staticElement;
+    FunctionTypeImpl functionType = identifier.staticType;
+    expect(functionType.toString(), type);
+    expect(element.typeParameters.toString(), elementTypeParams);
+    expect(functionType.typeParameters.toString(), typeParams);
+    expect(functionType.typeArguments.toString(), typeArgs);
+    expect(functionType.typeFormals.toString(), typeFormals);
+  }
+
+  /**
+   * Looks up the identifier with [name] and validates its static [type].
+   *
+   * If [type] is a string, validates that the identifier's static type
+   * stringifies to that text. Otherwise, [type] is used directly a [Matcher]
+   * to match the type.
+   *
+   * If [propagatedType] is given, also validate's the identifier's propagated
+   * type.
+   */
+  void _expectIdentifierType(String name, type, [propagatedType]) {
+    SimpleIdentifier identifier = _findIdentifier(name);
+    _expectType(identifier.staticType, type);
+    if (propagatedType != null) {
+      _expectType(identifier.propagatedType, propagatedType);
+    }
+  }
+
+  /**
+   * Looks up the initializer for the declaration containing [identifier] and
+   * validates its static [type].
+   *
+   * If [type] is a string, validates that the identifier's static type
+   * stringifies to that text. Otherwise, [type] is used directly a [Matcher]
+   * to match the type.
+   *
+   * If [propagatedType] is given, also validate's the identifier's propagated
+   * type.
+   */
+  void _expectInitializerType(String name, type, [propagatedType]) {
+    SimpleIdentifier identifier = _findIdentifier(name);
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    Expression initializer = declaration.initializer;
+    _expectType(initializer.staticType, type);
+    if (propagatedType != null) {
+      _expectType(initializer.propagatedType, propagatedType);
+    }
+  }
+
+  /**
+   * Validates that [type] matches [expected].
+   *
+   * If [expected] is a string, validates that the type stringifies to that
+   * text. Otherwise, [expected] is used directly a [Matcher] to match the type.
+   */
+  _expectType(DartType type, expected) {
+    if (expected is String) {
+      expect(type.toString(), expected);
+    } else {
+      expect(type, expected);
+    }
+  }
+
   SimpleIdentifier _findIdentifier(String search) {
     SimpleIdentifier identifier = EngineTestCase.findNode(
         testUnit, testCode, search, (node) => node is SimpleIdentifier);
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index d0d8949..071231e 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -4,8 +4,11 @@
 
 library analyzer.test.generated.scanner_test;
 
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index 2c1e2d2..137deb5 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -6,7 +6,9 @@
 
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_core.dart' show formatList;
 import 'package:analyzer/src/generated/source_io.dart';
+import 'package:unittest/unittest.dart';
 
 import '../reflective_tests.dart';
 import '../utils.dart';
@@ -15,6 +17,7 @@
 main() {
   initializeTestEnvironment();
   runReflectiveTests(StaticTypeWarningCodeTest);
+  runReflectiveTests(StrongModeStaticTypeWarningCodeTest);
 }
 
 @reflectiveTest
@@ -27,6 +30,79 @@
     verify([source]);
   }
 
+  void fail_method_lookup_mixin_of_extends() {
+    // See dartbug.com/25605
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource('''
+class A { a() => null; }
+class B {}
+abstract class M extends A {}
+class T = B with M; // Warning: B does not extend A
+main() {
+  new T().a(); // Warning: The method 'a' is not defined for the class 'T'
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      // TODO(paulberry): when dartbug.com/25614 is fixed, add static warning
+      // code for "B does not extend A".
+      StaticTypeWarningCode.UNDEFINED_METHOD
+    ]);
+  }
+
+  void fail_method_lookup_mixin_of_implements() {
+    // See dartbug.com/25605
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource('''
+class A { a() => null; }
+class B {}
+abstract class M implements A {}
+class T = B with M; // Warning: Missing concrete implementation of 'A.a'
+main() {
+  new T().a(); // Warning: The method 'a' is not defined for the class 'T'
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE,
+      StaticTypeWarningCode.UNDEFINED_METHOD
+    ]);
+  }
+
+  void fail_method_lookup_mixin_of_mixin() {
+    // See dartbug.com/25605
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource('''
+class A {}
+class B { b() => null; }
+class C {}
+class M extends A with B {}
+class T = C with M;
+main() {
+  new T().b();
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
+  }
+
+  void fail_method_lookup_mixin_of_mixin_application() {
+    // See dartbug.com/25605
+    resetWithOptions(new AnalysisOptionsImpl()..enableSuperMixins = true);
+    Source source = addSource('''
+class A { a() => null; }
+class B {}
+class C {}
+class M = A with B;
+class T = C with M;
+main() {
+  new T().a();
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [StaticTypeWarningCode.UNDEFINED_METHOD]);
+  }
+
   void fail_undefinedEnumConstant() {
     // We need a way to set the parseEnum flag in the parser to true.
     Source source = addSource(r'''
@@ -627,6 +703,16 @@
     verify([source]);
   }
 
+  void test_nonBoolCondition_for() {
+    Source source = addSource(r'''
+f() {
+  for (;3;) {}
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [StaticTypeWarningCode.NON_BOOL_CONDITION]);
+    verify([source]);
+  }
+
   void test_nonBoolCondition_if() {
     Source source = addSource(r'''
 f() {
@@ -2080,3 +2166,33 @@
     verify([source]);
   }
 }
+
+@reflectiveTest
+class StrongModeStaticTypeWarningCodeTest extends ResolverTestCase {
+  void setUp() {
+    super.setUp();
+    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+    options.strongMode = true;
+    resetWithOptions(options);
+  }
+
+  void test_genericMethodWrongNumberOfTypeArguments() {
+    Source source = addSource('''
+f() {}
+main() {
+  f/*<int>*/();
+}
+''');
+    computeLibrarySourceErrors(source);
+    assertErrors(
+        source, [StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS]);
+    for (AnalysisError error in analysisContext2.computeErrors(source)) {
+      if (error.errorCode ==
+          StaticTypeWarningCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS) {
+        expect(error.message,
+            formatList(error.errorCode.message, ['() → dynamic', 0, 1]));
+      }
+    }
+    verify([source]);
+  }
+}
diff --git a/pkg/analyzer/test/generated/static_warning_code_test.dart b/pkg/analyzer/test/generated/static_warning_code_test.dart
index eb6aa8b..02c44b8 100644
--- a/pkg/analyzer/test/generated/static_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_warning_code_test.dart
@@ -3616,4 +3616,22 @@
     computeLibrarySourceErrors(source);
     assertErrors(source, [StaticWarningCode.VOID_RETURN_FOR_GETTER]);
   }
+
+  void test_missingEnumConstantInSwitch() {
+    Source source = addSource(r'''
+enum E { ONE, TWO, THREE, FOUR }
+bool odd(E e) {
+  switch (e) {
+    case E.ONE:
+    case E.THREE: return true;
+  }
+  return false;
+}''');
+    computeLibrarySourceErrors(source);
+    assertErrors(source, [
+      StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH,
+      StaticWarningCode.MISSING_ENUM_CONSTANT_IN_SWITCH
+    ]);
+    verify([source]);
+  }
 }
diff --git a/pkg/analyzer/test/generated/test_all.dart b/pkg/analyzer/test/generated/test_all.dart
index e737b56..4785daf 100644
--- a/pkg/analyzer/test/generated/test_all.dart
+++ b/pkg/analyzer/test/generated/test_all.dart
@@ -8,10 +8,11 @@
 
 import '../utils.dart';
 import 'all_the_rest_test.dart' as all_the_rest;
-import 'ast_test.dart' as ast_test;
 import 'compile_time_error_code_test.dart' as compile_time_error_code_test;
+import 'constant_test.dart' as constant_test;
 import 'declaration_resolver_test.dart' as declaration_resolver_test;
 import 'engine_test.dart' as engine_test;
+import 'error_suppression_test.dart' as error_suppression_test;
 import 'incremental_resolver_test.dart' as incremental_resolver_test;
 import 'incremental_scanner_test.dart' as incremental_scanner_test;
 import 'java_core_test.dart' as java_core_test;
@@ -31,10 +32,11 @@
   initializeTestEnvironment();
   group('generated tests', () {
     all_the_rest.main();
-    ast_test.main();
     compile_time_error_code_test.main();
+    constant_test.main();
     declaration_resolver_test.main();
     engine_test.main();
+    error_suppression_test.main();
     incremental_resolver_test.main();
     incremental_scanner_test.main();
     java_core_test.main();
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 87b1282..239c42b 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -6,10 +6,10 @@
 
 import 'dart:collection';
 
+import 'package:analyzer/dart/ast/ast.dart' show AstNode, SimpleIdentifier;
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart'
-    show AstNode, NodeLocator, SimpleIdentifier;
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_core.dart';
@@ -423,9 +423,9 @@
    */
   bool _equalErrors(AnalysisError firstError, AnalysisError secondError) =>
       identical(firstError.errorCode, secondError.errorCode) &&
-          firstError.offset == secondError.offset &&
-          firstError.length == secondError.length &&
-          _equalSources(firstError.source, secondError.source);
+      firstError.offset == secondError.offset &&
+      firstError.length == secondError.length &&
+      _equalSources(firstError.source, secondError.source);
 
   /**
    * Return `true` if the two sources are equivalent.
@@ -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;
@@ -646,6 +644,8 @@
   TestSourceWithUri(String path, this.uri, [String content])
       : super(path, content);
 
+  String get encoding => uri.toString();
+
   UriKind get uriKind {
     if (uri == null) {
       return UriKind.FILE_URI;
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index 6486b63..20d1a821 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -20,10 +20,10 @@
 
 main() {
   initializeTestEnvironment();
-  runReflectiveTests(TypeSystemTest);
-  runReflectiveTests(StrongSubtypingTest);
   runReflectiveTests(StrongAssignabilityTest);
+  runReflectiveTests(StrongSubtypingTest);
   runReflectiveTests(StrongGenericFunctionInferenceTest);
+  runReflectiveTests(LeastUpperBoundTest);
 }
 
 @reflectiveTest
@@ -467,6 +467,27 @@
         [intType]);
   }
 
+  void test_returnTypeFromContext() {
+    // <T>() -> T
+    var t = TypeBuilder.variable('T');
+    var f = TypeBuilder.function(types: [t], required: [], result: t);
+    expect(_inferCall(f, [], stringType), [stringType]);
+  }
+
+  void test_returnTypeWithBoundFromContext() {
+    // <T extends num>() -> T
+    var t = TypeBuilder.variable('T', bound: numType);
+    var f = TypeBuilder.function(types: [t], required: [], result: t);
+    expect(_inferCall(f, [], doubleType), [doubleType]);
+  }
+
+  void test_returnTypeWithBoundFromInvalidContext() {
+    // <T extends num>() -> T
+    var t = TypeBuilder.variable('T', bound: numType);
+    var f = TypeBuilder.function(types: [t], required: [], result: t);
+    expect(_inferCall(f, [], stringType), [numType]);
+  }
+
   void test_unifyParametersToFunctionParam() {
     // <T>(f(T t), g(T t)) -> T
     var t = TypeBuilder.variable('T');
@@ -498,9 +519,10 @@
     expect(_inferCall(f, []), [numType]);
   }
 
-  List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments) {
-    FunctionType inferred = typeSystem.inferCallFromArguments(
-        typeProvider, ft, ft.parameters.map((p) => p.type).toList(), arguments);
+  List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments,
+      [DartType returnType]) {
+    FunctionType inferred = typeSystem.inferGenericFunctionCall(typeProvider,
+        ft, ft.parameters.map((p) => p.type).toList(), arguments, returnType);
     return inferred.typeArguments;
   }
 }
@@ -903,7 +925,7 @@
 }
 
 @reflectiveTest
-class TypeSystemTest {
+class LeastUpperBoundTest {
   TypeProvider typeProvider;
   TypeSystem typeSystem;
   FunctionType simpleFunctionType;
@@ -929,21 +951,21 @@
     simpleFunctionType = typeAlias.type;
   }
 
-  void test_getLeastUpperBound_bottom_function() {
+  void test_bottom_function() {
     _checkLeastUpperBound(bottomType, simpleFunctionType, simpleFunctionType);
   }
 
-  void test_getLeastUpperBound_bottom_interface() {
+  void test_bottom_interface() {
     DartType interfaceType = ElementFactory.classElement2('A', []).type;
     _checkLeastUpperBound(bottomType, interfaceType, interfaceType);
   }
 
-  void test_getLeastUpperBound_bottom_typeParam() {
+  void test_bottom_typeParam() {
     DartType typeParam = ElementFactory.typeParameterElement('T').type;
     _checkLeastUpperBound(bottomType, typeParam, typeParam);
   }
 
-  void test_getLeastUpperBound_directInterfaceCase() {
+  void test_directInterfaceCase() {
     //
     // class A
     // class B implements A
@@ -960,7 +982,7 @@
     _checkLeastUpperBound(typeB, typeC, typeB);
   }
 
-  void test_getLeastUpperBound_directSubclassCase() {
+  void test_directSubclassCase() {
     //
     // class A
     // class B extends A
@@ -974,34 +996,34 @@
     _checkLeastUpperBound(typeB, typeC, typeB);
   }
 
-  void test_getLeastUpperBound_dynamic_bottom() {
+  void test_dynamic_bottom() {
     _checkLeastUpperBound(dynamicType, bottomType, dynamicType);
   }
 
-  void test_getLeastUpperBound_dynamic_function() {
+  void test_dynamic_function() {
     _checkLeastUpperBound(dynamicType, simpleFunctionType, dynamicType);
   }
 
-  void test_getLeastUpperBound_dynamic_interface() {
+  void test_dynamic_interface() {
     DartType interfaceType = ElementFactory.classElement2('A', []).type;
     _checkLeastUpperBound(dynamicType, interfaceType, dynamicType);
   }
 
-  void test_getLeastUpperBound_dynamic_typeParam() {
+  void test_dynamic_typeParam() {
     DartType typeParam = ElementFactory.typeParameterElement('T').type;
     _checkLeastUpperBound(dynamicType, typeParam, dynamicType);
   }
 
-  void test_getLeastUpperBound_dynamic_void() {
+  void test_dynamic_void() {
     _checkLeastUpperBound(dynamicType, voidType, dynamicType);
   }
 
-  void test_getLeastUpperBound_interface_function() {
+  void test_interface_function() {
     DartType interfaceType = ElementFactory.classElement2('A', []).type;
     _checkLeastUpperBound(interfaceType, simpleFunctionType, objectType);
   }
 
-  void test_getLeastUpperBound_mixinCase() {
+  void test_mixinCase() {
     //
     // class A
     // class B extends A
@@ -1024,7 +1046,7 @@
     _checkLeastUpperBound(typeD, typeC, typeA);
   }
 
-  void test_getLeastUpperBound_object() {
+  void test_object() {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB = ElementFactory.classElement2("B");
     InterfaceType typeA = classA.type;
@@ -1038,29 +1060,25 @@
     _checkLeastUpperBound(typeA, typeB, typeObject);
   }
 
-  void test_getLeastUpperBound_self() {
+  void test_self() {
     DartType typeParam = ElementFactory.typeParameterElement('T').type;
     DartType interfaceType = ElementFactory.classElement2('A', []).type;
-    expect(
-        typeSystem.getLeastUpperBound(typeProvider, dynamicType, dynamicType),
-        dynamicType);
-    expect(typeSystem.getLeastUpperBound(typeProvider, voidType, voidType),
-        voidType);
-    expect(typeSystem.getLeastUpperBound(typeProvider, bottomType, bottomType),
-        bottomType);
-    expect(typeSystem.getLeastUpperBound(typeProvider, typeParam, typeParam),
-        typeParam);
-    expect(
-        typeSystem.getLeastUpperBound(
-            typeProvider, interfaceType, interfaceType),
-        interfaceType);
-    expect(
-        typeSystem.getLeastUpperBound(
-            typeProvider, simpleFunctionType, simpleFunctionType),
-        simpleFunctionType);
+
+    List<DartType> types = [
+      dynamicType,
+      voidType,
+      bottomType,
+      typeParam,
+      interfaceType,
+      simpleFunctionType
+    ];
+
+    for (DartType type in types) {
+      _checkLeastUpperBound(type, type, type);
+    }
   }
 
-  void test_getLeastUpperBound_sharedSuperclass1() {
+  void test_sharedSuperclass1() {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
     ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
@@ -1070,7 +1088,7 @@
     _checkLeastUpperBound(typeB, typeC, typeA);
   }
 
-  void test_getLeastUpperBound_sharedSuperclass2() {
+  void test_sharedSuperclass2() {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
     ClassElementImpl classC = ElementFactory.classElement("C", classA.type);
@@ -1081,7 +1099,7 @@
     _checkLeastUpperBound(typeB, typeD, typeA);
   }
 
-  void test_getLeastUpperBound_sharedSuperclass3() {
+  void test_sharedSuperclass3() {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB = ElementFactory.classElement("B", classA.type);
     ClassElementImpl classC = ElementFactory.classElement("C", classB.type);
@@ -1092,7 +1110,7 @@
     _checkLeastUpperBound(typeC, typeD, typeB);
   }
 
-  void test_getLeastUpperBound_sharedSuperclass4() {
+  void test_sharedSuperclass4() {
     ClassElement classA = ElementFactory.classElement2("A");
     ClassElement classA2 = ElementFactory.classElement2("A2");
     ClassElement classA3 = ElementFactory.classElement2("A3");
@@ -1108,7 +1126,7 @@
     _checkLeastUpperBound(typeB, typeC, typeA);
   }
 
-  void test_getLeastUpperBound_sharedSuperinterface1() {
+  void test_sharedSuperinterface1() {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB = ElementFactory.classElement2("B");
     ClassElementImpl classC = ElementFactory.classElement2("C");
@@ -1120,7 +1138,7 @@
     _checkLeastUpperBound(typeB, typeC, typeA);
   }
 
-  void test_getLeastUpperBound_sharedSuperinterface2() {
+  void test_sharedSuperinterface2() {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB = ElementFactory.classElement2("B");
     ClassElementImpl classC = ElementFactory.classElement2("C");
@@ -1135,7 +1153,7 @@
     _checkLeastUpperBound(typeB, typeD, typeA);
   }
 
-  void test_getLeastUpperBound_sharedSuperinterface3() {
+  void test_sharedSuperinterface3() {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB = ElementFactory.classElement2("B");
     ClassElementImpl classC = ElementFactory.classElement2("C");
@@ -1150,7 +1168,7 @@
     _checkLeastUpperBound(typeC, typeD, typeB);
   }
 
-  void test_getLeastUpperBound_sharedSuperinterface4() {
+  void test_sharedSuperinterface4() {
     ClassElement classA = ElementFactory.classElement2("A");
     ClassElement classA2 = ElementFactory.classElement2("A2");
     ClassElement classA3 = ElementFactory.classElement2("A3");
@@ -1166,11 +1184,11 @@
     _checkLeastUpperBound(typeB, typeC, typeA);
   }
 
-  void test_getLeastUpperBound_twoComparables() {
+  void test_twoComparables() {
     _checkLeastUpperBound(stringType, numType, objectType);
   }
 
-  void test_getLeastUpperBound_typeParam_function_bounded() {
+  void test_typeParam_function_bounded() {
     DartType typeA = ElementFactory.classElement('A', functionType).type;
     TypeParameterElementImpl typeParamElement =
         ElementFactory.typeParameterElement('T');
@@ -1179,12 +1197,12 @@
     _checkLeastUpperBound(typeParam, simpleFunctionType, functionType);
   }
 
-  void test_getLeastUpperBound_typeParam_function_noBound() {
+  void test_typeParam_function_noBound() {
     DartType typeParam = ElementFactory.typeParameterElement('T').type;
     _checkLeastUpperBound(typeParam, simpleFunctionType, objectType);
   }
 
-  void test_getLeastUpperBound_typeParam_interface_bounded() {
+  void test_typeParam_interface_bounded() {
     DartType typeA = ElementFactory.classElement2('A', []).type;
     DartType typeB = ElementFactory.classElement('B', typeA).type;
     DartType typeC = ElementFactory.classElement('C', typeA).type;
@@ -1195,13 +1213,13 @@
     _checkLeastUpperBound(typeParam, typeC, typeA);
   }
 
-  void test_getLeastUpperBound_typeParam_interface_noBound() {
+  void test_typeParam_interface_noBound() {
     DartType typeParam = ElementFactory.typeParameterElement('T').type;
     DartType interfaceType = ElementFactory.classElement2('A', []).type;
     _checkLeastUpperBound(typeParam, interfaceType, objectType);
   }
 
-  void test_getLeastUpperBound_typeParameters_different() {
+  void test_typeParameters_different() {
     //
     // class List<int>
     // class List<double>
@@ -1212,7 +1230,7 @@
     _checkLeastUpperBound(listOfIntType, listOfDoubleType, objectType);
   }
 
-  void test_getLeastUpperBound_typeParameters_same() {
+  void test_typeParameters_same() {
     //
     // List<int>
     // List<int>
@@ -1224,24 +1242,106 @@
         listOfIntType);
   }
 
-  void test_getLeastUpperBound_void_bottom() {
+  void test_void_bottom() {
     _checkLeastUpperBound(voidType, bottomType, voidType);
   }
 
-  void test_getLeastUpperBound_void_function() {
+  void test_void_function() {
     _checkLeastUpperBound(voidType, simpleFunctionType, voidType);
   }
 
-  void test_getLeastUpperBound_void_interface() {
+  void test_void_interface() {
     DartType interfaceType = ElementFactory.classElement2('A', []).type;
     _checkLeastUpperBound(voidType, interfaceType, voidType);
   }
 
-  void test_getLeastUpperBound_void_typeParam() {
+  void test_void_typeParam() {
     DartType typeParam = ElementFactory.typeParameterElement('T').type;
     _checkLeastUpperBound(voidType, typeParam, voidType);
   }
 
+  void test_functionsSameType() {
+    FunctionType type1 = _functionType([stringType, intType, numType],
+        optional: [doubleType], named: {'n': numType}, returns: intType);
+    FunctionType type2 = _functionType([stringType, intType, numType],
+        optional: [doubleType], named: {'n': numType}, returns: intType);
+    FunctionType expected = _functionType([stringType, intType, numType],
+        optional: [doubleType], named: {'n': numType}, returns: intType);
+    _checkLeastUpperBound(type1, type2, expected);
+  }
+
+  void test_functionsDifferentRequiredArity() {
+    FunctionType type1 = _functionType([intType, intType]);
+    FunctionType type2 = _functionType([intType, intType, intType]);
+    _checkLeastUpperBound(type1, type2, functionType);
+  }
+
+  void test_functionsLubRequiredParams() {
+    FunctionType type1 = _functionType([stringType, intType, intType]);
+    FunctionType type2 = _functionType([intType, doubleType, numType]);
+    FunctionType expected = _functionType([objectType, numType, numType]);
+    _checkLeastUpperBound(type1, type2, expected);
+  }
+
+  void test_functionsLubPositionalParams() {
+    FunctionType type1 = _functionType([], optional: [stringType, intType]);
+    FunctionType type2 = _functionType([], optional: [intType, doubleType]);
+    FunctionType expected = _functionType([], optional: [objectType, numType]);
+    _checkLeastUpperBound(type1, type2, expected);
+  }
+
+  void test_functionsIgnoreExtraPositionalParams() {
+    FunctionType type1 =
+        _functionType([], optional: [intType, intType, stringType]);
+    FunctionType type2 = _functionType([], optional: [doubleType]);
+    FunctionType expected = _functionType([], optional: [numType]);
+    _checkLeastUpperBound(type1, type2, expected);
+  }
+
+  void test_functionsLubNamedParams() {
+    FunctionType type1 =
+        _functionType([], named: {'a': stringType, 'b': intType});
+    FunctionType type2 =
+        _functionType([], named: {'a': intType, 'b': doubleType});
+    FunctionType expected =
+        _functionType([], named: {'a': objectType, 'b': numType});
+    _checkLeastUpperBound(type1, type2, expected);
+  }
+
+  void test_functionsIgnoreExtraNamedParams() {
+    FunctionType type1 = _functionType([], named: {'a': intType, 'b': intType});
+    FunctionType type2 =
+        _functionType([], named: {'a': doubleType, 'c': doubleType});
+    FunctionType expected = _functionType([], named: {'a': numType});
+    _checkLeastUpperBound(type1, type2, expected);
+  }
+
+  void test_functionsLubReturnType() {
+    FunctionType type1 = _functionType([], returns: intType);
+    FunctionType type2 = _functionType([], returns: doubleType);
+
+    FunctionType expected = _functionType([], returns: numType);
+    _checkLeastUpperBound(type1, type2, expected);
+  }
+
+  /**
+   * Creates a function type with the given parameter and return types.
+   *
+   * The return type defaults to `void` if omitted.
+   */
+  FunctionType _functionType(List<DartType> required,
+      {List<DartType> optional,
+      Map<String, DartType> named,
+      DartType returns}) {
+    if (returns == null) {
+      returns = voidType;
+    }
+
+    return ElementFactory
+        .functionElement8(required, returns, optional: optional, named: named)
+        .type;
+  }
+
   void _checkLeastUpperBound(
       DartType type1, DartType type2, DartType expectedResult) {
     expect(typeSystem.getLeastUpperBound(typeProvider, type1, type2),
diff --git a/pkg/analyzer/test/generated/utilities_test.dart b/pkg/analyzer/test/generated/utilities_test.dart
index bd5876b..f6f898a 100644
--- a/pkg/analyzer/test/generated/utilities_test.dart
+++ b/pkg/analyzer/test/generated/utilities_test.dart
@@ -6,10 +6,15 @@
 
 import 'dart:collection';
 
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
@@ -28,7 +33,6 @@
   runReflectiveTests(SourceRangeTest);
   runReflectiveTests(BooleanArrayTest);
   runReflectiveTests(DirectedGraphTest);
-  runReflectiveTests(ListUtilitiesTest);
   runReflectiveTests(MultipleMapIteratorTest);
   runReflectiveTests(SingleMapIteratorTest);
   runReflectiveTests(TokenMapTest);
@@ -62,1663 +66,1046 @@
 @reflectiveTest
 class AstClonerTest extends EngineTestCase {
   void test_visitAdjacentStrings() {
-    _assertClone(AstFactory
-        .adjacentStrings([AstFactory.string2("a"), AstFactory.string2("b")]));
+    _assertCloneExpression("'a' 'b'");
   }
 
   void test_visitAnnotation_constant() {
-    _assertClone(AstFactory.annotation(AstFactory.identifier3("A")));
+    _assertCloneUnitMember('@A main() {}');
   }
 
   void test_visitAnnotation_constructor() {
-    _assertClone(AstFactory.annotation2(AstFactory.identifier3("A"),
-        AstFactory.identifier3("c"), AstFactory.argumentList()));
+    _assertCloneUnitMember('@A.c() main() {}');
   }
 
   void test_visitArgumentList() {
-    _assertClone(AstFactory.argumentList(
-        [AstFactory.identifier3("a"), AstFactory.identifier3("b")]));
+    _assertCloneExpression('m(a, b)');
   }
 
   void test_visitAsExpression() {
-    _assertClone(AstFactory.asExpression(
-        AstFactory.identifier3("e"), AstFactory.typeName4("T")));
+    _assertCloneExpression('e as T');
   }
 
   void test_visitAssertStatement() {
-    _assertClone(AstFactory.assertStatement(AstFactory.identifier3("a")));
+    _assertCloneStatement('assert(a);');
   }
 
   void test_visitAssignmentExpression() {
-    _assertClone(AstFactory.assignmentExpression(AstFactory.identifier3("a"),
-        TokenType.EQ, AstFactory.identifier3("b")));
+    _assertCloneStatement('a = b;');
   }
 
   void test_visitAwaitExpression() {
-    _assertClone(AstFactory.awaitExpression(AstFactory.identifier3("a")));
+    _assertCloneStatement('await a;');
   }
 
   void test_visitBinaryExpression() {
-    _assertClone(AstFactory.binaryExpression(AstFactory.identifier3("a"),
-        TokenType.PLUS, AstFactory.identifier3("b")));
+    _assertCloneExpression('a + b');
   }
 
   void test_visitBlock_empty() {
-    _assertClone(AstFactory.block());
+    _assertCloneStatement('{}');
   }
 
   void test_visitBlock_nonEmpty() {
-    _assertClone(AstFactory
-        .block([AstFactory.breakStatement(), AstFactory.breakStatement()]));
+    _assertCloneStatement('{ print(1); print(2); }');
   }
 
   void test_visitBlockFunctionBody() {
-    _assertClone(AstFactory.blockFunctionBody2());
+    _assertCloneUnitMember('main() {}');
   }
 
   void test_visitBooleanLiteral_false() {
-    _assertClone(AstFactory.booleanLiteral(false));
+    _assertCloneExpression('false');
   }
 
   void test_visitBooleanLiteral_true() {
-    _assertClone(AstFactory.booleanLiteral(true));
+    _assertCloneExpression('true');
   }
 
   void test_visitBreakStatement_label() {
-    _assertClone(AstFactory.breakStatement2("l"));
+    _assertCloneStatement('l: while(true) { break l; }');
   }
 
   void test_visitBreakStatement_noLabel() {
-    _assertClone(AstFactory.breakStatement());
+    _assertCloneStatement('while(true) { break; }');
   }
 
   void test_visitCascadeExpression_field() {
-    _assertClone(AstFactory.cascadeExpression(AstFactory.identifier3("a"), [
-      AstFactory.cascadedPropertyAccess("b"),
-      AstFactory.cascadedPropertyAccess("c")
-    ]));
+    _assertCloneExpression('a..b..c');
   }
 
   void test_visitCascadeExpression_index() {
-    _assertClone(AstFactory.cascadeExpression(AstFactory.identifier3("a"), [
-      AstFactory.cascadedIndexExpression(AstFactory.integer(0)),
-      AstFactory.cascadedIndexExpression(AstFactory.integer(1))
-    ]));
+    _assertCloneExpression('a..[0]..[1]');
   }
 
   void test_visitCascadeExpression_method() {
-    _assertClone(AstFactory.cascadeExpression(AstFactory.identifier3("a"), [
-      AstFactory.cascadedMethodInvocation("b"),
-      AstFactory.cascadedMethodInvocation("c")
-    ]));
+    _assertCloneExpression('a..b()..c()');
   }
 
   void test_visitCatchClause_catch_noStack() {
-    _assertClone(AstFactory.catchClause("e"));
+    _assertCloneStatement('try {} catch (e) {}');
   }
 
   void test_visitCatchClause_catch_stack() {
-    _assertClone(AstFactory.catchClause2("e", "s"));
+    _assertCloneStatement('try {} catch (e, s) {}');
   }
 
   void test_visitCatchClause_on() {
-    _assertClone(AstFactory.catchClause3(AstFactory.typeName4("E")));
+    _assertCloneStatement('try {} on E {}');
   }
 
   void test_visitCatchClause_on_catch() {
-    _assertClone(AstFactory.catchClause4(AstFactory.typeName4("E"), "e"));
+    _assertCloneStatement('try {} on E catch (e) {}');
   }
 
   void test_visitClassDeclaration_abstract() {
-    _assertClone(AstFactory.classDeclaration(
-        Keyword.ABSTRACT, "C", null, null, null, null));
+    _assertCloneUnitMember('abstract class C {}');
   }
 
   void test_visitClassDeclaration_empty() {
-    _assertClone(
-        AstFactory.classDeclaration(null, "C", null, null, null, null));
+    _assertCloneUnitMember('class C {}');
   }
 
   void test_visitClassDeclaration_extends() {
-    _assertClone(AstFactory.classDeclaration(null, "C", null,
-        AstFactory.extendsClause(AstFactory.typeName4("A")), null, null));
+    _assertCloneUnitMember('class C extends A {}');
   }
 
   void test_visitClassDeclaration_extends_implements() {
-    _assertClone(AstFactory.classDeclaration(
-        null,
-        "C",
-        null,
-        AstFactory.extendsClause(AstFactory.typeName4("A")),
-        null,
-        AstFactory.implementsClause([AstFactory.typeName4("B")])));
+    _assertCloneUnitMember('class C extends A implements B {}');
   }
 
   void test_visitClassDeclaration_extends_with() {
-    _assertClone(AstFactory.classDeclaration(
-        null,
-        "C",
-        null,
-        AstFactory.extendsClause(AstFactory.typeName4("A")),
-        AstFactory.withClause([AstFactory.typeName4("M")]),
-        null));
+    _assertCloneUnitMember('class C extends A with M {}');
   }
 
   void test_visitClassDeclaration_extends_with_implements() {
-    _assertClone(AstFactory.classDeclaration(
-        null,
-        "C",
-        null,
-        AstFactory.extendsClause(AstFactory.typeName4("A")),
-        AstFactory.withClause([AstFactory.typeName4("M")]),
-        AstFactory.implementsClause([AstFactory.typeName4("B")])));
+    _assertCloneUnitMember('class C extends A with M implements B {}');
   }
 
   void test_visitClassDeclaration_implements() {
-    _assertClone(AstFactory.classDeclaration(null, "C", null, null, null,
-        AstFactory.implementsClause([AstFactory.typeName4("B")])));
+    _assertCloneUnitMember('class C implements B {}');
   }
 
   void test_visitClassDeclaration_multipleMember() {
-    _assertClone(
-        AstFactory.classDeclaration(null, "C", null, null, null, null, [
-      AstFactory.fieldDeclaration2(
-          false, Keyword.VAR, [AstFactory.variableDeclaration("a")]),
-      AstFactory.fieldDeclaration2(
-          false, Keyword.VAR, [AstFactory.variableDeclaration("b")])
-    ]));
+    _assertCloneUnitMember('class C { var a;  var b; }');
   }
 
   void test_visitClassDeclaration_parameters() {
-    _assertClone(AstFactory.classDeclaration(
-        null, "C", AstFactory.typeParameterList(["E"]), null, null, null));
+    _assertCloneUnitMember('class C<E> {}');
   }
 
   void test_visitClassDeclaration_parameters_extends() {
-    _assertClone(AstFactory.classDeclaration(
-        null,
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        AstFactory.extendsClause(AstFactory.typeName4("A")),
-        null,
-        null));
+    _assertCloneUnitMember('class C<E> extends A {}');
   }
 
   void test_visitClassDeclaration_parameters_extends_implements() {
-    _assertClone(AstFactory.classDeclaration(
-        null,
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        AstFactory.extendsClause(AstFactory.typeName4("A")),
-        null,
-        AstFactory.implementsClause([AstFactory.typeName4("B")])));
+    _assertCloneUnitMember('class C<E> extends A implements B {}');
   }
 
   void test_visitClassDeclaration_parameters_extends_with() {
-    _assertClone(AstFactory.classDeclaration(
-        null,
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        AstFactory.extendsClause(AstFactory.typeName4("A")),
-        AstFactory.withClause([AstFactory.typeName4("M")]),
-        null));
+    _assertCloneUnitMember('class C<E> extends A with M {}');
   }
 
   void test_visitClassDeclaration_parameters_extends_with_implements() {
-    _assertClone(AstFactory.classDeclaration(
-        null,
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        AstFactory.extendsClause(AstFactory.typeName4("A")),
-        AstFactory.withClause([AstFactory.typeName4("M")]),
-        AstFactory.implementsClause([AstFactory.typeName4("B")])));
+    _assertCloneUnitMember('class C<E> extends A with M implements B {}');
   }
 
   void test_visitClassDeclaration_parameters_implements() {
-    _assertClone(AstFactory.classDeclaration(
-        null,
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        null,
-        null,
-        AstFactory.implementsClause([AstFactory.typeName4("B")])));
+    _assertCloneUnitMember('class C<E> implements B {}');
   }
 
   void test_visitClassDeclaration_singleMember() {
-    _assertClone(
-        AstFactory.classDeclaration(null, "C", null, null, null, null, [
-      AstFactory.fieldDeclaration2(
-          false, Keyword.VAR, [AstFactory.variableDeclaration("a")])
-    ]));
+    _assertCloneUnitMember('class C { var a; }');
   }
 
   void test_visitClassDeclaration_withMetadata() {
-    ClassDeclaration declaration =
-        AstFactory.classDeclaration(null, "C", null, null, null, null);
-    declaration.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(declaration);
+    _assertCloneUnitMember('@deprecated class C {}');
   }
 
   void test_visitClassTypeAlias_abstract() {
-    _assertClone(AstFactory.classTypeAlias(
-        "C",
-        null,
-        Keyword.ABSTRACT,
-        AstFactory.typeName4("S"),
-        AstFactory.withClause([AstFactory.typeName4("M1")]),
-        null));
+    _assertCloneUnitMember('abstract class C = S with M1;');
   }
 
   void test_visitClassTypeAlias_abstract_implements() {
-    _assertClone(AstFactory.classTypeAlias(
-        "C",
-        null,
-        Keyword.ABSTRACT,
-        AstFactory.typeName4("S"),
-        AstFactory.withClause([AstFactory.typeName4("M1")]),
-        AstFactory.implementsClause([AstFactory.typeName4("I")])));
+    _assertCloneUnitMember('abstract class C = S with M1 implements I;');
   }
 
   void test_visitClassTypeAlias_generic() {
-    _assertClone(AstFactory.classTypeAlias(
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        null,
-        AstFactory.typeName4("S", [AstFactory.typeName4("E")]),
-        AstFactory.withClause([
-          AstFactory.typeName4("M1", [AstFactory.typeName4("E")])
-        ]),
-        null));
+    _assertCloneUnitMember('class C<E> = S<E> with M1<E>;');
   }
 
   void test_visitClassTypeAlias_implements() {
-    _assertClone(AstFactory.classTypeAlias(
-        "C",
-        null,
-        null,
-        AstFactory.typeName4("S"),
-        AstFactory.withClause([AstFactory.typeName4("M1")]),
-        AstFactory.implementsClause([AstFactory.typeName4("I")])));
+    _assertCloneUnitMember('class C = S with M1 implements I;');
   }
 
   void test_visitClassTypeAlias_minimal() {
-    _assertClone(AstFactory.classTypeAlias(
-        "C",
-        null,
-        null,
-        AstFactory.typeName4("S"),
-        AstFactory.withClause([AstFactory.typeName4("M1")]),
-        null));
+    _assertCloneUnitMember('class C = S with M1;');
   }
 
   void test_visitClassTypeAlias_parameters_abstract() {
-    _assertClone(AstFactory.classTypeAlias(
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        Keyword.ABSTRACT,
-        AstFactory.typeName4("S"),
-        AstFactory.withClause([AstFactory.typeName4("M1")]),
-        null));
+    _assertCloneUnitMember('abstract class C = S<E> with M1;');
   }
 
   void test_visitClassTypeAlias_parameters_abstract_implements() {
-    _assertClone(AstFactory.classTypeAlias(
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        Keyword.ABSTRACT,
-        AstFactory.typeName4("S"),
-        AstFactory.withClause([AstFactory.typeName4("M1")]),
-        AstFactory.implementsClause([AstFactory.typeName4("I")])));
+    _assertCloneUnitMember('abstract class C = S<E> with M1 implements I;');
   }
 
   void test_visitClassTypeAlias_parameters_implements() {
-    _assertClone(AstFactory.classTypeAlias(
-        "C",
-        AstFactory.typeParameterList(["E"]),
-        null,
-        AstFactory.typeName4("S"),
-        AstFactory.withClause([AstFactory.typeName4("M1")]),
-        AstFactory.implementsClause([AstFactory.typeName4("I")])));
+    _assertCloneUnitMember('class C = S<E> with M1 implements I;');
   }
 
   void test_visitClassTypeAlias_withMetadata() {
-    ClassTypeAlias declaration = AstFactory.classTypeAlias(
-        "C",
-        null,
-        null,
-        AstFactory.typeName4("S"),
-        AstFactory.withClause([AstFactory.typeName4("M1")]),
-        null);
-    declaration.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(declaration);
+    _assertCloneUnitMember('@deprecated class C = S with M;');
   }
 
   void test_visitComment() {
-    _assertClone(Comment.createBlockComment(
-        <Token>[TokenFactory.tokenFromString("/* comment */")]));
+    _assertCloneUnitMember('main() { print(1);  /* comment */  print(2); }');
+  }
+
+  void test_visitComment_beginToken() {
+    _assertCloneUnitMember('/** comment */ main() {}');
   }
 
   void test_visitCommentReference() {
-    _assertClone(new CommentReference(null, AstFactory.identifier3("a")));
+    _assertCloneUnitMember('/** ref [a]. */ main(a) {}');
   }
 
   void test_visitCompilationUnit_declaration() {
-    _assertClone(AstFactory.compilationUnit2([
-      AstFactory.topLevelVariableDeclaration2(
-          Keyword.VAR, [AstFactory.variableDeclaration("a")])
-    ]));
+    _assertCloneUnitMember('var a;');
   }
 
   void test_visitCompilationUnit_directive() {
-    _assertClone(
-        AstFactory.compilationUnit3([AstFactory.libraryDirective2("l")]));
+    _assertCloneUnit('library l;');
   }
 
   void test_visitCompilationUnit_directive_declaration() {
-    _assertClone(AstFactory.compilationUnit4([
-      AstFactory.libraryDirective2("l")
-    ], [
-      AstFactory.topLevelVariableDeclaration2(
-          Keyword.VAR, [AstFactory.variableDeclaration("a")])
-    ]));
+    _assertCloneUnit('library l;  var a;');
+  }
+
+  void test_visitCompilationUnit_directive_withComment() {
+    _assertCloneUnit(r'''
+/// aaa
+/// bbb
+library l;''');
   }
 
   void test_visitCompilationUnit_empty() {
-    _assertClone(AstFactory.compilationUnit());
+    _assertCloneUnit('');
   }
 
   void test_visitCompilationUnit_script() {
-    _assertClone(AstFactory.compilationUnit5("!#/bin/dartvm"));
+    _assertCloneUnit('#!/bin/dartvm');
   }
 
   void test_visitCompilationUnit_script_declaration() {
-    _assertClone(AstFactory.compilationUnit6("!#/bin/dartvm", [
-      AstFactory.topLevelVariableDeclaration2(
-          Keyword.VAR, [AstFactory.variableDeclaration("a")])
-    ]));
+    _assertCloneUnit('#!/bin/dartvm \n var a;');
   }
 
   void test_visitCompilationUnit_script_directive() {
-    _assertClone(AstFactory.compilationUnit7(
-        "!#/bin/dartvm", [AstFactory.libraryDirective2("l")]));
+    _assertCloneUnit('#!/bin/dartvm \n library l;');
   }
 
   void test_visitCompilationUnit_script_directives_declarations() {
-    _assertClone(AstFactory.compilationUnit8("!#/bin/dartvm", [
-      AstFactory.libraryDirective2("l")
-    ], [
-      AstFactory.topLevelVariableDeclaration2(
-          Keyword.VAR, [AstFactory.variableDeclaration("a")])
-    ]));
+    _assertCloneUnit('#!/bin/dartvm \n library l;  var a;');
   }
 
   void test_visitConditionalExpression() {
-    _assertClone(AstFactory.conditionalExpression(AstFactory.identifier3("a"),
-        AstFactory.identifier3("b"), AstFactory.identifier3("c")));
+    _assertCloneExpression('a ? b : c');
   }
 
   void test_visitConstructorDeclaration_const() {
-    _assertClone(AstFactory.constructorDeclaration2(
-        Keyword.CONST,
-        null,
-        AstFactory.identifier3("C"),
-        null,
-        AstFactory.formalParameterList(),
-        null,
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { const C(); }');
   }
 
   void test_visitConstructorDeclaration_external() {
-    _assertClone(AstFactory.constructorDeclaration(AstFactory.identifier3("C"),
-        null, AstFactory.formalParameterList(), null));
+    _assertCloneUnitMember('class C { external C(); }');
   }
 
   void test_visitConstructorDeclaration_minimal() {
-    _assertClone(AstFactory.constructorDeclaration2(
-        null,
-        null,
-        AstFactory.identifier3("C"),
-        null,
-        AstFactory.formalParameterList(),
-        null,
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { C() {} }');
   }
 
   void test_visitConstructorDeclaration_multipleInitializers() {
-    _assertClone(AstFactory.constructorDeclaration2(
-        null,
-        null,
-        AstFactory.identifier3("C"),
-        null,
-        AstFactory.formalParameterList(),
-        [
-          AstFactory.constructorFieldInitializer(
-              false, "a", AstFactory.identifier3("b")),
-          AstFactory.constructorFieldInitializer(
-              false, "c", AstFactory.identifier3("d"))
-        ],
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { C() : a = b, c = d {} }');
   }
 
   void test_visitConstructorDeclaration_multipleParameters() {
-    _assertClone(AstFactory.constructorDeclaration2(
-        null,
-        null,
-        AstFactory.identifier3("C"),
-        null,
-        AstFactory.formalParameterList([
-          AstFactory.simpleFormalParameter(Keyword.VAR, "a"),
-          AstFactory.simpleFormalParameter(Keyword.VAR, "b")
-        ]),
-        null,
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { C(var a, var b) {} }');
   }
 
   void test_visitConstructorDeclaration_named() {
-    _assertClone(AstFactory.constructorDeclaration2(
-        null,
-        null,
-        AstFactory.identifier3("C"),
-        "m",
-        AstFactory.formalParameterList(),
-        null,
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { C.m() {} }');
   }
 
   void test_visitConstructorDeclaration_singleInitializer() {
-    _assertClone(AstFactory.constructorDeclaration2(
-        null,
-        null,
-        AstFactory.identifier3("C"),
-        null,
-        AstFactory.formalParameterList(),
-        [
-          AstFactory.constructorFieldInitializer(
-              false, "a", AstFactory.identifier3("b"))
-        ],
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { C() : a = b {} }');
   }
 
   void test_visitConstructorDeclaration_withMetadata() {
-    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
-        null,
-        null,
-        AstFactory.identifier3("C"),
-        null,
-        AstFactory.formalParameterList(),
-        null,
-        AstFactory.blockFunctionBody2());
-    declaration.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(declaration);
+    _assertCloneUnitMember('class C { @deprecated C() {} }');
   }
 
   void test_visitConstructorFieldInitializer_withoutThis() {
-    _assertClone(AstFactory.constructorFieldInitializer(
-        false, "a", AstFactory.identifier3("b")));
+    _assertCloneUnitMember('class C { C() : a = b {} }');
   }
 
   void test_visitConstructorFieldInitializer_withThis() {
-    _assertClone(AstFactory.constructorFieldInitializer(
-        true, "a", AstFactory.identifier3("b")));
+    _assertCloneUnitMember('class C { C() : this.a = b {} }');
   }
 
   void test_visitConstructorName_named_prefix() {
-    _assertClone(
-        AstFactory.constructorName(AstFactory.typeName4("p.C.n"), null));
+    _assertCloneExpression('new p.C.n()');
   }
 
   void test_visitConstructorName_unnamed_noPrefix() {
-    _assertClone(AstFactory.constructorName(AstFactory.typeName4("C"), null));
+    _assertCloneExpression('new C()');
   }
 
   void test_visitConstructorName_unnamed_prefix() {
-    _assertClone(AstFactory.constructorName(
-        AstFactory.typeName3(AstFactory.identifier5("p", "C")), null));
+    _assertCloneExpression('new p.C()');
   }
 
   void test_visitContinueStatement_label() {
-    _assertClone(AstFactory.continueStatement("l"));
+    _assertCloneStatement('l: while (true) { continue l; }');
   }
 
   void test_visitContinueStatement_noLabel() {
-    _assertClone(AstFactory.continueStatement());
+    _assertCloneStatement('while (true) { continue; }');
   }
 
   void test_visitDefaultFormalParameter_named_noValue() {
-    _assertClone(AstFactory.namedFormalParameter(
-        AstFactory.simpleFormalParameter3("p"), null));
+    _assertCloneUnitMember('main({p}) {}');
   }
 
   void test_visitDefaultFormalParameter_named_value() {
-    _assertClone(AstFactory.namedFormalParameter(
-        AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0)));
+    _assertCloneUnitMember('main({p : 0}) {}');
   }
 
   void test_visitDefaultFormalParameter_positional_noValue() {
-    _assertClone(AstFactory.positionalFormalParameter(
-        AstFactory.simpleFormalParameter3("p"), null));
+    _assertCloneUnitMember('main([p]) {}');
   }
 
   void test_visitDefaultFormalParameter_positional_value() {
-    _assertClone(AstFactory.positionalFormalParameter(
-        AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0)));
+    _assertCloneUnitMember('main([p = 0]) {}');
   }
 
   void test_visitDoStatement() {
-    _assertClone(AstFactory.doStatement(
-        AstFactory.block(), AstFactory.identifier3("c")));
+    _assertCloneStatement('do {} while (c);');
   }
 
   void test_visitDoubleLiteral() {
-    _assertClone(AstFactory.doubleLiteral(4.2));
+    _assertCloneExpression('4.2');
   }
 
   void test_visitEmptyFunctionBody() {
-    _assertClone(AstFactory.emptyFunctionBody());
+    _assertCloneUnitMember('main() {}');
   }
 
   void test_visitEmptyStatement() {
-    _assertClone(AstFactory.emptyStatement());
+    _assertCloneUnitMember('main() { ; }');
   }
 
   void test_visitExportDirective_combinator() {
-    _assertClone(AstFactory.exportDirective2("a.dart", [
-      AstFactory.showCombinator([AstFactory.identifier3("A")])
-    ]));
+    _assertCloneUnit('export "a.dart" show A;');
   }
 
   void test_visitExportDirective_combinators() {
-    _assertClone(AstFactory.exportDirective2("a.dart", [
-      AstFactory.showCombinator([AstFactory.identifier3("A")]),
-      AstFactory.hideCombinator([AstFactory.identifier3("B")])
-    ]));
+    _assertCloneUnit('export "a.dart" show A hide B;');
   }
 
   void test_visitExportDirective_minimal() {
-    _assertClone(AstFactory.exportDirective2("a.dart"));
+    _assertCloneUnit('export "a.dart";');
   }
 
   void test_visitExportDirective_withMetadata() {
-    ExportDirective directive = AstFactory.exportDirective2("a.dart");
-    directive.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(directive);
+    _assertCloneUnit('@deprecated export "a.dart";');
   }
 
   void test_visitExpressionFunctionBody() {
-    _assertClone(
-        AstFactory.expressionFunctionBody(AstFactory.identifier3("a")));
+    _assertCloneUnitMember('main() => a;');
   }
 
   void test_visitExpressionStatement() {
-    _assertClone(AstFactory.expressionStatement(AstFactory.identifier3("a")));
+    _assertCloneStatement('a;');
   }
 
   void test_visitExtendsClause() {
-    _assertClone(AstFactory.extendsClause(AstFactory.typeName4("C")));
+    _assertCloneUnitMember('class A extends B {}');
   }
 
   void test_visitFieldDeclaration_instance() {
-    _assertClone(AstFactory.fieldDeclaration2(
-        false, Keyword.VAR, [AstFactory.variableDeclaration("a")]));
+    _assertCloneUnitMember('class C { var a; }');
   }
 
   void test_visitFieldDeclaration_static() {
-    _assertClone(AstFactory.fieldDeclaration2(
-        true, Keyword.VAR, [AstFactory.variableDeclaration("a")]));
+    _assertCloneUnitMember('class C { static var a; }');
   }
 
   void test_visitFieldDeclaration_withMetadata() {
-    FieldDeclaration declaration = AstFactory.fieldDeclaration2(
-        false, Keyword.VAR, [AstFactory.variableDeclaration("a")]);
-    declaration.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(declaration);
+    _assertCloneUnitMember('class C { @deprecated var a; }');
   }
 
   void test_visitFieldFormalParameter_functionTyped() {
-    _assertClone(AstFactory.fieldFormalParameter(
-        null,
-        AstFactory.typeName4("A"),
-        "a",
-        AstFactory
-            .formalParameterList([AstFactory.simpleFormalParameter3("b")])));
+    _assertCloneUnitMember('class C { C(A this.a(b)); }');
   }
 
   void test_visitFieldFormalParameter_keyword() {
-    _assertClone(AstFactory.fieldFormalParameter(Keyword.VAR, null, "a"));
+    _assertCloneUnitMember('class C { C(var this.a); }');
   }
 
   void test_visitFieldFormalParameter_keywordAndType() {
-    _assertClone(AstFactory.fieldFormalParameter(
-        Keyword.FINAL, AstFactory.typeName4("A"), "a"));
+    _assertCloneUnitMember('class C { C(final A this.a); }');
   }
 
   void test_visitFieldFormalParameter_type() {
-    _assertClone(
-        AstFactory.fieldFormalParameter(null, AstFactory.typeName4("A"), "a"));
+    _assertCloneUnitMember('class C { C(A this.a); }');
   }
 
   void test_visitForEachStatement_declared() {
-    _assertClone(AstFactory.forEachStatement(
-        AstFactory.declaredIdentifier3("a"),
-        AstFactory.identifier3("b"),
-        AstFactory.block()));
+    _assertCloneStatement('for (var a in b) {}');
   }
 
   void test_visitForEachStatement_variable() {
-    _assertClone(new ForEachStatement.withReference(
-        null,
-        TokenFactory.tokenFromKeyword(Keyword.FOR),
-        TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-        AstFactory.identifier3("a"),
-        TokenFactory.tokenFromKeyword(Keyword.IN),
-        AstFactory.identifier3("b"),
-        TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
-        AstFactory.block()));
+    _assertCloneStatement('for (a in b) {}');
   }
 
   void test_visitForEachStatement_variable_await() {
-    _assertClone(new ForEachStatement.withReference(
-        TokenFactory.tokenFromString("await"),
-        TokenFactory.tokenFromKeyword(Keyword.FOR),
-        TokenFactory.tokenFromType(TokenType.OPEN_PAREN),
-        AstFactory.identifier3("a"),
-        TokenFactory.tokenFromKeyword(Keyword.IN),
-        AstFactory.identifier3("b"),
-        TokenFactory.tokenFromType(TokenType.CLOSE_PAREN),
-        AstFactory.block()));
+    _assertCloneUnitMember('main(s) async { await for (a in s) {} }');
   }
 
   void test_visitFormalParameterList_empty() {
-    _assertClone(AstFactory.formalParameterList());
+    _assertCloneUnitMember('main() {}');
   }
 
   void test_visitFormalParameterList_n() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("a"), AstFactory.integer(0))
-    ]));
+    _assertCloneUnitMember('main({a: 0}) {}');
   }
 
   void test_visitFormalParameterList_nn() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("a"), AstFactory.integer(0)),
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("b"), AstFactory.integer(1))
-    ]));
+    _assertCloneUnitMember('main({a: 0, b: 1}) {}');
   }
 
   void test_visitFormalParameterList_p() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("a"), AstFactory.integer(0))
-    ]));
+    _assertCloneUnitMember('main([a = 0]) {}');
   }
 
   void test_visitFormalParameterList_pp() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("a"), AstFactory.integer(0)),
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("b"), AstFactory.integer(1))
-    ]));
+    _assertCloneUnitMember('main([a = 0, b = 1]) {}');
   }
 
   void test_visitFormalParameterList_r() {
-    _assertClone(AstFactory
-        .formalParameterList([AstFactory.simpleFormalParameter3("a")]));
+    _assertCloneUnitMember('main(a) {}');
   }
 
   void test_visitFormalParameterList_rn() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("b"), AstFactory.integer(1))
-    ]));
+    _assertCloneUnitMember('main(a, {b: 1}) {}');
   }
 
   void test_visitFormalParameterList_rnn() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("b"), AstFactory.integer(1)),
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("c"), AstFactory.integer(2))
-    ]));
+    _assertCloneUnitMember('main(a, {b: 1, c: 2}) {}');
   }
 
   void test_visitFormalParameterList_rp() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("b"), AstFactory.integer(1))
-    ]));
+    _assertCloneUnitMember('main(a, [b = 1]) {}');
   }
 
   void test_visitFormalParameterList_rpp() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("b"), AstFactory.integer(1)),
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("c"), AstFactory.integer(2))
-    ]));
+    _assertCloneUnitMember('main(a, [b = 1, c = 2]) {}');
   }
 
   void test_visitFormalParameterList_rr() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.simpleFormalParameter3("b")
-    ]));
+    _assertCloneUnitMember('main(a, b) {}');
   }
 
   void test_visitFormalParameterList_rrn() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.simpleFormalParameter3("b"),
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("c"), AstFactory.integer(3))
-    ]));
+    _assertCloneUnitMember('main(a, b, {c: 3}) {}');
   }
 
   void test_visitFormalParameterList_rrnn() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.simpleFormalParameter3("b"),
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("c"), AstFactory.integer(3)),
-      AstFactory.namedFormalParameter(
-          AstFactory.simpleFormalParameter3("d"), AstFactory.integer(4))
-    ]));
+    _assertCloneUnitMember('main(a, b, {c: 3, d: 4}) {}');
   }
 
   void test_visitFormalParameterList_rrp() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.simpleFormalParameter3("b"),
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("c"), AstFactory.integer(3))
-    ]));
+    _assertCloneUnitMember('main(a, b, [c = 3]) {}');
   }
 
   void test_visitFormalParameterList_rrpp() {
-    _assertClone(AstFactory.formalParameterList([
-      AstFactory.simpleFormalParameter3("a"),
-      AstFactory.simpleFormalParameter3("b"),
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("c"), AstFactory.integer(3)),
-      AstFactory.positionalFormalParameter(
-          AstFactory.simpleFormalParameter3("d"), AstFactory.integer(4))
-    ]));
+    _assertCloneUnitMember('main(a, b, [c = 3, d = 4]) {}');
   }
 
   void test_visitForStatement_c() {
-    _assertClone(AstFactory.forStatement(
-        null, AstFactory.identifier3("c"), null, AstFactory.block()));
+    _assertCloneStatement('for (; c;) {}');
   }
 
   void test_visitForStatement_cu() {
-    _assertClone(AstFactory.forStatement(null, AstFactory.identifier3("c"),
-        [AstFactory.identifier3("u")], AstFactory.block()));
+    _assertCloneStatement('for (; c; u) {}');
   }
 
   void test_visitForStatement_e() {
-    _assertClone(AstFactory.forStatement(
-        AstFactory.identifier3("e"), null, null, AstFactory.block()));
+    _assertCloneStatement('for (e; ;) {}');
   }
 
   void test_visitForStatement_ec() {
-    _assertClone(AstFactory.forStatement(AstFactory.identifier3("e"),
-        AstFactory.identifier3("c"), null, AstFactory.block()));
+    _assertCloneStatement('for (e; c;) {}');
   }
 
   void test_visitForStatement_ecu() {
-    _assertClone(AstFactory.forStatement(
-        AstFactory.identifier3("e"),
-        AstFactory.identifier3("c"),
-        [AstFactory.identifier3("u")],
-        AstFactory.block()));
+    _assertCloneStatement('for (e; c; u) {}');
   }
 
   void test_visitForStatement_eu() {
-    _assertClone(AstFactory.forStatement(AstFactory.identifier3("e"), null,
-        [AstFactory.identifier3("u")], AstFactory.block()));
+    _assertCloneStatement('for (e; ; u) {}');
   }
 
   void test_visitForStatement_i() {
-    _assertClone(AstFactory.forStatement2(
-        AstFactory.variableDeclarationList2(
-            Keyword.VAR, [AstFactory.variableDeclaration("i")]),
-        null,
-        null,
-        AstFactory.block()));
+    _assertCloneStatement('for (var i; ;) {}');
   }
 
   void test_visitForStatement_ic() {
-    _assertClone(AstFactory.forStatement2(
-        AstFactory.variableDeclarationList2(
-            Keyword.VAR, [AstFactory.variableDeclaration("i")]),
-        AstFactory.identifier3("c"),
-        null,
-        AstFactory.block()));
+    _assertCloneStatement('for (var i; c;) {}');
   }
 
   void test_visitForStatement_icu() {
-    _assertClone(AstFactory.forStatement2(
-        AstFactory.variableDeclarationList2(
-            Keyword.VAR, [AstFactory.variableDeclaration("i")]),
-        AstFactory.identifier3("c"),
-        [AstFactory.identifier3("u")],
-        AstFactory.block()));
+    _assertCloneStatement('for (var i; c; u) {}');
   }
 
   void test_visitForStatement_iu() {
-    _assertClone(AstFactory.forStatement2(
-        AstFactory.variableDeclarationList2(
-            Keyword.VAR, [AstFactory.variableDeclaration("i")]),
-        null,
-        [AstFactory.identifier3("u")],
-        AstFactory.block()));
+    _assertCloneStatement('for (var i; ; u) {}');
   }
 
   void test_visitForStatement_u() {
-    _assertClone(AstFactory.forStatement(
-        null, null, [AstFactory.identifier3("u")], AstFactory.block()));
+    _assertCloneStatement('for (; ; u) {}');
   }
 
   void test_visitFunctionDeclaration_getter() {
-    _assertClone(AstFactory.functionDeclaration(
-        null, Keyword.GET, "f", AstFactory.functionExpression()));
+    _assertCloneUnitMember('get f {}');
   }
 
   void test_visitFunctionDeclaration_normal() {
-    _assertClone(AstFactory.functionDeclaration(
-        null, null, "f", AstFactory.functionExpression()));
+    _assertCloneUnitMember('f() {}');
   }
 
   void test_visitFunctionDeclaration_setter() {
-    _assertClone(AstFactory.functionDeclaration(
-        null, Keyword.SET, "f", AstFactory.functionExpression()));
+    _assertCloneUnitMember('set f(x) {}');
   }
 
   void test_visitFunctionDeclaration_withMetadata() {
-    FunctionDeclaration declaration = AstFactory.functionDeclaration(
-        null, null, "f", AstFactory.functionExpression());
-    declaration.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(declaration);
+    _assertCloneUnitMember('@deprecated f() {}');
   }
 
   void test_visitFunctionDeclarationStatement() {
-    _assertClone(AstFactory.functionDeclarationStatement(
-        null, null, "f", AstFactory.functionExpression()));
-  }
-
-  void test_visitFunctionExpression() {
-    _assertClone(AstFactory.functionExpression());
+    _assertCloneStatement('f() {}');
   }
 
   void test_visitFunctionExpressionInvocation() {
-    _assertClone(
-        AstFactory.functionExpressionInvocation(AstFactory.identifier3("f")));
+    _assertCloneStatement('{ () {}(); }');
   }
 
   void test_visitFunctionTypeAlias_generic() {
-    _assertClone(AstFactory.typeAlias(AstFactory.typeName4("A"), "F",
-        AstFactory.typeParameterList(["B"]), AstFactory.formalParameterList()));
+    _assertCloneUnitMember('typedef A F<B>();');
   }
 
   void test_visitFunctionTypeAlias_nonGeneric() {
-    _assertClone(AstFactory.typeAlias(AstFactory.typeName4("A"), "F", null,
-        AstFactory.formalParameterList()));
+    _assertCloneUnitMember('typedef A F();');
   }
 
   void test_visitFunctionTypeAlias_withMetadata() {
-    FunctionTypeAlias declaration = AstFactory.typeAlias(
-        AstFactory.typeName4("A"), "F", null, AstFactory.formalParameterList());
-    declaration.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(declaration);
+    _assertCloneUnitMember('@deprecated typedef A F();');
   }
 
   void test_visitFunctionTypedFormalParameter_noType() {
-    _assertClone(AstFactory.functionTypedFormalParameter(null, "f"));
+    _assertCloneUnitMember('main( f() ) {}');
   }
 
   void test_visitFunctionTypedFormalParameter_type() {
-    _assertClone(AstFactory.functionTypedFormalParameter(
-        AstFactory.typeName4("T"), "f"));
+    _assertCloneUnitMember('main( T f() ) {}');
   }
 
   void test_visitIfStatement_withElse() {
-    _assertClone(AstFactory.ifStatement2(
-        AstFactory.identifier3("c"), AstFactory.block(), AstFactory.block()));
+    _assertCloneStatement('if (c) {} else {}');
   }
 
   void test_visitIfStatement_withoutElse() {
-    _assertClone(AstFactory.ifStatement(
-        AstFactory.identifier3("c"), AstFactory.block()));
+    _assertCloneStatement('if (c) {}');
   }
 
   void test_visitImplementsClause_multiple() {
-    _assertClone(AstFactory.implementsClause(
-        [AstFactory.typeName4("A"), AstFactory.typeName4("B")]));
+    _assertCloneUnitMember('class A implements B, C {}');
   }
 
   void test_visitImplementsClause_single() {
-    _assertClone(AstFactory.implementsClause([AstFactory.typeName4("A")]));
+    _assertCloneUnitMember('class A implements B {}');
   }
 
   void test_visitImportDirective_combinator() {
-    _assertClone(AstFactory.importDirective3("a.dart", null, [
-      AstFactory.showCombinator([AstFactory.identifier3("A")])
-    ]));
+    _assertCloneUnit('import "a.dart" show A;');
   }
 
   void test_visitImportDirective_combinators() {
-    _assertClone(AstFactory.importDirective3("a.dart", null, [
-      AstFactory.showCombinator([AstFactory.identifier3("A")]),
-      AstFactory.hideCombinator([AstFactory.identifier3("B")])
-    ]));
+    _assertCloneUnit('import "a.dart" show A hide B;');
   }
 
   void test_visitImportDirective_minimal() {
-    _assertClone(AstFactory.importDirective3("a.dart", null));
+    _assertCloneUnit('import "a.dart";');
   }
 
   void test_visitImportDirective_prefix() {
-    _assertClone(AstFactory.importDirective3("a.dart", "p"));
+    _assertCloneUnit('import "a.dart" as p;');
   }
 
   void test_visitImportDirective_prefix_combinator() {
-    _assertClone(AstFactory.importDirective3("a.dart", "p", [
-      AstFactory.showCombinator([AstFactory.identifier3("A")])
-    ]));
+    _assertCloneUnit('import "a.dart" as p show A;');
   }
 
   void test_visitImportDirective_prefix_combinators() {
-    _assertClone(AstFactory.importDirective3("a.dart", "p", [
-      AstFactory.showCombinator([AstFactory.identifier3("A")]),
-      AstFactory.hideCombinator([AstFactory.identifier3("B")])
-    ]));
+    _assertCloneUnit('import "a.dart" as p show A hide B;');
   }
 
   void test_visitImportDirective_withMetadata() {
-    ImportDirective directive = AstFactory.importDirective3("a.dart", null);
-    directive.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(directive);
+    _assertCloneUnit('@deprecated import "a.dart";');
   }
 
   void test_visitImportHideCombinator_multiple() {
-    _assertClone(AstFactory.hideCombinator(
-        [AstFactory.identifier3("a"), AstFactory.identifier3("b")]));
+    _assertCloneUnit('import "a.dart" hide a, b;');
   }
 
   void test_visitImportHideCombinator_single() {
-    _assertClone(AstFactory.hideCombinator([AstFactory.identifier3("a")]));
+    _assertCloneUnit('import "a.dart" hide a;');
   }
 
   void test_visitImportShowCombinator_multiple() {
-    _assertClone(AstFactory.showCombinator(
-        [AstFactory.identifier3("a"), AstFactory.identifier3("b")]));
+    _assertCloneUnit('import "a.dart" show a, b;');
   }
 
   void test_visitImportShowCombinator_single() {
-    _assertClone(AstFactory.showCombinator([AstFactory.identifier3("a")]));
+    _assertCloneUnit('import "a.dart" show a;');
   }
 
   void test_visitIndexExpression() {
-    _assertClone(AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("i")));
+    _assertCloneExpression('a[i]');
   }
 
   void test_visitInstanceCreationExpression_const() {
-    _assertClone(AstFactory.instanceCreationExpression2(
-        Keyword.CONST, AstFactory.typeName4("C")));
+    _assertCloneExpression('const C()');
   }
 
   void test_visitInstanceCreationExpression_named() {
-    _assertClone(AstFactory.instanceCreationExpression3(
-        Keyword.NEW, AstFactory.typeName4("C"), "c"));
+    _assertCloneExpression('new C.c()');
   }
 
   void test_visitInstanceCreationExpression_unnamed() {
-    _assertClone(AstFactory.instanceCreationExpression2(
-        Keyword.NEW, AstFactory.typeName4("C")));
+    _assertCloneExpression('new C()');
   }
 
   void test_visitIntegerLiteral() {
-    _assertClone(AstFactory.integer(42));
+    _assertCloneExpression('42');
   }
 
   void test_visitInterpolationExpression_expression() {
-    _assertClone(
-        AstFactory.interpolationExpression(AstFactory.identifier3("a")));
+    _assertCloneExpression(r'"${c}"');
   }
 
   void test_visitInterpolationExpression_identifier() {
-    _assertClone(AstFactory.interpolationExpression2("a"));
-  }
-
-  void test_visitInterpolationString() {
-    _assertClone(AstFactory.interpolationString("'x", "x"));
+    _assertCloneExpression(r'"$c"');
   }
 
   void test_visitIsExpression_negated() {
-    _assertClone(AstFactory.isExpression(
-        AstFactory.identifier3("a"), true, AstFactory.typeName4("C")));
+    _assertCloneExpression('a is! C');
   }
 
   void test_visitIsExpression_normal() {
-    _assertClone(AstFactory.isExpression(
-        AstFactory.identifier3("a"), false, AstFactory.typeName4("C")));
+    _assertCloneExpression('a is C');
   }
 
   void test_visitLabel() {
-    _assertClone(AstFactory.label2("a"));
+    _assertCloneStatement('a: return;');
   }
 
   void test_visitLabeledStatement_multiple() {
-    _assertClone(AstFactory.labeledStatement(
-        [AstFactory.label2("a"), AstFactory.label2("b")],
-        AstFactory.returnStatement()));
+    _assertCloneStatement('a: b: return;');
   }
 
   void test_visitLabeledStatement_single() {
-    _assertClone(AstFactory.labeledStatement(
-        [AstFactory.label2("a")], AstFactory.returnStatement()));
+    _assertCloneStatement('a: return;');
   }
 
   void test_visitLibraryDirective() {
-    _assertClone(AstFactory.libraryDirective2("l"));
+    _assertCloneUnit('library l;');
   }
 
   void test_visitLibraryDirective_withMetadata() {
-    LibraryDirective directive = AstFactory.libraryDirective2("l");
-    directive.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(directive);
+    _assertCloneUnit('@deprecated library l;');
   }
 
   void test_visitLibraryIdentifier_multiple() {
-    _assertClone(AstFactory.libraryIdentifier([
-      AstFactory.identifier3("a"),
-      AstFactory.identifier3("b"),
-      AstFactory.identifier3("c")
-    ]));
+    _assertCloneUnit('library a.b.c;');
   }
 
   void test_visitLibraryIdentifier_single() {
-    _assertClone(AstFactory.libraryIdentifier([AstFactory.identifier3("a")]));
+    _assertCloneUnit('library a;');
   }
 
   void test_visitListLiteral_const() {
-    _assertClone(AstFactory.listLiteral2(Keyword.CONST, null));
+    _assertCloneExpression('const []');
   }
 
   void test_visitListLiteral_empty() {
-    _assertClone(AstFactory.listLiteral());
+    _assertCloneExpression('[]');
   }
 
   void test_visitListLiteral_nonEmpty() {
-    _assertClone(AstFactory.listLiteral([
-      AstFactory.identifier3("a"),
-      AstFactory.identifier3("b"),
-      AstFactory.identifier3("c")
-    ]));
+    _assertCloneExpression('[a, b, c]');
   }
 
   void test_visitMapLiteral_const() {
-    _assertClone(AstFactory.mapLiteral(Keyword.CONST, null));
+    _assertCloneExpression('const {}');
   }
 
   void test_visitMapLiteral_empty() {
-    _assertClone(AstFactory.mapLiteral2());
+    _assertCloneExpression('{}');
   }
 
   void test_visitMapLiteral_nonEmpty() {
-    _assertClone(AstFactory.mapLiteral2([
-      AstFactory.mapLiteralEntry("a", AstFactory.identifier3("a")),
-      AstFactory.mapLiteralEntry("b", AstFactory.identifier3("b")),
-      AstFactory.mapLiteralEntry("c", AstFactory.identifier3("c"))
-    ]));
-  }
-
-  void test_visitMapLiteralEntry() {
-    _assertClone(AstFactory.mapLiteralEntry("a", AstFactory.identifier3("b")));
+    _assertCloneExpression('{a: a, b: b, c: c}');
   }
 
   void test_visitMethodDeclaration_external() {
-    _assertClone(AstFactory.methodDeclaration(null, null, null, null,
-        AstFactory.identifier3("m"), AstFactory.formalParameterList()));
+    _assertCloneUnitMember('class C { external m(); }');
   }
 
   void test_visitMethodDeclaration_external_returnType() {
-    _assertClone(AstFactory.methodDeclaration(
-        null,
-        AstFactory.typeName4("T"),
-        null,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList()));
+    _assertCloneUnitMember('class C { T m(); }');
   }
 
   void test_visitMethodDeclaration_getter() {
-    _assertClone(AstFactory.methodDeclaration2(null, null, Keyword.GET, null,
-        AstFactory.identifier3("m"), null, AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { get m {} }');
   }
 
   void test_visitMethodDeclaration_getter_returnType() {
-    _assertClone(AstFactory.methodDeclaration2(
-        null,
-        AstFactory.typeName4("T"),
-        Keyword.GET,
-        null,
-        AstFactory.identifier3("m"),
-        null,
-        AstFactory.blockFunctionBody2()));
-  }
-
-  void test_visitMethodDeclaration_getter_seturnType() {
-    _assertClone(AstFactory.methodDeclaration2(
-        null,
-        AstFactory.typeName4("T"),
-        Keyword.SET,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList(
-            [AstFactory.simpleFormalParameter(Keyword.VAR, "v")]),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { T get m {} }');
   }
 
   void test_visitMethodDeclaration_minimal() {
-    _assertClone(AstFactory.methodDeclaration2(
-        null,
-        null,
-        null,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList(),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { m() {} }');
   }
 
   void test_visitMethodDeclaration_multipleParameters() {
-    _assertClone(AstFactory.methodDeclaration2(
-        null,
-        null,
-        null,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList([
-          AstFactory.simpleFormalParameter(Keyword.VAR, "a"),
-          AstFactory.simpleFormalParameter(Keyword.VAR, "b")
-        ]),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { m(var a, var b) {} }');
   }
 
   void test_visitMethodDeclaration_operator() {
-    _assertClone(AstFactory.methodDeclaration2(
-        null,
-        null,
-        null,
-        Keyword.OPERATOR,
-        AstFactory.identifier3("+"),
-        AstFactory.formalParameterList(),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { operator+() {} }');
   }
 
   void test_visitMethodDeclaration_operator_returnType() {
-    _assertClone(AstFactory.methodDeclaration2(
-        null,
-        AstFactory.typeName4("T"),
-        null,
-        Keyword.OPERATOR,
-        AstFactory.identifier3("+"),
-        AstFactory.formalParameterList(),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { T operator+() {} }');
   }
 
   void test_visitMethodDeclaration_returnType() {
-    _assertClone(AstFactory.methodDeclaration2(
-        null,
-        AstFactory.typeName4("T"),
-        null,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList(),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { T m() {} }');
   }
 
   void test_visitMethodDeclaration_setter() {
-    _assertClone(AstFactory.methodDeclaration2(
-        null,
-        null,
-        Keyword.SET,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList(
-            [AstFactory.simpleFormalParameter(Keyword.VAR, "v")]),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { set m(var v) {} }');
+  }
+
+  void test_visitMethodDeclaration_setter_returnType() {
+    _assertCloneUnitMember('class C { T set m(v) {} }');
   }
 
   void test_visitMethodDeclaration_static() {
-    _assertClone(AstFactory.methodDeclaration2(
-        Keyword.STATIC,
-        null,
-        null,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList(),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { static m() {} }');
   }
 
   void test_visitMethodDeclaration_static_returnType() {
-    _assertClone(AstFactory.methodDeclaration2(
-        Keyword.STATIC,
-        AstFactory.typeName4("T"),
-        null,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList(),
-        AstFactory.blockFunctionBody2()));
+    _assertCloneUnitMember('class C { static T m() {} }');
   }
 
   void test_visitMethodDeclaration_withMetadata() {
-    MethodDeclaration declaration = AstFactory.methodDeclaration2(
-        null,
-        null,
-        null,
-        null,
-        AstFactory.identifier3("m"),
-        AstFactory.formalParameterList(),
-        AstFactory.blockFunctionBody2());
-    declaration.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(declaration);
+    _assertCloneUnitMember('class C { @deprecated m() {} }');
   }
 
   void test_visitMethodInvocation_noTarget() {
-    _assertClone(AstFactory.methodInvocation2("m"));
+    _assertCloneExpression('m()');
   }
 
   void test_visitMethodInvocation_target() {
-    _assertClone(AstFactory.methodInvocation(AstFactory.identifier3("t"), "m"));
+    _assertCloneExpression('t.m()');
   }
 
   void test_visitNamedExpression() {
-    _assertClone(AstFactory.namedExpression2("a", AstFactory.identifier3("b")));
-  }
-
-  void test_visitNamedFormalParameter() {
-    _assertClone(AstFactory.namedFormalParameter(
-        AstFactory.simpleFormalParameter(Keyword.VAR, "a"),
-        AstFactory.integer(0)));
+    _assertCloneExpression('m(a: b)');
   }
 
   void test_visitNativeClause() {
-    _assertClone(AstFactory.nativeClause("code"));
+    _assertCloneUnitMember('f() native "code";');
   }
 
   void test_visitNativeFunctionBody() {
-    _assertClone(AstFactory.nativeFunctionBody("str"));
+    _assertCloneUnitMember('f() native "str";');
   }
 
   void test_visitNullLiteral() {
-    _assertClone(AstFactory.nullLiteral());
+    _assertCloneExpression('null');
   }
 
   void test_visitParenthesizedExpression() {
-    _assertClone(
-        AstFactory.parenthesizedExpression(AstFactory.identifier3("a")));
+    _assertCloneExpression('(a)');
   }
 
   void test_visitPartDirective() {
-    _assertClone(AstFactory.partDirective2("a.dart"));
+    _assertCloneUnit('part "a.dart";');
   }
 
   void test_visitPartDirective_withMetadata() {
-    PartDirective directive = AstFactory.partDirective2("a.dart");
-    directive.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(directive);
+    _assertCloneUnit('@deprecated part "a.dart";');
   }
 
   void test_visitPartOfDirective() {
-    _assertClone(
-        AstFactory.partOfDirective(AstFactory.libraryIdentifier2(["l"])));
+    _assertCloneUnit('part of l;');
   }
 
   void test_visitPartOfDirective_withMetadata() {
-    PartOfDirective directive =
-        AstFactory.partOfDirective(AstFactory.libraryIdentifier2(["l"]));
-    directive.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(directive);
+    _assertCloneUnit('@deprecated part of l;');
   }
 
   void test_visitPositionalFormalParameter() {
-    _assertClone(AstFactory.positionalFormalParameter(
-        AstFactory.simpleFormalParameter(Keyword.VAR, "a"),
-        AstFactory.integer(0)));
+    _assertCloneUnitMember('main([var p = 0]) {}');
   }
 
   void test_visitPostfixExpression() {
-    _assertClone(AstFactory.postfixExpression(
-        AstFactory.identifier3("a"), TokenType.PLUS_PLUS));
+    _assertCloneExpression('a++');
   }
 
   void test_visitPrefixedIdentifier() {
-    _assertClone(AstFactory.identifier5("a", "b"));
+    _assertCloneExpression('a.b');
   }
 
   void test_visitPrefixExpression() {
-    _assertClone(AstFactory.prefixExpression(
-        TokenType.MINUS, AstFactory.identifier3("a")));
+    _assertCloneExpression('-a');
   }
 
   void test_visitPropertyAccess() {
-    _assertClone(AstFactory.propertyAccess2(AstFactory.identifier3("a"), "b"));
+    _assertCloneExpression('a.b.c');
   }
 
   void test_visitRedirectingConstructorInvocation_named() {
-    _assertClone(AstFactory.redirectingConstructorInvocation2("c"));
+    _assertCloneUnitMember('class A { factory A() = B.b; }');
   }
 
   void test_visitRedirectingConstructorInvocation_unnamed() {
-    _assertClone(AstFactory.redirectingConstructorInvocation());
+    _assertCloneUnitMember('class A { factory A() = B; }');
   }
 
   void test_visitRethrowExpression() {
-    _assertClone(AstFactory.rethrowExpression());
+    _assertCloneExpression('rethrow');
   }
 
   void test_visitReturnStatement_expression() {
-    _assertClone(AstFactory.returnStatement2(AstFactory.identifier3("a")));
+    _assertCloneStatement('return a;');
   }
 
   void test_visitReturnStatement_noExpression() {
-    _assertClone(AstFactory.returnStatement());
+    _assertCloneStatement('return;');
   }
 
   void test_visitScriptTag() {
-    String scriptTag = "!#/bin/dart.exe";
-    _assertClone(AstFactory.scriptTag(scriptTag));
+    _assertCloneUnit('#!/bin/dart.exe');
   }
 
   void test_visitSimpleFormalParameter_keyword() {
-    _assertClone(AstFactory.simpleFormalParameter(Keyword.VAR, "a"));
+    _assertCloneUnitMember('main(var a) {}');
   }
 
   void test_visitSimpleFormalParameter_keyword_type() {
-    _assertClone(AstFactory.simpleFormalParameter2(
-        Keyword.FINAL, AstFactory.typeName4("A"), "a"));
+    _assertCloneUnitMember('main(final A a) {}');
   }
 
   void test_visitSimpleFormalParameter_type() {
-    _assertClone(
-        AstFactory.simpleFormalParameter4(AstFactory.typeName4("A"), "a"));
+    _assertCloneUnitMember('main(A a) {}');
   }
 
   void test_visitSimpleIdentifier() {
-    _assertClone(AstFactory.identifier3("a"));
+    _assertCloneExpression('a');
   }
 
   void test_visitSimpleStringLiteral() {
-    _assertClone(AstFactory.string2("a"));
+    _assertCloneExpression("'a'");
   }
 
   void test_visitStringInterpolation() {
-    _assertClone(AstFactory.string([
-      AstFactory.interpolationString("'a", "a"),
-      AstFactory.interpolationExpression(AstFactory.identifier3("e")),
-      AstFactory.interpolationString("b'", "b")
-    ]));
+    _assertCloneExpression(r"'a${e}b'");
   }
 
   void test_visitSuperConstructorInvocation() {
-    _assertClone(AstFactory.superConstructorInvocation());
+    _assertCloneUnitMember('class C { C() : super(); }');
   }
 
   void test_visitSuperConstructorInvocation_named() {
-    _assertClone(AstFactory.superConstructorInvocation2("c"));
+    _assertCloneUnitMember('class C { C() : super.c(); }');
   }
 
   void test_visitSuperExpression() {
-    _assertClone(AstFactory.superExpression());
+    _assertCloneUnitMember('class C { m() { super.m(); } }');
   }
 
   void test_visitSwitchCase_multipleLabels() {
-    _assertClone(AstFactory.switchCase2(
-        [AstFactory.label2("l1"), AstFactory.label2("l2")],
-        AstFactory.identifier3("a"),
-        [AstFactory.block()]));
+    _assertCloneStatement('switch (v) {l1: l2: case a: {} }');
   }
 
   void test_visitSwitchCase_multipleStatements() {
-    _assertClone(AstFactory.switchCase(
-        AstFactory.identifier3("a"), [AstFactory.block(), AstFactory.block()]));
+    _assertCloneStatement('switch (v) { case a: {} {} }');
   }
 
   void test_visitSwitchCase_noLabels() {
-    _assertClone(AstFactory.switchCase(
-        AstFactory.identifier3("a"), [AstFactory.block()]));
+    _assertCloneStatement('switch (v) { case a: {} }');
   }
 
   void test_visitSwitchCase_singleLabel() {
-    _assertClone(AstFactory.switchCase2([AstFactory.label2("l1")],
-        AstFactory.identifier3("a"), [AstFactory.block()]));
+    _assertCloneStatement('switch (v) { l1: case a: {} }');
   }
 
   void test_visitSwitchDefault_multipleLabels() {
-    _assertClone(AstFactory.switchDefault(
-        [AstFactory.label2("l1"), AstFactory.label2("l2")],
-        [AstFactory.block()]));
+    _assertCloneStatement('switch (v) { l1: l2: default: {} }');
   }
 
   void test_visitSwitchDefault_multipleStatements() {
-    _assertClone(
-        AstFactory.switchDefault2([AstFactory.block(), AstFactory.block()]));
+    _assertCloneStatement('switch (v) { default: {} {} }');
   }
 
   void test_visitSwitchDefault_noLabels() {
-    _assertClone(AstFactory.switchDefault2([AstFactory.block()]));
+    _assertCloneStatement('switch (v) { default: {} }');
   }
 
   void test_visitSwitchDefault_singleLabel() {
-    _assertClone(AstFactory.switchDefault(
-        [AstFactory.label2("l1")], [AstFactory.block()]));
+    _assertCloneStatement('switch (v) { l1: default: {} }');
   }
 
   void test_visitSwitchStatement() {
-    _assertClone(AstFactory.switchStatement(AstFactory.identifier3("a"), [
-      AstFactory.switchCase(AstFactory.string2("b"), [AstFactory.block()]),
-      AstFactory.switchDefault2([AstFactory.block()])
-    ]));
+    _assertCloneStatement('switch (a) { case b: {} default: {} }');
   }
 
   void test_visitSymbolLiteral_multiple() {
-    _assertClone(AstFactory.symbolLiteral(["a", "b", "c"]));
+    _assertCloneExpression('#a.b.c');
   }
 
   void test_visitSymbolLiteral_single() {
-    _assertClone(AstFactory.symbolLiteral(["a"]));
+    _assertCloneExpression('#a');
   }
 
   void test_visitThisExpression() {
-    _assertClone(AstFactory.thisExpression());
+    _assertCloneExpression('this');
   }
 
   void test_visitThrowStatement() {
-    _assertClone(AstFactory.throwExpression2(AstFactory.identifier3("e")));
+    _assertCloneStatement('throw e;');
   }
 
   void test_visitTopLevelVariableDeclaration_multiple() {
-    _assertClone(AstFactory.topLevelVariableDeclaration2(
-        Keyword.VAR, [AstFactory.variableDeclaration("a")]));
+    _assertCloneUnitMember('var a;');
   }
 
   void test_visitTopLevelVariableDeclaration_single() {
-    _assertClone(AstFactory.topLevelVariableDeclaration2(Keyword.VAR, [
-      AstFactory.variableDeclaration("a"),
-      AstFactory.variableDeclaration("b")
-    ]));
+    _assertCloneUnitMember('var a, b;');
   }
 
   void test_visitTryStatement_catch() {
-    _assertClone(AstFactory.tryStatement2(AstFactory.block(),
-        [AstFactory.catchClause3(AstFactory.typeName4("E"))]));
+    _assertCloneStatement('try {} on E {}');
   }
 
   void test_visitTryStatement_catches() {
-    _assertClone(AstFactory.tryStatement2(AstFactory.block(), [
-      AstFactory.catchClause3(AstFactory.typeName4("E")),
-      AstFactory.catchClause3(AstFactory.typeName4("F"))
-    ]));
+    _assertCloneStatement('try {} on E {} on F {}');
   }
 
   void test_visitTryStatement_catchFinally() {
-    _assertClone(AstFactory.tryStatement3(
-        AstFactory.block(),
-        [AstFactory.catchClause3(AstFactory.typeName4("E"))],
-        AstFactory.block()));
+    _assertCloneStatement('try {} on E {} finally {}');
   }
 
   void test_visitTryStatement_finally() {
-    _assertClone(
-        AstFactory.tryStatement(AstFactory.block(), AstFactory.block()));
-  }
-
-  void test_visitTypeArgumentList_multiple() {
-    _assertClone(AstFactory.typeArgumentList(
-        [AstFactory.typeName4("E"), AstFactory.typeName4("F")]));
-  }
-
-  void test_visitTypeArgumentList_single() {
-    _assertClone(AstFactory.typeArgumentList([AstFactory.typeName4("E")]));
+    _assertCloneStatement('try {} finally {}');
   }
 
   void test_visitTypeName_multipleArgs() {
-    _assertClone(AstFactory.typeName4(
-        "C", [AstFactory.typeName4("D"), AstFactory.typeName4("E")]));
+    _assertCloneExpression('new C<D, E>()');
   }
 
   void test_visitTypeName_nestedArg() {
-    _assertClone(AstFactory.typeName4("C", [
-      AstFactory.typeName4("D", [AstFactory.typeName4("E")])
-    ]));
+    _assertCloneExpression('new C<D<E>>()');
   }
 
   void test_visitTypeName_noArgs() {
-    _assertClone(AstFactory.typeName4("C"));
+    _assertCloneExpression('new C()');
   }
 
   void test_visitTypeName_singleArg() {
-    _assertClone(AstFactory.typeName4("C", [AstFactory.typeName4("D")]));
+    _assertCloneExpression('new C<D>()');
   }
 
   void test_visitTypeParameter_withExtends() {
-    _assertClone(AstFactory.typeParameter2("E", AstFactory.typeName4("C")));
+    _assertCloneUnitMember('class A<E extends C> {}');
   }
 
   void test_visitTypeParameter_withMetadata() {
-    TypeParameter parameter = AstFactory.typeParameter("E");
-    parameter.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(parameter);
+    _assertCloneUnitMember('class A<@deprecated E> {}');
   }
 
   void test_visitTypeParameter_withoutExtends() {
-    _assertClone(AstFactory.typeParameter("E"));
+    _assertCloneUnitMember('class A<E> {}');
   }
 
   void test_visitTypeParameterList_multiple() {
-    _assertClone(AstFactory.typeParameterList(["E", "F"]));
+    _assertCloneUnitMember('class A<E, F> {}');
   }
 
   void test_visitTypeParameterList_single() {
-    _assertClone(AstFactory.typeParameterList(["E"]));
+    _assertCloneUnitMember('class A<E> {}');
   }
 
   void test_visitVariableDeclaration_initialized() {
-    _assertClone(
-        AstFactory.variableDeclaration2("a", AstFactory.identifier3("b")));
+    _assertCloneStatement('var a = b;');
   }
 
   void test_visitVariableDeclaration_uninitialized() {
-    _assertClone(AstFactory.variableDeclaration("a"));
+    _assertCloneStatement('var a;');
   }
 
   void test_visitVariableDeclarationList_const_type() {
-    _assertClone(AstFactory.variableDeclarationList(
-        Keyword.CONST, AstFactory.typeName4("C"), [
-      AstFactory.variableDeclaration("a"),
-      AstFactory.variableDeclaration("b")
-    ]));
+    _assertCloneStatement('const C a, b;');
   }
 
   void test_visitVariableDeclarationList_final_noType() {
-    _assertClone(AstFactory.variableDeclarationList2(Keyword.FINAL, [
-      AstFactory.variableDeclaration("a"),
-      AstFactory.variableDeclaration("b")
-    ]));
+    _assertCloneStatement('final a, b;');
   }
 
   void test_visitVariableDeclarationList_final_withMetadata() {
-    VariableDeclarationList declarationList = AstFactory
-        .variableDeclarationList2(Keyword.FINAL, [
-      AstFactory.variableDeclaration("a"),
-      AstFactory.variableDeclaration("b")
-    ]);
-    declarationList.metadata
-        .add(AstFactory.annotation(AstFactory.identifier3("deprecated")));
-    _assertClone(declarationList);
+    _assertCloneStatement('@deprecated final a, b;');
   }
 
   void test_visitVariableDeclarationList_type() {
-    _assertClone(AstFactory.variableDeclarationList(
-        null, AstFactory.typeName4("C"), [
-      AstFactory.variableDeclaration("a"),
-      AstFactory.variableDeclaration("b")
-    ]));
+    _assertCloneStatement('C a, b;');
   }
 
   void test_visitVariableDeclarationList_var() {
-    _assertClone(AstFactory.variableDeclarationList2(Keyword.VAR, [
-      AstFactory.variableDeclaration("a"),
-      AstFactory.variableDeclaration("b")
-    ]));
+    _assertCloneStatement('var a, b;');
   }
 
   void test_visitVariableDeclarationStatement() {
-    _assertClone(AstFactory.variableDeclarationStatement(null,
-        AstFactory.typeName4("C"), [AstFactory.variableDeclaration("c")]));
+    _assertCloneStatement('C c;');
   }
 
   void test_visitWhileStatement() {
-    _assertClone(AstFactory.whileStatement(
-        AstFactory.identifier3("c"), AstFactory.block()));
+    _assertCloneStatement('while (c) {}');
   }
 
   void test_visitWithClause_multiple() {
-    _assertClone(AstFactory.withClause([
-      AstFactory.typeName4("A"),
-      AstFactory.typeName4("B"),
-      AstFactory.typeName4("C")
-    ]));
+    _assertCloneUnitMember('class X extends Y with A, B, C {}');
   }
 
   void test_visitWithClause_single() {
-    _assertClone(AstFactory.withClause([AstFactory.typeName4("A")]));
+    _assertCloneUnitMember('class X extends Y with A {}');
   }
 
   void test_visitYieldStatement() {
-    _assertClone(AstFactory.yieldStatement(AstFactory.identifier3("A")));
+    _assertCloneUnitMember('main() async* { yield 42; }');
   }
 
   /**
@@ -1729,16 +1116,143 @@
    * @throws AFE if the visitor does not produce the expected source for the given node
    */
   void _assertClone(AstNode node) {
-    AstNode clone = node.accept(new AstCloner());
-    AstCloneComparator comparitor = new AstCloneComparator(false);
-    if (!comparitor.isEqualNodes(node, clone)) {
-      fail("Failed to clone ${node.runtimeType.toString()}");
+    {
+      AstNode clone = node.accept(new AstCloner());
+      AstCloneComparator comparator = new AstCloneComparator(false);
+      if (!comparator.isEqualNodes(node, clone)) {
+        fail("Failed to clone ${node.runtimeType.toString()}");
+      }
+      _assertEqualTokens(clone, node);
     }
+    {
+      AstNode clone = node.accept(new AstCloner(true));
+      AstCloneComparator comparator = new AstCloneComparator(true);
+      if (!comparator.isEqualNodes(node, clone)) {
+        fail("Failed to clone ${node.runtimeType.toString()}");
+      }
+      _assertEqualTokens(clone, node);
+    }
+  }
 
-    clone = node.accept(new AstCloner(true));
-    comparitor = new AstCloneComparator(true);
-    if (!comparitor.isEqualNodes(node, clone)) {
-      fail("Failed to clone ${node.runtimeType.toString()}");
+  void _assertCloneExpression(String code) {
+    AstNode node = _parseExpression(code);
+    _assertClone(node);
+  }
+
+  void _assertCloneStatement(String code) {
+    AstNode node = _parseStatement(code);
+    _assertClone(node);
+  }
+
+  void _assertCloneUnit(String code) {
+    AstNode node = _parseUnit(code);
+    _assertClone(node);
+  }
+
+  void _assertCloneUnitMember(String code) {
+    AstNode node = _parseUnitMember(code);
+    _assertClone(node);
+  }
+
+  Expression _parseExpression(String code) {
+    CompilationUnit unit = _parseUnit('var v = $code;');
+    TopLevelVariableDeclaration decl = unit.declarations.single;
+    return decl.variables.variables.single.initializer;
+  }
+
+  Statement _parseStatement(String code) {
+    CompilationUnit unit = _parseUnit('main() { $code }');
+    FunctionDeclaration main = unit.declarations.single;
+    BlockFunctionBody body = main.functionExpression.body;
+    return body.block.statements.single;
+  }
+
+  CompilationUnit _parseUnit(String code) {
+    GatheringErrorListener listener = new GatheringErrorListener();
+    CharSequenceReader reader = new CharSequenceReader(code);
+    Scanner scanner = new Scanner(null, reader, listener);
+    Token token = scanner.tokenize();
+    Parser parser = new Parser(null, listener);
+    CompilationUnit unit = parser.parseCompilationUnit(token);
+    expect(unit, isNotNull);
+    listener.assertNoErrors();
+    return unit;
+  }
+
+  CompilationUnitMember _parseUnitMember(String code) {
+    CompilationUnit unit = _parseUnit(code);
+    return unit.declarations.single;
+  }
+
+  static void _assertEqualToken(Token clone, Token original) {
+    expect(clone.type, original.type);
+    expect(clone.offset, original.offset);
+    expect(clone.length, original.length);
+    expect(clone.lexeme, original.lexeme);
+  }
+
+  static void _assertEqualTokens(AstNode cloneNode, AstNode originalNode) {
+    Token clone = cloneNode.beginToken;
+    Token original = originalNode.beginToken;
+    if (original is! CommentToken) {
+      _assertHasPrevious(original);
+      _assertHasPrevious(clone);
+    }
+    Token stopOriginalToken = originalNode.endToken.next;
+    Token skipCloneComment = null;
+    Token skipOriginalComment = null;
+    while (original != stopOriginalToken) {
+      expect(clone, isNotNull);
+      _assertEqualToken(clone, original);
+      // comments
+      {
+        Token cloneComment = clone.precedingComments;
+        Token originalComment = original.precedingComments;
+        if (cloneComment != skipCloneComment &&
+            originalComment != skipOriginalComment) {
+          while (true) {
+            if (originalComment == null) {
+              expect(cloneComment, isNull);
+              break;
+            }
+            expect(cloneComment, isNotNull);
+            _assertEqualToken(cloneComment, originalComment);
+            cloneComment = cloneComment.next;
+            originalComment = originalComment.next;
+          }
+        }
+      }
+      // next tokens
+      if (original is CommentToken) {
+        expect(clone, new isInstanceOf<CommentToken>());
+        skipOriginalComment = original;
+        skipCloneComment = clone;
+        original = (original as CommentToken).parent;
+        clone = (clone as CommentToken).parent;
+      } else {
+        clone = clone.next;
+        original = original.next;
+      }
+    }
+  }
+
+  /**
+   * Assert that the [token] has `previous` set, and if it `EOF`, then it
+   * points itself.
+   */
+  static void _assertHasPrevious(Token token) {
+    expect(token, isNotNull);
+    if (token.type == TokenType.EOF) {
+      return;
+    }
+    while (token != null) {
+      Token previous = token.previous;
+      expect(previous, isNotNull);
+      if (token.type == TokenType.EOF) {
+        expect(previous, same(token));
+        break;
+      }
+      token = previous;
     }
   }
 }
@@ -3275,39 +2789,6 @@
 }
 
 @reflectiveTest
-class ListUtilitiesTest {
-  void test_addAll_emptyToEmpty() {
-    List<String> list = new List<String>();
-    List<String> elements = <String>[];
-    ListUtilities.addAll(list, elements);
-    expect(list.length, 0);
-  }
-
-  void test_addAll_emptyToNonEmpty() {
-    List<String> list = new List<String>();
-    list.add("a");
-    List<String> elements = <String>[];
-    ListUtilities.addAll(list, elements);
-    expect(list.length, 1);
-  }
-
-  void test_addAll_nonEmptyToEmpty() {
-    List<String> list = new List<String>();
-    List<String> elements = ["b", "c"];
-    ListUtilities.addAll(list, elements);
-    expect(list.length, 2);
-  }
-
-  void test_addAll_nonEmptyToNonEmpty() {
-    List<String> list = new List<String>();
-    list.add("a");
-    List<String> elements = ["b", "c"];
-    ListUtilities.addAll(list, elements);
-    expect(list.length, 3);
-  }
-}
-
-@reflectiveTest
 class MultipleMapIteratorTest extends EngineTestCase {
   void test_multipleMaps_firstEmpty() {
     Map<String, String> map1 = new HashMap<String, String>();
@@ -3534,8 +3015,8 @@
         AstFactory.extendsClause(AstFactory.typeName4("B")),
         AstFactory.withClause([AstFactory.typeName4("C")]),
         AstFactory.implementsClause([AstFactory.typeName4("D")]), [
-      AstFactory.fieldDeclaration2(
-          false, null, [AstFactory.variableDeclaration("f")])
+      AstFactory
+          .fieldDeclaration2(false, null, [AstFactory.variableDeclaration("f")])
     ]);
     node.documentationComment =
         Comment.createEndOfLineComment(EMPTY_TOKEN_LIST);
@@ -3981,8 +3462,8 @@
   }
 
   void test_labeledStatement() {
-    LabeledStatement node = AstFactory.labeledStatement(
-        [AstFactory.label2("l")], AstFactory.block());
+    LabeledStatement node = AstFactory
+        .labeledStatement([AstFactory.label2("l")], AstFactory.block());
     _assertReplace(
         node, new ListGetter_NodeReplacerTest_test_labeledStatement(0));
     _assertReplace(node, new Getter_NodeReplacerTest_test_labeledStatement());
@@ -4181,8 +3662,8 @@
   }
 
   void test_switchDefault() {
-    SwitchDefault node = AstFactory.switchDefault(
-        [AstFactory.label2("l")], [AstFactory.block()]);
+    SwitchDefault node = AstFactory
+        .switchDefault([AstFactory.label2("l")], [AstFactory.block()]);
     _testSwitchMember(node);
   }
 
@@ -4235,8 +3716,8 @@
   }
 
   void test_typeName() {
-    TypeName node = AstFactory.typeName4(
-        "T", [AstFactory.typeName4("E"), AstFactory.typeName4("F")]);
+    TypeName node = AstFactory
+        .typeName4("T", [AstFactory.typeName4("E"), AstFactory.typeName4("F")]);
     _assertReplace(node, new Getter_NodeReplacerTest_test_typeName_2());
     _assertReplace(node, new Getter_NodeReplacerTest_test_typeName());
   }
@@ -4270,10 +3751,14 @@
   void test_variableDeclarationList() {
     VariableDeclarationList node = AstFactory.variableDeclarationList(
         null, AstFactory.typeName4("T"), [AstFactory.variableDeclaration("a")]);
+    node.documentationComment =
+        Comment.createEndOfLineComment(EMPTY_TOKEN_LIST);
+    node.metadata.add(AstFactory.annotation(AstFactory.identifier3("a")));
     _assertReplace(
         node, new Getter_NodeReplacerTest_test_variableDeclarationList());
     _assertReplace(
         node, new ListGetter_NodeReplacerTest_test_variableDeclarationList(0));
+    _testAnnotatedNode(node);
   }
 
   void test_variableDeclarationStatement() {
diff --git a/pkg/analyzer/test/reflective_tests.dart b/pkg/analyzer/test/reflective_tests.dart
index 24c36cb..970743d 100644
--- a/pkg/analyzer/test/reflective_tests.dart
+++ b/pkg/analyzer/test/reflective_tests.dart
@@ -73,14 +73,15 @@
 
 Future _invokeSymbolIfExists(InstanceMirror instanceMirror, Symbol symbol) {
   var invocationResult = null;
+  InstanceMirror closure;
   try {
-    invocationResult = instanceMirror.invoke(symbol, []).reflectee;
+    closure = instanceMirror.getField(symbol);
   } on NoSuchMethodError {}
-  if (invocationResult is Future) {
-    return invocationResult;
-  } else {
-    return new Future.value(invocationResult);
+
+  if (closure is ClosureMirror) {
+    invocationResult = closure.apply([]).reflectee;
   }
+  return new Future.value(invocationResult);
 }
 
 /**
diff --git a/pkg/analyzer/test/source/embedder_test.dart b/pkg/analyzer/test/source/embedder_test.dart
index c152773..eecb818 100644
--- a/pkg/analyzer/test/source/embedder_test.dart
+++ b/pkg/analyzer/test/source/embedder_test.dart
@@ -4,19 +4,26 @@
 
 library analyzer.test.source.embedder_test;
 
+import 'dart:core' hide Resource;
+
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/source/embedder.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/util/absolute_path.dart';
+import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
 
 import '../utils.dart';
 
 main() {
-  initializeTestEnvironment();
   group('EmbedderUriResolverTest', () {
     setUp(() {
+      initializeTestEnvironment(path.context);
       buildResourceProvider();
     });
     tearDown(() {
+      initializeTestEnvironment();
       clearResourceProvider();
     });
     test('test_NullEmbedderYamls', () {
@@ -25,22 +32,29 @@
     });
     test('test_NoEmbedderYamls', () {
       var locator = new EmbedderYamlLocator({
-        'fox': [resourceProvider.getResource('/empty')]
+        'fox': [pathTranslator.getResource('/empty')]
       });
       expect(locator.embedderYamls.length, equals(0));
     });
     test('test_EmbedderYaml', () {
       var locator = new EmbedderYamlLocator({
-        'fox': [resourceProvider.getResource('/tmp')]
+        'fox': [pathTranslator.getResource('/tmp')]
       });
       var resolver = new EmbedderUriResolver(locator.embedderYamls);
+
+      expectResolved(dartUri, posixPath) {
+        Source source = resolver.resolveAbsolute(Uri.parse(dartUri));
+        expect(source, isNotNull, reason: dartUri);
+        expect(source.fullName, posixToOSPath(posixPath));
+      }
+
       // We have four mappings.
       expect(resolver.length, equals(4));
       // Check that they map to the correct paths.
-      expect(resolver['dart:fox'], equals("/tmp/slippy.dart"));
-      expect(resolver['dart:bear'], equals("/tmp/grizzly.dart"));
-      expect(resolver['dart:relative'], equals("/relative.dart"));
-      expect(resolver['dart:deep'], equals("/tmp/deep/directory/file.dart"));
+      expectResolved('dart:fox', '/tmp/slippy.dart');
+      expectResolved('dart:bear', '/tmp/grizzly.dart');
+      expectResolved('dart:relative', '/relative.dart');
+      expectResolved('dart:deep', '/tmp/deep/directory/file.dart');
     });
     test('test_BadYAML', () {
       var locator = new EmbedderYamlLocator(null);
@@ -49,32 +63,94 @@
     });
     test('test_restoreAbsolute', () {
       var locator = new EmbedderYamlLocator({
-        'fox': [resourceProvider.getResource('/tmp')]
+        'fox': [pathTranslator.getResource('/tmp')]
       });
       var resolver = new EmbedderUriResolver(locator.embedderYamls);
-      var source = resolver.resolveAbsolute(Uri.parse('dart:fox'));
-      expect(source, isNotNull);
-      // Restore source's uri.
-      var restoreUri = resolver.restoreAbsolute(source);
-      expect(restoreUri, isNotNull);
-      // Verify that it is 'dart:fox'.
-      expect(restoreUri.toString(), equals('dart:fox'));
-      expect(restoreUri.scheme, equals('dart'));
-      expect(restoreUri.path, equals('fox'));
+
+      expectRestore(String dartUri, [String expected]) {
+        var parsedUri = Uri.parse(dartUri);
+        var source = resolver.resolveAbsolute(parsedUri);
+        expect(source, isNotNull);
+        // Restore source's uri.
+        var restoreUri = resolver.restoreAbsolute(source);
+        expect(restoreUri, isNotNull, reason: dartUri);
+        // Verify that it is 'dart:fox'.
+        expect(restoreUri.toString(), equals(expected ?? dartUri));
+        List<String> split = (expected ?? dartUri).split(':');
+        expect(restoreUri.scheme, equals(split[0]));
+        expect(restoreUri.path, equals(split[1]));
+      }
+
+      expectRestore('dart:deep');
+      expectRestore('dart:deep/file.dart', 'dart:deep');
+      expectRestore('dart:deep/part.dart');
+      expectRestore('dart:deep/deep/file.dart');
+    });
+
+    test('test_EmbedderSdk_fromFileUri', () {
+      var locator = new EmbedderYamlLocator({
+        'fox': [pathTranslator.getResource('/tmp')]
+      });
+      var resolver = new EmbedderUriResolver(locator.embedderYamls);
+      var sdk = resolver.dartSdk;
+
+      expectSource(String posixPath, String dartUri) {
+        var uri = Uri.parse(posixToOSFileUri(posixPath));
+        var source = sdk.fromFileUri(uri);
+        expect(source, isNotNull, reason: posixPath);
+        expect(source.uri.toString(), dartUri);
+        expect(source.fullName, posixToOSPath(posixPath));
+      }
+
+      expectSource('/tmp/slippy.dart', 'dart:fox');
+      expectSource('/tmp/deep/directory/file.dart', 'dart:deep');
+      expectSource('/tmp/deep/directory/part.dart', 'dart:deep/part.dart');
+    });
+    test('test_EmbedderSdk_getSdkLibrary', () {
+      var locator = new EmbedderYamlLocator({
+        'fox': [pathTranslator.getResource('/tmp')]
+      });
+      var resolver = new EmbedderUriResolver(locator.embedderYamls);
+      var sdk = resolver.dartSdk;
+      var lib = sdk.getSdkLibrary('dart:fox');
+      expect(lib, isNotNull);
+      expect(lib.path, posixToOSPath('/tmp/slippy.dart'));
+      expect(lib.shortName, 'fox');
+    });
+    test('test_EmbedderSdk_mapDartUri', () {
+      var locator = new EmbedderYamlLocator({
+        'fox': [pathTranslator.getResource('/tmp')]
+      });
+      var resolver = new EmbedderUriResolver(locator.embedderYamls);
+      var sdk = resolver.dartSdk;
+
+      expectSource(String dartUri, String posixPath) {
+        var source = sdk.mapDartUri(dartUri);
+        expect(source, isNotNull, reason: posixPath);
+        expect(source.uri.toString(), dartUri);
+        expect(source.fullName, posixToOSPath(posixPath));
+      }
+
+      expectSource('dart:fox', '/tmp/slippy.dart');
+      expectSource('dart:deep', '/tmp/deep/directory/file.dart');
+      expectSource('dart:deep/part.dart', '/tmp/deep/directory/part.dart');
     });
   });
 }
 
-MemoryResourceProvider resourceProvider;
+ResourceProvider resourceProvider;
+TestPathTranslator pathTranslator;
 
 buildResourceProvider() {
-  resourceProvider = new MemoryResourceProvider();
-  resourceProvider.newFolder('/empty');
-  resourceProvider.newFolder('/tmp');
-  resourceProvider.newFile(
-      '/tmp/_embedder.yaml',
-      r'''
-embedder_libs:
+  var rawProvider = new MemoryResourceProvider(isWindows: isWindows);
+  resourceProvider = new TestResourceProvider(rawProvider);
+  pathTranslator = new TestPathTranslator(rawProvider)
+    ..newFolder('/empty')
+    ..newFolder('/tmp')
+    ..newFile(
+        '/tmp/_embedder.yaml',
+        r'''
+embedded_libs:
   "dart:fox": "slippy.dart"
   "dart:bear": "grizzly.dart"
   "dart:relative": "../relative.dart"
@@ -85,4 +161,117 @@
 
 clearResourceProvider() {
   resourceProvider = null;
+  pathTranslator = null;
+}
+
+// TODO(danrubel) if this approach works well for running tests
+// in a platform specific way, then move all of the following functionality
+// into a separate test utility library.
+
+bool get isWindows => path.Style.platform == path.Style.windows;
+
+/**
+ * Assert that the given path is posix.
+ */
+void expectAbsolutePosixPath(String posixPath) {
+  expect(posixPath, startsWith('/'),
+      reason: 'Expected absolute posix path, but found $posixPath');
+}
+
+/**
+ * Translate the given posixPath to a path appropriate for the
+ * platform on which the tests are executing.
+ */
+String posixToOSPath(String posixPath) {
+  expectAbsolutePosixPath(posixPath);
+  if (isWindows) {
+    String windowsPath = posixPath.replaceAll('/', '\\');
+    if (posixPath.startsWith('/')) {
+      return 'C:$windowsPath';
+    }
+    return windowsPath;
+  }
+  return posixPath;
+}
+
+/**
+ * Translate the given posixPath to a file URI appropriate for the
+ * platform on which the tests are executing.
+ */
+String posixToOSFileUri(String posixPath) {
+  expectAbsolutePosixPath(posixPath);
+  return isWindows ? 'file:///C:$posixPath' : 'file://$posixPath';
+}
+
+/**
+ * A convenience utility for setting up a test [MemoryResourceProvider].
+ * All supplied paths are assumed to be in [path.posix] format
+ * and are automatically translated to [path.context].
+ *
+ * This class intentionally does not implement [ResourceProvider]
+ * directly or indirectly so that it cannot be used as a resource provider.
+ * We do not want functionality under test to interact with a resource provider
+ * that automatically translates paths.
+ */
+class TestPathTranslator {
+  final MemoryResourceProvider _provider;
+
+  TestPathTranslator(this._provider);
+
+  Resource getResource(String posixPath) =>
+      _provider.getResource(posixToOSPath(posixPath));
+
+  File newFile(String posixPath, String content) =>
+      _provider.newFile(posixToOSPath(posixPath), content);
+
+  Folder newFolder(String posixPath) =>
+      _provider.newFolder(posixToOSPath(posixPath));
+}
+
+/**
+ * A resource provider for testing that asserts that any supplied paths
+ * are appropriate for the OS platform on which the tests are running.
+ */
+class TestResourceProvider implements ResourceProvider {
+  final ResourceProvider _provider;
+
+  TestResourceProvider(this._provider) {
+    expect(_provider.absolutePathContext.separator, isWindows ? '\\' : '/');
+  }
+
+  @override
+  AbsolutePathContext get absolutePathContext => _provider.absolutePathContext;
+
+  @override
+  File getFile(String path) => _provider.getFile(_assertPath(path));
+
+  @override
+  Folder getFolder(String path) => _provider.getFolder(_assertPath(path));
+
+  @override
+  Resource getResource(String path) => _provider.getResource(_assertPath(path));
+
+  @override
+  Folder getStateLocation(String pluginId) =>
+      _provider.getStateLocation(pluginId);
+
+  @override
+  path.Context get pathContext => _provider.pathContext;
+
+  /**
+   * Assert that the given path is valid for the OS platform on which the
+   * tests are running.
+   */
+  String _assertPath(String path) {
+    if (isWindows) {
+      if (path.contains('/')) {
+        fail('Expected windows path, but found: $path');
+      }
+    } else {
+      if (path.contains('\\')) {
+        fail('Expected posix path, but found: $path');
+      }
+    }
+    return path;
+  }
 }
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 41feb593..d7e0a58 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -5,20 +5,22 @@
 library analyzer.test.src.context.context_test;
 
 import 'dart:async';
+import 'dart:collection';
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/visitor.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/cancelable_future.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/generated/ast.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_engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart';
 import 'package:analyzer/src/task/dart.dart';
@@ -488,6 +490,13 @@
     expect(context.computeDocumentationComment(null), isNull);
   }
 
+  void test_computeErrors_dart_malformedCode() {
+    Source source = addSource("/lib.dart", "final int , = 42;");
+    List<AnalysisError> errors = context.computeErrors(source);
+    expect(errors, isNotNull);
+    expect(errors.length > 0, isTrue);
+  }
+
   void test_computeErrors_dart_none() {
     Source source = addSource("/lib.dart", "library lib;");
     List<AnalysisError> errors = context.computeErrors(source);
@@ -2002,6 +2011,72 @@
     _assertNoExceptions();
   }
 
+  void test_resolveCompilationUnit_existingElementModel() {
+    Source source = addSource(
+        '/test.dart',
+        r'''
+library test;
+
+String topLevelVariable;
+int get topLevelGetter => 0;
+void set topLevelSetter(int value) {}
+String topLevelFunction(int i) => '';
+
+typedef String FunctionTypeAlias(int i);
+
+enum EnumeratedType {Invalid, Valid}
+
+class ClassOne {
+  int instanceField;
+  static int staticField;
+
+  ClassOne();
+  ClassOne.named();
+
+  int get instanceGetter => 0;
+  static String get staticGetter => '';
+
+  void set instanceSetter(int value) {}
+  static void set staticSetter(int value) {}
+
+  int instanceMethod(int first, [int second = 0]) {
+    int localVariable;
+    int localFunction(String s) {}
+  }
+  static String staticMethod(int first, {int second: 0}) => '';
+}
+
+class ClassTwo {
+  // Implicit no-argument constructor
+}
+''');
+    context.resolveCompilationUnit2(source, source);
+    LibraryElement firstElement = context.computeLibraryElement(source);
+    _ElementGatherer gatherer = new _ElementGatherer();
+    firstElement.accept(gatherer);
+
+    CacheEntry entry =
+        context.analysisCache.get(new LibrarySpecificUnit(source, source));
+    entry.setState(RESOLVED_UNIT1, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT2, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT3, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT4, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT5, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT6, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT7, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
+    entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
+
+    context.resolveCompilationUnit2(source, source);
+    LibraryElement secondElement = context.computeLibraryElement(source);
+    _ElementComparer comparer = new _ElementComparer(gatherer.elements);
+    secondElement.accept(comparer);
+    comparer.expectNoDifferences();
+  }
+
   void test_resolveCompilationUnit_import_relative() {
     Source sourceA =
         addSource("/libA.dart", "library libA; import 'libB.dart'; class A{}");
@@ -2473,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,
@@ -2685,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) {
@@ -2731,3 +2808,82 @@
   @override
   bool contains(Source source) => source == libB;
 }
+
+/**
+ * A visitor that can be used to compare all of the elements in an element model
+ * with a previously created map of elements. The class [ElementGatherer] can be
+ * used to create the map of elements.
+ */
+class _ElementComparer extends GeneralizingElementVisitor {
+  /**
+   * The previously created map of elements.
+   */
+  final Map<Element, Element> previousElements;
+
+  /**
+   * The number of elements that were found to have been overwritten.
+   */
+  int overwrittenCount = 0;
+
+  /**
+   * A buffer to which a description of the overwritten elements will be written.
+   */
+  final StringBuffer buffer = new StringBuffer();
+
+  /**
+   * Initialize a newly created visitor.
+   */
+  _ElementComparer(this.previousElements);
+
+  /**
+   * Expect that no differences were found, causing the test to fail if that
+   * wasn't the case.
+   */
+  void expectNoDifferences() {
+    if (overwrittenCount > 0) {
+      fail('Found $overwrittenCount overwritten elements.$buffer');
+    }
+  }
+
+  @override
+  void visitElement(Element element) {
+    Element previousElement = previousElements[element];
+    if (!identical(previousElement, element)) {
+      if (overwrittenCount == 0) {
+        buffer.writeln();
+      }
+      overwrittenCount++;
+      buffer.writeln('Overwritten element:');
+      Element currentElement = element;
+      while (currentElement != null) {
+        buffer.write('  ');
+        buffer.writeln(currentElement.toString());
+        currentElement = currentElement.enclosingElement;
+      }
+    }
+    super.visitElement(element);
+  }
+}
+
+/**
+ * A visitor that can be used to collect all of the elements in an element
+ * model.
+ */
+class _ElementGatherer extends GeneralizingElementVisitor {
+  /**
+   * The map in which the elements are collected. The value of each key is the
+   * key itself.
+   */
+  Map<Element, Element> elements = new HashMap<Element, Element>();
+
+  /**
+   * Initialize the visitor.
+   */
+  _ElementGatherer();
+
+  @override
+  void visitElement(Element element) {
+    elements[element] = element;
+    super.visitElement(element);
+  }
+}
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index 5cf93dd..5466949 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -13,11 +13,61 @@
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 
-class MockSdk implements DartSdk {
-  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary(
-      'dart:core',
-      '/lib/core/core.dart',
-      '''
+const _MockSdkLibrary _LIB_ASYNC = const _MockSdkLibrary(
+    'dart:async',
+    '/lib/async/async.dart',
+    '''
+library dart.async;
+
+import 'dart:math';
+
+part 'stream.dart';
+
+class Future<T> {
+  factory Future(computation()) => null;
+  factory Future.delayed(Duration duration, [T computation()]) => null;
+  factory Future.value([T value]) => null;
+
+  static Future<List/*<T>*/> wait/*<T>*/(
+      Iterable<Future/*<T>*/> futures) => null;
+  Future/*<R>*/ then/*<R>*/(/*=R*/ onValue(T value)) => null;
+}
+''',
+    const <String, String>{
+      '/lib/async/stream.dart': r'''
+part of dart.async;
+class Stream<T> {
+  Future<T> get first;
+}
+abstract class StreamTransformer<S, T> {}
+'''
+    });
+
+const _MockSdkLibrary _LIB_COLLECTION = const _MockSdkLibrary(
+    'dart:collection',
+    '/lib/collection/collection.dart',
+    '''
+library dart.collection;
+
+abstract class HashMap<K, V> implements Map<K, V> {}
+''');
+
+const _MockSdkLibrary _LIB_CONVERT = const _MockSdkLibrary(
+    'dart:convert',
+    '/lib/convert/convert.dart',
+    '''
+library dart.convert;
+
+import 'dart:async';
+
+abstract class Converter<S, T> implements StreamTransformer {}
+class JsonDecoder extends Converter<String, Object> {}
+''');
+
+const _MockSdkLibrary _LIB_CORE = const _MockSdkLibrary(
+    'dart:core',
+    '/lib/core/core.dart',
+    '''
 library dart.core;
 
 import 'dart:async';
@@ -37,15 +87,21 @@
   int compareTo(T other);
 }
 
-abstract class String implements Comparable<String> {
+abstract class Pattern {}
+abstract class String implements Comparable<String>, Pattern {
   external factory String.fromCharCodes(Iterable<int> charCodes,
                                         [int start = 0, int end]);
+  String operator +(String other) => null;
   bool get isEmpty => false;
   bool get isNotEmpty => false;
   int get length => 0;
+  String substring(int len) => null;
   String toUpperCase();
   List<int> get codeUnits;
 }
+abstract class RegExp implements Pattern {
+  external factory RegExp(String source);
+}
 
 class bool extends Object {}
 abstract class num implements Comparable<num> {
@@ -58,6 +114,7 @@
   num operator *(num other);
   num operator /(num other);
   int toInt();
+  double toDouble();
   num abs();
   int round();
 }
@@ -86,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));
 
@@ -103,6 +161,8 @@
 
 abstract class Map<K, V> extends Object {
   Iterable<K> get keys;
+  V operator [](K key);
+  void operator []=(K key, V value);
 }
 
 external bool identical(Object a, Object b);
@@ -115,60 +175,29 @@
 const Object override = const _Override();
 ''');
 
-  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary(
-      'dart:async',
-      '/lib/async/async.dart',
-      '''
-library dart.async;
+const _MockSdkLibrary _LIB_FOREIGN_HELPER = const _MockSdkLibrary(
+    'dart:_foreign_helper',
+    '/lib/_foreign_helper/_foreign_helper.dart',
+    '''
+library dart._foreign_helper;
 
-import 'dart:math';
-
-part 'stream.dart';
-
-class Future<T> {
-  factory Future.delayed(Duration duration, [T computation()]) => null;
-  factory Future.value([value]) => null;
-
-  static Future<List</*<T>*/> wait/*<T>*/(
-      Iterable<Future/*<T>*/> futures) => null;
-  Future/*<R>*/ then/*<R>*/(/*=R*/ onValue(T value)) => null;
-}
-''',
-      const <_MockSdkFile>[
-    const _MockSdkFile(
-        '/lib/async/stream.dart',
-        r'''
-part of dart.async;
-class Stream<T> {}
-abstract class StreamTransformer<S, T> {}
-''')
-  ]);
-
-  static const _MockSdkLibrary LIB_COLLECTION = const _MockSdkLibrary(
-      'dart:collection',
-      '/lib/collection/collection.dart',
-      '''
-library dart.collection;
-
-abstract class HashMap<K, V> implements Map<K, V> {}
+JS(String typeDescription, String codeTemplate,
+  [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11])
+{}
 ''');
 
-  static const _MockSdkLibrary LIB_CONVERT = const _MockSdkLibrary(
-      'dart:convert',
-      '/lib/convert/convert.dart',
-      '''
-library dart.convert;
-
-import 'dart:async';
-
-abstract class Converter<S, T> implements StreamTransformer {}
-class JsonDecoder extends Converter<String, Object> {}
+const _MockSdkLibrary _LIB_HTML = const _MockSdkLibrary(
+    'dart:html',
+    '/lib/html/dartium/html_dartium.dart',
+    '''
+library dart.html;
+class HtmlElement {}
 ''');
 
-  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary(
-      'dart:math',
-      '/lib/math/math.dart',
-      '''
+const _MockSdkLibrary _LIB_MATH = const _MockSdkLibrary(
+    'dart:math',
+    '/lib/math/math.dart',
+    '''
 library dart.math;
 
 const double E = 2.718281828459045;
@@ -188,38 +217,54 @@
 }
 ''');
 
-  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary(
-      'dart:html',
-      '/lib/html/dartium/html_dartium.dart',
-      '''
-library dart.html;
-class HtmlElement {}
-''');
+const List<SdkLibrary> _LIBRARIES = const [
+  _LIB_CORE,
+  _LIB_ASYNC,
+  _LIB_COLLECTION,
+  _LIB_CONVERT,
+  _LIB_FOREIGN_HELPER,
+  _LIB_MATH,
+  _LIB_HTML,
+];
 
-  static const List<SdkLibrary> LIBRARIES = const [
-    LIB_CORE,
-    LIB_ASYNC,
-    LIB_COLLECTION,
-    LIB_CONVERT,
-    LIB_MATH,
-    LIB_HTML,
-  ];
+class MockSdk implements DartSdk {
+  static const Map<String, String> FULL_URI_MAP = const {
+    "dart:core": "/lib/core/core.dart",
+    "dart:html": "/lib/html/dartium/html_dartium.dart",
+    "dart:async": "/lib/async/async.dart",
+    "dart:async/stream.dart": "/lib/async/stream.dart",
+    "dart:collection": "/lib/collection/collection.dart",
+    "dart:convert": "/lib/convert/convert.dart",
+    "dart:_foreign_helper": "/lib/_foreign_helper/_foreign_helper.dart",
+    "dart:math": "/lib/math/math.dart"
+  };
+
+  static const Map<String, String> NO_ASYNC_URI_MAP = const {
+    "dart:core": "/lib/core/core.dart",
+  };
 
   final resource.MemoryResourceProvider provider =
       new resource.MemoryResourceProvider();
 
+  final Map<String, String> uriMap;
+
   /**
    * The [AnalysisContextImpl] which is used for all of the sources.
    */
   AnalysisContextImpl _analysisContext;
 
-  MockSdk() {
-    LIBRARIES.forEach((_MockSdkLibrary library) {
+  @override
+  final List<SdkLibrary> sdkLibraries;
+
+  MockSdk({bool dartAsync: true})
+      : sdkLibraries = dartAsync ? _LIBRARIES : [_LIB_CORE],
+        uriMap = dartAsync ? FULL_URI_MAP : NO_ASYNC_URI_MAP {
+    for (_MockSdkLibrary library in sdkLibraries) {
       provider.newFile(library.path, library.content);
-      library.parts.forEach((file) {
-        provider.newFile(file.path, file.content);
+      library.parts.forEach((String path, String content) {
+        provider.newFile(path, content);
       });
-    });
+    }
   }
 
   @override
@@ -228,32 +273,16 @@
       _analysisContext = new _SdkAnalysisContext(this);
       SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
       _analysisContext.sourceFactory = factory;
-      ChangeSet changeSet = new ChangeSet();
-      for (String uri in uris) {
-        Source source = factory.forUri(uri);
-        changeSet.addedSource(source);
-      }
-      _analysisContext.applyChanges(changeSet);
     }
     return _analysisContext;
   }
 
   @override
-  List<SdkLibrary> get sdkLibraries => LIBRARIES;
+  String get sdkVersion => throw new UnimplementedError();
 
   @override
-  String get sdkVersion => throw unimplemented;
-
-  UnimplementedError get unimplemented => new UnimplementedError();
-
-  @override
-  List<String> get uris {
-    List<String> uris = <String>[];
-    for (SdkLibrary library in LIBRARIES) {
-      uris.add(library.shortName);
-    }
-    return uris;
-  }
+  List<String> get uris =>
+      sdkLibraries.map((SdkLibrary library) => library.shortName).toList();
 
   @override
   Source fromFileUri(Uri uri) {
@@ -262,7 +291,7 @@
     if (!filePath.startsWith("$libPath/")) {
       return null;
     }
-    for (SdkLibrary library in LIBRARIES) {
+    for (SdkLibrary library in sdkLibraries) {
       String libraryPath = library.path;
       if (filePath.replaceAll('\\', '/') == libraryPath) {
         try {
@@ -298,17 +327,7 @@
 
   @override
   Source mapDartUri(String dartUri) {
-    const Map<String, String> uriToPath = const {
-      "dart:core": "/lib/core/core.dart",
-      "dart:html": "/lib/html/dartium/html_dartium.dart",
-      "dart:async": "/lib/async/async.dart",
-      "dart:async/stream.dart": "/lib/async/stream.dart",
-      "dart:collection": "/lib/collection/collection.dart",
-      "dart:convert": "/lib/convert/convert.dart",
-      "dart:math": "/lib/math/math.dart"
-    };
-
-    String path = uriToPath[dartUri];
+    String path = uriMap[dartUri];
     if (path != null) {
       resource.File file = provider.getResource(path);
       Uri uri = new Uri(scheme: 'dart', path: dartUri.substring(5));
@@ -321,44 +340,35 @@
   }
 }
 
-class _MockSdkFile {
-  final String path;
-  final String content;
-
-  const _MockSdkFile(this.path, this.content);
-}
-
 class _MockSdkLibrary implements SdkLibrary {
   final String shortName;
   final String path;
   final String content;
-  final List<_MockSdkFile> parts;
+  final Map<String, String> parts;
 
   const _MockSdkLibrary(this.shortName, this.path, this.content,
-      [this.parts = const <_MockSdkFile>[]]);
+      [this.parts = const <String, String>{}]);
 
   @override
-  String get category => throw unimplemented;
+  String get category => throw new UnimplementedError();
 
   @override
-  bool get isDart2JsLibrary => throw unimplemented;
+  bool get isDart2JsLibrary => throw new UnimplementedError();
 
   @override
-  bool get isDocumented => throw unimplemented;
+  bool get isDocumented => throw new UnimplementedError();
 
   @override
-  bool get isImplementation => throw unimplemented;
+  bool get isImplementation => throw new UnimplementedError();
 
   @override
-  bool get isInternal => throw unimplemented;
+  bool get isInternal => throw new UnimplementedError();
 
   @override
-  bool get isShared => throw unimplemented;
+  bool get isShared => throw new UnimplementedError();
 
   @override
-  bool get isVmLibrary => throw unimplemented;
-
-  UnimplementedError get unimplemented => new UnimplementedError();
+  bool get isVmLibrary => throw new UnimplementedError();
 }
 
 /**
diff --git a/pkg/analyzer/test/src/dart/ast/test_all.dart b/pkg/analyzer/test/src/dart/ast/test_all.dart
new file mode 100644
index 0000000..f0648c4
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/ast/test_all.dart
@@ -0,0 +1,18 @@
+// 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 analyzer.test.src.dart.ast.test_all;
+
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'utilities_test.dart' as utilities;
+
+/// Utility for manually running all tests.
+main() {
+  initializeTestEnvironment();
+  group('ast tests', () {
+    utilities.main();
+  });
+}
diff --git a/pkg/analyzer/test/generated/ast_test.dart b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
similarity index 63%
rename from pkg/analyzer/test/generated/ast_test.dart
rename to pkg/analyzer/test/src/dart/ast/utilities_test.dart
index bff9b8b..f3a0e4c 100644
--- a/pkg/analyzer/test/generated/ast_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
@@ -2,222 +2,29 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analyzer.test.generated.ast_test;
+library analyzer.test.src.dart.ast.utilities_test;
 
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart' show Predicate;
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:unittest/unittest.dart';
 
-import '../reflective_tests.dart';
-import '../utils.dart';
-import 'parser_test.dart' show ParserTestCase;
-import 'test_support.dart';
+import '../../../generated/parser_test.dart' show ParserTestCase;
+import '../../../generated/test_support.dart';
+import '../../../reflective_tests.dart';
+import '../../../utils.dart';
 
 main() {
   initializeTestEnvironment();
-  runReflectiveTests(BreadthFirstVisitorTest);
-  runReflectiveTests(ClassDeclarationTest);
-  runReflectiveTests(ClassTypeAliasTest);
   runReflectiveTests(ConstantEvaluatorTest);
-  runReflectiveTests(ConstructorDeclarationTest);
-  runReflectiveTests(FieldFormalParameterTest);
-  runReflectiveTests(IndexExpressionTest);
-  runReflectiveTests(NodeListTest);
   runReflectiveTests(NodeLocatorTest);
   runReflectiveTests(NodeLocator2Test);
-  runReflectiveTests(SimpleIdentifierTest);
-  runReflectiveTests(SimpleStringLiteralTest);
-  runReflectiveTests(StringInterpolationTest);
   runReflectiveTests(ToSourceVisitorTest);
-  runReflectiveTests(VariableDeclarationTest);
-}
-
-class AssignmentKind extends Enum<AssignmentKind> {
-  static const AssignmentKind BINARY = const AssignmentKind('BINARY', 0);
-
-  static const AssignmentKind COMPOUND_LEFT =
-      const AssignmentKind('COMPOUND_LEFT', 1);
-
-  static const AssignmentKind COMPOUND_RIGHT =
-      const AssignmentKind('COMPOUND_RIGHT', 2);
-
-  static const AssignmentKind POSTFIX_INC =
-      const AssignmentKind('POSTFIX_INC', 3);
-
-  static const AssignmentKind PREFIX_DEC =
-      const AssignmentKind('PREFIX_DEC', 4);
-
-  static const AssignmentKind PREFIX_INC =
-      const AssignmentKind('PREFIX_INC', 5);
-
-  static const AssignmentKind PREFIX_NOT =
-      const AssignmentKind('PREFIX_NOT', 6);
-
-  static const AssignmentKind SIMPLE_LEFT =
-      const AssignmentKind('SIMPLE_LEFT', 7);
-
-  static const AssignmentKind SIMPLE_RIGHT =
-      const AssignmentKind('SIMPLE_RIGHT', 8);
-
-  static const AssignmentKind NONE = const AssignmentKind('NONE', 9);
-
-  static const List<AssignmentKind> values = const [
-    BINARY,
-    COMPOUND_LEFT,
-    COMPOUND_RIGHT,
-    POSTFIX_INC,
-    PREFIX_DEC,
-    PREFIX_INC,
-    PREFIX_NOT,
-    SIMPLE_LEFT,
-    SIMPLE_RIGHT,
-    NONE
-  ];
-
-  const AssignmentKind(String name, int ordinal) : super(name, ordinal);
-}
-
-class BreadthFirstVisitor_BreadthFirstVisitorTest_testIt
-    extends BreadthFirstVisitor<Object> {
-  List<AstNode> nodes;
-
-  BreadthFirstVisitor_BreadthFirstVisitorTest_testIt(this.nodes) : super();
-
-  @override
-  Object visitNode(AstNode node) {
-    nodes.add(node);
-    return super.visitNode(node);
-  }
-}
-
-@reflectiveTest
-class BreadthFirstVisitorTest extends ParserTestCase {
-  void test_it() {
-    String source = r'''
-class A {
-  bool get g => true;
-}
-class B {
-  int f() {
-    num q() {
-      return 3;
-    }
-  return q() + 4;
-  }
-}
-A f(var p) {
-  if ((p as A).g) {
-    return p;
-  } else {
-    return null;
-  }
-}''';
-    CompilationUnit unit = ParserTestCase.parseCompilationUnit(source);
-    List<AstNode> nodes = new List<AstNode>();
-    BreadthFirstVisitor<Object> visitor =
-        new BreadthFirstVisitor_BreadthFirstVisitorTest_testIt(nodes);
-    visitor.visitAllNodes(unit);
-    expect(nodes, hasLength(59));
-    EngineTestCase.assertInstanceOf(
-        (obj) => obj is CompilationUnit, CompilationUnit, nodes[0]);
-    EngineTestCase.assertInstanceOf(
-        (obj) => obj is ClassDeclaration, ClassDeclaration, nodes[2]);
-    EngineTestCase.assertInstanceOf(
-        (obj) => obj is FunctionDeclaration, FunctionDeclaration, nodes[3]);
-    EngineTestCase.assertInstanceOf(
-        (obj) => obj is FunctionDeclarationStatement,
-        FunctionDeclarationStatement,
-        nodes[27]);
-    EngineTestCase.assertInstanceOf(
-        (obj) => obj is IntegerLiteral, IntegerLiteral, nodes[58]);
-    //3
-  }
-}
-
-@reflectiveTest
-class ClassDeclarationTest extends ParserTestCase {
-  void test_getConstructor() {
-    List<ConstructorInitializer> initializers =
-        new List<ConstructorInitializer>();
-    ConstructorDeclaration defaultConstructor = AstFactory
-        .constructorDeclaration(AstFactory.identifier3("Test"), null,
-            AstFactory.formalParameterList(), initializers);
-    ConstructorDeclaration aConstructor = AstFactory.constructorDeclaration(
-        AstFactory.identifier3("Test"),
-        "a",
-        AstFactory.formalParameterList(),
-        initializers);
-    ConstructorDeclaration bConstructor = AstFactory.constructorDeclaration(
-        AstFactory.identifier3("Test"),
-        "b",
-        AstFactory.formalParameterList(),
-        initializers);
-    ClassDeclaration clazz = AstFactory.classDeclaration(null, "Test", null,
-        null, null, null, [defaultConstructor, aConstructor, bConstructor]);
-    expect(clazz.getConstructor(null), same(defaultConstructor));
-    expect(clazz.getConstructor("a"), same(aConstructor));
-    expect(clazz.getConstructor("b"), same(bConstructor));
-    expect(clazz.getConstructor("noSuchConstructor"), same(null));
-  }
-
-  void test_getField() {
-    VariableDeclaration aVar = AstFactory.variableDeclaration("a");
-    VariableDeclaration bVar = AstFactory.variableDeclaration("b");
-    VariableDeclaration cVar = AstFactory.variableDeclaration("c");
-    ClassDeclaration clazz =
-        AstFactory.classDeclaration(null, "Test", null, null, null, null, [
-      AstFactory.fieldDeclaration2(false, null, [aVar]),
-      AstFactory.fieldDeclaration2(false, null, [bVar, cVar])
-    ]);
-    expect(clazz.getField("a"), same(aVar));
-    expect(clazz.getField("b"), same(bVar));
-    expect(clazz.getField("c"), same(cVar));
-    expect(clazz.getField("noSuchField"), same(null));
-  }
-
-  void test_getMethod() {
-    MethodDeclaration aMethod = AstFactory.methodDeclaration(null, null, null,
-        null, AstFactory.identifier3("a"), AstFactory.formalParameterList());
-    MethodDeclaration bMethod = AstFactory.methodDeclaration(null, null, null,
-        null, AstFactory.identifier3("b"), AstFactory.formalParameterList());
-    ClassDeclaration clazz = AstFactory.classDeclaration(
-        null, "Test", null, null, null, null, [aMethod, bMethod]);
-    expect(clazz.getMethod("a"), same(aMethod));
-    expect(clazz.getMethod("b"), same(bMethod));
-    expect(clazz.getMethod("noSuchMethod"), same(null));
-  }
-
-  void test_isAbstract() {
-    expect(
-        AstFactory
-            .classDeclaration(null, "A", null, null, null, null)
-            .isAbstract,
-        isFalse);
-    expect(
-        AstFactory
-            .classDeclaration(Keyword.ABSTRACT, "B", null, null, null, null)
-            .isAbstract,
-        isTrue);
-  }
-}
-
-@reflectiveTest
-class ClassTypeAliasTest extends ParserTestCase {
-  void test_isAbstract() {
-    expect(
-        AstFactory.classTypeAlias("A", null, null, null, null, null).isAbstract,
-        isFalse);
-    expect(
-        AstFactory
-            .classTypeAlias("B", null, Keyword.ABSTRACT, null, null, null)
-            .isAbstract,
-        isTrue);
-  }
 }
 
 @reflectiveTest
@@ -525,427 +332,6 @@
 }
 
 @reflectiveTest
-class ConstructorDeclarationTest extends EngineTestCase {
-  void test_firstTokenAfterCommentAndMetadata_all_inverted() {
-    Token externalKeyword = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
-    externalKeyword.offset = 14;
-    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
-        Keyword.CONST,
-        Keyword.FACTORY,
-        AstFactory.identifier3('int'),
-        null,
-        null,
-        null,
-        null);
-    declaration.externalKeyword = externalKeyword;
-    declaration.constKeyword.offset = 8;
-    Token factoryKeyword = declaration.factoryKeyword;
-    factoryKeyword.offset = 0;
-    expect(declaration.firstTokenAfterCommentAndMetadata, factoryKeyword);
-  }
-
-  void test_firstTokenAfterCommentAndMetadata_all_normal() {
-    Token token = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
-    token.offset = 0;
-    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
-        Keyword.CONST,
-        Keyword.FACTORY,
-        AstFactory.identifier3('int'),
-        null,
-        null,
-        null,
-        null);
-    declaration.externalKeyword = token;
-    declaration.constKeyword.offset = 9;
-    declaration.factoryKeyword.offset = 15;
-    expect(declaration.firstTokenAfterCommentAndMetadata, token);
-  }
-
-  void test_firstTokenAfterCommentAndMetadata_constOnly() {
-    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
-        Keyword.CONST,
-        null,
-        AstFactory.identifier3('int'),
-        null,
-        null,
-        null,
-        null);
-    expect(declaration.firstTokenAfterCommentAndMetadata,
-        declaration.constKeyword);
-  }
-
-  void test_firstTokenAfterCommentAndMetadata_externalOnly() {
-    Token externalKeyword = TokenFactory.tokenFromKeyword(Keyword.EXTERNAL);
-    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
-        null, null, AstFactory.identifier3('int'), null, null, null, null);
-    declaration.externalKeyword = externalKeyword;
-    expect(declaration.firstTokenAfterCommentAndMetadata, externalKeyword);
-  }
-
-  void test_firstTokenAfterCommentAndMetadata_factoryOnly() {
-    ConstructorDeclaration declaration = AstFactory.constructorDeclaration2(
-        null,
-        Keyword.FACTORY,
-        AstFactory.identifier3('int'),
-        null,
-        null,
-        null,
-        null);
-    expect(declaration.firstTokenAfterCommentAndMetadata,
-        declaration.factoryKeyword);
-  }
-}
-
-@reflectiveTest
-class FieldFormalParameterTest extends EngineTestCase {
-  void test_endToken_noParameters() {
-    FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('field');
-    expect(parameter.endToken, parameter.identifier.endToken);
-  }
-
-  void test_endToken_parameters() {
-    FieldFormalParameter parameter = AstFactory.fieldFormalParameter(
-        null, null, 'field', AstFactory.formalParameterList([]));
-    expect(parameter.endToken, parameter.parameters.endToken);
-  }
-}
-
-@reflectiveTest
-class IndexExpressionTest extends EngineTestCase {
-  void test_inGetterContext_assignment_compound_left() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // a[b] += c
-    AstFactory.assignmentExpression(
-        expression, TokenType.PLUS_EQ, AstFactory.identifier3("c"));
-    expect(expression.inGetterContext(), isTrue);
-  }
-
-  void test_inGetterContext_assignment_simple_left() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // a[b] = c
-    AstFactory.assignmentExpression(
-        expression, TokenType.EQ, AstFactory.identifier3("c"));
-    expect(expression.inGetterContext(), isFalse);
-  }
-
-  void test_inGetterContext_nonAssignment() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // a[b] + c
-    AstFactory.binaryExpression(
-        expression, TokenType.PLUS, AstFactory.identifier3("c"));
-    expect(expression.inGetterContext(), isTrue);
-  }
-
-  void test_inSetterContext_assignment_compound_left() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // a[b] += c
-    AstFactory.assignmentExpression(
-        expression, TokenType.PLUS_EQ, AstFactory.identifier3("c"));
-    expect(expression.inSetterContext(), isTrue);
-  }
-
-  void test_inSetterContext_assignment_compound_right() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // c += a[b]
-    AstFactory.assignmentExpression(
-        AstFactory.identifier3("c"), TokenType.PLUS_EQ, expression);
-    expect(expression.inSetterContext(), isFalse);
-  }
-
-  void test_inSetterContext_assignment_simple_left() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // a[b] = c
-    AstFactory.assignmentExpression(
-        expression, TokenType.EQ, AstFactory.identifier3("c"));
-    expect(expression.inSetterContext(), isTrue);
-  }
-
-  void test_inSetterContext_assignment_simple_right() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // c = a[b]
-    AstFactory.assignmentExpression(
-        AstFactory.identifier3("c"), TokenType.EQ, expression);
-    expect(expression.inSetterContext(), isFalse);
-  }
-
-  void test_inSetterContext_nonAssignment() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    AstFactory.binaryExpression(
-        expression, TokenType.PLUS, AstFactory.identifier3("c"));
-    // a[b] + cc
-    expect(expression.inSetterContext(), isFalse);
-  }
-
-  void test_inSetterContext_postfix() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    AstFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
-    // a[b]++
-    expect(expression.inSetterContext(), isTrue);
-  }
-
-  void test_inSetterContext_prefix_bang() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // !a[b]
-    AstFactory.prefixExpression(TokenType.BANG, expression);
-    expect(expression.inSetterContext(), isFalse);
-  }
-
-  void test_inSetterContext_prefix_minusMinus() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // --a[b]
-    AstFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
-    expect(expression.inSetterContext(), isTrue);
-  }
-
-  void test_inSetterContext_prefix_plusPlus() {
-    IndexExpression expression = AstFactory.indexExpression(
-        AstFactory.identifier3("a"), AstFactory.identifier3("b"));
-    // ++a[b]
-    AstFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
-    expect(expression.inSetterContext(), isTrue);
-  }
-}
-
-@reflectiveTest
-class NodeListTest extends EngineTestCase {
-  void test_add() {
-    AstNode parent = AstFactory.argumentList();
-    AstNode firstNode = AstFactory.booleanLiteral(true);
-    AstNode secondNode = AstFactory.booleanLiteral(false);
-    NodeList<AstNode> list = new NodeList<AstNode>(parent);
-    list.insert(0, secondNode);
-    list.insert(0, firstNode);
-    expect(list, hasLength(2));
-    expect(list[0], same(firstNode));
-    expect(list[1], same(secondNode));
-    expect(firstNode.parent, same(parent));
-    expect(secondNode.parent, same(parent));
-    AstNode thirdNode = AstFactory.booleanLiteral(false);
-    list.insert(1, thirdNode);
-    expect(list, hasLength(3));
-    expect(list[0], same(firstNode));
-    expect(list[1], same(thirdNode));
-    expect(list[2], same(secondNode));
-    expect(firstNode.parent, same(parent));
-    expect(secondNode.parent, same(parent));
-    expect(thirdNode.parent, same(parent));
-  }
-
-  void test_add_negative() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    try {
-      list.insert(-1, AstFactory.booleanLiteral(true));
-      fail("Expected IndexOutOfBoundsException");
-    } on RangeError {
-      // Expected
-    }
-  }
-
-  void test_add_tooBig() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    try {
-      list.insert(1, AstFactory.booleanLiteral(true));
-      fail("Expected IndexOutOfBoundsException");
-    } on RangeError {
-      // Expected
-    }
-  }
-
-  void test_addAll() {
-    AstNode parent = AstFactory.argumentList();
-    List<AstNode> firstNodes = new List<AstNode>();
-    AstNode firstNode = AstFactory.booleanLiteral(true);
-    AstNode secondNode = AstFactory.booleanLiteral(false);
-    firstNodes.add(firstNode);
-    firstNodes.add(secondNode);
-    NodeList<AstNode> list = new NodeList<AstNode>(parent);
-    list.addAll(firstNodes);
-    expect(list, hasLength(2));
-    expect(list[0], same(firstNode));
-    expect(list[1], same(secondNode));
-    expect(firstNode.parent, same(parent));
-    expect(secondNode.parent, same(parent));
-    List<AstNode> secondNodes = new List<AstNode>();
-    AstNode thirdNode = AstFactory.booleanLiteral(true);
-    AstNode fourthNode = AstFactory.booleanLiteral(false);
-    secondNodes.add(thirdNode);
-    secondNodes.add(fourthNode);
-    list.addAll(secondNodes);
-    expect(list, hasLength(4));
-    expect(list[0], same(firstNode));
-    expect(list[1], same(secondNode));
-    expect(list[2], same(thirdNode));
-    expect(list[3], same(fourthNode));
-    expect(firstNode.parent, same(parent));
-    expect(secondNode.parent, same(parent));
-    expect(thirdNode.parent, same(parent));
-    expect(fourthNode.parent, same(parent));
-  }
-
-  void test_creation() {
-    AstNode owner = AstFactory.argumentList();
-    NodeList<AstNode> list = new NodeList<AstNode>(owner);
-    expect(list, isNotNull);
-    expect(list, hasLength(0));
-    expect(list.owner, same(owner));
-  }
-
-  void test_get_negative() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    try {
-      list[-1];
-      fail("Expected IndexOutOfBoundsException");
-    } on RangeError {
-      // Expected
-    }
-  }
-
-  void test_get_tooBig() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    try {
-      list[1];
-      fail("Expected IndexOutOfBoundsException");
-    } on RangeError {
-      // Expected
-    }
-  }
-
-  void test_getBeginToken_empty() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    expect(list.beginToken, isNull);
-  }
-
-  void test_getBeginToken_nonEmpty() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    AstNode node =
-        AstFactory.parenthesizedExpression(AstFactory.booleanLiteral(true));
-    list.add(node);
-    expect(list.beginToken, same(node.beginToken));
-  }
-
-  void test_getEndToken_empty() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    expect(list.endToken, isNull);
-  }
-
-  void test_getEndToken_nonEmpty() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    AstNode node =
-        AstFactory.parenthesizedExpression(AstFactory.booleanLiteral(true));
-    list.add(node);
-    expect(list.endToken, same(node.endToken));
-  }
-
-  void test_indexOf() {
-    List<AstNode> nodes = new List<AstNode>();
-    AstNode firstNode = AstFactory.booleanLiteral(true);
-    AstNode secondNode = AstFactory.booleanLiteral(false);
-    AstNode thirdNode = AstFactory.booleanLiteral(true);
-    AstNode fourthNode = AstFactory.booleanLiteral(false);
-    nodes.add(firstNode);
-    nodes.add(secondNode);
-    nodes.add(thirdNode);
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    list.addAll(nodes);
-    expect(list, hasLength(3));
-    expect(list.indexOf(firstNode), 0);
-    expect(list.indexOf(secondNode), 1);
-    expect(list.indexOf(thirdNode), 2);
-    expect(list.indexOf(fourthNode), -1);
-    expect(list.indexOf(null), -1);
-  }
-
-  void test_remove() {
-    List<AstNode> nodes = new List<AstNode>();
-    AstNode firstNode = AstFactory.booleanLiteral(true);
-    AstNode secondNode = AstFactory.booleanLiteral(false);
-    AstNode thirdNode = AstFactory.booleanLiteral(true);
-    nodes.add(firstNode);
-    nodes.add(secondNode);
-    nodes.add(thirdNode);
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    list.addAll(nodes);
-    expect(list, hasLength(3));
-    expect(list.removeAt(1), same(secondNode));
-    expect(list, hasLength(2));
-    expect(list[0], same(firstNode));
-    expect(list[1], same(thirdNode));
-  }
-
-  void test_remove_negative() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    try {
-      list.removeAt(-1);
-      fail("Expected IndexOutOfBoundsException");
-    } on RangeError {
-      // Expected
-    }
-  }
-
-  void test_remove_tooBig() {
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    try {
-      list.removeAt(1);
-      fail("Expected IndexOutOfBoundsException");
-    } on RangeError {
-      // Expected
-    }
-  }
-
-  void test_set() {
-    List<AstNode> nodes = new List<AstNode>();
-    AstNode firstNode = AstFactory.booleanLiteral(true);
-    AstNode secondNode = AstFactory.booleanLiteral(false);
-    AstNode thirdNode = AstFactory.booleanLiteral(true);
-    nodes.add(firstNode);
-    nodes.add(secondNode);
-    nodes.add(thirdNode);
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    list.addAll(nodes);
-    expect(list, hasLength(3));
-    AstNode fourthNode = AstFactory.integer(0);
-    expect(javaListSet(list, 1, fourthNode), same(secondNode));
-    expect(list, hasLength(3));
-    expect(list[0], same(firstNode));
-    expect(list[1], same(fourthNode));
-    expect(list[2], same(thirdNode));
-  }
-
-  void test_set_negative() {
-    AstNode node = AstFactory.booleanLiteral(true);
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    try {
-      javaListSet(list, -1, node);
-      fail("Expected IndexOutOfBoundsException");
-    } on RangeError {
-      // Expected
-    }
-  }
-
-  void test_set_tooBig() {
-    AstNode node = AstFactory.booleanLiteral(true);
-    NodeList<AstNode> list = new NodeList<AstNode>(AstFactory.argumentList());
-    try {
-      javaListSet(list, 1, node);
-      fail("Expected IndexOutOfBoundsException");
-    } on RangeError {
-      // Expected
-    }
-  }
-}
-
-@reflectiveTest
 class NodeLocator2Test extends ParserTestCase {
   void test_onlyStartOffset() {
     String code = ' int vv; ';
@@ -1042,659 +428,6 @@
 }
 
 @reflectiveTest
-class SimpleIdentifierTest extends ParserTestCase {
-  void test_inDeclarationContext_catch_exception() {
-    SimpleIdentifier identifier =
-        AstFactory.catchClause("e").exceptionParameter;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_catch_stack() {
-    SimpleIdentifier identifier =
-        AstFactory.catchClause2("e", "s").stackTraceParameter;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_classDeclaration() {
-    SimpleIdentifier identifier =
-        AstFactory.classDeclaration(null, "C", null, null, null, null).name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_classTypeAlias() {
-    SimpleIdentifier identifier =
-        AstFactory.classTypeAlias("C", null, null, null, null, null).name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_constructorDeclaration() {
-    SimpleIdentifier identifier = AstFactory
-        .constructorDeclaration(AstFactory.identifier3("C"), "c", null, null)
-        .name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_declaredIdentifier() {
-    DeclaredIdentifier declaredIdentifier = AstFactory.declaredIdentifier3("v");
-    SimpleIdentifier identifier = declaredIdentifier.identifier;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_enumConstantDeclaration() {
-    EnumDeclaration enumDeclaration =
-        AstFactory.enumDeclaration2('MyEnum', ['CONST']);
-    SimpleIdentifier identifier = enumDeclaration.constants[0].name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_enumDeclaration() {
-    EnumDeclaration enumDeclaration =
-        AstFactory.enumDeclaration2('MyEnum', ['A', 'B', 'C']);
-    SimpleIdentifier identifier = enumDeclaration.name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_fieldFormalParameter() {
-    SimpleIdentifier identifier =
-        AstFactory.fieldFormalParameter2("p").identifier;
-    expect(identifier.inDeclarationContext(), isFalse);
-  }
-
-  void test_inDeclarationContext_functionDeclaration() {
-    SimpleIdentifier identifier =
-        AstFactory.functionDeclaration(null, null, "f", null).name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_functionTypeAlias() {
-    SimpleIdentifier identifier =
-        AstFactory.typeAlias(null, "F", null, null).name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_label_false() {
-    SimpleIdentifier identifier =
-        AstFactory.namedExpression2("l", AstFactory.integer(0)).name.label;
-    expect(identifier.inDeclarationContext(), isFalse);
-  }
-
-  void test_inDeclarationContext_label_true() {
-    Label label = AstFactory.label2("l");
-    SimpleIdentifier identifier = label.label;
-    AstFactory.labeledStatement([label], AstFactory.emptyStatement());
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_methodDeclaration() {
-    SimpleIdentifier identifier = AstFactory.identifier3("m");
-    AstFactory.methodDeclaration2(
-        null, null, null, null, identifier, null, null);
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_prefix() {
-    SimpleIdentifier identifier =
-        AstFactory.importDirective3("uri", "pref").prefix;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_simpleFormalParameter() {
-    SimpleIdentifier identifier =
-        AstFactory.simpleFormalParameter3("p").identifier;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_typeParameter_bound() {
-    TypeName bound = AstFactory.typeName4("A");
-    SimpleIdentifier identifier = bound.name as SimpleIdentifier;
-    AstFactory.typeParameter2("E", bound);
-    expect(identifier.inDeclarationContext(), isFalse);
-  }
-
-  void test_inDeclarationContext_typeParameter_name() {
-    SimpleIdentifier identifier = AstFactory.typeParameter("E").name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inDeclarationContext_variableDeclaration() {
-    SimpleIdentifier identifier = AstFactory.variableDeclaration("v").name;
-    expect(identifier.inDeclarationContext(), isTrue);
-  }
-
-  void test_inGetterContext() {
-    for (WrapperKind wrapper in WrapperKind.values) {
-      for (AssignmentKind assignment in AssignmentKind.values) {
-        SimpleIdentifier identifier = _createIdentifier(wrapper, assignment);
-        if (assignment == AssignmentKind.SIMPLE_LEFT &&
-            wrapper != WrapperKind.PREFIXED_LEFT &&
-            wrapper != WrapperKind.PROPERTY_LEFT) {
-          if (identifier.inGetterContext()) {
-            fail("Expected ${_topMostNode(identifier).toSource()} to be false");
-          }
-        } else {
-          if (!identifier.inGetterContext()) {
-            fail("Expected ${_topMostNode(identifier).toSource()} to be true");
-          }
-        }
-      }
-    }
-  }
-
-  void test_inGetterContext_forEachLoop() {
-    SimpleIdentifier identifier = AstFactory.identifier3("a");
-    Expression iterator = AstFactory.listLiteral();
-    Statement body = AstFactory.block();
-    AstFactory.forEachStatement2(identifier, iterator, body);
-    expect(identifier.inGetterContext(), isFalse);
-  }
-
-  void test_inReferenceContext() {
-    SimpleIdentifier identifier = AstFactory.identifier3("id");
-    AstFactory.namedExpression(
-        AstFactory.label(identifier), AstFactory.identifier3("_"));
-    expect(identifier.inGetterContext(), isFalse);
-    expect(identifier.inSetterContext(), isFalse);
-  }
-
-  void test_inSetterContext() {
-    for (WrapperKind wrapper in WrapperKind.values) {
-      for (AssignmentKind assignment in AssignmentKind.values) {
-        SimpleIdentifier identifier = _createIdentifier(wrapper, assignment);
-        if (wrapper == WrapperKind.PREFIXED_LEFT ||
-            wrapper == WrapperKind.PROPERTY_LEFT ||
-            assignment == AssignmentKind.BINARY ||
-            assignment == AssignmentKind.COMPOUND_RIGHT ||
-            assignment == AssignmentKind.PREFIX_NOT ||
-            assignment == AssignmentKind.SIMPLE_RIGHT ||
-            assignment == AssignmentKind.NONE) {
-          if (identifier.inSetterContext()) {
-            fail("Expected ${_topMostNode(identifier).toSource()} to be false");
-          }
-        } else {
-          if (!identifier.inSetterContext()) {
-            fail("Expected ${_topMostNode(identifier).toSource()} to be true");
-          }
-        }
-      }
-    }
-  }
-
-  void test_inSetterContext_forEachLoop() {
-    SimpleIdentifier identifier = AstFactory.identifier3("a");
-    Expression iterator = AstFactory.listLiteral();
-    Statement body = AstFactory.block();
-    AstFactory.forEachStatement2(identifier, iterator, body);
-    expect(identifier.inSetterContext(), isTrue);
-  }
-
-  void test_isQualified_inMethodInvocation_noTarget() {
-    MethodInvocation invocation =
-        AstFactory.methodInvocation2("test", [AstFactory.identifier3("arg0")]);
-    SimpleIdentifier identifier = invocation.methodName;
-    expect(identifier.isQualified, isFalse);
-  }
-
-  void test_isQualified_inMethodInvocation_withTarget() {
-    MethodInvocation invocation = AstFactory.methodInvocation(
-        AstFactory.identifier3("target"),
-        "test",
-        [AstFactory.identifier3("arg0")]);
-    SimpleIdentifier identifier = invocation.methodName;
-    expect(identifier.isQualified, isTrue);
-  }
-
-  void test_isQualified_inPrefixedIdentifier_name() {
-    SimpleIdentifier identifier = AstFactory.identifier3("test");
-    AstFactory.identifier4("prefix", identifier);
-    expect(identifier.isQualified, isTrue);
-  }
-
-  void test_isQualified_inPrefixedIdentifier_prefix() {
-    SimpleIdentifier identifier = AstFactory.identifier3("test");
-    AstFactory.identifier(identifier, AstFactory.identifier3("name"));
-    expect(identifier.isQualified, isFalse);
-  }
-
-  void test_isQualified_inPropertyAccess_name() {
-    SimpleIdentifier identifier = AstFactory.identifier3("test");
-    AstFactory.propertyAccess(AstFactory.identifier3("target"), identifier);
-    expect(identifier.isQualified, isTrue);
-  }
-
-  void test_isQualified_inPropertyAccess_target() {
-    SimpleIdentifier identifier = AstFactory.identifier3("test");
-    AstFactory.propertyAccess(identifier, AstFactory.identifier3("name"));
-    expect(identifier.isQualified, isFalse);
-  }
-
-  void test_isQualified_inReturnStatement() {
-    SimpleIdentifier identifier = AstFactory.identifier3("test");
-    AstFactory.returnStatement2(identifier);
-    expect(identifier.isQualified, isFalse);
-  }
-
-  SimpleIdentifier _createIdentifier(
-      WrapperKind wrapper, AssignmentKind assignment) {
-    SimpleIdentifier identifier = AstFactory.identifier3("a");
-    Expression expression = identifier;
-    while (true) {
-      if (wrapper == WrapperKind.PREFIXED_LEFT) {
-        expression =
-            AstFactory.identifier(identifier, AstFactory.identifier3("_"));
-      } else if (wrapper == WrapperKind.PREFIXED_RIGHT) {
-        expression =
-            AstFactory.identifier(AstFactory.identifier3("_"), identifier);
-      } else if (wrapper == WrapperKind.PROPERTY_LEFT) {
-        expression = AstFactory.propertyAccess2(expression, "_");
-      } else if (wrapper == WrapperKind.PROPERTY_RIGHT) {
-        expression =
-            AstFactory.propertyAccess(AstFactory.identifier3("_"), identifier);
-      } else if (wrapper == WrapperKind.NONE) {}
-      break;
-    }
-    while (true) {
-      if (assignment == AssignmentKind.BINARY) {
-        AstFactory.binaryExpression(
-            expression, TokenType.PLUS, AstFactory.identifier3("_"));
-      } else if (assignment == AssignmentKind.COMPOUND_LEFT) {
-        AstFactory.assignmentExpression(
-            expression, TokenType.PLUS_EQ, AstFactory.identifier3("_"));
-      } else if (assignment == AssignmentKind.COMPOUND_RIGHT) {
-        AstFactory.assignmentExpression(
-            AstFactory.identifier3("_"), TokenType.PLUS_EQ, expression);
-      } else if (assignment == AssignmentKind.POSTFIX_INC) {
-        AstFactory.postfixExpression(expression, TokenType.PLUS_PLUS);
-      } else if (assignment == AssignmentKind.PREFIX_DEC) {
-        AstFactory.prefixExpression(TokenType.MINUS_MINUS, expression);
-      } else if (assignment == AssignmentKind.PREFIX_INC) {
-        AstFactory.prefixExpression(TokenType.PLUS_PLUS, expression);
-      } else if (assignment == AssignmentKind.PREFIX_NOT) {
-        AstFactory.prefixExpression(TokenType.BANG, expression);
-      } else if (assignment == AssignmentKind.SIMPLE_LEFT) {
-        AstFactory.assignmentExpression(
-            expression, TokenType.EQ, AstFactory.identifier3("_"));
-      } else if (assignment == AssignmentKind.SIMPLE_RIGHT) {
-        AstFactory.assignmentExpression(
-            AstFactory.identifier3("_"), TokenType.EQ, expression);
-      } else if (assignment == AssignmentKind.NONE) {}
-      break;
-    }
-    return identifier;
-  }
-
-  /**
-   * Return the top-most node in the AST structure containing the given identifier.
-   *
-   * @param identifier the identifier in the AST structure being traversed
-   * @return the root of the AST structure containing the identifier
-   */
-  AstNode _topMostNode(SimpleIdentifier identifier) {
-    AstNode child = identifier;
-    AstNode parent = identifier.parent;
-    while (parent != null) {
-      child = parent;
-      parent = parent.parent;
-    }
-    return child;
-  }
-}
-
-@reflectiveTest
-class SimpleStringLiteralTest extends ParserTestCase {
-  void test_contentsEnd() {
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
-            .contentsEnd,
-        2);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString('"X"'), "X")
-            .contentsEnd,
-        2);
-
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString('"""X"""'), "X")
-            .contentsEnd,
-        4);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
-            .contentsEnd,
-        4);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("'''  \nX'''"), "X").contentsEnd,
-        7);
-
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
-            .contentsEnd,
-        3);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString('r"X"'), "X")
-            .contentsEnd,
-        3);
-
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString('r"""X"""'), "X")
-            .contentsEnd,
-        5);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
-            .contentsEnd,
-        5);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("r'''  \nX'''"), "X").contentsEnd,
-        8);
-  }
-
-  void test_contentsOffset() {
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
-            .contentsOffset,
-        1);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
-            .contentsOffset,
-        1);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X").contentsOffset,
-        3);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
-            .contentsOffset,
-        3);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
-            .contentsOffset,
-        2);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
-            .contentsOffset,
-        2);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X").contentsOffset,
-        4);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
-            .contentsOffset,
-        4);
-    // leading whitespace
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("''' \ \nX''"), "X").contentsOffset,
-        6);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString('r""" \ \nX"""'), "X").contentsOffset,
-        7);
-  }
-
-  void test_isMultiline() {
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X")
-            .isMultiline,
-        isFalse);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
-            .isMultiline,
-        isFalse);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
-            .isMultiline,
-        isFalse);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
-            .isMultiline,
-        isFalse);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
-            .isMultiline,
-        isTrue);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
-            .isMultiline,
-        isTrue);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X").isMultiline,
-        isTrue);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X").isMultiline,
-        isTrue);
-  }
-
-  void test_isRaw() {
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("'X'"), "X").isRaw,
-        isFalse);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("\"X\""), "X")
-            .isRaw,
-        isFalse);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("\"\"\"X\"\"\""), "X").isRaw,
-        isFalse);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("'''X'''"), "X")
-            .isRaw,
-        isFalse);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r'X'"), "X")
-            .isRaw,
-        isTrue);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r\"X\""), "X")
-            .isRaw,
-        isTrue);
-    expect(
-        new SimpleStringLiteral(
-            TokenFactory.tokenFromString("r\"\"\"X\"\"\""), "X").isRaw,
-        isTrue);
-    expect(
-        new SimpleStringLiteral(TokenFactory.tokenFromString("r'''X'''"), "X")
-            .isRaw,
-        isTrue);
-  }
-
-  void test_isSingleQuoted() {
-    // '
-    {
-      var token = TokenFactory.tokenFromString("'X'");
-      var node = new SimpleStringLiteral(token, null);
-      expect(node.isSingleQuoted, isTrue);
-    }
-    // '''
-    {
-      var token = TokenFactory.tokenFromString("'''X'''");
-      var node = new SimpleStringLiteral(token, null);
-      expect(node.isSingleQuoted, isTrue);
-    }
-    // "
-    {
-      var token = TokenFactory.tokenFromString('"X"');
-      var node = new SimpleStringLiteral(token, null);
-      expect(node.isSingleQuoted, isFalse);
-    }
-    // """
-    {
-      var token = TokenFactory.tokenFromString('"""X"""');
-      var node = new SimpleStringLiteral(token, null);
-      expect(node.isSingleQuoted, isFalse);
-    }
-  }
-
-  void test_isSingleQuoted_raw() {
-    // r'
-    {
-      var token = TokenFactory.tokenFromString("r'X'");
-      var node = new SimpleStringLiteral(token, null);
-      expect(node.isSingleQuoted, isTrue);
-    }
-    // r'''
-    {
-      var token = TokenFactory.tokenFromString("r'''X'''");
-      var node = new SimpleStringLiteral(token, null);
-      expect(node.isSingleQuoted, isTrue);
-    }
-    // r"
-    {
-      var token = TokenFactory.tokenFromString('r"X"');
-      var node = new SimpleStringLiteral(token, null);
-      expect(node.isSingleQuoted, isFalse);
-    }
-    // r"""
-    {
-      var token = TokenFactory.tokenFromString('r"""X"""');
-      var node = new SimpleStringLiteral(token, null);
-      expect(node.isSingleQuoted, isFalse);
-    }
-  }
-
-  void test_simple() {
-    Token token = TokenFactory.tokenFromString("'value'");
-    SimpleStringLiteral stringLiteral = new SimpleStringLiteral(token, "value");
-    expect(stringLiteral.literal, same(token));
-    expect(stringLiteral.beginToken, same(token));
-    expect(stringLiteral.endToken, same(token));
-    expect(stringLiteral.value, "value");
-  }
-}
-
-@reflectiveTest
-class StringInterpolationTest extends ParserTestCase {
-  void test_contentsOffsetEnd() {
-    AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
-    // 'a${bb}ccc'
-    {
-      var ae = AstFactory.interpolationString("'a", "a");
-      var cToken = new StringToken(TokenType.STRING, "ccc'", 10);
-      var cElement = new InterpolationString(cToken, 'ccc');
-      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
-      expect(node.contentsOffset, 1);
-      expect(node.contentsEnd, 10 + 4 - 1);
-    }
-    // '''a${bb}ccc'''
-    {
-      var ae = AstFactory.interpolationString("'''a", "a");
-      var cToken = new StringToken(TokenType.STRING, "ccc'''", 10);
-      var cElement = new InterpolationString(cToken, 'ccc');
-      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
-      expect(node.contentsOffset, 3);
-      expect(node.contentsEnd, 10 + 4 - 1);
-    }
-    // """a${bb}ccc"""
-    {
-      var ae = AstFactory.interpolationString('"""a', "a");
-      var cToken = new StringToken(TokenType.STRING, 'ccc"""', 10);
-      var cElement = new InterpolationString(cToken, 'ccc');
-      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
-      expect(node.contentsOffset, 3);
-      expect(node.contentsEnd, 10 + 4 - 1);
-    }
-    // r'a${bb}ccc'
-    {
-      var ae = AstFactory.interpolationString("r'a", "a");
-      var cToken = new StringToken(TokenType.STRING, "ccc'", 10);
-      var cElement = new InterpolationString(cToken, 'ccc');
-      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
-      expect(node.contentsOffset, 2);
-      expect(node.contentsEnd, 10 + 4 - 1);
-    }
-    // r'''a${bb}ccc'''
-    {
-      var ae = AstFactory.interpolationString("r'''a", "a");
-      var cToken = new StringToken(TokenType.STRING, "ccc'''", 10);
-      var cElement = new InterpolationString(cToken, 'ccc');
-      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
-      expect(node.contentsOffset, 4);
-      expect(node.contentsEnd, 10 + 4 - 1);
-    }
-    // r"""a${bb}ccc"""
-    {
-      var ae = AstFactory.interpolationString('r"""a', "a");
-      var cToken = new StringToken(TokenType.STRING, 'ccc"""', 10);
-      var cElement = new InterpolationString(cToken, 'ccc');
-      StringInterpolation node = AstFactory.string([ae, ae, cElement]);
-      expect(node.contentsOffset, 4);
-      expect(node.contentsEnd, 10 + 4 - 1);
-    }
-  }
-
-  void test_isMultiline() {
-    var b = AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
-    // '
-    {
-      var a = AstFactory.interpolationString("'a", "a");
-      var c = AstFactory.interpolationString("ccc'", "ccc");
-      StringInterpolation node = AstFactory.string([a, b, c]);
-      expect(node.isMultiline, isFalse);
-    }
-    // '''
-    {
-      var a = AstFactory.interpolationString("'''a", "a");
-      var c = AstFactory.interpolationString("ccc'''", "ccc");
-      StringInterpolation node = AstFactory.string([a, b, c]);
-      expect(node.isMultiline, isTrue);
-    }
-    // "
-    {
-      var a = AstFactory.interpolationString('"a', "a");
-      var c = AstFactory.interpolationString('ccc"', "ccc");
-      StringInterpolation node = AstFactory.string([a, b, c]);
-      expect(node.isMultiline, isFalse);
-    }
-    // """
-    {
-      var a = AstFactory.interpolationString('"""a', "a");
-      var c = AstFactory.interpolationString('ccc"""', "ccc");
-      StringInterpolation node = AstFactory.string([a, b, c]);
-      expect(node.isMultiline, isTrue);
-    }
-  }
-
-  void test_isRaw() {
-    StringInterpolation node = AstFactory.string();
-    expect(node.isRaw, isFalse);
-  }
-
-  void test_isSingleQuoted() {
-    var b = AstFactory.interpolationExpression(AstFactory.identifier3('bb'));
-    // "
-    {
-      var a = AstFactory.interpolationString('"a', "a");
-      var c = AstFactory.interpolationString('ccc"', "ccc");
-      StringInterpolation node = AstFactory.string([a, b, c]);
-      expect(node.isSingleQuoted, isFalse);
-    }
-    // """
-    {
-      var a = AstFactory.interpolationString('"""a', "a");
-      var c = AstFactory.interpolationString('ccc"""', "ccc");
-      StringInterpolation node = AstFactory.string([a, b, c]);
-      expect(node.isSingleQuoted, isFalse);
-    }
-    // '
-    {
-      var a = AstFactory.interpolationString("'a", "a");
-      var c = AstFactory.interpolationString("ccc'", "ccc");
-      StringInterpolation node = AstFactory.string([a, b, c]);
-      expect(node.isSingleQuoted, isTrue);
-    }
-    // '''
-    {
-      var a = AstFactory.interpolationString("'''a", "a");
-      var c = AstFactory.interpolationString("ccc'''", "ccc");
-      StringInterpolation node = AstFactory.string([a, b, c]);
-      expect(node.isSingleQuoted, isTrue);
-    }
-  }
-}
-
-@reflectiveTest
 class ToSourceVisitorTest extends EngineTestCase {
   void test_visitAdjacentStrings() {
     _assertSource(
@@ -3648,8 +2381,8 @@
   void test_visitSwitchCase_noLabels() {
     _assertSource(
         "case a: {}",
-        AstFactory.switchCase(
-            AstFactory.identifier3("a"), [AstFactory.block()]));
+        AstFactory
+            .switchCase(AstFactory.identifier3("a"), [AstFactory.block()]));
   }
 
   void test_visitSwitchCase_singleLabel() {
@@ -3680,8 +2413,8 @@
   void test_visitSwitchDefault_singleLabel() {
     _assertSource(
         "l1: default: {}",
-        AstFactory.switchDefault(
-            [AstFactory.label2("l1")], [AstFactory.block()]));
+        AstFactory
+            .switchDefault([AstFactory.label2("l1")], [AstFactory.block()]));
   }
 
   void test_visitSwitchStatement() {
@@ -3932,50 +2665,3 @@
     expect(writer.toString(), expectedSource);
   }
 }
-
-@reflectiveTest
-class VariableDeclarationTest extends ParserTestCase {
-  void test_getDocumentationComment_onGrandParent() {
-    VariableDeclaration varDecl = AstFactory.variableDeclaration("a");
-    TopLevelVariableDeclaration decl =
-        AstFactory.topLevelVariableDeclaration2(Keyword.VAR, [varDecl]);
-    Comment comment = Comment.createDocumentationComment(new List<Token>(0));
-    expect(varDecl.documentationComment, isNull);
-    decl.documentationComment = comment;
-    expect(varDecl.documentationComment, isNotNull);
-    expect(decl.documentationComment, isNotNull);
-  }
-
-  void test_getDocumentationComment_onNode() {
-    VariableDeclaration decl = AstFactory.variableDeclaration("a");
-    Comment comment = Comment.createDocumentationComment(new List<Token>(0));
-    decl.documentationComment = comment;
-    expect(decl.documentationComment, isNotNull);
-  }
-}
-
-class WrapperKind extends Enum<WrapperKind> {
-  static const WrapperKind PREFIXED_LEFT =
-      const WrapperKind('PREFIXED_LEFT', 0);
-
-  static const WrapperKind PREFIXED_RIGHT =
-      const WrapperKind('PREFIXED_RIGHT', 1);
-
-  static const WrapperKind PROPERTY_LEFT =
-      const WrapperKind('PROPERTY_LEFT', 2);
-
-  static const WrapperKind PROPERTY_RIGHT =
-      const WrapperKind('PROPERTY_RIGHT', 3);
-
-  static const WrapperKind NONE = const WrapperKind('NONE', 4);
-
-  static const List<WrapperKind> values = const [
-    PREFIXED_LEFT,
-    PREFIXED_RIGHT,
-    PROPERTY_LEFT,
-    PROPERTY_RIGHT,
-    NONE
-  ];
-
-  const WrapperKind(String name, int ordinal) : super(name, ordinal);
-}
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index bf01506..f907ae3 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -2,13 +2,13 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analyzer.test.generated.element_test;
+library analyzer.test.src.dart.element.element_test;
 
+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/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/java_core.dart';
@@ -1857,6 +1857,14 @@
     expect(paramType.prunedTypedefs[0], same(f));
   }
 
+  void test_resolveToBound() {
+    FunctionElementImpl f = ElementFactory.functionElement('f');
+    FunctionTypeImpl type = f.type;
+
+    // Returns this.
+    expect(type.resolveToBound(null), same(type));
+  }
+
   void test_returnType_pruned_no_type_arguments() {
     FunctionTypeAliasElementImpl f =
         ElementFactory.functionTypeAliasElement('f');
@@ -3392,6 +3400,14 @@
     expect(typeA.lookUpSetter("s", library), isNull);
   }
 
+  void test_resolveToBound() {
+    InterfaceTypeImpl type =
+        ElementFactory.classElement2("A").type as InterfaceTypeImpl;
+
+    // Returns this.
+    expect(type.resolveToBound(null), same(type));
+  }
+
   void test_setTypeArguments() {
     InterfaceTypeImpl type =
         ElementFactory.classElement2("A").type as InterfaceTypeImpl;
@@ -3936,6 +3952,36 @@
     expect(typeParameterTypeT.isMoreSpecificThan(classS.type), isTrue);
   }
 
+  void test_resolveToBound_unbound() {
+    TypeParameterTypeImpl type = new TypeParameterTypeImpl(
+        new TypeParameterElementImpl.forNode(AstFactory.identifier3("E")));
+    // Returns whatever type is passed to resolveToBound().
+    expect(type.resolveToBound(VoidTypeImpl.instance),
+        same(VoidTypeImpl.instance));
+  }
+
+  void test_resolveToBound_bound() {
+    ClassElementImpl classS = ElementFactory.classElement2("A");
+    TypeParameterElementImpl element =
+    new TypeParameterElementImpl.forNode(AstFactory.identifier3("E"));
+    element.bound = classS.type;
+    TypeParameterTypeImpl type = new TypeParameterTypeImpl(element);
+    expect(type.resolveToBound(null), same(classS.type));
+  }
+
+  void test_resolveToBound_nestedBound() {
+    ClassElementImpl classS = ElementFactory.classElement2("A");
+    TypeParameterElementImpl elementE =
+    new TypeParameterElementImpl.forNode(AstFactory.identifier3("E"));
+    elementE.bound = classS.type;
+    TypeParameterTypeImpl typeE = new TypeParameterTypeImpl(elementE);
+    TypeParameterElementImpl elementF =
+    new TypeParameterElementImpl.forNode(AstFactory.identifier3("F"));
+    elementF.bound = typeE;
+    TypeParameterTypeImpl typeF = new TypeParameterTypeImpl(elementE);
+    expect(typeF.resolveToBound(null), same(classS.type));
+  }
+
   void test_substitute_equal() {
     TypeParameterElementImpl element =
         new TypeParameterElementImpl.forNode(AstFactory.identifier3("E"));
@@ -3995,6 +4041,11 @@
   void test_isVoid() {
     expect(_voidType.isVoid, isTrue);
   }
+
+  void test_resolveToBound() {
+    // Returns this.
+    expect(_voidType.resolveToBound(null), same(_voidType));
+  }
 }
 
 class _FunctionTypeImplTest_isSubtypeOf_baseCase_classFunction
diff --git a/pkg/analyzer/test/src/dart/element/test_all.dart b/pkg/analyzer/test/src/dart/element/test_all.dart
index c401919..1997466 100644
--- a/pkg/analyzer/test/src/dart/element/test_all.dart
+++ b/pkg/analyzer/test/src/dart/element/test_all.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analyzer.test.generated.test_all;
+library analyzer.test.src.dart.element.test_all;
 
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analyzer/test/src/dart/test_all.dart b/pkg/analyzer/test/src/dart/test_all.dart
index f0c4598..ec4f182 100644
--- a/pkg/analyzer/test/src/dart/test_all.dart
+++ b/pkg/analyzer/test/src/dart/test_all.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-library analyzer.test.generated.test_all;
+library analyzer.test.src.dart.test_all;
 
 import 'package:unittest/unittest.dart';
 
diff --git a/pkg/analyzer/test/src/mock_sdk.dart b/pkg/analyzer/test/src/mock_sdk.dart
deleted file mode 100644
index b08e293..0000000
--- a/pkg/analyzer/test/src/mock_sdk.dart
+++ /dev/null
@@ -1,328 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library analyzer.test.src.mock_sdk;
-
-import 'package:analyzer/file_system/file_system.dart' as resource;
-import 'package:analyzer/file_system/memory_file_system.dart' as resource;
-import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/source.dart';
-
-class MockSdk implements DartSdk {
-  static const _MockSdkLibrary LIB_CORE = const _MockSdkLibrary(
-      'dart:core',
-      '/lib/core/core.dart',
-      '''
-library dart.core;
-
-import 'dart:async';
-
-class Object {
-  bool operator ==(other) => identical(this, other);
-  String toString() => 'a string';
-  int get hashCode => 0;
-}
-
-class Function {}
-class StackTrace {}
-class Symbol {}
-class Type {}
-
-abstract class Comparable<T> {
-  int compareTo(T other);
-}
-
-abstract class String implements Comparable<String> {
-  external factory String.fromCharCodes(Iterable<int> charCodes,
-                                        [int start = 0, int end]);
-  bool get isEmpty => false;
-  bool get isNotEmpty => false;
-  int get length => 0;
-  String toUpperCase();
-  List<int> get codeUnits;
-}
-
-class bool extends Object {}
-abstract class num implements Comparable<num> {
-  bool operator <(num other);
-  bool operator <=(num other);
-  bool operator >(num other);
-  bool operator >=(num other);
-  num operator +(num other);
-  num operator -(num other);
-  num operator *(num other);
-  num operator /(num other);
-  int toInt();
-  num abs();
-  int round();
-}
-abstract class int extends num {
-  bool get isEven => false;
-  int operator -();
-  external static int parse(String source,
-                            { int radix,
-                              int onError(String source) });
-}
-class double extends num {}
-class DateTime extends Object {}
-class Null extends Object {}
-
-class Deprecated extends Object {
-  final String expires;
-  const Deprecated(this.expires);
-}
-const Object deprecated = const Deprecated("next release");
-
-class Iterator<E> {
-  bool moveNext();
-  E get current;
-}
-
-abstract class Iterable<E> {
-  Iterator<E> get iterator;
-  bool get isEmpty;
-}
-
-abstract class List<E> implements Iterable<E> {
-  void add(E value);
-  E operator [](int index);
-  void operator []=(int index, E value);
-  Iterator<E> get iterator => null;
-  void clear();
-}
-
-abstract class Map<K, V> extends Object {
-  Iterable<K> get keys;
-}
-
-external bool identical(Object a, Object b);
-
-void print(Object object) {}
-
-class _Override {
-  const _Override();
-}
-const Object override = const _Override();
-''');
-
-  static const _MockSdkLibrary LIB_ASYNC = const _MockSdkLibrary(
-      'dart:async',
-      '/lib/async/async.dart',
-      '''
-library dart.async;
-
-import 'dart:math';
-
-class Future<T> {
-  factory Future.delayed(Duration duration, [T computation()]) => null;
-  factory Future.value([value]) => null;
-  static Future wait(List<Future> futures) => null;
-}
-
-class Stream<T> {}
-abstract class StreamTransformer<S, T> {}
-''');
-
-  static const _MockSdkLibrary LIB_COLLECTION = const _MockSdkLibrary(
-      'dart:collection',
-      '/lib/collection/collection.dart',
-      '''
-library dart.collection;
-
-abstract class HashMap<K, V> implements Map<K, V> {}
-''');
-
-  static const _MockSdkLibrary LIB_CONVERT = const _MockSdkLibrary(
-      'dart:convert',
-      '/lib/convert/convert.dart',
-      '''
-library dart.convert;
-
-import 'dart:async';
-
-abstract class Converter<S, T> implements StreamTransformer {}
-class JsonDecoder extends Converter<String, Object> {}
-''');
-
-  static const _MockSdkLibrary LIB_MATH = const _MockSdkLibrary(
-      'dart:math',
-      '/lib/math/math.dart',
-      '''
-library dart.math;
-const double E = 2.718281828459045;
-const double PI = 3.1415926535897932;
-const double LN10 =  2.302585092994046;
-num min(num a, num b) => 0;
-num max(num a, num b) => 0;
-external double cos(num x);
-external double sin(num x);
-external double sqrt(num x);
-class Random {
-  bool nextBool() => true;
-  double nextDouble() => 2.0;
-  int nextInt() => 1;
-}
-''');
-
-  static const _MockSdkLibrary LIB_HTML = const _MockSdkLibrary(
-      'dart:html',
-      '/lib/html/dartium/html_dartium.dart',
-      '''
-library dart.html;
-class HtmlElement {}
-''');
-
-  static const List<SdkLibrary> LIBRARIES = const [
-    LIB_CORE,
-    LIB_ASYNC,
-    LIB_COLLECTION,
-    LIB_CONVERT,
-    LIB_MATH,
-    LIB_HTML,
-  ];
-
-  final resource.MemoryResourceProvider provider =
-      new resource.MemoryResourceProvider();
-
-  /**
-   * The [AnalysisContext] which is used for all of the sources.
-   */
-  InternalAnalysisContext _analysisContext;
-
-  MockSdk() {
-    LIBRARIES.forEach((_MockSdkLibrary library) {
-      provider.newFile(library.path, library.content);
-    });
-  }
-
-  @override
-  AnalysisContext get context {
-    if (_analysisContext == null) {
-      _analysisContext = new SdkAnalysisContext();
-      SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
-      _analysisContext.sourceFactory = factory;
-      ChangeSet changeSet = new ChangeSet();
-      for (String uri in uris) {
-        Source source = factory.forUri(uri);
-        changeSet.addedSource(source);
-      }
-      _analysisContext.applyChanges(changeSet);
-    }
-    return _analysisContext;
-  }
-
-  @override
-  List<SdkLibrary> get sdkLibraries => LIBRARIES;
-
-  @override
-  String get sdkVersion => throw unimplemented;
-
-  UnimplementedError get unimplemented => new UnimplementedError();
-
-  @override
-  List<String> get uris {
-    List<String> uris = <String>[];
-    for (SdkLibrary library in LIBRARIES) {
-      uris.add(library.shortName);
-    }
-    return uris;
-  }
-
-  @override
-  Source fromFileUri(Uri uri) {
-    String filePath = uri.path;
-    String libPath = '/lib';
-    if (!filePath.startsWith("$libPath/")) {
-      return null;
-    }
-    for (SdkLibrary library in LIBRARIES) {
-      String libraryPath = library.path;
-      if (filePath.replaceAll('\\', '/') == libraryPath) {
-        try {
-          resource.File file = provider.getResource(uri.path);
-          Uri dartUri = Uri.parse(library.shortName);
-          return file.createSource(dartUri);
-        } catch (exception) {
-          return null;
-        }
-      }
-      if (filePath.startsWith("$libraryPath/")) {
-        String pathInLibrary = filePath.substring(libraryPath.length + 1);
-        String path = '${library.shortName}/$pathInLibrary';
-        try {
-          resource.File file = provider.getResource(uri.path);
-          Uri dartUri = new Uri(scheme: 'dart', path: path);
-          return file.createSource(dartUri);
-        } catch (exception) {
-          return null;
-        }
-      }
-    }
-    return null;
-  }
-
-  @override
-  SdkLibrary getSdkLibrary(String dartUri) {
-    // getSdkLibrary() is only used to determine whether a library is internal
-    // to the SDK.  The mock SDK doesn't have any internals, so it's safe to
-    // return null.
-    return null;
-  }
-
-  @override
-  Source mapDartUri(String dartUri) {
-    const Map<String, String> uriToPath = const {
-      "dart:core": "/lib/core/core.dart",
-      "dart:html": "/lib/html/dartium/html_dartium.dart",
-      "dart:async": "/lib/async/async.dart",
-      "dart:collection": "/lib/collection/collection.dart",
-      "dart:convert": "/lib/convert/convert.dart",
-      "dart:math": "/lib/math/math.dart"
-    };
-
-    String path = uriToPath[dartUri];
-    if (path != null) {
-      resource.File file = provider.getResource(path);
-      Uri uri = new Uri(scheme: 'dart', path: dartUri.substring(5));
-      return file.createSource(uri);
-    }
-
-    // If we reach here then we tried to use a dartUri that's not in the
-    // table above.
-    return null;
-  }
-}
-
-class _MockSdkLibrary implements SdkLibrary {
-  final String shortName;
-  final String path;
-  final String content;
-
-  const _MockSdkLibrary(this.shortName, this.path, this.content);
-
-  @override
-  String get category => throw unimplemented;
-
-  @override
-  bool get isDart2JsLibrary => throw unimplemented;
-
-  @override
-  bool get isDocumented => throw unimplemented;
-
-  @override
-  bool get isImplementation => throw unimplemented;
-
-  @override
-  bool get isInternal => throw unimplemented;
-
-  @override
-  bool get isShared => throw unimplemented;
-
-  @override
-  bool get isVmLibrary => throw unimplemented;
-
-  UnimplementedError get unimplemented => new UnimplementedError();
-}
diff --git a/pkg/analyzer/test/src/summary/flat_buffers_test.dart b/pkg/analyzer/test/src/summary/flat_buffers_test.dart
index e7b7804..076df23 100644
--- a/pkg/analyzer/test/src/summary/flat_buffers_test.dart
+++ b/pkg/analyzer/test/src/summary/flat_buffers_test.dart
@@ -4,6 +4,8 @@
 
 library test.src.summary.flat_buffers_test;
 
+import 'dart:typed_data';
+
 import 'package:analyzer/src/summary/flat_buffers.dart';
 import 'package:unittest/unittest.dart';
 
@@ -53,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();
@@ -86,6 +116,39 @@
     expect(const Int32Reader().vTableGet(object, 1, 15), 20);
   }
 
+  void test_table_format() {
+    Uint8List byteList;
+    {
+      Builder builder = new Builder(initialSize: 0);
+      builder.startTable();
+      builder.addInt32(0, 10);
+      builder.addInt32(1, 20);
+      builder.addInt32(2, 30);
+      byteList = builder.finish(builder.endTable());
+    }
+    // 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);
+    // 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 10.
+    expect(byteData.getUint16(vTableLoc, Endianness.LITTLE_ENDIAN), 10);
+    // Next 2 bytes are the size of the object in bytes (including the vtable
+    // pointer), which should be 16.
+    expect(byteData.getUint16(vTableLoc + 2, Endianness.LITTLE_ENDIAN), 16);
+    // Remaining 6 bytes are the offsets within the object where the ints are
+    // located.
+    for (int i = 0; i < 3; i++) {
+      int offset =
+          byteData.getUint16(vTableLoc + 4 + 2 * i, Endianness.LITTLE_ENDIAN);
+      expect(byteData.getInt32(tableDataLoc + offset, Endianness.LITTLE_ENDIAN),
+          10 + 10 * i);
+    }
+  }
+
   void test_table_types() {
     List<int> byteList;
     {
@@ -97,6 +160,8 @@
       builder.addInt32(2, 20);
       builder.addOffset(3, stringOffset);
       builder.addInt32(4, 40);
+      builder.addUint32(5, 0x9ABCDEF0);
+      builder.addUint8(6, 0x9A);
       Offset offset = builder.endTable();
       byteList = builder.finish(offset);
     }
@@ -107,6 +172,81 @@
     expect(const Int32Reader().vTableGet(object, 2), 20);
     expect(const StringReader().vTableGet(object, 3), '12345');
     expect(const Int32Reader().vTableGet(object, 4), 40);
+    expect(const Uint32Reader().vTableGet(object, 5), 0x9ABCDEF0);
+    expect(const Uint8Reader().vTableGet(object, 6), 0x9A);
+  }
+
+  void test_writeList_of_Uint32() {
+    List<int> values = <int>[10, 100, 12345, 0x9abcdef0];
+    // write
+    List<int> byteList;
+    {
+      Builder builder = new Builder(initialSize: 0);
+      Offset offset = builder.writeListUint32(values);
+      byteList = builder.finish(offset);
+    }
+    // read and verify
+    BufferPointer root = new BufferPointer.fromBytes(byteList);
+    List<int> items = const Uint32ListReader().read(root);
+    expect(items, hasLength(4));
+    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
+    List<int> byteList;
+    {
+      Builder builder = new Builder(initialSize: 0);
+      Offset offset = builder.writeListFloat64(values);
+      byteList = builder.finish(offset);
+    }
+    // read and verify
+    BufferPointer root = new BufferPointer.fromBytes(byteList);
+    List<double> items = const Float64ListReader().read(root);
+    expect(items, hasLength(5));
+    expect(items, orderedEquals(values));
   }
 
   void test_writeList_ofInt32() {
@@ -195,6 +335,34 @@
     expect(items, contains('12345'));
     expect(items, contains('ABC'));
   }
+
+  void test_writeList_ofUint32() {
+    List<int> byteList;
+    {
+      Builder builder = new Builder(initialSize: 0);
+      Offset offset = builder.writeListUint32(<int>[1, 2, 0x9ABCDEF0]);
+      byteList = builder.finish(offset);
+    }
+    // read and verify
+    BufferPointer root = new BufferPointer.fromBytes(byteList);
+    List<int> items = const ListReader<int>(const Uint32Reader()).read(root);
+    expect(items, hasLength(3));
+    expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
+  }
+
+  void test_writeList_ofUint8() {
+    List<int> byteList;
+    {
+      Builder builder = new Builder(initialSize: 0);
+      Offset offset = builder.writeListUint8(<int>[1, 2, 0x9A]);
+      byteList = builder.finish(offset);
+    }
+    // read and verify
+    BufferPointer root = new BufferPointer.fromBytes(byteList);
+    List<int> items = const ListReader<int>(const Uint8Reader()).read(root);
+    expect(items, hasLength(3));
+    expect(items, orderedEquals(<int>[1, 2, 0x9A]));
+  }
 }
 
 class StringListWrapperImpl {
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/name_filter_test.dart b/pkg/analyzer/test/src/summary/name_filter_test.dart
index a3c9ae5..5f5ca4f 100644
--- a/pkg/analyzer/test/src/summary/name_filter_test.dart
+++ b/pkg/analyzer/test/src/summary/name_filter_test.dart
@@ -14,28 +14,11 @@
   runReflectiveTests(NameFilterTest);
 }
 
-class MockUnlinkedCombinator implements UnlinkedCombinator {
-  @override
-  final List<String> hides;
-
-  @override
-  final List<String> shows;
-
-  MockUnlinkedCombinator(
-      {this.hides: const <String>[], this.shows: const <String>[]});
-
-  @override
-  Map<String, Object> toMap() {
-    fail('toMap() called unexpectedly');
-    return null;
-  }
-}
-
 @reflectiveTest
 class NameFilterTest {
   test_accepts_accessors_hide() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(hides: ['bar']));
+        new UnlinkedCombinatorBuilder(hides: ['bar']));
     expect(filter.accepts('foo'), isTrue);
     expect(filter.accepts('foo='), isTrue);
     expect(filter.accepts('bar'), isFalse);
@@ -44,7 +27,7 @@
 
   test_accepts_accessors_show() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(shows: ['foo']));
+        new UnlinkedCombinatorBuilder(shows: ['foo']));
     expect(filter.accepts('foo'), isTrue);
     expect(filter.accepts('foo='), isTrue);
     expect(filter.accepts('bar'), isFalse);
@@ -88,7 +71,7 @@
 
   test_forUnlinkedCombinator_hide() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(hides: ['foo', 'bar']));
+        new UnlinkedCombinatorBuilder(hides: ['foo', 'bar']));
     expect(filter.accepts('foo'), isFalse);
     expect(filter.accepts('bar'), isFalse);
     expect(filter.accepts('baz'), isTrue);
@@ -99,7 +82,7 @@
 
   test_forUnlinkedCombinator_show() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(shows: ['foo', 'bar']));
+        new UnlinkedCombinatorBuilder(shows: ['foo', 'bar']));
     expect(filter.accepts('foo'), isTrue);
     expect(filter.accepts('bar'), isTrue);
     expect(filter.accepts('baz'), isFalse);
@@ -110,8 +93,8 @@
 
   test_forUnlinkedCombinators() {
     NameFilter filter = new NameFilter.forUnlinkedCombinators([
-      new MockUnlinkedCombinator(hides: ['foo']),
-      new MockUnlinkedCombinator(hides: ['bar'])
+      new UnlinkedCombinatorBuilder(hides: ['foo']),
+      new UnlinkedCombinatorBuilder(hides: ['bar'])
     ]);
     expect(filter.accepts('foo'), isFalse);
     expect(filter.accepts('bar'), isFalse);
@@ -130,9 +113,9 @@
 
   test_merge_hides_hides() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(hides: ['foo'])).merge(
+        new UnlinkedCombinatorBuilder(hides: ['foo'])).merge(
         new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(hides: ['bar'])));
+            new UnlinkedCombinatorBuilder(hides: ['bar'])));
     expect(filter.accepts('foo'), isFalse);
     expect(filter.accepts('bar'), isFalse);
     expect(filter.accepts('baz'), isTrue);
@@ -143,7 +126,7 @@
 
   test_merge_hides_identity() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(hides: ['foo', 'bar']))
+            new UnlinkedCombinatorBuilder(hides: ['foo', 'bar']))
         .merge(NameFilter.identity);
     expect(filter.accepts('foo'), isFalse);
     expect(filter.accepts('bar'), isFalse);
@@ -155,9 +138,9 @@
 
   test_merge_hides_shows() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(hides: ['bar', 'baz'])).merge(
+        new UnlinkedCombinatorBuilder(hides: ['bar', 'baz'])).merge(
         new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(shows: ['foo', 'bar'])));
+            new UnlinkedCombinatorBuilder(shows: ['foo', 'bar'])));
     expect(filter.accepts('foo'), isTrue);
     expect(filter.accepts('bar'), isFalse);
     expect(filter.accepts('baz'), isFalse);
@@ -169,7 +152,7 @@
   test_merge_identity_hides() {
     NameFilter filter = NameFilter.identity.merge(
         new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(hides: ['foo', 'bar'])));
+            new UnlinkedCombinatorBuilder(hides: ['foo', 'bar'])));
     expect(filter.accepts('foo'), isFalse);
     expect(filter.accepts('bar'), isFalse);
     expect(filter.accepts('baz'), isTrue);
@@ -189,7 +172,7 @@
   test_merge_identity_shows() {
     NameFilter filter = NameFilter.identity.merge(
         new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(shows: ['foo', 'bar'])));
+            new UnlinkedCombinatorBuilder(shows: ['foo', 'bar'])));
     expect(filter.accepts('foo'), isTrue);
     expect(filter.accepts('bar'), isTrue);
     expect(filter.accepts('baz'), isFalse);
@@ -200,9 +183,9 @@
 
   test_merge_shows_hides() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(shows: ['foo', 'bar'])).merge(
+        new UnlinkedCombinatorBuilder(shows: ['foo', 'bar'])).merge(
         new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(hides: ['bar', 'baz'])));
+            new UnlinkedCombinatorBuilder(hides: ['bar', 'baz'])));
     expect(filter.accepts('foo'), isTrue);
     expect(filter.accepts('bar'), isFalse);
     expect(filter.accepts('baz'), isFalse);
@@ -213,7 +196,7 @@
 
   test_merge_shows_identity() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(shows: ['foo', 'bar']))
+            new UnlinkedCombinatorBuilder(shows: ['foo', 'bar']))
         .merge(NameFilter.identity);
     expect(filter.accepts('foo'), isTrue);
     expect(filter.accepts('bar'), isTrue);
@@ -225,9 +208,9 @@
 
   test_merge_shows_shows() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(shows: ['foo', 'bar'])).merge(
+        new UnlinkedCombinatorBuilder(shows: ['foo', 'bar'])).merge(
         new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(shows: ['bar', 'baz'])));
+            new UnlinkedCombinatorBuilder(shows: ['bar', 'baz'])));
     expect(filter.accepts('foo'), isFalse);
     expect(filter.accepts('bar'), isTrue);
     expect(filter.accepts('baz'), isFalse);
@@ -238,9 +221,9 @@
 
   test_merge_shows_shows_emptyResult() {
     NameFilter filter = new NameFilter.forUnlinkedCombinator(
-        new MockUnlinkedCombinator(shows: ['foo'])).merge(
+        new UnlinkedCombinatorBuilder(shows: ['foo'])).merge(
         new NameFilter.forUnlinkedCombinator(
-            new MockUnlinkedCombinator(shows: ['bar'])));
+            new UnlinkedCombinatorBuilder(shows: ['bar'])));
     expect(filter.accepts('foo'), isFalse);
     expect(filter.accepts('bar'), isFalse);
     expect(filter.accepts('baz'), isFalse);
diff --git a/pkg/analyzer/test/src/summary/prelinker_test.dart b/pkg/analyzer/test/src/summary/prelinker_test.dart
new file mode 100644
index 0000000..4453ab0
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/prelinker_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.summary.prelinker_test;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/prelink.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'summarize_elements_test.dart';
+import 'summary_common.dart';
+
+main() {
+  groupSep = ' | ';
+  runReflectiveTests(PrelinkerTest);
+}
+
+/**
+ * Override of [SummaryTest] which verifies the correctness of the prelinker by
+ * creating summaries from the element model, discarding their prelinked
+ * information, and then recreating it using the prelinker.
+ */
+@reflectiveTest
+class PrelinkerTest extends SummarizeElementsTest {
+  final Map<String, UnlinkedPublicNamespace> uriToPublicNamespace =
+      <String, UnlinkedPublicNamespace>{};
+
+  @override
+  bool get expectAbsoluteUrisInDependencies => false;
+
+  @override
+  bool get skipFullyLinkedData => true;
+
+  @override
+  bool get strongMode => false;
+
+  @override
+  Source addNamedSource(String filePath, String contents) {
+    Source source = super.addNamedSource(filePath, contents);
+    uriToPublicNamespace[absUri(filePath)] =
+        computePublicNamespaceFromText(contents, source);
+    return source;
+  }
+
+  String resolveToAbsoluteUri(LibraryElement library, String relativeUri) {
+    Source resolvedSource =
+        analysisContext.sourceFactory.resolveUri(library.source, relativeUri);
+    if (resolvedSource == null) {
+      fail('Failed to resolve relative uri "$relativeUri"');
+    }
+    return resolvedSource.uri.toString();
+  }
+
+  @override
+  void serializeLibraryElement(LibraryElement library) {
+    super.serializeLibraryElement(library);
+    Map<String, UnlinkedUnit> uriToUnit = <String, UnlinkedUnit>{};
+    expect(unlinkedUnits.length, unitUris.length);
+    for (int i = 1; i < unlinkedUnits.length; i++) {
+      uriToUnit[unitUris[i]] = unlinkedUnits[i];
+    }
+    UnlinkedUnit getPart(String relativeUri) {
+      String absoluteUri = resolveToAbsoluteUri(library, relativeUri);
+      UnlinkedUnit unit = uriToUnit[absoluteUri];
+      if (unit == null) {
+        fail('Prelinker unexpectedly requested unit for "$relativeUri"'
+            ' (resolves to "$absoluteUri").');
+      }
+      return unit;
+    }
+    UnlinkedPublicNamespace getImport(String relativeUri) {
+      String absoluteUri = resolveToAbsoluteUri(library, relativeUri);
+      UnlinkedPublicNamespace namespace = sdkPublicNamespace[absoluteUri];
+      if (namespace == null) {
+        namespace = uriToPublicNamespace[absoluteUri];
+      }
+      if (namespace == null && !allowMissingFiles) {
+        fail('Prelinker unexpectedly requested namespace for "$relativeUri"'
+            ' (resolves to "$absoluteUri").'
+            '  Namespaces available: ${uriToPublicNamespace.keys}');
+      }
+      return namespace;
+    }
+    linked = new LinkedLibrary.fromBuffer(
+        prelink(unlinkedUnits[0], getPart, getImport).toBuffer());
+    validateLinkedLibrary(linked);
+  }
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
new file mode 100644
index 0000000..37c2f4a
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/resynthesize_strong_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.summary.resynthesize_strong_test;
+
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'resynthesize_test.dart';
+
+main() {
+  groupSep = ' | ';
+  runReflectiveTests(ResynthStrongTest);
+}
+
+@reflectiveTest
+class ResynthStrongTest extends ResynthTest {
+  @override
+  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 c27b507..e163d04 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -4,17 +4,30 @@
 
 library test.src.serialization.elements_test;
 
-import 'package:analyzer/src/generated/element.dart';
+import 'dart:convert';
+
+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/ast/ast.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/generated/constant.dart' show DartObject;
+import 'package:analyzer/src/generated/element_handle.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart' show Namespace;
+import 'package:analyzer/src/generated/resolver.dart'
+    show Namespace, TypeProvider;
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/generated/testing/ast_factory.dart';
+import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/resynthesize.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
 import 'package:unittest/unittest.dart';
 
 import '../../generated/resolver_test.dart';
 import '../../reflective_tests.dart';
+import 'summary_common.dart' show canonicalize;
 
 main() {
   groupSep = ' | ';
@@ -24,6 +37,13 @@
 @reflectiveTest
 class ResynthTest extends ResolverTestCase {
   Set<Source> otherLibrarySources = new Set<Source>();
+  bool constantInitializersAreInvalid = false;
+
+  /**
+   * Determine the analysis options that should be used for this test.
+   */
+  AnalysisOptionsImpl createOptions() =>
+      new AnalysisOptionsImpl()..enableGenericMethods = true;
 
   void addLibrary(String uri) {
     otherLibrarySources.add(analysisContext2.sourceFactory.forUri(uri));
@@ -33,13 +53,26 @@
     otherLibrarySources.add(addNamedSource(filePath, contents));
   }
 
+  /**
+   * Verify that the given prefix is safe to elide from a resynthesized AST.
+   */
+  void checkElidablePrefix(SimpleIdentifier prefix) {
+    if (prefix.staticElement is! PrefixElement &&
+        prefix.staticElement is! ClassElement) {
+      fail('Prefix of type ${prefix.staticElement.runtimeType}'
+          ' should not have been elided');
+    }
+  }
+
   void checkLibrary(String text,
-      {bool allowErrors: false, int resynthesisCount: 1}) {
+      {bool allowErrors: false, bool dumpSummaries: false}) {
     Source source = addSource(text);
     LibraryElementImpl original = resolve2(source);
-    LibraryElementImpl resynthesized = resynthesizeLibrary(
-        source, original, allowErrors,
-        resynthesisCount: resynthesisCount);
+    LibraryElementImpl resynthesized = resynthesizeLibraryElement(
+        encodeLibrary(original,
+            allowErrors: allowErrors, dumpSummaries: dumpSummaries),
+        source.uri.toString(),
+        original);
     checkLibraryElements(original, resynthesized);
   }
 
@@ -67,6 +100,10 @@
           'export ${original.exports[i].uri}');
     }
     expect(resynthesized.nameLength, original.nameLength);
+    compareNamespaces(resynthesized.publicNamespace, original.publicNamespace,
+        '(public namespace)');
+    compareNamespaces(resynthesized.exportNamespace, original.exportNamespace,
+        '(export namespace)');
     if (original.entryPoint == null) {
       expect(resynthesized.entryPoint, isNull);
     } else {
@@ -74,11 +111,77 @@
       compareFunctionElements(
           resynthesized.entryPoint, original.entryPoint, '(entry point)');
     }
-    compareNamespaces(resynthesized.publicNamespace, original.publicNamespace,
-        '(public namespace)');
-    compareNamespaces(resynthesized.exportNamespace, original.exportNamespace,
-        '(export namespace)');
-    // TODO(paulberry): test metadata.
+    // The libraries `dart:core` and `dart:async` cannot create their
+    // `loadLibrary` functions until after both are created.
+    if (original.name != 'dart.core' && original.name != 'dart.async') {
+      compareExecutableElements(
+          resynthesized.loadLibraryFunction as ExecutableElementImpl,
+          original.loadLibraryFunction as ExecutableElementImpl,
+          '(loadLibraryFunction)');
+    }
+    expect(resynthesized.libraryCycle.toSet(), original.libraryCycle.toSet());
+  }
+
+  /**
+   * Verify that the [resynthesizer] didn't do any unnecessary work when
+   * resynthesizing [library].
+   */
+  void checkMinimalResynthesisWork(
+      _TestSummaryResynthesizer resynthesizer, LibraryElement library) {
+    // Check that no other summaries needed to be resynthesized to resynthesize
+    // the library element.
+    expect(resynthesizer.resynthesisCount, 1);
+    // Check that the only linked summary consulted was that for [uri].
+    expect(resynthesizer.linkedSummariesRequested, hasLength(1));
+    expect(resynthesizer.linkedSummariesRequested.first,
+        library.source.uri.toString());
+    // Check that the only unlinked summaries consulted were those for the
+    // library in question.
+    Set<String> expectedCompilationUnitUris = library.units
+        .map((CompilationUnitElement unit) => unit.source.uri.toString())
+        .toSet();
+    for (String requestedUri in resynthesizer.unlinkedSummariesRequested) {
+      expect(expectedCompilationUnitUris, contains(requestedUri));
+    }
+  }
+
+  void checkPossibleLocalElements(Element resynthesized, Element original) {
+    if (original is! LocalElement && resynthesized is! LocalElement) {
+      return;
+    }
+    if (original is LocalElement && resynthesized is LocalElement) {
+      expect(resynthesized.visibleRange, original.visibleRange);
+    } else {
+      fail('Incompatible local elements '
+          '${resynthesized.runtimeType} vs. ${original.runtimeType}');
+    }
+  }
+
+  void checkPossibleMember(
+      Element resynthesized, Element original, String desc) {
+    Element resynthesizedNonHandle = resynthesized is ElementHandle
+        ? resynthesized.actualElement
+        : resynthesized;
+    if (original is Member) {
+      expect(resynthesizedNonHandle, new isInstanceOf<Member>(), reason: desc);
+      if (resynthesizedNonHandle is Member) {
+        List<DartType> resynthesizedTypeArguments =
+            resynthesizedNonHandle.definingType.typeArguments;
+        List<DartType> originalTypeArguments =
+            original.definingType.typeArguments;
+        expect(
+            resynthesizedTypeArguments, hasLength(originalTypeArguments.length),
+            reason: desc);
+        for (int i = 0; i < originalTypeArguments.length; i++) {
+          compareTypeImpls(resynthesizedTypeArguments[i],
+              originalTypeArguments[i], '$desc type argument $i');
+        }
+      }
+    } else {
+      expect(
+          resynthesizedNonHandle, isNot(new isInstanceOf<ConstructorMember>()),
+          reason: desc);
+    }
   }
 
   void compareClassElements(
@@ -88,8 +191,8 @@
         reason: '$desc fields.length');
     for (int i = 0; i < resynthesized.fields.length; i++) {
       String name = original.fields[i].name;
-      compareFieldElements(resynthesized.getField(name), original.fields[i],
-          '$desc.field $name');
+      compareFieldElements(
+          resynthesized.fields[i], original.fields[i], '$desc.field $name');
     }
     compareTypes(
         resynthesized.supertype, original.supertype, '$desc supertype');
@@ -120,18 +223,10 @@
     }
     expect(resynthesized.accessors.length, original.accessors.length);
     for (int i = 0; i < resynthesized.accessors.length; i++) {
-      String name = original.accessors[i].name;
-      if (name.endsWith('=')) {
-        comparePropertyAccessorElements(
-            resynthesized.getSetter(name),
-            original.accessors[i],
-            '$desc setter ${original.accessors[i].name}');
-      } else {
-        comparePropertyAccessorElements(
-            resynthesized.getGetter(name),
-            original.accessors[i],
-            '$desc getter ${original.accessors[i].name}');
-      }
+      comparePropertyAccessorElements(
+          resynthesized.accessors[i],
+          original.accessors[i],
+          '$desc accessor ${original.accessors[i].name}');
     }
     expect(resynthesized.methods.length, original.methods.length);
     for (int i = 0; i < resynthesized.methods.length; i++) {
@@ -139,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,
@@ -155,10 +252,12 @@
     expect(resynthesized.topLevelVariables.length,
         original.topLevelVariables.length);
     for (int i = 0; i < resynthesized.topLevelVariables.length; i++) {
+      String name = resynthesized.topLevelVariables[i].name;
       compareTopLevelVariableElements(
           resynthesized.topLevelVariables[i],
-          original.topLevelVariables[i],
-          'variable ${original.topLevelVariables[i].name}');
+          original.topLevelVariables
+              .singleWhere((TopLevelVariableElement e) => e.name == name),
+          'variable $name');
     }
     expect(resynthesized.functions.length, original.functions.length);
     for (int i = 0; i < resynthesized.functions.length; i++) {
@@ -180,26 +279,341 @@
     }
     expect(resynthesized.accessors.length, original.accessors.length);
     for (int i = 0; i < resynthesized.accessors.length; i++) {
+      String name = resynthesized.accessors[i].name;
       if (original.accessors[i].isGetter) {
-        comparePropertyAccessorElements(resynthesized.accessors[i],
-            original.accessors[i], 'getter ${original.accessors[i].name}');
+        comparePropertyAccessorElements(
+            resynthesized.accessors[i],
+            original.accessors
+                .singleWhere((PropertyAccessorElement e) => e.name == name),
+            'getter $name');
       } else {
-        comparePropertyAccessorElements(resynthesized.accessors[i],
-            original.accessors[i], 'setter ${original.accessors[i].name}');
+        comparePropertyAccessorElements(
+            resynthesized.accessors[i],
+            original.accessors
+                .singleWhere((PropertyAccessorElement e) => e.name == name),
+            'setter $name');
       }
     }
-    // TODO(paulberry): test metadata and offsetToElementMap.
+    // Note: no need to test CompilationUnitElementImpl._offsetToElementMap
+    // since it is built on demand when needed (see
+    // CompilationUnitElementImpl.getElementAt])
   }
 
-  void compareConstructorElements(ConstructorElementImpl resynthesized,
-      ConstructorElementImpl original, String desc) {
+  void compareConstAstLists(
+      List<Object> rItems, List<Object> oItems, String desc) {
+    if (rItems == null && oItems == null) {
+      return;
+    }
+    expect(rItems != null && oItems != null, isTrue);
+    expect(rItems, hasLength(oItems.length));
+    for (int i = 0; i < oItems.length; i++) {
+      Object rItem = rItems[i];
+      Object oItem = oItems[i];
+      if (rItem is Expression && oItem is Expression) {
+        compareConstAsts(rItem, oItem, desc);
+      } else if (rItem is TypeName && oItem is TypeName) {
+        compareConstAsts(rItem.name, oItem.name, desc);
+      } else if (rItem is InterpolationString && oItem is InterpolationString) {
+        expect(rItem.value, oItem.value);
+      } else if (rItem is InterpolationExpression &&
+          oItem is InterpolationExpression) {
+        compareConstAsts(rItem.expression, oItem.expression, desc);
+      } else if (rItem is MapLiteralEntry && oItem is MapLiteralEntry) {
+        compareConstAsts(rItem.key, oItem.key, desc);
+        compareConstAsts(rItem.value, oItem.value, desc);
+      } else if (oItem is ConstructorFieldInitializer &&
+          rItem is ConstructorFieldInitializer) {
+        compareConstAsts(rItem.fieldName, oItem.fieldName, desc);
+        if (constantInitializersAreInvalid) {
+          _assertUnresolvedIdentifier(rItem.expression, desc);
+        } else {
+          compareConstAsts(rItem.expression, oItem.expression, desc);
+        }
+      } else if (oItem is SuperConstructorInvocation &&
+          rItem is SuperConstructorInvocation) {
+        compareElements(rItem.staticElement, oItem.staticElement, desc);
+        compareConstAsts(rItem.constructorName, oItem.constructorName, desc);
+        compareConstAstLists(
+            rItem.argumentList.arguments, oItem.argumentList.arguments, desc);
+      } else if (oItem is RedirectingConstructorInvocation &&
+          rItem is RedirectingConstructorInvocation) {
+        compareElements(rItem.staticElement, oItem.staticElement, desc);
+        compareConstAsts(rItem.constructorName, oItem.constructorName, desc);
+        compareConstAstLists(
+            rItem.argumentList.arguments, oItem.argumentList.arguments, desc);
+      } else {
+        fail('$desc Incompatible item types: '
+            '${rItem.runtimeType} vs. ${oItem.runtimeType}');
+      }
+    }
+  }
+
+  void compareConstAsts(AstNode r, AstNode o, String desc) {
+    if (o == null) {
+      expect(r, isNull, reason: desc);
+    } else {
+      expect(r, isNotNull, reason: desc);
+      // ConstantAstCloner does not copy static types, and constant values
+      // computer does not use static types. So, we don't set them during
+      // resynthesis and should not check them here.
+      if (o is ParenthesizedExpression) {
+        // We don't resynthesize parenthesis, so just ignore it.
+        compareConstAsts(r, o.expression, desc);
+      } else if (o is SimpleIdentifier && r is SimpleIdentifier) {
+        expect(r.name, o.name, reason: desc);
+        compareElements(r.staticElement, o.staticElement, desc);
+      } else if (o is PrefixedIdentifier && r is SimpleIdentifier) {
+        // We don't resynthesize prefixed identifiers when the prefix refers to
+        // a PrefixElement or a ClassElement.  We use simple identifiers with
+        // correct elements.
+        if (o.prefix.staticElement is PrefixElement ||
+            o.prefix.staticElement is ClassElement) {
+          compareConstAsts(r, o.identifier, desc);
+        } else {
+          fail('Prefix of type ${o.prefix.staticElement.runtimeType} should not'
+              ' have been elided');
+        }
+      } else if (o is PropertyAccess &&
+          o.target is PrefixedIdentifier &&
+          r is PrefixedIdentifier) {
+        // We don't resynthesize prefixed identifiers when the prefix refers to
+        // a PrefixElement or a ClassElement.  Which means that if the original
+        // expression was e.g. `prefix.topLevelVariableName.length`, it will get
+        // resynthesized as `topLevelVariableName.length`
+        PrefixedIdentifier oTarget = o.target;
+        checkElidablePrefix(oTarget.prefix);
+        compareConstAsts(
+            r, AstFactory.identifier(oTarget.identifier, o.propertyName), desc);
+      } else if (o is PrefixedIdentifier && r is PrefixedIdentifier) {
+        compareConstAsts(r.prefix, o.prefix, desc);
+        compareConstAsts(r.identifier, o.identifier, desc);
+      } else if (o is PropertyAccess && r is PropertyAccess) {
+        compareConstAsts(r.target, o.target, desc);
+        expect(r.propertyName.name, o.propertyName.name, reason: desc);
+        compareElements(
+            r.propertyName.staticElement, o.propertyName.staticElement, desc);
+      } else if (o is PropertyAccess &&
+          o.target is PrefixedIdentifier &&
+          r is SimpleIdentifier) {
+        // We don't resynthesize property access when it takes the form
+        // `prefixName.className.staticMember`.  We just resynthesize a
+        // SimpleIdentifier correctly resolved to the static member.
+        PrefixedIdentifier oTarget = o.target;
+        checkElidablePrefix(oTarget.prefix);
+        checkElidablePrefix(oTarget.identifier);
+        compareConstAsts(r, o.propertyName, desc);
+      } else if (o is NullLiteral) {
+        expect(r, new isInstanceOf<NullLiteral>(), reason: desc);
+      } else if (o is BooleanLiteral && r is BooleanLiteral) {
+        expect(r.value, o.value, reason: desc);
+      } else if (o is IntegerLiteral && r is IntegerLiteral) {
+        expect(r.value, o.value, reason: desc);
+      } else if (o is DoubleLiteral && r is DoubleLiteral) {
+        if (r.value != null &&
+            r.value.isNaN &&
+            o.value != null &&
+            o.value.isNaN) {
+          // NaN is not comparable.
+        } else {
+          expect(r.value, o.value, reason: desc);
+        }
+      } else if (o is StringInterpolation && r is StringInterpolation) {
+        compareConstAstLists(r.elements, o.elements, desc);
+      } else if (o is StringLiteral && r is StringLiteral) {
+        // We don't keep all the tokens of AdjacentStrings.
+        // So, we can compare only their values.
+        expect(r.stringValue, o.stringValue, reason: desc);
+      } else if (o is SymbolLiteral && r is SymbolLiteral) {
+        // We don't keep all the tokens of symbol literals.
+        // So, we can compare only their values.
+        expect(r.components.map((t) => t.lexeme).join('.'),
+            o.components.map((t) => t.lexeme).join('.'),
+            reason: desc);
+      } else if (o is NamedExpression && r is NamedExpression) {
+        expect(r.name.label.name, o.name.label.name, reason: desc);
+        compareConstAsts(r.expression, o.expression, desc);
+      } else if (o is BinaryExpression && r is BinaryExpression) {
+        expect(r.operator.lexeme, o.operator.lexeme, reason: desc);
+        compareConstAsts(r.leftOperand, o.leftOperand, desc);
+        compareConstAsts(r.rightOperand, o.rightOperand, desc);
+      } else if (o is PrefixExpression && r is PrefixExpression) {
+        expect(r.operator.lexeme, o.operator.lexeme, reason: desc);
+        compareConstAsts(r.operand, o.operand, desc);
+      } else if (o is ConditionalExpression && r is ConditionalExpression) {
+        compareConstAsts(r.condition, o.condition, desc);
+        compareConstAsts(r.thenExpression, o.thenExpression, desc);
+        compareConstAsts(r.elseExpression, o.elseExpression, desc);
+      } else if (o is ListLiteral && r is ListLiteral) {
+        compareConstAstLists(
+            r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
+        compareConstAstLists(r.elements, o.elements, desc);
+      } else if (o is MapLiteral && r is MapLiteral) {
+        compareConstAstLists(
+            r.typeArguments?.arguments, o.typeArguments?.arguments, desc);
+        compareConstAstLists(r.entries, o.entries, desc);
+      } else if (o is InstanceCreationExpression &&
+          r is InstanceCreationExpression) {
+        compareElements(r.staticElement, o.staticElement, desc);
+        ConstructorName oConstructor = o.constructorName;
+        ConstructorName rConstructor = r.constructorName;
+        expect(oConstructor, isNotNull, reason: desc);
+        expect(rConstructor, isNotNull, reason: desc);
+        compareConstructorElements(
+            rConstructor.staticElement, oConstructor.staticElement, desc);
+        TypeName oType = oConstructor.type;
+        TypeName rType = rConstructor.type;
+        expect(oType, isNotNull, reason: desc);
+        expect(rType, isNotNull, reason: desc);
+        compareConstAsts(rType.name, oType.name, desc);
+        compareConstAsts(rConstructor.name, oConstructor.name, desc);
+        compareConstAstLists(rType.typeArguments?.arguments,
+            oType.typeArguments?.arguments, desc);
+        compareConstAstLists(
+            r.argumentList.arguments, o.argumentList.arguments, desc);
+      } else if (o is AnnotationImpl && r is AnnotationImpl) {
+        expect(o.atSign.lexeme, r.atSign.lexeme, reason: desc);
+        Identifier rName = r.name;
+        Identifier oName = o.name;
+        if (oName is PrefixedIdentifier && o.constructorName != null) {
+          // E.g. `@prefix.cls.ctor`.  This gets resynthesized as `@cls.ctor`,
+          // with `cls.ctor` represented as a PrefixedIdentifier.
+          expect(rName, new isInstanceOf<PrefixedIdentifier>(), reason: desc);
+          if (rName is PrefixedIdentifier) {
+            compareConstAsts(rName.prefix, oName.identifier, desc);
+            expect(rName.period.lexeme, '.', reason: desc);
+            compareConstAsts(rName.identifier, o.constructorName, desc);
+            expect(r.period, isNull, reason: desc);
+            expect(r.constructorName, isNull, reason: desc);
+          }
+        } else {
+          compareConstAsts(r.name, o.name, desc);
+          expect(r.period?.lexeme, o.period?.lexeme, reason: desc);
+          compareConstAsts(r.constructorName, o.constructorName, desc);
+        }
+        compareConstAstLists(
+            r.arguments?.arguments, o.arguments?.arguments, desc);
+        Element expectedElement = o.element;
+        if (oName is PrefixedIdentifier && o.constructorName != null) {
+          // Due to dartbug.com/25706, [o.element] incorrectly points to the
+          // class rather than the named constructor.  Hack around this.
+          // TODO(paulberry): when dartbug.com/25706 is fixed, remove this.
+          expectedElement = (expectedElement as ClassElement)
+              .getNamedConstructor(o.constructorName.name);
+          expect(expectedElement, isNotNull, reason: desc);
+        }
+        compareElements(r.element, expectedElement, desc);
+        // elementAnnotation should be null; it is only used in the full AST.
+        expect(o.elementAnnotation, isNull);
+        expect(r.elementAnnotation, isNull);
+      } else {
+        fail('Not implemented for ${r.runtimeType} vs. ${o.runtimeType}');
+      }
+    }
+  }
+
+  void compareConstructorElements(ConstructorElement resynthesized,
+      ConstructorElement original, String desc) {
+    if (original == null && resynthesized == null) {
+      return;
+    }
     compareExecutableElements(resynthesized, original, desc);
-    // TODO(paulberry): test redirectedConstructor and constantInitializers
+    if (original.isConst) {
+      ConstructorElementImpl resynthesizedImpl =
+          getActualElement(resynthesized, desc);
+      ConstructorElementImpl originalImpl = getActualElement(original, desc);
+      compareConstAstLists(resynthesizedImpl.constantInitializers,
+          originalImpl.constantInitializers, desc);
+    }
+    if (original.redirectedConstructor == null) {
+      expect(resynthesized.redirectedConstructor, isNull, reason: desc);
+    } else {
+      compareConstructorElements(resynthesized.redirectedConstructor,
+          original.redirectedConstructor, '$desc redirectedConstructor');
+    }
+    checkPossibleMember(resynthesized, original, desc);
+    expect(resynthesized.nameEnd, original.nameEnd, reason: desc);
+    expect(resynthesized.periodOffset, original.periodOffset, reason: desc);
   }
 
-  void compareElements(
-      ElementImpl resynthesized, ElementImpl original, String desc) {
+  void compareConstValues(
+      DartObject resynthesized, DartObject original, String desc) {
+    if (original == null) {
+      expect(resynthesized, isNull, reason: desc);
+    } else {
+      expect(resynthesized, isNotNull, reason: desc);
+      compareTypes(resynthesized.type, original.type, desc);
+      expect(resynthesized.hasKnownValue, original.hasKnownValue, reason: desc);
+      if (original.isNull) {
+        expect(resynthesized.isNull, isTrue, reason: desc);
+      } else if (original.toBoolValue() != null) {
+        expect(resynthesized.toBoolValue(), original.toBoolValue(),
+            reason: desc);
+      } else if (original.toIntValue() != null) {
+        expect(resynthesized.toIntValue(), original.toIntValue(), reason: desc);
+      } else if (original.toDoubleValue() != null) {
+        expect(resynthesized.toDoubleValue(), original.toDoubleValue(),
+            reason: desc);
+      } else if (original.toListValue() != null) {
+        List<DartObject> resynthesizedList = resynthesized.toListValue();
+        List<DartObject> originalList = original.toListValue();
+        expect(resynthesizedList, hasLength(originalList.length));
+        for (int i = 0; i < originalList.length; i++) {
+          compareConstValues(resynthesizedList[i], originalList[i], desc);
+        }
+      } else if (original.toMapValue() != null) {
+        Map<DartObject, DartObject> resynthesizedMap =
+            resynthesized.toMapValue();
+        Map<DartObject, DartObject> originalMap = original.toMapValue();
+        expect(resynthesizedMap, hasLength(originalMap.length));
+        List<DartObject> resynthesizedKeys = resynthesizedMap.keys.toList();
+        List<DartObject> originalKeys = originalMap.keys.toList();
+        for (int i = 0; i < originalKeys.length; i++) {
+          DartObject resynthesizedKey = resynthesizedKeys[i];
+          DartObject originalKey = originalKeys[i];
+          compareConstValues(resynthesizedKey, originalKey, desc);
+          DartObject resynthesizedValue = resynthesizedMap[resynthesizedKey];
+          DartObject originalValue = originalMap[originalKey];
+          compareConstValues(resynthesizedValue, originalValue, desc);
+        }
+      } else if (original.toStringValue() != null) {
+        expect(resynthesized.toStringValue(), original.toStringValue(),
+            reason: desc);
+      } else if (original.toSymbolValue() != null) {
+        expect(resynthesized.toSymbolValue(), original.toSymbolValue(),
+            reason: desc);
+      } else if (original.toTypeValue() != null) {
+        fail('Not implemented');
+      }
+    }
+  }
+
+  void compareElementAnnotations(ElementAnnotationImpl resynthesized,
+      ElementAnnotationImpl original, String desc) {
+    expect(resynthesized.element, isNotNull, reason: desc);
+    expect(resynthesized.element.kind, original.element.kind, reason: desc);
+    expect(resynthesized.element.location, original.element.location,
+        reason: desc);
+    expect(resynthesized.compilationUnit, isNotNull, reason: desc);
+    expect(resynthesized.compilationUnit.location,
+        original.compilationUnit.location,
+        reason: desc);
+    expect(resynthesized.annotationAst, isNotNull, reason: desc);
+    compareConstAsts(resynthesized.annotationAst, original.annotationAst, desc);
+  }
+
+  void compareElements(Element resynthesized, Element original, String desc) {
+    ElementImpl rImpl = getActualElement(resynthesized, desc);
+    ElementImpl oImpl = getActualElement(original, desc);
+    if (oImpl == null && rImpl == null) {
+      return;
+    }
+    if (oImpl is PrefixElement) {
+      // TODO(scheglov) prefixes cannot be resynthesized
+      return;
+    }
+    expect(original, isNotNull);
     expect(resynthesized, isNotNull);
+    expect(rImpl.runtimeType, oImpl.runtimeType);
     expect(resynthesized.kind, original.kind);
     expect(resynthesized.location, original.location, reason: desc);
     expect(resynthesized.name, original.name);
@@ -207,31 +621,75 @@
     expect(resynthesized.documentationComment, original.documentationComment,
         reason: desc);
     expect(resynthesized.docRange, original.docRange, reason: desc);
-    for (Modifier modifier in Modifier.values) {
-      if (modifier == Modifier.MIXIN) {
-        // Skipping for now.  TODO(paulberry): fix.
-        continue;
-      }
-      bool got = resynthesized.hasModifier(modifier);
-      bool want = original.hasModifier(modifier);
+    compareMetadata(resynthesized.metadata, original.metadata, desc);
+    // Modifiers are a pain to test via handles.  So just test them via the
+    // actual element.
+    for (Modifier modifier in Modifier.persistedValues) {
+      bool got = rImpl.hasModifier(modifier);
+      bool want = oImpl.hasModifier(modifier);
       expect(got, want,
           reason: 'Mismatch in $desc.$modifier: got $got, want $want');
     }
+    for (Modifier modifier in Modifier.transientValues) {
+      bool got = rImpl.hasModifier(modifier);
+      bool want = false;
+      expect(got, false,
+          reason: 'Mismatch in $desc.$modifier: got $got, want $want');
+    }
+
+    // Validate members.
+    if (oImpl is Member) {
+      expect(rImpl, new isInstanceOf<Member>(), reason: desc);
+    } else {
+      expect(rImpl, isNot(new isInstanceOf<Member>()), reason: desc);
+    }
   }
 
-  void compareExecutableElements(ExecutableElementImpl resynthesized,
-      ExecutableElementImpl original, String desc) {
+  void compareExecutableElements(
+      ExecutableElement resynthesized, ExecutableElement original, String desc,
+      {bool shallow: false}) {
     compareElements(resynthesized, original, desc);
-    expect(resynthesized.parameters.length, original.parameters.length);
-    for (int i = 0; i < resynthesized.parameters.length; i++) {
-      compareParameterElements(
-          resynthesized.parameters[i],
-          original.parameters[i],
-          '$desc parameter ${original.parameters[i].name}');
-    }
+    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(
+          resynthesized.typeParameters[i],
+          original.typeParameters[i],
+          '$desc type parameter ${original.typeParameters[i].name}');
+    }
+    if (original is! Member) {
+      List<FunctionElement> rFunctions = resynthesized.functions;
+      List<FunctionElement> oFunctions = original.functions;
+      expect(rFunctions, hasLength(oFunctions.length));
+      for (int i = 0; i < oFunctions.length; i++) {
+        compareFunctionElements(rFunctions[i], oFunctions[i],
+            '$desc local function ${oFunctions[i].name}');
+      }
+    }
+    if (original is! Member) {
+      List<LabelElement> rLabels = resynthesized.labels;
+      List<LabelElement> oLabels = original.labels;
+      expect(rLabels, hasLength(oLabels.length));
+      for (int i = 0; i < oLabels.length; i++) {
+        compareLabelElements(
+            rLabels[i], oLabels[i], '$desc label ${oLabels[i].name}');
+      }
+    }
+    if (original is! Member) {
+      List<LocalVariableElement> rVariables = resynthesized.localVariables;
+      List<LocalVariableElement> oVariables = original.localVariables;
+      expect(rVariables, hasLength(oVariables.length));
+      for (int i = 0; i < oVariables.length; i++) {
+        compareVariableElements(rVariables[i], oVariables[i],
+            '$desc local variable ${oVariables[i].name}');
+      }
+    }
   }
 
   void compareExportElements(ExportElementImpl resynthesized,
@@ -249,12 +707,17 @@
   void compareFieldElements(
       FieldElementImpl resynthesized, FieldElementImpl original, String desc) {
     comparePropertyInducingElements(resynthesized, original, desc);
-    // TODO(paulberry): test evaluationResult
   }
 
-  void compareFunctionElements(FunctionElementImpl resynthesized,
-      FunctionElementImpl original, String desc) {
-    compareExecutableElements(resynthesized, original, desc);
+  void compareFunctionElements(
+      FunctionElement resynthesized, FunctionElement original, String desc,
+      {bool shallow: false}) {
+    if (original == null && resynthesized == null) {
+      return;
+    }
+    expect(resynthesized, isNotNull, reason: desc);
+    compareExecutableElements(resynthesized, original, desc, shallow: shallow);
+    checkPossibleLocalElements(resynthesized, original);
   }
 
   void compareFunctionTypeAliasElements(
@@ -262,13 +725,8 @@
       FunctionTypeAliasElementImpl original,
       String desc) {
     compareElements(resynthesized, original, desc);
-    expect(resynthesized.parameters.length, original.parameters.length);
-    for (int i = 0; i < resynthesized.parameters.length; i++) {
-      compareParameterElements(
-          resynthesized.parameters[i],
-          original.parameters[i],
-          '$desc parameter ${original.parameters[i].name}');
-    }
+    compareParameterElementLists(
+        resynthesized.parameters, original.parameters, desc);
     compareTypes(
         resynthesized.returnType, original.returnType, '$desc return type');
     compareTypes(resynthesized.type, original.type, desc);
@@ -286,6 +744,7 @@
     compareUriReferencedElements(resynthesized, original, desc);
     expect(resynthesized.importedLibrary.location,
         original.importedLibrary.location);
+    expect(resynthesized.prefixOffset, original.prefixOffset);
     if (original.prefix == null) {
       expect(resynthesized.prefix, isNull);
     } else {
@@ -299,11 +758,28 @@
     }
   }
 
+  void compareLabelElements(
+      LabelElementImpl resynthesized, LabelElementImpl original, String desc) {
+    expect(resynthesized.isOnSwitchMember, original.isOnSwitchMember,
+        reason: desc);
+    expect(resynthesized.isOnSwitchStatement, original.isOnSwitchStatement,
+        reason: desc);
+    compareElements(resynthesized, original, desc);
+  }
+
+  void compareMetadata(List<ElementAnnotation> resynthesized,
+      List<ElementAnnotation> original, String desc) {
+    expect(resynthesized, hasLength(original.length), reason: desc);
+    for (int i = 0; i < original.length; i++) {
+      compareElementAnnotations(
+          resynthesized[i], original[i], '$desc annotation $i');
+    }
+  }
+
   void compareMethodElements(MethodElementImpl resynthesized,
       MethodElementImpl original, String desc) {
     // TODO(paulberry): do we need to deal with
     // MultiplyInheritedMethodElementImpl?
-    // TODO(paulberry): compare type parameters for generic methods.
     compareExecutableElements(resynthesized, original, desc);
   }
 
@@ -312,6 +788,8 @@
     if (original is ShowElementCombinatorImpl &&
         resynthesized is ShowElementCombinatorImpl) {
       expect(resynthesized.shownNames, original.shownNames);
+      expect(resynthesized.offset, original.offset);
+      expect(resynthesized.end, original.end);
     } else if (original is HideElementCombinatorImpl &&
         resynthesized is HideElementCombinatorImpl) {
       expect(resynthesized.hiddenNames, original.hiddenNames);
@@ -336,23 +814,51 @@
     }
   }
 
-  void compareParameterElements(ParameterElementImpl resynthesized,
-      ParameterElementImpl original, String desc) {
-    compareVariableElements(resynthesized, original, desc);
-    expect(resynthesized.parameters.length, original.parameters.length);
-    for (int i = 0; i < resynthesized.parameters.length; i++) {
+  void compareParameterElementLists(
+      List<ParameterElement> resynthesizedParameters,
+      List<ParameterElement> originalParameters,
+      String desc) {
+    expect(resynthesizedParameters.length, originalParameters.length);
+    for (int i = 0; i < resynthesizedParameters.length; i++) {
       compareParameterElements(
-          resynthesized.parameters[i],
-          original.parameters[i],
-          '$desc parameter ${original.parameters[i].name}');
+          resynthesizedParameters[i],
+          originalParameters[i],
+          '$desc parameter ${originalParameters[i].name}');
     }
+  }
+
+  void compareParameterElements(
+      ParameterElement resynthesized, ParameterElement original, String desc) {
+    compareVariableElements(resynthesized, original, desc);
+    compareParameterElementLists(
+        resynthesized.parameters, original.parameters, desc);
     expect(resynthesized.parameterKind, original.parameterKind);
+    expect(resynthesized.isInitializingFormal, original.isInitializingFormal,
+        reason: desc);
+    expect(resynthesized is FieldFormalParameterElementImpl,
+        original is FieldFormalParameterElementImpl);
+    if (resynthesized is FieldFormalParameterElementImpl &&
+        original is FieldFormalParameterElementImpl) {
+      if (original.field == null) {
+        expect(resynthesized.field, isNull, reason: '$desc field');
+      } else {
+        expect(resynthesized.field, isNotNull, reason: '$desc field');
+        compareFieldElements(
+            resynthesized.field, original.field, '$desc field');
+      }
+    }
+    expect(resynthesized.defaultValueCode, original.defaultValueCode,
+        reason: desc);
+    ParameterElementImpl resynthesizedActual =
+        getActualElement(resynthesized, desc);
+    ParameterElementImpl originalActual = getActualElement(original, desc);
+    compareFunctionElements(
+        resynthesizedActual.initializer, originalActual.initializer, desc);
   }
 
   void comparePrefixElements(PrefixElementImpl resynthesized,
       PrefixElementImpl original, String desc) {
     compareElements(resynthesized, original, desc);
-    // TODO(paulberry): test _importedLibraries.
   }
 
   void comparePropertyAccessorElements(
@@ -371,6 +877,7 @@
       PropertyInducingElementImpl original,
       String desc) {
     compareVariableElements(resynthesized, original, desc);
+    compareTypes(resynthesized.propagatedType, original.propagatedType, desc);
     if (original.getter == null) {
       expect(resynthesized.getter, isNull);
     } else {
@@ -390,7 +897,6 @@
       TopLevelVariableElementImpl original,
       String desc) {
     comparePropertyInducingElements(resynthesized, original, desc);
-    // TODO(paulberry): test evaluationResult
   }
 
   void compareTypeImpls(
@@ -438,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++) {
@@ -464,9 +979,16 @@
       }
     } else if (resynthesized is VoidTypeImpl && original is VoidTypeImpl) {
       expect(resynthesized, same(original));
+    } else if (resynthesized is DynamicTypeImpl &&
+        original is UndefinedTypeImpl) {
+      // TODO(scheglov) In the strong mode constant variable like
+      //  `var V = new Unresolved()` gets `UndefinedTypeImpl`, and it gets
+      // `DynamicTypeImpl` in the spec mode.
+    } else if (resynthesized is BottomTypeImpl && original is BottomTypeImpl) {
+      expect(resynthesized, same(original));
     } else if (resynthesized.runtimeType != original.runtimeType) {
-      fail(
-          'Type mismatch: expected ${original.runtimeType}, got ${resynthesized.runtimeType}');
+      fail('Type mismatch: expected ${original.runtimeType},'
+          ' got ${resynthesized.runtimeType} ($desc)');
     } else {
       fail('Unimplemented comparison for ${original.runtimeType}');
     }
@@ -480,82 +1002,152 @@
     expect(resynthesized.uriEnd, original.uriEnd, reason: desc);
   }
 
-  void compareVariableElements(VariableElementImpl resynthesized,
-      VariableElementImpl original, String desc) {
+  void compareVariableElements(
+      VariableElement resynthesized, VariableElement original, String desc) {
     compareElements(resynthesized, original, desc);
     compareTypes(resynthesized.type, original.type, desc);
-    // TODO(paulberry): test initializer
+    VariableElementImpl resynthesizedActual =
+        getActualElement(resynthesized, desc);
+    VariableElementImpl originalActual = getActualElement(original, desc);
+    compareFunctionElements(resynthesizedActual.initializer,
+        originalActual.initializer, '$desc initializer');
+    if (originalActual is ConstVariableElement) {
+      Element oEnclosing = original.enclosingElement;
+      if (oEnclosing is ClassElement && oEnclosing.isEnum) {
+        compareConstValues(
+            resynthesized.constantValue, original.constantValue, desc);
+      } else {
+        Expression initializer = resynthesizedActual.constantInitializer;
+        if (constantInitializersAreInvalid) {
+          _assertUnresolvedIdentifier(initializer, desc);
+        } else {
+          compareConstAsts(initializer, originalActual.constantInitializer,
+              '$desc initializer');
+        }
+      }
+    }
+    checkPossibleMember(resynthesized, original, desc);
+    checkPossibleLocalElements(resynthesized, original);
+  }
+
+  /**
+   * Serialize the given [library] into a summary.  Then create a
+   * [_TestSummaryResynthesizer] which can deserialize it, along with any
+   * references it makes to `dart:core`.
+   *
+   * Errors will lead to a test failure unless [allowErrors] is `true`.
+   */
+  _TestSummaryResynthesizer encodeLibrary(LibraryElementImpl library,
+      {bool allowErrors: false, bool dumpSummaries: false}) {
+    if (!allowErrors) {
+      assertNoErrors(library.source);
+    }
+    addLibrary('dart:core');
+    return encodeLibraryElement(library, dumpSummaries: dumpSummaries);
+  }
+
+  /**
+   * Convert the library element [library] into a summary, and then create a
+   * [_TestSummaryResynthesizer] which can deserialize it.
+   *
+   * Caller is responsible for checking the library for errors, and adding any
+   * dependent libraries using [addLibrary].
+   */
+  _TestSummaryResynthesizer encodeLibraryElement(LibraryElementImpl library,
+      {bool dumpSummaries: false}) {
+    Map<String, UnlinkedUnit> unlinkedSummaries = <String, UnlinkedUnit>{};
+    LinkedLibrary getLinkedSummaryFor(LibraryElement lib) {
+      LibrarySerializationResult serialized = serializeLibrary(
+          lib, typeProvider, analysisContext.analysisOptions.strongMode);
+      for (int i = 0; i < serialized.unlinkedUnits.length; i++) {
+        unlinkedSummaries[serialized.unitUris[i]] =
+            new UnlinkedUnit.fromBuffer(serialized.unlinkedUnits[i].toBuffer());
+      }
+      return new LinkedLibrary.fromBuffer(serialized.linked.toBuffer());
+    }
+    Map<String, LinkedLibrary> linkedSummaries = <String, LinkedLibrary>{
+      library.source.uri.toString(): getLinkedSummaryFor(library)
+    };
+    for (Source source in otherLibrarySources) {
+      LibraryElement original = resolve2(source);
+      String uri = source.uri.toString();
+      linkedSummaries[uri] = getLinkedSummaryFor(original);
+    }
+    if (dumpSummaries) {
+      unlinkedSummaries.forEach((String path, UnlinkedUnit unit) {
+        print('Unlinked $path: ${JSON.encode(canonicalize(unit))}');
+      });
+      linkedSummaries.forEach((String path, LinkedLibrary lib) {
+        print('Linked $path: ${JSON.encode(canonicalize(lib))}');
+      });
+    }
+    return new _TestSummaryResynthesizer(
+        null,
+        analysisContext,
+        analysisContext.typeProvider,
+        analysisContext.sourceFactory,
+        unlinkedSummaries,
+        linkedSummaries,
+        createOptions().strongMode);
   }
 
   fail_library_hasExtUri() {
     checkLibrary('import "dart-ext:doesNotExist.dart";');
   }
 
-  LibraryElementImpl resynthesizeLibrary(
-      Source source, LibraryElementImpl original, bool allowErrors,
-      {int resynthesisCount: 1}) {
-    if (!allowErrors) {
-      assertNoErrors(source);
+  ElementImpl getActualElement(Element element, String desc) {
+    if (element == null) {
+      return null;
+    } else if (element is ElementImpl) {
+      return element;
+    } else if (element is ElementHandle) {
+      Element actualElement = element.actualElement;
+      // A handle should never point to a member, because if it did, then
+      // "is Member" checks on the handle would produce the wrong result.
+      expect(actualElement, isNot(new isInstanceOf<Member>()), reason: desc);
+      return getActualElement(actualElement, desc);
+    } else if (element is Member) {
+      return getActualElement(element.baseElement, desc);
+    } else {
+      fail('Unexpected type for resynthesized ($desc):'
+          ' ${element.runtimeType}');
+      return null;
     }
-    String uri = source.uri.toString();
-    addLibrary('dart:core');
-    return resynthesizeLibraryElement(uri, original,
-        resynthesisCount: resynthesisCount);
   }
 
+  /**
+   * Resynthesize the library element associated with [uri] using
+   * [resynthesizer], and verify that it only had to consult one summary in
+   * order to do so.  [original] is consulted merely to verify that no
+   * unnecessary resynthesis work was performed.
+   */
   LibraryElementImpl resynthesizeLibraryElement(
-      String uri, LibraryElementImpl original,
-      {int resynthesisCount: 1}) {
-    Map<String, UnlinkedUnit> unlinkedSummaries = <String, UnlinkedUnit>{};
-    PrelinkedLibrary getPrelinkedSummaryFor(LibraryElement lib) {
-      LibrarySerializationResult serialized =
-          serializeLibrary(lib, typeProvider);
-      for (int i = 0; i < serialized.unlinkedUnits.length; i++) {
-        unlinkedSummaries[serialized.unitUris[i]] =
-            new UnlinkedUnit.fromBuffer(serialized.unlinkedUnits[i].toBuffer());
-      }
-      return new PrelinkedLibrary.fromBuffer(serialized.prelinked.toBuffer());
-    }
-    Map<String, PrelinkedLibrary> prelinkedSummaries =
-        <String, PrelinkedLibrary>{uri: getPrelinkedSummaryFor(original)};
-    for (Source source in otherLibrarySources) {
-      LibraryElement original = resolve2(source);
-      String uri = source.uri.toString();
-      prelinkedSummaries[uri] = getPrelinkedSummaryFor(original);
-    }
-    PrelinkedLibrary getPrelinkedSummary(String uri) {
-      PrelinkedLibrary serializedLibrary = prelinkedSummaries[uri];
-      if (serializedLibrary == null) {
-        fail('Unexpectedly tried to get prelinked summary for $uri');
-      }
-      return serializedLibrary;
-    }
-    UnlinkedUnit getUnlinkedSummary(String uri) {
-      UnlinkedUnit serializedUnit = unlinkedSummaries[uri];
-      if (serializedUnit == null) {
-        fail('Unexpectedly tried to get unlinked summary for $uri');
-      }
-      return serializedUnit;
-    }
-    SummaryResynthesizer resynthesizer = new SummaryResynthesizer(
-        analysisContext,
-        analysisContext.typeProvider,
-        getPrelinkedSummary,
-        getUnlinkedSummary,
-        analysisContext.sourceFactory);
+      _TestSummaryResynthesizer resynthesizer,
+      String uri,
+      LibraryElement original) {
     LibraryElementImpl resynthesized = resynthesizer.getLibraryElement(uri);
-    // Check that no other summaries needed to be resynthesized to resynthesize
-    // the library element.
-    // TODO(paulberry): once export namespaces are resynthesized from
-    // prelinked data, resynthesisCount should be hardcoded to 1.
-    expect(resynthesizer.resynthesisCount, resynthesisCount);
+    checkMinimalResynthesisWork(resynthesizer, original);
     return resynthesized;
   }
 
+  @override
+  void setUp() {
+    super.setUp();
+    resetWithOptions(createOptions());
+  }
+
+  test_class_abstract() {
+    checkLibrary('abstract class C {}');
+  }
+
   test_class_alias() {
     checkLibrary('class C = D with E, F; class D {} class E {} class F {}');
   }
 
+  test_class_alias_abstract() {
+    checkLibrary('abstract class C = D with E; class D {} class E {}');
+  }
+
   test_class_alias_documented() {
     checkLibrary('''
 // Extra comment so doc comment offset != 0
@@ -662,8 +1254,18 @@
     checkLibrary('class C { dynamic x; C(this.x); }');
   }
 
+  test_class_constructor_field_formal_multiple_matching_fields() {
+    // This is a compile-time error but it should still analyze consistently.
+    checkLibrary('class C { C(this.x); int x; String x; }', allowErrors: true);
+  }
+
+  test_class_constructor_field_formal_no_matching_field() {
+    // This is a compile-time error but it should still analyze consistently.
+    checkLibrary('class C { C(this.x); }', allowErrors: true);
+  }
+
   test_class_constructor_field_formal_typed_dynamic() {
-    checkLibrary('class C { num x; C(dynamic this.x); }');
+    checkLibrary('class C { num x; C(dynamic this.x); }', allowErrors: true);
   }
 
   test_class_constructor_field_formal_typed_typed() {
@@ -686,6 +1288,22 @@
     checkLibrary('class C { var x; C(this.x); }');
   }
 
+  test_class_constructor_fieldFormal_named_noDefault() {
+    checkLibrary('class C { int x; C({this.x}); }');
+  }
+
+  test_class_constructor_fieldFormal_named_withDefault() {
+    checkLibrary('class C { int x; C({this.x: 42}); }');
+  }
+
+  test_class_constructor_fieldFormal_optional_noDefault() {
+    checkLibrary('class C { int x; C([this.x]); }');
+  }
+
+  test_class_constructor_fieldFormal_optional_withDefault() {
+    checkLibrary('class C { int x; C([this.x = 42]); }');
+  }
+
   test_class_constructor_implicit() {
     checkLibrary('class C {}');
   }
@@ -742,6 +1360,10 @@
     checkLibrary('class C { int i; int j; }');
   }
 
+  test_class_getter_abstract() {
+    checkLibrary('abstract class C { int get x; }');
+  }
+
   test_class_getter_external() {
     checkLibrary('class C { external int get x; }');
   }
@@ -770,6 +1392,10 @@
     checkLibrary('class C implements D, E {} class D {} class E {}');
   }
 
+  test_class_method_abstract() {
+    checkLibrary('abstract class C { f(); }');
+  }
+
   test_class_method_external() {
     checkLibrary('class C { external f(); }');
   }
@@ -790,6 +1416,10 @@
     checkLibrary('class C extends Object with D, E {} class D {} class E {}');
   }
 
+  test_class_setter_abstract() {
+    checkLibrary('abstract class C { void set x(int value); }');
+  }
+
   test_class_setter_external() {
     checkLibrary('class C { external void set x(int value); }');
   }
@@ -834,6 +1464,746 @@
     checkLibrary('class C {} class D {}');
   }
 
+  test_closure_executable_with_return_type_from_closure() {
+    checkLibrary('''
+f() {
+  print(() {});
+  print(() => () => 0);
+}
+''');
+  }
+
+  test_const_invalid_field_const() {
+    constantInitializersAreInvalid = true;
+    checkLibrary(
+        r'''
+class C {
+  static const f = 1 + foo();
+}
+int foo() => 42;
+''',
+        allowErrors: true);
+  }
+
+  test_const_invalid_field_final() {
+    constantInitializersAreInvalid = true;
+    checkLibrary(
+        r'''
+class C {
+  final f = 1 + foo();
+}
+int foo() => 42;
+''',
+        allowErrors: true);
+  }
+
+  test_const_invalid_topLevel() {
+    constantInitializersAreInvalid = true;
+    checkLibrary(
+        r'''
+const v = 1 + foo();
+int foo() => 42;
+''',
+        allowErrors: true);
+  }
+
+  test_const_invokeConstructor_generic_named() {
+    checkLibrary(r'''
+class C<K, V> {
+  const C.named(K k, V v);
+}
+const V = const C<int, String>.named(1, '222');
+''');
+  }
+
+  test_const_invokeConstructor_generic_named_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C<K, V> {
+  const C.named(K k, V v);
+}
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const V = const C<int, String>.named(1, '222');
+''');
+  }
+
+  test_const_invokeConstructor_generic_named_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C<K, V> {
+  const C.named(K k, V v);
+}
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const V = const p.C<int, String>.named(1, '222');
+''');
+  }
+
+  test_const_invokeConstructor_generic_noTypeArguments() {
+    checkLibrary(r'''
+class C<K, V> {
+  const C();
+}
+const V = const C();
+''');
+  }
+
+  test_const_invokeConstructor_generic_unnamed() {
+    checkLibrary(r'''
+class C<K, V> {
+  const C();
+}
+const V = const C<int, String>();
+''');
+  }
+
+  test_const_invokeConstructor_generic_unnamed_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C<K, V> {
+  const C();
+}
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const V = const C<int, String>();
+''');
+  }
+
+  test_const_invokeConstructor_generic_unnamed_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C<K, V> {
+  const C();
+}
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const V = const p.C<int, String>();
+''');
+  }
+
+  test_const_invokeConstructor_named() {
+    checkLibrary(r'''
+class C {
+  const C.named(bool a, int b, int c, {String d, double e});
+}
+const V = const C.named(true, 1, 2, d: 'ccc', e: 3.4);
+''');
+  }
+
+  test_const_invokeConstructor_named_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  const C.named();
+}
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const V = const C.named();
+''');
+  }
+
+  test_const_invokeConstructor_named_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  const C.named();
+}
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const V = const p.C.named();
+''');
+  }
+
+  test_const_invokeConstructor_named_unresolved() {
+    checkLibrary(
+        r'''
+class C {}
+const V = const C.named();
+''',
+        allowErrors: true);
+  }
+
+  test_const_invokeConstructor_named_unresolved2() {
+    checkLibrary(
+        r'''
+const V = const C.named();
+''',
+        allowErrors: true);
+  }
+
+  test_const_invokeConstructor_named_unresolved3() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+}
+''');
+    checkLibrary(
+        r'''
+import 'a.dart' as p;
+const V = const p.C.named();
+''',
+        allowErrors: true);
+  }
+
+  test_const_invokeConstructor_named_unresolved4() {
+    addLibrarySource('/a.dart', '');
+    checkLibrary(
+        r'''
+import 'a.dart' as p;
+const V = const p.C.named();
+''',
+        allowErrors: true);
+  }
+
+  test_const_invokeConstructor_named_unresolved5() {
+    checkLibrary(
+        r'''
+const V = const p.C.named();
+''',
+        allowErrors: true);
+  }
+
+  test_const_invokeConstructor_unnamed() {
+    checkLibrary(r'''
+class C {
+  const C();
+}
+const V = const C();
+''');
+  }
+
+  test_const_invokeConstructor_unnamed_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  const C();
+}
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const V = const C();
+''');
+  }
+
+  test_const_invokeConstructor_unnamed_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  const C();
+}
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const V = const p.C();
+''');
+  }
+
+  test_const_invokeConstructor_unnamed_unresolved() {
+    checkLibrary(
+        r'''
+const V = const C();
+''',
+        allowErrors: true);
+  }
+
+  test_const_invokeConstructor_unnamed_unresolved2() {
+    addLibrarySource('/a.dart', '');
+    checkLibrary(
+        r'''
+import 'a.dart' as p;
+const V = const p.C();
+''',
+        allowErrors: true);
+  }
+
+  test_const_invokeConstructor_unnamed_unresolved3() {
+    checkLibrary(
+        r'''
+const V = const p.C();
+''',
+        allowErrors: true);
+  }
+
+  test_const_length_ofClassConstField() {
+    checkLibrary(r'''
+class C {
+  static const String F = '';
+}
+const int v = C.F.length;
+''');
+  }
+
+  test_const_length_ofClassConstField_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  static const String F = '';
+}
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const int v = C.F.length;
+''');
+  }
+
+  test_const_length_ofClassConstField_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  static const String F = '';
+}
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const int v = p.C.F.length;
+''');
+  }
+
+  test_const_length_ofStringLiteral() {
+    checkLibrary(r'''
+const v = 'abc'.length;
+''');
+  }
+
+  test_const_length_ofTopLevelVariable() {
+    checkLibrary(r'''
+const String S = 'abc';
+const v = S.length;
+''');
+  }
+
+  test_const_length_ofTopLevelVariable_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+const String S = 'abc';
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const v = S.length;
+''');
+  }
+
+  test_const_length_ofTopLevelVariable_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+const String S = 'abc';
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const v = p.S.length;
+''');
+  }
+
+  test_const_length_staticMethod() {
+    checkLibrary(r'''
+class C {
+  static int length() => 42;
+}
+const v = C.length;
+''');
+  }
+
+  test_const_parameterDefaultValue_initializingFormal_functionTyped() {
+    checkLibrary(r'''
+class C {
+  final x;
+  const C({this.x: foo});
+}
+int foo() => 42;
+''');
+  }
+
+  test_const_parameterDefaultValue_initializingFormal_named() {
+    checkLibrary(r'''
+class C {
+  final x;
+  const C({this.x: 1 + 2});
+}
+''');
+  }
+
+  test_const_parameterDefaultValue_initializingFormal_positional() {
+    checkLibrary(r'''
+class C {
+  final x;
+  const C([this.x = 1 + 2]);
+}
+''');
+  }
+
+  test_const_parameterDefaultValue_normal() {
+    checkLibrary(r'''
+class C {
+  const C.positional([p = 1 + 2]);
+  const C.named({p: 1 + 2});
+  void methodPositional([p = 1 + 2]) {}
+  void methodPositionalWithoutDefault([p]) {}
+  void methodNamed({p: 1 + 2}) {}
+  void methodNamedWithoutDefault({p}) {}
+}
+''');
+  }
+
+  test_const_reference_staticField() {
+    checkLibrary(r'''
+class C {
+  static const int F = 42;
+}
+const V = C.F;
+''');
+  }
+
+  test_const_reference_staticField_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  static const int F = 42;
+}
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const V = C.F;
+''');
+  }
+
+  test_const_reference_staticField_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  static const int F = 42;
+}
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const V = p.C.F;
+''');
+  }
+
+  test_const_reference_staticMethod() {
+    checkLibrary(r'''
+class C {
+  static int m(int a, String b) => 42;
+}
+const V = C.m;
+''');
+  }
+
+  test_const_reference_staticMethod_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  static int m(int a, String b) => 42;
+}
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const V = C.m;
+''');
+  }
+
+  test_const_reference_staticMethod_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {
+  static int m(int a, String b) => 42;
+}
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const V = p.C.m;
+''');
+  }
+
+  test_const_reference_topLevelFunction() {
+    checkLibrary(r'''
+foo() {}
+const V = foo;
+''');
+  }
+
+  test_const_reference_topLevelFunction_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+foo() {}
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const V = foo;
+''');
+  }
+
+  test_const_reference_topLevelFunction_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+foo() {}
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const V = p.foo;
+''');
+  }
+
+  test_const_reference_topLevelVariable() {
+    checkLibrary(r'''
+const A = 1;
+const B = A + 2;
+''');
+  }
+
+  test_const_reference_topLevelVariable_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+const A = 1;
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const B = A + 2;
+''');
+  }
+
+  test_const_reference_topLevelVariable_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+const A = 1;
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const B = p.A + 2;
+''');
+  }
+
+  test_const_reference_type() {
+    checkLibrary(r'''
+class C {}
+class D<T> {}
+enum E {a, b, c}
+typedef F(int a, String b);
+const vDynamic = dynamic;
+const vNull = Null;
+const vObject = Object;
+const vClass = C;
+const vGenericClass = D;
+const vEnum = E;
+const vFunctionTypeAlias = F;
+''');
+  }
+
+  test_const_reference_type_imported() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {}
+enum E {a, b, c}
+typedef F(int a, String b);
+''');
+    checkLibrary(r'''
+import 'a.dart';
+const vClass = C;
+const vEnum = E;
+const vFunctionTypeAlias = F;
+''');
+  }
+
+  test_const_reference_type_imported_withPrefix() {
+    addLibrarySource(
+        '/a.dart',
+        r'''
+class C {}
+enum E {a, b, c}
+typedef F(int a, String b);
+''');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const vClass = p.C;
+const vEnum = p.E;
+const vFunctionTypeAlias = p.F;
+''');
+  }
+
+  test_const_reference_unresolved_prefix0() {
+    checkLibrary(
+        r'''
+const V = foo;
+''',
+        allowErrors: true);
+  }
+
+  test_const_reference_unresolved_prefix1() {
+    checkLibrary(
+        r'''
+class C {}
+const v = C.foo;
+''',
+        allowErrors: true);
+  }
+
+  test_const_reference_unresolved_prefix2() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+class C {}
+''');
+    checkLibrary(
+        r'''
+import 'foo.dart' as p;
+const v = p.C.foo;
+''',
+        allowErrors: true);
+  }
+
+  test_const_topLevel_binary() {
+    checkLibrary(r'''
+const vEqual = 1 == 2;
+const vAnd = true && false;
+const vOr = false || true;
+const vBitXor = 1 ^ 2;
+const vBitAnd = 1 & 2;
+const vBitOr = 1 | 2;
+const vBitShiftLeft = 1 << 2;
+const vBitShiftRight = 1 >> 2;
+const vAdd = 1 + 2;
+const vSubtract = 1 - 2;
+const vMiltiply = 1 * 2;
+const vDivide = 1 / 2;
+const vFloorDivide = 1 ~/ 2;
+const vModulo = 1 % 2;
+const vGreater = 1 > 2;
+const vGreaterEqual = 1 >= 2;
+const vLess = 1 < 2;
+const vLessEqual = 1 <= 2;
+''');
+  }
+
+  test_const_topLevel_conditional() {
+    checkLibrary(r'''
+const vConditional = (1 == 2) ? 11 : 22;
+''');
+  }
+
+  test_const_topLevel_identical() {
+    checkLibrary(r'''
+const vIdentical = (1 == 2) ? 11 : 22;
+''');
+  }
+
+  test_const_topLevel_literal() {
+    checkLibrary(r'''
+const vNull = null;
+const vBoolFalse = false;
+const vBoolTrue = true;
+const vInt = 1;
+const vIntLong = 0x9876543210987654321;
+const vDouble = 2.3;
+const vString = 'abc';
+const vStringConcat = 'aaa' 'bbb';
+const vStringInterpolation = 'aaa ${true} ${42} bbb';
+const vSymbol = #aaa.bbb.ccc;
+''');
+  }
+
+  test_const_topLevel_prefix() {
+    checkLibrary(r'''
+const vNotEqual = 1 != 2;
+const vNot = !true;
+const vNegate = -1;
+const vComplement = ~1;
+''');
+  }
+
+  test_const_topLevel_typedList() {
+    checkLibrary(r'''
+const vNull = const <Null>[];
+const vDynamic = const <dynamic>[1, 2, 3];
+const vInterfaceNoTypeParameters = const <int>[1, 2, 3];
+const vInterfaceNoTypeArguments = const <List>[];
+const vInterfaceWithTypeArguments = const <List<String>>[];
+const vInterfaceWithTypeArguments2 = const <Map<int, List<String>>>[];
+''');
+  }
+
+  test_const_topLevel_typedList_imported() {
+    addLibrarySource('/a.dart', 'class C {}');
+    checkLibrary(r'''
+import 'a.dart';
+const v = const <C>[];
+''');
+  }
+
+  test_const_topLevel_typedList_importedWithPrefix() {
+    addLibrarySource('/a.dart', 'class C {}');
+    checkLibrary(r'''
+import 'a.dart' as p;
+const v = const <p.C>[];
+''');
+  }
+
+  test_const_topLevel_typedMap() {
+    checkLibrary(r'''
+const vDynamic1 = const <dynamic, int>{};
+const vDynamic2 = const <int, dynamic>{};
+const vInterface = const <int, String>{};
+const vInterfaceWithTypeArguments = const <int, List<String>>{};
+''');
+  }
+
+  test_const_topLevel_untypedList() {
+    checkLibrary(r'''
+const v = const [1, 2, 3];
+''');
+  }
+
+  test_const_topLevel_untypedMap() {
+    checkLibrary(r'''
+const v = const {0: 'aaa', 1: 'bbb', 2: 'ccc'};
+''');
+  }
+
+  test_constExpr_pushReference_field_simpleIdentifier() {
+    checkLibrary('''
+class C {
+  static const a = b;
+  static const b = null;
+}
+''');
+  }
+
+  test_constExpr_pushReference_staticMethod_simpleIdentifier() {
+    checkLibrary('''
+class C {
+  static const a = m;
+  static m() {}
+}
+''');
+  }
+
   test_constructor_documented() {
     checkLibrary('''
 class C {
@@ -844,12 +2214,316 @@
 }''');
   }
 
+  test_constructor_initializers_field() {
+    checkLibrary('''
+class C {
+  final x;
+  const C() : x = 42;
+}
+''');
+  }
+
+  test_constructor_initializers_field_notConst() {
+    constantInitializersAreInvalid = true;
+    checkLibrary(
+        '''
+class C {
+  final x;
+  const A() : x = foo();
+}
+int foo() => 42;
+''',
+        allowErrors: true);
+  }
+
+  test_constructor_initializers_field_withParameter() {
+    checkLibrary('''
+class C {
+  final x;
+  const C(int p) : x = 1 + p;
+}
+''');
+  }
+
+  test_constructor_initializers_superInvocation_named() {
+    checkLibrary('''
+class A {
+  const A.aaa(int p);
+}
+class C extends A {
+  const C() : super.aaa(42);
+}
+''');
+  }
+
+  test_constructor_initializers_superInvocation_unnamed() {
+    checkLibrary('''
+class A {
+  const A(int p);
+}
+class C extends A {
+  const C.ccc() : super(42);
+}
+''');
+  }
+
+  test_constructor_initializers_thisInvocation_named() {
+    checkLibrary('''
+class C {
+  const C() : this.named(1, 'bbb');
+  const C.named(int a, String b);
+}
+''');
+  }
+
+  test_constructor_initializers_thisInvocation_unnamed() {
+    checkLibrary('''
+class C {
+  const C.named() : this(1, 'bbb');
+  const C(int a, String b);
+}
+''');
+  }
+
+  test_constructor_redirected_factory_named() {
+    checkLibrary('''
+class C {
+  factory C() = D.named;
+  C._();
+}
+class D extends C {
+  D.named() : super._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_named_generic() {
+    checkLibrary('''
+class C<T, U> {
+  factory C() = D<U, T>.named;
+  C._();
+}
+class D<T, U> extends C<U, T> {
+  D.named() : super._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_named_imported() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D extends C {
+  D.named() : super._();
+}
+''');
+    checkLibrary('''
+import 'foo.dart';
+class C {
+  factory C() = D.named;
+  C._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_named_imported_generic() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D<T, U> extends C<U, T> {
+  D.named() : super._();
+}
+''');
+    checkLibrary('''
+import 'foo.dart';
+class C<T, U> {
+  factory C() = D<U, T>.named;
+  C._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_named_prefixed() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D extends C {
+  D.named() : super._();
+}
+''');
+    checkLibrary('''
+import 'foo.dart' as foo;
+class C {
+  factory C() = foo.D.named;
+  C._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_named_prefixed_generic() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D<T, U> extends C<U, T> {
+  D.named() : super._();
+}
+''');
+    checkLibrary('''
+import 'foo.dart' as foo;
+class C<T, U> {
+  factory C() = foo.D<U, T>.named;
+  C._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_unnamed() {
+    checkLibrary('''
+class C {
+  factory C() = D;
+  C._();
+}
+class D extends C {
+  D() : super._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_unnamed_generic() {
+    checkLibrary('''
+class C<T, U> {
+  factory C() = D<U, T>;
+  C._();
+}
+class D<T, U> extends C<U, T> {
+  D() : super._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_unnamed_imported() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D extends C {
+  D() : super._();
+}
+''');
+    checkLibrary('''
+import 'foo.dart';
+class C {
+  factory C() = D;
+  C._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_unnamed_imported_generic() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D<T, U> extends C<U, T> {
+  D() : super._();
+}
+''');
+    checkLibrary('''
+import 'foo.dart';
+class C<T, U> {
+  factory C() = D<U, T>;
+  C._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_unnamed_prefixed() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D extends C {
+  D() : super._();
+}
+''');
+    checkLibrary('''
+import 'foo.dart' as foo;
+class C {
+  factory C() = foo.D;
+  C._();
+}
+''');
+  }
+
+  test_constructor_redirected_factory_unnamed_prefixed_generic() {
+    addLibrarySource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D<T, U> extends C<U, T> {
+  D() : super._();
+}
+''');
+    checkLibrary('''
+import 'foo.dart' as foo;
+class C<T, U> {
+  factory C() = foo.D<U, T>;
+  C._();
+}
+''');
+  }
+
+  test_constructor_redirected_thisInvocation_named() {
+    checkLibrary('''
+class C {
+  C.named();
+  C() : this.named();
+}
+''');
+  }
+
+  test_constructor_redirected_thisInvocation_named_generic() {
+    checkLibrary('''
+class C<T> {
+  C.named();
+  C() : this.named();
+}
+''');
+  }
+
+  test_constructor_redirected_thisInvocation_unnamed() {
+    checkLibrary('''
+class C {
+  C();
+  C.named() : this();
+}
+''');
+  }
+
+  test_constructor_redirected_thisInvocation_unnamed_generic() {
+    checkLibrary('''
+class C<T> {
+  C();
+  C.named() : this();
+}
+''');
+  }
+
   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));
-    LibraryElementImpl resynthesized =
-        resynthesizeLibraryElement(uri, original);
+    LibraryElementImpl resynthesized = resynthesizeLibraryElement(
+        encodeLibraryElement(original), uri, original);
     checkLibraryElements(original, resynthesized);
   }
 
@@ -880,28 +2554,78 @@
     checkLibrary('enum E1 { v1 } enum E2 { v2 }');
   }
 
+  test_executable_parameter_type_typedef() {
+    checkLibrary(r'''
+typedef F(int p);
+main(F f) {}
+''');
+  }
+
+  test_export_class() {
+    addLibrarySource('/a.dart', 'class C {}');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_export_class_type_alias() {
+    addLibrarySource(
+        '/a.dart', 'class C {} exends _D with _E; class _D {} class _E {}');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_export_function() {
+    addLibrarySource('/a.dart', 'f() {}');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_export_getter() {
+    addLibrarySource('/a.dart', 'get f() => null;');
+    checkLibrary('export "a.dart";');
+  }
+
   test_export_hide() {
     addLibrary('dart:async');
-    checkLibrary('export "dart:async" hide Stream, Future;',
-        resynthesisCount: 2);
+    checkLibrary('export "dart:async" hide Stream, Future;');
   }
 
   test_export_multiple_combinators() {
     addLibrary('dart:async');
-    checkLibrary('export "dart:async" hide Stream show Future;',
-        resynthesisCount: 2);
+    checkLibrary('export "dart:async" hide Stream show Future;');
+  }
+
+  test_export_setter() {
+    addLibrarySource('/a.dart', 'void set f(value) {}');
+    checkLibrary('export "a.dart";');
   }
 
   test_export_show() {
     addLibrary('dart:async');
-    checkLibrary('export "dart:async" show Future, Stream;',
-        resynthesisCount: 2);
+    checkLibrary('export "dart:async" show Future, Stream;');
+  }
+
+  test_export_typedef() {
+    addLibrarySource('/a.dart', 'typedef F();');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_export_variable() {
+    addLibrarySource('/a.dart', 'var x;');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_export_variable_const() {
+    addLibrarySource('/a.dart', 'const x = 0;');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_export_variable_final() {
+    addLibrarySource('/a.dart', 'final x = 0;');
+    checkLibrary('export "a.dart";');
   }
 
   test_exports() {
     addLibrarySource('/a.dart', 'library a;');
     addLibrarySource('/b.dart', 'library b;');
-    checkLibrary('export "a.dart"; export "b.dart";', resynthesisCount: 3);
+    checkLibrary('export "a.dart"; export "b.dart";');
   }
 
   test_field_documented() {
@@ -914,6 +2638,68 @@
 }''');
   }
 
+  test_field_formal_param_inferred_type_implicit() {
+    checkLibrary('class C extends D { var v; C(this.v); }'
+        ' abstract class D { int get v; }');
+  }
+
+  test_field_inferred_type_nonStatic_explicit_initialized() {
+    checkLibrary('class C { num v = 0; }');
+  }
+
+  test_field_inferred_type_nonStatic_implicit_initialized() {
+    checkLibrary('class C { var v = 0; }');
+  }
+
+  test_field_inferred_type_nonStatic_implicit_uninitialized() {
+    checkLibrary(
+        'class C extends D { var v; } abstract class D { int get v; }');
+  }
+
+  test_field_inferred_type_static_implicit_initialized() {
+    checkLibrary('class C { static var v = 0; }');
+  }
+
+  test_field_propagatedType_const_noDep() {
+    checkLibrary('''
+class C {
+  static const x = 0;
+}''');
+  }
+
+  test_field_propagatedType_final_dep_inLib() {
+    addLibrarySource('/a.dart', 'final a = 1;');
+    checkLibrary('''
+import "a.dart";
+class C {
+  final b = a / 2;
+}''');
+  }
+
+  test_field_propagatedType_final_dep_inPart() {
+    addNamedSource('/a.dart', 'part of lib; final a = 1;');
+    checkLibrary('''
+library lib;
+part "a.dart";
+class C {
+  final b = a / 2;
+}''');
+  }
+
+  test_field_propagatedType_final_noDep_instance() {
+    checkLibrary('''
+class C {
+  final x = 0;
+}''');
+  }
+
+  test_field_propagatedType_final_noDep_static() {
+    checkLibrary('''
+class C {
+  static final x = 0;
+}''');
+  }
+
   test_function_documented() {
     checkLibrary('''
 // Extra comment so doc comment offset != 0
@@ -929,12 +2715,12 @@
 
   test_function_entry_point_in_export() {
     addLibrarySource('/a.dart', 'library a; main() {}');
-    checkLibrary('export "a.dart";', resynthesisCount: 2);
+    checkLibrary('export "a.dart";');
   }
 
   test_function_entry_point_in_export_hidden() {
     addLibrarySource('/a.dart', 'library a; main() {}');
-    checkLibrary('export "a.dart" hide main;', resynthesisCount: 2);
+    checkLibrary('export "a.dart" hide main;');
   }
 
   test_function_entry_point_in_part() {
@@ -947,12 +2733,10 @@
   }
 
   test_function_parameter_kind_named() {
-    // TODO(paulberry): also test default value.
     checkLibrary('f({x}) {}');
   }
 
   test_function_parameter_kind_positional() {
-    // TODO(paulberry): also test default value.
     checkLibrary('f([x]) {}');
   }
 
@@ -993,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)) {}');
   }
 
@@ -1006,6 +2790,89 @@
     checkLibrary('f() {} g() {}');
   }
 
+  test_generic_gClass_gMethodStatic() {
+    resetWithOptions(createOptions()..enableGenericMethods = true);
+    checkLibrary('''
+class C<T, U> {
+  static void m<V, W>(V v, W w) {
+    void f<X, Y>(V v, W w, X x, Y y) {
+    }
+  }
+}
+''');
+  }
+
+  test_getElement_constructor_named() {
+    ConstructorElement original = resolve2(addSource('class C { C.named(); }'))
+        .getType('C')
+        .getNamedConstructor('named');
+    expect(original, isNotNull);
+    ConstructorElement resynthesized = validateGetElement(original);
+    compareConstructorElements(resynthesized, original, 'C.constructor named');
+  }
+
+  test_getElement_constructor_unnamed() {
+    ConstructorElement original =
+        resolve2(addSource('class C { C(); }')).getType('C').unnamedConstructor;
+    expect(original, isNotNull);
+    ConstructorElement resynthesized = validateGetElement(original);
+    compareConstructorElements(resynthesized, original, 'C.constructor');
+  }
+
+  test_getElement_field() {
+    FieldElement original =
+        resolve2(addSource('class C { var f; }')).getType('C').getField('f');
+    expect(original, isNotNull);
+    FieldElement resynthesized = validateGetElement(original);
+    compareFieldElements(resynthesized, original, 'C.field f');
+  }
+
+  test_getElement_getter() {
+    PropertyAccessorElement original =
+        resolve2(addSource('class C { get f => null; }'))
+            .getType('C')
+            .getGetter('f');
+    expect(original, isNotNull);
+    PropertyAccessorElement resynthesized = validateGetElement(original);
+    comparePropertyAccessorElements(resynthesized, original, 'C.getter f');
+  }
+
+  test_getElement_method() {
+    MethodElement original =
+        resolve2(addSource('class C { f() {} }')).getType('C').getMethod('f');
+    expect(original, isNotNull);
+    MethodElement resynthesized = validateGetElement(original);
+    compareMethodElements(resynthesized, original, 'C.method f');
+  }
+
+  test_getElement_operator() {
+    MethodElement original =
+        resolve2(addSource('class C { operator+(x) => null; }'))
+            .getType('C')
+            .getMethod('+');
+    expect(original, isNotNull);
+    MethodElement resynthesized = validateGetElement(original);
+    compareMethodElements(resynthesized, original, 'C.operator+');
+  }
+
+  test_getElement_setter() {
+    PropertyAccessorElement original =
+        resolve2(addSource('class C { void set f(value) {} }'))
+            .getType('C')
+            .getSetter('f');
+    expect(original, isNotNull);
+    PropertyAccessorElement resynthesized = validateGetElement(original);
+    comparePropertyAccessorElements(resynthesized, original, 'C.setter f');
+  }
+
+  test_getElement_unit() {
+    Source source = addSource('class C { f() {} }');
+    CompilationUnitElement original = resolve2(source).definingCompilationUnit;
+    expect(original, isNotNull);
+    CompilationUnitElement resynthesized = validateGetElement(original);
+    compareCompilationUnitElements(resynthesized, original);
+  }
+
   test_getter_documented() {
     checkLibrary('''
 // Extra comment so doc comment offset != 0
@@ -1019,6 +2886,11 @@
     checkLibrary('external int get x;');
   }
 
+  test_getter_inferred_type_nonStatic_implicit_return() {
+    checkLibrary(
+        'class C extends D { get f => null; } abstract class D { int get f; }');
+  }
+
   test_getters() {
     checkLibrary('int get x => null; get y => null;');
   }
@@ -1031,6 +2903,11 @@
     checkLibrary('void set x(int value) {} int get x => 0;');
   }
 
+  test_import_deferred() {
+    addLibrarySource('/a.dart', 'f() {}');
+    checkLibrary('import "a.dart" deferred as p; main() { p.f(); }');
+  }
+
   test_import_hide() {
     addLibrary('dart:async');
     checkLibrary('import "dart:async" hide Stream, Completer; Future f;');
@@ -1057,6 +2934,155 @@
     checkLibrary('import "a.dart"; import "b.dart"; C c; D d;');
   }
 
+  test_inferred_function_type_for_variable_in_generic_function() {
+    // In the code below, `x` has an inferred type of `() => int`, with 2
+    // (unused) type parameters from the enclosing top level function.
+    checkLibrary('''
+f<U, V>() {
+  var x = () => 0;
+}
+''');
+  }
+
+  test_inferred_function_type_in_generic_class_constructor() {
+    // In the code below, `() => () => 0` has an inferred return type of
+    // `() => int`, with 2 (unused) type parameters from the enclosing class.
+    checkLibrary('''
+class C<U, V> {
+  final x;
+  C() : x = (() => () => 0);
+}
+''');
+  }
+
+  test_inferred_function_type_in_generic_class_getter() {
+    // In the code below, `() => () => 0` has an inferred return type of
+    // `() => int`, with 2 (unused) type parameters from the enclosing class.
+    checkLibrary('''
+class C<U, V> {
+  get x => () => () => 0;
+}
+''');
+  }
+
+  test_inferred_function_type_in_generic_class_in_generic_method() {
+    // In the code below, `() => () => 0` has an inferred return type of
+    // `() => int`, with 3 (unused) type parameters from the enclosing class
+    // and method.
+    checkLibrary('''
+class C<T> {
+  f<U, V>() {
+    print(() => () => 0);
+  }
+}
+''');
+  }
+
+  test_inferred_function_type_in_generic_class_setter() {
+    // In the code below, `() => () => 0` has an inferred return type of
+    // `() => int`, with 2 (unused) type parameters from the enclosing class.
+    checkLibrary('''
+class C<U, V> {
+  void set x(value) {
+    print(() => () => 0);
+  }
+}
+''');
+  }
+
+  test_inferred_function_type_in_generic_closure() {
+    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;
+    }
+    // In the code below, `<U, V>() => () => 0` has an inferred return type of
+    // `() => int`, with 3 (unused) type parameters.
+    checkLibrary('''
+f<T>() {
+  print(/*<U, V>*/() => () => 0);
+}
+''');
+  }
+
+  test_inferred_generic_function_type_in_generic_closure() {
+    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;
+    }
+    // In the code below, `<U, V>() => <W, X, Y, Z>() => 0` has an inferred
+    // return type of `() => int`, with 7 (unused) type parameters.
+    checkLibrary('''
+f<T>() {
+  print(/*<U, V>*/() => /*<W, X, Y, Z>*/() => 0);
+}
+''');
+  }
+
+  test_inferred_type_is_typedef() {
+    checkLibrary('typedef int F(String s);'
+        ' class C extends D { var v; }'
+        ' abstract class D { F get v; }');
+  }
+
+  test_inferred_type_refers_to_bound_type_param() {
+    checkLibrary('class C<T> extends D<int, T> { var v; }'
+        ' abstract class D<U, V> { Map<V, U> get v; }');
+  }
+
+  test_inferred_type_refers_to_function_typed_parameter_type_generic_class() {
+    checkLibrary('class C<T, U> extends D<U, int> { void f(int x, g) {} }'
+        ' abstract class D<V, W> { void f(int x, W g(V s)); }');
+  }
+
+  test_inferred_type_refers_to_function_typed_parameter_type_other_lib() {
+    addLibrarySource(
+        '/a.dart', 'import "b.dart"; abstract class D extends E {}');
+    addLibrarySource(
+        '/b.dart', 'abstract class E { void f(int x, int g(String s)); }');
+    checkLibrary('import "a.dart"; class C extends D { void f(int x, g) {} }');
+  }
+
+  test_inferred_type_refers_to_method_function_typed_parameter_type() {
+    checkLibrary('class C extends D { void f(int x, g) {} }'
+        ' abstract class D { void f(int x, int g(String s)); }');
+  }
+
+  test_inferred_type_refers_to_setter_function_typed_parameter_type() {
+    checkLibrary('class C extends D { void set f(g) {} }'
+        ' abstract class D { void set f(int g(String s)); }');
+  }
+
+  test_initializer_executable_with_return_type_from_closure() {
+    checkLibrary('var v = () => 0;');
+  }
+
+  test_initializer_executable_with_return_type_from_closure_field() {
+    checkLibrary('''
+class C {
+  var v = () => 0;
+}
+''');
+  }
+
+  test_initializer_executable_with_return_type_from_closure_local() {
+    checkLibrary('''
+void f() {
+  int u = 0;
+  var v = () => 0;
+}
+''');
+  }
+
   test_library() {
     checkLibrary('');
   }
@@ -1078,6 +3104,331 @@
     checkLibrary('library foo.bar;');
   }
 
+  test_localFunctions() {
+    checkLibrary(r'''
+f() {
+  f1() {}
+  {
+    f2() {}
+  }
+}
+''');
+  }
+
+  test_localFunctions_inConstructor() {
+    checkLibrary(r'''
+class C {
+  C() {
+    f() {}
+  }
+}
+''');
+  }
+
+  test_localFunctions_inMethod() {
+    checkLibrary(r'''
+class C {
+  m() {
+    f() {}
+  }
+}
+''');
+  }
+
+  test_localFunctions_inTopLevelGetter() {
+    checkLibrary(r'''
+get g {
+  f() {}
+}
+''');
+  }
+
+  test_localLabels_inConstructor() {
+    checkLibrary(r'''
+class C {
+  C() {
+    aaa: while (true) {}
+    bbb: switch (42) {
+      ccc: case 0:
+        break;
+    }
+  }
+}
+''');
+  }
+
+  test_localLabels_inMethod() {
+    checkLibrary(r'''
+class C {
+  m() {
+    aaa: while (true) {}
+    bbb: switch (42) {
+      ccc: case 0:
+        break;
+    }
+  }
+}
+''');
+  }
+
+  test_localLabels_inTopLevelFunction() {
+    checkLibrary(r'''
+main() {
+  aaa: while (true) {}
+  bbb: switch (42) {
+    ccc: case 0:
+      break;
+  }
+}
+''');
+  }
+
+  test_localVariables_inConstructor() {
+    checkLibrary(r'''
+class C {
+  C() {
+    int v;
+    f() {}
+  }
+}
+''');
+  }
+
+  test_localVariables_inLocalFunction() {
+    checkLibrary(r'''
+f() {
+  f1() {
+    int v1 = 1;
+  } // 2
+  f2() {
+    int v1 = 1;
+    f3() {
+      int v2 = 1;
+    }
+  }
+}
+''');
+  }
+
+  test_localVariables_inMethod() {
+    checkLibrary(r'''
+class C {
+  m() {
+    int v;
+  }
+}
+''');
+  }
+
+  test_localVariables_inTopLevelFunction() {
+    checkLibrary(r'''
+main() {
+  int v1 = 1;
+  {
+    const String v2 = 'bbb';
+  }
+  Map<int, List<double>> v3;
+}
+''');
+  }
+
+  test_localVariables_inTopLevelGetter() {
+    checkLibrary(r'''
+get g {
+  int v;
+}
+''');
+  }
+
+  test_main_class() {
+    checkLibrary('class main {}');
+  }
+
+  test_main_class_alias() {
+    checkLibrary('class main = C with D; class C {} class D {}');
+  }
+
+  test_main_class_alias_via_export() {
+    addLibrarySource('/a.dart', 'class main = C with D; class C {} class D {}');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_main_class_via_export() {
+    addLibrarySource('/a.dart', 'class main {}');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_main_getter() {
+    checkLibrary('get main => null;');
+  }
+
+  test_main_getter_via_export() {
+    addLibrarySource('/a.dart', 'get main => null;');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_main_typedef() {
+    checkLibrary('typedef main();');
+  }
+
+  test_main_typedef_via_export() {
+    addLibrarySource('/a.dart', 'typedef main();');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_main_variable() {
+    checkLibrary('var main;');
+  }
+
+  test_main_variable_via_export() {
+    addLibrarySource('/a.dart', 'var main;');
+    checkLibrary('export "a.dart";');
+  }
+
+  test_metadata_classDeclaration() {
+    checkLibrary('const a = null; @a class C {}');
+  }
+
+  test_metadata_classTypeAlias() {
+    checkLibrary(
+        'const a = null; @a class C = D with E; class D {} class E {}');
+  }
+
+  test_metadata_constructor_call_named() {
+    checkLibrary('class A { const A.named(); } @A.named() class C {}');
+  }
+
+  test_metadata_constructor_call_named_prefixed() {
+    addLibrarySource('/foo.dart', 'class A { const A.named(); }');
+    checkLibrary('import "foo.dart" as foo; @foo.A.named() class C {}');
+  }
+
+  test_metadata_constructor_call_unnamed() {
+    checkLibrary('class A { const A(); } @A() class C {}');
+  }
+
+  test_metadata_constructor_call_unnamed_prefixed() {
+    addLibrarySource('/foo.dart', 'class A { const A(); }');
+    checkLibrary('import "foo.dart" as foo; @foo.A() class C {}');
+  }
+
+  test_metadata_constructor_call_with_args() {
+    checkLibrary('class A { const A(x); } @A(null) class C {}');
+  }
+
+  test_metadata_constructorDeclaration_named() {
+    checkLibrary('const a = null; class C { @a C.named(); }');
+  }
+
+  test_metadata_constructorDeclaration_unnamed() {
+    checkLibrary('const a = null; class C { @a C(); }');
+  }
+
+  test_metadata_enumDeclaration() {
+    checkLibrary('const a = null; @a enum E { v }');
+  }
+
+  test_metadata_exportDirective() {
+    addLibrarySource('/foo.dart', '');
+    checkLibrary('@a export "foo.dart"; const a = null;');
+  }
+
+  test_metadata_fieldDeclaration() {
+    checkLibrary('const a = null; class C { @a int x; }');
+  }
+
+  test_metadata_fieldFormalParameter() {
+    checkLibrary('const a = null; class C { var x; C(@a this.x); }');
+  }
+
+  test_metadata_fieldFormalParameter_withDefault() {
+    checkLibrary('const a = null; class C { var x; C([@a this.x = null]); }');
+  }
+
+  test_metadata_functionDeclaration_function() {
+    checkLibrary('const a = null; @a f() {}');
+  }
+
+  test_metadata_functionDeclaration_getter() {
+    checkLibrary('const a = null; @a get f => null;');
+  }
+
+  test_metadata_functionDeclaration_setter() {
+    checkLibrary('const a = null; @a set f(value) {}');
+  }
+
+  test_metadata_functionTypeAlias() {
+    checkLibrary('const a = null; @a typedef F();');
+  }
+
+  test_metadata_functionTypedFormalParameter() {
+    checkLibrary('const a = null; f(@a g()) {}');
+  }
+
+  test_metadata_functionTypedFormalParameter_withDefault() {
+    checkLibrary('const a = null; f([@a g() = null]) {}');
+  }
+
+  test_metadata_importDirective() {
+    addLibrarySource('/foo.dart', 'const b = null;');
+    checkLibrary('@a import "foo.dart"; const a = b;');
+  }
+
+  test_metadata_libraryDirective() {
+    checkLibrary('@a library L; const a = null;');
+  }
+
+  test_metadata_methodDeclaration_getter() {
+    checkLibrary('const a = null; class C { @a get m => null; }');
+  }
+
+  test_metadata_methodDeclaration_method() {
+    checkLibrary('const a = null; class C { @a m() {} }');
+  }
+
+  test_metadata_methodDeclaration_setter() {
+    checkLibrary('const a = null; class C { @a set m(value) {} }');
+  }
+
+  test_metadata_partDirective() {
+    addNamedSource('/foo.dart', 'part of L;');
+    checkLibrary('library L; @a part "foo.dart"; const a = null;');
+  }
+
+  test_metadata_prefixed_variable() {
+    addLibrarySource('/a.dart', 'const b = null;');
+    checkLibrary('import "a.dart" as a; @a.b class C {}');
+  }
+
+  test_metadata_simpleFormalParameter() {
+    checkLibrary('const a = null; f(@a x) {}');
+  }
+
+  test_metadata_simpleFormalParameter_withDefault() {
+    checkLibrary('const a = null; f([@a x = null]) {}');
+  }
+
+  test_metadata_topLevelVariableDeclaration() {
+    checkLibrary('const a = null; @a int v;');
+  }
+
+  test_metadata_typeParameter_ofClass() {
+    checkLibrary('const a = null; class C<@a T> {}');
+  }
+
+  test_metadata_typeParameter_ofClassTypeAlias() {
+    checkLibrary(
+        'const a = null; class C<@a T> = D with E; class D {} class E {}');
+  }
+
+  test_metadata_typeParameter_ofFunction() {
+    checkLibrary('const a = null; f<@a T>() {}');
+  }
+
+  test_metadata_typeParameter_ofTypedef() {
+    checkLibrary('const a = null; typedef F<@a T>();');
+  }
+
   test_method_documented() {
     checkLibrary('''
 class C {
@@ -1088,6 +3439,16 @@
 }''');
   }
 
+  test_method_inferred_type_nonStatic_implicit_param() {
+    checkLibrary('class C extends D { void f(value) {} }'
+        ' abstract class D { void f(int value); }');
+  }
+
+  test_method_inferred_type_nonStatic_implicit_return() {
+    checkLibrary(
+        'class C extends D { f() => null; } abstract class D { int f(); }');
+  }
+
   test_method_parameter_parameters() {
     checkLibrary('class C { f(g(x, y)) {} }');
   }
@@ -1105,26 +3466,82 @@
   }
 
   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)) {} }');
   }
 
+  test_nested_generic_functions_in_generic_class_with_function_typed_params() {
+    checkLibrary('''
+class C<T, U> {
+  void g<V, W>() {
+    void h<X, Y>(void p(T t, U u, V v, W w, X x, Y y)) {
+    }
+  }
+}
+''');
+  }
+
+  test_nested_generic_functions_in_generic_class_with_local_variables() {
+    checkLibrary('''
+class C<T, U> {
+  void g<V, W>() {
+    void h<X, Y>() {
+      T t;
+      U u;
+      V v;
+      W w;
+      X x;
+      Y y;
+    }
+  }
+}
+''');
+  }
+
+  test_nested_generic_functions_with_function_typed_param() {
+    checkLibrary('''
+void f<T, U>() {
+  void g<V, W>() {
+    void h<X, Y>(void p(T t, U u, V v, W w, X x, Y y)) {
+    }
+  }
+}
+''');
+  }
+
+  test_nested_generic_functions_with_local_variables() {
+    checkLibrary('''
+void f<T, U>() {
+  void g<V, W>() {
+    void h<X, Y>() {
+      T t;
+      U u;
+      V v;
+      W w;
+      X x;
+      Y y;
+    }
+  }
+}
+''');
+  }
+
   test_operator() {
     checkLibrary('class C { C operator+(C other) => null; }');
   }
 
   test_operator_equal() {
-    checkLibrary('class C { bool operator==(C other) => false; }');
+    checkLibrary('class C { bool operator==(Object other) => false; }');
   }
 
   test_operator_external() {
@@ -1147,12 +3564,65 @@
     checkLibrary('class C { bool operator<=(C other) => false; }');
   }
 
+  test_parameterTypeNotInferred_constructor() {
+    // Strong mode doesn't do type inference on constructor parameters, so it's
+    // ok that we don't store inferred type info for them in summaries.
+    checkLibrary('''
+class C {
+  C.positional([x = 1]);
+  C.named({x: 1});
+}
+''');
+  }
+
+  test_parameterTypeNotInferred_initializingFormal() {
+    // Strong mode doesn't do type inference on initializing formals, so it's
+    // ok that we don't store inferred type info for them in summaries.
+    checkLibrary('''
+class C {
+  var x;
+  C.positional([this.x = 1]);
+  C.named({this.x: 1});
+}
+''');
+  }
+
+  test_parameterTypeNotInferred_staticMethod() {
+    // Strong mode doesn't do type inference on parameters of static methods,
+    // so it's ok that we don't store inferred type info for them in summaries.
+    checkLibrary('''
+class C {
+  static void positional([x = 1]) {}
+  static void named({x: 1}) {}
+}
+''');
+  }
+
+  test_parameterTypeNotInferred_topLevelFunction() {
+    // Strong mode doesn't do type inference on parameters of top level
+    // functions, so it's ok that we don't store inferred type info for them in
+    // summaries.
+    checkLibrary('''
+void positional([x = 1]) {}
+void named({x: 1}) {}
+''');
+  }
+
   test_parts() {
     addNamedSource('/a.dart', 'part of my.lib;');
     addNamedSource('/b.dart', 'part of my.lib;');
     checkLibrary('library my.lib; part "a.dart"; part "b.dart";');
   }
 
+  test_propagated_type_refers_to_closure() {
+    checkLibrary('''
+void f() {
+  var x = () => 0;
+  var y = x;
+}
+''');
+  }
+
   test_setter_documented() {
     checkLibrary('''
 // Extra comment so doc comment offset != 0
@@ -1166,11 +3636,100 @@
     checkLibrary('external void set x(int value);');
   }
 
+  test_setter_inferred_type_nonStatic_implicit_param() {
+    checkLibrary('class C extends D { void set f(value) {} }'
+        ' abstract class D { void set f(int value); }');
+  }
+
+  test_setter_inferred_type_static_implicit_return() {
+    checkLibrary('class C { static set f(int value) {} }');
+  }
+
+  test_setter_inferred_type_top_level_implicit_return() {
+    checkLibrary('set f(int value) {}');
+  }
+
   test_setters() {
     checkLibrary('void set x(int value) {} set y(value) {}');
   }
 
-  test_type_arguments_explicit() {
+  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;');
+  }
+
+  test_type_arguments_explicit_dynamic_int() {
+    checkLibrary('Map<dynamic, int> m;');
+  }
+
+  test_type_arguments_explicit_String_dynamic() {
+    checkLibrary('Map<String, dynamic> m;');
+  }
+
+  test_type_arguments_explicit_String_int() {
     checkLibrary('Map<String, int> m;');
   }
 
@@ -1386,11 +3945,141 @@
 var x;''');
   }
 
+  test_variable_final() {
+    checkLibrary('final int x = 0;');
+  }
+
+  test_variable_getterInLib_setterInPart() {
+    addNamedSource('/a.dart', 'part of my.lib; void set x(int _) {}');
+    checkLibrary('library my.lib; part "a.dart"; int get x => 42;');
+  }
+
+  test_variable_getterInPart_setterInLib() {
+    addNamedSource('/a.dart', 'part of my.lib; int get x => 42;');
+    checkLibrary('library my.lib; part "a.dart"; void set x(int _) {}');
+  }
+
+  test_variable_getterInPart_setterInPart() {
+    addNamedSource('/a.dart', 'part of my.lib; int get x => 42;');
+    addNamedSource('/b.dart', 'part of my.lib; void set x(int _) {}');
+    checkLibrary('library my.lib; part "a.dart"; part "b.dart";');
+  }
+
   test_variable_implicit_type() {
     checkLibrary('var x;');
   }
 
+  test_variable_inferred_type_implicit_initialized() {
+    checkLibrary('var v = 0;');
+  }
+
+  test_variable_propagatedType_const_noDep() {
+    checkLibrary('const i = 0;');
+  }
+
+  test_variable_propagatedType_final_dep_inLib() {
+    addLibrarySource('/a.dart', 'final a = 1;');
+    checkLibrary('import "a.dart"; final b = a / 2;');
+  }
+
+  test_variable_propagatedType_final_dep_inPart() {
+    addNamedSource('/a.dart', 'part of lib; final a = 1;');
+    checkLibrary('library lib; part "a.dart"; final b = a / 2;');
+  }
+
+  test_variable_propagatedType_final_noDep() {
+    checkLibrary('final i = 0;');
+  }
+
+  test_variable_propagatedType_implicit_dep() {
+    // The propagated type is defined in a library that is not imported.
+    addLibrarySource('/a.dart', 'class C {}');
+    addLibrarySource('/b.dart', 'import "a.dart"; C f() => null;');
+    checkLibrary('import "b.dart"; final x = f();');
+  }
+
+  test_variable_setterInPart_getterInPart() {
+    addNamedSource('/a.dart', 'part of my.lib; void set x(int _) {}');
+    addNamedSource('/b.dart', 'part of my.lib; int get x => 42;');
+    checkLibrary('library my.lib; part "a.dart"; part "b.dart";');
+  }
+
   test_variables() {
     checkLibrary('int i; int j;');
   }
+
+  /**
+   * Encode the library containing [original] into a summary and then use
+   * [_TestSummaryResynthesizer.getElement] to retrieve just the original
+   * element from the resynthesized summary.
+   */
+  Element validateGetElement(Element original) {
+    _TestSummaryResynthesizer resynthesizer = encodeLibrary(original.library);
+    ElementLocationImpl location = original.location;
+    Element result = resynthesizer.getElement(location);
+    checkMinimalResynthesisWork(resynthesizer, original.library);
+    // Check that no other summaries needed to be resynthesized to resynthesize
+    // the library element.
+    expect(resynthesizer.resynthesisCount, 1);
+    expect(result.location, location);
+    return result;
+  }
+
+  void _assertUnresolvedIdentifier(Expression initializer, String desc) {
+    expect(initializer, new isInstanceOf<SimpleIdentifier>(), reason: desc);
+    SimpleIdentifier identifier = initializer;
+    expect(identifier.staticElement, isNull, reason: desc);
+  }
+}
+
+class _TestSummaryResynthesizer extends SummaryResynthesizer {
+  final Map<String, UnlinkedUnit> unlinkedSummaries;
+  final Map<String, LinkedLibrary> linkedSummaries;
+
+  /**
+   * The set of uris for which unlinked summaries have been requested using
+   * [getUnlinkedSummary].
+   */
+  final Set<String> unlinkedSummariesRequested = new Set<String>();
+
+  /**
+   * The set of uris for which linked summaries have been requested using
+   * [getLinkedSummary].
+   */
+  final Set<String> linkedSummariesRequested = new Set<String>();
+
+  _TestSummaryResynthesizer(
+      SummaryResynthesizer parent,
+      AnalysisContext context,
+      TypeProvider typeProvider,
+      SourceFactory sourceFactory,
+      this.unlinkedSummaries,
+      this.linkedSummaries,
+      bool strongMode)
+      : super(parent, context, typeProvider, sourceFactory, strongMode);
+
+  @override
+  LinkedLibrary getLinkedSummary(String uri) {
+    linkedSummariesRequested.add(uri);
+    LinkedLibrary serializedLibrary = linkedSummaries[uri];
+    if (serializedLibrary == null) {
+      fail('Unexpectedly tried to get linked summary for $uri');
+    }
+    return serializedLibrary;
+  }
+
+  @override
+  UnlinkedUnit getUnlinkedSummary(String uri) {
+    unlinkedSummariesRequested.add(uri);
+    UnlinkedUnit serializedUnit = unlinkedSummaries[uri];
+    if (serializedUnit == null) {
+      fail('Unexpectedly tried to get unlinked summary for $uri');
+    }
+    return serializedUnit;
+  }
+
+  @override
+  bool hasLibrarySummary(String uri) {
+    return true;
+  }
 }
diff --git a/pkg/analyzer/test/src/summary/summarize_ast_test.dart b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
new file mode 100644
index 0000000..4e4cc1e
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/summarize_ast_test.dart
@@ -0,0 +1,120 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.summary.summarize_ast_test;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/prelink.dart';
+import 'package:analyzer/src/summary/summarize_ast.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'summary_common.dart';
+
+main() {
+  groupSep = ' | ';
+  runReflectiveTests(UnlinkedSummarizeAstTest);
+}
+
+/**
+ * Override of [SummaryTest] which creates unlinked summaries directly from the
+ * AST.
+ */
+@reflectiveTest
+class UnlinkedSummarizeAstTest extends Object with SummaryTest {
+  @override
+  LinkedLibrary linked;
+
+  @override
+  List<UnlinkedUnit> unlinkedUnits;
+
+  /**
+   * Map from absolute URI to the [UnlinkedUnit] for each compilation unit
+   * passed to [addNamedSource].
+   */
+  Map<String, UnlinkedUnit> uriToUnit = <String, UnlinkedUnit>{};
+
+  @override
+  bool get checkAstDerivedData => true;
+
+  @override
+  bool get expectAbsoluteUrisInDependencies => false;
+
+  @override
+  bool get skipFullyLinkedData => true;
+
+  @override
+  bool get strongMode => false;
+
+  @override
+  addNamedSource(String filePath, String contents) {
+    CompilationUnit unit = _parseText(contents);
+    UnlinkedUnit unlinkedUnit =
+        new UnlinkedUnit.fromBuffer(serializeAstUnlinked(unit).toBuffer());
+    uriToUnit[absUri(filePath)] = unlinkedUnit;
+  }
+
+  @override
+  void serializeLibraryText(String text, {bool allowErrors: false}) {
+    Uri testDartUri = Uri.parse(absUri('/test.dart'));
+    String resolveToAbsoluteUri(String relativeUri) =>
+        testDartUri.resolve(relativeUri).toString();
+    CompilationUnit unit = _parseText(text);
+    UnlinkedUnit definingUnit =
+        new UnlinkedUnit.fromBuffer(serializeAstUnlinked(unit).toBuffer());
+    UnlinkedUnit getPart(String relativeUri) {
+      String absoluteUri = resolveToAbsoluteUri(relativeUri);
+      UnlinkedUnit unit = uriToUnit[absoluteUri];
+      if (unit == null && !allowMissingFiles) {
+        fail('Prelinker unexpectedly requested unit for "$relativeUri"'
+            ' (resolves to "$absoluteUri").');
+      }
+      return unit;
+    }
+    UnlinkedPublicNamespace getImport(String relativeUri) {
+      String absoluteUri = resolveToAbsoluteUri(relativeUri);
+      UnlinkedPublicNamespace namespace = sdkPublicNamespace[absoluteUri];
+      if (namespace == null) {
+        namespace = uriToUnit[absoluteUri]?.publicNamespace;
+      }
+      if (namespace == null && !allowMissingFiles) {
+        fail('Prelinker unexpectedly requested namespace for "$relativeUri"'
+            ' (resolves to "$absoluteUri").'
+            '  Namespaces available: ${uriToUnit.keys}');
+      }
+      return namespace;
+    }
+    linked = new LinkedLibrary.fromBuffer(
+        prelink(definingUnit, getPart, getImport).toBuffer());
+    validateLinkedLibrary(linked);
+    unlinkedUnits = <UnlinkedUnit>[definingUnit];
+    for (String relativeUri in definingUnit.publicNamespace.parts) {
+      UnlinkedUnit unit = uriToUnit[resolveToAbsoluteUri(relativeUri)];
+      if (unit == null) {
+        if (!allowMissingFiles) {
+          fail('Test referred to unknown unit $relativeUri');
+        }
+      } else {
+        unlinkedUnits.add(unit);
+      }
+    }
+  }
+
+  CompilationUnit _parseText(String text) {
+    CharSequenceReader reader = new CharSequenceReader(text);
+    Scanner scanner =
+        new Scanner(null, reader, AnalysisErrorListener.NULL_LISTENER);
+    Token token = scanner.tokenize();
+    Parser parser = new Parser(null, AnalysisErrorListener.NULL_LISTENER);
+    parser.parseGenericMethods = true;
+    return parser.parseCompilationUnit(token);
+  }
+}
diff --git a/pkg/analyzer/test/src/summary/summarize_elements_strong_test.dart b/pkg/analyzer/test/src/summary/summarize_elements_strong_test.dart
new file mode 100644
index 0000000..8a8bfe6
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/summarize_elements_strong_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.summary.summarize_elements_strong_test;
+
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../reflective_tests.dart';
+import 'summarize_elements_test.dart';
+import 'summary_common.dart';
+
+main() {
+  groupSep = ' | ';
+  runReflectiveTests(SummarizeElementsStrongTest);
+}
+
+/**
+ * Override of [SummaryTest] which creates summaries from the element model
+ * using strong mode.
+ */
+@reflectiveTest
+class SummarizeElementsStrongTest extends SummarizeElementsTest {
+  @override
+  AnalysisOptionsImpl get options => super.options..strongMode = true;
+
+  @override
+  bool get strongMode => true;
+}
diff --git a/pkg/analyzer/test/src/summary/summarize_elements_test.dart b/pkg/analyzer/test/src/summary/summarize_elements_test.dart
new file mode 100644
index 0000000..b854d31
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/summarize_elements_test.dart
@@ -0,0 +1,157 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.summary.summarize_elements_test;
+
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/engine.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/public_namespace_computer.dart'
+    as public_namespace;
+import 'package:analyzer/src/summary/summarize_elements.dart'
+    as summarize_elements;
+import 'package:unittest/unittest.dart';
+
+import '../../generated/resolver_test.dart';
+import '../../reflective_tests.dart';
+import 'summary_common.dart';
+
+main() {
+  groupSep = ' | ';
+  runReflectiveTests(SummarizeElementsTest);
+}
+
+/**
+ * Override of [SummaryTest] which creates summaries from the element model.
+ */
+@reflectiveTest
+class SummarizeElementsTest extends ResolverTestCase with SummaryTest {
+  /**
+   * The list of absolute unit URIs corresponding to the compilation units in
+   * [unlinkedUnits].
+   */
+  List<String> unitUris;
+
+  /**
+   * Map containing all source files in this test, and their corresponding file
+   * contents.
+   */
+  final Map<Source, String> _fileContents = <Source, String>{};
+
+  @override
+  LinkedLibrary linked;
+
+  @override
+  List<UnlinkedUnit> unlinkedUnits;
+
+  @override
+  bool get checkAstDerivedData => false;
+
+  @override
+  bool get expectAbsoluteUrisInDependencies => true;
+
+  /**
+   * Determine the analysis options that should be used for this test.
+   */
+  AnalysisOptionsImpl get options =>
+      new AnalysisOptionsImpl()..enableGenericMethods = true;
+
+  @override
+  bool get skipFullyLinkedData => false;
+
+  @override
+  bool get strongMode => false;
+
+  @override
+  Source addNamedSource(String filePath, String contents) {
+    Source source = super.addNamedSource(filePath, contents);
+    _fileContents[source] = contents;
+    return source;
+  }
+
+  /**
+   * Serialize the library containing the given class [element], then
+   * deserialize it and return the summary of the class.
+   */
+  UnlinkedClass serializeClassElement(ClassElement element) {
+    serializeLibraryElement(element.library);
+    return findClass(element.name, failIfAbsent: true);
+  }
+
+  /**
+   * Serialize the given [library] element, then deserialize it and store the
+   * resulting summary in [linked] and [unlinkedUnits].
+   */
+  void serializeLibraryElement(LibraryElement library) {
+    summarize_elements.LibrarySerializationResult serializedLib =
+        summarize_elements.serializeLibrary(
+            library, typeProvider, analysisContext.analysisOptions.strongMode);
+    {
+      List<int> buffer = serializedLib.linked.toBuffer();
+      linked = new LinkedLibrary.fromBuffer(buffer);
+      validateLinkedLibrary(linked);
+    }
+    unlinkedUnits = serializedLib.unlinkedUnits.map((UnlinkedUnitBuilder b) {
+      List<int> buffer = b.toBuffer();
+      return new UnlinkedUnit.fromBuffer(buffer);
+    }).toList();
+    unitUris = serializedLib.unitUris;
+  }
+
+  @override
+  void serializeLibraryText(String text, {bool allowErrors: false}) {
+    Source source = addSource(text);
+    _fileContents[source] = text;
+    LibraryElement library = resolve2(source);
+    if (!allowErrors) {
+      assertNoErrors(source);
+    }
+    serializeLibraryElement(library);
+    expect(unlinkedUnits[0].imports.length, linked.importDependencies.length);
+    expect(linked.units.length, unlinkedUnits.length);
+    for (int i = 0; i < linked.units.length; i++) {
+      expect(unlinkedUnits[i].references.length,
+          lessThanOrEqualTo(linked.units[i].references.length));
+    }
+    verifyPublicNamespace();
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    resetWithOptions(options);
+  }
+
+  test_class_no_superclass() {
+    UnlinkedClass cls = serializeClassElement(typeProvider.objectType.element);
+    expect(cls.supertype, isNull);
+    expect(cls.hasNoSupertype, isTrue);
+  }
+
+  /**
+   * Verify that [public_namespace.computePublicNamespace] produces data that's
+   * equivalent to that produced by [summarize_elements.serializeLibrary].
+   */
+  void verifyPublicNamespace() {
+    for (int i = 0; i < unlinkedUnits.length; i++) {
+      Source source = analysisContext.sourceFactory.forUri(unitUris[i]);
+      String text = _fileContents[source];
+      if (text == null) {
+        if (!allowMissingFiles) {
+          fail('Could not find file while verifying public namespace: '
+              '${unitUris[i]}');
+        }
+      } else {
+        UnlinkedPublicNamespace namespace =
+            computePublicNamespaceFromText(text, source);
+        expect(canonicalize(namespace),
+            canonicalize(unlinkedUnits[i].publicNamespace),
+            reason: 'publicNamespace(${unitUris[i]})');
+      }
+    }
+  }
+}
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
new file mode 100644
index 0000000..9427cd6
--- /dev/null
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -0,0 +1,7451 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.summary.summary_common;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.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_engine_io.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/summary/base.dart';
+import 'package:analyzer/src/summary/idl.dart';
+import 'package:analyzer/src/summary/public_namespace_computer.dart'
+    as public_namespace;
+import 'package:analyzer/src/summary/summarize_elements.dart'
+    as summarize_elements;
+import 'package:unittest/unittest.dart';
+
+import '../../generated/resolver_test.dart';
+
+/**
+ * The public namespaces of the sdk are computed once so that we don't bog
+ * down the test.  Structured as a map from absolute URI to the corresponding
+ * public namespace.
+ *
+ * Note: should an exception occur during computation of this variable, it
+ * will silently be set to null to allow other tests to run.
+ */
+final Map<String, UnlinkedPublicNamespace> sdkPublicNamespace = () {
+  try {
+    AnalysisContext analysisContext = AnalysisContextFactory.contextWithCore();
+    Map<String, UnlinkedPublicNamespace> uriToNamespace =
+        <String, UnlinkedPublicNamespace>{};
+    List<LibraryElement> libraries = [
+      analysisContext.typeProvider.objectType.element.library,
+      analysisContext.typeProvider.futureType.element.library
+    ];
+    for (LibraryElement library in libraries) {
+      summarize_elements.LibrarySerializationResult serializedLibrary =
+          summarize_elements.serializeLibrary(
+              library, analysisContext.typeProvider, false);
+      for (int i = 0; i < serializedLibrary.unlinkedUnits.length; i++) {
+        uriToNamespace[serializedLibrary.unitUris[i]] =
+            new UnlinkedUnit.fromBuffer(
+                    serializedLibrary.unlinkedUnits[i].toBuffer())
+                .publicNamespace;
+      }
+    }
+    return uriToNamespace;
+  } catch (_) {
+    return null;
+  }
+}();
+
+/**
+ * Convert a summary object (or a portion of one) into a canonical form that
+ * can be easily compared using [expect].  If [orderByName] is true, and the
+ * object is a [List], it is sorted by the `name` field of its elements.
+ */
+Object canonicalize(Object obj, {bool orderByName: false}) {
+  if (obj is SummaryClass) {
+    Map<String, Object> result = <String, Object>{};
+    obj.toMap().forEach((String key, Object value) {
+      bool orderByName = false;
+      if (obj is UnlinkedPublicNamespace && key == 'names') {
+        orderByName = true;
+      }
+      result[key] = canonicalize(value, orderByName: orderByName);
+    });
+    return result;
+  } else if (obj is List) {
+    List<Object> result = <Object>[];
+    for (Object item in obj) {
+      result.add(canonicalize(item));
+    }
+    if (orderByName) {
+      result.sort((Object a, Object b) {
+        if (a is Map && b is Map) {
+          return Comparable.compare(a['name'], b['name']);
+        } else {
+          return 0;
+        }
+      });
+    }
+    return result;
+  } else if (obj is String || obj is num || obj is bool) {
+    return obj;
+  } else {
+    return obj.toString();
+  }
+}
+
+UnlinkedPublicNamespace computePublicNamespaceFromText(
+    String text, Source source) {
+  CharacterReader reader = new CharSequenceReader(text);
+  Scanner scanner =
+      new Scanner(source, reader, AnalysisErrorListener.NULL_LISTENER);
+  Parser parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER);
+  parser.parseGenericMethods = true;
+  CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
+  UnlinkedPublicNamespace namespace = new UnlinkedPublicNamespace.fromBuffer(
+      public_namespace.computePublicNamespace(unit).toBuffer());
+  return namespace;
+}
+
+/**
+ * Type of a function that validates an [EntityRef].
+ */
+typedef void _EntityRefValidator(EntityRef entityRef);
+
+/**
+ * Base class containing most summary tests.  This allows summary tests to be
+ * re-used to exercise all the different ways in which summaries can be
+ * generated (e.g. direct from the AST, from the element model, from a
+ * "relinking" process, etc.)
+ */
+abstract class SummaryTest {
+  /**
+   * A test will set this to `true` if it contains `import`, `export`, or
+   * `part` declarations that deliberately refer to non-existent files.
+   */
+  bool allowMissingFiles = false;
+
+  /**
+   * `true` if the summary was created directly from the AST (and hence
+   * contains information that is not obtainable from the element model alone).
+   * TODO(paulberry): modify the element model so that it contains all the data
+   * that summaries need, so that this flag is no longer needed.
+   */
+  bool get checkAstDerivedData;
+
+  /**
+   * Get access to the linked defining compilation unit.
+   */
+  LinkedUnit get definingUnit => linked.units[0];
+
+  /**
+   * `true` if the linked portion of the summary is expected to contain
+   * absolute URIs.  This happens because the element model doesn't (yet) store
+   * enough information to recover relative URIs, TODO(paulberry): fix this.
+   */
+  bool get expectAbsoluteUrisInDependencies;
+
+  /**
+   * Get access to the linked summary that results from serializing and
+   * then deserializing the library under test.
+   */
+  LinkedLibrary get linked;
+
+  /**
+   * `true` if the linked portion of the summary only contains prelinked data.
+   * This happens because we don't yet have a full linker; only a prelinker.
+   */
+  bool get skipFullyLinkedData;
+
+  /**
+   * `true` if the linked portion of the summary contains the result of strong
+   * mode analysis.
+   */
+  bool get strongMode;
+
+  /**
+   * Get access to the unlinked compilation unit summaries that result from
+   * serializing and deserializing the library under test.
+   */
+  List<UnlinkedUnit> get unlinkedUnits;
+
+  /**
+   * Convert [path] to a suitably formatted absolute path URI for the current
+   * platform.
+   */
+  String absUri(String path) {
+    return FileUtilities2.createFile(path).toURI().toString();
+  }
+
+  /**
+   * Add the given source file so that it may be referenced by the file under
+   * test.
+   */
+  Source addNamedSource(String filePath, String contents);
+
+  /**
+   * Check that [annotations] contains a single entry which is a reference to
+   * a top level variable called `a` in the current library.
+   */
+  void checkAnnotationA(List<UnlinkedConst> annotations) {
+    expect(annotations, hasLength(1));
+    _assertUnlinkedConst(annotations[0], operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'a',
+          expectedKind: ReferenceKind.topLevelPropertyAccessor)
+    ]);
+  }
+
+  /**
+   * Verify that the [dependency]th element of the dependency table represents
+   * a file reachable via the given [absoluteUri] and [relativeUri].
+   */
+  void checkDependency(int dependency, String absoluteUri, String relativeUri) {
+    if (expectAbsoluteUrisInDependencies) {
+      // The element model doesn't (yet) store enough information to recover
+      // relative URIs, so we have to use the absolute URI.
+      // TODO(paulberry): fix this.
+      relativeUri = absoluteUri;
+    }
+    expect(dependency, new isInstanceOf<int>());
+    expect(linked.dependencies[dependency].uri, relativeUri);
+  }
+
+  /**
+   * Verify that the given [dependency] lists the given [absoluteUris] or
+   * [relativeUris] as its parts.
+   */
+  void checkDependencyParts(LinkedDependency dependency,
+      List<String> absoluteUris, List<String> relativeUris) {
+    if (expectAbsoluteUrisInDependencies) {
+      // The element model doesn't (yet) store enough information to recover
+      // relative URIs, so we have to use the absolute URI.
+      // TODO(paulberry): fix this.
+      relativeUris = absoluteUris;
+    }
+    expect(dependency.parts, relativeUris);
+  }
+
+  /**
+   * Check that the given [documentationComment] matches the first
+   * Javadoc-style comment found in [text].
+   *
+   * Note that the algorithm for finding the Javadoc-style comment in [text] is
+   * a simple-minded text search; it is easily confused by corner cases such as
+   * strings containing comments, nested comments, etc.
+   */
+  void checkDocumentationComment(
+      UnlinkedDocumentationComment documentationComment, String text) {
+    expect(documentationComment, isNotNull);
+    int commentStart = text.indexOf('/*');
+    expect(commentStart, isNot(-1));
+    int commentEnd = text.indexOf('*/');
+    expect(commentEnd, isNot(-1));
+    commentEnd += 2;
+    String expectedCommentText =
+        text.substring(commentStart, commentEnd).replaceAll('\r\n', '\n');
+    expect(documentationComment.text, expectedCommentText);
+    expect(documentationComment.offset, commentStart);
+    expect(documentationComment.length, commentEnd - commentStart);
+  }
+
+  /**
+   * Verify that the given [typeRef] represents the type `dynamic`.
+   */
+  void checkDynamicTypeRef(EntityRef typeRef) {
+    checkTypeRef(typeRef, null, null, 'dynamic');
+  }
+
+  /**
+   * Verify that the given [exportName] represents a reference to an entity
+   * declared in a file reachable via [absoluteUri] and [relativeUri], having
+   * name [expectedName].  [expectedKind] is the kind of object referenced.
+   * [expectedTargetUnit] is the index of the compilation unit in which the
+   * target of the [exportName] is expected to appear; if not specified it is
+   * assumed to be the defining compilation unit.
+   */
+  void checkExportName(LinkedExportName exportName, String absoluteUri,
+      String relativeUri, String expectedName, ReferenceKind expectedKind,
+      {int expectedTargetUnit: 0}) {
+    expect(exportName, new isInstanceOf<LinkedExportName>());
+    // Exported names must come from other libraries.
+    expect(exportName.dependency, isNot(0));
+    checkDependency(exportName.dependency, absoluteUri, relativeUri);
+    expect(exportName.name, expectedName);
+    expect(exportName.kind, expectedKind);
+    expect(exportName.unit, expectedTargetUnit);
+  }
+
+  /**
+   * Verify that the dependency table contains an entry for a file reachable
+   * via the given [absoluteUri] and [relativeUri].  If [fullyLinked] is
+   * `true`, then the dependency should be a fully-linked dependency; otherwise
+   * it should be a prelinked dependency.
+   *
+   * The index of the [LinkedDependency] is returned.
+   */
+  int checkHasDependency(String absoluteUri, String relativeUri,
+      {bool fullyLinked: false}) {
+    if (expectAbsoluteUrisInDependencies) {
+      // The element model doesn't (yet) store enough information to recover
+      // relative URIs, so we have to use the absolute URI.
+      // TODO(paulberry): fix this.
+      relativeUri = absoluteUri;
+    }
+    List<String> found = <String>[];
+    for (int i = 0; i < linked.dependencies.length; i++) {
+      LinkedDependency dep = linked.dependencies[i];
+      if (dep.uri == relativeUri) {
+        if (fullyLinked) {
+          expect(i, greaterThanOrEqualTo(linked.numPrelinkedDependencies));
+        } else {
+          expect(i, lessThan(linked.numPrelinkedDependencies));
+        }
+        return i;
+      }
+      found.add(dep.uri);
+    }
+    fail('Did not find dependency $relativeUri.  Found: $found');
+    return null;
+  }
+
+  /**
+   * Test an inferred type.  If [onlyInStrongMode] is `true` (the default) and
+   * strong mode is disabled, verify that the given [slotId] exists and has no
+   * associated type.  Otherwise, behave as in [checkLinkedTypeSlot].
+   */
+  void checkInferredTypeSlot(
+      int slotId, String absoluteUri, String relativeUri, String expectedName,
+      {bool allowTypeParameters: false,
+      ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+      int expectedTargetUnit: 0,
+      LinkedUnit linkedSourceUnit,
+      UnlinkedUnit unlinkedSourceUnit,
+      int numTypeParameters: 0,
+      bool onlyInStrongMode: true}) {
+    if (strongMode || !onlyInStrongMode) {
+      checkLinkedTypeSlot(slotId, absoluteUri, relativeUri, expectedName,
+          allowTypeArguments: allowTypeParameters,
+          expectedKind: expectedKind,
+          expectedTargetUnit: expectedTargetUnit,
+          linkedSourceUnit: linkedSourceUnit,
+          unlinkedSourceUnit: unlinkedSourceUnit,
+          numTypeParameters: numTypeParameters);
+    } else {
+      // A slot id should have been assigned but it should not be associated
+      // with any type.
+      expect(slotId, isNot(0));
+      expect(getTypeRefForSlot(slotId, linkedSourceUnit: linkedSourceUnit),
+          isNull);
+    }
+  }
+
+  /**
+   * Verify that the dependency table *does not* contain any entries for a file
+   * reachable via the given [absoluteUri] and [relativeUri].
+   */
+  void checkLacksDependency(String absoluteUri, String relativeUri) {
+    if (expectAbsoluteUrisInDependencies) {
+      // The element model doesn't (yet) store enough information to recover
+      // relative URIs, so we have to use the absolute URI.
+      // TODO(paulberry): fix this.
+      relativeUri = absoluteUri;
+    }
+    for (LinkedDependency dep in linked.dependencies) {
+      if (dep.uri == relativeUri) {
+        fail('Unexpected dependency found: $relativeUri');
+      }
+    }
+  }
+
+  /**
+   * Verify that the given [typeRef] represents a reference to a type declared
+   * in a file reachable via [absoluteUri] and [relativeUri], having name
+   * [expectedName].  If [allowTypeArguments] is true, allow the type
+   * reference to supply type arguments.  [expectedKind] is the kind of object
+   * referenced.  [linkedSourceUnit] and [unlinkedSourceUnit] refer to the
+   * compilation unit within which the [typeRef] appears; if not specified they
+   * are assumed to refer to the defining compilation unit.
+   * [expectedTargetUnit] is the index of the compilation unit in which the
+   * target of the [typeRef] is expected to appear; if not specified it is
+   * assumed to be the defining compilation unit.  [numTypeParameters] is the
+   * number of type parameters of the thing being referred to.
+   */
+  void checkLinkedTypeRef(EntityRef typeRef, String absoluteUri,
+      String relativeUri, String expectedName,
+      {bool allowTypeArguments: false,
+      ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+      int expectedTargetUnit: 0,
+      LinkedUnit linkedSourceUnit,
+      UnlinkedUnit unlinkedSourceUnit,
+      int numTypeParameters: 0}) {
+    linkedSourceUnit ??= definingUnit;
+    expect(typeRef, isNotNull,
+        reason: 'No entry in linkedSourceUnit.types matching slotId');
+    expect(typeRef.paramReference, 0);
+    int index = typeRef.reference;
+    if (!allowTypeArguments) {
+      expect(typeRef.typeArguments, isEmpty);
+    }
+    checkReferenceIndex(index, absoluteUri, relativeUri, expectedName,
+        expectedKind: expectedKind,
+        expectedTargetUnit: expectedTargetUnit,
+        linkedSourceUnit: linkedSourceUnit,
+        unlinkedSourceUnit: unlinkedSourceUnit,
+        numTypeParameters: numTypeParameters);
+  }
+
+  /**
+   * Verify that the given [slotId] represents a reference to a type declared
+   * in a file reachable via [absoluteUri] and [relativeUri], having name
+   * [expectedName].  If [allowTypeArguments] is true, allow the type
+   * reference to supply type arguments.  [expectedKind] is the kind of object
+   * referenced.  [linkedSourceUnit] and [unlinkedSourceUnit] refer to the
+   * compilation unit within which the [typeRef] appears; if not specified they
+   * are assumed to refer to the defining compilation unit.
+   * [expectedTargetUnit] is the index of the compilation unit in which the
+   * target of the [typeRef] is expected to appear; if not specified it is
+   * assumed to be the defining compilation unit.  [numTypeParameters] is the
+   * number of type parameters of the thing being referred to.
+   */
+  void checkLinkedTypeSlot(
+      int slotId, String absoluteUri, String relativeUri, String expectedName,
+      {bool allowTypeArguments: false,
+      ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+      int expectedTargetUnit: 0,
+      LinkedUnit linkedSourceUnit,
+      UnlinkedUnit unlinkedSourceUnit,
+      int numTypeParameters: 0}) {
+    // Slot ids should be nonzero, since zero means "no associated slot".
+    expect(slotId, isNot(0));
+    if (skipFullyLinkedData) {
+      return;
+    }
+    linkedSourceUnit ??= definingUnit;
+    checkLinkedTypeRef(
+        getTypeRefForSlot(slotId, linkedSourceUnit: linkedSourceUnit),
+        absoluteUri,
+        relativeUri,
+        expectedName,
+        allowTypeArguments: allowTypeArguments,
+        expectedKind: expectedKind,
+        expectedTargetUnit: expectedTargetUnit,
+        linkedSourceUnit: linkedSourceUnit,
+        unlinkedSourceUnit: unlinkedSourceUnit,
+        numTypeParameters: numTypeParameters);
+  }
+
+  /**
+   * Verify that the given [typeRef] represents a reference to a type parameter
+   * having the given [deBruijnIndex].
+   */
+  void checkParamTypeRef(EntityRef typeRef, int deBruijnIndex) {
+    expect(typeRef, new isInstanceOf<EntityRef>());
+    expect(typeRef.reference, 0);
+    expect(typeRef.typeArguments, isEmpty);
+    expect(typeRef.paramReference, deBruijnIndex);
+  }
+
+  /**
+   * Verify that [prefixReference] is a valid reference to a prefix having the
+   * given [name].
+   */
+  void checkPrefix(int prefixReference, String name) {
+    expect(prefixReference, isNot(0));
+    expect(unlinkedUnits[0].references[prefixReference].prefixReference, 0);
+    expect(unlinkedUnits[0].references[prefixReference].name, name);
+    expect(definingUnit.references[prefixReference].dependency, 0);
+    expect(definingUnit.references[prefixReference].kind, ReferenceKind.prefix);
+    expect(definingUnit.references[prefixReference].unit, 0);
+  }
+
+  /**
+   * Check the data structures that are reachable from an index in the
+   * references table..  If the reference in question is an explicit
+   * reference, return the [UnlinkedReference] that is used to make the
+   * explicit reference.  If the type reference in question is an implicit
+   * reference, return `null`.
+   *
+   * TODO(scheglov) remove [checkAstDerivedDataOverride] once elements-based
+   * serializer can record unresolved information.
+   */
+  UnlinkedReference checkReferenceIndex(int referenceIndex, String absoluteUri,
+      String relativeUri, String expectedName,
+      {ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+      int expectedTargetUnit: 0,
+      LinkedUnit linkedSourceUnit,
+      UnlinkedUnit unlinkedSourceUnit,
+      int numTypeParameters: 0,
+      bool checkAstDerivedDataOverride: false,
+      int localIndex: 0}) {
+    linkedSourceUnit ??= definingUnit;
+    unlinkedSourceUnit ??= unlinkedUnits[0];
+    LinkedReference referenceResolution =
+        linkedSourceUnit.references[referenceIndex];
+    String name;
+    UnlinkedReference reference;
+    if (referenceIndex < unlinkedSourceUnit.references.length) {
+      // This is an explicit reference, so its name and prefix should be in
+      // [UnlinkedUnit.references].
+      expect(referenceResolution.name, isEmpty);
+      reference = unlinkedSourceUnit.references[referenceIndex];
+      name = reference.name;
+      if (reference.prefixReference != 0) {
+        // Prefixes should appear in the references table before any reference
+        // that uses them.
+        expect(reference.prefixReference, lessThan(referenceIndex));
+      }
+    } else {
+      // This is an implicit reference, so its name should be in
+      // [LinkedUnit.references].
+      name = referenceResolution.name;
+    }
+    // Index 0 is reserved.
+    expect(referenceIndex, isNot(0));
+    if (absoluteUri == null) {
+      expect(referenceResolution.dependency, 0);
+    } else {
+      checkDependency(referenceResolution.dependency, absoluteUri, relativeUri);
+    }
+    if (expectedKind == ReferenceKind.unresolved &&
+        !checkAstDerivedData &&
+        !checkAstDerivedDataOverride) {
+      // summarize_elements.dart isn't yet able to record the name of
+      // unresolved references.  TODO(paulberry): fix this.
+      expect(name, '*unresolved*');
+    } else {
+      if (expectedName == null) {
+        expect(name, isEmpty);
+      } else {
+        expect(name, expectedName);
+      }
+    }
+    expect(referenceResolution.kind, expectedKind);
+    expect(referenceResolution.unit, expectedTargetUnit);
+    expect(referenceResolution.numTypeParameters, numTypeParameters);
+    expect(referenceResolution.localIndex, localIndex);
+    return reference;
+  }
+
+  /**
+   * Verify that the given [typeRef] represents a reference to a type declared
+   * in a file reachable via [absoluteUri] and [relativeUri], having name
+   * [expectedName].  If [expectedPrefix] is supplied, verify that the type is
+   * reached via the given prefix.  If [allowTypeParameters] is true, allow the
+   * type reference to supply type parameters.  [expectedKind] is the kind of
+   * object referenced.  [linkedSourceUnit] and [unlinkedSourceUnit] refer
+   * to the compilation unit within which the [typeRef] appears; if not
+   * specified they are assumed to refer to the defining compilation unit.
+   * [expectedTargetUnit] is the index of the compilation unit in which the
+   * target of the [typeRef] is expected to appear; if not specified it is
+   * assumed to be the defining compilation unit.  [numTypeParameters] is the
+   * number of type parameters of the thing being referred to.
+   *
+   * TODO(scheglov) remove [checkAstDerivedDataOverride] once elements-based
+   * serializer can record unresolved information.
+   */
+  void checkTypeRef(EntityRef typeRef, String absoluteUri, String relativeUri,
+      String expectedName,
+      {String expectedPrefix,
+      List<_PrefixExpectation> prefixExpectations,
+      bool allowTypeParameters: false,
+      ReferenceKind expectedKind: ReferenceKind.classOrEnum,
+      int expectedTargetUnit: 0,
+      LinkedUnit linkedSourceUnit,
+      UnlinkedUnit unlinkedSourceUnit,
+      int numTypeParameters: 0,
+      bool checkAstDerivedDataOverride: false}) {
+    linkedSourceUnit ??= definingUnit;
+    expect(typeRef, new isInstanceOf<EntityRef>());
+    expect(typeRef.paramReference, 0);
+    int index = typeRef.reference;
+    if (!allowTypeParameters) {
+      expect(typeRef.typeArguments, isEmpty);
+    }
+    UnlinkedReference reference = checkReferenceIndex(
+        index, absoluteUri, relativeUri, expectedName,
+        expectedKind: expectedKind,
+        expectedTargetUnit: expectedTargetUnit,
+        linkedSourceUnit: linkedSourceUnit,
+        unlinkedSourceUnit: unlinkedSourceUnit,
+        numTypeParameters: numTypeParameters,
+        checkAstDerivedDataOverride: checkAstDerivedDataOverride);
+    expect(reference, isNotNull,
+        reason: 'Unlinked type refs must refer to an explicit reference');
+    if (expectedKind == ReferenceKind.unresolved &&
+        !checkAstDerivedData &&
+        !checkAstDerivedDataOverride) {
+      // summarize_elements.dart isn't yet able to record the prefix of
+      // unresolved references.  TODO(paulberry): fix this.
+      expect(reference.prefixReference, 0);
+    } else if (expectedPrefix != null) {
+      checkPrefix(reference.prefixReference, expectedPrefix);
+    } else if (prefixExpectations != null) {
+      for (_PrefixExpectation expectation in prefixExpectations) {
+        expect(reference.prefixReference, isNot(0));
+        reference = checkReferenceIndex(reference.prefixReference,
+            expectation.absoluteUri, expectation.relativeUri, expectation.name,
+            expectedKind: expectation.kind,
+            checkAstDerivedDataOverride: checkAstDerivedDataOverride,
+            expectedTargetUnit: expectedTargetUnit,
+            linkedSourceUnit: linkedSourceUnit,
+            unlinkedSourceUnit: unlinkedSourceUnit,
+            numTypeParameters: expectation.numTypeParameters);
+      }
+      expect(reference.prefixReference, 0);
+    } else {
+      expect(reference.prefixReference, 0);
+    }
+  }
+
+  /**
+   * Verify that the given [typeRef] represents a reference to an unresolved
+   * type.
+   */
+  void checkUnresolvedTypeRef(
+      EntityRef typeRef, String expectedPrefix, String expectedName,
+      {LinkedUnit linkedSourceUnit, UnlinkedUnit unlinkedSourceUnit}) {
+    // When serializing from the element model, unresolved type refs lose their
+    // name.
+    checkTypeRef(typeRef, null, null, checkAstDerivedData ? expectedName : null,
+        expectedPrefix: expectedPrefix,
+        expectedKind: ReferenceKind.unresolved,
+        linkedSourceUnit: linkedSourceUnit,
+        unlinkedSourceUnit: unlinkedSourceUnit);
+  }
+
+  /**
+   * Verify that the given [typeRef] represents the type `void`.
+   */
+  void checkVoidTypeRef(EntityRef typeRef) {
+    checkTypeRef(typeRef, null, null, 'void');
+  }
+
+  /**
+   * Find the class with the given [className] in the summary, and return its
+   * [UnlinkedClass] data structure.  If [unit] is not given, the class is
+   * looked for in the defining compilation unit.
+   */
+  UnlinkedClass findClass(String className,
+      {bool failIfAbsent: false, UnlinkedUnit unit}) {
+    unit ??= unlinkedUnits[0];
+    UnlinkedClass result;
+    for (UnlinkedClass cls in unit.classes) {
+      if (cls.name == className) {
+        if (result != null) {
+          fail('Duplicate class $className');
+        }
+        result = cls;
+      }
+    }
+    if (result == null && failIfAbsent) {
+      fail('Class $className not found in serialized output');
+    }
+    return result;
+  }
+
+  /**
+   * Find the enum with the given [enumName] in the summary, and return its
+   * [UnlinkedEnum] data structure.  If [unit] is not given, the enum is looked
+   * for in the defining compilation unit.
+   */
+  UnlinkedEnum findEnum(String enumName,
+      {bool failIfAbsent: false, UnlinkedUnit unit}) {
+    unit ??= unlinkedUnits[0];
+    UnlinkedEnum result;
+    for (UnlinkedEnum e in unit.enums) {
+      if (e.name == enumName) {
+        if (result != null) {
+          fail('Duplicate enum $enumName');
+        }
+        result = e;
+      }
+    }
+    if (result == null && failIfAbsent) {
+      fail('Enum $enumName not found in serialized output');
+    }
+    return result;
+  }
+
+  /**
+   * Find the executable with the given [executableName] in the summary, and
+   * return its [UnlinkedExecutable] data structure.  If [executables] is not
+   * given, then the executable is searched for in the defining compilation
+   * unit.
+   */
+  UnlinkedExecutable findExecutable(String executableName,
+      {List<UnlinkedExecutable> executables, bool failIfAbsent: false}) {
+    executables ??= unlinkedUnits[0].executables;
+    UnlinkedExecutable result;
+    for (UnlinkedExecutable executable in executables) {
+      if (executable.name == executableName) {
+        if (result != null) {
+          fail('Duplicate executable $executableName');
+        }
+        result = executable;
+      }
+    }
+    if (result == null && failIfAbsent) {
+      fail('Executable $executableName not found in serialized output');
+    }
+    return result;
+  }
+
+  /**
+   * Find the typedef with the given [typedefName] in the summary, and return
+   * its [UnlinkedTypedef] data structure.  If [unit] is not given, the typedef
+   * is looked for in the defining compilation unit.
+   */
+  UnlinkedTypedef findTypedef(String typedefName,
+      {bool failIfAbsent: false, UnlinkedUnit unit}) {
+    unit ??= unlinkedUnits[0];
+    UnlinkedTypedef result;
+    for (UnlinkedTypedef type in unit.typedefs) {
+      if (type.name == typedefName) {
+        if (result != null) {
+          fail('Duplicate typedef $typedefName');
+        }
+        result = type;
+      }
+    }
+    if (result == null && failIfAbsent) {
+      fail('Typedef $typedefName not found in serialized output');
+    }
+    return result;
+  }
+
+  /**
+   * Find the top level variable with the given [variableName] in the summary,
+   * and return its [UnlinkedVariable] data structure.  If [variables] is not
+   * specified, the variable is looked for in the defining compilation unit.
+   */
+  UnlinkedVariable findVariable(String variableName,
+      {List<UnlinkedVariable> variables, bool failIfAbsent: false}) {
+    variables ??= unlinkedUnits[0].variables;
+    UnlinkedVariable result;
+    for (UnlinkedVariable variable in variables) {
+      if (variable.name == variableName) {
+        if (result != null) {
+          fail('Duplicate variable $variableName');
+        }
+        result = variable;
+      }
+    }
+    if (result == null && failIfAbsent) {
+      fail('Variable $variableName not found in serialized output');
+    }
+    return result;
+  }
+
+  /**
+   * Find the entry in [linkedSourceUnit.types] matching [slotId].
+   */
+  EntityRef getTypeRefForSlot(int slotId, {LinkedUnit linkedSourceUnit}) {
+    linkedSourceUnit ??= definingUnit;
+    for (EntityRef typeRef in linkedSourceUnit.types) {
+      if (typeRef.slot == slotId) {
+        return typeRef;
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Serialize the given library [text] and return the summary of the class
+   * with the given [className].
+   */
+  UnlinkedClass serializeClassText(String text,
+      {String className: 'C', bool allowErrors: false}) {
+    serializeLibraryText(text, allowErrors: allowErrors);
+    return findClass(className, failIfAbsent: true);
+  }
+
+  /**
+   * Serialize the given library [text] and return the summary of the enum with
+   * the given [enumName].
+   */
+  UnlinkedEnum serializeEnumText(String text, [String enumName = 'E']) {
+    serializeLibraryText(text);
+    return findEnum(enumName, failIfAbsent: true);
+  }
+
+  /**
+   * Serialize the given library [text] and return the summary of the
+   * executable with the given [executableName].
+   */
+  UnlinkedExecutable serializeExecutableText(String text,
+      {String executableName: 'f', bool allowErrors: false}) {
+    serializeLibraryText(text, allowErrors: allowErrors);
+    return findExecutable(executableName, failIfAbsent: true);
+  }
+
+  /**
+   * Serialize the given library [text], then deserialize it and store its
+   * summary in [lib].
+   */
+  void serializeLibraryText(String text, {bool allowErrors: false});
+
+  /**
+   * Serialize the given method [text] and return the summary of the executable
+   * with the given [executableName].
+   */
+  UnlinkedExecutable serializeMethodText(String text,
+      [String executableName = 'f']) {
+    serializeLibraryText('class C { $text }');
+    return findExecutable(executableName,
+        executables: findClass('C', failIfAbsent: true).executables,
+        failIfAbsent: true);
+  }
+
+  /**
+   * Serialize the given library [text] and return the summary of the typedef
+   * with the given [typedefName].
+   */
+  UnlinkedTypedef serializeTypedefText(String text,
+      [String typedefName = 'F']) {
+    serializeLibraryText(text);
+    return findTypedef(typedefName, failIfAbsent: true);
+  }
+
+  /**
+   * Serialize a type declaration using the given [text] as a type name, and
+   * return a summary of the corresponding [EntityRef].  If the type
+   * declaration needs to refer to types that are not available in core, those
+   * types may be declared in [otherDeclarations].
+   */
+  EntityRef serializeTypeText(String text,
+      {String otherDeclarations: '', bool allowErrors: false}) {
+    return serializeVariableText('$otherDeclarations\n$text v;',
+            allowErrors: allowErrors)
+        .type;
+  }
+
+  /**
+   * Serialize the given library [text] and return the summary of the variable
+   * with the given [variableName].
+   */
+  UnlinkedVariable serializeVariableText(String text,
+      {String variableName: 'v', bool allowErrors: false}) {
+    serializeLibraryText(text, allowErrors: allowErrors);
+    return findVariable(variableName, failIfAbsent: true);
+  }
+
+  test_bottom_reference_shared() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    // The synthetic executables for both `x` and `y` have type `() => `Bottom`.
+    // Verify that they both use the same reference to `Bottom`.
+    serializeLibraryText('int x = null; int y = null;');
+    EntityRef xInitializerReturnType =
+        getTypeRefForSlot(findVariable('x').initializer.inferredReturnTypeSlot);
+    EntityRef yInitializerReturnType =
+        getTypeRefForSlot(findVariable('y').initializer.inferredReturnTypeSlot);
+    expect(xInitializerReturnType.reference, yInitializerReturnType.reference);
+  }
+
+  test_cascaded_export_hide_hide() {
+    addNamedSource('/lib1.dart', 'export "lib2.dart" hide C hide B, C;');
+    addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
+    serializeLibraryText(
+        '''
+import 'lib1.dart';
+A a;
+B b;
+C c;
+    ''',
+        allowErrors: true);
+    checkTypeRef(
+        findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
+    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+  }
+
+  test_cascaded_export_hide_show() {
+    addNamedSource('/lib1.dart', 'export "lib2.dart" hide C show A, C;');
+    addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
+    serializeLibraryText(
+        '''
+import 'lib1.dart';
+A a;
+B b;
+C c;
+    ''',
+        allowErrors: true);
+    checkTypeRef(
+        findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
+    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+  }
+
+  test_cascaded_export_show_hide() {
+    addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B hide B, C;');
+    addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
+    serializeLibraryText(
+        '''
+import 'lib1.dart';
+A a;
+B b;
+C c;
+    ''',
+        allowErrors: true);
+    checkTypeRef(
+        findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
+    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+  }
+
+  test_cascaded_export_show_show() {
+    addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B show A, C;');
+    addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
+    serializeLibraryText(
+        '''
+import 'lib1.dart';
+A a;
+B b;
+C c;
+    ''',
+        allowErrors: true);
+    checkTypeRef(
+        findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
+    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+  }
+
+  test_cascaded_import_hide_hide() {
+    addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
+    serializeLibraryText(
+        '''
+import 'lib.dart' hide C hide B, C;
+A a;
+B b;
+C c;
+    ''',
+        allowErrors: true);
+    checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
+    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+  }
+
+  test_cascaded_import_hide_show() {
+    addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
+    serializeLibraryText(
+        '''
+import 'lib.dart' hide C show A, C;
+A a;
+B b;
+C c;
+    ''',
+        allowErrors: true);
+    checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
+    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+  }
+
+  test_cascaded_import_show_hide() {
+    addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
+    serializeLibraryText(
+        '''
+import 'lib.dart' show A, B hide B, C;
+A a;
+B b;
+C c;
+    ''',
+        allowErrors: true);
+    checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
+    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+  }
+
+  test_cascaded_import_show_show() {
+    addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
+    serializeLibraryText(
+        '''
+import 'lib.dart' show A, B show A, C;
+A a;
+B b;
+C c;
+    ''',
+        allowErrors: true);
+    checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
+    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
+    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
+  }
+
+  test_class_abstract() {
+    UnlinkedClass cls = serializeClassText('abstract class C {}');
+    expect(cls.isAbstract, true);
+  }
+
+  test_class_alias_abstract() {
+    UnlinkedClass cls = serializeClassText(
+        'abstract class C = D with E; class D {} class E {}');
+    expect(cls.isAbstract, true);
+  }
+
+  test_class_alias_concrete() {
+    UnlinkedClass cls =
+        serializeClassText('class C = _D with _E; class _D {} class _E {}');
+    expect(cls.isAbstract, false);
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+        ReferenceKind.classOrEnum);
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+  }
+
+  test_class_alias_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+class C = D with E;
+
+class D {}
+class E {}''';
+    UnlinkedClass cls = serializeClassText(text);
+    expect(cls.documentationComment, isNotNull);
+    checkDocumentationComment(cls.documentationComment, text);
+  }
+
+  test_class_alias_flag() {
+    UnlinkedClass cls =
+        serializeClassText('class C = D with E; class D {} class E {}');
+    expect(cls.isMixinApplication, true);
+  }
+
+  test_class_alias_generic() {
+    serializeClassText('class C<A, B> = _D with _E; class _D {} class _E {}');
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 2);
+  }
+
+  test_class_alias_mixin_order() {
+    UnlinkedClass cls = serializeClassText('''
+class C = D with E, F;
+class D {}
+class E {}
+class F {}
+''');
+    expect(cls.mixins, hasLength(2));
+    checkTypeRef(cls.mixins[0], null, null, 'E');
+    checkTypeRef(cls.mixins[1], null, null, 'F');
+  }
+
+  test_class_alias_no_implicit_constructors() {
+    UnlinkedClass cls = serializeClassText('''
+class C = D with E;
+class D {
+  D.foo();
+  D.bar();
+}
+class E {}
+''');
+    expect(cls.executables, isEmpty);
+  }
+
+  test_class_alias_private() {
+    serializeClassText('class _C = _D with _E; class _D {} class _E {}',
+        className: '_C');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+  }
+
+  test_class_alias_reference_generic() {
+    EntityRef typeRef = serializeTypeText('C',
+        otherDeclarations: 'class C<D, E> = F with G; class F {} class G {}');
+    checkTypeRef(typeRef, null, null, 'C', numTypeParameters: 2);
+  }
+
+  test_class_alias_reference_generic_imported() {
+    addNamedSource(
+        '/lib.dart', 'class C<D, E> = F with G; class F {} class G {}');
+    EntityRef typeRef =
+        serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
+    checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'C',
+        numTypeParameters: 2);
+  }
+
+  test_class_alias_supertype() {
+    UnlinkedClass cls =
+        serializeClassText('class C = D with E; class D {} class E {}');
+    checkTypeRef(cls.supertype, null, null, 'D');
+    expect(cls.hasNoSupertype, isFalse);
+  }
+
+  test_class_concrete() {
+    UnlinkedClass cls = serializeClassText('class C {}');
+    expect(cls.isAbstract, false);
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+        ReferenceKind.classOrEnum);
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+  }
+
+  test_class_constMembers() {
+    UnlinkedClass cls = serializeClassText('''
+class C {
+  int fieldInstance = 0;
+  final int fieldInstanceFinal = 0;
+  static int fieldStatic = 0;
+  static final int fieldStaticFinal = 0;
+  static const int fieldStaticConst = 0;
+  static const int _fieldStaticConstPrivate = 0;
+  static void methodStaticPublic() {}
+  static void _methodStaticPrivate() {}
+  void methodInstancePublic() {}
+  C operator+(C c) => null;
+}
+''');
+    expect(cls.isAbstract, false);
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    UnlinkedPublicName className = unlinkedUnits[0].publicNamespace.names[0];
+    expect(className.kind, ReferenceKind.classOrEnum);
+    expect(className.name, 'C');
+    expect(className.numTypeParameters, 0);
+    // executables
+    Map<String, UnlinkedPublicName> executablesMap =
+        <String, UnlinkedPublicName>{};
+    className.members.forEach((e) => executablesMap[e.name] = e);
+    expect(executablesMap, hasLength(2));
+    {
+      UnlinkedPublicName executable = executablesMap['fieldStaticConst'];
+      expect(executable.kind, ReferenceKind.propertyAccessor);
+      expect(executable.members, isEmpty);
+    }
+    {
+      UnlinkedPublicName executable = executablesMap['methodStaticPublic'];
+      expect(executable.kind, ReferenceKind.method);
+      expect(executable.members, isEmpty);
+    }
+  }
+
+  test_class_constMembers_constructors() {
+    UnlinkedClass cls = serializeClassText('''
+class C {
+  const C();
+  const C.constructorNamedPublicConst();
+  C.constructorNamedPublic();
+  C._constructorNamedPrivate();
+}
+''');
+    expect(cls.isAbstract, false);
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    UnlinkedPublicName className = unlinkedUnits[0].publicNamespace.names[0];
+    expect(className.kind, ReferenceKind.classOrEnum);
+    expect(className.name, 'C');
+    expect(className.numTypeParameters, 0);
+    // executables
+    Map<String, UnlinkedPublicName> executablesMap =
+        <String, UnlinkedPublicName>{};
+    className.members.forEach((e) => executablesMap[e.name] = e);
+    expect(executablesMap, hasLength(2));
+    {
+      UnlinkedPublicName executable =
+          executablesMap['constructorNamedPublicConst'];
+      expect(executable.kind, ReferenceKind.constructor);
+      expect(executable.members, isEmpty);
+    }
+    {
+      UnlinkedPublicName executable = executablesMap['constructorNamedPublic'];
+      expect(executable.kind, ReferenceKind.constructor);
+      expect(executable.members, isEmpty);
+    }
+  }
+
+  test_class_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+class C {}''';
+    UnlinkedClass cls = serializeClassText(text);
+    expect(cls.documentationComment, isNotNull);
+    checkDocumentationComment(cls.documentationComment, text);
+  }
+
+  test_class_documented_with_references() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs referring to [D] and [E]
+ */
+class C {}
+
+class D {}
+class E {}''';
+    UnlinkedClass cls = serializeClassText(text);
+    expect(cls.documentationComment, isNotNull);
+    checkDocumentationComment(cls.documentationComment, text);
+  }
+
+  test_class_documented_with_with_windows_line_endings() {
+    String text = '/**\r\n * Docs\r\n */\r\nclass C {}';
+    UnlinkedClass cls = serializeClassText(text);
+    expect(cls.documentationComment, isNotNull);
+    checkDocumentationComment(cls.documentationComment, text);
+  }
+
+  test_class_interface() {
+    UnlinkedClass cls = serializeClassText('''
+class C implements D {}
+class D {}
+''');
+    expect(cls.interfaces, hasLength(1));
+    checkTypeRef(cls.interfaces[0], null, null, 'D');
+  }
+
+  test_class_interface_order() {
+    UnlinkedClass cls = serializeClassText('''
+class C implements D, E {}
+class D {}
+class E {}
+''');
+    expect(cls.interfaces, hasLength(2));
+    checkTypeRef(cls.interfaces[0], null, null, 'D');
+    checkTypeRef(cls.interfaces[1], null, null, 'E');
+  }
+
+  test_class_mixin() {
+    UnlinkedClass cls = serializeClassText('''
+class C extends Object with D {}
+class D {}
+''');
+    expect(cls.mixins, hasLength(1));
+    checkTypeRef(cls.mixins[0], null, null, 'D');
+  }
+
+  test_class_mixin_order() {
+    UnlinkedClass cls = serializeClassText('''
+class C extends Object with D, E {}
+class D {}
+class E {}
+''');
+    expect(cls.mixins, hasLength(2));
+    checkTypeRef(cls.mixins[0], null, null, 'D');
+    checkTypeRef(cls.mixins[1], null, null, 'E');
+  }
+
+  test_class_name() {
+    var classText = 'class C {}';
+    UnlinkedClass cls = serializeClassText(classText);
+    expect(cls.name, 'C');
+    expect(cls.nameOffset, classText.indexOf('C'));
+  }
+
+  test_class_no_flags() {
+    UnlinkedClass cls = serializeClassText('class C {}');
+    expect(cls.isAbstract, false);
+    expect(cls.isMixinApplication, false);
+  }
+
+  test_class_no_interface() {
+    UnlinkedClass cls = serializeClassText('class C {}');
+    expect(cls.interfaces, isEmpty);
+  }
+
+  test_class_no_mixins() {
+    UnlinkedClass cls = serializeClassText('class C {}');
+    expect(cls.mixins, isEmpty);
+  }
+
+  test_class_no_type_param() {
+    UnlinkedClass cls = serializeClassText('class C {}');
+    expect(cls.typeParameters, isEmpty);
+  }
+
+  test_class_non_alias_flag() {
+    UnlinkedClass cls = serializeClassText('class C {}');
+    expect(cls.isMixinApplication, false);
+  }
+
+  test_class_private() {
+    serializeClassText('class _C {}', className: '_C');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+  }
+
+  test_class_reference_generic() {
+    EntityRef typeRef =
+        serializeTypeText('C', otherDeclarations: 'class C<D, E> {}');
+    checkTypeRef(typeRef, null, null, 'C', numTypeParameters: 2);
+  }
+
+  test_class_reference_generic_imported() {
+    addNamedSource('/lib.dart', 'class C<D, E> {}');
+    EntityRef typeRef =
+        serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
+    checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'C',
+        numTypeParameters: 2);
+  }
+
+  test_class_superclass() {
+    UnlinkedClass cls = serializeClassText('class C {}');
+    expect(cls.supertype, isNull);
+    expect(cls.hasNoSupertype, isFalse);
+  }
+
+  test_class_superclass_explicit() {
+    UnlinkedClass cls = serializeClassText('class C extends D {} class D {}');
+    expect(cls.supertype, isNotNull);
+    checkTypeRef(cls.supertype, null, null, 'D');
+    expect(cls.hasNoSupertype, isFalse);
+  }
+
+  test_class_type_param_bound() {
+    UnlinkedClass cls = serializeClassText('class C<T extends List> {}');
+    expect(cls.typeParameters, hasLength(1));
+    expect(cls.typeParameters[0].name, 'T');
+    expect(cls.typeParameters[0].bound, isNotNull);
+    checkTypeRef(cls.typeParameters[0].bound, 'dart:core', 'dart:core', 'List',
+        allowTypeParameters: true, numTypeParameters: 1);
+  }
+
+  test_class_type_param_f_bound() {
+    UnlinkedClass cls = serializeClassText('class C<T, U extends List<T>> {}');
+    EntityRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
+    checkParamTypeRef(typeArgument, 2);
+  }
+
+  test_class_type_param_f_bound_self_ref() {
+    UnlinkedClass cls = serializeClassText('class C<T, U extends List<U>> {}');
+    EntityRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
+    checkParamTypeRef(typeArgument, 1);
+  }
+
+  test_class_type_param_no_bound() {
+    String text = 'class C<T> {}';
+    UnlinkedClass cls = serializeClassText(text);
+    expect(cls.typeParameters, hasLength(1));
+    expect(cls.typeParameters[0].name, 'T');
+    expect(cls.typeParameters[0].nameOffset, text.indexOf('T'));
+    expect(cls.typeParameters[0].bound, isNull);
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
+  }
+
+  test_closure_executable_with_bottom_return_type() {
+    UnlinkedExecutable executable =
+        serializeExecutableText('f() { print((() => null)()); }');
+    expect(executable.localFunctions, hasLength(1));
+    expect(executable.localFunctions[0].returnType, isNull);
+    if (strongMode) {
+      // Strong mode infers a type for the closure of `() => dynamic`, so the
+      // inferred return type slot should be empty.
+      expect(
+          getTypeRefForSlot(
+              executable.localFunctions[0].inferredReturnTypeSlot),
+          isNull);
+    } else {
+      // Spec mode infers a type for the closure of `() => Bottom`.
+      checkInferredTypeSlot(executable.localFunctions[0].inferredReturnTypeSlot,
+          null, null, '*bottom*',
+          onlyInStrongMode: false);
+    }
+  }
+
+  test_closure_executable_with_imported_return_type() {
+    addNamedSource('/a.dart', 'class C { D d; } class D {}');
+    // The closure has type `() => D`; `D` is defined in a library that is
+    // imported.
+    UnlinkedExecutable executable = serializeExecutableText(
+        'import "a.dart"; f() { print((() => new C().d)()); }');
+    expect(executable.localFunctions, hasLength(1));
+    expect(executable.localFunctions[0].returnType, isNull);
+    checkInferredTypeSlot(executable.localFunctions[0].inferredReturnTypeSlot,
+        absUri('/a.dart'), 'a.dart', 'D',
+        onlyInStrongMode: false);
+    checkHasDependency(absUri('/a.dart'), 'a.dart', fullyLinked: false);
+  }
+
+  test_closure_executable_with_return_type_from_closure() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    // The closure has type `() => () => int`, where the `() => int` part refers
+    // to the nested closure.
+    UnlinkedExecutable executable = serializeExecutableText('''
+f() {
+  print(() {}); // force the closure below to have index 1
+  print(() => () => 0);
+}
+''');
+    expect(executable.localFunctions, hasLength(2));
+    EntityRef closureType =
+        getTypeRefForSlot(executable.localFunctions[1].inferredReturnTypeSlot);
+    checkLinkedTypeRef(closureType, null, null, '',
+        expectedKind: ReferenceKind.function);
+    int outerClosureIndex =
+        definingUnit.references[closureType.reference].containingReference;
+    checkReferenceIndex(outerClosureIndex, null, null, '',
+        expectedKind: ReferenceKind.function, localIndex: 1);
+    int topLevelFunctionIndex =
+        definingUnit.references[outerClosureIndex].containingReference;
+    checkReferenceIndex(topLevelFunctionIndex, null, null, 'f',
+        expectedKind: ReferenceKind.topLevelFunction);
+    expect(
+        definingUnit.references[topLevelFunctionIndex].containingReference, 0);
+  }
+
+  test_closure_executable_with_unimported_return_type() {
+    addNamedSource('/a.dart', 'import "b.dart"; class C { D d; }');
+    addNamedSource('/b.dart', 'class D {}');
+    // The closure has type `() => D`; `D` is defined in a library that is not
+    // imported.
+    UnlinkedExecutable executable = serializeExecutableText(
+        'import "a.dart"; f() { print((() => new C().d)()); }');
+    expect(executable.localFunctions, hasLength(1));
+    expect(executable.localFunctions[0].returnType, isNull);
+    checkInferredTypeSlot(executable.localFunctions[0].inferredReturnTypeSlot,
+        absUri('/b.dart'), 'b.dart', 'D',
+        onlyInStrongMode: false);
+    if (!skipFullyLinkedData) {
+      checkHasDependency(absUri('/b.dart'), 'b.dart', fullyLinked: true);
+    }
+  }
+
+  test_constExpr_binary_add() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 + 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.add
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_and() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = true && false;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushTrue,
+      UnlinkedConstOperation.pushFalse,
+      UnlinkedConstOperation.and
+    ]);
+  }
+
+  test_constExpr_binary_bitAnd() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 & 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.bitAnd
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_bitOr() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 | 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.bitOr
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_bitShiftLeft() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 << 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.bitShiftLeft
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_bitShiftRight() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 >> 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.bitShiftRight
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_bitXor() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 ^ 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.bitXor
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_divide() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 / 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.divide
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_equal() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 == 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.equal
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_equal_not() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 != 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.notEqual
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_floorDivide() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 ~/ 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.floorDivide
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_greater() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 > 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.greater
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_greaterEqual() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 >= 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.greaterEqual
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_less() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 < 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.less
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_lessEqual() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 <= 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.lessEqual
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_modulo() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 % 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.modulo
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_multiply() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 * 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.multiply
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_binary_or() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = false || true;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushFalse,
+      UnlinkedConstOperation.pushTrue,
+      UnlinkedConstOperation.or
+    ]);
+  }
+
+  test_constExpr_binary_subtract() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1 - 2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.subtract
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_classMember_shadows_typeParam() {
+    // Although it is an error for a class member to have the same name as a
+    // type parameter, the spec makes it clear that the class member scope is
+    // nested inside the type parameter scope.  So go ahead and verify that
+    // the class member shadows the type parameter.
+    String text = '''
+class C<T> {
+  static const T = null;
+  final x;
+  const C() : x = T;
+}
+''';
+    UnlinkedClass cls = serializeClassText(text, allowErrors: true);
+    _assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
+        operators: [
+          UnlinkedConstOperation.pushReference
+        ],
+        referenceValidators: [
+          (EntityRef r) => checkTypeRef(r, null, null, 'T',
+                  expectedKind: ReferenceKind.propertyAccessor,
+                  prefixExpectations: [
+                    new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                        numTypeParameters: 1)
+                  ])
+        ]);
+  }
+
+  test_constExpr_conditional() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = true ? 1 : 2;', allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushTrue,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.conditional
+    ], ints: [
+      1,
+      2
+    ]);
+  }
+
+  test_constExpr_constructorParam_shadows_classMember() {
+    UnlinkedClass cls = serializeClassText('''
+class C {
+  static const a = null;
+  final b;
+  const C(a) : b = a;
+}
+''');
+    _assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
+        operators: [UnlinkedConstOperation.pushConstructorParameter],
+        strings: ['a']);
+  }
+
+  test_constExpr_constructorParam_shadows_typeParam() {
+    UnlinkedClass cls = serializeClassText('''
+class C<T> {
+  final x;
+  const C(T) : x = T;
+}
+''');
+    _assertUnlinkedConst(cls.executables[0].constantInitializers[0].expression,
+        operators: [UnlinkedConstOperation.pushConstructorParameter],
+        strings: ['T']);
+  }
+
+  test_constExpr_identical() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = identical(42, null);');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushNull,
+      UnlinkedConstOperation.identical
+    ], ints: [
+      42
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_generic_named() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C<K, V> {
+  const C.named();
+}
+const v = const C<int, String>.named();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) {
+        checkTypeRef(r, null, null, 'named',
+            expectedKind: ReferenceKind.constructor,
+            prefixExpectations: [
+              new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                  numTypeParameters: 2)
+            ],
+            allowTypeParameters: true);
+        checkTypeRef(r.typeArguments[0], 'dart:core', 'dart:core', 'int');
+        checkTypeRef(r.typeArguments[1], 'dart:core', 'dart:core', 'String');
+      }
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_generic_named_imported() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C<K, V> {
+  const C.named();
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = const C<int, String>.named();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) {
+        checkTypeRef(r, null, null, 'named',
+            expectedKind: ReferenceKind.constructor,
+            prefixExpectations: [
+              new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                  absoluteUri: absUri('/a.dart'),
+                  relativeUri: 'a.dart',
+                  numTypeParameters: 2)
+            ],
+            allowTypeParameters: true);
+        checkTypeRef(r.typeArguments[0], 'dart:core', 'dart:core', 'int');
+        checkTypeRef(r.typeArguments[1], 'dart:core', 'dart:core', 'String');
+      }
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_generic_named_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C<K, V> {
+  const C.named();
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = const p.C<int, String>.named();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) {
+        checkTypeRef(r, null, null, 'named',
+            expectedKind: ReferenceKind.constructor,
+            prefixExpectations: [
+              new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                  absoluteUri: absUri('/a.dart'),
+                  relativeUri: 'a.dart',
+                  numTypeParameters: 2),
+              new _PrefixExpectation(ReferenceKind.prefix, 'p')
+            ],
+            allowTypeParameters: true);
+        checkTypeRef(r.typeArguments[0], 'dart:core', 'dart:core', 'int');
+        checkTypeRef(r.typeArguments[1], 'dart:core', 'dart:core', 'String');
+      }
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_generic_unnamed() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C<K, V> {
+  const C();
+}
+const v = const C<int, String>();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) {
+        checkTypeRef(r, null, null, 'C',
+            expectedKind: ReferenceKind.classOrEnum,
+            numTypeParameters: 2,
+            allowTypeParameters: true);
+        checkTypeRef(r.typeArguments[0], 'dart:core', 'dart:core', 'int');
+        checkTypeRef(r.typeArguments[1], 'dart:core', 'dart:core', 'String');
+      }
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_generic_unnamed_imported() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C<K, V> {
+  const C();
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = const C<int, String>();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) {
+        checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'C',
+            expectedKind: ReferenceKind.classOrEnum,
+            numTypeParameters: 2,
+            allowTypeParameters: true);
+        checkTypeRef(r.typeArguments[0], 'dart:core', 'dart:core', 'int');
+        checkTypeRef(r.typeArguments[1], 'dart:core', 'dart:core', 'String');
+      }
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_generic_unnamed_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C<K, V> {
+  const C();
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = const p.C<int, String>();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) {
+        checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'C',
+            expectedKind: ReferenceKind.classOrEnum,
+            numTypeParameters: 2,
+            allowTypeParameters: true,
+            prefixExpectations: [
+              new _PrefixExpectation(ReferenceKind.prefix, 'p')
+            ]);
+        checkTypeRef(r.typeArguments[0], 'dart:core', 'dart:core', 'int');
+        checkTypeRef(r.typeArguments[1], 'dart:core', 'dart:core', 'String');
+      }
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_named() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C {
+  const C.named();
+}
+const v = const C.named();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'named',
+              expectedKind: ReferenceKind.constructor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_named_imported() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  const C.named();
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = const C.named();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'named',
+              expectedKind: ReferenceKind.constructor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
+              ])
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_named_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  const C.named();
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = const p.C.named();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'named',
+              expectedKind: ReferenceKind.constructor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p')
+              ])
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_unnamed() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C {
+  const C(a, b, c, d, {e, f, g});
+}
+const v = const C(11, 22, 3.3, '444', e: 55, g: '777', f: 66);
+''');
+    // Stack: 11 22 3.3 '444' 55 '777' 66 ^head
+    // Ints: ^pointer 3 4
+    // Doubles: ^pointer
+    // Strings: ^pointer 'e' 'g' 'f' ''
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushDouble,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      11,
+      22,
+      55,
+      66,
+      3,
+      4,
+    ], doubles: [
+      3.3
+    ], strings: [
+      '444',
+      '777',
+      'e',
+      'g',
+      'f'
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'C',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_unnamed_imported() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  const C();
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = const C();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'C',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_unnamed_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  const C();
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = const p.C();
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'C',
+              expectedKind: ReferenceKind.classOrEnum,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.prefix, 'p')
+              ])
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_unresolved_named() {
+    UnlinkedVariable variable = serializeVariableText(
+        '''
+class C {}
+const v = const C.foo();
+''',
+        allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+              expectedKind: ReferenceKind.unresolved,
+              checkAstDerivedDataOverride: true,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_unresolved_named2() {
+    UnlinkedVariable variable = serializeVariableText(
+        '''
+const v = const C.foo();
+''',
+        allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+              expectedKind: ReferenceKind.unresolved,
+              checkAstDerivedDataOverride: true,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.unresolved, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_unresolved_named_prefixed() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+}
+''');
+    UnlinkedVariable variable = serializeVariableText(
+        '''
+import 'a.dart' as p;
+const v = const p.C.foo();
+''',
+        allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+              expectedKind: ReferenceKind.unresolved,
+              checkAstDerivedDataOverride: true,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p')
+              ])
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_unresolved_named_prefixed2() {
+    addNamedSource('/a.dart', '');
+    UnlinkedVariable variable = serializeVariableText(
+        '''
+import 'a.dart' as p;
+const v = const p.C.foo();
+''',
+        allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+              expectedKind: ReferenceKind.unresolved,
+              checkAstDerivedDataOverride: true,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.unresolved, 'C'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p')
+              ])
+    ]);
+  }
+
+  test_constExpr_invokeConstructor_unresolved_unnamed() {
+    UnlinkedVariable variable = serializeVariableText(
+        '''
+const v = const Foo();
+''',
+        allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'Foo',
+          expectedKind: ReferenceKind.unresolved,
+          checkAstDerivedDataOverride: true)
+    ]);
+  }
+
+  test_constExpr_length_classConstField() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C {
+  static const int length = 0;
+}
+const int v = C.length;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'length',
+              expectedKind: ReferenceKind.propertyAccessor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_length_classConstField_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  static const int length = 0;
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const int v = p.C.length;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'length',
+              expectedKind: ReferenceKind.propertyAccessor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p')
+              ])
+    ]);
+  }
+
+  test_constExpr_length_identifierTarget() {
+    UnlinkedVariable variable = serializeVariableText('''
+const String a = 'aaa';
+const int v = a.length;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'length',
+              expectedKind: ReferenceKind.length,
+              prefixExpectations: [
+                new _PrefixExpectation(
+                    ReferenceKind.topLevelPropertyAccessor, 'a')
+              ])
+    ]);
+  }
+
+  test_constExpr_length_identifierTarget_classConstField() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C {
+  static const String F = '';
+}
+const int v = C.F.length;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'length',
+              expectedKind: ReferenceKind.length,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.propertyAccessor, 'F'),
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C'),
+              ])
+    ]);
+  }
+
+  test_constExpr_length_identifierTarget_imported() {
+    addNamedSource(
+        '/a.dart',
+        '''
+const String a = 'aaa';
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const int v = a.length;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'length',
+              expectedKind: ReferenceKind.length,
+              prefixExpectations: [
+                new _PrefixExpectation(
+                    ReferenceKind.topLevelPropertyAccessor, 'a',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
+              ])
+    ]);
+  }
+
+  test_constExpr_length_identifierTarget_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+const String a = 'aaa';
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const int v = p.a.length;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'length',
+              expectedKind: ReferenceKind.length,
+              prefixExpectations: [
+                new _PrefixExpectation(
+                    ReferenceKind.topLevelPropertyAccessor, 'a',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p')
+              ])
+    ]);
+  }
+
+  test_constExpr_length_parenthesizedBinaryTarget() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = ("abc" + "edf").length;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.add,
+      UnlinkedConstOperation.length
+    ], strings: [
+      'abc',
+      'edf'
+    ]);
+  }
+
+  test_constExpr_length_parenthesizedStringTarget() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = ("abc").length;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.length
+    ], strings: [
+      'abc'
+    ]);
+  }
+
+  test_constExpr_length_stringLiteralTarget() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = "abc".length;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.length
+    ], strings: [
+      'abc'
+    ]);
+  }
+
+  test_constExpr_makeSymbol() {
+    UnlinkedVariable variable = serializeVariableText('const v = #a.bb.ccc;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.makeSymbol], strings: ['a.bb.ccc']);
+  }
+
+  test_constExpr_makeTypedList() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = const <int>[11, 22, 33];');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.makeTypedList
+    ], ints: [
+      11,
+      22,
+      33,
+      3
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, 'dart:core', 'dart:core', 'int',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
+  test_constExpr_makeTypedList_dynamic() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = const <dynamic>[11, 22, 33];');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.makeTypedList
+    ], ints: [
+      11,
+      22,
+      33,
+      3
+    ], referenceValidators: [
+      (EntityRef r) => checkDynamicTypeRef(r)
+    ]);
+  }
+
+  test_constExpr_makeTypedMap() {
+    UnlinkedVariable variable = serializeVariableText(
+        'const v = const <int, String>{11: "aaa", 22: "bbb", 33: "ccc"};');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.makeTypedMap
+    ], ints: [
+      11,
+      22,
+      33,
+      3
+    ], strings: [
+      'aaa',
+      'bbb',
+      'ccc'
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, 'dart:core', 'dart:core', 'int',
+          expectedKind: ReferenceKind.classOrEnum),
+      (EntityRef r) => checkTypeRef(r, 'dart:core', 'dart:core', 'String',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
+  test_constExpr_makeTypedMap_dynamic() {
+    UnlinkedVariable variable = serializeVariableText(
+        'const v = const <dynamic, dynamic>{11: "aaa", 22: "bbb", 33: "ccc"};');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.makeTypedMap
+    ], ints: [
+      11,
+      22,
+      33,
+      3
+    ], strings: [
+      'aaa',
+      'bbb',
+      'ccc'
+    ], referenceValidators: [
+      (EntityRef r) => checkDynamicTypeRef(r),
+      (EntityRef r) => checkDynamicTypeRef(r)
+    ]);
+  }
+
+  test_constExpr_makeUntypedList() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = const [11, 22, 33];');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.makeUntypedList
+    ], ints: [
+      11,
+      22,
+      33,
+      3
+    ]);
+  }
+
+  test_constExpr_makeUntypedMap() {
+    UnlinkedVariable variable = serializeVariableText(
+        'const v = const {11: "aaa", 22: "bbb", 33: "ccc"};');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.makeUntypedMap
+    ], ints: [
+      11,
+      22,
+      33,
+      3
+    ], strings: [
+      'aaa',
+      'bbb',
+      'ccc'
+    ]);
+  }
+
+  test_constExpr_parenthesized() {
+    UnlinkedVariable variable = serializeVariableText('const v = (1 + 2) * 3;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.add,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.multiply,
+    ], ints: [
+      1,
+      2,
+      3
+    ]);
+  }
+
+  test_constExpr_prefix_complement() {
+    UnlinkedVariable variable = serializeVariableText('const v = ~2;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.complement
+    ], ints: [
+      2
+    ]);
+  }
+
+  test_constExpr_prefix_negate() {
+    UnlinkedVariable variable = serializeVariableText('const v = -(2);');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.negate
+    ], ints: [
+      2
+    ]);
+  }
+
+  test_constExpr_prefix_not() {
+    UnlinkedVariable variable = serializeVariableText('const v = !true;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushTrue,
+      UnlinkedConstOperation.not
+    ]);
+  }
+
+  test_constExpr_pushDouble() {
+    UnlinkedVariable variable = serializeVariableText('const v = 123.4567;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushDouble], doubles: [123.4567]);
+  }
+
+  test_constExpr_pushFalse() {
+    UnlinkedVariable variable = serializeVariableText('const v = false;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushFalse]);
+  }
+
+  test_constExpr_pushInt() {
+    UnlinkedVariable variable = serializeVariableText('const v = 1;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+  }
+
+  test_constExpr_pushInt_max() {
+    UnlinkedVariable variable = serializeVariableText('const v = 0xFFFFFFFF;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushInt,], ints: [0xFFFFFFFF]);
+  }
+
+  test_constExpr_pushInt_negative() {
+    UnlinkedVariable variable = serializeVariableText('const v = -5;');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.negate
+    ], ints: [
+      5
+    ]);
+  }
+
+  test_constExpr_pushLongInt() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = 0xA123456789ABCDEF012345678;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushLongInt],
+        ints: [4, 0xA, 0x12345678, 0x9ABCDEF0, 0x12345678]);
+  }
+
+  test_constExpr_pushLongInt_min2() {
+    UnlinkedVariable variable = serializeVariableText('const v = 0x100000000;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushLongInt], ints: [2, 1, 0,]);
+  }
+
+  test_constExpr_pushLongInt_min3() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = 0x10000000000000000;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushLongInt], ints: [3, 1, 0, 0,]);
+  }
+
+  test_constExpr_pushNull() {
+    UnlinkedVariable variable = serializeVariableText('const v = null;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushNull]);
+  }
+
+  test_constExpr_pushReference_class() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C {}
+const v = C;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'C',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
+  test_constExpr_pushReference_enum() {
+    UnlinkedVariable variable = serializeVariableText('''
+enum C {V1, V2, V3}
+const v = C;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'C',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
+  test_constExpr_pushReference_field() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C {
+  static const int F = 1;
+}
+const v = C.F;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'F',
+              expectedKind: ReferenceKind.propertyAccessor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_field_imported() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  static const int F = 1;
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = C.F;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'F',
+              expectedKind: ReferenceKind.propertyAccessor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_field_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  static const int F = 1;
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.C.F;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'F',
+              expectedKind: ReferenceKind.propertyAccessor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p'),
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_field_simpleIdentifier() {
+    UnlinkedVariable variable = serializeClassText('''
+class C {
+  static const a = b;
+  static const b = null;
+}
+''').fields[0];
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'b',
+              expectedKind: ReferenceKind.propertyAccessor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_staticMethod() {
+    UnlinkedVariable variable = serializeVariableText('''
+class C {
+  static m() {}
+}
+const v = C.m;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'm',
+              expectedKind: ReferenceKind.method,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_staticMethod_imported() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  static m() {}
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = C.m;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'm',
+              expectedKind: ReferenceKind.method,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_staticMethod_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {
+  static m() {}
+}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.C.m;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'm',
+              expectedKind: ReferenceKind.method,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_staticMethod_simpleIdentifier() {
+    UnlinkedVariable variable = serializeClassText('''
+class C {
+  static const a = m;
+  static m() {}
+}
+''').fields[0];
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'm',
+              expectedKind: ReferenceKind.method,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_topLevelFunction() {
+    UnlinkedVariable variable = serializeVariableText('''
+f() {}
+const v = f;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'f',
+          expectedKind: ReferenceKind.topLevelFunction)
+    ]);
+  }
+
+  test_constExpr_pushReference_topLevelFunction_imported() {
+    addNamedSource(
+        '/a.dart',
+        '''
+f() {}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = f;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'f',
+          expectedKind: ReferenceKind.topLevelFunction)
+    ]);
+  }
+
+  test_constExpr_pushReference_topLevelFunction_imported_withPrefix() {
+    addNamedSource(
+        '/a.dart',
+        '''
+f() {}
+''');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.f;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'f',
+              expectedKind: ReferenceKind.topLevelFunction,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.prefix, 'p')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_topLevelVariable() {
+    UnlinkedVariable variable = serializeVariableText('''
+const int a = 1;
+const v = a;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'a',
+          expectedKind: ReferenceKind.topLevelPropertyAccessor)
+    ]);
+  }
+
+  test_constExpr_pushReference_topLevelVariable_imported() {
+    addNamedSource('/a.dart', 'const int a = 1;');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart';
+const v = a;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'a',
+          expectedKind: ReferenceKind.topLevelPropertyAccessor)
+    ]);
+  }
+
+  test_constExpr_pushReference_topLevelVariable_imported_withPrefix() {
+    addNamedSource('/a.dart', 'const int a = 1;');
+    UnlinkedVariable variable = serializeVariableText('''
+import 'a.dart' as p;
+const v = p.a;
+''');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) {
+        return checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'a',
+            expectedKind: ReferenceKind.topLevelPropertyAccessor,
+            expectedPrefix: 'p');
+      }
+    ]);
+  }
+
+  test_constExpr_pushReference_typeParameter() {
+    String text = '''
+class C<T> {
+  static const a = T;
+}
+''';
+    UnlinkedVariable variable =
+        serializeClassText(text, allowErrors: true).fields[0];
+    _assertUnlinkedConst(variable.constExpr, isInvalid: true);
+  }
+
+  test_constExpr_pushReference_unresolved_prefix0() {
+    UnlinkedVariable variable = serializeVariableText(
+        '''
+const v = foo;
+''',
+        allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+          expectedKind: ReferenceKind.unresolved,
+          checkAstDerivedDataOverride: true)
+    ]);
+  }
+
+  test_constExpr_pushReference_unresolved_prefix1() {
+    UnlinkedVariable variable = serializeVariableText(
+        '''
+class C {}
+const v = C.foo;
+''',
+        allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+              expectedKind: ReferenceKind.unresolved,
+              checkAstDerivedDataOverride: true,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C')
+              ])
+    ]);
+  }
+
+  test_constExpr_pushReference_unresolved_prefix2() {
+    addNamedSource(
+        '/a.dart',
+        '''
+class C {}
+''');
+    UnlinkedVariable variable = serializeVariableText(
+        '''
+import 'a.dart' as p;
+const v = p.C.foo;
+''',
+        allowErrors: true);
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+              expectedKind: ReferenceKind.unresolved,
+              checkAstDerivedDataOverride: true,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'C',
+                    absoluteUri: absUri('/a.dart'), relativeUri: 'a.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'p'),
+              ])
+    ]);
+  }
+
+  test_constExpr_pushString_adjacent() {
+    UnlinkedVariable variable =
+        serializeVariableText('const v = "aaa" "b" "ccc";');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushString], strings: ['aaabccc']);
+  }
+
+  test_constExpr_pushString_adjacent_interpolation() {
+    UnlinkedVariable variable =
+        serializeVariableText(r'const v = "aaa" "bb ${42} bbb" "cccc";');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.concatenate,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.concatenate,
+    ], ints: [
+      42,
+      3,
+      3,
+    ], strings: [
+      'aaa',
+      'bb ',
+      ' bbb',
+      'cccc'
+    ]);
+  }
+
+  test_constExpr_pushString_interpolation() {
+    UnlinkedVariable variable =
+        serializeVariableText(r'const v = "aaa ${42} bbb";');
+    _assertUnlinkedConst(variable.constExpr, operators: [
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.pushInt,
+      UnlinkedConstOperation.pushString,
+      UnlinkedConstOperation.concatenate
+    ], ints: [
+      42,
+      3
+    ], strings: [
+      'aaa ',
+      ' bbb'
+    ]);
+  }
+
+  test_constExpr_pushString_simple() {
+    UnlinkedVariable variable = serializeVariableText('const v = "abc";');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushString], strings: ['abc']);
+  }
+
+  test_constExpr_pushTrue() {
+    UnlinkedVariable variable = serializeVariableText('const v = true;');
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushTrue]);
+  }
+
+  test_constructor() {
+    String text = 'class C { C(); }';
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(text).executables);
+    expect(executable.kind, UnlinkedExecutableKind.constructor);
+    expect(executable.returnType, isNull);
+    expect(executable.isExternal, isFalse);
+    expect(executable.nameOffset, text.indexOf('C();'));
+    expect(executable.periodOffset, 0);
+    expect(executable.nameEnd, 0);
+    expect(executable.isRedirectedConstructor, isFalse);
+    expect(executable.redirectedConstructor, isNull);
+    expect(executable.redirectedConstructorName, isEmpty);
+    expect(executable.visibleOffset, 0);
+    expect(executable.visibleLength, 0);
+  }
+
+  test_constructor_anonymous() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(); }').executables);
+    expect(executable.name, isEmpty);
+  }
+
+  test_constructor_const() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { const C(); }').executables);
+    expect(executable.isConst, isTrue);
+    expect(executable.isExternal, isFalse);
+  }
+
+  test_constructor_const_external() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { external const C(); }').executables);
+    expect(executable.isConst, isTrue);
+    expect(executable.isExternal, isTrue);
+  }
+
+  test_constructor_documented() {
+    String text = '''
+class C {
+  /**
+   * Docs
+   */
+  C();
+}''';
+    UnlinkedExecutable executable = serializeClassText(text).executables[0];
+    expect(executable.documentationComment, isNotNull);
+    checkDocumentationComment(executable.documentationComment, text);
+  }
+
+  test_constructor_external() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { external C(); }').executables);
+    expect(executable.isExternal, isTrue);
+  }
+
+  test_constructor_factory() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { factory C() => null; }').executables);
+    expect(executable.isFactory, isTrue);
+  }
+
+  test_constructor_implicit() {
+    // Implicit constructors are not serialized.
+    UnlinkedExecutable executable = findExecutable(null,
+        executables: serializeClassText('class C { C(); }').executables,
+        failIfAbsent: false);
+    expect(executable, isNull);
+  }
+
+  test_constructor_initializers_field() {
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(r'''
+class C {
+  final x;
+  const C() : x = 42;
+}
+''').executables);
+    expect(executable.constantInitializers, hasLength(1));
+    UnlinkedConstructorInitializer initializer =
+        executable.constantInitializers[0];
+    expect(initializer.kind, UnlinkedConstructorInitializerKind.field);
+    expect(initializer.name, 'x');
+    _assertUnlinkedConst(initializer.expression,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+    expect(initializer.arguments, isEmpty);
+  }
+
+  test_constructor_initializers_field_withParameter() {
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(r'''
+class C {
+  final x;
+  const C(int p) : x = p;
+}
+''').executables);
+    expect(executable.constantInitializers, hasLength(1));
+    UnlinkedConstructorInitializer initializer =
+        executable.constantInitializers[0];
+    expect(initializer.kind, UnlinkedConstructorInitializerKind.field);
+    expect(initializer.name, 'x');
+    _assertUnlinkedConst(initializer.expression,
+        operators: [UnlinkedConstOperation.pushConstructorParameter],
+        strings: ['p']);
+    expect(initializer.arguments, isEmpty);
+  }
+
+  test_constructor_initializers_notConst() {
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(r'''
+class C {
+  final x;
+  C() : x = 42;
+}
+''').executables);
+    expect(executable.constantInitializers, isEmpty);
+  }
+
+  test_constructor_initializers_superInvocation_named() {
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(r'''
+class A {
+  const A.aaa(int p);
+}
+class C extends A {
+  const C() : super.aaa(42);
+}
+''').executables);
+    expect(executable.constantInitializers, hasLength(1));
+    UnlinkedConstructorInitializer initializer =
+        executable.constantInitializers[0];
+    expect(
+        initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
+    expect(initializer.name, 'aaa');
+    expect(initializer.expression, isNull);
+    expect(initializer.arguments, hasLength(1));
+    _assertUnlinkedConst(initializer.arguments[0],
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+  }
+
+  test_constructor_initializers_superInvocation_unnamed() {
+    UnlinkedExecutable executable =
+        findExecutable('ccc', executables: serializeClassText(r'''
+class A {
+  const A(int p);
+}
+class C extends A {
+  const C.ccc() : super(42);
+}
+''').executables);
+    expect(executable.constantInitializers, hasLength(1));
+    UnlinkedConstructorInitializer initializer =
+        executable.constantInitializers[0];
+    expect(
+        initializer.kind, UnlinkedConstructorInitializerKind.superInvocation);
+    expect(initializer.name, '');
+    expect(initializer.expression, isNull);
+    expect(initializer.arguments, hasLength(1));
+    _assertUnlinkedConst(initializer.arguments[0],
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+  }
+
+  test_constructor_initializers_thisInvocation_named() {
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(r'''
+class C {
+  const C() : this.named(1, 'bbb');
+  const C.named(int a, String b);
+}
+''').executables);
+    expect(executable.constantInitializers, hasLength(1));
+    UnlinkedConstructorInitializer initializer =
+        executable.constantInitializers[0];
+    expect(initializer.kind, UnlinkedConstructorInitializerKind.thisInvocation);
+    expect(initializer.name, 'named');
+    expect(initializer.expression, isNull);
+    expect(initializer.arguments, hasLength(2));
+    _assertUnlinkedConst(initializer.arguments[0],
+        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+    _assertUnlinkedConst(initializer.arguments[1],
+        operators: [UnlinkedConstOperation.pushString], strings: ['bbb']);
+  }
+
+  test_constructor_initializers_thisInvocation_unnamed() {
+    UnlinkedExecutable executable =
+        findExecutable('named', executables: serializeClassText(r'''
+class C {
+  const C.named() : this(1, 'bbb');
+  const C(int a, String b);
+}
+''').executables);
+    expect(executable.constantInitializers, hasLength(1));
+    UnlinkedConstructorInitializer initializer =
+        executable.constantInitializers[0];
+    expect(initializer.kind, UnlinkedConstructorInitializerKind.thisInvocation);
+    expect(initializer.name, '');
+    expect(initializer.expression, isNull);
+    expect(initializer.arguments, hasLength(2));
+    _assertUnlinkedConst(initializer.arguments[0],
+        operators: [UnlinkedConstOperation.pushInt], ints: [1]);
+    _assertUnlinkedConst(initializer.arguments[1],
+        operators: [UnlinkedConstOperation.pushString], strings: ['bbb']);
+  }
+
+  test_constructor_initializing_formal() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { C(this.x); final x; }').executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.isInitializingFormal, isTrue);
+  }
+
+  test_constructor_initializing_formal_explicit_type() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(int this.x); final x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_constructor_initializing_formal_function_typed() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(this.x()); final x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.isFunctionTyped, isTrue);
+  }
+
+  test_constructor_initializing_formal_function_typed_explicit_return_type() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { C(int this.x()); Function x; }')
+                .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_constructor_initializing_formal_function_typed_implicit_return_type() {
+    if (!checkAstDerivedData) {
+      // TODO(paulberry): this test fails when building the summary from the
+      // element model because the element model doesn't record whether a
+      // function-typed parameter's return type is implicit.
+      return;
+    }
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(this.x()); Function x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.isFunctionTyped, isTrue);
+    expect(parameter.type, isNull);
+  }
+
+  test_constructor_initializing_formal_function_typed_no_parameters() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(this.x()); final x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.parameters, isEmpty);
+  }
+
+  test_constructor_initializing_formal_function_typed_parameter() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(this.x(a)); final x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.parameters, hasLength(1));
+  }
+
+  test_constructor_initializing_formal_function_typed_parameter_order() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(this.x(a, b)); final x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.parameters, hasLength(2));
+    expect(parameter.parameters[0].name, 'a');
+    expect(parameter.parameters[1].name, 'b');
+  }
+
+  test_constructor_initializing_formal_function_typed_withDefault() {
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(r'''
+class C {
+  C([this.x() = foo]);
+  final x;
+}
+int foo() => 0;
+''').executables);
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.isFunctionTyped, isTrue);
+    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.defaultValueCode, 'foo');
+    _assertUnlinkedConst(param.defaultValue, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+          expectedKind: ReferenceKind.topLevelFunction)
+    ]);
+  }
+
+  test_constructor_initializing_formal_implicit_type() {
+    // Note: the implicit type of an initializing formal is the type of the
+    // field.
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { C(this.x); int x; }').executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.type, isNull);
+  }
+
+  test_constructor_initializing_formal_name() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { C(this.x); final x; }').executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.name, 'x');
+  }
+
+  test_constructor_initializing_formal_named() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C({this.x}); final x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.kind, UnlinkedParamKind.named);
+    expect(parameter.defaultValue, isNull);
+    expect(parameter.defaultValueCode, isEmpty);
+  }
+
+  test_constructor_initializing_formal_named_withDefault() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C({this.x: 42}); final x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.kind, UnlinkedParamKind.named);
+    expect(parameter.initializer, isNotNull);
+    expect(parameter.defaultValueCode, '42');
+    _assertUnlinkedConst(parameter.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+  }
+
+  test_constructor_initializing_formal_non_function_typed() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { C(this.x); final x; }').executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.isFunctionTyped, isFalse);
+  }
+
+  test_constructor_initializing_formal_positional() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C([this.x]); final x; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.kind, UnlinkedParamKind.positional);
+    expect(parameter.defaultValue, isNull);
+    expect(parameter.defaultValueCode, isEmpty);
+  }
+
+  test_constructor_initializing_formal_positional_withDefault() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { C([this.x = 42]); final x; }')
+                .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.kind, UnlinkedParamKind.positional);
+    expect(parameter.initializer, isNotNull);
+    expect(parameter.defaultValueCode, '42');
+    _assertUnlinkedConst(parameter.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+  }
+
+  test_constructor_initializing_formal_required() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables:
+            serializeClassText('class C { C(this.x); final x; }').executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.kind, UnlinkedParamKind.required);
+  }
+
+  test_constructor_initializing_formal_typedef() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText(
+                'typedef F<T>(T x); class C<X> { C(this.f); F<X> f; }')
+            .executables);
+    UnlinkedParam parameter = executable.parameters[0];
+    expect(parameter.isFunctionTyped, isFalse);
+    expect(parameter.parameters, isEmpty);
+  }
+
+  test_constructor_initializing_formal_withDefault() {
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(r'''
+class C {
+  C([this.x = 42]);
+  final int x;
+}''').executables);
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.defaultValueCode, '42');
+    _assertUnlinkedConst(param.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+  }
+
+  test_constructor_named() {
+    String text = 'class C { C.foo(); }';
+    UnlinkedExecutable executable = findExecutable('foo',
+        executables: serializeClassText(text).executables);
+    expect(executable.name, 'foo');
+    expect(executable.nameOffset, text.indexOf('foo'));
+    expect(executable.periodOffset, text.indexOf('.foo'));
+    expect(executable.nameEnd, text.indexOf('()'));
+  }
+
+  test_constructor_non_const() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(); }').executables);
+    expect(executable.isConst, isFalse);
+  }
+
+  test_constructor_non_factory() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(); }').executables);
+    expect(executable.isFactory, isFalse);
+  }
+
+  test_constructor_param_inferred_type_explicit() {
+    UnlinkedExecutable ctor =
+        serializeClassText('class C { C(int v); }').executables[0];
+    expect(ctor.kind, UnlinkedExecutableKind.constructor);
+    expect(ctor.parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_constructor_param_inferred_type_implicit() {
+    UnlinkedExecutable ctor =
+        serializeClassText('class C { C(v); }').executables[0];
+    expect(ctor.kind, UnlinkedExecutableKind.constructor);
+    expect(ctor.parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_constructor_redirected_factory_named() {
+    String text = '''
+class C {
+  factory C() = D.named;
+  C._();
+}
+class D extends C {
+  D.named() : super._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(executable.redirectedConstructor, null, null, 'named',
+        expectedKind: ReferenceKind.constructor,
+        prefixExpectations: [
+          new _PrefixExpectation(ReferenceKind.classOrEnum, 'D')
+        ]);
+  }
+
+  test_constructor_redirected_factory_named_generic() {
+    String text = '''
+class C<T, U> {
+  factory C() = D<U, T>.named;
+  C._();
+}
+class D<T, U> extends C<U, T> {
+  D.named() : super._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(executable.redirectedConstructor, null, null, 'named',
+        expectedKind: ReferenceKind.constructor,
+        prefixExpectations: [
+          new _PrefixExpectation(ReferenceKind.classOrEnum, 'D',
+              numTypeParameters: 2)
+        ],
+        allowTypeParameters: true);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
+  }
+
+  test_constructor_redirected_factory_named_imported() {
+    addNamedSource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D extends C {
+  D.named() : super._();
+}
+''');
+    String text = '''
+import 'foo.dart';
+class C {
+  factory C() = D.named;
+  C._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(executable.redirectedConstructor, null, null, 'named',
+        expectedKind: ReferenceKind.constructor,
+        prefixExpectations: [
+          new _PrefixExpectation(ReferenceKind.classOrEnum, 'D',
+              absoluteUri: absUri('/foo.dart'), relativeUri: 'foo.dart')
+        ]);
+  }
+
+  test_constructor_redirected_factory_named_imported_generic() {
+    addNamedSource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D<T, U> extends C<U, T> {
+  D.named() : super._();
+}
+''');
+    String text = '''
+import 'foo.dart';
+class C<T, U> {
+  factory C() = D<U, T>.named;
+  C._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(executable.redirectedConstructor, null, null, 'named',
+        expectedKind: ReferenceKind.constructor,
+        prefixExpectations: [
+          new _PrefixExpectation(ReferenceKind.classOrEnum, 'D',
+              numTypeParameters: 2,
+              absoluteUri: absUri('/foo.dart'),
+              relativeUri: 'foo.dart')
+        ],
+        allowTypeParameters: true);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
+  }
+
+  test_constructor_redirected_factory_named_prefixed() {
+    addNamedSource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D extends C {
+  D.named() : super._();
+}
+''');
+    String text = '''
+import 'foo.dart' as foo;
+class C {
+  factory C() = foo.D.named;
+  C._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(executable.redirectedConstructor, null, null, 'named',
+        expectedKind: ReferenceKind.constructor,
+        prefixExpectations: [
+          new _PrefixExpectation(ReferenceKind.classOrEnum, 'D',
+              absoluteUri: absUri('/foo.dart'), relativeUri: 'foo.dart'),
+          new _PrefixExpectation(ReferenceKind.prefix, 'foo')
+        ]);
+  }
+
+  test_constructor_redirected_factory_named_prefixed_generic() {
+    addNamedSource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D<T, U> extends C<U, T> {
+  D.named() : super._();
+}
+''');
+    String text = '''
+import 'foo.dart' as foo;
+class C<T, U> {
+  factory C() = foo.D<U, T>.named;
+  C._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(executable.redirectedConstructor, null, null, 'named',
+        expectedKind: ReferenceKind.constructor,
+        prefixExpectations: [
+          new _PrefixExpectation(ReferenceKind.classOrEnum, 'D',
+              numTypeParameters: 2,
+              absoluteUri: absUri('/foo.dart'),
+              relativeUri: 'foo.dart'),
+          new _PrefixExpectation(ReferenceKind.prefix, 'foo')
+        ],
+        allowTypeParameters: true);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
+  }
+
+  test_constructor_redirected_factory_unnamed() {
+    String text = '''
+class C {
+  factory C() = D;
+  C._();
+}
+class D extends C {
+  D() : super._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(executable.redirectedConstructor, null, null, 'D');
+  }
+
+  test_constructor_redirected_factory_unnamed_generic() {
+    String text = '''
+class C<T, U> {
+  factory C() = D<U, T>;
+  C._();
+}
+class D<T, U> extends C<U, T> {
+  D() : super._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(executable.redirectedConstructor, null, null, 'D',
+        allowTypeParameters: true, numTypeParameters: 2);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
+  }
+
+  test_constructor_redirected_factory_unnamed_imported() {
+    addNamedSource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D extends C {
+  D() : super._();
+}
+''');
+    String text = '''
+import 'foo.dart';
+class C {
+  factory C() = D;
+  C._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(
+        executable.redirectedConstructor, absUri('/foo.dart'), 'foo.dart', 'D');
+  }
+
+  test_constructor_redirected_factory_unnamed_imported_generic() {
+    addNamedSource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D<T, U> extends C<U, T> {
+  D() : super._();
+}
+''');
+    String text = '''
+import 'foo.dart';
+class C<T, U> {
+  factory C() = D<U, T>;
+  C._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(
+        executable.redirectedConstructor, absUri('/foo.dart'), 'foo.dart', 'D',
+        allowTypeParameters: true, numTypeParameters: 2);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
+  }
+
+  test_constructor_redirected_factory_unnamed_prefixed() {
+    addNamedSource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D extends C {
+  D() : super._();
+}
+''');
+    String text = '''
+import 'foo.dart' as foo;
+class C {
+  factory C() = foo.D;
+  C._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(
+        executable.redirectedConstructor, absUri('/foo.dart'), 'foo.dart', 'D',
+        expectedPrefix: 'foo');
+  }
+
+  test_constructor_redirected_factory_unnamed_prefixed_generic() {
+    addNamedSource(
+        '/foo.dart',
+        '''
+import 'test.dart';
+class D<T, U> extends C<U, T> {
+  D() : super._();
+}
+''');
+    String text = '''
+import 'foo.dart' as foo;
+class C<T, U> {
+  factory C() = foo.D<U, T>;
+  C._();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isTrue);
+    expect(executable.redirectedConstructorName, isEmpty);
+    checkTypeRef(
+        executable.redirectedConstructor, absUri('/foo.dart'), 'foo.dart', 'D',
+        allowTypeParameters: true, numTypeParameters: 2, expectedPrefix: 'foo');
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[0], 1);
+    checkParamTypeRef(executable.redirectedConstructor.typeArguments[1], 2);
+  }
+
+  test_constructor_redirected_thisInvocation_named() {
+    String text = '''
+class C {
+  C() : this.named();
+  C.named();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isFalse);
+    expect(executable.redirectedConstructorName, 'named');
+    expect(executable.redirectedConstructor, isNull);
+  }
+
+  test_constructor_redirected_thisInvocation_unnamed() {
+    String text = '''
+class C {
+  C.named() : this();
+  C();
+}
+''';
+    UnlinkedExecutable executable =
+        serializeClassText(text, className: 'C').executables[0];
+    expect(executable.isRedirectedConstructor, isTrue);
+    expect(executable.isFactory, isFalse);
+    expect(executable.redirectedConstructorName, isEmpty);
+    expect(executable.redirectedConstructor, isNull);
+  }
+
+  test_constructor_return_type() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C { C(); }').executables);
+    expect(executable.returnType, isNull);
+  }
+
+  test_constructor_return_type_parameterized() {
+    UnlinkedExecutable executable = findExecutable('',
+        executables: serializeClassText('class C<T, U> { C(); }').executables);
+    expect(executable.returnType, isNull);
+  }
+
+  test_dependencies_export_to_export_unused() {
+    addNamedSource('/a.dart', 'export "b.dart";');
+    addNamedSource('/b.dart', '');
+    serializeLibraryText('export "a.dart";');
+    // The main test library depends on b.dart, even though it doesn't
+    // re-export any names defined in b.dart, because a change to b.dart might
+    // cause it to start exporting a name that the main test library *does*
+    // use.
+    checkHasDependency(absUri('/b.dart'), 'b.dart');
+  }
+
+  test_dependencies_export_unused() {
+    addNamedSource('/a.dart', '');
+    serializeLibraryText('export "a.dart";');
+    // The main test library depends on a.dart, even though it doesn't
+    // re-export any names defined in a.dart, because a change to a.dart might
+    // cause it to start exporting a name that the main test library *will*
+    // re-export.
+    checkHasDependency(absUri('/a.dart'), 'a.dart');
+  }
+
+  test_dependencies_import_to_export() {
+    addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
+    addNamedSource('/b.dart', 'library b;');
+    serializeLibraryText('import "a.dart"; A a;');
+    checkHasDependency(absUri('/a.dart'), 'a.dart');
+    // The main test library depends on b.dart, because names defined in
+    // b.dart are exported by a.dart.
+    checkHasDependency(absUri('/b.dart'), 'b.dart');
+  }
+
+  test_dependencies_import_to_export_in_subdirs_absolute_export() {
+    addNamedSource('/a/a.dart',
+        'library a; export "${absUri('/a/b/b.dart')}"; class A {}');
+    addNamedSource('/a/b/b.dart', 'library b;');
+    serializeLibraryText('import "a/a.dart"; A a;');
+    checkHasDependency(absUri('/a/a.dart'), 'a/a.dart');
+    // The main test library depends on b.dart, because names defined in
+    // b.dart are exported by a.dart.
+    checkHasDependency(absUri('/a/b/b.dart'), absUri('/a/b/b.dart'));
+  }
+
+  test_dependencies_import_to_export_in_subdirs_absolute_import() {
+    addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
+    addNamedSource('/a/b/b.dart', 'library b;');
+    serializeLibraryText('import "${absUri('/a/a.dart')}"; A a;');
+    checkHasDependency(absUri('/a/a.dart'), absUri('/a/a.dart'));
+    // The main test library depends on b.dart, because names defined in
+    // b.dart are exported by a.dart.
+    checkHasDependency(absUri('/a/b/b.dart'), absUri('/a/b/b.dart'));
+  }
+
+  test_dependencies_import_to_export_in_subdirs_relative() {
+    addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
+    addNamedSource('/a/b/b.dart', 'library b;');
+    serializeLibraryText('import "a/a.dart"; A a;');
+    checkHasDependency(absUri('/a/a.dart'), 'a/a.dart');
+    // The main test library depends on b.dart, because names defined in
+    // b.dart are exported by a.dart.
+    checkHasDependency(absUri('/a/b/b.dart'), 'a/b/b.dart');
+  }
+
+  test_dependencies_import_to_export_loop() {
+    addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
+    addNamedSource('/b.dart', 'library b; export "a.dart";');
+    serializeLibraryText('import "a.dart"; A a;');
+    checkHasDependency(absUri('/a.dart'), 'a.dart');
+    // Serialization should have been able to walk the transitive export
+    // dependencies to b.dart without going into an infinite loop.
+    checkHasDependency(absUri('/b.dart'), 'b.dart');
+  }
+
+  test_dependencies_import_to_export_transitive_closure() {
+    addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
+    addNamedSource('/b.dart', 'library b; export "c.dart";');
+    addNamedSource('/c.dart', 'library c;');
+    serializeLibraryText('import "a.dart"; A a;');
+    checkHasDependency(absUri('/a.dart'), 'a.dart');
+    // The main test library depends on c.dart, because names defined in
+    // c.dart are exported by b.dart and then re-exported by a.dart.
+    checkHasDependency(absUri('/c.dart'), 'c.dart');
+  }
+
+  test_dependencies_import_to_export_unused() {
+    addNamedSource('/a.dart', 'export "b.dart";');
+    addNamedSource('/b.dart', '');
+    serializeLibraryText('import "a.dart";', allowErrors: true);
+    // The main test library depends on b.dart, even though it doesn't use any
+    // names defined in b.dart, because a change to b.dart might cause it to
+    // start exporting a name that the main test library *does* use.
+    checkHasDependency(absUri('/b.dart'), 'b.dart');
+  }
+
+  test_dependencies_import_transitive_closure() {
+    addNamedSource(
+        '/a.dart', 'library a; import "b.dart"; class A extends B {}');
+    addNamedSource('/b.dart', 'library b; class B {}');
+    serializeLibraryText('import "a.dart"; A a;');
+    checkHasDependency(absUri('/a.dart'), 'a.dart');
+    // The main test library doesn't depend on b.dart, because no change to
+    // b.dart can possibly affect the serialized element model for it.
+    checkLacksDependency(absUri('/b.dart'), 'b.dart');
+  }
+
+  test_dependencies_import_unused() {
+    addNamedSource('/a.dart', '');
+    serializeLibraryText('import "a.dart";', allowErrors: true);
+    // The main test library depends on a.dart, even though it doesn't use any
+    // names defined in a.dart, because a change to a.dart might cause it to
+    // start exporting a name that the main test library *does* use.
+    checkHasDependency(absUri('/a.dart'), 'a.dart');
+  }
+
+  test_dependencies_parts() {
+    addNamedSource(
+        '/a.dart', 'library a; part "b.dart"; part "c.dart"; class A {}');
+    addNamedSource('/b.dart', 'part of a;');
+    addNamedSource('/c.dart', 'part of a;');
+    serializeLibraryText('import "a.dart"; A a;');
+    int dep = checkHasDependency(absUri('/a.dart'), 'a.dart');
+    checkDependencyParts(linked.dependencies[dep],
+        [absUri('/b.dart'), absUri('/c.dart')], ['b.dart', 'c.dart']);
+  }
+
+  test_dependencies_parts_relative_to_importing_library() {
+    addNamedSource('/a/b.dart', 'export "c/d.dart";');
+    addNamedSource('/a/c/d.dart',
+        'library d; part "e/f.dart"; part "g/h.dart"; class D {}');
+    addNamedSource('/a/c/e/f.dart', 'part of d;');
+    addNamedSource('/a/c/g/h.dart', 'part of d;');
+    serializeLibraryText('import "a/b.dart"; D d;');
+    int dep = checkHasDependency(absUri('/a/c/d.dart'), 'a/c/d.dart');
+    checkDependencyParts(
+        linked.dependencies[dep],
+        [absUri('/a/c/e/f.dart'), absUri('/a/c/g/h.dart')],
+        ['a/c/e/f.dart', 'a/c/g/h.dart']);
+  }
+
+  test_elements_in_part() {
+    addNamedSource(
+        '/part1.dart',
+        '''
+part of my.lib;
+
+class C {}
+enum E { v }
+var v;
+f() {}
+typedef F();
+''');
+    serializeLibraryText('library my.lib; part "part1.dart";');
+    UnlinkedUnit unit = unlinkedUnits[1];
+    expect(findClass('C', unit: unit), isNotNull);
+    expect(findEnum('E', unit: unit), isNotNull);
+    expect(findVariable('v', variables: unit.variables), isNotNull);
+    expect(findExecutable('f', executables: unit.executables), isNotNull);
+    expect(findTypedef('F', unit: unit), isNotNull);
+  }
+
+  test_enum() {
+    String text = 'enum E { v1 }';
+    UnlinkedEnum e = serializeEnumText(text);
+    expect(e.name, 'E');
+    expect(e.nameOffset, text.indexOf('E'));
+    expect(e.values, hasLength(1));
+    expect(e.values[0].name, 'v1');
+    expect(e.values[0].nameOffset, text.indexOf('v1'));
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+        ReferenceKind.classOrEnum);
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'E');
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+  }
+
+  test_enum_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+enum E { v }''';
+    UnlinkedEnum enm = serializeEnumText(text);
+    expect(enm.documentationComment, isNotNull);
+    checkDocumentationComment(enm.documentationComment, text);
+  }
+
+  test_enum_order() {
+    UnlinkedEnum e = serializeEnumText('enum E { v1, v2 }');
+    expect(e.values, hasLength(2));
+    expect(e.values[0].name, 'v1');
+    expect(e.values[1].name, 'v2');
+  }
+
+  test_enum_private() {
+    serializeEnumText('enum _E { v1 }', '_E');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+  }
+
+  test_enum_value_documented() {
+    String text = '''
+enum E {
+  /**
+   * Docs
+   */
+  v
+}''';
+    UnlinkedEnumValue value = serializeEnumText(text).values[0];
+    expect(value.documentationComment, isNotNull);
+    checkDocumentationComment(value.documentationComment, text);
+  }
+
+  test_executable_abstract() {
+    UnlinkedExecutable executable =
+        serializeClassText('abstract class C { f(); }').executables[0];
+    expect(executable.isAbstract, isTrue);
+  }
+
+  test_executable_concrete() {
+    UnlinkedExecutable executable =
+        serializeClassText('abstract class C { f() {} }').executables[0];
+    expect(executable.isAbstract, isFalse);
+  }
+
+  test_executable_function() {
+    String text = '  f() {}';
+    UnlinkedExecutable executable = serializeExecutableText(text);
+    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+    expect(executable.returnType, isNull);
+    expect(executable.isExternal, isFalse);
+    expect(executable.nameOffset, text.indexOf('f'));
+    expect(executable.visibleOffset, 0);
+    expect(executable.visibleLength, 0);
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+        ReferenceKind.topLevelFunction);
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+  }
+
+  test_executable_function_explicit_return() {
+    UnlinkedExecutable executable =
+        serializeExecutableText('dynamic f() => null;');
+    checkDynamicTypeRef(executable.returnType);
+  }
+
+  test_executable_function_external() {
+    UnlinkedExecutable executable = serializeExecutableText('external f();');
+    expect(executable.isExternal, isTrue);
+  }
+
+  test_executable_function_private() {
+    serializeExecutableText('_f() {}', executableName: '_f');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+  }
+
+  test_executable_getter() {
+    String text = 'int get f => 1;';
+    UnlinkedExecutable executable = serializeExecutableText(text);
+    expect(executable.kind, UnlinkedExecutableKind.getter);
+    expect(executable.returnType, isNotNull);
+    expect(executable.isExternal, isFalse);
+    expect(executable.nameOffset, text.indexOf('f'));
+    expect(findVariable('f'), isNull);
+    expect(findExecutable('f='), isNull);
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+        ReferenceKind.topLevelPropertyAccessor);
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
+  }
+
+  test_executable_getter_external() {
+    UnlinkedExecutable executable =
+        serializeExecutableText('external int get f;');
+    expect(executable.isExternal, isTrue);
+  }
+
+  test_executable_getter_private() {
+    serializeExecutableText('int get _f => 1;', executableName: '_f');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+  }
+
+  test_executable_getter_type() {
+    UnlinkedExecutable executable = serializeExecutableText('int get f => 1;');
+    checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'int');
+    expect(executable.parameters, isEmpty);
+  }
+
+  test_executable_getter_type_implicit() {
+    UnlinkedExecutable executable = serializeExecutableText('get f => 1;');
+    expect(executable.returnType, isNull);
+    expect(executable.parameters, isEmpty);
+  }
+
+  test_executable_localFunctions() {
+    String code = r'''
+f() { // 1
+  f1() {}
+  { // 2
+    f2() {}
+  } // 3
+} // 4
+''';
+    UnlinkedExecutable executable = serializeExecutableText(code);
+    List<UnlinkedExecutable> functions = executable.localFunctions;
+    expect(functions, hasLength(2));
+    {
+      UnlinkedExecutable f1 = functions.singleWhere((v) => v.name == 'f1');
+      _assertExecutableVisible(code, f1, '{ // 1', '} // 4');
+    }
+    {
+      UnlinkedExecutable f2 = functions.singleWhere((v) => v.name == 'f2');
+      _assertExecutableVisible(code, f2, '{ // 2', '} // 3');
+    }
+  }
+
+  test_executable_localLabels_inMethod() {
+    String code = r'''
+class C {
+  m() {
+    aaa: while (true) {}
+    bbb: while (true) {}
+  }
+}
+''';
+    UnlinkedExecutable executable =
+        findExecutable('m', executables: serializeClassText(code).executables);
+    List<UnlinkedLabel> labels = executable.localLabels;
+    expect(labels, hasLength(2));
+    {
+      UnlinkedLabel aaa = labels.singleWhere((l) => l.name == 'aaa');
+      expect(aaa, isNotNull);
+      expect(aaa.isOnSwitchMember, isFalse);
+      expect(aaa.isOnSwitchStatement, isFalse);
+    }
+    {
+      UnlinkedLabel bbb = labels.singleWhere((l) => l.name == 'bbb');
+      expect(bbb, isNotNull);
+      expect(bbb.isOnSwitchMember, isFalse);
+      expect(bbb.isOnSwitchStatement, isFalse);
+    }
+  }
+
+  test_executable_localLabels_inTopLevelFunction() {
+    String code = r'''
+f() {
+  aaa: while (true) {}
+  bbb: switch (42) {
+    ccc: case 0:
+      break;
+  }
+}
+''';
+    UnlinkedExecutable executable = serializeExecutableText(code);
+    List<UnlinkedLabel> labels = executable.localLabels;
+    expect(labels, hasLength(3));
+    {
+      UnlinkedLabel aaa = labels.singleWhere((l) => l.name == 'aaa');
+      expect(aaa, isNotNull);
+      expect(aaa.isOnSwitchMember, isFalse);
+      expect(aaa.isOnSwitchStatement, isFalse);
+    }
+    {
+      UnlinkedLabel bbb = labels.singleWhere((l) => l.name == 'bbb');
+      expect(bbb, isNotNull);
+      expect(bbb.isOnSwitchMember, isFalse);
+      expect(bbb.isOnSwitchStatement, isTrue);
+    }
+    {
+      UnlinkedLabel ccc = labels.singleWhere((l) => l.name == 'ccc');
+      expect(ccc, isNotNull);
+      expect(ccc.isOnSwitchMember, isTrue);
+      expect(ccc.isOnSwitchStatement, isFalse);
+    }
+  }
+
+  test_executable_localLabels_inTopLevelGetter() {
+    String code = r'''
+get g {
+  aaa: while (true) {}
+  bbb: while (true) {}
+}
+''';
+    UnlinkedExecutable executable =
+        serializeExecutableText(code, executableName: 'g');
+    List<UnlinkedLabel> labels = executable.localLabels;
+    expect(labels, hasLength(2));
+    {
+      UnlinkedLabel aaa = labels.singleWhere((l) => l.name == 'aaa');
+      expect(aaa, isNotNull);
+      expect(aaa.isOnSwitchMember, isFalse);
+      expect(aaa.isOnSwitchStatement, isFalse);
+    }
+    {
+      UnlinkedLabel bbb = labels.singleWhere((l) => l.name == 'bbb');
+      expect(bbb, isNotNull);
+      expect(bbb.isOnSwitchMember, isFalse);
+      expect(bbb.isOnSwitchStatement, isFalse);
+    }
+  }
+
+  test_executable_localVariables_empty() {
+    UnlinkedExecutable executable = serializeExecutableText(r'''
+f() {
+}
+''');
+    expect(executable.localVariables, isEmpty);
+  }
+
+  test_executable_localVariables_inConstructor() {
+    String code = r'''
+class C {
+  C() { // 1
+    int v;
+  } // 2
+}
+''';
+    UnlinkedExecutable executable =
+        findExecutable('', executables: serializeClassText(code).executables);
+    List<UnlinkedVariable> variables = executable.localVariables;
+    expect(variables, hasLength(1));
+    {
+      UnlinkedVariable v = variables.singleWhere((v) => v.name == 'v');
+      _assertVariableVisible(code, v, '{ // 1', '} // 2');
+      checkTypeRef(v.type, 'dart:core', 'dart:core', 'int');
+    }
+  }
+
+  test_executable_localVariables_inLocalFunctions() {
+    String code = r'''
+f() {
+  f1() { // 1
+    int v1 = 1;
+  } // 2
+  f2() { // 3
+    int v1 = 1;
+    f3() { // 4
+      int v2 = 1;
+    } // 5
+  } // 6
+} // 7
+''';
+    UnlinkedExecutable executable = serializeExecutableText(code);
+    List<UnlinkedExecutable> functions = executable.localFunctions;
+    expect(functions, hasLength(2));
+    // f - f1
+    {
+      UnlinkedExecutable f1 = functions.singleWhere((v) => v.name == 'f1');
+      List<UnlinkedVariable> variables = f1.localVariables;
+      expect(variables, hasLength(1));
+      // f1 - v1
+      UnlinkedVariable v1 = variables.singleWhere((v) => v.name == 'v1');
+      _assertVariableVisible(code, v1, '{ // 1', '} // 2');
+      checkTypeRef(v1.type, 'dart:core', 'dart:core', 'int');
+    }
+    // f - f2
+    {
+      UnlinkedExecutable f2 = functions.singleWhere((v) => v.name == 'f2');
+      List<UnlinkedVariable> variables2 = f2.localVariables;
+      List<UnlinkedExecutable> functions2 = f2.localFunctions;
+      expect(variables2, hasLength(1));
+      expect(functions2, hasLength(1));
+      // f - f2 - v1
+      UnlinkedVariable v1 = variables2.singleWhere((v) => v.name == 'v1');
+      _assertVariableVisible(code, v1, '{ // 3', '} // 6');
+      checkTypeRef(v1.type, 'dart:core', 'dart:core', 'int');
+      // f - f2 - f3
+      UnlinkedExecutable f3 = functions2.singleWhere((v) => v.name == 'f3');
+      _assertExecutableVisible(code, f3, '{ // 3', '} // 6');
+      List<UnlinkedVariable> variables3 = f3.localVariables;
+      List<UnlinkedExecutable> functions3 = f3.localFunctions;
+      expect(variables3, hasLength(1));
+      expect(functions3, hasLength(0));
+      // f - f3 - v2
+      UnlinkedVariable v2 = variables3.singleWhere((v) => v.name == 'v2');
+      _assertVariableVisible(code, v2, '{ // 4', '} // 5');
+      checkTypeRef(v2.type, 'dart:core', 'dart:core', 'int');
+    }
+  }
+
+  test_executable_localVariables_inMethod() {
+    String code = r'''
+class C {
+  m() { // 1
+    int v;
+    f() {}
+  } // 2
+}
+''';
+    UnlinkedExecutable executable =
+        findExecutable('m', executables: serializeClassText(code).executables);
+    {
+      List<UnlinkedExecutable> functions = executable.localFunctions;
+      expect(functions, hasLength(1));
+      UnlinkedExecutable f = functions.singleWhere((v) => v.name == 'f');
+      _assertExecutableVisible(code, f, '{ // 1', '} // 2');
+    }
+    {
+      List<UnlinkedVariable> variables = executable.localVariables;
+      expect(variables, hasLength(1));
+      UnlinkedVariable v = variables.singleWhere((v) => v.name == 'v');
+      _assertVariableVisible(code, v, '{ // 1', '} // 2');
+      checkTypeRef(v.type, 'dart:core', 'dart:core', 'int');
+    }
+  }
+
+  test_executable_localVariables_inTopLevelFunction() {
+    String code = r'''
+f() { // 1
+  int v1 = 1;
+  { // 2
+    int v2 = 2;
+  } // 3
+  var v3 = 3;
+} // 4
+''';
+    UnlinkedExecutable executable = serializeExecutableText(code);
+    List<UnlinkedVariable> variables = executable.localVariables;
+    expect(variables, hasLength(3));
+    {
+      UnlinkedVariable v1 = variables.singleWhere((v) => v.name == 'v1');
+      _assertVariableVisible(code, v1, '{ // 1', '} // 4');
+      checkTypeRef(v1.type, 'dart:core', 'dart:core', 'int');
+    }
+    {
+      UnlinkedVariable v2 = variables.singleWhere((v) => v.name == 'v2');
+      _assertVariableVisible(code, v2, '{ // 2', '} // 3');
+      checkTypeRef(v2.type, 'dart:core', 'dart:core', 'int');
+    }
+    {
+      UnlinkedVariable v3 = variables.singleWhere((v) => v.name == 'v3');
+      _assertVariableVisible(code, v3, '{ // 1', '} // 4');
+      expect(v3.type, isNull);
+    }
+  }
+
+  test_executable_localVariables_inTopLevelGetter() {
+    String code = r'''
+get g { // 1
+  int v;
+  f() {}
+} // 2
+''';
+    UnlinkedExecutable executable =
+        serializeExecutableText(code, executableName: 'g');
+    {
+      List<UnlinkedExecutable> functions = executable.localFunctions;
+      expect(functions, hasLength(1));
+      UnlinkedExecutable f = functions.singleWhere((v) => v.name == 'f');
+      _assertExecutableVisible(code, f, '{ // 1', '} // 2');
+    }
+    {
+      List<UnlinkedVariable> variables = executable.localVariables;
+      expect(variables, hasLength(1));
+      UnlinkedVariable v = variables.singleWhere((v) => v.name == 'v');
+      _assertVariableVisible(code, v, '{ // 1', '} // 2');
+      checkTypeRef(v.type, 'dart:core', 'dart:core', 'int');
+    }
+  }
+
+  test_executable_member_function() {
+    UnlinkedExecutable executable = findExecutable('f',
+        executables: serializeClassText('class C { f() {} }').executables);
+    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+    expect(executable.returnType, isNull);
+    expect(executable.isExternal, isFalse);
+    expect(executable.visibleOffset, 0);
+    expect(executable.visibleLength, 0);
+  }
+
+  test_executable_member_function_explicit_return() {
+    UnlinkedExecutable executable = findExecutable('f',
+        executables:
+            serializeClassText('class C { dynamic f() => null; }').executables);
+    expect(executable.returnType, isNotNull);
+  }
+
+  test_executable_member_function_external() {
+    UnlinkedExecutable executable = findExecutable('f',
+        executables:
+            serializeClassText('class C { external f(); }').executables);
+    expect(executable.isExternal, isTrue);
+  }
+
+  test_executable_member_getter() {
+    UnlinkedClass cls = serializeClassText('class C { int get f => 1; }');
+    UnlinkedExecutable executable =
+        findExecutable('f', executables: cls.executables, failIfAbsent: true);
+    expect(executable.kind, UnlinkedExecutableKind.getter);
+    expect(executable.returnType, isNotNull);
+    expect(executable.isExternal, isFalse);
+    expect(findVariable('f', variables: cls.fields), isNull);
+    expect(findExecutable('f=', executables: cls.executables), isNull);
+  }
+
+  test_executable_member_getter_external() {
+    UnlinkedClass cls = serializeClassText('class C { external int get f; }');
+    UnlinkedExecutable executable =
+        findExecutable('f', executables: cls.executables, failIfAbsent: true);
+    expect(executable.isExternal, isTrue);
+  }
+
+  test_executable_member_setter() {
+    UnlinkedClass cls = serializeClassText('class C { void set f(value) {} }');
+    UnlinkedExecutable executable =
+        findExecutable('f=', executables: cls.executables, failIfAbsent: true);
+    expect(executable.kind, UnlinkedExecutableKind.setter);
+    expect(executable.returnType, isNotNull);
+    expect(executable.isExternal, isFalse);
+    expect(findVariable('f', variables: cls.fields), isNull);
+    expect(findExecutable('f', executables: cls.executables), isNull);
+  }
+
+  test_executable_member_setter_external() {
+    UnlinkedClass cls =
+        serializeClassText('class C { external void set f(value); }');
+    UnlinkedExecutable executable =
+        findExecutable('f=', executables: cls.executables, failIfAbsent: true);
+    expect(executable.isExternal, isTrue);
+  }
+
+  test_executable_member_setter_implicit_return() {
+    UnlinkedClass cls = serializeClassText('class C { set f(value) {} }');
+    UnlinkedExecutable executable =
+        findExecutable('f=', executables: cls.executables, failIfAbsent: true);
+    expect(executable.returnType, isNull);
+  }
+
+  test_executable_name() {
+    UnlinkedExecutable executable = serializeExecutableText('f() {}');
+    expect(executable.name, 'f');
+  }
+
+  test_executable_no_flags() {
+    UnlinkedExecutable executable = serializeExecutableText('f() {}');
+    expect(executable.isAbstract, isFalse);
+    expect(executable.isConst, isFalse);
+    expect(executable.isFactory, isFalse);
+    expect(executable.isStatic, isFalse);
+  }
+
+  test_executable_non_static() {
+    UnlinkedExecutable executable =
+        serializeClassText('class C { f() {} }').executables[0];
+    expect(executable.isStatic, isFalse);
+  }
+
+  test_executable_non_static_top_level() {
+    // Top level executables are considered non-static.
+    UnlinkedExecutable executable = serializeExecutableText('f() {}');
+    expect(executable.isStatic, isFalse);
+  }
+
+  test_executable_operator() {
+    UnlinkedExecutable executable =
+        serializeClassText('class C { C operator+(C c) => null; }').executables[
+            0];
+    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+    expect(executable.name, '+');
+    expect(executable.returnType, isNotNull);
+    expect(executable.isAbstract, false);
+    expect(executable.isConst, false);
+    expect(executable.isFactory, false);
+    expect(executable.isStatic, false);
+    expect(executable.parameters, hasLength(1));
+    checkTypeRef(executable.returnType, null, null, 'C');
+    expect(executable.typeParameters, isEmpty);
+    expect(executable.isExternal, false);
+  }
+
+  test_executable_operator_equal() {
+    UnlinkedExecutable executable = serializeClassText(
+            'class C { bool operator==(Object other) => false; }')
+        .executables[0];
+    expect(executable.name, '==');
+  }
+
+  test_executable_operator_external() {
+    UnlinkedExecutable executable =
+        serializeClassText('class C { external C operator+(C c); }')
+            .executables[0];
+    expect(executable.isExternal, true);
+  }
+
+  test_executable_operator_greater_equal() {
+    UnlinkedExecutable executable =
+        serializeClassText('class C { bool operator>=(C other) => false; }')
+            .executables[0];
+    expect(executable.name, '>=');
+  }
+
+  test_executable_operator_index() {
+    UnlinkedExecutable executable =
+        serializeClassText('class C { bool operator[](int i) => null; }')
+            .executables[0];
+    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+    expect(executable.name, '[]');
+    expect(executable.returnType, isNotNull);
+    expect(executable.isAbstract, false);
+    expect(executable.isConst, false);
+    expect(executable.isFactory, false);
+    expect(executable.isStatic, false);
+    expect(executable.parameters, hasLength(1));
+    checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'bool');
+    expect(executable.typeParameters, isEmpty);
+  }
+
+  test_executable_operator_index_set() {
+    UnlinkedExecutable executable = serializeClassText(
+            'class C { void operator[]=(int i, bool v) => null; }')
+        .executables[0];
+    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
+    expect(executable.name, '[]=');
+    expect(executable.returnType, isNotNull);
+    expect(executable.isAbstract, false);
+    expect(executable.isConst, false);
+    expect(executable.isFactory, false);
+    expect(executable.isStatic, false);
+    expect(executable.parameters, hasLength(2));
+    checkVoidTypeRef(executable.returnType);
+    expect(executable.typeParameters, isEmpty);
+  }
+
+  test_executable_operator_less_equal() {
+    UnlinkedExecutable executable =
+        serializeClassText('class C { bool operator<=(C other) => false; }')
+            .executables[0];
+    expect(executable.name, '<=');
+  }
+
+  test_executable_param_function_typed() {
+    if (!checkAstDerivedData) {
+      // TODO(paulberry): this test fails when building the summary from the
+      // element model because the elment model doesn't record whether a
+      // function-typed parameter's return type is implicit.
+      return;
+    }
+    UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
+    expect(executable.parameters[0].isFunctionTyped, isTrue);
+    expect(executable.parameters[0].type, isNull);
+  }
+
+  test_executable_param_function_typed_explicit_return_type() {
+    UnlinkedExecutable executable =
+        serializeExecutableText('f(dynamic g()) {}');
+    expect(executable.parameters[0].type, isNotNull);
+  }
+
+  test_executable_param_function_typed_param() {
+    UnlinkedExecutable executable = serializeExecutableText('f(g(x)) {}');
+    expect(executable.parameters[0].parameters, hasLength(1));
+  }
+
+  test_executable_param_function_typed_param_none() {
+    UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
+    expect(executable.parameters[0].parameters, isEmpty);
+  }
+
+  test_executable_param_function_typed_param_order() {
+    UnlinkedExecutable executable = serializeExecutableText('f(g(x, y)) {}');
+    expect(executable.parameters[0].parameters, hasLength(2));
+    expect(executable.parameters[0].parameters[0].name, 'x');
+    expect(executable.parameters[0].parameters[1].name, 'y');
+  }
+
+  test_executable_param_function_typed_return_type() {
+    UnlinkedExecutable executable = serializeExecutableText('f(int g()) {}');
+    checkTypeRef(
+        executable.parameters[0].type, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_executable_param_function_typed_return_type_implicit() {
+    if (!checkAstDerivedData) {
+      // TODO(paulberry): this test fails when building the summary from the
+      // element model because the element model doesn't record whether a
+      // function-typed parameter's return type is implicit.
+      return;
+    }
+    UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
+    expect(executable.parameters[0].isFunctionTyped, isTrue);
+    expect(executable.parameters[0].type, isNull);
+  }
+
+  test_executable_param_function_typed_return_type_void() {
+    UnlinkedExecutable executable = serializeExecutableText('f(void g()) {}');
+    checkVoidTypeRef(executable.parameters[0].type);
+  }
+
+  test_executable_param_function_typed_withDefault() {
+    UnlinkedExecutable executable = serializeExecutableText(r'''
+f([int p(int a2, String b2) = foo]) {}
+int foo(int a, String b) => 0;
+''');
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.initializer, isNotNull);
+    expect(param.defaultValueCode, 'foo');
+    _assertUnlinkedConst(param.defaultValue, operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'foo',
+          expectedKind: ReferenceKind.topLevelFunction)
+    ]);
+  }
+
+  test_executable_param_kind_named() {
+    UnlinkedExecutable executable = serializeExecutableText('f({x}) {}');
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.named);
+    expect(param.initializer, isNull);
+    expect(param.defaultValue, isNull);
+    expect(param.defaultValueCode, isEmpty);
+  }
+
+  test_executable_param_kind_named_withDefault() {
+    UnlinkedExecutable executable = serializeExecutableText('f({x: 42}) {}');
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.named);
+    expect(param.initializer, isNotNull);
+    expect(param.defaultValueCode, '42');
+    _assertUnlinkedConst(param.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+  }
+
+  test_executable_param_kind_positional() {
+    UnlinkedExecutable executable = serializeExecutableText('f([x]) {}');
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.initializer, isNull);
+    expect(param.defaultValue, isNull);
+    expect(param.defaultValueCode, isEmpty);
+  }
+
+  test_executable_param_kind_positional_withDefault() {
+    UnlinkedExecutable executable = serializeExecutableText('f([x = 42]) {}');
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.positional);
+    expect(param.initializer, isNotNull);
+    expect(param.defaultValueCode, '42');
+    _assertUnlinkedConst(param.defaultValue,
+        operators: [UnlinkedConstOperation.pushInt], ints: [42]);
+  }
+
+  test_executable_param_kind_required() {
+    UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
+    UnlinkedParam param = executable.parameters[0];
+    expect(param.kind, UnlinkedParamKind.required);
+    expect(param.initializer, isNull);
+    expect(param.defaultValue, isNull);
+    expect(param.defaultValueCode, isEmpty);
+  }
+
+  test_executable_param_name() {
+    String text = 'f(x) {}';
+    UnlinkedExecutable executable = serializeExecutableText(text);
+    expect(executable.parameters, hasLength(1));
+    expect(executable.parameters[0].name, 'x');
+    expect(executable.parameters[0].nameOffset, text.indexOf('x'));
+  }
+
+  test_executable_param_no_flags() {
+    UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
+    expect(executable.parameters[0].isFunctionTyped, isFalse);
+    expect(executable.parameters[0].isInitializingFormal, isFalse);
+  }
+
+  test_executable_param_non_function_typed() {
+    UnlinkedExecutable executable = serializeExecutableText('f(g) {}');
+    expect(executable.parameters[0].isFunctionTyped, isFalse);
+  }
+
+  test_executable_param_none() {
+    UnlinkedExecutable executable = serializeExecutableText('f() {}');
+    expect(executable.parameters, isEmpty);
+  }
+
+  test_executable_param_order() {
+    UnlinkedExecutable executable = serializeExecutableText('f(x, y) {}');
+    expect(executable.parameters, hasLength(2));
+    expect(executable.parameters[0].name, 'x');
+    expect(executable.parameters[1].name, 'y');
+  }
+
+  test_executable_param_type_explicit() {
+    UnlinkedExecutable executable = serializeExecutableText('f(dynamic x) {}');
+    checkDynamicTypeRef(executable.parameters[0].type);
+  }
+
+  test_executable_param_type_implicit() {
+    UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
+    expect(executable.parameters[0].type, isNull);
+  }
+
+  test_executable_param_type_typedef() {
+    UnlinkedExecutable executable = serializeExecutableText(r'''
+typedef MyFunction(int p);
+f(MyFunction myFunction) {}
+''');
+    expect(executable.parameters[0].isFunctionTyped, isFalse);
+    checkTypeRef(executable.parameters[0].type, null, null, 'MyFunction',
+        expectedKind: ReferenceKind.typedef);
+  }
+
+  test_executable_return_type() {
+    UnlinkedExecutable executable = serializeExecutableText('int f() => 1;');
+    checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_executable_return_type_implicit() {
+    UnlinkedExecutable executable = serializeExecutableText('f() {}');
+    expect(executable.returnType, isNull);
+  }
+
+  test_executable_return_type_void() {
+    UnlinkedExecutable executable = serializeExecutableText('void f() {}');
+    checkVoidTypeRef(executable.returnType);
+  }
+
+  test_executable_setter() {
+    String text = 'void set f(value) {}';
+    UnlinkedExecutable executable =
+        serializeExecutableText(text, executableName: 'f=');
+    expect(executable.kind, UnlinkedExecutableKind.setter);
+    expect(executable.returnType, isNotNull);
+    expect(executable.isExternal, isFalse);
+    expect(executable.nameOffset, text.indexOf('f'));
+    expect(findVariable('f'), isNull);
+    expect(findExecutable('f'), isNull);
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+        ReferenceKind.topLevelPropertyAccessor);
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f=');
+  }
+
+  test_executable_setter_external() {
+    UnlinkedExecutable executable = serializeExecutableText(
+        'external void set f(value);',
+        executableName: 'f=');
+    expect(executable.isExternal, isTrue);
+  }
+
+  test_executable_setter_implicit_return() {
+    UnlinkedExecutable executable =
+        serializeExecutableText('set f(value) {}', executableName: 'f=');
+    expect(executable.returnType, isNull);
+  }
+
+  test_executable_setter_private() {
+    serializeExecutableText('void set _f(value) {}', executableName: '_f=');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+  }
+
+  test_executable_setter_type() {
+    UnlinkedExecutable executable = serializeExecutableText(
+        'void set f(int value) {}',
+        executableName: 'f=');
+    checkVoidTypeRef(executable.returnType);
+    expect(executable.parameters, hasLength(1));
+    expect(executable.parameters[0].name, 'value');
+    checkTypeRef(
+        executable.parameters[0].type, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_executable_static() {
+    UnlinkedExecutable executable =
+        serializeClassText('class C { static f() {} }').executables[0];
+    expect(executable.isStatic, isTrue);
+  }
+
+  test_executable_type_param_f_bound_function() {
+    UnlinkedExecutable ex =
+        serializeExecutableText('void f<T, U extends List<T>>() {}');
+    EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
+    checkParamTypeRef(typeArgument, 2);
+  }
+
+  test_executable_type_param_f_bound_method() {
+    UnlinkedExecutable ex =
+        serializeMethodText('void f<T, U extends List<T>>() {}');
+    EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
+    checkParamTypeRef(typeArgument, 2);
+  }
+
+  test_executable_type_param_f_bound_self_ref_function() {
+    UnlinkedExecutable ex =
+        serializeExecutableText('void f<T, U extends List<U>>() {}');
+    EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
+    checkParamTypeRef(typeArgument, 1);
+  }
+
+  test_executable_type_param_f_bound_self_ref_method() {
+    UnlinkedExecutable ex =
+        serializeMethodText('void f<T, U extends List<U>>() {}');
+    EntityRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
+    checkParamTypeRef(typeArgument, 1);
+  }
+
+  test_executable_type_param_in_parameter_function() {
+    UnlinkedExecutable ex = serializeExecutableText('void f<T>(T t) {}');
+    checkParamTypeRef(ex.parameters[0].type, 1);
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
+  }
+
+  test_executable_type_param_in_parameter_method() {
+    UnlinkedExecutable ex = serializeMethodText('void f<T>(T t) {}');
+    checkParamTypeRef(ex.parameters[0].type, 1);
+  }
+
+  test_executable_type_param_in_return_type_function() {
+    UnlinkedExecutable ex = serializeExecutableText('T f<T>() => null;');
+    checkParamTypeRef(ex.returnType, 1);
+  }
+
+  test_executable_type_param_in_return_type_method() {
+    UnlinkedExecutable ex = serializeMethodText('T f<T>() => null;');
+    checkParamTypeRef(ex.returnType, 1);
+  }
+
+  test_export_class() {
+    addNamedSource('/a.dart', 'class C {}');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'C',
+        ReferenceKind.classOrEnum);
+  }
+
+  test_export_class_alias() {
+    addNamedSource(
+        '/a.dart', 'class C extends _D with _E {} class _D {} class _E {}');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'C',
+        ReferenceKind.classOrEnum);
+  }
+
+  test_export_enum() {
+    addNamedSource('/a.dart', 'enum E { v }');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'E',
+        ReferenceKind.classOrEnum);
+  }
+
+  test_export_from_part() {
+    addNamedSource('/a.dart', 'library foo; part "b.dart";');
+    addNamedSource('/b.dart', 'part of foo; f() {}');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+        ReferenceKind.topLevelFunction,
+        expectedTargetUnit: 1);
+  }
+
+  test_export_function() {
+    addNamedSource('/a.dart', 'f() {}');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+        ReferenceKind.topLevelFunction);
+  }
+
+  test_export_getter() {
+    addNamedSource('/a.dart', 'get f => null');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+        ReferenceKind.topLevelPropertyAccessor);
+  }
+
+  test_export_hide() {
+    addNamedSource('/a.dart', 'f() {} g() {}');
+    serializeLibraryText('export "a.dart" hide g;');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+        ReferenceKind.topLevelFunction);
+  }
+
+  test_export_hide_order() {
+    serializeLibraryText('export "dart:async" hide Future, Stream;');
+    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+    expect(
+        unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
+        isEmpty);
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
+        hasLength(2));
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[0],
+        'Future');
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[1],
+        'Stream');
+    expect(
+        unlinkedUnits[0].publicNamespace.exports[0].combinators[0].offset, 0);
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].end, 0);
+    expect(linked.exportNames, isNotEmpty);
+  }
+
+  test_export_names_excludes_names_from_library() {
+    addNamedSource('/a.dart', 'part of my.lib; int y; int _y;');
+    serializeLibraryText('library my.lib; part "a.dart"; int x; int _x;');
+    expect(linked.exportNames, isEmpty);
+  }
+
+  test_export_no_combinators() {
+    serializeLibraryText('export "dart:async";');
+    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators, isEmpty);
+  }
+
+  test_export_not_shadowed_by_prefix() {
+    addNamedSource('/a.dart', 'f() {}');
+    serializeLibraryText('export "a.dart"; import "dart:core" as f; f.int _x;');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+        ReferenceKind.topLevelFunction);
+  }
+
+  test_export_offset() {
+    String libraryText = '    export "dart:async";';
+    serializeLibraryText(libraryText);
+    expect(unlinkedUnits[0].exports[0].uriOffset,
+        libraryText.indexOf('"dart:async"'));
+    expect(unlinkedUnits[0].exports[0].uriEnd, libraryText.indexOf(';'));
+    expect(unlinkedUnits[0].exports[0].offset, libraryText.indexOf('export'));
+  }
+
+  test_export_private() {
+    // Private names should not be exported.
+    addNamedSource('/a.dart', '_f() {}');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, isEmpty);
+  }
+
+  test_export_setter() {
+    addNamedSource('/a.dart', 'void set f(value) {}');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f=',
+        ReferenceKind.topLevelPropertyAccessor);
+  }
+
+  test_export_shadowed() {
+    // f() is not shown in exportNames because it is already defined at top
+    // level in the library.
+    addNamedSource('/a.dart', 'f() {}');
+    serializeLibraryText('export "a.dart"; f() {}');
+    expect(linked.exportNames, isEmpty);
+  }
+
+  test_export_shadowed_variable() {
+    // Neither `v` nor `v=` is shown in exportNames because both are defined at
+    // top level in the library by the declaration `var v;`.
+    addNamedSource('/a.dart', 'var v;');
+    serializeLibraryText('export "a.dart"; var v;');
+    expect(linked.exportNames, isEmpty);
+  }
+
+  test_export_shadowed_variable_const() {
+    // `v=` is shown in exportNames because the top level declaration
+    // `const v = 0;` only shadows `v`, not `v=`.
+    addNamedSource('/a.dart', 'var v;');
+    serializeLibraryText('export "a.dart"; const v = 0;');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'v=',
+        ReferenceKind.topLevelPropertyAccessor);
+  }
+
+  test_export_shadowed_variable_final() {
+    // `v=` is shown in exportNames because the top level declaration
+    // `final v = 0;` only shadows `v`, not `v=`.
+    addNamedSource('/a.dart', 'var v;');
+    serializeLibraryText('export "a.dart"; final v = 0;');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'v=',
+        ReferenceKind.topLevelPropertyAccessor);
+  }
+
+  test_export_show() {
+    addNamedSource('/a.dart', 'f() {} g() {}');
+    serializeLibraryText('export "a.dart" show f;');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'f',
+        ReferenceKind.topLevelFunction);
+  }
+
+  test_export_show_order() {
+    String libraryText = 'export "dart:async" show Future, Stream;';
+    serializeLibraryText(libraryText);
+    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+    expect(
+        unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
+        hasLength(2));
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
+        isEmpty);
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[0],
+        'Future');
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[1],
+        'Stream');
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].offset,
+        libraryText.indexOf('show'));
+    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].end,
+        libraryText.indexOf(';'));
+  }
+
+  test_export_typedef() {
+    addNamedSource('/a.dart', 'typedef F();');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(1));
+    checkExportName(linked.exportNames[0], absUri('/a.dart'), 'a.dart', 'F',
+        ReferenceKind.typedef);
+  }
+
+  test_export_uri() {
+    addNamedSource('/a.dart', 'library my.lib;');
+    String uriString = '"a.dart"';
+    String libraryText = 'export $uriString;';
+    serializeLibraryText(libraryText);
+    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.exports[0].uri, 'a.dart');
+  }
+
+  test_export_variable() {
+    addNamedSource('/a.dart', 'var v;');
+    serializeLibraryText('export "a.dart";');
+    expect(linked.exportNames, hasLength(2));
+    LinkedExportName getter =
+        linked.exportNames.firstWhere((e) => e.name == 'v');
+    expect(getter, isNotNull);
+    checkExportName(getter, absUri('/a.dart'), 'a.dart', 'v',
+        ReferenceKind.topLevelPropertyAccessor);
+    LinkedExportName setter =
+        linked.exportNames.firstWhere((e) => e.name == 'v=');
+    expect(setter, isNotNull);
+    checkExportName(setter, absUri('/a.dart'), 'a.dart', 'v=',
+        ReferenceKind.topLevelPropertyAccessor);
+  }
+
+  test_field() {
+    UnlinkedClass cls = serializeClassText('class C { int i; }');
+    UnlinkedVariable variable = findVariable('i', variables: cls.fields);
+    expect(variable, isNotNull);
+    expect(variable.isConst, isFalse);
+    expect(variable.isStatic, isFalse);
+    expect(variable.isFinal, isFalse);
+    expect(variable.constExpr, isNull);
+    expect(findExecutable('i', executables: cls.executables), isNull);
+    expect(findExecutable('i=', executables: cls.executables), isNull);
+  }
+
+  test_field_const() {
+    UnlinkedVariable variable =
+        serializeClassText('class C { static const int i = 0; }').fields[0];
+    expect(variable.isConst, isTrue);
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushInt], ints: [0]);
+  }
+
+  test_field_documented() {
+    String text = '''
+class C {
+  /**
+   * Docs
+   */
+  var v;
+}''';
+    UnlinkedVariable variable = serializeClassText(text).fields[0];
+    expect(variable.documentationComment, isNotNull);
+    checkDocumentationComment(variable.documentationComment, text);
+  }
+
+  test_field_final() {
+    UnlinkedVariable variable =
+        serializeClassText('class C { final int i = 0; }').fields[0];
+    expect(variable.isFinal, isTrue);
+    _assertUnlinkedConst(variable.constExpr,
+        operators: [UnlinkedConstOperation.pushInt], ints: [0]);
+  }
+
+  test_field_final_invalidConstExpr() {
+    UnlinkedVariable variable = serializeClassText(r'''
+class C {
+  final int f = 1 + m();
+  static int m() => 42;
+}''').fields[0];
+    expect(variable.isFinal, isTrue);
+    _assertUnlinkedConst(variable.constExpr, isInvalid: true);
+  }
+
+  test_field_formal_param_inferred_type_explicit() {
+    UnlinkedClass cls = serializeClassText(
+        'class C extends D { var v; C(int this.v); }'
+        ' abstract class D { num get v; }',
+        className: 'C');
+    checkInferredTypeSlot(
+        cls.fields[0].inferredTypeSlot, 'dart:core', 'dart:core', 'num');
+    expect(cls.executables[0].kind, UnlinkedExecutableKind.constructor);
+    expect(cls.executables[0].parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_field_formal_param_inferred_type_implicit() {
+    // Both the field `v` and the constructor argument `this.v` will have their
+    // type inferred by strong mode.  But only the field should have its
+    // inferred type stored in the summary, since the standard rules for field
+    // formal parameters will take care of the rest (they implicitly inherit
+    // the type of the associated field).
+    UnlinkedClass cls = serializeClassText(
+        'class C extends D { var v; C(this.v); }'
+        ' abstract class D { int get v; }',
+        className: 'C');
+    checkInferredTypeSlot(
+        cls.fields[0].inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+    expect(cls.executables[0].kind, UnlinkedExecutableKind.constructor);
+    expect(cls.executables[0].parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_field_inferred_type_nonstatic_explicit_initialized() {
+    UnlinkedVariable v = serializeClassText('class C { num v = 0; }').fields[0];
+    expect(v.inferredTypeSlot, 0);
+  }
+
+  test_field_inferred_type_nonstatic_explicit_uninitialized() {
+    UnlinkedVariable v = serializeClassText(
+            'class C extends D { num v; } abstract class D { int get v; }',
+            className: 'C',
+            allowErrors: true)
+        .fields[0];
+    expect(v.inferredTypeSlot, 0);
+  }
+
+  test_field_inferred_type_nonstatic_implicit_initialized() {
+    UnlinkedVariable v = serializeClassText('class C { var v = 0; }').fields[0];
+    checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_field_inferred_type_nonstatic_implicit_uninitialized() {
+    UnlinkedVariable v = serializeClassText(
+            'class C extends D { var v; } abstract class D { int get v; }',
+            className: 'C')
+        .fields[0];
+    checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_field_inferred_type_static_explicit_initialized() {
+    UnlinkedVariable v =
+        serializeClassText('class C { static int v = 0; }').fields[0];
+    expect(v.inferredTypeSlot, 0);
+  }
+
+  test_field_inferred_type_static_implicit_initialized() {
+    UnlinkedVariable v =
+        serializeClassText('class C { static var v = 0; }').fields[0];
+    checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_field_inferred_type_static_implicit_uninitialized() {
+    UnlinkedVariable v =
+        serializeClassText('class C { static var v; }').fields[0];
+    expect(v.inferredTypeSlot, 0);
+  }
+
+  test_field_propagated_type_final_immediate() {
+    UnlinkedVariable v =
+        serializeClassText('class C { final v = 0; }').fields[0];
+    checkLinkedTypeSlot(v.propagatedTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_field_static() {
+    UnlinkedVariable variable =
+        serializeClassText('class C { static int i; }').fields[0];
+    expect(variable.isStatic, isTrue);
+    expect(variable.constExpr, isNull);
+  }
+
+  test_field_static_final() {
+    UnlinkedVariable variable =
+        serializeClassText('class C { static final int i = 0; }').fields[0];
+    expect(variable.isStatic, isTrue);
+    expect(variable.isFinal, isTrue);
+    expect(variable.constExpr, isNull);
+  }
+
+  test_fully_linked_references_follow_other_references() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    serializeLibraryText('final x = 0; String y;');
+    checkLinkedTypeSlot(unlinkedUnits[0].variables[0].propagatedTypeSlot,
+        'dart:core', 'dart:core', 'int');
+    checkTypeRef(
+        unlinkedUnits[0].variables[1].type, 'dart:core', 'dart:core', 'String');
+    // Even though the definition of y follows the definition of x, the linked
+    // type reference for x should use a higher numbered reference than the
+    // unlinked type reference for y.
+    EntityRef propagatedType =
+        getTypeRefForSlot(unlinkedUnits[0].variables[0].propagatedTypeSlot);
+    expect(unlinkedUnits[0].variables[1].type.reference,
+        lessThan(propagatedType.reference));
+  }
+
+  test_function_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+f() {}''';
+    UnlinkedExecutable executable = serializeExecutableText(text);
+    expect(executable.documentationComment, isNotNull);
+    checkDocumentationComment(executable.documentationComment, text);
+  }
+
+  test_function_inferred_type_implicit_param() {
+    UnlinkedExecutable f = serializeExecutableText('void f(value) {}');
+    expect(f.parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_function_inferred_type_implicit_return() {
+    UnlinkedExecutable f = serializeExecutableText('f() => null;');
+    expect(f.inferredReturnTypeSlot, 0);
+  }
+
+  test_generic_gClass_gMethodStatic() {
+    UnlinkedClass cls = serializeClassText('''
+class C<T, U> {
+  static void m<V, W>(V v, W w) {
+    void f<X, Y>(V v, W w, X x, Y y) {
+    }
+  }
+}
+''');
+    UnlinkedExecutable m = cls.executables[0];
+    UnlinkedExecutable f = m.localFunctions[0];
+    checkParamTypeRef(m.parameters[0].type, 2);
+    checkParamTypeRef(m.parameters[1].type, 1);
+    checkParamTypeRef(f.parameters[0].type, 4);
+    checkParamTypeRef(f.parameters[1].type, 3);
+    checkParamTypeRef(f.parameters[2].type, 2);
+    checkParamTypeRef(f.parameters[3].type, 1);
+  }
+
+  test_generic_method_in_generic_class() {
+    UnlinkedClass cls = serializeClassText(
+        'class C<T, U> { void m<V, W>(T t, U u, V v, W w) {} }');
+    List<UnlinkedParam> params = cls.executables[0].parameters;
+    checkParamTypeRef(params[0].type, 4);
+    checkParamTypeRef(params[1].type, 3);
+    checkParamTypeRef(params[2].type, 2);
+    checkParamTypeRef(params[3].type, 1);
+  }
+
+  test_getter_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+get f => null;''';
+    UnlinkedExecutable executable = serializeExecutableText(text);
+    expect(executable.documentationComment, isNotNull);
+    checkDocumentationComment(executable.documentationComment, text);
+  }
+
+  test_getter_inferred_type_nonstatic_explicit_return() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { num get f => null; }'
+            ' abstract class D { int get f; }',
+            className: 'C',
+            allowErrors: true)
+        .executables[0];
+    expect(f.inferredReturnTypeSlot, 0);
+  }
+
+  test_getter_inferred_type_nonstatic_implicit_return() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { get f => null; } abstract class D { int get f; }',
+            className: 'C')
+        .executables[0];
+    checkInferredTypeSlot(
+        f.inferredReturnTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_getter_inferred_type_static_implicit_return() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { static get f => null; }'
+            ' class D { static int get f => null; }',
+            className: 'C')
+        .executables[0];
+    expect(f.inferredReturnTypeSlot, 0);
+  }
+
+  test_implicit_dependencies_follow_other_dependencies() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    addNamedSource('/a.dart', 'import "b.dart"; class C {} D f() => null;');
+    addNamedSource('/b.dart', 'class D {}');
+    serializeLibraryText('import "a.dart"; final x = f(); C y;');
+    // The dependency on b.dart is implicit, so it should be placed at the end
+    // of the dependency list, after a.dart, even though the code that refers
+    // to b.dart comes before the code that refers to a.dart.
+    int aDep =
+        checkHasDependency(absUri('/a.dart'), 'a.dart', fullyLinked: false);
+    int bDep =
+        checkHasDependency(absUri('/b.dart'), 'b.dart', fullyLinked: true);
+    expect(aDep, lessThan(bDep));
+  }
+
+  test_import_deferred() {
+    serializeLibraryText(
+        'import "dart:async" deferred as a; main() { print(a.Future); }');
+    expect(unlinkedUnits[0].imports[0].isDeferred, isTrue);
+  }
+
+  test_import_dependency() {
+    serializeLibraryText('import "dart:async"; Future x;');
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    checkDependency(linked.importDependencies[0], 'dart:async', 'dart:async');
+  }
+
+  test_import_explicit() {
+    serializeLibraryText('import "dart:core"; int i;');
+    expect(unlinkedUnits[0].imports, hasLength(1));
+    expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
+  }
+
+  test_import_hide_order() {
+    serializeLibraryText(
+        'import "dart:async" hide Future, Stream; Completer c;');
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
+    expect(unlinkedUnits[0].imports[0].combinators[0].shows, isEmpty);
+    expect(unlinkedUnits[0].imports[0].combinators[0].hides, hasLength(2));
+    expect(unlinkedUnits[0].imports[0].combinators[0].hides[0], 'Future');
+    expect(unlinkedUnits[0].imports[0].combinators[0].hides[1], 'Stream');
+    expect(unlinkedUnits[0].imports[0].combinators[0].offset, 0);
+    expect(unlinkedUnits[0].imports[0].combinators[0].end, 0);
+  }
+
+  test_import_implicit() {
+    // The implicit import of dart:core is represented in the model.
+    serializeLibraryText('');
+    expect(unlinkedUnits[0].imports, hasLength(1));
+    checkDependency(linked.importDependencies[0], 'dart:core', 'dart:core');
+    expect(unlinkedUnits[0].imports[0].uri, isEmpty);
+    expect(unlinkedUnits[0].imports[0].uriOffset, 0);
+    expect(unlinkedUnits[0].imports[0].uriEnd, 0);
+    expect(unlinkedUnits[0].imports[0].prefixReference, 0);
+    expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
+    expect(unlinkedUnits[0].imports[0].isImplicit, isTrue);
+  }
+
+  test_import_missing() {
+    if (!checkAstDerivedData) {
+      // TODO(paulberry): At the moment unresolved imports are not included in
+      // the element model, so we can't pass this test.
+      return;
+    }
+    // Unresolved imports are included since this is necessary for proper
+    // dependency tracking.
+    allowMissingFiles = true;
+    serializeLibraryText('import "foo.dart";', allowErrors: true);
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    checkDependency(
+        linked.importDependencies[0], absUri('/foo.dart'), 'foo.dart');
+  }
+
+  test_import_no_combinators() {
+    serializeLibraryText('import "dart:async"; Future x;');
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
+  }
+
+  test_import_no_flags() {
+    serializeLibraryText('import "dart:async"; Future x;');
+    expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
+    expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
+  }
+
+  test_import_non_deferred() {
+    serializeLibraryText(
+        'import "dart:async" as a; main() { print(a.Future); }');
+    expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
+  }
+
+  test_import_of_file_with_missing_part() {
+    // Other references in foo.dart should be resolved even though foo.dart's
+    // part declaration for bar.dart refers to a non-existent file.
+    allowMissingFiles = true;
+    addNamedSource('/foo.dart', 'part "bar.dart"; class C {}');
+    serializeLibraryText('import "foo.dart"; C x;');
+    checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'foo.dart', 'C');
+  }
+
+  test_import_of_missing_export() {
+    // Other references in foo.dart should be resolved even though foo.dart's
+    // re-export of bar.dart refers to a non-existent file.
+    allowMissingFiles = true;
+    addNamedSource('/foo.dart', 'export "bar.dart"; class C {}');
+    serializeLibraryText('import "foo.dart"; C x;');
+    checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'foo.dart', 'C');
+  }
+
+  test_import_offset() {
+    String libraryText = '    import "dart:async"; Future x;';
+    serializeLibraryText(libraryText);
+    expect(unlinkedUnits[0].imports[0].offset, libraryText.indexOf('import'));
+    expect(unlinkedUnits[0].imports[0].uriOffset,
+        libraryText.indexOf('"dart:async"'));
+    expect(unlinkedUnits[0].imports[0].uriEnd, libraryText.indexOf('; Future'));
+  }
+
+  test_import_prefix_name() {
+    String libraryText = 'import "dart:async" as a; a.Future x;';
+    serializeLibraryText(libraryText);
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    checkPrefix(unlinkedUnits[0].imports[0].prefixReference, 'a');
+    expect(unlinkedUnits[0].imports[0].prefixOffset, libraryText.indexOf('a;'));
+  }
+
+  test_import_prefix_none() {
+    serializeLibraryText('import "dart:async"; Future x;');
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    expect(unlinkedUnits[0].imports[0].prefixReference, 0);
+  }
+
+  test_import_prefix_not_in_public_namespace() {
+    serializeLibraryText('import "dart:async" as a; a.Future v;');
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'v');
+    expect(unlinkedUnits[0].publicNamespace.names[1].name, 'v=');
+  }
+
+  test_import_prefix_reference() {
+    UnlinkedVariable variable =
+        serializeVariableText('import "dart:async" as a; a.Future v;');
+    checkTypeRef(variable.type, 'dart:async', 'dart:async', 'Future',
+        expectedPrefix: 'a', numTypeParameters: 1);
+  }
+
+  test_import_prefixes_take_precedence_over_imported_names() {
+    addNamedSource('/a.dart', 'class b {} class A');
+    addNamedSource('/b.dart', 'class Cls {}');
+    addNamedSource('/c.dart', 'class Cls {}');
+    addNamedSource('/d.dart', 'class c {} class D');
+    serializeLibraryText('''
+import 'a.dart';
+import 'b.dart' as b;
+import 'c.dart' as c;
+import 'd.dart';
+A aCls;
+b.Cls bCls;
+c.Cls cCls;
+D dCls;
+''');
+    checkTypeRef(findVariable('aCls').type, absUri('/a.dart'), 'a.dart', 'A');
+    checkTypeRef(findVariable('bCls').type, absUri('/b.dart'), 'b.dart', 'Cls',
+        expectedPrefix: 'b');
+    checkTypeRef(findVariable('cCls').type, absUri('/c.dart'), 'c.dart', 'Cls',
+        expectedPrefix: 'c');
+    checkTypeRef(findVariable('dCls').type, absUri('/d.dart'), 'd.dart', 'D');
+  }
+
+  test_import_reference() {
+    UnlinkedVariable variable =
+        serializeVariableText('import "dart:async"; Future v;');
+    checkTypeRef(variable.type, 'dart:async', 'dart:async', 'Future',
+        numTypeParameters: 1);
+  }
+
+  test_import_reference_merged_no_prefix() {
+    serializeLibraryText('''
+import "dart:async" show Future;
+import "dart:async" show Stream;
+
+Future f;
+Stream s;
+''');
+    checkTypeRef(findVariable('f').type, 'dart:async', 'dart:async', 'Future',
+        numTypeParameters: 1);
+    checkTypeRef(findVariable('s').type, 'dart:async', 'dart:async', 'Stream',
+        numTypeParameters: 1);
+  }
+
+  test_import_reference_merged_prefixed() {
+    serializeLibraryText('''
+import "dart:async" as a show Future;
+import "dart:async" as a show Stream;
+
+a.Future f;
+a.Stream s;
+''');
+    checkTypeRef(findVariable('f').type, 'dart:async', 'dart:async', 'Future',
+        expectedPrefix: 'a', numTypeParameters: 1);
+    checkTypeRef(findVariable('s').type, 'dart:async', 'dart:async', 'Stream',
+        expectedPrefix: 'a', numTypeParameters: 1);
+  }
+
+  test_import_reference_merged_prefixed_separate_libraries() {
+    addNamedSource('/a.dart', 'class A {}');
+    addNamedSource('/b.dart', 'class B {}');
+    serializeLibraryText('''
+import 'a.dart' as p;
+import 'b.dart' as p;
+
+p.A a;
+p.B b;
+''');
+    checkTypeRef(findVariable('a').type, absUri('/a.dart'), 'a.dart', 'A',
+        expectedPrefix: 'p');
+    checkTypeRef(findVariable('b').type, absUri('/b.dart'), 'b.dart', 'B',
+        expectedPrefix: 'p');
+  }
+
+  test_import_show_order() {
+    String libraryText =
+        'import "dart:async" show Future, Stream; Future x; Stream y;';
+    serializeLibraryText(libraryText);
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
+    expect(unlinkedUnits[0].imports[0].combinators[0].shows, hasLength(2));
+    expect(unlinkedUnits[0].imports[0].combinators[0].hides, isEmpty);
+    expect(unlinkedUnits[0].imports[0].combinators[0].shows[0], 'Future');
+    expect(unlinkedUnits[0].imports[0].combinators[0].shows[1], 'Stream');
+    expect(unlinkedUnits[0].imports[0].combinators[0].offset,
+        libraryText.indexOf('show'));
+    expect(unlinkedUnits[0].imports[0].combinators[0].end,
+        libraryText.indexOf('; Future'));
+  }
+
+  test_import_uri() {
+    String uriString = '"dart:async"';
+    String libraryText = 'import $uriString; Future x;';
+    serializeLibraryText(libraryText);
+    // Second import is the implicit import of dart:core
+    expect(unlinkedUnits[0].imports, hasLength(2));
+    expect(unlinkedUnits[0].imports[0].uri, 'dart:async');
+  }
+
+  test_inferred_type_refers_to_bound_type_param() {
+    if (!strongMode || skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedClass cls = serializeClassText(
+        'class C<T> extends D<int, T> { var v; }'
+        ' abstract class D<U, V> { Map<V, U> get v; }',
+        className: 'C');
+    EntityRef type = getTypeRefForSlot(cls.fields[0].inferredTypeSlot);
+    // Check that v has inferred type Map<T, int>.
+    checkLinkedTypeRef(type, 'dart:core', 'dart:core', 'Map',
+        allowTypeArguments: true, numTypeParameters: 2);
+    checkParamTypeRef(type.typeArguments[0], 1);
+    checkLinkedTypeRef(type.typeArguments[1], 'dart:core', 'dart:core', 'int');
+  }
+
+  test_inferred_type_refers_to_function_typed_parameter_type_generic_class() {
+    if (!strongMode || skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedClass cls = serializeClassText(
+        'class C<T, U> extends D<U, int> { void f(int x, g) {} }'
+        ' abstract class D<V, W> { void f(int x, W g(V s)); }',
+        className: 'C');
+    EntityRef type =
+        getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
+    // Check that parameter g's inferred type is the type implied by D.f's 1st
+    // (zero-based) parameter.
+    expect(type.implicitFunctionTypeIndices, [1]);
+    expect(type.paramReference, 0);
+    expect(type.typeArguments, hasLength(2));
+    checkParamTypeRef(type.typeArguments[0], 1);
+    checkTypeRef(type.typeArguments[1], 'dart:core', 'dart:core', 'int');
+    expect(type.reference,
+        greaterThanOrEqualTo(unlinkedUnits[0].references.length));
+    LinkedReference linkedReference =
+        linked.units[0].references[type.reference];
+    expect(linkedReference.dependency, 0);
+    expect(linkedReference.kind, ReferenceKind.method);
+    expect(linkedReference.name, 'f');
+    expect(linkedReference.numTypeParameters, 0);
+    expect(linkedReference.unit, 0);
+    expect(linkedReference.containingReference, isNot(0));
+    expect(linkedReference.containingReference, lessThan(type.reference));
+    checkReferenceIndex(linkedReference.containingReference, null, null, 'D',
+        numTypeParameters: 2);
+  }
+
+  test_inferred_type_refers_to_function_typed_parameter_type_other_lib() {
+    if (!strongMode || skipFullyLinkedData) {
+      return;
+    }
+    addNamedSource('/a.dart', 'import "b.dart"; abstract class D extends E {}');
+    addNamedSource(
+        '/b.dart', 'abstract class E { void f(int x, int g(String s)); }');
+    UnlinkedClass cls = serializeClassText(
+        'import "a.dart"; class C extends D { void f(int x, g) {} }');
+    EntityRef type =
+        getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
+    // Check that parameter g's inferred type is the type implied by D.f's 1st
+    // (zero-based) parameter.
+    expect(type.implicitFunctionTypeIndices, [1]);
+    expect(type.paramReference, 0);
+    expect(type.typeArguments, isEmpty);
+    expect(type.reference,
+        greaterThanOrEqualTo(unlinkedUnits[0].references.length));
+    LinkedReference linkedReference =
+        linked.units[0].references[type.reference];
+    expect(linkedReference.dependency, 0);
+    expect(linkedReference.kind, ReferenceKind.method);
+    expect(linkedReference.name, 'f');
+    expect(linkedReference.numTypeParameters, 0);
+    expect(linkedReference.unit, 0);
+    expect(linkedReference.containingReference, isNot(0));
+    expect(linkedReference.containingReference, lessThan(type.reference));
+    checkReferenceIndex(
+        linkedReference.containingReference, absUri('/b.dart'), 'b.dart', 'E');
+  }
+
+  test_inferred_type_refers_to_method_function_typed_parameter_type() {
+    if (!strongMode || skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedClass cls = serializeClassText(
+        'class C extends D { void f(int x, g) {} }'
+        ' abstract class D { void f(int x, int g(String s)); }',
+        className: 'C');
+    EntityRef type =
+        getTypeRefForSlot(cls.executables[0].parameters[1].inferredTypeSlot);
+    // Check that parameter g's inferred type is the type implied by D.f's 1st
+    // (zero-based) parameter.
+    expect(type.implicitFunctionTypeIndices, [1]);
+    expect(type.paramReference, 0);
+    expect(type.typeArguments, isEmpty);
+    expect(type.reference,
+        greaterThanOrEqualTo(unlinkedUnits[0].references.length));
+    LinkedReference linkedReference =
+        linked.units[0].references[type.reference];
+    expect(linkedReference.dependency, 0);
+    expect(linkedReference.kind, ReferenceKind.method);
+    expect(linkedReference.name, 'f');
+    expect(linkedReference.numTypeParameters, 0);
+    expect(linkedReference.unit, 0);
+    expect(linkedReference.containingReference, isNot(0));
+    expect(linkedReference.containingReference, lessThan(type.reference));
+    checkReferenceIndex(linkedReference.containingReference, null, null, 'D');
+  }
+
+  test_inferred_type_refers_to_setter_function_typed_parameter_type() {
+    if (!strongMode || skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedClass cls = serializeClassText(
+        'class C extends D { void set f(g) {} }'
+        ' abstract class D { void set f(int g(String s)); }',
+        className: 'C');
+    EntityRef type =
+        getTypeRefForSlot(cls.executables[0].parameters[0].inferredTypeSlot);
+    // Check that parameter g's inferred type is the type implied by D.f's 1st
+    // (zero-based) parameter.
+    expect(type.implicitFunctionTypeIndices, [0]);
+    expect(type.paramReference, 0);
+    expect(type.typeArguments, isEmpty);
+    expect(type.reference,
+        greaterThanOrEqualTo(unlinkedUnits[0].references.length));
+    LinkedReference linkedReference =
+        linked.units[0].references[type.reference];
+    expect(linkedReference.dependency, 0);
+    expect(linkedReference.kind, ReferenceKind.propertyAccessor);
+    expect(linkedReference.name, 'f=');
+    expect(linkedReference.numTypeParameters, 0);
+    expect(linkedReference.unit, 0);
+    expect(linkedReference.containingReference, isNot(0));
+    expect(linkedReference.containingReference, lessThan(type.reference));
+    checkReferenceIndex(linkedReference.containingReference, null, null, 'D');
+  }
+
+  test_initializer_executable_with_bottom_return_type() {
+    // The synthetic executable for `v` has type `() => Bottom`.
+    UnlinkedVariable variable = serializeVariableText('int v = null;');
+    expect(variable.initializer.returnType, isNull);
+    checkInferredTypeSlot(
+        variable.initializer.inferredReturnTypeSlot, null, null, '*bottom*',
+        onlyInStrongMode: false);
+  }
+
+  test_initializer_executable_with_imported_return_type() {
+    addNamedSource('/a.dart', 'class C { D d; } class D {}');
+    // The synthetic executable for `v` has type `() => D`; `D` is defined in
+    // a library that is imported.  Note: `v` is mis-typed as `int` to prevent
+    // type propagation, which would complicate the test.
+    UnlinkedVariable variable = serializeVariableText(
+        'import "a.dart"; int v = new C().d;',
+        allowErrors: true);
+    expect(variable.initializer.returnType, isNull);
+    checkInferredTypeSlot(variable.initializer.inferredReturnTypeSlot,
+        absUri('/a.dart'), 'a.dart', 'D',
+        onlyInStrongMode: false);
+    checkHasDependency(absUri('/a.dart'), 'a.dart', fullyLinked: false);
+  }
+
+  test_initializer_executable_with_return_type_from_closure() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    // The synthetic executable for `v` has type `() => () => int`, where the
+    // `() => int` part refers to the closure declared inside the initializer
+    // for v.  Note: `v` is mis-typed as `int` to prevent type propagation,
+    // which would complicate the test.
+    UnlinkedVariable variable =
+        serializeVariableText('int v = () => 0;', allowErrors: true);
+    EntityRef closureType =
+        getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
+    checkLinkedTypeRef(closureType, null, null, '',
+        expectedKind: ReferenceKind.function);
+    int initializerIndex =
+        definingUnit.references[closureType.reference].containingReference;
+    checkReferenceIndex(initializerIndex, null, null, '',
+        expectedKind: ReferenceKind.function);
+    int variableIndex =
+        definingUnit.references[initializerIndex].containingReference;
+    checkReferenceIndex(variableIndex, null, null, 'v',
+        expectedKind: ReferenceKind.topLevelPropertyAccessor);
+    expect(definingUnit.references[variableIndex].containingReference, 0);
+  }
+
+  test_initializer_executable_with_return_type_from_closure_field() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    // The synthetic executable for `v` has type `() => () => int`, where the
+    // `() => int` part refers to the closure declared inside the initializer
+    // for v.  Note: `v` is mis-typed as `int` to prevent type propagation,
+    // which would complicate the test.
+    UnlinkedClass cls = serializeClassText(
+        '''
+class C {
+  int v = () => 0;
+}
+''',
+        allowErrors: true);
+    UnlinkedVariable variable = cls.fields[0];
+    EntityRef closureType =
+        getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
+    checkLinkedTypeRef(closureType, null, null, '',
+        expectedKind: ReferenceKind.function);
+    int initializerIndex =
+        definingUnit.references[closureType.reference].containingReference;
+    checkReferenceIndex(initializerIndex, null, null, '',
+        expectedKind: ReferenceKind.function);
+    int variableIndex =
+        definingUnit.references[initializerIndex].containingReference;
+    checkReferenceIndex(variableIndex, null, null, 'v',
+        expectedKind: ReferenceKind.propertyAccessor);
+    int classIndex = definingUnit.references[variableIndex].containingReference;
+    checkReferenceIndex(classIndex, null, null, 'C');
+    expect(definingUnit.references[classIndex].containingReference, 0);
+  }
+
+  test_initializer_executable_with_return_type_from_closure_local() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    // The synthetic executable for `v` has type `() => () => int`, where the
+    // `() => int` part refers to the closure declared inside the initializer
+    // for v.  Note: `v` is mis-typed as `int` to prevent type propagation,
+    // which would complicate the test.
+    UnlinkedExecutable executable = serializeExecutableText(
+        '''
+void f() {
+  int u = 0; // force the variable below to have index 1
+  int v = () => 0;
+}''',
+        allowErrors: true);
+    UnlinkedVariable variable = executable.localVariables[1];
+    EntityRef closureType =
+        getTypeRefForSlot(variable.initializer.inferredReturnTypeSlot);
+    checkLinkedTypeRef(closureType, null, null, '',
+        expectedKind: ReferenceKind.function);
+    int initializerIndex =
+        definingUnit.references[closureType.reference].containingReference;
+    checkReferenceIndex(initializerIndex, null, null, '',
+        expectedKind: ReferenceKind.function);
+    int variableIndex =
+        definingUnit.references[initializerIndex].containingReference;
+    checkReferenceIndex(variableIndex, null, null, 'v',
+        expectedKind: ReferenceKind.variable, localIndex: 1);
+    int topLevelFunctionIndex =
+        definingUnit.references[variableIndex].containingReference;
+    checkReferenceIndex(topLevelFunctionIndex, null, null, 'f',
+        expectedKind: ReferenceKind.topLevelFunction);
+    expect(
+        definingUnit.references[topLevelFunctionIndex].containingReference, 0);
+  }
+
+  test_initializer_executable_with_unimported_return_type() {
+    addNamedSource('/a.dart', 'import "b.dart"; class C { D d; }');
+    addNamedSource('/b.dart', 'class D {}');
+    // The synthetic executable for `v` has type `() => D`; `D` is defined in
+    // a library that is not imported.  Note: `v` is mis-typed as `int` to
+    // prevent type propagation, which would complicate the test.
+    UnlinkedVariable variable = serializeVariableText(
+        'import "a.dart"; int v = new C().d;',
+        allowErrors: true);
+    expect(variable.initializer.returnType, isNull);
+    checkInferredTypeSlot(variable.initializer.inferredReturnTypeSlot,
+        absUri('/b.dart'), 'b.dart', 'D',
+        onlyInStrongMode: false);
+    if (!skipFullyLinkedData) {
+      checkHasDependency(absUri('/b.dart'), 'b.dart', fullyLinked: true);
+    }
+  }
+
+  test_invalid_prefix_dynamic() {
+    if (checkAstDerivedData) {
+      // TODO(paulberry): get this to work properly.
+      return;
+    }
+    checkUnresolvedTypeRef(
+        serializeTypeText('dynamic.T', allowErrors: true), 'dynamic', 'T');
+  }
+
+  test_invalid_prefix_type_parameter() {
+    if (checkAstDerivedData) {
+      // TODO(paulberry): get this to work properly.
+      return;
+    }
+    checkUnresolvedTypeRef(
+        serializeClassText('class C<T> { T.U x; }', allowErrors: true)
+            .fields[0]
+            .type,
+        'T',
+        'U');
+  }
+
+  test_invalid_prefix_void() {
+    if (checkAstDerivedData) {
+      // TODO(paulberry): get this to work properly.
+      return;
+    }
+    checkUnresolvedTypeRef(
+        serializeTypeText('void.T', allowErrors: true), 'void', 'T');
+  }
+
+  test_library_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+library foo;''';
+    serializeLibraryText(text);
+    expect(unlinkedUnits[0].libraryDocumentationComment, isNotNull);
+    checkDocumentationComment(
+        unlinkedUnits[0].libraryDocumentationComment, text);
+  }
+
+  test_library_name_with_spaces() {
+    String text = 'library foo . bar ;';
+    serializeLibraryText(text);
+    expect(unlinkedUnits[0].libraryName, 'foo.bar');
+    expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo . bar'));
+    expect(unlinkedUnits[0].libraryNameLength, 'foo . bar'.length);
+  }
+
+  test_library_named() {
+    String text = 'library foo.bar;';
+    serializeLibraryText(text);
+    expect(unlinkedUnits[0].libraryName, 'foo.bar');
+    expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo.bar'));
+    expect(unlinkedUnits[0].libraryNameLength, 'foo.bar'.length);
+  }
+
+  test_library_unnamed() {
+    serializeLibraryText('');
+    expect(unlinkedUnits[0].libraryName, isEmpty);
+    expect(unlinkedUnits[0].libraryNameOffset, 0);
+    expect(unlinkedUnits[0].libraryNameLength, 0);
+  }
+
+  test_library_with_missing_part() {
+    // References to other parts should still be resolved.
+    allowMissingFiles = true;
+    addNamedSource('/bar.dart', 'part of my.lib; class C {}');
+    serializeLibraryText(
+        'library my.lib; part "foo.dart"; part "bar.dart"; C c;',
+        allowErrors: true);
+    checkTypeRef(findVariable('c').type, null, null, 'C',
+        expectedTargetUnit: 2);
+  }
+
+  test_linked_reference_reuse() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    // When the reference for a linked type is the same as an explicitly
+    // referenced type, the explicit reference should be re-used.
+    addNamedSource('/a.dart', 'class C {}');
+    addNamedSource('/b.dart', 'import "a.dart"; C f() => null;');
+    serializeLibraryText(
+        'import "a.dart"; import "b.dart"; C c1; final c2 = f();');
+    int explicitReference = findVariable('c1').type.reference;
+    expect(getTypeRefForSlot(findVariable('c2').propagatedTypeSlot).reference,
+        explicitReference);
+  }
+
+  test_linked_type_dependency_reuse() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    // When the dependency for a linked type is the same as an explicit
+    // dependency, the explicit dependency should be re-used.
+    addNamedSource('/a.dart', 'class C {} class D {}');
+    addNamedSource('/b.dart', 'import "a.dart"; D f() => null;');
+    serializeLibraryText(
+        'import "a.dart"; import "b.dart"; C c; final d = f();');
+    int cReference = findVariable('c').type.reference;
+    int explicitDependency = linked.units[0].references[cReference].dependency;
+    int dReference =
+        getTypeRefForSlot(findVariable('d').propagatedTypeSlot).reference;
+    expect(
+        linked.units[0].references[dReference].dependency, explicitDependency);
+  }
+
+  test_local_names_take_precedence_over_imported_names() {
+    addNamedSource('/a.dart', 'class C {} class D {}');
+    serializeLibraryText('''
+import 'a.dart';
+class C {}
+C c;
+D d;''');
+    checkTypeRef(findVariable('c').type, null, null, 'C');
+    checkTypeRef(findVariable('d').type, absUri('/a.dart'), 'a.dart', 'D');
+  }
+
+  test_metadata_classDeclaration() {
+    checkAnnotationA(
+        serializeClassText('const a = null; @a class C {}').annotations);
+  }
+
+  test_metadata_classTypeAlias() {
+    checkAnnotationA(serializeClassText(
+            'const a = null; @a class C = D with E; class D {} class E {}',
+            className: 'C')
+        .annotations);
+  }
+
+  test_metadata_constructor_call_named() {
+    UnlinkedClass cls = serializeClassText(
+        'class A { const A.named(); } @A.named() class C {}');
+    expect(cls.annotations, hasLength(1));
+    _assertUnlinkedConst(cls.annotations[0], operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'named',
+              expectedKind: ReferenceKind.constructor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'A')
+              ])
+    ]);
+  }
+
+  test_metadata_constructor_call_named_prefixed() {
+    addNamedSource('/foo.dart', 'class A { const A.named(); }');
+    UnlinkedClass cls = serializeClassText(
+        'import "foo.dart" as foo; @foo.A.named() class C {}');
+    expect(cls.annotations, hasLength(1));
+    _assertUnlinkedConst(cls.annotations[0], operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'named',
+              expectedKind: ReferenceKind.constructor,
+              prefixExpectations: [
+                new _PrefixExpectation(ReferenceKind.classOrEnum, 'A',
+                    absoluteUri: absUri('/foo.dart'), relativeUri: 'foo.dart'),
+                new _PrefixExpectation(ReferenceKind.prefix, 'foo')
+              ])
+    ]);
+  }
+
+  test_metadata_constructor_call_unnamed() {
+    UnlinkedClass cls =
+        serializeClassText('class A { const A(); } @A() class C {}');
+    expect(cls.annotations, hasLength(1));
+    _assertUnlinkedConst(cls.annotations[0], operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'A',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
+  test_metadata_constructor_call_unnamed_prefixed() {
+    addNamedSource('/foo.dart', 'class A { const A(); }');
+    UnlinkedClass cls =
+        serializeClassText('import "foo.dart" as foo; @foo.A() class C {}');
+    expect(cls.annotations, hasLength(1));
+    _assertUnlinkedConst(cls.annotations[0], operators: [
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      0
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, absUri('/foo.dart'), 'foo.dart', 'A',
+          expectedKind: ReferenceKind.classOrEnum, expectedPrefix: 'foo')
+    ]);
+  }
+
+  test_metadata_constructor_call_with_args() {
+    UnlinkedClass cls =
+        serializeClassText('class A { const A(x); } @A(null) class C {}');
+    expect(cls.annotations, hasLength(1));
+    _assertUnlinkedConst(cls.annotations[0], operators: [
+      UnlinkedConstOperation.pushNull,
+      UnlinkedConstOperation.invokeConstructor,
+    ], ints: [
+      0,
+      1
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'A',
+          expectedKind: ReferenceKind.classOrEnum)
+    ]);
+  }
+
+  test_metadata_constructorDeclaration_named() {
+    checkAnnotationA(
+        serializeClassText('const a = null; class C { @a C.named(); }')
+            .executables[0]
+            .annotations);
+  }
+
+  test_metadata_constructorDeclaration_unnamed() {
+    checkAnnotationA(serializeClassText('const a = null; class C { @a C(); }')
+        .executables[0]
+        .annotations);
+  }
+
+  test_metadata_enumDeclaration() {
+    checkAnnotationA(
+        serializeEnumText('const a = null; @a enum E { v }').annotations);
+  }
+
+  test_metadata_exportDirective() {
+    addNamedSource('/foo.dart', '');
+    serializeLibraryText('@a export "foo.dart"; const a = null;');
+    checkAnnotationA(unlinkedUnits[0].exports[0].annotations);
+  }
+
+  test_metadata_fieldDeclaration() {
+    checkAnnotationA(serializeClassText('const a = null; class C { @a int x; }')
+        .fields[0]
+        .annotations);
+  }
+
+  test_metadata_fieldFormalParameter() {
+    checkAnnotationA(
+        serializeClassText('const a = null; class C { var x; C(@a this.x); }')
+            .executables[0]
+            .parameters[0]
+            .annotations);
+  }
+
+  test_metadata_fieldFormalParameter_withDefault() {
+    checkAnnotationA(serializeClassText(
+            'const a = null; class C { var x; C([@a this.x = null]); }')
+        .executables[0]
+        .parameters[0]
+        .annotations);
+  }
+
+  test_metadata_functionDeclaration_function() {
+    checkAnnotationA(
+        serializeExecutableText('const a = null; @a f() {}').annotations);
+  }
+
+  test_metadata_functionDeclaration_getter() {
+    checkAnnotationA(
+        serializeExecutableText('const a = null; @a get f => null;')
+            .annotations);
+  }
+
+  test_metadata_functionDeclaration_setter() {
+    checkAnnotationA(serializeExecutableText(
+            'const a = null; @a set f(value) {}',
+            executableName: 'f=')
+        .annotations);
+  }
+
+  test_metadata_functionTypeAlias() {
+    checkAnnotationA(
+        serializeTypedefText('const a = null; @a typedef F();').annotations);
+  }
+
+  test_metadata_functionTypedFormalParameter() {
+    checkAnnotationA(serializeExecutableText('const a = null; f(@a g()) {}')
+        .parameters[0]
+        .annotations);
+  }
+
+  test_metadata_functionTypedFormalParameter_withDefault() {
+    checkAnnotationA(
+        serializeExecutableText('const a = null; f([@a g() = null]) {}')
+            .parameters[0]
+            .annotations);
+  }
+
+  test_metadata_importDirective() {
+    addNamedSource('/foo.dart', 'const b = null;');
+    serializeLibraryText('@a import "foo.dart"; const a = b;');
+    checkAnnotationA(unlinkedUnits[0].imports[0].annotations);
+  }
+
+  test_metadata_libraryDirective() {
+    serializeLibraryText('@a library L; const a = null;');
+    checkAnnotationA(unlinkedUnits[0].libraryAnnotations);
+  }
+
+  test_metadata_methodDeclaration_getter() {
+    checkAnnotationA(
+        serializeClassText('const a = null; class C { @a get m => null; }')
+            .executables[0]
+            .annotations);
+  }
+
+  test_metadata_methodDeclaration_method() {
+    checkAnnotationA(serializeClassText('const a = null; class C { @a m() {} }')
+        .executables[0]
+        .annotations);
+  }
+
+  test_metadata_methodDeclaration_setter() {
+    checkAnnotationA(
+        serializeClassText('const a = null; class C { @a set m(value) {} }')
+            .executables[0]
+            .annotations);
+  }
+
+  test_metadata_multiple_annotations() {
+    UnlinkedClass cls =
+        serializeClassText('const a = null, b = null; @a @b class C {}');
+    List<UnlinkedConst> annotations = cls.annotations;
+    expect(annotations, hasLength(2));
+    _assertUnlinkedConst(annotations[0], operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'a',
+          expectedKind: ReferenceKind.topLevelPropertyAccessor)
+    ]);
+    _assertUnlinkedConst(annotations[1], operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, null, null, 'b',
+          expectedKind: ReferenceKind.topLevelPropertyAccessor)
+    ]);
+  }
+
+  test_metadata_partDirective() {
+    addNamedSource('/foo.dart', 'part of L;');
+    serializeLibraryText('library L; @a part "foo.dart"; const a = null;');
+    checkAnnotationA(unlinkedUnits[0].parts[0].annotations);
+  }
+
+  test_metadata_prefixed_variable() {
+    addNamedSource('/a.dart', 'const b = null;');
+    UnlinkedClass cls =
+        serializeClassText('import "a.dart" as a; @a.b class C {}');
+    expect(cls.annotations, hasLength(1));
+    _assertUnlinkedConst(cls.annotations[0], operators: [
+      UnlinkedConstOperation.pushReference
+    ], referenceValidators: [
+      (EntityRef r) => checkTypeRef(r, absUri('/a.dart'), 'a.dart', 'b',
+          expectedKind: ReferenceKind.topLevelPropertyAccessor,
+          expectedPrefix: 'a')
+    ]);
+  }
+
+  test_metadata_simpleFormalParameter() {
+    checkAnnotationA(serializeExecutableText('const a = null; f(@a x) {}')
+        .parameters[0]
+        .annotations);
+  }
+
+  test_metadata_simpleFormalParameter_withDefault() {
+    checkAnnotationA(
+        serializeExecutableText('const a = null; f([@a x = null]) {}')
+            .parameters[0]
+            .annotations);
+  }
+
+  test_metadata_topLevelVariableDeclaration() {
+    checkAnnotationA(
+        serializeVariableText('const a = null; @a int v;').annotations);
+  }
+
+  test_metadata_typeParameter_ofClass() {
+    checkAnnotationA(serializeClassText('const a = null; class C<@a T> {}')
+        .typeParameters[0]
+        .annotations);
+  }
+
+  test_metadata_typeParameter_ofClassTypeAlias() {
+    checkAnnotationA(serializeClassText(
+            'const a = null; class C<@a T> = D with E; class D {} class E {}',
+            className: 'C')
+        .typeParameters[0]
+        .annotations);
+  }
+
+  test_metadata_typeParameter_ofFunction() {
+    checkAnnotationA(serializeExecutableText('const a = null; f<@a T>() {}')
+        .typeParameters[0]
+        .annotations);
+  }
+
+  test_metadata_typeParameter_ofTypedef() {
+    checkAnnotationA(serializeTypedefText('const a = null; typedef F<@a T>();')
+        .typeParameters[0]
+        .annotations);
+  }
+
+  test_method_documented() {
+    String text = '''
+class C {
+  /**
+   * Docs
+   */
+  f() {}
+}''';
+    UnlinkedExecutable executable = serializeClassText(text).executables[0];
+    expect(executable.documentationComment, isNotNull);
+    checkDocumentationComment(executable.documentationComment, text);
+  }
+
+  test_method_inferred_type_nonstatic_explicit_param() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { void f(num value) {} }'
+            ' abstract class D { void f(int value); }',
+            className: 'C')
+        .executables[0];
+    expect(f.parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_method_inferred_type_nonstatic_explicit_return() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { num f() => null; } abstract class D { int f(); }',
+            className: 'C',
+            allowErrors: true)
+        .executables[0];
+    expect(f.inferredReturnTypeSlot, 0);
+  }
+
+  test_method_inferred_type_nonstatic_implicit_param() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { void f(value) {} }'
+            ' abstract class D { void f(int value); }',
+            className: 'C')
+        .executables[0];
+    checkInferredTypeSlot(
+        f.parameters[0].inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_method_inferred_type_nonstatic_implicit_return() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { f() => null; } abstract class D { int f(); }',
+            className: 'C')
+        .executables[0];
+    checkInferredTypeSlot(
+        f.inferredReturnTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_method_inferred_type_static_implicit_param() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { static void f(value) {} }'
+            ' class D { static void f(int value) {} }',
+            className: 'C')
+        .executables[0];
+    expect(f.parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_method_inferred_type_static_implicit_return() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { static f() => null; }'
+            ' class D { static int f() => null; }',
+            className: 'C')
+        .executables[0];
+    expect(f.inferredReturnTypeSlot, 0);
+  }
+
+  test_nested_generic_functions() {
+    UnlinkedExecutable executable = serializeExecutableText('''
+void f<T, U>() {
+  void g<V, W>() {
+    void h<X, Y>() {
+      T t;
+      U u;
+      V v;
+      W w;
+      X x;
+      Y y;
+    }
+  }
+}
+''');
+    expect(executable.typeParameters, hasLength(2));
+    expect(executable.localFunctions[0].typeParameters, hasLength(2));
+    expect(executable.localFunctions[0].localFunctions[0].typeParameters,
+        hasLength(2));
+    List<UnlinkedVariable> localVariables =
+        executable.localFunctions[0].localFunctions[0].localVariables;
+    checkParamTypeRef(findVariable('t', variables: localVariables).type, 6);
+    checkParamTypeRef(findVariable('u', variables: localVariables).type, 5);
+    checkParamTypeRef(findVariable('v', variables: localVariables).type, 4);
+    checkParamTypeRef(findVariable('w', variables: localVariables).type, 3);
+    checkParamTypeRef(findVariable('x', variables: localVariables).type, 2);
+    checkParamTypeRef(findVariable('y', variables: localVariables).type, 1);
+  }
+
+  test_nested_generic_functions_in_generic_class() {
+    UnlinkedClass cls = serializeClassText('''
+class C<T, U> {
+  void g<V, W>() {
+    void h<X, Y>() {
+      T t;
+      U u;
+      V v;
+      W w;
+      X x;
+      Y y;
+    }
+  }
+}
+''');
+    expect(cls.typeParameters, hasLength(2));
+    expect(cls.executables[0].typeParameters, hasLength(2));
+    expect(cls.executables[0].localFunctions[0].typeParameters, hasLength(2));
+    List<UnlinkedVariable> localVariables =
+        cls.executables[0].localFunctions[0].localVariables;
+    checkParamTypeRef(findVariable('t', variables: localVariables).type, 6);
+    checkParamTypeRef(findVariable('u', variables: localVariables).type, 5);
+    checkParamTypeRef(findVariable('v', variables: localVariables).type, 4);
+    checkParamTypeRef(findVariable('w', variables: localVariables).type, 3);
+    checkParamTypeRef(findVariable('x', variables: localVariables).type, 2);
+    checkParamTypeRef(findVariable('y', variables: localVariables).type, 1);
+  }
+
+  test_parameter_visibleRange_abstractMethod() {
+    UnlinkedExecutable m = findExecutable('m',
+        executables:
+            serializeClassText('abstract class C { m(p); }').executables,
+        failIfAbsent: true);
+    _assertParameterZeroVisibleRange(m.parameters[0]);
+  }
+
+  test_parameter_visibleRange_function_blockBody() {
+    String text = r'''
+f(x) { // 1
+  f2(y) { // 2
+  } // 3
+} // 4
+''';
+    UnlinkedExecutable f = serializeExecutableText(text);
+    UnlinkedExecutable f2 = f.localFunctions[0];
+    _assertParameterVisible(text, f.parameters[0], '{ // 1', '} // 4');
+    _assertParameterVisible(text, f2.parameters[0], '{ // 2', '} // 3');
+  }
+
+  test_parameter_visibleRange_function_emptyBody() {
+    UnlinkedExecutable f = serializeExecutableText('external f(x);');
+    _assertParameterZeroVisibleRange(f.parameters[0]);
+  }
+
+  test_parameter_visibleRange_function_expressionBody() {
+    String text = r'''
+f(x) => 42;
+''';
+    UnlinkedExecutable f = serializeExecutableText(text);
+    _assertParameterVisible(text, f.parameters[0], '=>', ';');
+  }
+
+  test_parameter_visibleRange_inFunctionTypedParameter() {
+    String text = 'f(g(p)) {}';
+    UnlinkedExecutable f = serializeExecutableText(text);
+    UnlinkedParam g = f.parameters[0];
+    UnlinkedParam p = g.parameters[0];
+    expect(g.name, 'g');
+    expect(p.name, 'p');
+    _assertParameterVisible(text, g, '{', '}');
+    _assertParameterZeroVisibleRange(p);
+  }
+
+  test_parameter_visibleRange_typedef() {
+    UnlinkedTypedef type = serializeTypedefText('typedef F(x);');
+    _assertParameterZeroVisibleRange(type.parameters[0]);
+  }
+
+  test_part_declaration() {
+    addNamedSource('/a.dart', 'part of my.lib;');
+    String text = 'library my.lib; part "a.dart"; // <-part';
+    serializeLibraryText(text);
+    expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.parts[0], 'a.dart');
+    expect(unlinkedUnits[0].parts, hasLength(1));
+    expect(unlinkedUnits[0].parts[0].uriOffset, text.indexOf('"a.dart"'));
+    expect(unlinkedUnits[0].parts[0].uriEnd, text.indexOf('; // <-part'));
+  }
+
+  test_parts_defining_compilation_unit() {
+    serializeLibraryText('');
+    expect(linked.units, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.parts, isEmpty);
+  }
+
+  test_parts_included() {
+    addNamedSource('/part1.dart', 'part of my.lib;');
+    String partString = '"part1.dart"';
+    String libraryText = 'library my.lib; part $partString;';
+    serializeLibraryText(libraryText);
+    expect(linked.units, hasLength(2));
+    expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
+    expect(unlinkedUnits[0].publicNamespace.parts[0], 'part1.dart');
+  }
+
+  test_public_namespace_of_part() {
+    addNamedSource('/a.dart', 'part of foo; class C {}');
+    serializeLibraryText('library foo; part "a.dart";');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+    expect(unlinkedUnits[1].publicNamespace.names, hasLength(1));
+    expect(unlinkedUnits[1].publicNamespace.names[0].name, 'C');
+  }
+
+  test_setter_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+void set f(value) {}''';
+    UnlinkedExecutable executable =
+        serializeExecutableText(text, executableName: 'f=');
+    expect(executable.documentationComment, isNotNull);
+    checkDocumentationComment(executable.documentationComment, text);
+  }
+
+  test_setter_inferred_type_nonstatic_explicit_param() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { void set f(num value) {} }'
+            ' abstract class D { void set f(int value); }',
+            className: 'C')
+        .executables[0];
+    expect(f.parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_setter_inferred_type_nonstatic_explicit_return() {
+    UnlinkedExecutable f =
+        serializeClassText('class C { void set f(int value) {} }').executables[
+            0];
+    expect(f.inferredReturnTypeSlot, 0);
+  }
+
+  test_setter_inferred_type_nonstatic_implicit_param() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { void set f(value) {} }'
+            ' abstract class D { void set f(int value); }',
+            className: 'C')
+        .executables[0];
+    checkInferredTypeSlot(
+        f.parameters[0].inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_setter_inferred_type_nonstatic_implicit_return() {
+    UnlinkedExecutable f =
+        serializeClassText('class C { set f(int value) {} }').executables[0];
+    checkInferredTypeSlot(f.inferredReturnTypeSlot, null, null, 'void');
+  }
+
+  test_setter_inferred_type_static_implicit_param() {
+    UnlinkedExecutable f = serializeClassText(
+            'class C extends D { static void set f(value) {} }'
+            ' class D { static void set f(int value) {} }',
+            className: 'C')
+        .executables[0];
+    expect(f.parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_setter_inferred_type_static_implicit_return() {
+    UnlinkedExecutable f =
+        serializeClassText('class C { static set f(int value) {} }')
+            .executables[0];
+    expect(f.inferredReturnTypeSlot, 0);
+  }
+
+  test_setter_inferred_type_top_level_implicit_param() {
+    UnlinkedExecutable f =
+        serializeExecutableText('void set f(value) {}', executableName: 'f=');
+    expect(f.parameters[0].inferredTypeSlot, 0);
+  }
+
+  test_setter_inferred_type_top_level_implicit_return() {
+    UnlinkedExecutable f =
+        serializeExecutableText('set f(int value) {}', executableName: 'f=');
+    expect(f.inferredReturnTypeSlot, 0);
+  }
+
+  test_slot_reuse() {
+    // Different compilation units have independent notions of slot id, so slot
+    // ids should be reused.
+    addNamedSource('/a.dart', 'part of foo; final v = 0;');
+    serializeLibraryText('library foo; part "a.dart"; final w = 0;');
+    expect(unlinkedUnits[0].variables[0].propagatedTypeSlot, 1);
+    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',
+        allowTypeParameters: true, numTypeParameters: 1);
+    expect(typeRef.typeArguments, hasLength(1));
+    checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
+  }
+
+  test_type_arguments_explicit_dynamic() {
+    EntityRef typeRef = serializeTypeText('List<dynamic>');
+    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
+        allowTypeParameters: true, numTypeParameters: 1);
+    expect(typeRef.typeArguments, isEmpty);
+  }
+
+  test_type_arguments_explicit_dynamic_dynamic() {
+    EntityRef typeRef = serializeTypeText('Map<dynamic, dynamic>');
+    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+        allowTypeParameters: true, numTypeParameters: 2);
+    // Trailing type arguments of type `dynamic` are omitted.
+    expect(typeRef.typeArguments, isEmpty);
+  }
+
+  test_type_arguments_explicit_dynamic_int() {
+    EntityRef typeRef = serializeTypeText('Map<dynamic, int>');
+    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+        allowTypeParameters: true, numTypeParameters: 2);
+    // Leading type arguments of type `dynamic` are not omitted.
+    expect(typeRef.typeArguments.length, 2);
+    checkDynamicTypeRef(typeRef.typeArguments[0]);
+    checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'dart:core', 'int');
+  }
+
+  test_type_arguments_explicit_dynamic_typedef() {
+    EntityRef typeRef =
+        serializeTypeText('F<dynamic>', otherDeclarations: 'typedef T F<T>();');
+    checkTypeRef(typeRef, null, null, 'F',
+        allowTypeParameters: true,
+        expectedKind: ReferenceKind.typedef,
+        numTypeParameters: 1);
+    expect(typeRef.typeArguments, isEmpty);
+  }
+
+  test_type_arguments_explicit_String_dynamic() {
+    EntityRef typeRef = serializeTypeText('Map<String, dynamic>');
+    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+        allowTypeParameters: true, numTypeParameters: 2);
+    // Trailing type arguments of type `dynamic` are omitted.
+    expect(typeRef.typeArguments.length, 1);
+    checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'String');
+  }
+
+  test_type_arguments_explicit_String_int() {
+    EntityRef typeRef = serializeTypeText('Map<String, int>');
+    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+        allowTypeParameters: true, numTypeParameters: 2);
+    expect(typeRef.typeArguments.length, 2);
+    checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'String');
+    checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'dart:core', 'int');
+  }
+
+  test_type_arguments_explicit_typedef() {
+    EntityRef typeRef =
+        serializeTypeText('F<int>', otherDeclarations: 'typedef T F<T>();');
+    checkTypeRef(typeRef, null, null, 'F',
+        allowTypeParameters: true,
+        expectedKind: ReferenceKind.typedef,
+        numTypeParameters: 1);
+    expect(typeRef.typeArguments, hasLength(1));
+    checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
+  }
+
+  test_type_arguments_implicit() {
+    EntityRef typeRef = serializeTypeText('List');
+    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
+        allowTypeParameters: true, numTypeParameters: 1);
+    expect(typeRef.typeArguments, isEmpty);
+  }
+
+  test_type_arguments_implicit_typedef() {
+    EntityRef typeRef =
+        serializeTypeText('F', otherDeclarations: 'typedef T F<T>();');
+    checkTypeRef(typeRef, null, null, 'F',
+        allowTypeParameters: true,
+        expectedKind: ReferenceKind.typedef,
+        numTypeParameters: 1);
+    expect(typeRef.typeArguments, isEmpty);
+  }
+
+  test_type_arguments_order() {
+    EntityRef typeRef = serializeTypeText('Map<int, Object>');
+    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
+        allowTypeParameters: true, numTypeParameters: 2);
+    expect(typeRef.typeArguments, hasLength(2));
+    checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
+    checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'dart:core', 'Object');
+  }
+
+  test_type_dynamic() {
+    checkDynamicTypeRef(serializeTypeText('dynamic'));
+  }
+
+  test_type_param_not_shadowed_by_constructor() {
+    UnlinkedClass cls =
+        serializeClassText('class C<D> { D x; C.D(); } class D {}');
+    checkParamTypeRef(cls.fields[0].type, 1);
+  }
+
+  test_type_param_not_shadowed_by_field_in_extends() {
+    UnlinkedClass cls =
+        serializeClassText('class C<T> extends D<T> { T x; } class D<T> {}');
+    checkParamTypeRef(cls.supertype.typeArguments[0], 1);
+  }
+
+  test_type_param_not_shadowed_by_field_in_implements() {
+    UnlinkedClass cls =
+        serializeClassText('class C<T> implements D<T> { T x; } class D<T> {}');
+    checkParamTypeRef(cls.interfaces[0].typeArguments[0], 1);
+  }
+
+  test_type_param_not_shadowed_by_field_in_with() {
+    UnlinkedClass cls = serializeClassText(
+        'class C<T> extends Object with D<T> { T x; } class D<T> {}');
+    checkParamTypeRef(cls.mixins[0].typeArguments[0], 1);
+  }
+
+  test_type_param_not_shadowed_by_method_parameter() {
+    UnlinkedClass cls = serializeClassText('class C<T> { f(int T, T x) {} }');
+    checkParamTypeRef(cls.executables[0].parameters[1].type, 1);
+  }
+
+  test_type_param_not_shadowed_by_setter() {
+    // The code under test should not produce a compile-time error, but it
+    // does.
+    bool workAroundBug25525 = true;
+    UnlinkedClass cls = serializeClassText(
+        'class C<D> { D x; void set D(value) {} } class D {}',
+        allowErrors: workAroundBug25525);
+    checkParamTypeRef(cls.fields[0].type, 1);
+  }
+
+  test_type_param_not_shadowed_by_typedef_parameter() {
+    UnlinkedTypedef typedef =
+        serializeTypedefText('typedef void F<T>(int T, T x);');
+    checkParamTypeRef(typedef.parameters[1].type, 1);
+  }
+
+  test_type_param_shadowed_by_field() {
+    UnlinkedClass cls = serializeClassText(
+        'class C<D> { D x; int D; } class D {}',
+        allowErrors: true);
+    checkDynamicTypeRef(cls.fields[0].type);
+  }
+
+  test_type_param_shadowed_by_getter() {
+    UnlinkedClass cls = serializeClassText(
+        'class C<D> { D x; int get D => null; } class D {}',
+        allowErrors: true);
+    checkDynamicTypeRef(cls.fields[0].type);
+  }
+
+  test_type_param_shadowed_by_method() {
+    UnlinkedClass cls = serializeClassText(
+        'class C<D> { D x; void D() {} } class D {}',
+        allowErrors: true);
+    checkDynamicTypeRef(cls.fields[0].type);
+  }
+
+  test_type_param_shadowed_by_type_param() {
+    UnlinkedClass cls =
+        serializeClassText('class C<T> { T f<T>(T x) => null; }');
+    checkParamTypeRef(cls.executables[0].returnType, 1);
+    checkParamTypeRef(cls.executables[0].parameters[0].type, 1);
+  }
+
+  test_type_reference_from_part() {
+    addNamedSource('/a.dart', 'part of foo; C v;');
+    serializeLibraryText('library foo; part "a.dart"; class C {}');
+    checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
+        null, null, 'C',
+        expectedKind: ReferenceKind.classOrEnum,
+        linkedSourceUnit: linked.units[1],
+        unlinkedSourceUnit: unlinkedUnits[1]);
+  }
+
+  test_type_reference_from_part_withPrefix() {
+    addNamedSource('/a.dart', 'class C {}');
+    addNamedSource('/p.dart', 'part of foo; a.C v;');
+    serializeLibraryText(
+        'library foo; import "a.dart"; import "a.dart" as a; part "p.dart";',
+        allowErrors: true);
+    checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
+        absUri('/a.dart'), 'a.dart', 'C',
+        expectedPrefix: 'a',
+        linkedSourceUnit: linked.units[1],
+        unlinkedSourceUnit: unlinkedUnits[1]);
+  }
+
+  test_type_reference_to_class_argument() {
+    UnlinkedClass cls = serializeClassText('class C<T, U> { T t; U u; }');
+    {
+      EntityRef typeRef =
+          findVariable('t', variables: cls.fields, failIfAbsent: true).type;
+      checkParamTypeRef(typeRef, 2);
+    }
+    {
+      EntityRef typeRef =
+          findVariable('u', variables: cls.fields, failIfAbsent: true).type;
+      checkParamTypeRef(typeRef, 1);
+    }
+  }
+
+  test_type_reference_to_import_of_export() {
+    addNamedSource('/a.dart', 'library a; export "b.dart";');
+    addNamedSource('/b.dart', 'library b; class C {}');
+    checkTypeRef(serializeTypeText('C', otherDeclarations: 'import "a.dart";'),
+        absUri('/b.dart'), 'b.dart', 'C');
+  }
+
+  test_type_reference_to_import_of_export_via_prefix() {
+    addNamedSource('/a.dart', 'library a; export "b.dart";');
+    addNamedSource('/b.dart', 'library b; class C {}');
+    checkTypeRef(
+        serializeTypeText('p.C', otherDeclarations: 'import "a.dart" as p;'),
+        absUri('/b.dart'),
+        'b.dart',
+        'C',
+        expectedPrefix: 'p');
+  }
+
+  test_type_reference_to_imported_part() {
+    addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
+    addNamedSource('/b.dart', 'part of my.lib; class C {}');
+    checkTypeRef(
+        serializeTypeText('C',
+            otherDeclarations: 'library my.lib; import "a.dart";'),
+        absUri('/a.dart'),
+        'a.dart',
+        'C',
+        expectedTargetUnit: 1);
+  }
+
+  test_type_reference_to_imported_part_with_prefix() {
+    addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
+    addNamedSource('/b.dart', 'part of my.lib; class C {}');
+    checkTypeRef(
+        serializeTypeText('p.C',
+            otherDeclarations: 'library my.lib; import "a.dart" as p;'),
+        absUri('/a.dart'),
+        'a.dart',
+        'C',
+        expectedPrefix: 'p',
+        expectedTargetUnit: 1);
+  }
+
+  test_type_reference_to_internal_class() {
+    checkTypeRef(serializeTypeText('C', otherDeclarations: 'class C {}'), null,
+        null, 'C');
+  }
+
+  test_type_reference_to_internal_class_alias() {
+    checkTypeRef(
+        serializeTypeText('C',
+            otherDeclarations: 'class C = D with E; class D {} class E {}'),
+        null,
+        null,
+        'C');
+  }
+
+  test_type_reference_to_internal_enum() {
+    checkTypeRef(serializeTypeText('E', otherDeclarations: 'enum E { value }'),
+        null, null, 'E');
+  }
+
+  test_type_reference_to_local_part() {
+    addNamedSource('/a.dart', 'part of my.lib; class C {}');
+    checkTypeRef(
+        serializeTypeText('C',
+            otherDeclarations: 'library my.lib; part "a.dart";'),
+        null,
+        null,
+        'C',
+        expectedTargetUnit: 1);
+  }
+
+  test_type_reference_to_nonexistent_file_via_prefix() {
+    if (!checkAstDerivedData) {
+      // TODO(paulberry): this test currently fails because there is not enough
+      // information in the element model to figure out that the unresolved
+      // reference `p.C` uses the prefix `p`.
+      return;
+    }
+    allowMissingFiles = true;
+    EntityRef typeRef = serializeTypeText('p.C',
+        otherDeclarations: 'import "foo.dart" as p;', allowErrors: true);
+    checkUnresolvedTypeRef(typeRef, 'p', 'C');
+  }
+
+  test_type_reference_to_part() {
+    addNamedSource('/a.dart', 'part of foo; class C { C(); }');
+    serializeLibraryText('library foo; part "a.dart"; C c;');
+    checkTypeRef(unlinkedUnits[0].variables.single.type, null, null, 'C',
+        expectedKind: ReferenceKind.classOrEnum, expectedTargetUnit: 1);
+  }
+
+  test_type_reference_to_type_visible_via_multiple_import_prefixes() {
+    if (!checkAstDerivedData) {
+      // TODO(paulberry): this test currently fails because the element model
+      // doesn't record enough information to track which prefix is used to
+      // refer to a type.
+      return;
+    }
+    addNamedSource('/lib1.dart', 'class C');
+    addNamedSource('/lib2.dart', 'export "lib1.dart";');
+    addNamedSource('/lib3.dart', 'export "lib1.dart";');
+    addNamedSource('/lib4.dart', 'export "lib1.dart";');
+    serializeLibraryText('''
+import 'lib2.dart';
+import 'lib3.dart' as a;
+import 'lib4.dart' as b;
+C c2;
+a.C c3;
+b.C c4;''');
+    // Note: it is important that each reference to class C records the prefix
+    // used to find it; otherwise it's possible that relinking might produce an
+    // incorrect result after a change to lib2.dart, lib3.dart, or lib4.dart.
+    checkTypeRef(
+        findVariable('c2').type, absUri('/lib1.dart'), 'lib1.dart', 'C');
+    checkTypeRef(
+        findVariable('c3').type, absUri('/lib1.dart'), 'lib1.dart', 'C',
+        expectedPrefix: 'a');
+    checkTypeRef(
+        findVariable('c4').type, absUri('/lib1.dart'), 'lib1.dart', 'C',
+        expectedPrefix: 'b');
+  }
+
+  test_type_reference_to_typedef() {
+    checkTypeRef(serializeTypeText('F', otherDeclarations: 'typedef void F();'),
+        null, null, 'F',
+        expectedKind: ReferenceKind.typedef);
+  }
+
+  test_type_unit_counts_unreferenced_units() {
+    addNamedSource('/a.dart', 'library a; part "b.dart"; part "c.dart";');
+    addNamedSource('/b.dart', 'part of a;');
+    addNamedSource('/c.dart', 'part of a; class C {}');
+    EntityRef typeRef =
+        serializeTypeText('C', otherDeclarations: 'import "a.dart";');
+    // The referenced unit should be 2, since unit 0 is a.dart and unit 1 is
+    // b.dart.  a.dart and b.dart are counted even though nothing is imported
+    // from them.
+    checkTypeRef(typeRef, absUri('/a.dart'), 'a.dart', 'C',
+        expectedTargetUnit: 2);
+  }
+
+  test_type_unresolved() {
+    EntityRef typeRef = serializeTypeText('Foo', allowErrors: true);
+    checkUnresolvedTypeRef(typeRef, null, 'Foo');
+  }
+
+  test_typedef_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+typedef F();''';
+    UnlinkedTypedef typedef = serializeTypedefText(text);
+    expect(typedef.documentationComment, isNotNull);
+    checkDocumentationComment(typedef.documentationComment, text);
+  }
+
+  test_typedef_name() {
+    String text = 'typedef F();';
+    UnlinkedTypedef type = serializeTypedefText(text);
+    expect(type.name, 'F');
+    expect(type.nameOffset, text.indexOf('F'));
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
+    expect(
+        unlinkedUnits[0].publicNamespace.names[0].kind, ReferenceKind.typedef);
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'F');
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+  }
+
+  test_typedef_param_none() {
+    UnlinkedTypedef type = serializeTypedefText('typedef F();');
+    expect(type.parameters, isEmpty);
+  }
+
+  test_typedef_param_order() {
+    UnlinkedTypedef type = serializeTypedefText('typedef F(x, y);');
+    expect(type.parameters, hasLength(2));
+    expect(type.parameters[0].name, 'x');
+    expect(type.parameters[1].name, 'y');
+  }
+
+  test_typedef_private() {
+    serializeTypedefText('typedef _F();', '_F');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+  }
+
+  test_typedef_reference_generic() {
+    EntityRef typeRef =
+        serializeTypeText('F', otherDeclarations: 'typedef void F<A, B>();');
+    checkTypeRef(typeRef, null, null, 'F',
+        numTypeParameters: 2, expectedKind: ReferenceKind.typedef);
+  }
+
+  test_typedef_reference_generic_imported() {
+    addNamedSource('/lib.dart', 'typedef void F<A, B>();');
+    EntityRef typeRef =
+        serializeTypeText('F', otherDeclarations: 'import "lib.dart";');
+    checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'F',
+        numTypeParameters: 2, expectedKind: ReferenceKind.typedef);
+  }
+
+  test_typedef_return_type_explicit() {
+    UnlinkedTypedef type = serializeTypedefText('typedef int F();');
+    checkTypeRef(type.returnType, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_typedef_type_param_in_parameter() {
+    UnlinkedTypedef type = serializeTypedefText('typedef F<T>(T t);');
+    checkParamTypeRef(type.parameters[0].type, 1);
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
+  }
+
+  test_typedef_type_param_in_return_type() {
+    UnlinkedTypedef type = serializeTypedefText('typedef T F<T>();');
+    checkParamTypeRef(type.returnType, 1);
+  }
+
+  test_typedef_type_param_none() {
+    UnlinkedTypedef type = serializeTypedefText('typedef F();');
+    expect(type.typeParameters, isEmpty);
+  }
+
+  test_typedef_type_param_order() {
+    UnlinkedTypedef type = serializeTypedefText('typedef F<T, U>();');
+    expect(type.typeParameters, hasLength(2));
+    expect(type.typeParameters[0].name, 'T');
+    expect(type.typeParameters[1].name, 'U');
+  }
+
+  test_unresolved_reference_in_multiple_parts() {
+    addNamedSource('/a.dart', 'part of foo; int x; Unresolved y;');
+    serializeLibraryText('library foo; part "a.dart"; Unresolved z;',
+        allowErrors: true);
+    // The unresolved types in the defining compilation unit and the part
+    // should both work correctly even though they use different reference
+    // indices.
+    checkUnresolvedTypeRef(
+        unlinkedUnits[0].variables[0].type, null, 'Unresolved');
+    checkUnresolvedTypeRef(
+        unlinkedUnits[1].variables[1].type, null, 'Unresolved',
+        linkedSourceUnit: linked.units[1],
+        unlinkedSourceUnit: unlinkedUnits[1]);
+  }
+
+  test_unresolved_reference_shared() {
+    // Both `x` and `y` use unresolved identifier `C` as their type.  Verify
+    // that they both use the same unresolved reference.
+    serializeLibraryText('C x; C y;', allowErrors: true);
+    EntityRef xType = findVariable('x').type;
+    EntityRef yType = findVariable('y').type;
+    expect(xType.reference, yType.reference);
+  }
+
+  test_variable() {
+    String text = 'int i;';
+    UnlinkedVariable v = serializeVariableText(text, variableName: 'i');
+    expect(v.nameOffset, text.indexOf('i;'));
+    expect(findExecutable('i'), isNull);
+    expect(findExecutable('i='), isNull);
+    expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
+    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
+        ReferenceKind.topLevelPropertyAccessor);
+    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'i');
+    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
+    expect(unlinkedUnits[0].publicNamespace.names[1].kind,
+        ReferenceKind.topLevelPropertyAccessor);
+    expect(unlinkedUnits[0].publicNamespace.names[1].name, 'i=');
+    expect(unlinkedUnits[0].publicNamespace.names[1].numTypeParameters, 0);
+  }
+
+  test_variable_const() {
+    UnlinkedVariable variable =
+        serializeVariableText('const int i = 0;', variableName: 'i');
+    expect(variable.isConst, isTrue);
+  }
+
+  test_variable_documented() {
+    String text = '''
+// Extra comment so doc comment offset != 0
+/**
+ * Docs
+ */
+var v;''';
+    UnlinkedVariable variable = serializeVariableText(text);
+    expect(variable.documentationComment, isNotNull);
+    checkDocumentationComment(variable.documentationComment, text);
+  }
+
+  test_variable_explicit_dynamic() {
+    UnlinkedVariable variable = serializeVariableText('dynamic v;');
+    checkDynamicTypeRef(variable.type);
+  }
+
+  test_variable_final_top_level() {
+    UnlinkedVariable variable =
+        serializeVariableText('final int i = 0;', variableName: 'i');
+    expect(variable.isFinal, isTrue);
+    expect(variable.constExpr, isNull);
+  }
+
+  test_variable_implicit_dynamic() {
+    UnlinkedVariable variable = serializeVariableText('var v;');
+    expect(variable.type, isNull);
+  }
+
+  test_variable_inferred_type_explicit_initialized() {
+    UnlinkedVariable v = serializeVariableText('int v = 0;');
+    expect(v.inferredTypeSlot, 0);
+  }
+
+  test_variable_inferred_type_implicit_initialized() {
+    UnlinkedVariable v = serializeVariableText('var v = 0;');
+    checkInferredTypeSlot(v.inferredTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_variable_inferred_type_implicit_uninitialized() {
+    UnlinkedVariable v = serializeVariableText('var v;');
+    expect(v.inferredTypeSlot, 0);
+  }
+
+  test_variable_initializer_literal() {
+    UnlinkedVariable variable = serializeVariableText('var v = 42;');
+    UnlinkedExecutable initializer = variable.initializer;
+    expect(initializer, isNotNull);
+    expect(initializer.nameOffset, 8);
+    expect(initializer.name, isEmpty);
+    expect(initializer.localFunctions, isEmpty);
+    expect(initializer.localVariables, isEmpty);
+  }
+
+  test_variable_initializer_noInitializer() {
+    UnlinkedVariable variable = serializeVariableText('var v;');
+    expect(variable.initializer, isNull);
+  }
+
+  test_variable_initializer_withLocals() {
+    String text = 'var v = <dynamic, dynamic>{"1": () { f1() {} var v1; }, '
+        '"2": () { f2() {} var v2; }};';
+    UnlinkedVariable variable = serializeVariableText(text);
+    UnlinkedExecutable initializer = variable.initializer;
+    expect(initializer, isNotNull);
+    expect(initializer.nameOffset, text.indexOf('<dynamic, dynamic>{"1'));
+    expect(initializer.name, isEmpty);
+    expect(initializer.localFunctions, hasLength(2));
+    // closure: () { f1() {} var v1; }
+    {
+      UnlinkedExecutable closure = initializer.localFunctions[0];
+      expect(closure.nameOffset, text.indexOf('() { f1()'));
+      expect(closure.name, isEmpty);
+      // closure - f1
+      expect(closure.localFunctions, hasLength(1));
+      expect(closure.localFunctions[0].name, 'f1');
+      expect(closure.localFunctions[0].nameOffset, text.indexOf('f1()'));
+      // closure - v1
+      expect(closure.localVariables, hasLength(1));
+      expect(closure.localVariables[0].name, 'v1');
+      expect(closure.localVariables[0].nameOffset, text.indexOf('v1;'));
+    }
+    // closure: () { f2() {} var v2; }
+    {
+      UnlinkedExecutable closure = initializer.localFunctions[1];
+      expect(closure.nameOffset, text.indexOf('() { f2()'));
+      expect(closure.name, isEmpty);
+      // closure - f1
+      expect(closure.localFunctions, hasLength(1));
+      expect(closure.localFunctions[0].name, 'f2');
+      expect(closure.localFunctions[0].nameOffset, text.indexOf('f2()'));
+      // closure - v1
+      expect(closure.localVariables, hasLength(1));
+      expect(closure.localVariables[0].name, 'v2');
+      expect(closure.localVariables[0].nameOffset, text.indexOf('v2;'));
+    }
+  }
+
+  test_variable_name() {
+    UnlinkedVariable variable =
+        serializeVariableText('int i;', variableName: 'i');
+    expect(variable.name, 'i');
+  }
+
+  test_variable_no_flags() {
+    UnlinkedVariable variable =
+        serializeVariableText('int i;', variableName: 'i');
+    expect(variable.isStatic, isFalse);
+    expect(variable.isConst, isFalse);
+    expect(variable.isFinal, isFalse);
+  }
+
+  test_variable_non_const() {
+    UnlinkedVariable variable =
+        serializeVariableText('int i = 0;', variableName: 'i');
+    expect(variable.isConst, isFalse);
+  }
+
+  test_variable_non_final() {
+    UnlinkedVariable variable =
+        serializeVariableText('int i;', variableName: 'i');
+    expect(variable.isFinal, isFalse);
+  }
+
+  test_variable_non_static() {
+    UnlinkedVariable variable =
+        serializeClassText('class C { int i; }').fields[0];
+    expect(variable.isStatic, isFalse);
+  }
+
+  test_variable_non_static_top_level() {
+    // Top level variables are considered non-static.
+    UnlinkedVariable variable =
+        serializeVariableText('int i;', variableName: 'i');
+    expect(variable.isStatic, isFalse);
+  }
+
+  test_variable_private() {
+    serializeVariableText('int _i;', variableName: '_i');
+    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
+  }
+
+  test_variable_propagated_type_final_immediate() {
+    UnlinkedVariable v = serializeVariableText('final v = 0;');
+    checkLinkedTypeSlot(v.propagatedTypeSlot, 'dart:core', 'dart:core', 'int');
+  }
+
+  test_variable_propagated_type_new_reference() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedVariable v = serializeVariableText('final v = 0;');
+    // Since the propagated type of `v` is `int`, and there are no references
+    // to `int` elsewhere in the source file, a new linked reference should
+    // have been created for it, with no associated unlinked reference.
+    expect(v.propagatedTypeSlot, isNot(0));
+    EntityRef type = getTypeRefForSlot(v.propagatedTypeSlot);
+    expect(type, isNotNull);
+    expect(type.reference,
+        greaterThanOrEqualTo(unlinkedUnits[0].references.length));
+  }
+
+  test_variable_propagated_type_omit_dynamic() {
+    if (skipFullyLinkedData) {
+      return;
+    }
+    UnlinkedVariable v = serializeVariableText('final v = <int, dynamic>{};');
+    EntityRef type = getTypeRefForSlot(v.propagatedTypeSlot);
+    checkLinkedTypeRef(type, 'dart:core', 'dart:core', 'Map',
+        allowTypeArguments: true, numTypeParameters: 2);
+    expect(type.typeArguments, hasLength(1));
+    checkLinkedTypeRef(type.typeArguments[0], 'dart:core', 'dart:core', 'int');
+  }
+
+  test_variable_propagatedTypeSlot_const() {
+    // Const variables are propagable so they have a nonzero
+    // propagatedTypeSlot.
+    UnlinkedVariable variable = serializeVariableText('const v = 0;');
+    expect(variable.propagatedTypeSlot, isNot(0));
+  }
+
+  test_variable_propagatedTypeSlot_final() {
+    // Final variables are propagable so they have a nonzero
+    // propagatedTypeSlot.
+    UnlinkedVariable variable = serializeVariableText('final v = 0;');
+    expect(variable.propagatedTypeSlot, isNot(0));
+  }
+
+  test_variable_propagatedTypeSlot_non_propagable() {
+    // Non-final non-const variables aren't propagable so they don't have a
+    // propagatedTypeSlot.
+    UnlinkedVariable variable = serializeVariableText('var v;');
+    expect(variable.propagatedTypeSlot, 0);
+  }
+
+  test_variable_static() {
+    UnlinkedVariable variable =
+        serializeClassText('class C { static int i; }').fields[0];
+    expect(variable.isStatic, isTrue);
+  }
+
+  test_variable_type() {
+    UnlinkedVariable variable =
+        serializeVariableText('int i;', variableName: 'i');
+    checkTypeRef(variable.type, 'dart:core', 'dart:core', 'int');
+  }
+
+  /**
+   * Verify invariants of the given [linkedLibrary].
+   */
+  void validateLinkedLibrary(LinkedLibrary linkedLibrary) {
+    for (LinkedUnit unit in linkedLibrary.units) {
+      for (LinkedReference reference in unit.references) {
+        switch (reference.kind) {
+          case ReferenceKind.classOrEnum:
+          case ReferenceKind.topLevelPropertyAccessor:
+          case ReferenceKind.topLevelFunction:
+          case ReferenceKind.typedef:
+            // This reference can have either a zero or a nonzero dependency,
+            // since it refers to top level element which might or might not be
+            // imported from another library.
+            break;
+          case ReferenceKind.prefix:
+            // Prefixes should have a dependency of 0, since they come from the
+            // current library.
+            expect(reference.dependency, 0,
+                reason: 'Nonzero dependency for prefix');
+            break;
+          case ReferenceKind.unresolved:
+            // Unresolved references always have a dependency of 0.
+            expect(reference.dependency, 0,
+                reason: 'Nonzero dependency for undefined');
+            break;
+          default:
+            // This reference should have a dependency of 0, since it refers to
+            // an element that is contained within some other element.
+            expect(reference.dependency, 0,
+                reason: 'Nonzero dependency for ${reference.kind}');
+        }
+      }
+    }
+  }
+
+  void _assertExecutableVisible(String code, UnlinkedExecutable f,
+      String visibleBegin, String visibleEnd) {
+    int expectedVisibleOffset = code.indexOf(visibleBegin);
+    int expectedVisibleLength =
+        code.indexOf(visibleEnd) - expectedVisibleOffset + 1;
+    expect(f.visibleOffset, expectedVisibleOffset);
+    expect(f.visibleLength, expectedVisibleLength);
+  }
+
+  void _assertParameterVisible(
+      String code, UnlinkedParam p, String visibleBegin, String visibleEnd) {
+    int expectedVisibleOffset = code.indexOf(visibleBegin);
+    int expectedVisibleLength =
+        code.indexOf(visibleEnd) - expectedVisibleOffset + 1;
+    expect(p.visibleOffset, expectedVisibleOffset);
+    expect(p.visibleLength, expectedVisibleLength);
+  }
+
+  void _assertParameterZeroVisibleRange(UnlinkedParam p) {
+    expect(p.visibleOffset, isZero);
+    expect(p.visibleLength, isZero);
+  }
+
+  void _assertUnlinkedConst(UnlinkedConst constExpr,
+      {bool isInvalid: false,
+      List<UnlinkedConstOperation> operators: const <UnlinkedConstOperation>[],
+      List<int> ints: const <int>[],
+      List<double> doubles: const <double>[],
+      List<String> strings: const <String>[],
+      List<_EntityRefValidator> referenceValidators:
+          const <_EntityRefValidator>[]}) {
+    expect(constExpr, isNotNull);
+    expect(constExpr.isInvalid, isInvalid);
+    expect(constExpr.operations, operators);
+    expect(constExpr.ints, ints);
+    expect(constExpr.doubles, doubles);
+    expect(constExpr.strings, strings);
+    expect(constExpr.references, hasLength(referenceValidators.length));
+    for (int i = 0; i < referenceValidators.length; i++) {
+      referenceValidators[i](constExpr.references[i]);
+    }
+  }
+
+  void _assertVariableVisible(
+      String code, UnlinkedVariable v, String visibleBegin, String visibleEnd) {
+    int expectedVisibleOffset = code.indexOf(visibleBegin);
+    int expectedVisibleLength =
+        code.indexOf(visibleEnd) - expectedVisibleOffset + 1;
+    expect(v.visibleOffset, expectedVisibleOffset);
+    expect(v.visibleLength, expectedVisibleLength);
+  }
+}
+
+/**
+ * Description of expectations for a prelinked prefix reference.
+ */
+class _PrefixExpectation {
+  final ReferenceKind kind;
+  final String name;
+  final String absoluteUri;
+  final String relativeUri;
+  final int numTypeParameters;
+
+  _PrefixExpectation(this.kind, this.name,
+      {this.absoluteUri, this.relativeUri, this.numTypeParameters: 0});
+}
diff --git a/pkg/analyzer/test/src/summary/summary_sdk_test.dart b/pkg/analyzer/test/src/summary/summary_sdk_test.dart
deleted file mode 100644
index 5ec807e..0000000
--- a/pkg/analyzer/test/src/summary/summary_sdk_test.dart
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.src.summary.summary_sdk_test;
-
-import 'dart:io';
-
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/engine.dart'
-    show AnalysisContext, CacheState;
-import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/summary/format.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' show AnalysisContextTarget;
-import 'package:analyzer/task/model.dart';
-import 'package:path/path.dart' as pathos;
-import 'package:unittest/unittest.dart';
-
-import '../../generated/test_support.dart';
-import '../../reflective_tests.dart';
-
-main() {
-  groupSep = ' | ';
-  runReflectiveTests(SummarySdkAnalysisContextTest);
-}
-
-@reflectiveTest
-class SummarySdkAnalysisContextTest {
-  static String _analyzerPackagePath;
-  static bool _analyzerPackagePathInitialized = false;
-
-  static SdkBundle sdkBundle;
-
-  SummarySdkAnalysisContext context;
-
-  void setUp() {
-    _initializeSdkContext();
-  }
-
-  test_libraryResults() {
-    if (context == null) {
-      return;
-    }
-    // verify that there are at least some interesting libraries in the bundle
-    expect(sdkBundle.prelinkedLibraryUris, contains('dart:core'));
-    expect(sdkBundle.prelinkedLibraryUris, contains('dart:async'));
-    expect(sdkBundle.prelinkedLibraryUris, contains('dart:html'));
-    // verify every library
-    for (String uri in sdkBundle.prelinkedLibraryUris) {
-      // TODO(scheglov) breaks at _LibraryResynthesizer.buildImplicitTopLevelVariable
-      if (uri == 'dart:io' || uri == 'dart:_isolate_helper') {
-        continue;
-      }
-      _assertLibraryResults(uri);
-    }
-  }
-
-  test_sourceKind() {
-    if (context == null) {
-      return;
-    }
-    // libraries
-    _assertHasSourceKind('dart:core', SourceKind.LIBRARY);
-    _assertHasSourceKind('dart:async', SourceKind.LIBRARY);
-    _assertHasSourceKind('dart:math', SourceKind.LIBRARY);
-    // parts
-    _assertHasSourceKind('dart:core/bool.dart', SourceKind.PART);
-    _assertHasSourceKind('dart:async/future.dart', SourceKind.PART);
-    // unknown
-    _assertHasSourceKind('dart:no_such_library.dart', null);
-    _assertHasSourceKind('dart:core/no_such_part.dart', null);
-  }
-
-  test_typeProvider() {
-    if (context == null) {
-      return;
-    }
-    AnalysisContextTarget target = AnalysisContextTarget.request;
-    CacheEntry cacheEntry = context.getCacheEntry(target);
-    bool hasResult = context.aboutToComputeResult(cacheEntry, TYPE_PROVIDER);
-    expect(hasResult, isTrue);
-    expect(cacheEntry.getState(TYPE_PROVIDER), CacheState.VALID);
-    TypeProvider typeProvider = cacheEntry.getValue(TYPE_PROVIDER);
-    expect(typeProvider.objectType, isNotNull);
-    expect(typeProvider.boolType, isNotNull);
-    expect(typeProvider.intType, isNotNull);
-    expect(typeProvider.futureType, isNotNull);
-    expect(typeProvider.futureDynamicType, isNotNull);
-    expect(typeProvider.streamType, isNotNull);
-    expect(typeProvider.streamDynamicType, isNotNull);
-  }
-
-  void _assertHasLibraryElement(CacheEntry cacheEntry,
-      ResultDescriptor<LibraryElement> resultDescriptor) {
-    bool hasResult = context.aboutToComputeResult(cacheEntry, resultDescriptor);
-    expect(hasResult, isTrue);
-    expect(cacheEntry.getState(resultDescriptor), CacheState.VALID);
-    LibraryElement library = cacheEntry.getValue(resultDescriptor);
-    expect(library, isNotNull);
-  }
-
-  void _assertHasSourceKind(String uri, SourceKind expectedValue) {
-    Source target = context.sourceFactory.forUri(uri);
-    CacheEntry cacheEntry = context.getCacheEntry(target);
-    ResultDescriptor<SourceKind> resultDescriptor = SOURCE_KIND;
-    bool hasResult = context.aboutToComputeResult(cacheEntry, resultDescriptor);
-    if (expectedValue == null) {
-      expect(hasResult, isFalse);
-      expect(cacheEntry.getState(resultDescriptor), CacheState.INVALID);
-    } else {
-      expect(hasResult, isTrue);
-      expect(cacheEntry.getState(resultDescriptor), CacheState.VALID);
-      SourceKind value = cacheEntry.getValue(resultDescriptor);
-      expect(value, expectedValue);
-    }
-  }
-
-  void _assertIsLibraryElementReady(
-      CacheEntry cacheEntry, ResultDescriptor<bool> resultDescriptor) {
-    bool hasResult = context.aboutToComputeResult(cacheEntry, resultDescriptor);
-    expect(hasResult, isTrue);
-    expect(cacheEntry.getState(resultDescriptor), CacheState.VALID);
-    bool ready = cacheEntry.getValue(resultDescriptor);
-    expect(ready, isTrue);
-  }
-
-  void _assertLibraryResults(String uri) {
-    Source target = context.sourceFactory.forUri(uri);
-    CacheEntry cacheEntry = context.getCacheEntry(target);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT1);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT2);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT3);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT4);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT5);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT6);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT7);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT8);
-    _assertHasLibraryElement(cacheEntry, LIBRARY_ELEMENT);
-    _assertIsLibraryElementReady(cacheEntry, READY_LIBRARY_ELEMENT2);
-    _assertIsLibraryElementReady(cacheEntry, READY_LIBRARY_ELEMENT5);
-    _assertIsLibraryElementReady(cacheEntry, READY_LIBRARY_ELEMENT6);
-  }
-
-  void _initializeSdkBundle() {
-    if (sdkBundle != null) {
-      return;
-    }
-    // prepare analyzer path
-    String analyzerPath = getAnalyzerPackagePath();
-    if (analyzerPath == null) {
-      return;
-    }
-    // prepare summary path
-    String sdkSummaryPath = pathos.join(
-        analyzerPath, 'test', 'src', 'summary', 'sdk_analysis_summary');
-    File file = new File(sdkSummaryPath);
-    if (!file.existsSync()) {
-      return;
-    }
-    // load SdkBundle
-    List<int> bytes = file.readAsBytesSync();
-    sdkBundle = new SdkBundle.fromBuffer(bytes);
-  }
-
-  void _initializeSdkContext() {
-    _initializeSdkBundle();
-    if (sdkBundle == null) {
-      return;
-    }
-    context = new _TestSummarySdkAnalysisContext(sdkBundle);
-    DartSdk sdk = new _TestSummaryDartSdk();
-    context.sourceFactory = new SourceFactory([new DartUriResolver(sdk)]);
-  }
-
-  static String getAnalyzerPackagePath() {
-    if (!_analyzerPackagePathInitialized) {
-      _analyzerPackagePathInitialized = true;
-      _analyzerPackagePath = _computeAnalyzerPackagePath();
-    }
-    return _analyzerPackagePath;
-  }
-
-  /**
-   * Return the path to the `analyzer` package root, or `null` if it cannot
-   * be determined.
-   *
-   * This method expects that one of the `analyzer` tests was run, so
-   * [Platform.script] is inside of the `analyzer/test` folder.
-   */
-  static String _computeAnalyzerPackagePath() {
-    Uri uri = Platform.script;
-    if (uri == null || uri.scheme != 'file') {
-      return null;
-    }
-    String path = pathos.fromUri(uri);
-    List<String> segments = pathos.split(path);
-    while (segments.length > 2) {
-      if (segments[segments.length - 1] == 'test' &&
-          segments[segments.length - 2] == 'analyzer') {
-        segments.removeLast();
-        return pathos.joinAll(segments);
-      }
-      segments.removeLast();
-    }
-    return null;
-  }
-}
-
-class _TestSummaryDartSdk implements DartSdk {
-  @override
-  Source mapDartUri(String uriStr) {
-    Uri uri = Uri.parse(uriStr);
-    List<String> segments = uri.pathSegments;
-    if (segments.length == 1) {
-      String libraryName = segments.first;
-      String path = '/sdk/$libraryName/$libraryName.dart';
-      return new _TestSummarySdkSource(path, uri);
-    } else {
-      String path = '/sdk/' + segments.join('/');
-      return new _TestSummarySdkSource(path, uri);
-    }
-  }
-
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-/**
- * [SummarySdkAnalysisContext] with simplified cache creation.
- */
-class _TestSummarySdkAnalysisContext extends SummarySdkAnalysisContext {
-  _TestSummarySdkAnalysisContext(SdkBundle bundle) : super(bundle);
-
-  @override
-  AnalysisCache createCacheFromSourceFactory(SourceFactory factory) {
-    return new AnalysisCache(<CachePartition>[new SdkCachePartition(this)]);
-  }
-}
-
-class _TestSummarySdkSource extends TestSourceWithUri {
-  _TestSummarySdkSource(String path, Uri uri) : super(path, uri);
-
-  @override
-  bool get isInSystemLibrary => true;
-
-  @override
-  Uri resolveRelativeUri(Uri relativeUri) {
-    Uri baseUri = uri;
-    if (uri.scheme == 'dart') {
-      String libraryName = uri.path;
-      baseUri = Uri.parse('dart:$libraryName/$libraryName.dart');
-    }
-    return baseUri.resolveUri(relativeUri);
-  }
-}
diff --git a/pkg/analyzer/test/src/summary/summary_test.dart b/pkg/analyzer/test/src/summary/summary_test.dart
deleted file mode 100644
index 8b25e9d..0000000
--- a/pkg/analyzer/test/src/summary/summary_test.dart
+++ /dev/null
@@ -1,2966 +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 analyzer.test.src.summary.summary_test;
-
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_engine_io.dart';
-import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/summary/base.dart';
-import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/prelink.dart';
-import 'package:analyzer/src/summary/public_namespace_computer.dart'
-    as public_namespace;
-import 'package:analyzer/src/summary/summarize_elements.dart'
-    as summarize_elements;
-import 'package:unittest/unittest.dart';
-
-import '../../generated/resolver_test.dart';
-import '../../reflective_tests.dart';
-
-main() {
-  groupSep = ' | ';
-  runReflectiveTests(SummarizeElementsTest);
-  runReflectiveTests(PrelinkerTest);
-}
-
-/**
- * Convert a summary object (or a portion of one) into a canonical form that
- * can be easily compared using [expect].  If [orderByName] is true, and the
- * object is a [List], it is sorted by the `name` field of its elements.
- */
-Object canonicalize(Object obj, {bool orderByName: false}) {
-  if (obj is SummaryClass) {
-    Map<String, Object> result = <String, Object>{};
-    obj.toMap().forEach((String key, Object value) {
-      bool orderByName = false;
-      if (obj is UnlinkedPublicNamespace && key == 'names') {
-        orderByName = true;
-      }
-      result[key] = canonicalize(value, orderByName: orderByName);
-    });
-    return result;
-  } else if (obj is List) {
-    List<Object> result = <Object>[];
-    for (Object item in obj) {
-      result.add(canonicalize(item));
-    }
-    if (orderByName) {
-      result.sort((Object a, Object b) {
-        if (a is Map && b is Map) {
-          return Comparable.compare(a['name'], b['name']);
-        } else {
-          return 0;
-        }
-      });
-    }
-    return result;
-  } else if (obj is String || obj is num || obj is bool) {
-    return obj;
-  } else {
-    return obj.toString();
-  }
-}
-
-UnlinkedPublicNamespace computePublicNamespaceFromText(
-    String text, Source source) {
-  CharacterReader reader = new CharSequenceReader(text);
-  Scanner scanner =
-      new Scanner(source, reader, AnalysisErrorListener.NULL_LISTENER);
-  Parser parser = new Parser(source, AnalysisErrorListener.NULL_LISTENER);
-  parser.parseGenericMethods = true;
-  CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
-  UnlinkedPublicNamespace namespace = new UnlinkedPublicNamespace.fromBuffer(
-      public_namespace.computePublicNamespace(unit).toBuffer());
-  return namespace;
-}
-
-/**
- * Override of [SummaryTest] which verifies the correctness of the prelinker by
- * creating summaries from the element model, discarding their prelinked
- * information, and then recreating it using the prelinker.
- */
-@reflectiveTest
-class PrelinkerTest extends SummarizeElementsTest {
-  /**
-   * The public namespaces of the sdk are computed once so that we don't bog
-   * down the test.  Structured as a map from absolute URI to the corresponding
-   * public namespace.
-   *
-   * Note: should an exception occur during computation of this variable, it
-   * will silently be set to null to allow other tests to run.
-   */
-  static final Map<String, UnlinkedPublicNamespace> sdkPublicNamespace = () {
-    try {
-      AnalysisContext analysisContext =
-          AnalysisContextFactory.contextWithCore();
-      Map<String, UnlinkedPublicNamespace> uriToNamespace =
-          <String, UnlinkedPublicNamespace>{};
-      List<LibraryElement> libraries = [
-        analysisContext.typeProvider.objectType.element.library,
-        analysisContext.typeProvider.futureType.element.library
-      ];
-      for (LibraryElement library in libraries) {
-        summarize_elements.LibrarySerializationResult serializedLibrary =
-            summarize_elements.serializeLibrary(
-                library, analysisContext.typeProvider);
-        for (int i = 0; i < serializedLibrary.unlinkedUnits.length; i++) {
-          uriToNamespace[
-              serializedLibrary.unitUris[i]] = new UnlinkedUnit.fromBuffer(
-              serializedLibrary.unlinkedUnits[i].toBuffer()).publicNamespace;
-        }
-      }
-      return uriToNamespace;
-    } catch (_) {
-      return null;
-    }
-  }();
-
-  final Map<String, UnlinkedPublicNamespace> uriToPublicNamespace =
-      <String, UnlinkedPublicNamespace>{};
-
-  @override
-  bool get expectAbsoluteUrisInDependencies => false;
-
-  @override
-  Source addNamedSource(String filePath, String contents) {
-    Source source = super.addNamedSource(filePath, contents);
-    uriToPublicNamespace[absUri(filePath)] =
-        computePublicNamespaceFromText(contents, source);
-    return source;
-  }
-
-  String resolveToAbsoluteUri(LibraryElement library, String relativeUri) {
-    Source resolvedSource =
-        analysisContext.sourceFactory.resolveUri(library.source, relativeUri);
-    if (resolvedSource == null) {
-      fail('Failed to resolve relative uri "$relativeUri"');
-    }
-    return resolvedSource.uri.toString();
-  }
-
-  @override
-  void serializeLibraryElement(LibraryElement library) {
-    super.serializeLibraryElement(library);
-    Map<String, UnlinkedUnit> uriToUnit = <String, UnlinkedUnit>{};
-    expect(unlinkedUnits.length, unitUris.length);
-    for (int i = 1; i < unlinkedUnits.length; i++) {
-      uriToUnit[unitUris[i]] = unlinkedUnits[i];
-    }
-    UnlinkedUnit getPart(String relativeUri) {
-      String absoluteUri = resolveToAbsoluteUri(library, relativeUri);
-      UnlinkedUnit unit = uriToUnit[absoluteUri];
-      if (unit == null) {
-        fail('Prelinker unexpectedly requested unit for "$relativeUri"'
-            ' (resolves to "$absoluteUri").');
-      }
-      return unit;
-    }
-    UnlinkedPublicNamespace getImport(String relativeUri) {
-      String absoluteUri = resolveToAbsoluteUri(library, relativeUri);
-      UnlinkedPublicNamespace namespace = sdkPublicNamespace[absoluteUri];
-      if (namespace == null) {
-        namespace = uriToPublicNamespace[absoluteUri];
-      }
-      if (namespace == null && !allowMissingFiles) {
-        fail('Prelinker unexpectedly requested namespace for "$relativeUri"'
-            ' (resolves to "$absoluteUri").'
-            '  Namespaces available: ${uriToPublicNamespace.keys}');
-      }
-      return namespace;
-    }
-    prelinked = new PrelinkedLibrary.fromBuffer(
-        prelink(unlinkedUnits[0], getPart, getImport).toBuffer());
-  }
-}
-
-/**
- * Override of [SummaryTest] which creates summaries from the element model.
- */
-@reflectiveTest
-class SummarizeElementsTest extends ResolverTestCase with SummaryTest {
-  /**
-   * The list of absolute unit URIs corresponding to the compilation units in
-   * [unlinkedUnits].
-   */
-  List<String> unitUris;
-
-  /**
-   * Map containing all source files in this test, and their corresponding file
-   * contents.
-   */
-  final Map<Source, String> _fileContents = <Source, String>{};
-
-  @override
-  bool get checkAstDerivedData => false;
-
-  @override
-  bool get expectAbsoluteUrisInDependencies => true;
-
-  @override
-  Source addNamedSource(String filePath, String contents) {
-    Source source = super.addNamedSource(filePath, contents);
-    _fileContents[source] = contents;
-    return source;
-  }
-
-  /**
-   * Serialize the library containing the given class [element], then
-   * deserialize it and return the summary of the class.
-   */
-  UnlinkedClass serializeClassElement(ClassElement element) {
-    serializeLibraryElement(element.library);
-    return findClass(element.name, failIfAbsent: true);
-  }
-
-  /**
-   * Serialize the given [library] element, then deserialize it and store the
-   * resulting summary in [prelinked] and [unlinkedUnits].
-   */
-  void serializeLibraryElement(LibraryElement library) {
-    summarize_elements.LibrarySerializationResult serializedLib =
-        summarize_elements.serializeLibrary(library, typeProvider);
-    {
-      List<int> buffer = serializedLib.prelinked.toBuffer();
-      prelinked = new PrelinkedLibrary.fromBuffer(buffer);
-    }
-    unlinkedUnits = serializedLib.unlinkedUnits.map((UnlinkedUnitBuilder b) {
-      List<int> buffer = b.toBuffer();
-      return new UnlinkedUnit.fromBuffer(buffer);
-    }).toList();
-    unitUris = serializedLib.unitUris;
-  }
-
-  @override
-  void serializeLibraryText(String text, {bool allowErrors: false}) {
-    Source source = addSource(text);
-    _fileContents[source] = text;
-    LibraryElement library = resolve2(source);
-    if (!allowErrors) {
-      assertNoErrors(source);
-    }
-    serializeLibraryElement(library);
-    expect(
-        unlinkedUnits[0].imports.length, prelinked.importDependencies.length);
-    expect(prelinked.units.length, unlinkedUnits.length);
-    for (int i = 0; i < prelinked.units.length; i++) {
-      expect(unlinkedUnits[i].references.length,
-          prelinked.units[i].references.length);
-    }
-    verifyPublicNamespace();
-  }
-
-  @override
-  void setUp() {
-    super.setUp();
-    AnalysisOptionsImpl options = new AnalysisOptionsImpl();
-    options.enableGenericMethods = true;
-    resetWithOptions(options);
-  }
-
-  test_class_no_superclass() {
-    UnlinkedClass cls = serializeClassElement(typeProvider.objectType.element);
-    expect(cls.supertype, isNull);
-    expect(cls.hasNoSupertype, isTrue);
-  }
-
-  /**
-   * Verify that [public_namespace.computePublicNamespace] produces data that's
-   * equivalent to that produced by [summarize_elements.serializeLibrary].
-   */
-  void verifyPublicNamespace() {
-    for (int i = 0; i < unlinkedUnits.length; i++) {
-      Source source = analysisContext.sourceFactory.forUri(unitUris[i]);
-      String text = _fileContents[source];
-      if (text == null) {
-        if (!allowMissingFiles) {
-          fail('Could not find file while verifying public namespace: '
-              '${unitUris[i]}');
-        }
-      } else {
-        UnlinkedPublicNamespace namespace =
-            computePublicNamespaceFromText(text, source);
-        expect(canonicalize(namespace),
-            canonicalize(unlinkedUnits[i].publicNamespace),
-            reason: 'publicNamespace(${unitUris[i]})');
-      }
-    }
-  }
-}
-
-/**
- * Base class containing most summary tests.  This allows summary tests to be
- * re-used to exercise all the different ways in which summaries can be
- * generated (e.g. direct from the AST, from the element model, from a
- * "relinking" process, etc.)
- */
-abstract class SummaryTest {
-  /**
-   * Prelinked summary that results from serializing and then deserializing the
-   * library under test.
-   */
-  PrelinkedLibrary prelinked;
-
-  /**
-   * Unlinked compilation unit summaries that result from serializing and
-   * deserializing the library under test.
-   */
-  List<UnlinkedUnit> unlinkedUnits;
-
-  /**
-   * A test will set this to `true` if it contains `import`, `export`, or
-   * `part` declarations that deliberately refer to non-existent files.
-   */
-  bool allowMissingFiles = false;
-
-  /**
-   * `true` if the summary was created directly from the AST (and hence
-   * contains information that is not obtainable from the element model alone).
-   * TODO(paulberry): modify the element model so that it contains all the data
-   * that summaries need, so that this flag is no longer needed.
-   */
-  bool get checkAstDerivedData;
-
-  /**
-   * Get access to the prelinked defining compilation unit.
-   */
-  PrelinkedUnit get definingUnit => prelinked.units[0];
-
-  /**
-   * `true` if the prelinked portion of the summary is expected to contain
-   * absolute URIs.  This happens because the element model doesn't (yet) store
-   * enough information to recover relative URIs, TODO(paulberry): fix this.
-   */
-  bool get expectAbsoluteUrisInDependencies;
-
-  /**
-   * Convert [path] to a suitably formatted absolute path URI for the current
-   * platform.
-   */
-  String absUri(String path) {
-    return FileUtilities2.createFile(path).toURI().toString();
-  }
-
-  /**
-   * Add the given source file so that it may be referenced by the file under
-   * test.
-   */
-  Source addNamedSource(String filePath, String contents);
-
-  /**
-   * Verify that the [dependency]th element of the dependency table represents
-   * a file reachable via the given [absoluteUri] and [relativeUri].
-   */
-  void checkDependency(int dependency, String absoluteUri, String relativeUri) {
-    if (expectAbsoluteUrisInDependencies) {
-      // The element model doesn't (yet) store enough information to recover
-      // relative URIs, so we have to use the absolute URI.
-      // TODO(paulberry): fix this.
-      relativeUri = absoluteUri;
-    }
-    expect(dependency, new isInstanceOf<int>());
-    expect(prelinked.dependencies[dependency].uri, relativeUri);
-  }
-
-  /**
-   * Verify that the given [dependency] lists the given [absoluteUris] or
-   * [relativeUris] as its parts.
-   */
-  void checkDependencyParts(PrelinkedDependency dependency,
-      List<String> absoluteUris, List<String> relativeUris) {
-    if (expectAbsoluteUrisInDependencies) {
-      // The element model doesn't (yet) store enough information to recover
-      // relative URIs, so we have to use the absolute URI.
-      // TODO(paulberry): fix this.
-      relativeUris = absoluteUris;
-    }
-    expect(dependency.parts, relativeUris);
-  }
-
-  /**
-   * Check that the given [documentationComment] matches the first
-   * Javadoc-style comment found in [text].
-   *
-   * Note that the algorithm for finding the Javadoc-style comment in [text] is
-   * a simple-minded text search; it is easily confused by corner cases such as
-   * strings containing comments, nested comments, etc.
-   */
-  void checkDocumentationComment(
-      UnlinkedDocumentationComment documentationComment, String text) {
-    expect(documentationComment, isNotNull);
-    int commentStart = text.indexOf('/*');
-    expect(commentStart, isNot(-1));
-    int commentEnd = text.indexOf('*/');
-    expect(commentEnd, isNot(-1));
-    commentEnd += 2;
-    String expectedCommentText =
-        text.substring(commentStart, commentEnd).replaceAll('\r\n', '\n');
-    expect(documentationComment.text, expectedCommentText);
-    expect(documentationComment.offset, commentStart);
-    expect(documentationComment.length, commentEnd - commentStart);
-  }
-
-  /**
-   * Verify that the given [typeRef] represents the type `dynamic`.
-   */
-  void checkDynamicTypeRef(UnlinkedTypeRef typeRef) {
-    checkTypeRef(typeRef, null, null, null);
-  }
-
-  /**
-   * Verify that the dependency table contains an entry for a file reachable
-   * via the given [absoluteUri] and [relativeUri].
-   *
-   * The [PrelinkedDependency] is returned.
-   */
-  PrelinkedDependency checkHasDependency(
-      String absoluteUri, String relativeUri) {
-    if (expectAbsoluteUrisInDependencies) {
-      // The element model doesn't (yet) store enough information to recover
-      // relative URIs, so we have to use the absolute URI.
-      // TODO(paulberry): fix this.
-      relativeUri = absoluteUri;
-    }
-    List<String> found = <String>[];
-    for (PrelinkedDependency dep in prelinked.dependencies) {
-      if (dep.uri == relativeUri) {
-        return dep;
-      }
-      found.add(dep.uri);
-    }
-    fail('Did not find dependency $relativeUri.  Found: $found');
-    return null;
-  }
-
-  /**
-   * Verify that the dependency table *does not* contain any entries for a file
-   * reachable via the given [absoluteUri] and [relativeUri].
-   */
-  void checkLacksDependency(String absoluteUri, String relativeUri) {
-    if (expectAbsoluteUrisInDependencies) {
-      // The element model doesn't (yet) store enough information to recover
-      // relative URIs, so we have to use the absolute URI.
-      // TODO(paulberry): fix this.
-      relativeUri = absoluteUri;
-    }
-    for (PrelinkedDependency dep in prelinked.dependencies) {
-      if (dep.uri == relativeUri) {
-        fail('Unexpected dependency found: $relativeUri');
-      }
-    }
-  }
-
-  /**
-   * Verify that the given [typeRef] represents a reference to a type parameter
-   * having the given [deBruijnIndex].
-   */
-  void checkParamTypeRef(UnlinkedTypeRef typeRef, int deBruijnIndex) {
-    expect(typeRef, new isInstanceOf<UnlinkedTypeRef>());
-    expect(typeRef.reference, 0);
-    expect(typeRef.typeArguments, isEmpty);
-    expect(typeRef.paramReference, deBruijnIndex);
-  }
-
-  /**
-   * Verify that [prefixReference] is a valid reference to a prefix having the
-   * given [name].
-   */
-  void checkPrefix(int prefixReference, String name) {
-    expect(prefixReference, isNot(0));
-    expect(unlinkedUnits[0].references[prefixReference].prefixReference, 0);
-    expect(unlinkedUnits[0].references[prefixReference].name, name);
-    expect(definingUnit.references[prefixReference].dependency, 0);
-    expect(definingUnit.references[prefixReference].kind,
-        PrelinkedReferenceKind.prefix);
-    expect(definingUnit.references[prefixReference].unit, 0);
-  }
-
-  /**
-   * Verify that the given [typeRef] represents a reference to a type declared
-   * in a file reachable via [absoluteUri] and [relativeUri], having name
-   * [expectedName].  If [expectedPrefix] is supplied, verify that the type is
-   * reached via the given prefix.  If [allowTypeParameters] is true, allow the
-   * type reference to supply type parameters.  [expectedKind] is the kind of
-   * object referenced.  [prelinkedSourceUnit] and [unlinkedSourceUnit] refer
-   * to the compilation unit within which the [typeRef] appears; if not
-   * specified they are assumed to refer to the defining compilation unit.
-   * [expectedTargetUnit] is the index of the compilation unit in which the
-   * target of the [typeRef] is expected to appear; if not specified it is
-   * assumed to be the defining compilation unit.  [numTypeParameters] is the
-   * number of type parameters of the thing being referred to.
-   */
-  void checkTypeRef(UnlinkedTypeRef typeRef, String absoluteUri,
-      String relativeUri, String expectedName,
-      {String expectedPrefix,
-      bool allowTypeParameters: false,
-      PrelinkedReferenceKind expectedKind: PrelinkedReferenceKind.classOrEnum,
-      int expectedTargetUnit: 0,
-      PrelinkedUnit prelinkedSourceUnit,
-      UnlinkedUnit unlinkedSourceUnit,
-      int numTypeParameters: 0}) {
-    prelinkedSourceUnit ??= definingUnit;
-    unlinkedSourceUnit ??= unlinkedUnits[0];
-    expect(typeRef, new isInstanceOf<UnlinkedTypeRef>());
-    expect(typeRef.paramReference, 0);
-    int index = typeRef.reference;
-    UnlinkedReference reference = unlinkedSourceUnit.references[index];
-    PrelinkedReference referenceResolution =
-        prelinkedSourceUnit.references[index];
-    if (index == 0) {
-      // Index 0 is reserved for "dynamic".
-      expect(reference.name, isEmpty);
-      expect(reference.prefixReference, 0);
-    }
-    if (absoluteUri == null) {
-      expect(referenceResolution.dependency, 0);
-    } else {
-      checkDependency(referenceResolution.dependency, absoluteUri, relativeUri);
-    }
-    if (!allowTypeParameters) {
-      expect(typeRef.typeArguments, isEmpty);
-    }
-    if (expectedKind == PrelinkedReferenceKind.unresolved) {
-      // summarize_elements.dart isn't yet able to record the name of
-      // unresolved references.  TODO(paulberry): fix this.
-      expect(reference.name, '*unresolved*');
-    } else if (expectedName == null) {
-      expect(reference.name, isEmpty);
-    } else {
-      expect(reference.name, expectedName);
-    }
-    if (expectedPrefix == null) {
-      expect(reference.prefixReference, 0);
-    } else {
-      checkPrefix(reference.prefixReference, expectedPrefix);
-    }
-    expect(referenceResolution.kind, expectedKind);
-    expect(referenceResolution.unit, expectedTargetUnit);
-    expect(referenceResolution.numTypeParameters, numTypeParameters);
-  }
-
-  /**
-   * Verify that the given [typeRef] represents a reference to an unresolved
-   * type.
-   */
-  void checkUnresolvedTypeRef(
-      UnlinkedTypeRef typeRef, String expectedPrefix, String expectedName) {
-    // When serializing from the element model, unresolved type refs lose their
-    // name.
-    checkTypeRef(typeRef, null, null, checkAstDerivedData ? expectedName : null,
-        expectedPrefix: expectedPrefix,
-        expectedKind: PrelinkedReferenceKind.unresolved);
-  }
-
-  fail_enum_value_documented() {
-    // TODO(paulberry): currently broken because of dartbug.com/25385
-    String text = '''
-enum E {
-  /**
-   * Docs
-   */
-  v
-}''';
-    UnlinkedEnumValue value = serializeEnumText(text).values[0];
-    expect(value.documentationComment, isNotNull);
-    checkDocumentationComment(value.documentationComment, text);
-  }
-
-  fail_test_import_missing() {
-    // TODO(paulberry): At the moment unresolved imports are not included in
-    // the element model, so we can't pass this test.
-    // Unresolved imports are included since this is necessary for proper
-    // dependency tracking.
-    allowMissingFiles = true;
-    serializeLibraryText('import "foo.dart";', allowErrors: true);
-    // Second import is the implicit import of dart:core
-    expect(unlinkedUnits[0].imports, hasLength(2));
-    checkDependency(
-        prelinked.importDependencies[0], absUri('/foo.dart'), 'foo.dart');
-  }
-
-  fail_type_reference_to_nonexistent_file_via_prefix() {
-    // TODO(paulberry): this test currently fails because there is not enough
-    // information in the element model to figure out that the unresolved
-    // reference `p.C` uses the prefix `p`.
-    allowMissingFiles = true;
-    UnlinkedTypeRef typeRef = serializeTypeText('p.C',
-        otherDeclarations: 'import "foo.dart" as p;', allowErrors: true);
-    checkUnresolvedTypeRef(typeRef, 'p', 'C');
-  }
-
-  fail_type_reference_to_type_visible_via_multiple_import_prefixes() {
-    // TODO(paulberry): this test currently fails because the element model
-    // doesn't record enough information to track which prefix is used to refer
-    // to a type.
-    addNamedSource('/lib1.dart', 'class C');
-    addNamedSource('/lib2.dart', 'export "lib1.dart";');
-    addNamedSource('/lib3.dart', 'export "lib1.dart";');
-    addNamedSource('/lib4.dart', 'export "lib1.dart";');
-    serializeLibraryText('''
-import 'lib2.dart';
-import 'lib3.dart' as a;
-import 'lib4.dart' as b;
-C c2;
-a.C c3;
-b.C c4;''');
-    // Note: it is important that each reference to class C records the prefix
-    // used to find it; otherwise it's possible that relinking might produce an
-    // incorrect result after a change to lib2.dart, lib3.dart, or lib4.dart.
-    checkTypeRef(
-        findVariable('c2').type, absUri('/lib1.dart'), 'lib1.dart', 'C');
-    checkTypeRef(
-        findVariable('c3').type, absUri('/lib1.dart'), 'lib1.dart', 'C',
-        expectedPrefix: 'a');
-    checkTypeRef(
-        findVariable('c4').type, absUri('/lib1.dart'), 'lib1.dart', 'C',
-        expectedPrefix: 'b');
-  }
-
-  /**
-   * Find the class with the given [className] in the summary, and return its
-   * [UnlinkedClass] data structure.  If [unit] is not given, the class is
-   * looked for in the defining compilation unit.
-   */
-  UnlinkedClass findClass(String className,
-      {bool failIfAbsent: false, UnlinkedUnit unit}) {
-    unit ??= unlinkedUnits[0];
-    UnlinkedClass result;
-    for (UnlinkedClass cls in unit.classes) {
-      if (cls.name == className) {
-        if (result != null) {
-          fail('Duplicate class $className');
-        }
-        result = cls;
-      }
-    }
-    if (result == null && failIfAbsent) {
-      fail('Class $className not found in serialized output');
-    }
-    return result;
-  }
-
-  /**
-   * Find the enum with the given [enumName] in the summary, and return its
-   * [UnlinkedEnum] data structure.  If [unit] is not given, the enum is looked
-   * for in the defining compilation unit.
-   */
-  UnlinkedEnum findEnum(String enumName,
-      {bool failIfAbsent: false, UnlinkedUnit unit}) {
-    unit ??= unlinkedUnits[0];
-    UnlinkedEnum result;
-    for (UnlinkedEnum e in unit.enums) {
-      if (e.name == enumName) {
-        if (result != null) {
-          fail('Duplicate enum $enumName');
-        }
-        result = e;
-      }
-    }
-    if (result == null && failIfAbsent) {
-      fail('Enum $enumName not found in serialized output');
-    }
-    return result;
-  }
-
-  /**
-   * Find the executable with the given [executableName] in the summary, and
-   * return its [UnlinkedExecutable] data structure.  If [executables] is not
-   * given, then the executable is searched for in the defining compilation
-   * unit.
-   */
-  UnlinkedExecutable findExecutable(String executableName,
-      {List<UnlinkedExecutable> executables, bool failIfAbsent: false}) {
-    executables ??= unlinkedUnits[0].executables;
-    UnlinkedExecutable result;
-    for (UnlinkedExecutable executable in executables) {
-      if (executable.name == executableName) {
-        if (result != null) {
-          fail('Duplicate executable $executableName');
-        }
-        result = executable;
-      }
-    }
-    if (result == null && failIfAbsent) {
-      fail('Executable $executableName not found in serialized output');
-    }
-    return result;
-  }
-
-  /**
-   * Find the typedef with the given [typedefName] in the summary, and return
-   * its [UnlinkedTypedef] data structure.  If [unit] is not given, the typedef
-   * is looked for in the defining compilation unit.
-   */
-  UnlinkedTypedef findTypedef(String typedefName,
-      {bool failIfAbsent: false, UnlinkedUnit unit}) {
-    unit ??= unlinkedUnits[0];
-    UnlinkedTypedef result;
-    for (UnlinkedTypedef type in unit.typedefs) {
-      if (type.name == typedefName) {
-        if (result != null) {
-          fail('Duplicate typedef $typedefName');
-        }
-        result = type;
-      }
-    }
-    if (result == null && failIfAbsent) {
-      fail('Typedef $typedefName not found in serialized output');
-    }
-    return result;
-  }
-
-  /**
-   * Find the top level variable with the given [variableName] in the summary,
-   * and return its [UnlinkedVariable] data structure.  If [variables] is not
-   * specified, the variable is looked for in the defining compilation unit.
-   */
-  UnlinkedVariable findVariable(String variableName,
-      {List<UnlinkedVariable> variables, bool failIfAbsent: false}) {
-    variables ??= unlinkedUnits[0].variables;
-    UnlinkedVariable result;
-    for (UnlinkedVariable variable in variables) {
-      if (variable.name == variableName) {
-        if (result != null) {
-          fail('Duplicate variable $variableName');
-        }
-        result = variable;
-      }
-    }
-    if (result == null && failIfAbsent) {
-      fail('Variable $variableName not found in serialized output');
-    }
-    return result;
-  }
-
-  /**
-   * Serialize the given library [text] and return the summary of the class
-   * with the given [className].
-   */
-  UnlinkedClass serializeClassText(String text, [String className = 'C']) {
-    serializeLibraryText(text);
-    return findClass(className, failIfAbsent: true);
-  }
-
-  /**
-   * Serialize the given library [text] and return the summary of the enum with
-   * the given [enumName].
-   */
-  UnlinkedEnum serializeEnumText(String text, [String enumName = 'E']) {
-    serializeLibraryText(text);
-    return findEnum(enumName, failIfAbsent: true);
-  }
-
-  /**
-   * Serialize the given library [text] and return the summary of the
-   * executable with the given [executableName].
-   */
-  UnlinkedExecutable serializeExecutableText(String text,
-      [String executableName = 'f']) {
-    serializeLibraryText(text);
-    return findExecutable(executableName, failIfAbsent: true);
-  }
-
-  /**
-   * Serialize the given library [text], then deserialize it and store its
-   * summary in [lib].
-   */
-  void serializeLibraryText(String text, {bool allowErrors: false});
-
-  /**
-   * Serialize the given method [text] and return the summary of the executable
-   * with the given [executableName].
-   */
-  UnlinkedExecutable serializeMethodText(String text,
-      [String executableName = 'f']) {
-    serializeLibraryText('class C { $text }');
-    return findExecutable(executableName,
-        executables: findClass('C', failIfAbsent: true).executables,
-        failIfAbsent: true);
-  }
-
-  /**
-   * Serialize the given library [text] and return the summary of the typedef
-   * with the given [typedefName].
-   */
-  UnlinkedTypedef serializeTypedefText(String text,
-      [String typedefName = 'F']) {
-    serializeLibraryText(text);
-    return findTypedef(typedefName, failIfAbsent: true);
-  }
-
-  /**
-   * Serialize a type declaration using the given [text] as a type name, and
-   * return a summary of the corresponding [UnlinkedTypeRef].  If the type
-   * declaration needs to refer to types that are not available in core, those
-   * types may be declared in [otherDeclarations].
-   */
-  UnlinkedTypeRef serializeTypeText(String text,
-      {String otherDeclarations: '', bool allowErrors: false}) {
-    return serializeVariableText('$otherDeclarations\n$text v;',
-        allowErrors: allowErrors).type;
-  }
-
-  /**
-   * Serialize the given library [text] and return the summary of the variable
-   * with the given [variableName].
-   */
-  UnlinkedVariable serializeVariableText(String text,
-      {String variableName: 'v', bool allowErrors: false}) {
-    serializeLibraryText(text, allowErrors: allowErrors);
-    return findVariable(variableName, failIfAbsent: true);
-  }
-
-  test_cascaded_export_hide_hide() {
-    addNamedSource('/lib1.dart', 'export "lib2.dart" hide C hide B, C;');
-    addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
-    serializeLibraryText(
-        '''
-import 'lib1.dart';
-A a;
-B b;
-C c;
-    ''',
-        allowErrors: true);
-    checkTypeRef(
-        findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
-    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
-    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
-  }
-
-  test_cascaded_export_hide_show() {
-    addNamedSource('/lib1.dart', 'export "lib2.dart" hide C show A, C;');
-    addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
-    serializeLibraryText(
-        '''
-import 'lib1.dart';
-A a;
-B b;
-C c;
-    ''',
-        allowErrors: true);
-    checkTypeRef(
-        findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
-    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
-    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
-  }
-
-  test_cascaded_export_show_hide() {
-    addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B hide B, C;');
-    addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
-    serializeLibraryText(
-        '''
-import 'lib1.dart';
-A a;
-B b;
-C c;
-    ''',
-        allowErrors: true);
-    checkTypeRef(
-        findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
-    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
-    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
-  }
-
-  test_cascaded_export_show_show() {
-    addNamedSource('/lib1.dart', 'export "lib2.dart" show A, B show A, C;');
-    addNamedSource('/lib2.dart', 'class A {} class B {} class C {}');
-    serializeLibraryText(
-        '''
-import 'lib1.dart';
-A a;
-B b;
-C c;
-    ''',
-        allowErrors: true);
-    checkTypeRef(
-        findVariable('a').type, absUri('/lib2.dart'), 'lib2.dart', 'A');
-    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
-    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
-  }
-
-  test_cascaded_import_hide_hide() {
-    addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
-    serializeLibraryText(
-        '''
-import 'lib.dart' hide C hide B, C;
-A a;
-B b;
-C c;
-    ''',
-        allowErrors: true);
-    checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
-    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
-    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
-  }
-
-  test_cascaded_import_hide_show() {
-    addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
-    serializeLibraryText(
-        '''
-import 'lib.dart' hide C show A, C;
-A a;
-B b;
-C c;
-    ''',
-        allowErrors: true);
-    checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
-    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
-    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
-  }
-
-  test_cascaded_import_show_hide() {
-    addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
-    serializeLibraryText(
-        '''
-import 'lib.dart' show A, B hide B, C;
-A a;
-B b;
-C c;
-    ''',
-        allowErrors: true);
-    checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
-    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
-    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
-  }
-
-  test_cascaded_import_show_show() {
-    addNamedSource('/lib.dart', 'class A {} class B {} class C {}');
-    serializeLibraryText(
-        '''
-import 'lib.dart' show A, B show A, C;
-A a;
-B b;
-C c;
-    ''',
-        allowErrors: true);
-    checkTypeRef(findVariable('a').type, absUri('/lib.dart'), 'lib.dart', 'A');
-    checkUnresolvedTypeRef(findVariable('b').type, null, 'B');
-    checkUnresolvedTypeRef(findVariable('c').type, null, 'C');
-  }
-
-  test_class_abstract() {
-    UnlinkedClass cls = serializeClassText('abstract class C {}');
-    expect(cls.isAbstract, true);
-  }
-
-  test_class_alias_abstract() {
-    UnlinkedClass cls = serializeClassText(
-        'abstract class C = D with E; class D {} class E {}');
-    expect(cls.isAbstract, true);
-  }
-
-  test_class_alias_concrete() {
-    UnlinkedClass cls =
-        serializeClassText('class C = _D with _E; class _D {} class _E {}');
-    expect(cls.isAbstract, false);
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
-        PrelinkedReferenceKind.classOrEnum);
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
-  }
-
-  test_class_alias_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-class C = D with E;
-
-class D {}
-class E {}''';
-    UnlinkedClass cls = serializeClassText(text);
-    expect(cls.documentationComment, isNotNull);
-    checkDocumentationComment(cls.documentationComment, text);
-  }
-
-  test_class_alias_flag() {
-    UnlinkedClass cls =
-        serializeClassText('class C = D with E; class D {} class E {}');
-    expect(cls.isMixinApplication, true);
-  }
-
-  test_class_alias_generic() {
-    serializeClassText('class C<A, B> = _D with _E; class _D {} class _E {}');
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 2);
-  }
-
-  test_class_alias_mixin_order() {
-    UnlinkedClass cls = serializeClassText('''
-class C = D with E, F;
-class D {}
-class E {}
-class F {}
-''');
-    expect(cls.mixins, hasLength(2));
-    checkTypeRef(cls.mixins[0], null, null, 'E');
-    checkTypeRef(cls.mixins[1], null, null, 'F');
-  }
-
-  test_class_alias_no_implicit_constructors() {
-    UnlinkedClass cls = serializeClassText('''
-class C = D with E;
-class D {
-  D.foo();
-  D.bar();
-}
-class E {}
-''');
-    expect(cls.executables, isEmpty);
-  }
-
-  test_class_alias_private() {
-    serializeClassText('class _C = _D with _E; class _D {} class _E {}', '_C');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-  }
-
-  test_class_alias_reference_generic() {
-    UnlinkedTypeRef typeRef = serializeTypeText('C',
-        otherDeclarations: 'class C<D, E> = F with G; class F {} class G {}');
-    checkTypeRef(typeRef, null, null, 'C', numTypeParameters: 2);
-  }
-
-  test_class_alias_reference_generic_imported() {
-    addNamedSource(
-        '/lib.dart', 'class C<D, E> = F with G; class F {} class G {}');
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
-    checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'C',
-        numTypeParameters: 2);
-  }
-
-  test_class_alias_supertype() {
-    UnlinkedClass cls =
-        serializeClassText('class C = D with E; class D {} class E {}');
-    checkTypeRef(cls.supertype, null, null, 'D');
-    expect(cls.hasNoSupertype, isFalse);
-  }
-
-  test_class_concrete() {
-    UnlinkedClass cls = serializeClassText('class C {}');
-    expect(cls.isAbstract, false);
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
-        PrelinkedReferenceKind.classOrEnum);
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'C');
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
-  }
-
-  test_class_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-class C {}''';
-    UnlinkedClass cls = serializeClassText(text);
-    expect(cls.documentationComment, isNotNull);
-    checkDocumentationComment(cls.documentationComment, text);
-  }
-
-  test_class_documented_with_references() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs referring to [D] and [E]
- */
-class C {}
-
-class D {}
-class E {}''';
-    UnlinkedClass cls = serializeClassText(text);
-    expect(cls.documentationComment, isNotNull);
-    checkDocumentationComment(cls.documentationComment, text);
-  }
-
-  test_class_documented_with_with_windows_line_endings() {
-    String text = '/**\r\n * Docs\r\n */\r\nclass C {}';
-    UnlinkedClass cls = serializeClassText(text);
-    expect(cls.documentationComment, isNotNull);
-    checkDocumentationComment(cls.documentationComment, text);
-  }
-
-  test_class_interface() {
-    UnlinkedClass cls = serializeClassText('''
-class C implements D {}
-class D {}
-''');
-    expect(cls.interfaces, hasLength(1));
-    checkTypeRef(cls.interfaces[0], null, null, 'D');
-  }
-
-  test_class_interface_order() {
-    UnlinkedClass cls = serializeClassText('''
-class C implements D, E {}
-class D {}
-class E {}
-''');
-    expect(cls.interfaces, hasLength(2));
-    checkTypeRef(cls.interfaces[0], null, null, 'D');
-    checkTypeRef(cls.interfaces[1], null, null, 'E');
-  }
-
-  test_class_mixin() {
-    UnlinkedClass cls = serializeClassText('''
-class C extends Object with D {}
-class D {}
-''');
-    expect(cls.mixins, hasLength(1));
-    checkTypeRef(cls.mixins[0], null, null, 'D');
-  }
-
-  test_class_mixin_order() {
-    UnlinkedClass cls = serializeClassText('''
-class C extends Object with D, E {}
-class D {}
-class E {}
-''');
-    expect(cls.mixins, hasLength(2));
-    checkTypeRef(cls.mixins[0], null, null, 'D');
-    checkTypeRef(cls.mixins[1], null, null, 'E');
-  }
-
-  test_class_name() {
-    var classText = 'class C {}';
-    UnlinkedClass cls = serializeClassText(classText);
-    expect(cls.name, 'C');
-    expect(cls.nameOffset, classText.indexOf('C'));
-  }
-
-  test_class_no_flags() {
-    UnlinkedClass cls = serializeClassText('class C {}');
-    expect(cls.isAbstract, false);
-    expect(cls.isMixinApplication, false);
-  }
-
-  test_class_no_interface() {
-    UnlinkedClass cls = serializeClassText('class C {}');
-    expect(cls.interfaces, isEmpty);
-  }
-
-  test_class_no_mixins() {
-    UnlinkedClass cls = serializeClassText('class C {}');
-    expect(cls.mixins, isEmpty);
-  }
-
-  test_class_no_type_param() {
-    UnlinkedClass cls = serializeClassText('class C {}');
-    expect(cls.typeParameters, isEmpty);
-  }
-
-  test_class_non_alias_flag() {
-    UnlinkedClass cls = serializeClassText('class C {}');
-    expect(cls.isMixinApplication, false);
-  }
-
-  test_class_private() {
-    serializeClassText('class _C {}', '_C');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-  }
-
-  test_class_reference_generic() {
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('C', otherDeclarations: 'class C<D, E> {}');
-    checkTypeRef(typeRef, null, null, 'C', numTypeParameters: 2);
-  }
-
-  test_class_reference_generic_imported() {
-    addNamedSource('/lib.dart', 'class C<D, E> {}');
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('C', otherDeclarations: 'import "lib.dart";');
-    checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'C',
-        numTypeParameters: 2);
-  }
-
-  test_class_superclass() {
-    UnlinkedClass cls = serializeClassText('class C {}');
-    expect(cls.supertype, isNull);
-    expect(cls.hasNoSupertype, isFalse);
-  }
-
-  test_class_superclass_explicit() {
-    UnlinkedClass cls = serializeClassText('class C extends D {} class D {}');
-    expect(cls.supertype, isNotNull);
-    checkTypeRef(cls.supertype, null, null, 'D');
-    expect(cls.hasNoSupertype, isFalse);
-  }
-
-  test_class_type_param_bound() {
-    UnlinkedClass cls = serializeClassText('class C<T extends List> {}');
-    expect(cls.typeParameters, hasLength(1));
-    expect(cls.typeParameters[0].name, 'T');
-    expect(cls.typeParameters[0].bound, isNotNull);
-    checkTypeRef(cls.typeParameters[0].bound, 'dart:core', 'dart:core', 'List',
-        allowTypeParameters: true, numTypeParameters: 1);
-  }
-
-  test_class_type_param_f_bound() {
-    UnlinkedClass cls = serializeClassText('class C<T, U extends List<T>> {}');
-    UnlinkedTypeRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
-    checkParamTypeRef(typeArgument, 2);
-  }
-
-  test_class_type_param_f_bound_self_ref() {
-    UnlinkedClass cls = serializeClassText('class C<T, U extends List<U>> {}');
-    UnlinkedTypeRef typeArgument = cls.typeParameters[1].bound.typeArguments[0];
-    checkParamTypeRef(typeArgument, 1);
-  }
-
-  test_class_type_param_no_bound() {
-    String text = 'class C<T> {}';
-    UnlinkedClass cls = serializeClassText(text);
-    expect(cls.typeParameters, hasLength(1));
-    expect(cls.typeParameters[0].name, 'T');
-    expect(cls.typeParameters[0].nameOffset, text.indexOf('T'));
-    expect(cls.typeParameters[0].bound, isNull);
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
-  }
-
-  test_constructor() {
-    String text = 'class C { C(); }';
-    UnlinkedExecutable executable =
-        findExecutable('', executables: serializeClassText(text).executables);
-    expect(executable.kind, UnlinkedExecutableKind.constructor);
-    expect(executable.hasImplicitReturnType, isFalse);
-    expect(executable.isExternal, isFalse);
-    expect(executable.nameOffset, text.indexOf('C();'));
-  }
-
-  test_constructor_anonymous() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(); }').executables);
-    expect(executable.name, isEmpty);
-  }
-
-  test_constructor_const() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { const C(); }').executables);
-    expect(executable.isConst, isTrue);
-    expect(executable.isExternal, isFalse);
-  }
-
-  test_constructor_const_external() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { external const C(); }').executables);
-    expect(executable.isConst, isTrue);
-    expect(executable.isExternal, isTrue);
-  }
-
-  test_constructor_documented() {
-    String text = '''
-class C {
-  /**
-   * Docs
-   */
-  C();
-}''';
-    UnlinkedExecutable executable = serializeClassText(text).executables[0];
-    expect(executable.documentationComment, isNotNull);
-    checkDocumentationComment(executable.documentationComment, text);
-  }
-
-  test_constructor_external() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { external C(); }').executables);
-    expect(executable.isExternal, isTrue);
-  }
-
-  test_constructor_factory() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { factory C() => null; }').executables);
-    expect(executable.isFactory, isTrue);
-  }
-
-  test_constructor_implicit() {
-    // Implicit constructors are not serialized.
-    UnlinkedExecutable executable = findExecutable(null,
-        executables: serializeClassText('class C { C(); }').executables,
-        failIfAbsent: false);
-    expect(executable, isNull);
-  }
-
-  test_constructor_initializing_formal() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { C(this.x); final x; }').executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.isInitializingFormal, isTrue);
-  }
-
-  test_constructor_initializing_formal_explicit_type() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(int this.x); final x; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
-  }
-
-  test_constructor_initializing_formal_function_typed() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(this.x()); final x; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.isFunctionTyped, isTrue);
-  }
-
-  test_constructor_initializing_formal_function_typed_explicit_return_type() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { C(int this.x()); Function x; }')
-                .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
-  }
-
-  test_constructor_initializing_formal_function_typed_implicit_return_type() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(this.x()); Function x; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    // Since the parameter is function-typed it is considered to have an
-    // explicit type, even though that explicit type itself has an implicit
-    // return type.
-    expect(parameter.hasImplicitType, isFalse);
-    checkDynamicTypeRef(parameter.type);
-  }
-
-  test_constructor_initializing_formal_function_typed_no_parameters() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(this.x()); final x; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.parameters, isEmpty);
-  }
-
-  test_constructor_initializing_formal_function_typed_parameter() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(this.x(a)); final x; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.parameters, hasLength(1));
-  }
-
-  test_constructor_initializing_formal_function_typed_parameter_order() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(this.x(a, b)); final x; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.parameters, hasLength(2));
-    expect(parameter.parameters[0].name, 'a');
-    expect(parameter.parameters[1].name, 'b');
-  }
-
-  test_constructor_initializing_formal_implicit_type() {
-    // Note: the implicit type of an initializing formal is the type of the
-    // field.
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { C(this.x); int x; }').executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    checkTypeRef(parameter.type, 'dart:core', 'dart:core', 'int');
-    expect(parameter.hasImplicitType, isTrue);
-  }
-
-  test_constructor_initializing_formal_name() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { C(this.x); final x; }').executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.name, 'x');
-  }
-
-  test_constructor_initializing_formal_named() {
-    // TODO(paulberry): also test default value
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C({this.x}); final x; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.kind, UnlinkedParamKind.named);
-  }
-
-  test_constructor_initializing_formal_non_function_typed() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { C(this.x); final x; }').executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.isFunctionTyped, isFalse);
-  }
-
-  test_constructor_initializing_formal_positional() {
-    // TODO(paulberry): also test default value
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C([this.x]); final x; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.kind, UnlinkedParamKind.positional);
-  }
-
-  test_constructor_initializing_formal_required() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables:
-            serializeClassText('class C { C(this.x); final x; }').executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.kind, UnlinkedParamKind.required);
-  }
-
-  test_constructor_initializing_formal_typedef() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText(
-                'typedef F<T>(T x); class C<X> { C(this.f); F<X> f; }')
-            .executables);
-    UnlinkedParam parameter = executable.parameters[0];
-    expect(parameter.parameters, hasLength(1));
-  }
-
-  test_constructor_named() {
-    String text = 'class C { C.foo(); }';
-    UnlinkedExecutable executable = findExecutable('foo',
-        executables: serializeClassText(text).executables);
-    expect(executable.name, 'foo');
-    expect(executable.nameOffset, text.indexOf('foo'));
-  }
-
-  test_constructor_non_const() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(); }').executables);
-    expect(executable.isConst, isFalse);
-  }
-
-  test_constructor_non_factory() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(); }').executables);
-    expect(executable.isFactory, isFalse);
-  }
-
-  test_constructor_return_type() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C { C(); }').executables);
-    expect(executable.returnType, isNull);
-  }
-
-  test_constructor_return_type_parameterized() {
-    UnlinkedExecutable executable = findExecutable('',
-        executables: serializeClassText('class C<T, U> { C(); }').executables);
-    expect(executable.returnType, isNull);
-  }
-
-  test_dependencies_export_none() {
-    // Exports are not listed as dependencies since no change to the exported
-    // file can change the summary of the exporting file.
-    // TODO(paulberry): this needs to change since the element model for a
-    // library includes its export namespace.
-    addNamedSource('/a.dart', 'library a; export "b.dart";');
-    addNamedSource('/b.dart', 'library b;');
-    serializeLibraryText('export "a.dart";');
-    checkLacksDependency(absUri('/a.dart'), 'a.dart');
-    checkLacksDependency(absUri('/b.dart'), 'b.dart');
-  }
-
-  test_dependencies_import_to_export() {
-    addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
-    addNamedSource('/b.dart', 'library b;');
-    serializeLibraryText('import "a.dart"; A a;');
-    checkHasDependency(absUri('/a.dart'), 'a.dart');
-    // The main test library depends on b.dart, because names defined in
-    // b.dart are exported by a.dart.
-    checkHasDependency(absUri('/b.dart'), 'b.dart');
-  }
-
-  test_dependencies_import_to_export_in_subdirs_absolute_export() {
-    addNamedSource('/a/a.dart',
-        'library a; export "${absUri('/a/b/b.dart')}"; class A {}');
-    addNamedSource('/a/b/b.dart', 'library b;');
-    serializeLibraryText('import "a/a.dart"; A a;');
-    checkHasDependency(absUri('/a/a.dart'), 'a/a.dart');
-    // The main test library depends on b.dart, because names defined in
-    // b.dart are exported by a.dart.
-    checkHasDependency(absUri('/a/b/b.dart'), absUri('/a/b/b.dart'));
-  }
-
-  test_dependencies_import_to_export_in_subdirs_absolute_import() {
-    addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
-    addNamedSource('/a/b/b.dart', 'library b;');
-    serializeLibraryText('import "${absUri('/a/a.dart')}"; A a;');
-    checkHasDependency(absUri('/a/a.dart'), absUri('/a/a.dart'));
-    // The main test library depends on b.dart, because names defined in
-    // b.dart are exported by a.dart.
-    checkHasDependency(absUri('/a/b/b.dart'), absUri('/a/b/b.dart'));
-  }
-
-  test_dependencies_import_to_export_in_subdirs_relative() {
-    addNamedSource('/a/a.dart', 'library a; export "b/b.dart"; class A {}');
-    addNamedSource('/a/b/b.dart', 'library b;');
-    serializeLibraryText('import "a/a.dart"; A a;');
-    checkHasDependency(absUri('/a/a.dart'), 'a/a.dart');
-    // The main test library depends on b.dart, because names defined in
-    // b.dart are exported by a.dart.
-    checkHasDependency(absUri('/a/b/b.dart'), 'a/b/b.dart');
-  }
-
-  test_dependencies_import_to_export_loop() {
-    addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
-    addNamedSource('/b.dart', 'library b; export "a.dart";');
-    serializeLibraryText('import "a.dart"; A a;');
-    checkHasDependency(absUri('/a.dart'), 'a.dart');
-    // Serialization should have been able to walk the transitive export
-    // dependencies to b.dart without going into an infinite loop.
-    checkHasDependency(absUri('/b.dart'), 'b.dart');
-  }
-
-  test_dependencies_import_to_export_transitive_closure() {
-    addNamedSource('/a.dart', 'library a; export "b.dart"; class A {}');
-    addNamedSource('/b.dart', 'library b; export "c.dart";');
-    addNamedSource('/c.dart', 'library c;');
-    serializeLibraryText('import "a.dart"; A a;');
-    checkHasDependency(absUri('/a.dart'), 'a.dart');
-    // The main test library depends on c.dart, because names defined in
-    // c.dart are exported by b.dart and then re-exported by a.dart.
-    checkHasDependency(absUri('/c.dart'), 'c.dart');
-  }
-
-  test_dependencies_import_transitive_closure() {
-    addNamedSource(
-        '/a.dart', 'library a; import "b.dart"; class A extends B {}');
-    addNamedSource('/b.dart', 'library b; class B {}');
-    serializeLibraryText('import "a.dart"; A a;');
-    checkHasDependency(absUri('/a.dart'), 'a.dart');
-    // The main test library doesn't depend on b.dart, because no change to
-    // b.dart can possibly affect the serialized element model for it.
-    checkLacksDependency(absUri('/b.dart'), 'b.dart');
-  }
-
-  test_dependencies_parts() {
-    addNamedSource(
-        '/a.dart', 'library a; part "b.dart"; part "c.dart"; class A {}');
-    addNamedSource('/b.dart', 'part of a;');
-    addNamedSource('/c.dart', 'part of a;');
-    serializeLibraryText('import "a.dart"; A a;');
-    PrelinkedDependency dep = checkHasDependency(absUri('/a.dart'), 'a.dart');
-    checkDependencyParts(
-        dep, [absUri('/b.dart'), absUri('/c.dart')], ['b.dart', 'c.dart']);
-  }
-
-  test_dependencies_parts_relative_to_importing_library() {
-    addNamedSource('/a/b.dart', 'export "c/d.dart";');
-    addNamedSource('/a/c/d.dart',
-        'library d; part "e/f.dart"; part "g/h.dart"; class D {}');
-    addNamedSource('/a/c/e/f.dart', 'part of d;');
-    addNamedSource('/a/c/g/h.dart', 'part of d;');
-    serializeLibraryText('import "a/b.dart"; D d;');
-    PrelinkedDependency dep =
-        checkHasDependency(absUri('/a/c/d.dart'), 'a/c/d.dart');
-    checkDependencyParts(
-        dep,
-        [absUri('/a/c/e/f.dart'), absUri('/a/c/g/h.dart')],
-        ['a/c/e/f.dart', 'a/c/g/h.dart']);
-  }
-
-  test_elements_in_part() {
-    addNamedSource(
-        '/part1.dart',
-        '''
-part of my.lib;
-
-class C {}
-enum E { v }
-var v;
-f() {}
-typedef F();
-''');
-    serializeLibraryText('library my.lib; part "part1.dart";');
-    UnlinkedUnit unit = unlinkedUnits[1];
-    expect(findClass('C', unit: unit), isNotNull);
-    expect(findEnum('E', unit: unit), isNotNull);
-    expect(findVariable('v', variables: unit.variables), isNotNull);
-    expect(findExecutable('f', executables: unit.executables), isNotNull);
-    expect(findTypedef('F', unit: unit), isNotNull);
-  }
-
-  test_enum() {
-    String text = 'enum E { v1 }';
-    UnlinkedEnum e = serializeEnumText(text);
-    expect(e.name, 'E');
-    expect(e.nameOffset, text.indexOf('E'));
-    expect(e.values, hasLength(1));
-    expect(e.values[0].name, 'v1');
-    expect(e.values[0].nameOffset, text.indexOf('v1'));
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
-        PrelinkedReferenceKind.classOrEnum);
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'E');
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
-  }
-
-  test_enum_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-enum E { v }''';
-    UnlinkedEnum enm = serializeEnumText(text);
-    expect(enm.documentationComment, isNotNull);
-    checkDocumentationComment(enm.documentationComment, text);
-  }
-
-  test_enum_order() {
-    UnlinkedEnum e = serializeEnumText('enum E { v1, v2 }');
-    expect(e.values, hasLength(2));
-    expect(e.values[0].name, 'v1');
-    expect(e.values[1].name, 'v2');
-  }
-
-  test_enum_private() {
-    serializeEnumText('enum _E { v1 }', '_E');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-  }
-
-  test_executable_abstract() {
-    UnlinkedExecutable executable =
-        serializeClassText('abstract class C { f(); }').executables[0];
-    expect(executable.isAbstract, isTrue);
-  }
-
-  test_executable_concrete() {
-    UnlinkedExecutable executable =
-        serializeClassText('abstract class C { f() {} }').executables[0];
-    expect(executable.isAbstract, isFalse);
-  }
-
-  test_executable_function() {
-    String text = '  f() {}';
-    UnlinkedExecutable executable = serializeExecutableText(text);
-    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
-    expect(executable.hasImplicitReturnType, isTrue);
-    checkDynamicTypeRef(executable.returnType);
-    expect(executable.isExternal, isFalse);
-    expect(executable.nameOffset, text.indexOf('f'));
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
-        PrelinkedReferenceKind.other);
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
-  }
-
-  test_executable_function_explicit_return() {
-    UnlinkedExecutable executable =
-        serializeExecutableText('dynamic f() => null;');
-    expect(executable.hasImplicitReturnType, isFalse);
-    checkDynamicTypeRef(executable.returnType);
-  }
-
-  test_executable_function_external() {
-    UnlinkedExecutable executable = serializeExecutableText('external f();');
-    expect(executable.isExternal, isTrue);
-  }
-
-  test_executable_function_private() {
-    serializeExecutableText('_f() {}', '_f');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-  }
-
-  test_executable_getter() {
-    String text = 'int get f => 1;';
-    UnlinkedExecutable executable = serializeExecutableText(text);
-    expect(executable.kind, UnlinkedExecutableKind.getter);
-    expect(executable.hasImplicitReturnType, isFalse);
-    expect(executable.isExternal, isFalse);
-    expect(executable.nameOffset, text.indexOf('f'));
-    expect(findVariable('f'), isNull);
-    expect(findExecutable('f='), isNull);
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
-        PrelinkedReferenceKind.other);
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f');
-  }
-
-  test_executable_getter_external() {
-    UnlinkedExecutable executable =
-        serializeExecutableText('external int get f;');
-    expect(executable.isExternal, isTrue);
-  }
-
-  test_executable_getter_private() {
-    serializeExecutableText('int get _f => 1;', '_f');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-  }
-
-  test_executable_getter_type() {
-    UnlinkedExecutable executable = serializeExecutableText('int get f => 1;');
-    checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'int');
-    expect(executable.parameters, isEmpty);
-  }
-
-  test_executable_getter_type_implicit() {
-    UnlinkedExecutable executable = serializeExecutableText('get f => 1;');
-    checkDynamicTypeRef(executable.returnType);
-    expect(executable.hasImplicitReturnType, isTrue);
-    expect(executable.parameters, isEmpty);
-  }
-
-  test_executable_member_function() {
-    UnlinkedExecutable executable = findExecutable('f',
-        executables: serializeClassText('class C { f() {} }').executables);
-    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
-    expect(executable.hasImplicitReturnType, isTrue);
-    expect(executable.isExternal, isFalse);
-  }
-
-  test_executable_member_function_explicit_return() {
-    UnlinkedExecutable executable = findExecutable('f',
-        executables:
-            serializeClassText('class C { dynamic f() => null; }').executables);
-    expect(executable.hasImplicitReturnType, isFalse);
-  }
-
-  test_executable_member_function_external() {
-    UnlinkedExecutable executable = findExecutable('f',
-        executables:
-            serializeClassText('class C { external f(); }').executables);
-    expect(executable.isExternal, isTrue);
-  }
-
-  test_executable_member_getter() {
-    UnlinkedClass cls = serializeClassText('class C { int get f => 1; }');
-    UnlinkedExecutable executable =
-        findExecutable('f', executables: cls.executables, failIfAbsent: true);
-    expect(executable.kind, UnlinkedExecutableKind.getter);
-    expect(executable.hasImplicitReturnType, isFalse);
-    expect(executable.isExternal, isFalse);
-    expect(findVariable('f', variables: cls.fields), isNull);
-    expect(findExecutable('f=', executables: cls.executables), isNull);
-  }
-
-  test_executable_member_getter_external() {
-    UnlinkedClass cls = serializeClassText('class C { external int get f; }');
-    UnlinkedExecutable executable =
-        findExecutable('f', executables: cls.executables, failIfAbsent: true);
-    expect(executable.isExternal, isTrue);
-  }
-
-  test_executable_member_setter() {
-    UnlinkedClass cls = serializeClassText('class C { void set f(value) {} }');
-    UnlinkedExecutable executable =
-        findExecutable('f=', executables: cls.executables, failIfAbsent: true);
-    expect(executable.kind, UnlinkedExecutableKind.setter);
-    expect(executable.hasImplicitReturnType, isFalse);
-    expect(executable.isExternal, isFalse);
-    expect(findVariable('f', variables: cls.fields), isNull);
-    expect(findExecutable('f', executables: cls.executables), isNull);
-  }
-
-  test_executable_member_setter_external() {
-    UnlinkedClass cls =
-        serializeClassText('class C { external void set f(value); }');
-    UnlinkedExecutable executable =
-        findExecutable('f=', executables: cls.executables, failIfAbsent: true);
-    expect(executable.isExternal, isTrue);
-  }
-
-  test_executable_member_setter_implicit_return() {
-    UnlinkedClass cls = serializeClassText('class C { set f(value) {} }');
-    UnlinkedExecutable executable =
-        findExecutable('f=', executables: cls.executables, failIfAbsent: true);
-    expect(executable.hasImplicitReturnType, isTrue);
-    checkDynamicTypeRef(executable.returnType);
-  }
-
-  test_executable_name() {
-    UnlinkedExecutable executable = serializeExecutableText('f() {}');
-    expect(executable.name, 'f');
-  }
-
-  test_executable_no_flags() {
-    UnlinkedExecutable executable = serializeExecutableText('f() {}');
-    expect(executable.isAbstract, isFalse);
-    expect(executable.isConst, isFalse);
-    expect(executable.isFactory, isFalse);
-    expect(executable.isStatic, isFalse);
-  }
-
-  test_executable_non_static() {
-    UnlinkedExecutable executable =
-        serializeClassText('class C { f() {} }').executables[0];
-    expect(executable.isStatic, isFalse);
-  }
-
-  test_executable_non_static_top_level() {
-    // Top level executables are considered non-static.
-    UnlinkedExecutable executable = serializeExecutableText('f() {}');
-    expect(executable.isStatic, isFalse);
-  }
-
-  test_executable_operator() {
-    UnlinkedExecutable executable =
-        serializeClassText('class C { C operator+(C c) => null; }').executables[
-            0];
-    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
-    expect(executable.name, '+');
-    expect(executable.hasImplicitReturnType, false);
-    expect(executable.isAbstract, false);
-    expect(executable.isConst, false);
-    expect(executable.isFactory, false);
-    expect(executable.isStatic, false);
-    expect(executable.parameters, hasLength(1));
-    checkTypeRef(executable.returnType, null, null, 'C');
-    expect(executable.typeParameters, isEmpty);
-    expect(executable.isExternal, false);
-  }
-
-  test_executable_operator_equal() {
-    UnlinkedExecutable executable =
-        serializeClassText('class C { bool operator==(C other) => false; }')
-            .executables[0];
-    expect(executable.name, '==');
-  }
-
-  test_executable_operator_external() {
-    UnlinkedExecutable executable =
-        serializeClassText('class C { external C operator+(C c); }')
-            .executables[0];
-    expect(executable.isExternal, true);
-  }
-
-  test_executable_operator_greater_equal() {
-    UnlinkedExecutable executable =
-        serializeClassText('class C { bool operator>=(C other) => false; }')
-            .executables[0];
-    expect(executable.name, '>=');
-  }
-
-  test_executable_operator_index() {
-    UnlinkedExecutable executable =
-        serializeClassText('class C { bool operator[](int i) => null; }')
-            .executables[0];
-    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
-    expect(executable.name, '[]');
-    expect(executable.hasImplicitReturnType, false);
-    expect(executable.isAbstract, false);
-    expect(executable.isConst, false);
-    expect(executable.isFactory, false);
-    expect(executable.isStatic, false);
-    expect(executable.parameters, hasLength(1));
-    checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'bool');
-    expect(executable.typeParameters, isEmpty);
-  }
-
-  test_executable_operator_index_set() {
-    UnlinkedExecutable executable = serializeClassText(
-        'class C { void operator[]=(int i, bool v) => null; }').executables[0];
-    expect(executable.kind, UnlinkedExecutableKind.functionOrMethod);
-    expect(executable.name, '[]=');
-    expect(executable.hasImplicitReturnType, false);
-    expect(executable.isAbstract, false);
-    expect(executable.isConst, false);
-    expect(executable.isFactory, false);
-    expect(executable.isStatic, false);
-    expect(executable.parameters, hasLength(2));
-    expect(executable.returnType, isNull);
-    expect(executable.typeParameters, isEmpty);
-  }
-
-  test_executable_operator_less_equal() {
-    UnlinkedExecutable executable =
-        serializeClassText('class C { bool operator<=(C other) => false; }')
-            .executables[0];
-    expect(executable.name, '<=');
-  }
-
-  test_executable_param_function_typed() {
-    UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
-    expect(executable.parameters[0].isFunctionTyped, isTrue);
-    // Since the parameter is function-typed it is considered to have an
-    // explicit type, even though that explicit type itself has an implicit
-    // return type.
-    expect(executable.parameters[0].hasImplicitType, isFalse);
-  }
-
-  test_executable_param_function_typed_explicit_return_type() {
-    UnlinkedExecutable executable =
-        serializeExecutableText('f(dynamic g()) {}');
-    expect(executable.parameters[0].hasImplicitType, isFalse);
-  }
-
-  test_executable_param_function_typed_param() {
-    UnlinkedExecutable executable = serializeExecutableText('f(g(x)) {}');
-    expect(executable.parameters[0].parameters, hasLength(1));
-  }
-
-  test_executable_param_function_typed_param_none() {
-    UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
-    expect(executable.parameters[0].parameters, isEmpty);
-  }
-
-  test_executable_param_function_typed_param_order() {
-    UnlinkedExecutable executable = serializeExecutableText('f(g(x, y)) {}');
-    expect(executable.parameters[0].parameters, hasLength(2));
-    expect(executable.parameters[0].parameters[0].name, 'x');
-    expect(executable.parameters[0].parameters[1].name, 'y');
-  }
-
-  test_executable_param_function_typed_return_type() {
-    UnlinkedExecutable executable = serializeExecutableText('f(int g()) {}');
-    checkTypeRef(
-        executable.parameters[0].type, 'dart:core', 'dart:core', 'int');
-  }
-
-  test_executable_param_function_typed_return_type_implicit() {
-    UnlinkedExecutable executable = serializeExecutableText('f(g()) {}');
-    checkDynamicTypeRef(executable.parameters[0].type);
-  }
-
-  test_executable_param_function_typed_return_type_void() {
-    UnlinkedExecutable executable = serializeExecutableText('f(void g()) {}');
-    expect(executable.parameters[0].type, isNull);
-  }
-
-  test_executable_param_kind_named() {
-    UnlinkedExecutable executable = serializeExecutableText('f({x}) {}');
-    expect(executable.parameters[0].kind, UnlinkedParamKind.named);
-  }
-
-  test_executable_param_kind_positional() {
-    UnlinkedExecutable executable = serializeExecutableText('f([x]) {}');
-    expect(executable.parameters[0].kind, UnlinkedParamKind.positional);
-  }
-
-  test_executable_param_kind_required() {
-    UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
-    expect(executable.parameters[0].kind, UnlinkedParamKind.required);
-  }
-
-  test_executable_param_name() {
-    String text = 'f(x) {}';
-    UnlinkedExecutable executable = serializeExecutableText(text);
-    expect(executable.parameters, hasLength(1));
-    expect(executable.parameters[0].name, 'x');
-    expect(executable.parameters[0].nameOffset, text.indexOf('x'));
-  }
-
-  test_executable_param_no_flags() {
-    UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
-    expect(executable.parameters[0].isFunctionTyped, isFalse);
-    expect(executable.parameters[0].isInitializingFormal, isFalse);
-  }
-
-  test_executable_param_non_function_typed() {
-    UnlinkedExecutable executable = serializeExecutableText('f(g) {}');
-    expect(executable.parameters[0].isFunctionTyped, isFalse);
-  }
-
-  test_executable_param_none() {
-    UnlinkedExecutable executable = serializeExecutableText('f() {}');
-    expect(executable.parameters, isEmpty);
-  }
-
-  test_executable_param_order() {
-    UnlinkedExecutable executable = serializeExecutableText('f(x, y) {}');
-    expect(executable.parameters, hasLength(2));
-    expect(executable.parameters[0].name, 'x');
-    expect(executable.parameters[1].name, 'y');
-  }
-
-  test_executable_param_type_explicit() {
-    UnlinkedExecutable executable = serializeExecutableText('f(dynamic x) {}');
-    checkDynamicTypeRef(executable.parameters[0].type);
-    expect(executable.parameters[0].hasImplicitType, isFalse);
-  }
-
-  test_executable_param_type_implicit() {
-    UnlinkedExecutable executable = serializeExecutableText('f(x) {}');
-    checkDynamicTypeRef(executable.parameters[0].type);
-    expect(executable.parameters[0].hasImplicitType, isTrue);
-  }
-
-  test_executable_return_type() {
-    UnlinkedExecutable executable = serializeExecutableText('int f() => 1;');
-    checkTypeRef(executable.returnType, 'dart:core', 'dart:core', 'int');
-    expect(executable.hasImplicitReturnType, isFalse);
-  }
-
-  test_executable_return_type_implicit() {
-    UnlinkedExecutable executable = serializeExecutableText('f() {}');
-    checkDynamicTypeRef(executable.returnType);
-    expect(executable.hasImplicitReturnType, isTrue);
-  }
-
-  test_executable_return_type_void() {
-    UnlinkedExecutable executable = serializeExecutableText('void f() {}');
-    expect(executable.returnType, isNull);
-  }
-
-  test_executable_setter() {
-    String text = 'void set f(value) {}';
-    UnlinkedExecutable executable = serializeExecutableText(text, 'f=');
-    expect(executable.kind, UnlinkedExecutableKind.setter);
-    expect(executable.hasImplicitReturnType, isFalse);
-    expect(executable.isExternal, isFalse);
-    expect(executable.nameOffset, text.indexOf('f'));
-    expect(findVariable('f'), isNull);
-    expect(findExecutable('f'), isNull);
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
-        PrelinkedReferenceKind.other);
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'f=');
-  }
-
-  test_executable_setter_external() {
-    UnlinkedExecutable executable =
-        serializeExecutableText('external void set f(value);', 'f=');
-    expect(executable.isExternal, isTrue);
-  }
-
-  test_executable_setter_implicit_return() {
-    UnlinkedExecutable executable =
-        serializeExecutableText('set f(value) {}', 'f=');
-    expect(executable.hasImplicitReturnType, isTrue);
-    checkDynamicTypeRef(executable.returnType);
-  }
-
-  test_executable_setter_private() {
-    serializeExecutableText('void set _f(value) {}', '_f=');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-  }
-
-  test_executable_setter_type() {
-    UnlinkedExecutable executable =
-        serializeExecutableText('void set f(int value) {}', 'f=');
-    expect(executable.returnType, isNull);
-    expect(executable.parameters, hasLength(1));
-    expect(executable.parameters[0].name, 'value');
-    checkTypeRef(
-        executable.parameters[0].type, 'dart:core', 'dart:core', 'int');
-  }
-
-  test_executable_static() {
-    UnlinkedExecutable executable =
-        serializeClassText('class C { static f() {} }').executables[0];
-    expect(executable.isStatic, isTrue);
-  }
-
-  test_executable_type_param_f_bound_function() {
-    UnlinkedExecutable ex =
-        serializeExecutableText('void f<T, U extends List<T>>() {}');
-    UnlinkedTypeRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
-    checkParamTypeRef(typeArgument, 2);
-  }
-
-  test_executable_type_param_f_bound_method() {
-    UnlinkedExecutable ex =
-        serializeMethodText('void f<T, U extends List<T>>() {}');
-    UnlinkedTypeRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
-    checkParamTypeRef(typeArgument, 2);
-  }
-
-  test_executable_type_param_f_bound_self_ref_function() {
-    UnlinkedExecutable ex =
-        serializeExecutableText('void f<T, U extends List<U>>() {}');
-    UnlinkedTypeRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
-    checkParamTypeRef(typeArgument, 1);
-  }
-
-  test_executable_type_param_f_bound_self_ref_method() {
-    UnlinkedExecutable ex =
-        serializeMethodText('void f<T, U extends List<U>>() {}');
-    UnlinkedTypeRef typeArgument = ex.typeParameters[1].bound.typeArguments[0];
-    checkParamTypeRef(typeArgument, 1);
-  }
-
-  test_executable_type_param_in_parameter_function() {
-    UnlinkedExecutable ex = serializeExecutableText('void f<T>(T t) {}');
-    checkParamTypeRef(ex.parameters[0].type, 1);
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
-  }
-
-  test_executable_type_param_in_parameter_method() {
-    UnlinkedExecutable ex = serializeMethodText('void f<T>(T t) {}');
-    checkParamTypeRef(ex.parameters[0].type, 1);
-  }
-
-  test_executable_type_param_in_return_type_function() {
-    UnlinkedExecutable ex = serializeExecutableText('T f<T>() => null;');
-    checkParamTypeRef(ex.returnType, 1);
-  }
-
-  test_executable_type_param_in_return_type_method() {
-    UnlinkedExecutable ex = serializeMethodText('T f<T>() => null;');
-    checkParamTypeRef(ex.returnType, 1);
-  }
-
-  test_export_hide_order() {
-    serializeLibraryText('export "dart:async" hide Future, Stream;');
-    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
-    expect(
-        unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
-        isEmpty);
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
-        hasLength(2));
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[0],
-        'Future');
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides[1],
-        'Stream');
-  }
-
-  test_export_no_combinators() {
-    serializeLibraryText('export "dart:async";');
-    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators, isEmpty);
-  }
-
-  test_export_offset() {
-    String libraryText = '    export "dart:async";';
-    serializeLibraryText(libraryText);
-    expect(unlinkedUnits[0].exports[0].uriOffset,
-        libraryText.indexOf('"dart:async"'));
-    expect(unlinkedUnits[0].exports[0].uriEnd, libraryText.indexOf(';'));
-    expect(unlinkedUnits[0].exports[0].offset, libraryText.indexOf('export'));
-  }
-
-  test_export_show_order() {
-    serializeLibraryText('export "dart:async" show Future, Stream;');
-    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
-    expect(
-        unlinkedUnits[0].publicNamespace.exports[0].combinators, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows,
-        hasLength(2));
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].hides,
-        isEmpty);
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[0],
-        'Future');
-    expect(unlinkedUnits[0].publicNamespace.exports[0].combinators[0].shows[1],
-        'Stream');
-  }
-
-  test_export_uri() {
-    addNamedSource('/a.dart', 'library my.lib;');
-    String uriString = '"a.dart"';
-    String libraryText = 'export $uriString;';
-    serializeLibraryText(libraryText);
-    expect(unlinkedUnits[0].publicNamespace.exports, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.exports[0].uri, 'a.dart');
-  }
-
-  test_field() {
-    UnlinkedClass cls = serializeClassText('class C { int i; }');
-    UnlinkedVariable variable = findVariable('i', variables: cls.fields);
-    expect(variable, isNotNull);
-    expect(variable.isConst, isFalse);
-    expect(variable.isStatic, isFalse);
-    expect(variable.isFinal, isFalse);
-    expect(findExecutable('i', executables: cls.executables), isNull);
-    expect(findExecutable('i=', executables: cls.executables), isNull);
-  }
-
-  test_field_const() {
-    UnlinkedVariable variable =
-        serializeClassText('class C { static const int i = 0; }').fields[0];
-    expect(variable.isConst, isTrue);
-  }
-
-  test_field_documented() {
-    String text = '''
-class C {
-  /**
-   * Docs
-   */
-  var v;
-}''';
-    UnlinkedVariable variable = serializeClassText(text).fields[0];
-    expect(variable.documentationComment, isNotNull);
-    checkDocumentationComment(variable.documentationComment, text);
-  }
-
-  test_field_final() {
-    UnlinkedVariable variable =
-        serializeClassText('class C { final int i = 0; }').fields[0];
-    expect(variable.isFinal, isTrue);
-  }
-
-  test_field_static() {
-    UnlinkedVariable variable =
-        serializeClassText('class C { static int i; }').fields[0];
-    expect(variable.isStatic, isTrue);
-  }
-
-  test_function_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-f() {}''';
-    UnlinkedExecutable executable = serializeExecutableText(text);
-    expect(executable.documentationComment, isNotNull);
-    checkDocumentationComment(executable.documentationComment, text);
-  }
-
-  test_generic_method_in_generic_class() {
-    UnlinkedClass cls = serializeClassText(
-        'class C<T, U> { void m<V, W>(T t, U u, V v, W w) {} }');
-    List<UnlinkedParam> params = cls.executables[0].parameters;
-    checkParamTypeRef(params[0].type, 4);
-    checkParamTypeRef(params[1].type, 3);
-    checkParamTypeRef(params[2].type, 2);
-    checkParamTypeRef(params[3].type, 1);
-  }
-
-  test_getter_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-get f => null;''';
-    UnlinkedExecutable executable = serializeExecutableText(text);
-    expect(executable.documentationComment, isNotNull);
-    checkDocumentationComment(executable.documentationComment, text);
-  }
-
-  test_import_deferred() {
-    serializeLibraryText(
-        'import "dart:async" deferred as a; main() { print(a.Future); }');
-    expect(unlinkedUnits[0].imports[0].isDeferred, isTrue);
-  }
-
-  test_import_dependency() {
-    serializeLibraryText('import "dart:async"; Future x;');
-    // Second import is the implicit import of dart:core
-    expect(unlinkedUnits[0].imports, hasLength(2));
-    checkDependency(
-        prelinked.importDependencies[0], 'dart:async', 'dart:async');
-  }
-
-  test_import_explicit() {
-    serializeLibraryText('import "dart:core"; int i;');
-    expect(unlinkedUnits[0].imports, hasLength(1));
-    expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
-  }
-
-  test_import_hide_order() {
-    serializeLibraryText(
-        'import "dart:async" hide Future, Stream; Completer c;');
-    // Second import is the implicit import of dart:core
-    expect(unlinkedUnits[0].imports, hasLength(2));
-    expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
-    expect(unlinkedUnits[0].imports[0].combinators[0].shows, isEmpty);
-    expect(unlinkedUnits[0].imports[0].combinators[0].hides, hasLength(2));
-    expect(unlinkedUnits[0].imports[0].combinators[0].hides[0], 'Future');
-    expect(unlinkedUnits[0].imports[0].combinators[0].hides[1], 'Stream');
-  }
-
-  test_import_implicit() {
-    // The implicit import of dart:core is represented in the model.
-    serializeLibraryText('');
-    expect(unlinkedUnits[0].imports, hasLength(1));
-    checkDependency(prelinked.importDependencies[0], 'dart:core', 'dart:core');
-    expect(unlinkedUnits[0].imports[0].uri, isEmpty);
-    expect(unlinkedUnits[0].imports[0].uriOffset, 0);
-    expect(unlinkedUnits[0].imports[0].uriEnd, 0);
-    expect(unlinkedUnits[0].imports[0].prefixReference, 0);
-    expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
-    expect(unlinkedUnits[0].imports[0].isImplicit, isTrue);
-  }
-
-  test_import_no_combinators() {
-    serializeLibraryText('import "dart:async"; Future x;');
-    // Second import is the implicit import of dart:core
-    expect(unlinkedUnits[0].imports, hasLength(2));
-    expect(unlinkedUnits[0].imports[0].combinators, isEmpty);
-  }
-
-  test_import_no_flags() {
-    serializeLibraryText('import "dart:async"; Future x;');
-    expect(unlinkedUnits[0].imports[0].isImplicit, isFalse);
-    expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
-  }
-
-  test_import_non_deferred() {
-    serializeLibraryText(
-        'import "dart:async" as a; main() { print(a.Future); }');
-    expect(unlinkedUnits[0].imports[0].isDeferred, isFalse);
-  }
-
-  test_import_of_file_with_missing_part() {
-    // Other references in foo.dart should be resolved even though foo.dart's
-    // part declaration for bar.dart refers to a non-existent file.
-    allowMissingFiles = true;
-    addNamedSource('/foo.dart', 'part "bar.dart"; class C {}');
-    serializeLibraryText('import "foo.dart"; C x;');
-    checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'foo.dart', 'C');
-  }
-
-  test_import_of_missing_export() {
-    // Other references in foo.dart should be resolved even though foo.dart's
-    // re-export of bar.dart refers to a non-existent file.
-    allowMissingFiles = true;
-    addNamedSource('/foo.dart', 'export "bar.dart"; class C {}');
-    serializeLibraryText('import "foo.dart"; C x;');
-    checkTypeRef(findVariable('x').type, absUri('/foo.dart'), 'foo.dart', 'C');
-  }
-
-  test_import_offset() {
-    String libraryText = '    import "dart:async"; Future x;';
-    serializeLibraryText(libraryText);
-    expect(unlinkedUnits[0].imports[0].offset, libraryText.indexOf('import'));
-    expect(unlinkedUnits[0].imports[0].uriOffset,
-        libraryText.indexOf('"dart:async"'));
-    expect(unlinkedUnits[0].imports[0].uriEnd, libraryText.indexOf('; Future'));
-  }
-
-  test_import_prefix_name() {
-    String libraryText = 'import "dart:async" as a; a.Future x;';
-    serializeLibraryText(libraryText);
-    // Second import is the implicit import of dart:core
-    expect(unlinkedUnits[0].imports, hasLength(2));
-    checkPrefix(unlinkedUnits[0].imports[0].prefixReference, 'a');
-    expect(unlinkedUnits[0].imports[0].prefixOffset, libraryText.indexOf('a;'));
-  }
-
-  test_import_prefix_none() {
-    serializeLibraryText('import "dart:async"; Future x;');
-    // Second import is the implicit import of dart:core
-    expect(unlinkedUnits[0].imports, hasLength(2));
-    expect(unlinkedUnits[0].imports[0].prefixReference, 0);
-  }
-
-  test_import_prefix_not_in_public_namespace() {
-    serializeLibraryText('import "dart:async" as a; a.Future v;');
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'v');
-    expect(unlinkedUnits[0].publicNamespace.names[1].name, 'v=');
-  }
-
-  test_import_prefix_reference() {
-    UnlinkedVariable variable =
-        serializeVariableText('import "dart:async" as a; a.Future v;');
-    checkTypeRef(variable.type, 'dart:async', 'dart:async', 'Future',
-        expectedPrefix: 'a', numTypeParameters: 1);
-  }
-
-  test_import_prefixes_take_precedence_over_imported_names() {
-    addNamedSource('/a.dart', 'class b {} class A');
-    addNamedSource('/b.dart', 'class Cls {}');
-    addNamedSource('/c.dart', 'class Cls {}');
-    addNamedSource('/d.dart', 'class c {} class D');
-    serializeLibraryText('''
-import 'a.dart';
-import 'b.dart' as b;
-import 'c.dart' as c;
-import 'd.dart';
-A aCls;
-b.Cls bCls;
-c.Cls cCls;
-D dCls;
-''');
-    checkTypeRef(findVariable('aCls').type, absUri('/a.dart'), 'a.dart', 'A');
-    checkTypeRef(findVariable('bCls').type, absUri('/b.dart'), 'b.dart', 'Cls',
-        expectedPrefix: 'b');
-    checkTypeRef(findVariable('cCls').type, absUri('/c.dart'), 'c.dart', 'Cls',
-        expectedPrefix: 'c');
-    checkTypeRef(findVariable('dCls').type, absUri('/d.dart'), 'd.dart', 'D');
-  }
-
-  test_import_reference() {
-    UnlinkedVariable variable =
-        serializeVariableText('import "dart:async"; Future v;');
-    checkTypeRef(variable.type, 'dart:async', 'dart:async', 'Future',
-        numTypeParameters: 1);
-  }
-
-  test_import_reference_merged_no_prefix() {
-    serializeLibraryText('''
-import "dart:async" show Future;
-import "dart:async" show Stream;
-
-Future f;
-Stream s;
-''');
-    checkTypeRef(findVariable('f').type, 'dart:async', 'dart:async', 'Future',
-        numTypeParameters: 1);
-    checkTypeRef(findVariable('s').type, 'dart:async', 'dart:async', 'Stream',
-        numTypeParameters: 1);
-  }
-
-  test_import_reference_merged_prefixed() {
-    serializeLibraryText('''
-import "dart:async" as a show Future;
-import "dart:async" as a show Stream;
-
-a.Future f;
-a.Stream s;
-''');
-    checkTypeRef(findVariable('f').type, 'dart:async', 'dart:async', 'Future',
-        expectedPrefix: 'a', numTypeParameters: 1);
-    checkTypeRef(findVariable('s').type, 'dart:async', 'dart:async', 'Stream',
-        expectedPrefix: 'a', numTypeParameters: 1);
-  }
-
-  test_import_reference_merged_prefixed_separate_libraries() {
-    addNamedSource('/a.dart', 'class A {}');
-    addNamedSource('/b.dart', 'class B {}');
-    serializeLibraryText('''
-import 'a.dart' as p;
-import 'b.dart' as p;
-
-p.A a;
-p.B b;
-''');
-    checkTypeRef(findVariable('a').type, absUri('/a.dart'), 'a.dart', 'A',
-        expectedPrefix: 'p');
-    checkTypeRef(findVariable('b').type, absUri('/b.dart'), 'b.dart', 'B',
-        expectedPrefix: 'p');
-  }
-
-  test_import_show_order() {
-    String libraryText =
-        'import "dart:async" show Future, Stream; Future x; Stream y;';
-    serializeLibraryText(libraryText);
-    // Second import is the implicit import of dart:core
-    expect(unlinkedUnits[0].imports, hasLength(2));
-    expect(unlinkedUnits[0].imports[0].combinators, hasLength(1));
-    expect(unlinkedUnits[0].imports[0].combinators[0].shows, hasLength(2));
-    expect(unlinkedUnits[0].imports[0].combinators[0].hides, isEmpty);
-    expect(unlinkedUnits[0].imports[0].combinators[0].shows[0], 'Future');
-    expect(unlinkedUnits[0].imports[0].combinators[0].shows[1], 'Stream');
-  }
-
-  test_import_uri() {
-    String uriString = '"dart:async"';
-    String libraryText = 'import $uriString; Future x;';
-    serializeLibraryText(libraryText);
-    // Second import is the implicit import of dart:core
-    expect(unlinkedUnits[0].imports, hasLength(2));
-    expect(unlinkedUnits[0].imports[0].uri, 'dart:async');
-  }
-
-  test_library_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-library foo;''';
-    serializeLibraryText(text);
-    expect(unlinkedUnits[0].libraryDocumentationComment, isNotNull);
-    checkDocumentationComment(
-        unlinkedUnits[0].libraryDocumentationComment, text);
-  }
-
-  test_library_name_with_spaces() {
-    String text = 'library foo . bar ;';
-    serializeLibraryText(text);
-    expect(unlinkedUnits[0].libraryName, 'foo.bar');
-    expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo . bar'));
-    expect(unlinkedUnits[0].libraryNameLength, 'foo . bar'.length);
-  }
-
-  test_library_named() {
-    String text = 'library foo.bar;';
-    serializeLibraryText(text);
-    expect(unlinkedUnits[0].libraryName, 'foo.bar');
-    expect(unlinkedUnits[0].libraryNameOffset, text.indexOf('foo.bar'));
-    expect(unlinkedUnits[0].libraryNameLength, 'foo.bar'.length);
-  }
-
-  test_library_unnamed() {
-    serializeLibraryText('');
-    expect(unlinkedUnits[0].libraryName, isEmpty);
-    expect(unlinkedUnits[0].libraryNameOffset, 0);
-    expect(unlinkedUnits[0].libraryNameLength, 0);
-  }
-
-  test_library_with_missing_part() {
-    // References to other parts should still be resolved.
-    allowMissingFiles = true;
-    addNamedSource('/bar.dart', 'part of my.lib; class C {}');
-    serializeLibraryText(
-        'library my.lib; part "foo.dart"; part "bar.dart"; C c;',
-        allowErrors: true);
-    checkTypeRef(findVariable('c').type, null, null, 'C',
-        expectedTargetUnit: 2);
-  }
-
-  test_local_names_take_precedence_over_imported_names() {
-    addNamedSource('/a.dart', 'class C {} class D {}');
-    serializeLibraryText('''
-import 'a.dart';
-class C {}
-C c;
-D d;''');
-    checkTypeRef(findVariable('c').type, null, null, 'C');
-    checkTypeRef(findVariable('d').type, absUri('/a.dart'), 'a.dart', 'D');
-  }
-
-  test_method_documented() {
-    String text = '''
-class C {
-  /**
-   * Docs
-   */
-  f() {}
-}''';
-    UnlinkedExecutable executable = serializeClassText(text).executables[0];
-    expect(executable.documentationComment, isNotNull);
-    checkDocumentationComment(executable.documentationComment, text);
-  }
-
-  test_part_declaration() {
-    addNamedSource('/a.dart', 'part of my.lib;');
-    String text = 'library my.lib; part "a.dart"; // <-part';
-    serializeLibraryText(text);
-    expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.parts[0], 'a.dart');
-    expect(unlinkedUnits[0].parts, hasLength(1));
-    expect(unlinkedUnits[0].parts[0].uriOffset, text.indexOf('"a.dart"'));
-    expect(unlinkedUnits[0].parts[0].uriEnd, text.indexOf('; // <-part'));
-  }
-
-  test_parts_defining_compilation_unit() {
-    serializeLibraryText('');
-    expect(prelinked.units, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.parts, isEmpty);
-  }
-
-  test_parts_included() {
-    addNamedSource('/part1.dart', 'part of my.lib;');
-    String partString = '"part1.dart"';
-    String libraryText = 'library my.lib; part $partString;';
-    serializeLibraryText(libraryText);
-    expect(prelinked.units, hasLength(2));
-    expect(unlinkedUnits[0].publicNamespace.parts, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.parts[0], 'part1.dart');
-  }
-
-  test_public_namespace_of_part() {
-    addNamedSource('/a.dart', 'part of foo; class C {}');
-    serializeLibraryText('library foo; part "a.dart";');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-    expect(unlinkedUnits[1].publicNamespace.names, hasLength(1));
-    expect(unlinkedUnits[1].publicNamespace.names[0].name, 'C');
-  }
-
-  test_setter_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-void set f(value) {}''';
-    UnlinkedExecutable executable = serializeExecutableText(text, 'f=');
-    expect(executable.documentationComment, isNotNull);
-    checkDocumentationComment(executable.documentationComment, text);
-  }
-
-  test_type_arguments_explicit() {
-    UnlinkedTypeRef typeRef = serializeTypeText('List<int>');
-    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
-        allowTypeParameters: true, numTypeParameters: 1);
-    expect(typeRef.typeArguments, hasLength(1));
-    checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
-  }
-
-  test_type_arguments_explicit_dynamic() {
-    UnlinkedTypeRef typeRef = serializeTypeText('List<dynamic>');
-    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
-        allowTypeParameters: true, numTypeParameters: 1);
-    expect(typeRef.typeArguments, isEmpty);
-  }
-
-  test_type_arguments_explicit_dynamic_typedef() {
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('F<dynamic>', otherDeclarations: 'typedef T F<T>();');
-    checkTypeRef(typeRef, null, null, 'F',
-        allowTypeParameters: true,
-        expectedKind: PrelinkedReferenceKind.typedef,
-        numTypeParameters: 1);
-    expect(typeRef.typeArguments, isEmpty);
-  }
-
-  test_type_arguments_explicit_typedef() {
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('F<int>', otherDeclarations: 'typedef T F<T>();');
-    checkTypeRef(typeRef, null, null, 'F',
-        allowTypeParameters: true,
-        expectedKind: PrelinkedReferenceKind.typedef,
-        numTypeParameters: 1);
-    expect(typeRef.typeArguments, hasLength(1));
-    checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
-  }
-
-  test_type_arguments_implicit() {
-    UnlinkedTypeRef typeRef = serializeTypeText('List');
-    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'List',
-        allowTypeParameters: true, numTypeParameters: 1);
-    expect(typeRef.typeArguments, isEmpty);
-  }
-
-  test_type_arguments_implicit_typedef() {
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('F', otherDeclarations: 'typedef T F<T>();');
-    checkTypeRef(typeRef, null, null, 'F',
-        allowTypeParameters: true,
-        expectedKind: PrelinkedReferenceKind.typedef,
-        numTypeParameters: 1);
-    expect(typeRef.typeArguments, isEmpty);
-  }
-
-  test_type_arguments_order() {
-    UnlinkedTypeRef typeRef = serializeTypeText('Map<int, Object>');
-    checkTypeRef(typeRef, 'dart:core', 'dart:core', 'Map',
-        allowTypeParameters: true, numTypeParameters: 2);
-    expect(typeRef.typeArguments, hasLength(2));
-    checkTypeRef(typeRef.typeArguments[0], 'dart:core', 'dart:core', 'int');
-    checkTypeRef(typeRef.typeArguments[1], 'dart:core', 'dart:core', 'Object');
-  }
-
-  test_type_dynamic() {
-    checkDynamicTypeRef(serializeTypeText('dynamic'));
-  }
-
-  test_type_reference_from_part() {
-    addNamedSource('/a.dart', 'part of foo; C v;');
-    serializeLibraryText('library foo; part "a.dart"; class C {}');
-    checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
-        null, null, 'C',
-        expectedKind: PrelinkedReferenceKind.classOrEnum,
-        prelinkedSourceUnit: prelinked.units[1],
-        unlinkedSourceUnit: unlinkedUnits[1]);
-  }
-
-  test_type_reference_from_part_withPrefix() {
-    addNamedSource('/a.dart', 'class C {}');
-    addNamedSource('/p.dart', 'part of foo; a.C v;');
-    serializeLibraryText(
-        'library foo; import "a.dart"; import "a.dart" as a; part "p.dart";',
-        allowErrors: true);
-    checkTypeRef(findVariable('v', variables: unlinkedUnits[1].variables).type,
-        absUri('/a.dart'), 'a.dart', 'C',
-        expectedPrefix: 'a',
-        prelinkedSourceUnit: prelinked.units[1],
-        unlinkedSourceUnit: unlinkedUnits[1]);
-  }
-
-  test_type_reference_to_class_argument() {
-    UnlinkedClass cls = serializeClassText('class C<T, U> { T t; U u; }');
-    {
-      UnlinkedTypeRef typeRef =
-          findVariable('t', variables: cls.fields, failIfAbsent: true).type;
-      checkParamTypeRef(typeRef, 2);
-    }
-    {
-      UnlinkedTypeRef typeRef =
-          findVariable('u', variables: cls.fields, failIfAbsent: true).type;
-      checkParamTypeRef(typeRef, 1);
-    }
-  }
-
-  test_type_reference_to_import_of_export() {
-    addNamedSource('/a.dart', 'library a; export "b.dart";');
-    addNamedSource('/b.dart', 'library b; class C {}');
-    checkTypeRef(serializeTypeText('C', otherDeclarations: 'import "a.dart";'),
-        absUri('/b.dart'), 'b.dart', 'C');
-  }
-
-  test_type_reference_to_import_of_export_via_prefix() {
-    addNamedSource('/a.dart', 'library a; export "b.dart";');
-    addNamedSource('/b.dart', 'library b; class C {}');
-    checkTypeRef(
-        serializeTypeText('p.C', otherDeclarations: 'import "a.dart" as p;'),
-        absUri('/b.dart'),
-        'b.dart',
-        'C',
-        expectedPrefix: 'p');
-  }
-
-  test_type_reference_to_imported_part() {
-    addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
-    addNamedSource('/b.dart', 'part of my.lib; class C {}');
-    checkTypeRef(
-        serializeTypeText('C',
-            otherDeclarations: 'library my.lib; import "a.dart";'),
-        absUri('/a.dart'),
-        'a.dart',
-        'C',
-        expectedTargetUnit: 1);
-  }
-
-  test_type_reference_to_imported_part_with_prefix() {
-    addNamedSource('/a.dart', 'library my.lib; part "b.dart";');
-    addNamedSource('/b.dart', 'part of my.lib; class C {}');
-    checkTypeRef(
-        serializeTypeText('p.C',
-            otherDeclarations: 'library my.lib; import "a.dart" as p;'),
-        absUri('/a.dart'),
-        'a.dart',
-        'C',
-        expectedPrefix: 'p',
-        expectedTargetUnit: 1);
-  }
-
-  test_type_reference_to_internal_class() {
-    checkTypeRef(serializeTypeText('C', otherDeclarations: 'class C {}'), null,
-        null, 'C');
-  }
-
-  test_type_reference_to_internal_class_alias() {
-    checkTypeRef(
-        serializeTypeText('C',
-            otherDeclarations: 'class C = D with E; class D {} class E {}'),
-        null,
-        null,
-        'C');
-  }
-
-  test_type_reference_to_internal_enum() {
-    checkTypeRef(serializeTypeText('E', otherDeclarations: 'enum E { value }'),
-        null, null, 'E');
-  }
-
-  test_type_reference_to_local_part() {
-    addNamedSource('/a.dart', 'part of my.lib; class C {}');
-    checkTypeRef(
-        serializeTypeText('C',
-            otherDeclarations: 'library my.lib; part "a.dart";'),
-        null,
-        null,
-        'C',
-        expectedTargetUnit: 1);
-  }
-
-  test_type_reference_to_part() {
-    addNamedSource('/a.dart', 'part of foo; class C { C(); }');
-    serializeLibraryText('library foo; part "a.dart"; C c;');
-    checkTypeRef(unlinkedUnits[0].variables.single.type, null, null, 'C',
-        expectedKind: PrelinkedReferenceKind.classOrEnum,
-        expectedTargetUnit: 1);
-  }
-
-  test_type_reference_to_typedef() {
-    checkTypeRef(serializeTypeText('F', otherDeclarations: 'typedef void F();'),
-        null, null, 'F',
-        expectedKind: PrelinkedReferenceKind.typedef);
-  }
-
-  test_type_unit_counts_unreferenced_units() {
-    addNamedSource('/a.dart', 'library a; part "b.dart"; part "c.dart";');
-    addNamedSource('/b.dart', 'part of a;');
-    addNamedSource('/c.dart', 'part of a; class C {}');
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('C', otherDeclarations: 'import "a.dart";');
-    // The referenced unit should be 2, since unit 0 is a.dart and unit 1 is
-    // b.dart.  a.dart and b.dart are counted even though nothing is imported
-    // from them.
-    checkTypeRef(typeRef, absUri('/a.dart'), 'a.dart', 'C',
-        expectedTargetUnit: 2);
-  }
-
-  test_type_unresolved() {
-    UnlinkedTypeRef typeRef = serializeTypeText('Foo', allowErrors: true);
-    checkUnresolvedTypeRef(typeRef, null, 'Foo');
-  }
-
-  test_typedef_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-typedef F();''';
-    UnlinkedTypedef typedef = serializeTypedefText(text);
-    expect(typedef.documentationComment, isNotNull);
-    checkDocumentationComment(typedef.documentationComment, text);
-  }
-
-  test_typedef_name() {
-    String text = 'typedef F();';
-    UnlinkedTypedef type = serializeTypedefText(text);
-    expect(type.name, 'F');
-    expect(type.nameOffset, text.indexOf('F'));
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(1));
-    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
-        PrelinkedReferenceKind.typedef);
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'F');
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
-  }
-
-  test_typedef_param_none() {
-    UnlinkedTypedef type = serializeTypedefText('typedef F();');
-    expect(type.parameters, isEmpty);
-  }
-
-  test_typedef_param_order() {
-    UnlinkedTypedef type = serializeTypedefText('typedef F(x, y);');
-    expect(type.parameters, hasLength(2));
-    expect(type.parameters[0].name, 'x');
-    expect(type.parameters[1].name, 'y');
-  }
-
-  test_typedef_private() {
-    serializeTypedefText('typedef _F();', '_F');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-  }
-
-  test_typedef_reference_generic() {
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('F', otherDeclarations: 'typedef void F<A, B>();');
-    checkTypeRef(typeRef, null, null, 'F',
-        numTypeParameters: 2, expectedKind: PrelinkedReferenceKind.typedef);
-  }
-
-  test_typedef_reference_generic_imported() {
-    addNamedSource('/lib.dart', 'typedef void F<A, B>();');
-    UnlinkedTypeRef typeRef =
-        serializeTypeText('F', otherDeclarations: 'import "lib.dart";');
-    checkTypeRef(typeRef, absUri('/lib.dart'), 'lib.dart', 'F',
-        numTypeParameters: 2, expectedKind: PrelinkedReferenceKind.typedef);
-  }
-
-  test_typedef_return_type_explicit() {
-    UnlinkedTypedef type = serializeTypedefText('typedef int F();');
-    checkTypeRef(type.returnType, 'dart:core', 'dart:core', 'int');
-  }
-
-  test_typedef_type_param_in_parameter() {
-    UnlinkedTypedef type = serializeTypedefText('typedef F<T>(T t);');
-    checkParamTypeRef(type.parameters[0].type, 1);
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 1);
-  }
-
-  test_typedef_type_param_in_return_type() {
-    UnlinkedTypedef type = serializeTypedefText('typedef T F<T>();');
-    checkParamTypeRef(type.returnType, 1);
-  }
-
-  test_typedef_type_param_none() {
-    UnlinkedTypedef type = serializeTypedefText('typedef F();');
-    expect(type.typeParameters, isEmpty);
-  }
-
-  test_typedef_type_param_order() {
-    UnlinkedTypedef type = serializeTypedefText('typedef F<T, U>();');
-    expect(type.typeParameters, hasLength(2));
-    expect(type.typeParameters[0].name, 'T');
-    expect(type.typeParameters[1].name, 'U');
-  }
-
-  test_variable() {
-    String text = 'int i;';
-    UnlinkedVariable v = serializeVariableText(text, variableName: 'i');
-    expect(v.nameOffset, text.indexOf('i;'));
-    expect(findExecutable('i'), isNull);
-    expect(findExecutable('i='), isNull);
-    expect(unlinkedUnits[0].publicNamespace.names, hasLength(2));
-    expect(unlinkedUnits[0].publicNamespace.names[0].kind,
-        PrelinkedReferenceKind.other);
-    expect(unlinkedUnits[0].publicNamespace.names[0].name, 'i');
-    expect(unlinkedUnits[0].publicNamespace.names[0].numTypeParameters, 0);
-    expect(unlinkedUnits[0].publicNamespace.names[1].kind,
-        PrelinkedReferenceKind.other);
-    expect(unlinkedUnits[0].publicNamespace.names[1].name, 'i=');
-    expect(unlinkedUnits[0].publicNamespace.names[1].numTypeParameters, 0);
-  }
-
-  test_variable_const() {
-    UnlinkedVariable variable =
-        serializeVariableText('const int i = 0;', variableName: 'i');
-    expect(variable.isConst, isTrue);
-  }
-
-  test_variable_documented() {
-    String text = '''
-// Extra comment so doc comment offset != 0
-/**
- * Docs
- */
-var v;''';
-    UnlinkedVariable variable = serializeVariableText(text);
-    expect(variable.documentationComment, isNotNull);
-    checkDocumentationComment(variable.documentationComment, text);
-  }
-
-  test_variable_explicit_dynamic() {
-    UnlinkedVariable variable = serializeVariableText('dynamic v;');
-    checkDynamicTypeRef(variable.type);
-    expect(variable.hasImplicitType, isFalse);
-  }
-
-  test_variable_final_top_level() {
-    UnlinkedVariable variable =
-        serializeVariableText('final int i = 0;', variableName: 'i');
-    expect(variable.isFinal, isTrue);
-  }
-
-  test_variable_implicit_dynamic() {
-    UnlinkedVariable variable = serializeVariableText('var v;');
-    checkDynamicTypeRef(variable.type);
-    expect(variable.hasImplicitType, isTrue);
-  }
-
-  test_variable_name() {
-    UnlinkedVariable variable =
-        serializeVariableText('int i;', variableName: 'i');
-    expect(variable.name, 'i');
-  }
-
-  test_variable_no_flags() {
-    UnlinkedVariable variable =
-        serializeVariableText('int i;', variableName: 'i');
-    expect(variable.isStatic, isFalse);
-    expect(variable.isConst, isFalse);
-    expect(variable.isFinal, isFalse);
-  }
-
-  test_variable_non_const() {
-    UnlinkedVariable variable =
-        serializeVariableText('int i = 0;', variableName: 'i');
-    expect(variable.isConst, isFalse);
-  }
-
-  test_variable_non_final() {
-    UnlinkedVariable variable =
-        serializeVariableText('int i;', variableName: 'i');
-    expect(variable.isFinal, isFalse);
-  }
-
-  test_variable_non_static() {
-    UnlinkedVariable variable =
-        serializeClassText('class C { int i; }').fields[0];
-    expect(variable.isStatic, isFalse);
-  }
-
-  test_variable_non_static_top_level() {
-    // Top level variables are considered non-static.
-    UnlinkedVariable variable =
-        serializeVariableText('int i;', variableName: 'i');
-    expect(variable.isStatic, isFalse);
-  }
-
-  test_variable_static() {
-    UnlinkedVariable variable =
-        serializeClassText('class C { static int i; }').fields[0];
-    expect(variable.isStatic, isTrue);
-  }
-
-  test_variable_type() {
-    UnlinkedVariable variable =
-        serializeVariableText('int i;', variableName: 'i');
-    checkTypeRef(variable.type, 'dart:core', 'dart:core', 'int');
-  }
-
-  test_varible_private() {
-    serializeVariableText('int _i;', variableName: '_i');
-    expect(unlinkedUnits[0].publicNamespace.names, isEmpty);
-  }
-}
diff --git a/pkg/analyzer/test/src/summary/test_all.dart b/pkg/analyzer/test/src/summary/test_all.dart
index 252c95f..fe80a5a 100644
--- a/pkg/analyzer/test/src/summary/test_all.dart
+++ b/pkg/analyzer/test/src/summary/test_all.dart
@@ -8,19 +8,27 @@
 
 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;
 import 'resynthesize_test.dart' as resynthesize_test;
-import 'summary_sdk_test.dart' as summary_sdk_test;
-import 'summary_test.dart' as summary_test;
+import 'summarize_ast_test.dart' as summarize_ast_test;
+import 'summarize_elements_strong_test.dart' as summarize_elements_strong_test;
+import 'summarize_elements_test.dart' as summarize_elements_test;
 
 /// Utility for manually running all tests.
 main() {
   initializeTestEnvironment();
   group('summary tests', () {
     flat_buffers_test.main();
+    index_unit_test.main();
     name_filter_test.main();
+    prelinker_test.main();
+    resynthesize_strong_test.main();
     resynthesize_test.main();
-    summary_sdk_test.main();
-    summary_test.main();
+    summarize_ast_test.main();
+    summarize_elements_strong_test.main();
+    summarize_elements_test.main();
   });
 }
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 23930d8..9bf0050 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -4,17 +4,18 @@
 
 library analyzer.test.src.task.dart_test;
 
+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/dart/element/type.dart';
 import 'package:analyzer/src/context/cache.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart'
-    show AnalysisOptionsImpl, CacheState;
+    show AnalysisOptions, AnalysisOptionsImpl, CacheState;
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/services/lint.dart';
@@ -31,6 +32,7 @@
 import '../../reflective_tests.dart';
 import '../../utils.dart';
 import '../context/abstract_context.dart';
+import '../context/mock_sdk.dart';
 
 main() {
   initializeTestEnvironment();
@@ -42,6 +44,7 @@
   runReflectiveTests(BuildPublicNamespaceTaskTest);
   runReflectiveTests(BuildSourceExportClosureTaskTest);
   runReflectiveTests(BuildTypeProviderTaskTest);
+  runReflectiveTests(BuildTypeProviderTaskTest_noAsync);
   runReflectiveTests(ComputeConstantDependenciesTaskTest);
   runReflectiveTests(ComputeConstantValueTaskTest);
   runReflectiveTests(ComputeInferableStaticVariableDependenciesTaskTest);
@@ -182,8 +185,7 @@
       unitElement.types[0].fields[0],
       unitElement.functions[0].localVariables[0],
       unitElement.types[0].constructors[0],
-      new ConstantEvaluationTarget_Annotation(
-          context, source, source, annotation),
+      annotation.elementAnnotation,
       unitElement.types[0].constructors[0].parameters[0]
     ];
     expect(
@@ -239,6 +241,22 @@
 
 @reflectiveTest
 class BuildDirectiveElementsTaskTest extends _AbstractDartTaskTest {
+  /**
+   * Verify that the given [element] has exactly one annotation, and that its
+   * [ElementAnnotationImpl] is unresolved and points back to [element].
+   *
+   * The compilation unit stored in the [ElementAnnotationImpl] should be
+   * [compilationUnit].
+   */
+  void checkMetadata(Element element, CompilationUnitElement compilationUnit) {
+    expect(element.metadata, hasLength(1));
+    expect(element.metadata[0], new isInstanceOf<ElementAnnotationImpl>());
+    ElementAnnotationImpl elementAnnotation = element.metadata[0];
+    expect(elementAnnotation.element, isNull); // Not yet resolved
+    expect(elementAnnotation.compilationUnit, isNotNull);
+    expect(elementAnnotation.compilationUnit, compilationUnit);
+  }
+
   test_perform() {
     List<Source> sources = newSources({
       '/libA.dart': '''
@@ -466,6 +484,58 @@
     expect(importElementC.prefix, prefixElement);
   }
 
+  test_perform_metadata() {
+    List<Source> sources = newSources({
+      '/libA.dart': '''
+@a library libA;
+@b import 'libB.dart';
+@c export 'libC.dart';
+@d part 'part.dart';''',
+      '/libB.dart': 'library libB;',
+      '/libC.dart': 'library libC;',
+      '/part.dart': 'part of libA;'
+    });
+    Source sourceA = sources[0];
+    // perform task
+    computeResult(sourceA, LIBRARY_ELEMENT2,
+        matcher: isBuildDirectiveElementsTask);
+    // Get outputs
+    LibraryElement libraryA =
+        context.getCacheEntry(sourceA).getValue(LIBRARY_ELEMENT2);
+    // Validate metadata
+    checkMetadata(libraryA, libraryA.definingCompilationUnit);
+    checkMetadata(libraryA.imports[0], libraryA.definingCompilationUnit);
+    checkMetadata(libraryA.exports[0], libraryA.definingCompilationUnit);
+    checkMetadata(libraryA.parts[0], libraryA.definingCompilationUnit);
+  }
+
+  test_perform_metadata_partOf() {
+    // We don't record annotations on `part of` directives because the element
+    // associated with a `part of` directive is the library, and the convention
+    // is to annotate the library at the site of the `library` declaration.
+    List<Source> sources = newSources({
+      '/libA.dart': '''
+library libA;
+part 'part.dart';''',
+      '/part.dart': '@a part of libA;'
+    });
+    Source sourceA = sources[0];
+    Source sourcePart = sources[1];
+    // perform task
+    computeResult(sourceA, LIBRARY_ELEMENT2,
+        matcher: isBuildDirectiveElementsTask);
+    // Get outputs
+    LibraryElement libraryA =
+        context.getCacheEntry(sourceA).getValue(LIBRARY_ELEMENT2);
+    CompilationUnit part = context
+        .getCacheEntry(new LibrarySpecificUnit(sourceA, sourcePart))
+        .getValue(RESOLVED_UNIT1);
+    // Validate metadata
+    expect(part.directives[0], new isInstanceOf<PartOfDirective>());
+    expect(part.directives[0].element, same(libraryA));
+    expect(part.directives[0].element.metadata, isEmpty);
+  }
+
   void _assertErrorsWithCodes(List<ErrorCode> expectedErrorCodes) {
     _fillErrorListener(BUILD_DIRECTIVES_ERRORS);
     errorListener.assertErrorsWithCodes(expectedErrorCodes);
@@ -1005,6 +1075,32 @@
 }
 
 @reflectiveTest
+class BuildTypeProviderTaskTest_noAsync extends _AbstractDartTaskTest {
+  void prepareAnalysisContext([AnalysisOptions options]) {
+    AnalysisOptionsImpl newOptions = new AnalysisOptionsImpl();
+    newOptions.enableAsync = false;
+    super.prepareAnalysisContext(newOptions);
+  }
+
+  void setUp() {
+    sdk = new MockSdk(dartAsync: false);
+    super.setUp();
+  }
+
+  test_perform_noAsync() {
+    expect(context, isNotNull);
+    computeResult(AnalysisContextTarget.request, TYPE_PROVIDER,
+        matcher: isBuildTypeProviderTask);
+    // validate
+    TypeProvider typeProvider = outputs[TYPE_PROVIDER];
+    expect(typeProvider, isNotNull);
+    expect(typeProvider.boolType, isNotNull);
+    expect(typeProvider.intType, isNotNull);
+    expect(typeProvider.futureType, isNotNull);
+  }
+}
+
+@reflectiveTest
 class ComputeConstantDependenciesTaskTest extends _AbstractDartTaskTest {
   Annotation findClassAnnotation(CompilationUnit unit, String className) {
     for (CompilationUnitMember member in unit.declarations) {
@@ -1043,15 +1139,39 @@
     // Now compute the dependencies for the annotation, and check that it is
     // the set [x, constructorForD].
     // TODO(paulberry): test librarySource != source
-    computeResult(
-        new ConstantEvaluationTarget_Annotation(
-            context, source, source, annotation),
-        CONSTANT_DEPENDENCIES,
+    computeResult(annotation.elementAnnotation, CONSTANT_DEPENDENCIES,
         matcher: isComputeConstantDependenciesTask);
     expect(
         outputs[CONSTANT_DEPENDENCIES].toSet(), [x, constructorForD].toSet());
   }
 
+  test_annotation_with_nonConstArg() {
+    Source source = newSource(
+        '/test.dart',
+        '''
+class A {
+  const A(x);
+}
+class C {
+  @A(const [(_) => null])
+  String s;
+}
+''');
+    // First compute the resolved unit for the source.
+    LibrarySpecificUnit librarySpecificUnit =
+        new LibrarySpecificUnit(source, source);
+    computeResult(librarySpecificUnit, RESOLVED_UNIT1);
+    CompilationUnit unit = outputs[RESOLVED_UNIT1];
+    // Find the annotation on the field.
+    ClassDeclaration classC = unit.declarations[1];
+    Annotation annotation = classC.members[0].metadata[0];
+    // Now compute the dependencies for the annotation, and check that it is
+    // the right size.
+    computeResult(annotation.elementAnnotation, CONSTANT_DEPENDENCIES,
+        matcher: isComputeConstantDependenciesTask);
+    expect(outputs[CONSTANT_DEPENDENCIES], hasLength(1));
+  }
+
   test_annotation_without_args() {
     Source source = newSource(
         '/test.dart',
@@ -1073,10 +1193,7 @@
     Annotation annotation = findClassAnnotation(unit, 'C');
     // Now compute the dependencies for the annotation, and check that it is
     // the list [x].
-    computeResult(
-        new ConstantEvaluationTarget_Annotation(
-            context, source, source, annotation),
-        CONSTANT_DEPENDENCIES,
+    computeResult(annotation.elementAnnotation, CONSTANT_DEPENDENCIES,
         matcher: isComputeConstantDependenciesTask);
     expect(outputs[CONSTANT_DEPENDENCIES], [x]);
   }
@@ -1140,9 +1257,7 @@
       if (member is ClassDeclaration && member.name.name == className) {
         expect(member.metadata, hasLength(1));
         Annotation annotation = member.metadata[0];
-        ConstantEvaluationTarget_Annotation target =
-            new ConstantEvaluationTarget_Annotation(
-                context, source, source, annotation);
+        ElementAnnotationImpl target = annotation.elementAnnotation;
         computeResult(target, CONSTANT_VALUE,
             matcher: isComputeConstantValueTask);
         expect(outputs[CONSTANT_VALUE], same(target));
@@ -2993,6 +3108,40 @@
     expect(outputs[UNITS], hasLength(1));
   }
 
+  test_perform_computeSourceKind_noDirectives_hasContainingLibrary() {
+    // Parse "lib.dart" to let the context know that "test.dart" is included.
+    computeResult(
+        newSource(
+            '/lib.dart',
+            r'''
+library lib;
+part 'test.dart';
+'''),
+        PARSED_UNIT);
+    // If there are no the "part of" directive, then it is not a part.
+    _performParseTask('');
+    expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
+  }
+
+  test_perform_computeSourceKind_noDirectives_noContainingLibrary() {
+    _performParseTask('');
+    expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
+  }
+
+  test_perform_doesNotExist() {
+    _performParseTask(null);
+    expect(outputs, hasLength(9));
+    expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
+    expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
+    _assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
+    expect(outputs[INCLUDED_PARTS], hasLength(0));
+    expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
+    expect(outputs[PARSE_ERRORS], hasLength(0));
+    expect(outputs[PARSED_UNIT], isNotNull);
+    expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
+    expect(outputs[UNITS], hasLength(1));
+  }
+
   test_perform_enableAsync_false() {
     AnalysisOptionsImpl options = new AnalysisOptionsImpl();
     options.enableAsync = false;
@@ -3028,40 +3177,6 @@
     expect(outputs[UNITS], hasLength(1));
   }
 
-  test_perform_computeSourceKind_noDirectives_hasContainingLibrary() {
-    // Parse "lib.dart" to let the context know that "test.dart" is included.
-    computeResult(
-        newSource(
-            '/lib.dart',
-            r'''
-library lib;
-part 'test.dart';
-'''),
-        PARSED_UNIT);
-    // If there are no the "part of" directive, then it is not a part.
-    _performParseTask('');
-    expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
-  }
-
-  test_perform_computeSourceKind_noDirectives_noContainingLibrary() {
-    _performParseTask('');
-    expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
-  }
-
-  test_perform_doesNotExist() {
-    _performParseTask(null);
-    expect(outputs, hasLength(9));
-    expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
-    expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
-    _assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
-    expect(outputs[INCLUDED_PARTS], hasLength(0));
-    expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
-    expect(outputs[PARSE_ERRORS], hasLength(0));
-    expect(outputs[PARSED_UNIT], isNotNull);
-    expect(outputs[SOURCE_KIND], SourceKind.UNKNOWN);
-    expect(outputs[UNITS], hasLength(1));
-  }
-
   test_perform_flushTokenStream() {
     _performParseTask(r'''
 class Test {}
@@ -3133,7 +3248,11 @@
   }
 
   void _performParseTask(String content) {
-    source = newSource('/test.dart', content);
+    if (content == null) {
+      source = resourceProvider.getFile('/test.dart').createSource();
+    } else {
+      source = newSource('/test.dart', content);
+    }
     computeResult(source, PARSED_UNIT, matcher: isParseDartTask);
   }
 
@@ -3956,10 +4075,10 @@
    * Verify that the mutated states of the given [variable] correspond to the
    * [mutatedInClosure] and [mutatedInScope] matchers.
    */
-  void expectMutated(VariableElement variable, Matcher mutatedInClosure,
-      Matcher mutatedInScope) {
-    expect(variable.isPotentiallyMutatedInClosure, mutatedInClosure);
-    expect(variable.isPotentiallyMutatedInScope, mutatedInScope);
+  void expectMutated(FunctionBody body, VariableElement variable,
+      bool mutatedInClosure, bool mutatedInScope) {
+    expect(body.isPotentiallyMutatedInClosure(variable), mutatedInClosure);
+    expect(body.isPotentiallyMutatedInScope(variable), mutatedInScope);
   }
 
   test_created_resolved_unit() {
@@ -4009,11 +4128,13 @@
         matcher: isResolveVariableReferencesTask);
     // validate
     CompilationUnit unit = outputs[RESOLVED_UNIT4];
-    FunctionElement main = unit.element.functions[0];
-    expectMutated(main.localVariables[0], isFalse, isFalse);
-    expectMutated(main.localVariables[1], isFalse, isTrue);
-    expectMutated(main.localVariables[2], isTrue, isTrue);
-    expectMutated(main.localVariables[3], isTrue, isTrue);
+    FunctionDeclaration mainDeclaration = unit.declarations[0];
+    FunctionBody body = mainDeclaration.functionExpression.body;
+    FunctionElement main = mainDeclaration.element;
+    expectMutated(body, main.localVariables[0], false, false);
+    expectMutated(body, main.localVariables[1], false, true);
+    expectMutated(body, main.localVariables[2], true, true);
+    expectMutated(body, main.localVariables[3], true, true);
   }
 
   test_perform_parameter() {
@@ -4034,11 +4155,13 @@
         matcher: isResolveVariableReferencesTask);
     // validate
     CompilationUnit unit = outputs[RESOLVED_UNIT4];
-    FunctionElement main = unit.element.functions[0];
-    expectMutated(main.parameters[0], isFalse, isFalse);
-    expectMutated(main.parameters[1], isFalse, isTrue);
-    expectMutated(main.parameters[2], isTrue, isTrue);
-    expectMutated(main.parameters[3], isTrue, isTrue);
+    FunctionDeclaration mainDeclaration = unit.declarations[0];
+    FunctionBody body = mainDeclaration.functionExpression.body;
+    FunctionElement main = mainDeclaration.element;
+    expectMutated(body, main.parameters[0], false, false);
+    expectMutated(body, main.parameters[1], false, true);
+    expectMutated(body, main.parameters[2], true, true);
+    expectMutated(body, main.parameters[3], true, true);
   }
 }
 
diff --git a/pkg/analyzer/test/src/task/dart_work_manager_test.dart b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
index 7938cc9..c6d3f1d 100644
--- a/pkg/analyzer/test/src/task/dart_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
@@ -4,8 +4,9 @@
 
 library analyzer.test.src.task.dart_work_manager_test;
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/src/context/cache.dart';
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart' show ScannerErrorCode;
 import 'package:analyzer/src/generated/engine.dart'
     show
         AnalysisErrorInfo,
@@ -15,7 +16,6 @@
         InternalAnalysisContext;
 import 'package:analyzer/src/generated/error.dart' show AnalysisError;
 import 'package:analyzer/src/generated/java_engine.dart' show CaughtException;
-import 'package:analyzer/src/generated/scanner.dart' show ScannerErrorCode;
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/testing/ast_factory.dart';
diff --git a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
index 114a452..8ef225a 100644
--- a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
+++ b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
@@ -4,8 +4,8 @@
 
 library analyzer.test.src.task.incremental_element_builder_test;
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/task/incremental_element_builder.dart';
 import 'package:unittest/unittest.dart';
diff --git a/pkg/analyzer/test/src/task/model_test.dart b/pkg/analyzer/test/src/task/model_test.dart
index 4db1ee2..a798472 100644
--- a/pkg/analyzer/test/src/task/model_test.dart
+++ b/pkg/analyzer/test/src/task/model_test.dart
@@ -103,7 +103,7 @@
 
 @reflectiveTest
 class TaskDescriptorImplTest extends EngineTestCase {
-  test_create() {
+  test_create_noOptionalArgs() {
     String name = 'name';
     BuildTask buildTask = (context, target) {};
     CreateTaskInputs createTaskInputs = (target) {};
@@ -114,12 +114,30 @@
     expect(descriptor.name, name);
     expect(descriptor.buildTask, equals(buildTask));
     expect(descriptor.createTaskInputs, equals(createTaskInputs));
+    expect(descriptor.suitabilityFor(null), TaskSuitability.LOWEST);
+    expect(descriptor.results, results);
+  }
+
+  test_create_withIsAppropriateFor() {
+    String name = 'name';
+    BuildTask buildTask = (context, target) {};
+    CreateTaskInputs createTaskInputs = (target) {};
+    List<ResultDescriptor> results = <ResultDescriptor>[];
+    SuitabilityFor suitabilityFor = (target) => TaskSuitability.NONE;
+    TaskDescriptorImpl descriptor = new TaskDescriptorImpl(
+        name, buildTask, createTaskInputs, results,
+        suitabilityFor: suitabilityFor);
+    expect(descriptor, isNotNull);
+    expect(descriptor.name, name);
+    expect(descriptor.buildTask, equals(buildTask));
+    expect(descriptor.createTaskInputs, equals(createTaskInputs));
+    expect(descriptor.suitabilityFor(null), TaskSuitability.NONE);
     expect(descriptor.results, results);
   }
 
   test_createTask() {
-    BuildTask buildTask = (context, target) =>
-        new TestAnalysisTask(context, target);
+    BuildTask buildTask =
+        (context, target) => new TestAnalysisTask(context, target);
     CreateTaskInputs createTaskInputs = (target) {};
     List<ResultDescriptor> results = <ResultDescriptor>[];
     TaskDescriptorImpl descriptor =
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/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 55b73a8..a87577c 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -12,8 +12,10 @@
 import 'strong_test_helper.dart';
 
 void main() {
-  testChecker('ternary operator', {
-    '/main.dart': '''
+  initStrongModeTests();
+
+  test('ternary operator', () {
+    checkFile('''
         abstract class Comparable<T> {
           int compareTo(T other);
           static int compare(Comparable a, Comparable b) => a.compareTo(b);
@@ -26,21 +28,19 @@
           Comparator<K> _comparator;
           _Predicate _validKey;
 
-          // Initializing _comparator needs a cast, since K may not always be
-          // Comparable.
-          // Initializing _validKey shouldn't need a cast.  Currently
-          // it requires inference to work because of dartbug.com/23381
+          // TODO(rnystrom): Initializing _comparator should have a cast, since
+          // K may not always be Comparable. It doesn't currently get one
+          // because we're using the spec's LUB on function types, which isn't
+          // sound.
           SplayTreeMap([int compare(K key1, K key2),
-                        bool isValidKey(potentialKey)]) {
-            : _comparator = /*warning:DOWN_CAST_COMPOSITE*/(compare == null)
-                           ? Comparable.compare : compare,
-              _validKey = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
-                         ? isValidKey : ((v) => true);
-             _Predicate<Object> _v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
-                                    ? isValidKey : (/*info:INFERRED_TYPE_CLOSURE*/(v) => true);
-        // TODO(leafp): Fix unimplemented LUB in analyzer
-        _v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
-             ? _v : (/*info:INFERRED_TYPE_CLOSURE*/(v) => true);
+                        bool isValidKey(potentialKey)])
+            : _comparator = (compare == null) ? Comparable.compare : compare,
+              _validKey = (isValidKey != null) ? isValidKey : ((v) => true) {
+            _Predicate<Object> v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
+                                    ? isValidKey : (/*info:INFERRED_TYPE_CLOSURE*/(_) => true);
+
+            v = (isValidKey != null)
+                 ? v : (/*info:INFERRED_TYPE_CLOSURE*/(_) => true);
           }
         }
         void main() {
@@ -53,13 +53,13 @@
           print((/*info:DOWN_CAST_IMPLICIT*/obj) ? false : true);
           print((/*info:DYNAMIC_CAST*/dyn) ? false : true);
         }
-      '''
+      ''');
   });
 
-  testChecker('if/for/do/while statements use boolean conversion', {
-    '/main.dart': '''
+  test('if/for/do/while statements use boolean conversion', () {
+    checkFile('''
       main() {
-        dynamic d = 42;
+        dynamic dyn = 42;
         Object obj = 42;
         int i = 42;
         bool b = false;
@@ -84,11 +84,11 @@
         for (;/*info:DOWN_CAST_IMPLICIT*/obj;) {}
         for (;/*severe:STATIC_TYPE_ERROR*/i;) {}
       }
-    '''
+    ''');
   });
 
-  testChecker('dynamic invocation', {
-    '/main.dart': '''
+  test('dynamic invocation', () {
+    checkFile('''
 
       class A {
         dynamic call(dynamic x) => x;
@@ -133,23 +133,25 @@
           (/*info:DYNAMIC_INVOKE*/g.call(32.0));
           (/*info:DYNAMIC_INVOKE*/g.col(42.0));
           (/*info:DYNAMIC_INVOKE*/g.foo(42.0));
-          (/*info:DYNAMIC_INVOKE*/g.x);
+          (/*info:DYNAMIC_INVOKE*/g./*info:UNDEFINED_GETTER*/x);
           A f = new B();
           f.call(32.0);
           (/*info:DYNAMIC_INVOKE*/f.col(42.0));
           (/*info:DYNAMIC_INVOKE*/f.foo(42.0));
-          (/*info:DYNAMIC_INVOKE*/f.x);
+          (/*info:DYNAMIC_INVOKE*/f./*warning:UNDEFINED_GETTER*/x);
         }
       }
-    '''
+    ''');
   });
 
-  testChecker('conversion and dynamic invoke', {
-    '/helper.dart': '''
+  test('conversion and dynamic invoke', () {
+    addFile(
+        '''
       dynamic toString = (int x) => x + 42;
       dynamic hashCode = "hello";
       ''',
-    '/main.dart': '''
+        name: '/helper.dart');
+    checkFile('''
       import 'helper.dart' as helper;
 
       class A {
@@ -201,7 +203,7 @@
         (/*info:DYNAMIC_INVOKE*/b2("hello"));
 
         dynamic a1 = new B();
-        (/*info:DYNAMIC_INVOKE*/a1.x);
+        (/*info:DYNAMIC_INVOKE*/a1./*info:UNDEFINED_GETTER*/x);
         a1.toString();
         (/*info:DYNAMIC_INVOKE*/a1.toString(42));
         var toStringClosure = a1.toString;
@@ -221,11 +223,11 @@
         baz().toString();
         baz().hashCode;
       }
-    '''
+    ''');
   });
 
-  testChecker('Constructors', {
-    '/main.dart': '''
+  test('Constructors', () {
+    checkFile('''
       const num z = 25;
       Object obj = "world";
 
@@ -255,38 +257,39 @@
          A a = new A.c2(/*info:DOWN_CAST_IMPLICIT*/z, /*severe:STATIC_TYPE_ERROR*/z);
          var b = new B.c2(/*severe:STATIC_TYPE_ERROR*/"hello", /*info:DOWN_CAST_IMPLICIT*/obj);
       }
-   '''
+   ''');
   });
 
-  testChecker('Unbound variable', {
-    '/main.dart': '''
+  test('Unbound variable', () {
+    checkFile('''
       void main() {
-         dynamic y = /*pass should be severe:STATIC_TYPE_ERROR*/unboundVariable;
+         dynamic y = /*warning:UNDEFINED_IDENTIFIER should be error*/unboundVariable;
       }
-   '''
+   ''');
   });
 
-  testChecker('Unbound type name', {
-    '/main.dart': '''
+  test('Unbound type name', () {
+    checkFile('''
       void main() {
-         /*pass should be severe:STATIC_TYPE_ERROR*/AToB y;
+         /*warning:UNDEFINED_CLASS should be error*/AToB y;
       }
-   '''
+   ''');
   });
 
   // Regression test for https://github.com/dart-lang/sdk/issues/25069
-  testChecker('Void subtyping', {
-    '/main.dart': '''
+  test('Void subtyping', () {
+    checkFile('''
       typedef int Foo();
       void foo() {}
       void main () {
         Foo x = /*severe:STATIC_TYPE_ERROR*/foo();
       }
-   '''
+   ''');
   });
 
-  testChecker('Ground type subtyping: dynamic is top', {
-    '/main.dart': '''
+  group('Ground type subtyping:', () {
+    test('dynamic is top', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -306,11 +309,11 @@
          y = a;
          y = b;
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Ground type subtyping: dynamic downcasts', {
-    '/main.dart': '''
+    test('dynamic downcasts', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -330,11 +333,11 @@
          a = /*info:DYNAMIC_CAST*/y;
          b = /*info:DYNAMIC_CAST*/y;
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Ground type subtyping: assigning a class', {
-    '/main.dart': '''
+    test('assigning a class', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -355,11 +358,11 @@
          a = a;
          b = /*info:DOWN_CAST_IMPLICIT*/a;
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Ground type subtyping: assigning a subclass', {
-    '/main.dart': '''
+    test('assigning a subclass', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -383,11 +386,11 @@
          b = b;
          c = /*severe:STATIC_TYPE_ERROR*/b;
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Ground type subtyping: interfaces', {
-    '/main.dart': '''
+    test('interfaces', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -424,11 +427,13 @@
            bot = bot;
          }
       }
-   '''
+   ''');
+    });
   });
 
-  testChecker('Function typing and subtyping: int and object', {
-    '/main.dart': '''
+  group('Function typing and subtyping:', () {
+    test('int and object', () {
+      checkFile('''
 
       typedef Object Top(int x);      // Top of the lattice
       typedef int Left(int x);        // Left branch
@@ -436,13 +441,20 @@
       typedef Object Right(Object x); // Right branch
       typedef int Bot(Object x);      // Bottom of the lattice
 
-      Object top(int x) => x;
-      int left(int x) => x;
-      Object right(Object x) => x;
+      Object globalTop(int x) => x;
+      int globalLeft(int x) => x;
+      Object globalRight(Object x) => x;
       int _bot(Object x) => /*info:DOWN_CAST_IMPLICIT*/x;
-      int bot(Object x) => x as int;
+      int globalBot(Object x) => x as int;
 
       void main() {
+        // Note: use locals so we only know the type, not that it's a specific
+        // function declaration. (we can issue better errors in that case.)
+        var top = globalTop;
+        var left = globalLeft;
+        var right = globalRight;
+        var bot = globalBot;
+
         { // Check typedef equality
           Left f = left;
           Left2 g = f;
@@ -476,11 +488,11 @@
           f = bot;
         }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: classes', {
-    '/main.dart': '''
+    test('classes', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -511,31 +523,31 @@
         }
         {
           Left f;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
           f = left;
-          f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
+          f = /*severe:STATIC_TYPE_ERROR*/right;
           f = bot;
         }
         {
           Right f;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
-          f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
           f = right;
           f = bot;
         }
         {
           Bot f;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
-          f = /*warning:DOWN_CAST_COMPOSITE*/left;
-          f = /*warning:DOWN_CAST_COMPOSITE*/right;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+          f = /*severe:STATIC_TYPE_ERROR*/right;
           f = bot;
         }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: dynamic', {
-    '/main.dart': '''
+    test('dynamic', () {
+      checkFile('''
 
       class A {}
 
@@ -544,12 +556,11 @@
       typedef A Right(dynamic x);         // Right branch
       typedef A Bottom(A x);              // Bottom of the lattice
 
-      dynamic left(A x) => x;
-      A bot(A x) => x;
-      dynamic top(dynamic x) => x;
-      A right(dynamic x) => /*info:DYNAMIC_CAST*/x;
-
       void main() {
+        Top top;
+        Left left;
+        Right right;
+        Bottom bot;
         {
           Top f;
           f = top;
@@ -579,11 +590,88 @@
           f = bot;
         }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: function literal variance', {
-    '/main.dart': '''
+    test('dynamic - known functions', () {
+
+      // Our lattice should look like this:
+      //
+      //
+      //           Bot -> Top
+      //          /        \
+      //      A -> Top    Bot -> A
+      //       /     \      /
+      // Top -> Top   A -> A
+      //         \      /
+      //         Top -> A
+      //
+      checkFile('''
+        class A {}
+
+        typedef dynamic BotTop(dynamic x);
+        typedef dynamic ATop(A x);
+        typedef A BotA(dynamic x);
+        typedef A AA(A x);
+        typedef A TopA(Object x);
+        typedef dynamic TopTop(Object x);
+
+        dynamic aTop(A x) => x;
+        A aa(A x) => x;
+        dynamic topTop(dynamic x) => x;
+        A topA(dynamic x) => /*info:DYNAMIC_CAST*/x;
+
+        void main() {
+          BotTop botTop;
+          BotA botA;
+          {
+            BotTop f;
+            f = topTop;
+            f = aTop;
+            f = topA;
+            f = aa;
+          }
+          {
+            ATop f;
+            f = topTop;
+            f = aTop;
+            f = topA;
+            f = aa;
+          }
+          {
+            BotA f;
+            f = /*severe:STATIC_TYPE_ERROR*/topTop;
+            f = /*severe:STATIC_TYPE_ERROR*/aTop;
+            f = topA;
+            f = aa;
+          }
+          {
+            AA f;
+            f = /*severe:STATIC_TYPE_ERROR*/topTop;
+            f = /*severe:STATIC_TYPE_ERROR*/aTop;
+            f = topA;
+            f = aa;
+          }
+          {
+            TopTop f;
+            f = topTop;
+            f = /*severe:STATIC_TYPE_ERROR*/aTop;
+            f = topA;
+            f = /*severe:STATIC_TYPE_ERROR*/aa;
+          }
+          {
+            TopA f;
+            f = /*severe:STATIC_TYPE_ERROR*/topTop;
+            f = /*severe:STATIC_TYPE_ERROR*/aTop;
+            f = topA;
+            f = /*severe:STATIC_TYPE_ERROR*/aa;
+          }
+        }
+     ''');
+    });
+
+    test('function literal variance', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -605,31 +693,31 @@
         }
         {
           Function2<B, B> f;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
           f = left;
-          f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
+          f = /*severe:STATIC_TYPE_ERROR*/right;
           f = bot;
         }
         {
           Function2<A, A> f;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
-          f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
           f = right;
           f = bot;
         }
         {
           Function2<A, B> f;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
-          f = /*warning:DOWN_CAST_COMPOSITE*/left;
-          f = /*warning:DOWN_CAST_COMPOSITE*/right;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+          f = /*severe:STATIC_TYPE_ERROR*/right;
           f = bot;
         }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: function variable variance', {
-    '/main.dart': '''
+    test('function variable variance', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -664,11 +752,108 @@
           bot = bot;
         }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: higher order function literals', {
-    '/main.dart': '''
+    test('static method variance', () {
+      checkFile('''
+
+      class A {}
+      class B extends A {}
+
+      class C {
+        static A top(B x) => x;
+        static B left(B x) => x;
+        static A right(A x) => x;
+        static B bot(A x) => x as B;
+      }
+
+      typedef T Function2<S, T>(S z);
+
+      void main() {
+        {
+          Function2<B, A> f;
+          f = C.top;
+          f = C.left;
+          f = C.right;
+          f = C.bot;
+        }
+        {
+          Function2<B, B> f;
+          f = /*severe:STATIC_TYPE_ERROR*/C.top;
+          f = C.left;
+          f = /*severe:STATIC_TYPE_ERROR*/C.right;
+          f = C.bot;
+        }
+        {
+          Function2<A, A> f;
+          f = /*severe:STATIC_TYPE_ERROR*/C.top;
+          f = /*severe:STATIC_TYPE_ERROR*/C.left;
+          f = C.right;
+          f = C.bot;
+        }
+        {
+          Function2<A, B> f;
+          f = /*severe:STATIC_TYPE_ERROR*/C.top;
+          f = /*severe:STATIC_TYPE_ERROR*/C.left;
+          f = /*severe:STATIC_TYPE_ERROR*/C.right;
+          f = C.bot;
+        }
+      }
+   ''');
+    });
+
+    test('instance method variance', () {
+      checkFile('''
+
+      class A {}
+      class B extends A {}
+
+      class C {
+        A top(B x) => x;
+        B left(B x) => x;
+        A right(A x) => x;
+        B bot(A x) => x as B;
+      }
+
+      typedef T Function2<S, T>(S z);
+
+      void main() {
+        C c = new C();
+        {
+          Function2<B, A> f;
+          f = c.top;
+          f = c.left;
+          f = c.right;
+          f = c.bot;
+        }
+        {
+          Function2<B, B> f;
+          f = /*warning:DOWN_CAST_COMPOSITE*/c.top;
+          f = c.left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/c.right;
+          f = c.bot;
+        }
+        {
+          Function2<A, A> f;
+          f = /*warning:DOWN_CAST_COMPOSITE*/c.top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/c.left;
+          f = c.right;
+          f = c.bot;
+        }
+        {
+          Function2<A, B> f;
+          f = /*warning:DOWN_CAST_COMPOSITE*/c.top;
+          f = /*warning:DOWN_CAST_COMPOSITE*/c.left;
+          f = /*warning:DOWN_CAST_COMPOSITE*/c.right;
+          f = c.bot;
+        }
+      }
+   ''');
+    });
+
+    test('higher order function literals 1', () {
+      checkFile('''
 
       class A {}
       class B extends A {}
@@ -684,12 +869,99 @@
       AToB _bot(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f;
       AToB bot(BToA f) => f as AToB;
 
+      void main() {
+        {
+          Function2<AToB, BToA> f; // Top
+          f = top;
+          f = left;
+          f = right;
+          f = bot;
+        }
+        {
+          Function2<AToB, AToB> f; // Left
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = left;
+          f = /*severe:STATIC_TYPE_ERROR*/right;
+          f = bot;
+        }
+        {
+          Function2<BToA, BToA> f; // Right
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+          f = right;
+          f = bot;
+        }
+        {
+          Function2<BToA, AToB> f; // Bot
+          f = bot;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+        }
+      }
+   ''');
+    });
+
+    test('higher order function literals 2', () {
+      checkFile('''
+
+      class A {}
+      class B extends A {}
+
+      typedef T Function2<S, T>(S z);
+
+      typedef A BToA(B x);  // Top of the base lattice
+      typedef B AToB(A x);  // Bot of the base lattice
+
       Function2<B, A> top(AToB f) => f;
       Function2<A, B> left(AToB f) => f;
       Function2<B, A> right(BToA f) => f;
       Function2<A, B> _bot(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f;
       Function2<A, B> bot(BToA f) => f as Function2<A, B>;
 
+      void main() {
+        {
+          Function2<AToB, BToA> f; // Top
+          f = top;
+          f = left;
+          f = right;
+          f = bot;
+        }
+        {
+          Function2<AToB, AToB> f; // Left
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = left;
+          f = /*severe:STATIC_TYPE_ERROR*/right;
+          f = bot;
+        }
+        {
+          Function2<BToA, BToA> f; // Right
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+          f = right;
+          f = bot;
+        }
+        {
+          Function2<BToA, AToB> f; // Bot
+          f = bot;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+        }
+      }
+   ''');
+    });
+
+    test('higher order function literals 3', () {
+      checkFile('''
+
+      class A {}
+      class B extends A {}
+
+      typedef T Function2<S, T>(S z);
+
+      typedef A BToA(B x);  // Top of the base lattice
+      typedef B AToB(A x);  // Bot of the base lattice
 
       BToA top(Function2<A, B> f) => f;
       AToB left(Function2<A, B> f) => f;
@@ -707,32 +979,31 @@
         }
         {
           Function2<AToB, AToB> f; // Left
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
           f = left;
-          f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
+          f = /*severe:STATIC_TYPE_ERROR*/right;
           f = bot;
         }
         {
           Function2<BToA, BToA> f; // Right
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
-          f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
           f = right;
           f = bot;
         }
         {
           Function2<BToA, AToB> f; // Bot
           f = bot;
-          f = /*warning:DOWN_CAST_COMPOSITE*/left;
-          f = /*warning:DOWN_CAST_COMPOSITE*/top;
-          f = /*warning:DOWN_CAST_COMPOSITE*/left;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
+          f = /*severe:STATIC_TYPE_ERROR*/top;
+          f = /*severe:STATIC_TYPE_ERROR*/left;
         }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker(
-      'Function typing and subtyping: higher order function variables', {
-    '/main.dart': '''
+    test('higher order function variables', () {
+      checkFile('''
 
     class A {}
     class B extends A {}
@@ -769,11 +1040,11 @@
         bot = bot;
       }
     }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: named and optional parameters', {
-    '/main.dart': '''
+    test('named and optional parameters', () {
+      checkFile('''
 
       class A {}
 
@@ -815,7 +1086,7 @@
          o = /*severe:STATIC_TYPE_ERROR*/ro;
          o = /*severe:STATIC_TYPE_ERROR*/rn;
          o = oo;
-         o = /*severe:STATIC_TYPE_ERROR*/nn
+         o = /*severe:STATIC_TYPE_ERROR*/nn;
          o = /*severe:STATIC_TYPE_ERROR*/nnn;
 
          n = /*severe:STATIC_TYPE_ERROR*/r;
@@ -888,11 +1159,11 @@
          nnn = /*warning:DOWN_CAST_COMPOSITE*/nn;
          nnn = nnn;
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function subtyping: objects with call methods', {
-    '/main.dart': '''
+    test('Function subtyping: objects with call methods', () {
+      checkFile('''
 
       typedef int I2I(int x);
       typedef num N2N(num x);
@@ -910,7 +1181,7 @@
            f = new A();
            f = /*severe:STATIC_TYPE_ERROR*/new B();
            f = i2i;
-           f = /*warning:DOWN_CAST_COMPOSITE*/n2n;
+           f = /*severe:STATIC_TYPE_ERROR*/n2n;
            f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
            f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
          }
@@ -918,7 +1189,7 @@
            N2N f;
            f = /*severe:STATIC_TYPE_ERROR*/new A();
            f = new B();
-           f = /*warning:DOWN_CAST_COMPOSITE*/i2i;
+           f = /*severe:STATIC_TYPE_ERROR*/i2i;
            f = n2n;
            f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
            f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
@@ -951,21 +1222,67 @@
            f = (n2n as Function);
          }
       }
-   '''
-  });
+   ''');
+    });
 
-  testChecker('Function typing and subtyping: void', {
-    '/main.dart': '''
+    test('void', () {
+      checkFile('''
 
       class A {
         void bar() => null;
         void foo() => bar; // allowed
       }
-   '''
+   ''');
+    });
+
+    test('uninferred closure', () {
+      checkFile('''
+        typedef num Num2Num(num x);
+        void main() {
+          Num2Num g = /*info:INFERRED_TYPE_CLOSURE,severe:STATIC_TYPE_ERROR*/(int x) { return x; };
+          print(g(42));
+        }
+      ''');
+    });
+
+    test('subtype of universal type', () {
+      checkFile('''
+        void main() {
+          nonGenericFn(x) => null;
+          {
+            /*=R*/ f/*<P, R>*/(/*=P*/ p) => null;
+            /*=T*/ g/*<S, T>*/(/*=S*/ s) => null;
+
+            var local = f;
+            local = g; // valid
+
+            // Non-generic function cannot subtype a generic one.
+            local = /*severe:STATIC_TYPE_ERROR*/(x) => null;
+            local = /*severe:STATIC_TYPE_ERROR*/nonGenericFn;
+          }
+          {
+            Iterable/*<R>*/ f/*<P, R>*/(List/*<P>*/ p) => null;
+            List/*<T>*/ g/*<S, T>*/(Iterable/*<S>*/ s) => null;
+
+            var local = f;
+            local = g; // valid
+
+            var local2 = g;
+            local = local2;
+            local2 = /*severe:STATIC_TYPE_ERROR*/f;
+            local2 = /*warning:DOWN_CAST_COMPOSITE*/local;
+
+            // Non-generic function cannot subtype a generic one.
+            local = /*severe:STATIC_TYPE_ERROR*/(x) => null;
+            local = /*severe:STATIC_TYPE_ERROR*/nonGenericFn;
+          }
+        }
+      ''');
+    });
   });
 
-  testChecker('Relaxed casts', {
-    '/main.dart': '''
+  test('Relaxed casts', () {
+    checkFile('''
 
       class A {}
 
@@ -1039,11 +1356,11 @@
         }
 
       }
-   '''
+   ''');
   });
 
-  testChecker('Type checking literals', {
-    '/main.dart': '''
+  test('Type checking literals', () {
+    checkFile('''
           test() {
             num n = 3;
             int i = 3;
@@ -1082,11 +1399,11 @@
                     s: s};
             }
           }
-   '''
+   ''');
   });
 
-  testChecker('casts in constant contexts', {
-    '/main.dart': '''
+  test('casts in constant contexts', () {
+    checkFile('''
           class A {
             static const num n = 3.0;
             static const int i = /*info:ASSIGNMENT_CAST*/n;
@@ -1099,11 +1416,11 @@
           void foo(Object o) {
             var a = const A(/*info:DOWN_CAST_IMPLICIT*/o);
           }
-     '''
+     ''');
   });
 
-  testChecker('casts in conditionals', {
-    '/main.dart': '''
+  test('casts in conditionals', () {
+    checkFile('''
           main() {
             bool b = true;
             num x = b ? 1 : 2.3;
@@ -1111,38 +1428,53 @@
             String z = !b ? "hello" : null;
             z = b ? null : "hello";
           }
-      '''
+      ''');
   });
 
   // This is a regression test for https://github.com/dart-lang/sdk/issues/25071
-  testChecker('unbound redirecting constructor', {
-    '/main.dart': '''
+  test('unbound redirecting constructor', () {
+    checkFile('''
       class Foo {
         Foo() : this.init();
       }
-       '''
+       ''');
   });
 
-  testChecker('redirecting constructor', {
-    '/main.dart': '''
+  test('redirecting constructor', () {
+    checkFile('''
           class A {
             A(A x) {}
             A.two() : this(/*severe:STATIC_TYPE_ERROR*/3);
           }
-       '''
+       ''');
   });
 
-  testChecker('super constructor', {
-    '/main.dart': '''
+  test('super constructor', () {
+    checkFile('''
           class A { A(A x) {} }
           class B extends A {
             B() : super(/*severe:STATIC_TYPE_ERROR*/3);
           }
-       '''
+       ''');
   });
 
-  testChecker('field/field override', {
-    '/main.dart': '''
+  test('factory constructor downcast', () {
+    checkFile(r'''
+        class Animal {
+          Animal();
+          factory Animal.cat() => new Cat();
+        }
+
+        class Cat extends Animal {}
+
+        void main() {
+          Cat c = /*info:ASSIGNMENT_CAST*/new Animal.cat();
+          c = /*severe:STATIC_TYPE_ERROR*/new Animal();
+        }''');
+  });
+
+  test('field/field override', () {
+    checkFile('''
           class A {}
           class B extends A {}
           class C extends B {}
@@ -1167,11 +1499,12 @@
             var f3;
             /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/dynamic f4;
           }
-       '''
+       ''');
   });
 
-  testChecker('private override', {
-    '/helper.dart': '''
+  test('private override', () {
+    addFile(
+        '''
           import 'main.dart' as main;
 
           class Base {
@@ -1191,7 +1524,8 @@
             /*severe:INVALID_METHOD_OVERRIDE*/String _m1();
           }
     ''',
-    '/main.dart': '''
+        name: '/helper.dart');
+    checkFile('''
           import 'helper.dart' as helper;
 
           class Child extends helper.Base {
@@ -1201,11 +1535,11 @@
 
             String _m1();
           }
-    '''
+    ''');
   });
 
-  testChecker('getter/getter override', {
-    '/main.dart': '''
+  test('getter/getter override', () {
+    checkFile('''
           class A {}
           class B extends A {}
           class C extends B {}
@@ -1223,11 +1557,11 @@
             get f3 => null;
             /*severe:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
           }
-       '''
+       ''');
   });
 
-  testChecker('field/getter override', {
-    '/main.dart': '''
+  test('field/getter override', () {
+    checkFile('''
           class A {}
           class B extends A {}
           class C extends B {}
@@ -1252,11 +1586,11 @@
             get f3 => null;
             /*severe:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
           }
-       '''
+       ''');
   });
 
-  testChecker('setter/setter override', {
-    '/main.dart': '''
+  test('setter/setter override', () {
+    checkFile('''
           class A {}
           class B extends A {}
           class C extends B {}
@@ -1276,11 +1610,11 @@
             /*severe:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
             set f5(B value) {}
           }
-       '''
+       ''');
   });
 
-  testChecker('field/setter override', {
-    '/main.dart': '''
+  test('field/setter override', () {
+    checkFile('''
           class A {}
           class B extends A {}
           class C extends B {}
@@ -1320,11 +1654,11 @@
             /*severe:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
             set f5(B value) {}
           }
-       '''
+       ''');
   });
 
-  testChecker('method override', {
-    '/main.dart': '''
+  test('method override', () {
+    checkFile('''
           class A {}
           class B extends A {}
           class C extends B {}
@@ -1346,11 +1680,11 @@
             m5(value) {}
             /*severe:INVALID_METHOD_OVERRIDE*/dynamic m6(dynamic value) {}
           }
-       '''
+       ''');
   });
 
-  testChecker('generic class method override', {
-    '/main.dart': '''
+  test('generic class method override', () {
+    checkFile('''
           class A {}
           class B extends A {}
 
@@ -1365,11 +1699,11 @@
           class Derived2<S extends B> extends Base<B> {
             S foo() => null;
           }
-       '''
+       ''');
   });
 
-  testChecker('generic method override', {
-    '/main.dart': '''
+  test('generic method override', () {
+    checkFile('''
           class Future<T> {
             /*=S*/ then/*<S>*/(/*=S*/ onValue(T t)) => null;
           }
@@ -1389,11 +1723,56 @@
           class DerivedFuture4<A> extends Future<A> {
             /*=B*/ then/*<B>*/(Object onValue(A a)) => null;
           }
-       '''
+      ''');
   });
 
-  testChecker('unary operators', {
-    '/main.dart': '''
+  test('generic function wrong number of arguments', () {
+    checkFile(r'''
+          /*=T*/ foo/*<T>*/(/*=T*/ x, /*=T*/ y) => x;
+          /*=T*/ bar/*<T>*/({/*=T*/ x, /*=T*/ y}) => x;
+
+          main() {
+            String x;
+            // resolving these shouldn't crash.
+            foo/*warning:EXTRA_POSITIONAL_ARGUMENTS*/(1, 2, 3);
+            x = foo/*warning:EXTRA_POSITIONAL_ARGUMENTS*/('1', '2', '3');
+            foo/*warning:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1);
+            x = foo/*warning:NOT_ENOUGH_REQUIRED_ARGUMENTS*/('1');
+            x = /*info:DYNAMIC_CAST*/foo/*warning:EXTRA_POSITIONAL_ARGUMENTS*/(1, 2, 3);
+            x = /*info:DYNAMIC_CAST*/foo/*warning:NOT_ENOUGH_REQUIRED_ARGUMENTS*/(1);
+
+            // named arguments
+            bar(y: 1, x: 2, /*warning:UNDEFINED_NAMED_PARAMETER*/z: 3);
+            x = bar(/*warning:UNDEFINED_NAMED_PARAMETER*/z: '1', x: '2', y: '3');
+            bar(y: 1);
+            x = bar(x: '1', /*warning:UNDEFINED_NAMED_PARAMETER*/z: 42);
+            x = /*info:DYNAMIC_CAST*/bar(y: 1, x: 2, /*warning:UNDEFINED_NAMED_PARAMETER*/z: 3);
+            x = /*info:DYNAMIC_CAST*/bar(x: 1);
+          }
+      ''');
+  });
+
+  test('type promotion from dynamic', () {
+    checkFile(r'''
+          f() {
+            dynamic x;
+            if (x is int) {
+              int y = x;
+              String z = /*severe:STATIC_TYPE_ERROR*/x;
+            }
+          }
+          g() {
+            Object x;
+            if (x is int) {
+              int y = x;
+              String z = /*severe:STATIC_TYPE_ERROR*/x;
+            }
+          }
+    ''');
+  });
+
+  test('unary operators', () {
+    checkFile('''
       class A {
         A operator ~() {}
         A operator +(int x) {}
@@ -1406,6 +1785,7 @@
       test() {
         A a = new A();
         var c = foo();
+        dynamic d;
 
         ~a;
         (/*info:DYNAMIC_INVOKE*/~d);
@@ -1425,11 +1805,11 @@
         a--;
         (/*info:DYNAMIC_INVOKE*/d++);
         (/*info:DYNAMIC_INVOKE*/d--);
-      }'''
+      }''');
   });
 
-  testChecker('binary and index operators', {
-    '/main.dart': '''
+  test('binary and index operators', () {
+    checkFile('''
           class A {
             A operator *(B b) {}
             A operator /(B b) {}
@@ -1490,11 +1870,11 @@
             c = (/*info:DYNAMIC_INVOKE*/c[b]);
             a[/*severe:STATIC_TYPE_ERROR*/y];
           }
-       '''
+       ''');
   });
 
-  testChecker('null coalescing operator', {
-    '/main.dart': '''
+  test('null coalescing operator', () {
+    checkFile('''
           class A {}
           class C<T> {}
           main() {
@@ -1507,11 +1887,11 @@
             c ??= /*info:INFERRED_TYPE_ALLOCATION*/new C();
             d = d ?? /*info:INFERRED_TYPE_ALLOCATION*/new C();
           }
-       '''
+       ''');
   });
 
-  testChecker('compound assignments', {
-    '/main.dart': '''
+  test('compound assignments', () {
+    checkFile('''
           class A {
             A operator *(B b) {}
             A operator /(B b) {}
@@ -1587,13 +1967,13 @@
             a[/*severe:STATIC_TYPE_ERROR*/z] += d;
             a[b] += /*info:DYNAMIC_CAST*/c;
             a[b] += /*severe:STATIC_TYPE_ERROR*/z;
-            (/*info:DYNAMIC_INVOKE*/(/*info:DYNAMIC_INVOKE*/c[b]) += d);
+            /*info:DYNAMIC_INVOKE,info:DYNAMIC_INVOKE*/c[b] += d;
           }
-       '''
+       ''');
   });
 
-  testChecker('super call placement', {
-    '/main.dart': '''
+  test('super call placement', () {
+    checkFile('''
           class Base {
             var x;
             Base() : x = print('Base.1') { print('Base.2'); }
@@ -1624,11 +2004,11 @@
           }
 
           main() => new Derived();
-       '''
+       ''');
   });
 
-  testChecker('for loop variable', {
-    '/main.dart': '''
+  test('for loop variable', () {
+    checkFile('''
           foo() {
             for (int i = 0; i < 10; i++) {
               i = /*severe:STATIC_TYPE_ERROR*/"hi";
@@ -1639,12 +2019,22 @@
               int j = i + 1;
             }
           }
-        '''
+        ''');
+  });
+
+  test('loadLibrary', () {
+    addFile('''library lib1;''', name: '/lib1.dart');
+    checkFile(r'''
+        import 'lib1.dart' deferred as lib1;
+        import 'dart:async' show Future;
+        main() {
+          Future f = lib1.loadLibrary();
+        }''');
   });
 
   group('invalid overrides', () {
-    testChecker('child override', {
-      '/main.dart': '''
+    test('child override', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1653,11 +2043,11 @@
             }
 
             class T1 extends Base {
-              /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/B get f => null;
+              /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_FIELD_OVERRIDE*/B get f => null;
             }
 
             class T2 extends Base {
-              /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/set f(B b) => null;
+              /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_FIELD_OVERRIDE*/set f(B b) => null;
             }
 
             class T3 extends Base {
@@ -1683,11 +2073,11 @@
               // two: one for the getter one for the setter.
               /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/B f;
             }
-         '''
+         ''');
     });
 
-    testChecker('child override 2', {
-      '/main.dart': '''
+    test('child override 2', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1698,10 +2088,10 @@
             class Test extends Base {
                 /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
             }
-         '''
+         ''');
     });
-    testChecker('grandchild override', {
-      '/main.dart': '''
+    test('grandchild override', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1716,11 +2106,11 @@
                 /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
                 /*severe:INVALID_FIELD_OVERRIDE*/int x;
             }
-         '''
+         ''');
     });
 
-    testChecker('double override', {
-      '/main.dart': '''
+    test('double override', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1735,11 +2125,11 @@
                 // Reported only once
                 /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
             }
-         '''
+         ''');
     });
 
-    testChecker('double override 2', {
-      '/main.dart': '''
+    test('double override 2', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1753,11 +2143,11 @@
             class Test extends Parent {
                 m(B a) {}
             }
-         '''
+         ''');
     });
 
-    testChecker('mixin override to base', {
-      '/main.dart': '''
+    test('mixin override to base', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1777,11 +2167,11 @@
             class T1 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M1 {}
             class T2 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M1, /*severe:INVALID_FIELD_OVERRIDE*/M2 {}
             class T3 extends Base with /*severe:INVALID_FIELD_OVERRIDE*/M2, /*severe:INVALID_METHOD_OVERRIDE*/M1 {}
-         '''
+         ''');
     });
 
-    testChecker('mixin override to mixin', {
-      '/main.dart': '''
+    test('mixin override to mixin', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1799,14 +2189,14 @@
             }
 
             class T1 extends Base with M1, /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_FIELD_OVERRIDE*/M2 {}
-         '''
+         ''');
     });
 
     // This is a regression test for a bug in an earlier implementation were
     // names were hiding errors if the first mixin override looked correct,
     // but subsequent ones did not.
-    testChecker('no duplicate mixin override', {
-      '/main.dart': '''
+    test('no duplicate mixin override', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1828,11 +2218,11 @@
 
             class T1 extends Base
                 with M1, /*severe:INVALID_METHOD_OVERRIDE*/M2, M3 {}
-         '''
+         ''');
     });
 
-    testChecker('class override of interface', {
-      '/main.dart': '''
+    test('class override of interface', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1843,11 +2233,11 @@
             class T1 implements I {
                 /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
             }
-         '''
+         ''');
     });
 
-    testChecker('base class override to child interface', {
-      '/main.dart': '''
+    test('base class override to child interface', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1862,11 +2252,11 @@
 
             class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base implements I {
             }
-         '''
+         ''');
     });
 
-    testChecker('mixin override of interface', {
-      '/main.dart': '''
+    test('mixin override of interface', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1880,14 +2270,13 @@
 
             class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                implements I {}
-         '''
+         ''');
     });
 
     // This is a case were it is incorrect to say that the base class
     // incorrectly overrides the interface.
-    testChecker(
-        'no errors if subclass correctly overrides base and interface', {
-      '/main.dart': '''
+    test('no errors if subclass correctly overrides base and interface', () {
+      checkFile('''
             class A {}
             class B {}
 
@@ -1912,13 +2301,13 @@
             class T4 extends Object with Base implements I1 {
                 /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/m(a) {}
             }
-         '''
+         ''');
     });
   });
 
   group('class override of grand interface', () {
-    testChecker('interface of interface of child', {
-      '/main.dart': '''
+    test('interface of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -1930,10 +2319,10 @@
               class T1 implements I2 {
                   /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
-           '''
+           ''');
     });
-    testChecker('superclass of interface of child', {
-      '/main.dart': '''
+    test('superclass of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -1945,10 +2334,10 @@
               class T1 implements I2 {
                   /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
-           '''
+           ''');
     });
-    testChecker('mixin of interface of child', {
-      '/main.dart': '''
+    test('mixin of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -1960,10 +2349,10 @@
               class T1 implements I2 {
                   /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
-           '''
+           ''');
     });
-    testChecker('interface of abstract superclass', {
-      '/main.dart': '''
+    test('interface of abstract superclass', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -1975,10 +2364,10 @@
               class T1 extends Base {
                   /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
-           '''
+           ''');
     });
-    testChecker('interface of concrete superclass', {
-      '/main.dart': '''
+    test('interface of concrete superclass', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -1996,13 +2385,13 @@
                   // sufficient to check overrides against it.
                   m(B a) {}
               }
-           '''
+           ''');
     });
   });
 
   group('mixin override of grand interface', () {
-    testChecker('interface of interface of child', {
-      '/main.dart': '''
+    test('interface of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2018,10 +2407,10 @@
               class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I2 {
               }
-           '''
+           ''');
     });
-    testChecker('superclass of interface of child', {
-      '/main.dart': '''
+    test('superclass of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2037,10 +2426,10 @@
               class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I2 {
               }
-           '''
+           ''');
     });
-    testChecker('mixin of interface of child', {
-      '/main.dart': '''
+    test('mixin of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2056,10 +2445,10 @@
               class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I2 {
               }
-           '''
+           ''');
     });
-    testChecker('interface of abstract superclass', {
-      '/main.dart': '''
+    test('interface of abstract superclass', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2074,10 +2463,10 @@
 
               class T1 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M {
               }
-           '''
+           ''');
     });
-    testChecker('interface of concrete superclass', {
-      '/main.dart': '''
+    test('interface of concrete superclass', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2095,13 +2484,13 @@
 
               class T1 extends Base with M {
               }
-           '''
+           ''');
     });
   });
 
   group('superclass override of grand interface', () {
-    testChecker('interface of interface of child', {
-      '/main.dart': '''
+    test('interface of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2117,10 +2506,10 @@
               class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                   implements I2 {
               }
-           '''
+           ''');
     });
-    testChecker('superclass of interface of child', {
-      '/main.dart': '''
+    test('superclass of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2136,10 +2525,10 @@
               class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                   implements I2 {
               }
-           '''
+           ''');
     });
-    testChecker('mixin of interface of child', {
-      '/main.dart': '''
+    test('mixin of interface of child', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2155,10 +2544,10 @@
               class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                   implements I2 {
               }
-           '''
+           ''');
     });
-    testChecker('interface of abstract superclass', {
-      '/main.dart': '''
+    test('interface of abstract superclass', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2178,10 +2567,10 @@
                   // reported.
                   /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
-           '''
+           ''');
     });
-    testChecker('interface of concrete superclass', {
-      '/main.dart': '''
+    test('interface of concrete superclass', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2196,13 +2585,13 @@
               class T1 extends Base {
                   m(B a) {}
               }
-           '''
+           ''');
     });
   });
 
   group('no duplicate reports from overriding interfaces', () {
-    testChecker('type overrides same method in multiple interfaces', {
-      '/main.dart': '''
+    test('type overrides same method in multiple interfaces', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2219,11 +2608,11 @@
               class T1 implements I2 {
                 /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
               }
-           '''
+           ''');
     });
 
-    testChecker('type and base type override same method in interface', {
-      '/main.dart': '''
+    test('type and base type override same method in interface', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2246,11 +2635,11 @@
               class T2 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
                   implements I1 {
               }
-           '''
+           ''');
     });
 
-    testChecker('type and mixin override same method in interface', {
-      '/main.dart': '''
+    test('type and mixin override same method in interface', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2269,11 +2658,11 @@
               class T2 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I1 {
               }
-           '''
+           ''');
     });
 
-    testChecker('two grand types override same method in interface', {
-      '/main.dart': '''
+    test('two grand types override same method in interface', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2298,11 +2687,11 @@
               class T2 /*severe:INVALID_METHOD_OVERRIDE*/extends Parent2
                   implements I1 {
               }
-           '''
+           ''');
     });
 
-    testChecker('two mixins override same method in interface', {
-      '/main.dart': '''
+    test('two mixins override same method in interface', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2322,15 +2711,15 @@
               // different.
               // TODO(sigmund): should we merge these as well?
               class T1 extends Object
-                  with /*severe:INVALID_METHOD_OVERRIDE*/M1
-                  with /*severe:INVALID_METHOD_OVERRIDE*/M2
+                  with /*severe:INVALID_METHOD_OVERRIDE*/M1,
+                  /*severe:INVALID_METHOD_OVERRIDE*/M2
                   implements I1 {
               }
-           '''
+           ''');
     });
 
-    testChecker('base type and mixin override same method in interface', {
-      '/main.dart': '''
+    test('base type and mixin override same method in interface', () {
+      checkFile('''
               class A {}
               class B {}
 
@@ -2353,12 +2742,12 @@
                   with /*severe:INVALID_METHOD_OVERRIDE*/M
                   implements I1 {
               }
-           '''
+           ''');
     });
   });
 
-  testChecker('invalid runtime checks', {
-    '/main.dart': '''
+  test('invalid runtime checks', () {
+    checkFile('''
           typedef int I2I(int x);
           typedef int D2I(x);
           typedef int II2I(int x, int y);
@@ -2408,12 +2797,12 @@
             f = bar as ID2D;
             f = bar as DD2D;
           }
-      '''
+      ''');
   });
 
   group('function modifiers', () {
-    testChecker('async', {
-      '/main.dart': '''
+    test('async', () {
+      checkFile('''
         import 'dart:async';
         import 'dart:math' show Random;
 
@@ -2449,11 +2838,11 @@
             return new Future<bool>.value(false);
           }
         }
-    '''
+    ''');
     });
 
-    testChecker('async*', {
-      '/main.dart': '''
+    test('async*', () {
+      checkFile('''
         import 'dart:async';
 
         dynamic x;
@@ -2468,11 +2857,11 @@
         Stream<int> baz3() async* { yield* (/*warning:DOWN_CAST_COMPOSITE*/x); }
         Stream<int> baz4() async* { yield* new Stream<int>(); }
         Stream<int> baz5() async* { yield* (/*info:INFERRED_TYPE_ALLOCATION*/new Stream()); }
-    '''
+    ''');
     });
 
-    testChecker('sync*', {
-      '/main.dart': '''
+    test('sync*', () {
+      checkFile('''
         import 'dart:async';
 
         dynamic x;
@@ -2487,7 +2876,7 @@
         Iterable<int> baz3() sync* { yield* (/*warning:DOWN_CAST_COMPOSITE*/x); }
         Iterable<int> baz4() sync* { yield* new Iterable<int>(); }
         Iterable<int> baz5() sync* { yield* (/*info:INFERRED_TYPE_ALLOCATION*/new Iterable()); }
-    '''
+    ''');
     });
   });
 }
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index d823b20..4bfe3521 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -12,56 +12,58 @@
 import 'strong_test_helper.dart';
 
 void main() {
+  initStrongModeTests();
+
   // Error also expected when declared type is `int`.
-  testChecker('infer type on var', {
-    '/main.dart': '''
+  test('infer type on var', () {
+    checkFile('''
       test1() {
         int x = 3;
         x = /*severe:STATIC_TYPE_ERROR*/"hi";
       }
-    '''
+    ''');
   });
 
   // If inferred type is `int`, error is also reported
-  testChecker('infer type on var 2', {
-    '/main.dart': '''
+  test('infer type on var 2', () {
+    checkFile('''
       test2() {
         var x = 3;
         x = /*severe:STATIC_TYPE_ERROR*/"hi";
       }
-    '''
+    ''');
   });
 
-  testChecker('No error when declared type is `num` and assigned null.', {
-    '/main.dart': '''
+  test('No error when declared type is `num` and assigned null.', () {
+    checkFile('''
         test1() {
           num x = 3;
           x = null;
         }
-      '''
+      ''');
   });
 
-  testChecker('do not infer type on dynamic', {
-    '/main.dart': '''
+  test('do not infer type on dynamic', () {
+    checkFile('''
       test() {
         dynamic x = 3;
         x = "hi";
       }
-    '''
+    ''');
   });
 
-  testChecker('do not infer type when initializer is null', {
-    '/main.dart': '''
+  test('do not infer type when initializer is null', () {
+    checkFile('''
       test() {
         var x = null;
         x = "hi";
         x = 3;
       }
-    '''
+    ''');
   });
 
-  testChecker('infer type on var from field', {
-    '/main.dart': '''
+  test('infer type on var from field', () {
+    checkFile('''
       class A {
         int x = 0;
 
@@ -80,11 +82,11 @@
         int y; // field def after use
         final z = 42; // should infer `int`
       }
-    '''
+    ''');
   });
 
-  testChecker('infer type on var from top-level', {
-    '/main.dart': '''
+  test('infer type on var from top-level', () {
+    checkFile('''
       int x = 0;
 
       test1() {
@@ -101,11 +103,11 @@
 
       int y = 0; // field def after use
       final z = 42; // should infer `int`
-    '''
+    ''');
   });
 
-  testChecker('do not infer field type when initializer is null', {
-    '/main.dart': '''
+  test('do not infer field type when initializer is null', () {
+    checkFile('''
       var x = null;
       var y = 3;
       class A {
@@ -124,14 +126,16 @@
         new A().x2 = "hi";
         new A().y2 = /*severe:STATIC_TYPE_ERROR*/"hi";
       }
-    '''
+    ''');
   });
 
-  testChecker('infer from variables in non-cycle imports with flag', {
-    '/a.dart': '''
+  test('infer from variables in non-cycle imports with flag', () {
+    addFile(
+        '''
           var x = 2;
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
           import 'a.dart';
           var y = x;
 
@@ -139,14 +143,16 @@
             x = /*severe:STATIC_TYPE_ERROR*/"hi";
             y = /*severe:STATIC_TYPE_ERROR*/"hi";
           }
-    '''
+    ''');
   });
 
-  testChecker('infer from variables in non-cycle imports with flag 2', {
-    '/a.dart': '''
+  test('infer from variables in non-cycle imports with flag 2', () {
+    addFile(
+        '''
           class A { static var x = 2; }
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
           import 'a.dart';
           class B { static var y = A.x; }
 
@@ -154,15 +160,17 @@
             A.x = /*severe:STATIC_TYPE_ERROR*/"hi";
             B.y = /*severe:STATIC_TYPE_ERROR*/"hi";
           }
-    '''
+    ''');
   });
 
-  testChecker('infer from variables in cycle libs when flag is on', {
-    '/a.dart': '''
+  test('infer from variables in cycle libs when flag is on', () {
+    addFile(
+        '''
           import 'main.dart';
           var x = 2; // ok to infer
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
           import 'a.dart';
           var y = x; // now ok :)
 
@@ -171,15 +179,17 @@
             t = x;
             t = y;
           }
-    '''
+    ''');
   });
 
-  testChecker('infer from variables in cycle libs when flag is on 2', {
-    '/a.dart': '''
+  test('infer from variables in cycle libs when flag is on 2', () {
+    addFile(
+        '''
           import 'main.dart';
           class A { static var x = 2; }
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
           import 'a.dart';
           class B { static var y = A.x; }
 
@@ -188,24 +198,28 @@
             t = A.x;
             t = B.y;
           }
-    '''
+    ''');
   });
 
-  testChecker('can infer also from static and instance fields (flag on)', {
-    '/a.dart': '''
+  test('can infer also from static and instance fields (flag on)', () {
+    addFile(
+        '''
           import 'b.dart';
           class A {
             static final a1 = B.b1;
             final a2 = new B().b2;
           }
       ''',
-    '/b.dart': '''
+        name: '/a.dart');
+    addFile(
+        '''
           class B {
             static final b1 = 1;
             final b2 = 1;
           }
       ''',
-    '/main.dart': '''
+        name: '/b.dart');
+    checkFile('''
           import "a.dart";
 
           test1() {
@@ -214,24 +228,29 @@
             x = A.a1;
             x = new A().a2;
           }
-    '''
+    ''');
   });
 
-  testChecker('inference in cycles is deterministic', {
-    '/a.dart': '''
+  test('inference in cycles is deterministic', () {
+    addFile(
+        '''
           import 'b.dart';
           class A {
             static final a1 = B.b1;
             final a2 = new B().b2;
           }
       ''',
-    '/b.dart': '''
+        name: '/a.dart');
+    addFile(
+        '''
           class B {
             static final b1 = 1;
             final b2 = 1;
           }
       ''',
-    '/c.dart': '''
+        name: '/b.dart');
+    addFile(
+        '''
           import "main.dart"; // creates a cycle
 
           class C {
@@ -239,7 +258,10 @@
             final c2 = 1;
           }
       ''',
-    '/e.dart': '''
+        name: '/c.dart');
+    addFile(
+        '''
+          library e;
           import 'a.dart';
           part 'e2.dart';
 
@@ -252,16 +274,22 @@
             final e6 = new A().a2;
           }
       ''',
-    '/f.dart': '''
+        name: '/e.dart');
+    addFile(
+        '''
           part 'f2.dart';
       ''',
-    '/e2.dart': '''
+        name: '/f.dart');
+    addFile(
+        '''
+          part of e;
           class F {
             static final f1 = 1;
             final f2 = 1;
           }
       ''',
-    '/main.dart': '''
+        name: '/e2.dart');
+    checkFile('''
           import "a.dart";
           import "c.dart";
           import "e.dart";
@@ -299,27 +327,26 @@
             x = F.f1;
             x = new F().f2;
           }
-    '''
+    ''');
   });
 
-  testChecker(
-      'infer from complex expressions if the outer-most value is precise', {
-    '/main.dart': '''
+  test('infer from complex expressions if the outer-most value is precise', () {
+    checkFile('''
         class A { int x; B operator+(other) {} }
         class B extends A { B(ignore); }
         var a = new A();
         // Note: it doesn't matter that some of these refer to 'x'.
-        var b = new B(x);       // allocations
-        var c1 = [x];           // list literals
+        var b = new B(/*warning:UNDEFINED_IDENTIFIER*/x);  // allocations
+        var c1 = [/*warning:UNDEFINED_IDENTIFIER*/x];      // list literals
         var c2 = const [];
-        var d = {'a': 'b'};     // map literals
+        var d = <dynamic, dynamic>{'a': 'b'};     // map literals
         var e = new A()..x = 3; // cascades
         var f = 2 + 3;          // binary expressions are OK if the left operand
                                 // is from a library in a different strongest
                                 // conected component.
         var g = -3;
         var h = new A() + 3;
-        var i = - new A();
+        var i = /*warning:UNDEFINED_OPERATOR*/- new A();
         var j = null as B;
 
         test1() {
@@ -340,17 +367,17 @@
           g = 1;
           g = /*severe:STATIC_TYPE_ERROR*/false;
           h = /*severe:STATIC_TYPE_ERROR*/false;
-          h = new B();
+          h = new B('b');
           i = false;
-          j = new B();
+          j = new B('b');
           j = /*severe:STATIC_TYPE_ERROR*/false;
           j = /*severe:STATIC_TYPE_ERROR*/[];
         }
-    '''
+    ''');
   });
 
-  testChecker('infer list literal nested in map literal', {
-    '/main.dart': r'''
+  test('infer list literal nested in map literal', () {
+    checkFile(r'''
 class Resource {}
 class Folder extends Resource {}
 
@@ -376,17 +403,19 @@
     /*info:INFERRED_TYPE_LITERAL*/[/*info:DOWN_CAST_IMPLICIT*/getResource('/pkgA/lib/')]
   );
 }
-    '''
+    ''');
   });
 
   // but flags can enable this behavior.
-  testChecker('infer if complex expressions read possibly inferred field', {
-    '/a.dart': '''
+  test('infer if complex expressions read possibly inferred field', () {
+    addFile(
+        '''
         class A {
           var x = 3;
         }
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
         import 'a.dart';
         class B {
           var y = 3;
@@ -406,12 +435,12 @@
           i = /*info:DYNAMIC_CAST*/t4;
           i = new B().y; // B.y was inferred though
         }
-    '''
+    ''');
   });
 
   group('infer types on loop indices', () {
-    testChecker('foreach loop', {
-      '/main.dart': '''
+    test('foreach loop', () {
+      checkFile('''
       class Foo {
         int bar = 42;
       }
@@ -474,22 +503,22 @@
           String y = x;
         }
       }
-      '''
+      ''');
     });
 
-    testChecker('for loop, with inference', {
-      '/main.dart': '''
+    test('for loop, with inference', () {
+      checkFile('''
       test() {
         for (var i = 0; i < 10; i++) {
           int j = i + 1;
         }
       }
-      '''
+      ''');
     });
   });
 
-  testChecker('propagate inference to field in class', {
-    '/main.dart': '''
+  test('propagate inference to field in class', () {
+    checkFile('''
       class A {
         int x = 2;
       }
@@ -500,11 +529,11 @@
         print(a.x);     // doesn't require dynamic invoke
         print(a.x + 2); // ok to use in bigger expression
       }
-    '''
+    ''');
   });
 
-  testChecker('propagate inference to field in class dynamic warnings', {
-    '/main.dart': '''
+  test('propagate inference to field in class dynamic warnings', () {
+    checkFile('''
       class A {
         int x = 2;
       }
@@ -515,11 +544,11 @@
         print(/*info:DYNAMIC_INVOKE*/a.x);
         print(/*info:DYNAMIC_INVOKE*/(/*info:DYNAMIC_INVOKE*/a.x) + 2);
       }
-    '''
+    ''');
   });
 
-  testChecker('propagate inference transitively', {
-    '/main.dart': '''
+  test('propagate inference transitively', () {
+    checkFile('''
       class A {
         int x = 2;
       }
@@ -531,11 +560,11 @@
         A a2 = new A();
         a2.x = /*severe:STATIC_TYPE_ERROR*/"hi";
       }
-    '''
+    ''');
   });
 
-  testChecker('propagate inference transitively 2', {
-    '/main.dart': '''
+  test('propagate inference transitively 2', () {
+    checkFile('''
       class A {
         int x = 42;
       }
@@ -559,12 +588,12 @@
         D d2 = new D();
         print(d2.c.b.a.x);
       }
-    '''
+    ''');
   });
 
   group('infer type on overridden fields', () {
-    testChecker('2', {
-      '/main.dart': '''
+    test('2', () {
+      checkFile('''
         class A {
           int x = 2;
         }
@@ -577,11 +606,11 @@
           String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
           int z = new B().x;
         }
-    '''
+    ''');
     });
 
-    testChecker('4', {
-      '/main.dart': '''
+    test('4', () {
+      checkFile('''
         class A {
           int x = 2;
         }
@@ -594,13 +623,13 @@
           String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
           int z = new B().x;
         }
-    '''
+    ''');
     });
   });
 
   group('infer types on generic instantiations', () {
-    testChecker('infer', {
-      '/main.dart': '''
+    test('infer', () {
+      checkFile('''
         class A<T> {
           T x;
         }
@@ -613,11 +642,11 @@
           String y = /*info:DYNAMIC_CAST*/new B().x;
           int z = /*info:DYNAMIC_CAST*/new B().x;
         }
-    '''
+    ''');
     });
 
-    testChecker('3', {
-      '/main.dart': '''
+    test('3', () {
+      checkFile('''
         class A<T> {
           T x;
           T w;
@@ -632,11 +661,11 @@
           String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
           int z = new B().x;
         }
-    '''
+    ''');
     });
 
-    testChecker('4', {
-      '/main.dart': '''
+    test('4', () {
+      checkFile('''
         class A<T> {
           T x;
         }
@@ -650,18 +679,18 @@
           int y = /*severe:STATIC_TYPE_ERROR*/new B<String>().x;
           String z = new B<String>().x;
         }
-    '''
+    ''');
     });
 
-    testChecker('5', {
-      '/main.dart': '''
+    test('5', () {
+      checkFile('''
         abstract class I<E> {
-          String m(a, String f(v, T e));
+          String m(a, String f(v, E e));
         }
 
         abstract class A<E> implements I<E> {
           const A();
-          String m(a, String f(v, T e));
+          String m(a, String f(v, E e));
         }
 
         abstract class M {
@@ -672,24 +701,26 @@
           const B();
           int get y => 0;
 
-          m(a, f(v, T e)) {}
+          m(a, f(v, E e)) {}
         }
 
         foo () {
           int y = /*severe:STATIC_TYPE_ERROR*/new B().m(null, null);
           String z = new B().m(null, null);
         }
-    '''
+    ''');
     });
   });
 
-  testChecker('infer type regardless of declaration order or cycles', {
-    '/b.dart': '''
+  test('infer type regardless of declaration order or cycles', () {
+    addFile(
+        '''
         import 'main.dart';
 
         class B extends A { }
       ''',
-    '/main.dart': '''
+        name: '/b.dart');
+    checkFile('''
         import 'b.dart';
         class C extends B {
           get x;
@@ -699,22 +730,24 @@
         }
         foo () {
           int y = new C().x;
-          String y = /*severe:STATIC_TYPE_ERROR*/new C().x;
+          String z = /*severe:STATIC_TYPE_ERROR*/new C().x;
         }
-    '''
+    ''');
   });
 
   // Note: this is a regression test for a non-deterministic behavior we used to
   // have with inference in library cycles. If you see this test flake out,
   // change `test` to `skip_test` and reopen bug #48.
-  testChecker('infer types on generic instantiations in library cycle', {
-    '/a.dart': '''
+  test('infer types on generic instantiations in library cycle', () {
+    addFile(
+        '''
           import 'main.dart';
         abstract class I<E> {
           A<E> m(a, String f(v, int e));
         }
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
           import 'a.dart';
 
         abstract class A<E> implements I<E> {
@@ -738,12 +771,12 @@
           int y = /*severe:STATIC_TYPE_ERROR*/new B<String>().m(null, null).value;
           String z = new B<String>().m(null, null).value;
         }
-    '''
+    ''');
   });
 
   group('do not infer overridden fields that explicitly say dynamic', () {
-    testChecker('infer', {
-      '/main.dart': '''
+    test('infer', () {
+      checkFile('''
           class A {
             int x = 2;
           }
@@ -756,12 +789,12 @@
             String y = /*info:DYNAMIC_CAST*/new B().x;
             int z = /*info:DYNAMIC_CAST*/new B().x;
           }
-      '''
+      ''');
     });
   });
 
-  testChecker('conflicts can happen', {
-    '/main.dart': '''
+  test('conflicts can happen', () {
+    checkFile('''
         class I1 {
           int x;
         }
@@ -785,11 +818,11 @@
         class C2 implements B, A {
           /*severe:INVALID_METHOD_OVERRIDE*/get a => null;
         }
-    '''
+    ''');
   });
 
-  testChecker('conflicts can happen 2', {
-    '/main.dart': '''
+  test('conflicts can happen 2', () {
+    checkFile('''
         class I1 {
           int x;
         }
@@ -817,12 +850,11 @@
         class C2 implements A, B {
           /*severe:INVALID_METHOD_OVERRIDE*/get a => null;
         }
-    '''
+    ''');
   });
 
-  testChecker(
-      'infer from RHS only if it wont conflict with overridden fields', {
-    '/main.dart': '''
+  test('infer from RHS only if it wont conflict with overridden fields', () {
+    checkFile('''
         class A {
           var x;
         }
@@ -835,12 +867,11 @@
           String y = /*info:DYNAMIC_CAST*/new B().x;
           int z = /*info:DYNAMIC_CAST*/new B().x;
         }
-    '''
+    ''');
   });
 
-  testChecker(
-      'infer from RHS only if it wont conflict with overridden fields 2', {
-    '/main.dart': '''
+  test('infer from RHS only if it wont conflict with overridden fields 2', () {
+    checkFile('''
         class A {
           final x;
         }
@@ -853,11 +884,11 @@
           String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
           int z = new B().x;
         }
-    '''
+    ''');
   });
 
-  testChecker('infer correctly on multiple variables declared together', {
-    '/main.dart': '''
+  test('infer correctly on multiple variables declared together', () {
+    checkFile('''
         class A {
           var x, y = 2, z = "hi";
         }
@@ -880,20 +911,24 @@
           i = /*severe:STATIC_TYPE_ERROR*/new B().z;
           i = new B().w;
         }
-    '''
+    ''');
   });
 
-  testChecker('infer consts transitively', {
-    '/b.dart': '''
+  test('infer consts transitively', () {
+    addFile(
+        '''
         const b1 = 2;
       ''',
-    '/a.dart': '''
+        name: '/b.dart');
+    addFile(
+        '''
         import 'main.dart';
         import 'b.dart';
         const a1 = m2;
         const a2 = b1;
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
         import 'a.dart';
         const m1 = a1;
         const m2 = a2;
@@ -902,14 +937,17 @@
           int i;
           i = m1;
         }
-    '''
+    ''');
   });
 
-  testChecker('infer statics transitively', {
-    '/b.dart': '''
+  test('infer statics transitively', () {
+    addFile(
+        '''
         final b1 = 2;
       ''',
-    '/a.dart': '''
+        name: '/b.dart');
+    addFile(
+        '''
         import 'main.dart';
         import 'b.dart';
         final a1 = m2;
@@ -917,7 +955,8 @@
           static final a2 = b1;
         }
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
         import 'a.dart';
         final m1 = a1;
         final m2 = A.a2;
@@ -926,11 +965,11 @@
           int i;
           i = m1;
         }
-    '''
+    ''');
   });
 
-  testChecker('infer statics transitively 2', {
-    '/main.dart': '''
+  test('infer statics transitively 2', () {
+    checkFile('''
         const x1 = 1;
         final x2 = 1;
         final y1 = x1;
@@ -941,18 +980,20 @@
           i = y1;
           i = y2;
         }
-    '''
+    ''');
   });
 
-  testChecker('infer statics transitively 3', {
-    '/a.dart': '''
+  test('infer statics transitively 3', () {
+    addFile(
+        '''
         const a1 = 3;
         const a2 = 4;
         class A {
-          a3;
+          static const a3 = null;
         }
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
         import 'a.dart' show a1, A;
         import 'a.dart' as p show a2, A;
         const t1 = 1;
@@ -969,14 +1010,16 @@
           i = t3;
           i = t4;
         }
-    '''
+    ''');
   });
 
-  testChecker('infer statics with method invocations', {
-    '/a.dart': '''
+  test('infer statics with method invocations', () {
+    addFile(
+        '''
         m3(String a, String b, [a1,a2]) {}
       ''',
-    '/main.dart': '''
+        name: '/a.dart');
+    checkFile('''
         import 'a.dart';
         class T {
           static final T foo = m1(m2(m3('', '')));
@@ -985,11 +1028,11 @@
         }
 
 
-    '''
+    ''');
   });
 
-  testChecker('downwards inference: miscellaneous', {
-    '/main.dart': '''
+  test('downwards inference: miscellaneous', () {
+    checkFile('''
       typedef T Function2<S, T>(S x);
       class A<T> {
         Function2<T, T> x;
@@ -1007,12 +1050,12 @@
             A<int> a = /*info:INFERRED_TYPE_ALLOCATION*/new A(f);
           }
       }
-      '''
+      ''');
   });
 
   group('downwards inference on instance creations', () {
-    String info = 'info:INFERRED_TYPE_ALLOCATION';
-    String code = '''
+    test('infer downwards', () {
+      checkFile('''
       class A<S, T> {
         S x;
         T y;
@@ -1046,8 +1089,8 @@
 
       void main() {
         {
-          A<int, String> a0 = /*$info*/new A(3, "hello");
-          A<int, String> a1 = /*$info*/new A.named(3, "hello");
+          A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new A(3, "hello");
+          A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new A.named(3, "hello");
           A<int, String> a2 = new A<int, String>(3, "hello");
           A<int, String> a3 = new A<int, String>.named(3, "hello");
           A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new A<int, dynamic>(3, "hello");
@@ -1058,8 +1101,8 @@
           A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new A.named(/*severe:STATIC_TYPE_ERROR*/"hello", /*severe:STATIC_TYPE_ERROR*/3);
         }
         {
-          A<int, String> a0 = /*$info*/new B("hello", 3);
-          A<int, String> a1 = /*$info*/new B.named("hello", 3);
+          A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new B("hello", 3);
+          A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new B.named("hello", 3);
           A<int, String> a2 = new B<String, int>("hello", 3);
           A<int, String> a3 = new B<String, int>.named("hello", 3);
           A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new B<String, dynamic>("hello", 3);
@@ -1070,8 +1113,8 @@
           A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new B.named(/*severe:STATIC_TYPE_ERROR*/3, /*severe:STATIC_TYPE_ERROR*/"hello");
         }
         {
-          A<int, int> a0 = /*$info*/new C(3);
-          A<int, int> a1 = /*$info*/new C.named(3);
+          A<int, int> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new C(3);
+          A<int, int> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new C.named(3);
           A<int, int> a2 = new C<int>(3);
           A<int, int> a3 = new C<int>.named(3);
           A<int, int> a4 = /*severe:STATIC_TYPE_ERROR*/new C<dynamic>(3);
@@ -1082,8 +1125,8 @@
           A<int, int> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new C.named(/*severe:STATIC_TYPE_ERROR*/"hello");
         }
         {
-          A<int, String> a0 = /*$info*/new D("hello");
-          A<int, String> a1 = /*$info*/new D.named("hello");
+          A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new D("hello");
+          A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new D.named("hello");
           A<int, String> a2 = new D<int, String>("hello");
           A<int, String> a3 = new D<String, String>.named("hello");
           A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new D<num, dynamic>("hello");
@@ -1097,29 +1140,29 @@
           A<C<int>, String> a0 = /*severe:STATIC_TYPE_ERROR*/new E("hello");
         }
         { // Check named and optional arguments
-          A<int, String> a0 = /*$info*/new F(3, "hello", a: /*info:INFERRED_TYPE_LITERAL*/[3], b: /*info:INFERRED_TYPE_LITERAL*/["hello"]);
+          A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new F(3, "hello", a: /*info:INFERRED_TYPE_LITERAL*/[3], b: /*info:INFERRED_TYPE_LITERAL*/["hello"]);
           A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new F(3, "hello", a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"], b: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3]);
-          A<int, String> a2 = /*$info*/new F.named(3, "hello", 3, "hello");
-          A<int, String> a3 = /*$info*/new F.named(3, "hello");
+          A<int, String> a2 = /*info:INFERRED_TYPE_ALLOCATION*/new F.named(3, "hello", 3, "hello");
+          A<int, String> a3 = /*info:INFERRED_TYPE_ALLOCATION*/new F.named(3, "hello");
           A<int, String> a4 = /*info:INFERRED_TYPE_ALLOCATION*/new F.named(3, "hello", /*severe:STATIC_TYPE_ERROR*/"hello", /*severe:STATIC_TYPE_ERROR*/3);
           A<int, String> a5 = /*info:INFERRED_TYPE_ALLOCATION*/new F.named(3, "hello", /*severe:STATIC_TYPE_ERROR*/"hello");
         }
       }
-        ''';
-    testChecker('infer downwards', {'/main.dart': code});
+        ''');
+    });
   });
 
   group('downwards inference on list literals', () {
-    String info = "info:INFERRED_TYPE_LITERAL";
-    String code = '''
-      void foo([List<String> list1 = /*$info*/const [],
+    test('infer downwards', () {
+      checkFile('''
+      void foo([List<String> list1 = /*info:INFERRED_TYPE_LITERAL*/const [],
                 List<String> list2 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/42]]) {
       }
 
       void main() {
         {
-          List<int> l0 = /*$info*/[];
-          List<int> l1 = /*$info*/[3];
+          List<int> l0 = /*info:INFERRED_TYPE_LITERAL*/[];
+          List<int> l1 = /*info:INFERRED_TYPE_LITERAL*/[3];
           List<int> l2 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
           List<int> l3 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
         }
@@ -1136,22 +1179,23 @@
           List<int> l3 = /*severe:STATIC_TYPE_ERROR*/<num>[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
         }
         {
-          Iterable<int> i0 = /*$info*/[];
-          Iterable<int> i1 = /*$info*/[3];
+          Iterable<int> i0 = /*info:INFERRED_TYPE_LITERAL*/[];
+          Iterable<int> i1 = /*info:INFERRED_TYPE_LITERAL*/[3];
           Iterable<int> i2 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
           Iterable<int> i3 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
         }
         {
-          const List<int> c0 = /*$info*/const [];
-          const List<int> c1 = /*$info*/const [3];
+          const List<int> c0 = /*info:INFERRED_TYPE_LITERAL*/const [];
+          const List<int> c1 = /*info:INFERRED_TYPE_LITERAL*/const [3];
           const List<int> c2 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/"hello"];
           const List<int> c3 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/"hello", 3];
         }
       }
-      ''';
-    testChecker('infer downwards', {'/main.dart': code});
+      ''');
+    });
 
-    testChecker('infer if value types match context', {'/main.dart': r'''
+    test('infer if value types match context', () {
+      checkFile(r'''
 class DartType {}
 typedef void Asserter<T>(T type);
 typedef Asserter<T> AsserterBuilder<S, T>(S arg);
@@ -1161,7 +1205,7 @@
 
 abstract class C {
   static AsserterBuilder<List<Asserter<DartType>>, DartType> assertBOf;
-  static AsserterBuilder<List<Asserter<DartType>>, DartType> get assertCOf;
+  static AsserterBuilder<List<Asserter<DartType>>, DartType> get assertCOf => null;
 
   AsserterBuilder<List<Asserter<DartType>>, DartType> assertAOf;
   AsserterBuilder<List<Asserter<DartType>>, DartType> get assertDOf;
@@ -1188,7 +1232,7 @@
 }
 
 AsserterBuilder<List<Asserter<DartType>>, DartType> assertBOf;
-AsserterBuilder<List<Asserter<DartType>>, DartType> get assertCOf;
+AsserterBuilder<List<Asserter<DartType>>, DartType> get assertCOf => null;
 
 main() {
   AsserterBuilder<List<Asserter<DartType>>, DartType> assertAOf;
@@ -1206,172 +1250,173 @@
   g.assertAOf(/*info:INFERRED_TYPE_LITERAL*/[_isInt, _isString]);
   g.assertDOf(/*info:INFERRED_TYPE_LITERAL*/[_isInt, _isString]);
 }
-    '''});
+    ''');
+    });
   });
 
   group('downwards inference on function arguments', () {
-    String info = "info:INFERRED_TYPE_LITERAL";
-    String code = '''
-      void f0(List<int> a) {};
-      void f1({List<int> a}) {};
-      void f2(Iterable<int> a) {};
-      void f3(Iterable<Iterable<int>> a) {};
-      void f4({Iterable<Iterable<int>> a}) {};
+    test('infer downwards', () {
+      checkFile('''
+      void f0(List<int> a) {}
+      void f1({List<int> a}) {}
+      void f2(Iterable<int> a) {}
+      void f3(Iterable<Iterable<int>> a) {}
+      void f4({Iterable<Iterable<int>> a}) {}
       void main() {
-        f0(/*$info*/[]);
-        f0(/*$info*/[3]);
+        f0(/*info:INFERRED_TYPE_LITERAL*/[]);
+        f0(/*info:INFERRED_TYPE_LITERAL*/[3]);
         f0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
         f0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
-        f1(a: /*$info*/[]);
-        f1(a: /*$info*/[3]);
-        f1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
-        f1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+        f1(a: /*info:INFERRED_TYPE_LITERAL*/[]);
+        f1(a: /*info:INFERRED_TYPE_LITERAL*/[3]);
+        f1(a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        f1(a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
-        f2(/*$info*/[]);
-        f2(/*$info*/[3]);
-        f2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
-        f2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+        f2(/*info:INFERRED_TYPE_LITERAL*/[]);
+        f2(/*info:INFERRED_TYPE_LITERAL*/[3]);
+        f2(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        f2(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
-        f3(/*$info*/[]);
-        f3(/*$info*/[/*$info*/[3]]);
-        f3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
-        f3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"], /*$info*/[3]]);
+        f3(/*info:INFERRED_TYPE_LITERAL*/[]);
+        f3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[3]]);
+        f3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        f3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"], /*info:INFERRED_TYPE_LITERAL*/[3]]);
 
-        f4(a: /*$info*/[]);
-        f4(a: /*$info*/[/*$info*/[3]]);
-        f4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
-        f4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"], /*$info*/[3]]);
+        f4(a: /*info:INFERRED_TYPE_LITERAL*/[]);
+        f4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[3]]);
+        f4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        f4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"], /*info:INFERRED_TYPE_LITERAL*/[3]]);
       }
-      ''';
-    testChecker('infer downwards', {'/main.dart': code});
+      ''');
+    });
   });
 
   group('downwards inference on constructor arguments', () {
-    String info = "info:INFERRED_TYPE_LITERAL";
-    String code = '''
+    test('infer downwards', () {
+      checkFile('''
       class F0 {
-        F0(List<int> a) {};
+        F0(List<int> a) {}
       }
       class F1 {
-        F1({List<int> a}) {};
+        F1({List<int> a}) {}
       }
       class F2 {
-        F2(Iterable<int> a) {};
+        F2(Iterable<int> a) {}
       }
       class F3 {
-        F3(Iterable<Iterable<int>> a) {};
+        F3(Iterable<Iterable<int>> a) {}
       }
       class F4 {
-        F4({Iterable<Iterable<int>> a}) {};
+        F4({Iterable<Iterable<int>> a}) {}
       }
       void main() {
-        new F0(/*$info*/[]);
-        new F0(/*$info*/[3]);
+        new F0(/*info:INFERRED_TYPE_LITERAL*/[]);
+        new F0(/*info:INFERRED_TYPE_LITERAL*/[3]);
         new F0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
         new F0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello",
                                             3]);
 
-        new F1(a: /*$info*/[]);
-        new F1(a: /*$info*/[3]);
-        new F1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
-        new F1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+        new F1(a: /*info:INFERRED_TYPE_LITERAL*/[]);
+        new F1(a: /*info:INFERRED_TYPE_LITERAL*/[3]);
+        new F1(a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F1(a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
-        new F2(/*$info*/[]);
-        new F2(/*$info*/[3]);
-        new F2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
-        new F2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+        new F2(/*info:INFERRED_TYPE_LITERAL*/[]);
+        new F2(/*info:INFERRED_TYPE_LITERAL*/[3]);
+        new F2(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F2(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
-        new F3(/*$info*/[]);
-        new F3(/*$info*/[/*$info*/[3]]);
-        new F3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
-        new F3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
-                         /*$info*/[3]]);
+        new F3(/*info:INFERRED_TYPE_LITERAL*/[]);
+        new F3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[3]]);
+        new F3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        new F3(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+                         /*info:INFERRED_TYPE_LITERAL*/[3]]);
 
-        new F4(a: /*$info*/[]);
-        new F4(a: /*$info*/[/*$info*/[3]]);
-        new F4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
-        new F4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
-                            /*$info*/[3]]);
+        new F4(a: /*info:INFERRED_TYPE_LITERAL*/[]);
+        new F4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[3]]);
+        new F4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        new F4(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+                            /*info:INFERRED_TYPE_LITERAL*/[3]]);
       }
-      ''';
-    testChecker('infer downwards', {'/main.dart': code});
+      ''');
+    });
   });
 
   group('downwards inference on generic constructor arguments', () {
-    String info = "info:INFERRED_TYPE_LITERAL";
-    String code = '''
+    test('infer downwards', () {
+      checkFile('''
       class F0<T> {
-        F0(List<T> a) {};
+        F0(List<T> a) {}
       }
       class F1<T> {
-        F1({List<T> a}) {};
+        F1({List<T> a}) {}
       }
       class F2<T> {
-        F2(Iterable<T> a) {};
+        F2(Iterable<T> a) {}
       }
       class F3<T> {
-        F3(Iterable<Iterable<T>> a) {};
+        F3(Iterable<Iterable<T>> a) {}
       }
       class F4<T> {
-        F4({Iterable<Iterable<T>> a}) {};
+        F4({Iterable<Iterable<T>> a}) {}
       }
       void main() {
-        new F0<int>(/*$info*/[]);
-        new F0<int>(/*$info*/[3]);
+        new F0<int>(/*info:INFERRED_TYPE_LITERAL*/[]);
+        new F0<int>(/*info:INFERRED_TYPE_LITERAL*/[3]);
         new F0<int>(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
         new F0<int>(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello",
                                             3]);
 
-        new F1<int>(a: /*$info*/[]);
-        new F1<int>(a: /*$info*/[3]);
-        new F1<int>(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
-        new F1<int>(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+        new F1<int>(a: /*info:INFERRED_TYPE_LITERAL*/[]);
+        new F1<int>(a: /*info:INFERRED_TYPE_LITERAL*/[3]);
+        new F1<int>(a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F1<int>(a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
-        new F2<int>(/*$info*/[]);
-        new F2<int>(/*$info*/[3]);
-        new F2<int>(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
-        new F2<int>(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+        new F2<int>(/*info:INFERRED_TYPE_LITERAL*/[]);
+        new F2<int>(/*info:INFERRED_TYPE_LITERAL*/[3]);
+        new F2<int>(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+        new F2<int>(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
 
-        new F3<int>(/*$info*/[]);
-        new F3<int>(/*$info*/[/*$info*/[3]]);
-        new F3<int>(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
-        new F3<int>(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
-                         /*$info*/[3]]);
+        new F3<int>(/*info:INFERRED_TYPE_LITERAL*/[]);
+        new F3<int>(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[3]]);
+        new F3<int>(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        new F3<int>(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+                         /*info:INFERRED_TYPE_LITERAL*/[3]]);
 
-        new F4<int>(a: /*$info*/[]);
-        new F4<int>(a: /*$info*/[/*$info*/[3]]);
-        new F4<int>(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
-        new F4<int>(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
-                            /*$info*/[3]]);
+        new F4<int>(a: /*info:INFERRED_TYPE_LITERAL*/[]);
+        new F4<int>(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[3]]);
+        new F4<int>(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+        new F4<int>(a: /*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+                            /*info:INFERRED_TYPE_LITERAL*/[3]]);
 
-        new F3(/*$info*/[]);
-        new F3(/*$info*/[[3]]);
-        new F3(/*$info*/[["hello"]]);
-        new F3(/*$info*/[["hello"], [3]]);
+        new F3(/*info:INFERRED_TYPE_LITERAL*/[]);
+        new F3(/*info:INFERRED_TYPE_LITERAL*/[[3]]);
+        new F3(/*info:INFERRED_TYPE_LITERAL*/[["hello"]]);
+        new F3(/*info:INFERRED_TYPE_LITERAL*/[["hello"], [3]]);
 
-        new F4(a: /*$info*/[]);
-        new F4(a: /*$info*/[[3]]);
-        new F4(a: /*$info*/[["hello"]]);
-        new F4(a: /*$info*/[["hello"], [3]]);
+        new F4(a: /*info:INFERRED_TYPE_LITERAL*/[]);
+        new F4(a: /*info:INFERRED_TYPE_LITERAL*/[[3]]);
+        new F4(a: /*info:INFERRED_TYPE_LITERAL*/[["hello"]]);
+        new F4(a: /*info:INFERRED_TYPE_LITERAL*/[["hello"], [3]]);
       }
-      ''';
-    testChecker('infer downwards', {'/main.dart': code});
+      ''');
+    });
   });
 
   group('downwards inference on map literals', () {
-    String info = "info:INFERRED_TYPE_LITERAL";
-    String code = '''
-      void foo([Map<int, String> m1 = /*$info*/const {1: "hello"},
-        Map<int, String> m1 = /*$info*/const {(/*severe:STATIC_TYPE_ERROR*/"hello"): "world"}]) {
+    test('infer downwards', () {
+      checkFile('''
+      void foo([Map<int, String> m1 = /*info:INFERRED_TYPE_LITERAL*/const {1: "hello"},
+        Map<int, String> m2 = /*info:INFERRED_TYPE_LITERAL*/const {(/*severe:STATIC_TYPE_ERROR*/"hello"): "world"}]) {
       }
       void main() {
         {
-          Map<int, String> l0 = /*$info*/{};
-          Map<int, String> l1 = /*$info*/{3: "hello"};
-          Map<int, String> l2 = /*$info*/{(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
-          Map<int, String> l3 = /*$info*/{3: /*severe:STATIC_TYPE_ERROR*/3};
-          Map<int, String> l4 = /*$info*/{3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): /*severe:STATIC_TYPE_ERROR*/3};
+          Map<int, String> l0 = /*info:INFERRED_TYPE_LITERAL*/{};
+          Map<int, String> l1 = /*info:INFERRED_TYPE_LITERAL*/{3: "hello"};
+          Map<int, String> l2 = /*info:INFERRED_TYPE_LITERAL*/{(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
+          Map<int, String> l3 = /*info:INFERRED_TYPE_LITERAL*/{3: /*severe:STATIC_TYPE_ERROR*/3};
+          Map<int, String> l4 = /*info:INFERRED_TYPE_LITERAL*/{3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): /*severe:STATIC_TYPE_ERROR*/3};
         }
         {
           Map<dynamic, dynamic> l0 = {};
@@ -1381,18 +1426,18 @@
           Map<dynamic, dynamic> l4 = {3:"hello", "hello": 3};
         }
         {
-          Map<dynamic, String> l0 = /*$info*/{};
-          Map<dynamic, String> l1 = /*$info*/{3: "hello"};
-          Map<dynamic, String> l2 = /*$info*/{"hello": "hello"};
-          Map<dynamic, String> l3 = /*$info*/{3: /*severe:STATIC_TYPE_ERROR*/3};
-          Map<dynamic, String> l4 = /*$info*/{3:"hello", "hello": /*severe:STATIC_TYPE_ERROR*/3};
+          Map<dynamic, String> l0 = /*info:INFERRED_TYPE_LITERAL*/{};
+          Map<dynamic, String> l1 = /*info:INFERRED_TYPE_LITERAL*/{3: "hello"};
+          Map<dynamic, String> l2 = /*info:INFERRED_TYPE_LITERAL*/{"hello": "hello"};
+          Map<dynamic, String> l3 = /*info:INFERRED_TYPE_LITERAL*/{3: /*severe:STATIC_TYPE_ERROR*/3};
+          Map<dynamic, String> l4 = /*info:INFERRED_TYPE_LITERAL*/{3:"hello", "hello": /*severe:STATIC_TYPE_ERROR*/3};
         }
         {
-          Map<int, dynamic> l0 = /*$info*/{};
-          Map<int, dynamic> l1 = /*$info*/{3: "hello"};
-          Map<int, dynamic> l2 = /*$info*/{(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
-          Map<int, dynamic> l3 = /*$info*/{3: 3};
-          Map<int, dynamic> l4 = /*$info*/{3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): 3};
+          Map<int, dynamic> l0 = /*info:INFERRED_TYPE_LITERAL*/{};
+          Map<int, dynamic> l1 = /*info:INFERRED_TYPE_LITERAL*/{3: "hello"};
+          Map<int, dynamic> l2 = /*info:INFERRED_TYPE_LITERAL*/{(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
+          Map<int, dynamic> l3 = /*info:INFERRED_TYPE_LITERAL*/{3: 3};
+          Map<int, dynamic> l4 = /*info:INFERRED_TYPE_LITERAL*/{3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): 3};
         }
         {
           Map<int, String> l0 = /*severe:STATIC_TYPE_ERROR*/<num, dynamic>{};
@@ -1400,19 +1445,19 @@
           Map<int, String> l3 = /*severe:STATIC_TYPE_ERROR*/<num, dynamic>{3: 3};
         }
         {
-          const Map<int, String> l0 = /*$info*/const {};
-          const Map<int, String> l1 = /*$info*/const {3: "hello"};
-          const Map<int, String> l2 = /*$info*/const {(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
-          const Map<int, String> l3 = /*$info*/const {3: /*severe:STATIC_TYPE_ERROR*/3};
-          const Map<int, String> l4 = /*$info*/const {3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): /*severe:STATIC_TYPE_ERROR*/3};
+          const Map<int, String> l0 = /*info:INFERRED_TYPE_LITERAL*/const {};
+          const Map<int, String> l1 = /*info:INFERRED_TYPE_LITERAL*/const {3: "hello"};
+          const Map<int, String> l2 = /*info:INFERRED_TYPE_LITERAL*/const {(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
+          const Map<int, String> l3 = /*info:INFERRED_TYPE_LITERAL*/const {3: /*severe:STATIC_TYPE_ERROR*/3};
+          const Map<int, String> l4 = /*info:INFERRED_TYPE_LITERAL*/const {3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): /*severe:STATIC_TYPE_ERROR*/3};
         }
       }
-      ''';
-    testChecker('infer downwards', {'/main.dart': code});
+      ''');
+    });
   });
 
-  testChecker('downwards inference on function expressions', {
-    '/main.dart': '''
+  test('downwards inference on function expressions', () {
+    checkFile('''
       typedef T Function2<S, T>(S x);
 
       void main () {
@@ -1445,11 +1490,80 @@
           Function2<String, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(x) => x.substring(3);
         }
       }
-      '''
+      ''');
   });
 
-  testChecker('downwards inference initializing formal, default formal', {
-    '/main.dart': '''
+  test('downwards inference on generic function expressions', () {
+    checkFile('''
+      void main () {
+        {
+          String f/*<S>*/(int x) => null;
+          var v = f;
+          v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(int x) => null;
+          v = /*<T>*/(int x) => "hello";
+          v = /*severe:STATIC_TYPE_ERROR*//*<T>*/(String x) => "hello";
+          v = /*severe:STATIC_TYPE_ERROR*//*<T>*/(int x) => 3;
+          v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(int x) {return /*severe:STATIC_TYPE_ERROR*/3;};
+        }
+        {
+          String f/*<S>*/(int x) => null;
+          var v = f;
+          v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) => null;
+          v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) => "hello";
+          v = /*info:INFERRED_TYPE_CLOSURE, severe:STATIC_TYPE_ERROR*//*<T>*/(x) => 3;
+          v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) {return /*severe:STATIC_TYPE_ERROR*/3;};
+          v = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) {return /*severe:STATIC_TYPE_ERROR*/x;};
+        }
+        {
+          List<String> f/*<S>*/(int x) => null;
+          var v = f;
+          v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(int x) => null;
+          v = /*<T>*/(int x) => /*info:INFERRED_TYPE_LITERAL*/["hello"];
+          v = /*severe:STATIC_TYPE_ERROR*//*<T>*/(String x) => /*info:INFERRED_TYPE_LITERAL*/["hello"];
+          v = /*<T>*/(int x) => /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3];
+          v = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(int x) {return /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3];};
+        }
+        {
+          int int2int/*<S>*/(int x) => null;
+          String int2String/*<T>*/(int x) => null;
+          String string2String/*<T>*/(String x) => null;
+          var x = int2int;
+          x = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) => x;
+          x = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) => x+1;
+          var y = int2String;
+          y = /*info:INFERRED_TYPE_CLOSURE, severe:STATIC_TYPE_ERROR*//*<T>*/(x) => x;
+          y = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) => /*info:DYNAMIC_INVOKE, info:DYNAMIC_CAST*/x.substring(3);
+          var z = string2String;
+          z = /*info:INFERRED_TYPE_CLOSURE*//*<T>*/(x) => x.substring(3);
+        }
+      }
+      ''');
+  });
+
+  test('downwards inference on function<T> using the T', () {
+    checkFile('''
+      void main () {
+        {
+          /*=T*/ f/*<T>*/(/*=T*/ x) => null;
+          var v1 = f;
+          v1 = /*info:INFERRED_TYPE_CLOSURE*//*<S>*/(x) => x;
+        }
+        {
+          /*=List<T>*/ f/*<T>*/(/*=T*/ x) => null;
+          var v2 = f;
+          v2 = /*info:INFERRED_TYPE_CLOSURE*//*<S>*/(x) => /*info:INFERRED_TYPE_LITERAL*/[x];
+          Iterable<int> r = v2(42);
+          Iterable<String> s = v2('hello');
+          Iterable<List<int>> t = v2(<int>[]);
+          Iterable<num> u = v2(42);
+          Iterable<num> v = v2/*<num>*/(42);
+        }
+      }
+    ''');
+  });
+
+  test('downwards inference initializing formal, default formal', () {
+    checkFile('''
       typedef T Function2<S, T>([S x]);
       class Foo {
         List<int> x;
@@ -1457,34 +1571,36 @@
         Foo.named([List<int> x = /*info:INFERRED_TYPE_LITERAL*/const [1]]);
       }
       void f([List<int> l = /*info:INFERRED_TYPE_LITERAL*/const [1]]) {}
-// We do this inference in an early task but don't preserve the infos.
+      // We do this inference in an early task but don't preserve the infos.
       Function2<List<int>, String> g = /*pass should be info:INFERRED_TYPE_CLOSURE*/([llll = /*info:INFERRED_TYPE_LITERAL*/const [1]]) => "hello";
-'''
+    ''');
   });
 
-  testChecker('downwards inference async/await', {
-    '/main.dart': '''
+  test('downwards inference async/await', () {
+    checkFile('''
       import 'dart:async';
       Future<int> test() async {
-        List<int> l0 = /*warning:DOWN_CAST_COMPOSITE should be pass*/await /*pass should be info:INFERRED_TYPE_LITERAL*/[3];
-        List<int> l1 = await /*info:INFERRED_TYPE_ALLOCATION*/new Future.value(/*info:INFERRED_TYPE_LITERAL*/[3]);
-        '''
+        dynamic d;
+        List<int> l0 = /*warning:DOWN_CAST_COMPOSITE should be pass*/await /*pass should be info:INFERRED_TYPE_LITERAL*/[d];
+        List<int> l1 = await /*info:INFERRED_TYPE_ALLOCATION*/new Future.value(/*info:INFERRED_TYPE_LITERAL*/[/*info:DYNAMIC_CAST*/d]);
+      }
+    ''');
   });
 
-  testChecker('downwards inference foreach', {
-    '/main.dart': '''
+  test('downwards inference foreach', () {
+    checkFile('''
       import 'dart:async';
-      void main() {
+      Future main() async {
         for(int x in /*info:INFERRED_TYPE_LITERAL*/[1, 2, 3]) {
         }
         await for(int x in /*info:INFERRED_TYPE_ALLOCATION*/new Stream()) {
         }
       }
-        '''
+    ''');
   });
 
-  testChecker('downwards inference yield/yield*', {
-    '/main.dart': '''
+  test('downwards inference yield/yield*', () {
+    checkFile('''
       import 'dart:async';
         Stream<List<int>> foo() async* {
           yield /*info:INFERRED_TYPE_LITERAL*/[];
@@ -1499,11 +1615,11 @@
           yield* /*severe:STATIC_TYPE_ERROR*/{};
           yield* /*info:INFERRED_TYPE_ALLOCATION*/new List();
         }
-        '''
+        ''');
   });
 
-  testChecker('downwards inference, annotations', {
-    '/main.dart': '''
+  test('downwards inference, annotations', () {
+    checkFile('''
         class Foo {
           const Foo(List<String> l);
           const Foo.named(List<String> l);
@@ -1512,30 +1628,30 @@
         class Bar {}
         @Foo.named(/*info:INFERRED_TYPE_LITERAL*/const [])
         class Baz {}
-        '''
+        ''');
   });
 
-  testChecker('downwards inference, assignment statements', {
-    '/main.dart': '''
+  test('downwards inference, assignment statements', () {
+    checkFile('''
     void main() {
       List<int> l;
       l = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
       l = (l = /*info:INFERRED_TYPE_LITERAL*/[1]);
     }
-'''
+''');
   });
 
-  testChecker('inferred initializing formal checks default value', {
-    '/main.dart': '''
+  test('inferred initializing formal checks default value', () {
+    checkFile('''
       class Foo {
         var x = 1;
         Foo([this.x = /*severe:STATIC_TYPE_ERROR*/"1"]);
-      }'''
+      }''');
   });
 
   group('generic methods', () {
-    testChecker('dart:math min/max', {
-      '/main.dart': '''
+    test('dart:math min/max', () {
+      checkFile('''
         import 'dart:math';
 
         void printInt(int x) => print(x);
@@ -1566,11 +1682,11 @@
                   /*severe:STATIC_TYPE_ERROR*/"hi",
                   /*severe:STATIC_TYPE_ERROR*/"there"));
         }
-    '''
+    ''');
     });
 
-    testChecker('Iterable and Future', {
-      '/main.dart': '''
+    test('Iterable and Future', () {
+      checkFile('''
         import 'dart:async';
 
         Future<int> make(int x) => (/*info:INFERRED_TYPE_ALLOCATION*/new Future(() => x));
@@ -1578,10 +1694,501 @@
         main() {
           Iterable<Future<int>> list = <int>[1, 2, 3].map(make);
           Future<List<int>> results = Future.wait(list);
-          Future<String> results2 = results.then((List<int> list) 
-            => list.fold('', (String x, int y) => x + y.toString()));
+          Future<String> results2 = results.then((List<int> list)
+            => list.fold('', /*info:INFERRED_TYPE_CLOSURE*/(x, y) => x + y.toString()));
         }
-    '''
+    ''');
+    });
+
+    // TODO(jmesserly): we should change how this inference works.
+    // For now this test will cover what we use.
+    test('infer JS builtin', () {
+      checkFile('''
+        import 'dart:_foreign_helper' show JS;
+        main() {
+          String x = /*severe:STATIC_TYPE_ERROR*/JS('int', '42');
+          var y = JS('String', '"hello"');
+          y = "world";
+          y = /*severe:STATIC_TYPE_ERROR*/42;
+        }
+    ''');
+    });
+
+
+    test('inferred generic instantiation', () {
+      checkFile('''
+import 'dart:math' as math;
+import 'dart:math' show min;
+
+class C {
+  /*=T*/ m/*<T extends num>*/(/*=T*/ x, /*=T*/ y) => null;
+}
+
+main() {
+  takeIII(math.max);
+  takeDDD(math.max);
+  takeNNN(math.max);
+  takeIDN(math.max);
+  takeDIN(math.max);
+  takeIIN(math.max);
+  takeDDN(math.max);
+  takeIIO(math.max);
+  takeDDO(math.max);
+
+  takeOOI(/*severe:STATIC_TYPE_ERROR*/math.max);
+  takeIDI(/*severe:STATIC_TYPE_ERROR*/math.max);
+  takeDID(/*severe:STATIC_TYPE_ERROR*/math.max);
+  takeOON(/*severe:STATIC_TYPE_ERROR*/math.max);
+  takeOOO(/*severe:STATIC_TYPE_ERROR*/math.max);
+
+  // Also test SimpleIdentifier
+  takeIII(min);
+  takeDDD(min);
+  takeNNN(min);
+  takeIDN(min);
+  takeDIN(min);
+  takeIIN(min);
+  takeDDN(min);
+  takeIIO(min);
+  takeDDO(min);
+
+  takeOOI(/*severe:STATIC_TYPE_ERROR*/min);
+  takeIDI(/*severe:STATIC_TYPE_ERROR*/min);
+  takeDID(/*severe:STATIC_TYPE_ERROR*/min);
+  takeOON(/*severe:STATIC_TYPE_ERROR*/min);
+  takeOOO(/*severe:STATIC_TYPE_ERROR*/min);
+
+  // Also PropertyAccess
+  takeIII(new C().m);
+  takeDDD(new C().m);
+  takeNNN(new C().m);
+  takeIDN(new C().m);
+  takeDIN(new C().m);
+  takeIIN(new C().m);
+  takeDDN(new C().m);
+  takeIIO(new C().m);
+  takeDDO(new C().m);
+
+  // Note: this is a warning because a downcast of a method tear-off could work
+  // (derived method can be a subtype):
+  //
+  //     class D extends C {
+  //       S m<S extends num>(Object x, Object y);
+  //     }
+  //
+  // That's legal because we're loosening parameter types.
+  //
+  takeOON(/*warning:DOWN_CAST_COMPOSITE*/new C().m);
+  takeOOO(/*warning:DOWN_CAST_COMPOSITE*/new C().m);
+
+  // Note: this is a warning because a downcast of a method tear-off could work
+  // in "normal" Dart, due to bivariance.
+  takeOOI(/*warning:DOWN_CAST_COMPOSITE*/new C().m);
+  takeIDI(/*warning:DOWN_CAST_COMPOSITE*/new C().m);
+  takeDID(/*warning:DOWN_CAST_COMPOSITE*/new C().m);
+}
+
+void takeIII(int fn(int a, int b)) {}
+void takeDDD(double fn(double a, double b)) {}
+void takeIDI(int fn(double a, int b)) {}
+void takeDID(double fn(int a, double b)) {}
+void takeIDN(num fn(double a, int b)) {}
+void takeDIN(num fn(int a, double b)) {}
+void takeIIN(num fn(int a, int b)) {}
+void takeDDN(num fn(double a, double b)) {}
+void takeNNN(num fn(num a, num b)) {}
+void takeOON(num fn(Object a, Object b)) {}
+void takeOOO(num fn(Object a, Object b)) {}
+void takeOOI(int fn(Object a, Object b)) {}
+void takeIIO(Object fn(int a, int b)) {}
+void takeDDO(Object fn(double a, double b)) {}
+  ''');
+    });
+
+    // Regression test for https://github.com/dart-lang/sdk/issues/25668
+    test('infer generic method type', () {
+      checkFile('''
+class C {
+  /*=T*/ m/*<T>*/(/*=T*/ x) => x;
+}
+class D extends C {
+  m/*<S>*/(x) => x;
+}
+main() {
+  int y = new D().m/*<int>*/(42);
+  print(y);
+}
+    ''');
+    });
+
+    test('do not infer invalid override of generic method', () {
+      checkFile('''
+class C {
+  /*=T*/ m/*<T>*/(/*=T*/ x) => x;
+}
+class D extends C {
+  /*severe:INVALID_METHOD_OVERRIDE*/m(x) => x;
+}
+main() {
+  int y = /*info:DYNAMIC_CAST*/new D()./*warning:WRONG_NUMBER_OF_TYPE_ARGUMENTS*/m/*<int>*/(42);
+  print(y);
+}
+    ''');
+    });
+
+    test('correctly recognize generic upper bound', () {
+      // Regression test for https://github.com/dart-lang/sdk/issues/25740.
+      checkFile(r'''
+class Foo<T extends Pattern> {
+  void method/*<U extends T>*/(dynamic/*=U*/ u) {}
+}
+main() {
+  new Foo().method/*<String>*/("str");
+  new Foo();
+
+  new Foo<String>().method("str");
+  new Foo().method("str");
+
+  new Foo<String>().method(/*severe:STATIC_TYPE_ERROR*/42);
+}
+      ''');
+    });
+
+    test('basic downwards inference', () {
+      checkFile(r'''
+/*=T*/ f/*<S, T>*/(/*=S*/ s) => null;
+main() {
+  String x = f(42);
+  String y = (f)(42);
+}
+      ''');
+    });
+
+    test('downwards inference affects arguments', () {
+      checkFile(r'''
+/*=T*/ f/*<T>*/(List/*<T>*/ s) => null;
+main() {
+  String x = f(/*info:INFERRED_TYPE_LITERAL*/['hi']);
+  String y = f(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/42]);
+}
+      ''');
+    });
+
+    test('downwards inference fold', () {
+      // Regression from https://github.com/dart-lang/sdk/issues/25491
+      // The first example works now, but the latter requires a full solution to
+      // https://github.com/dart-lang/sdk/issues/25490
+      checkFile(r'''
+void main() {
+  List<int> o;
+  int y = o.fold(0, /*info:INFERRED_TYPE_CLOSURE*/(x, y) => x + y);
+  var z = o.fold(0, /*info:INFERRED_TYPE_CLOSURE*/(x, y) => /*info:DYNAMIC_INVOKE*/x + y);
+  y = /*info:DYNAMIC_CAST*/z;
+}
+void functionExpressionInvocation() {
+  List<int> o;
+  int y = (o.fold)(0, /*info:INFERRED_TYPE_CLOSURE*/(x, y) => x + y);
+  var z = (o.fold)(0, /*info:INFERRED_TYPE_CLOSURE*/(x, y) => /*info:DYNAMIC_INVOKE*/x + y);
+  y = /*info:DYNAMIC_CAST*/z;
+}
+      ''');
+    });
+
+  });
+
+  // Regression test for https://github.com/dart-lang/dev_compiler/issues/47
+  test('null literal should not infer as bottom', () {
+    checkFile(r'''
+      var h = null;
+      void foo(int f(Object _)) {}
+
+      main() {
+        var f = (Object x) => null;
+        String y = /*info:DYNAMIC_CAST*/f(42);
+
+        f = /*info:INFERRED_TYPE_CLOSURE*/(x) => 'hello';
+
+        var g = null;
+        g = 'hello';
+        (/*info:DYNAMIC_INVOKE*/g.foo());
+
+        h = 'hello';
+        (/*info:DYNAMIC_INVOKE*/h.foo());
+
+        foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) => null);
+        foo(/*info:INFERRED_TYPE_CLOSURE,info:INFERRED_TYPE_CLOSURE*/(x) => throw "not implemented");
+      }
+  ''');
+  });
+
+  test('list literals', () {
+    checkFile(r'''
+test1() {
+  var x = [1, 2, 3];
+  x.add(/*severe:STATIC_TYPE_ERROR*/'hi');
+  x.add(/*severe:STATIC_TYPE_ERROR*/4.0);
+  x.add(4);
+  List<num> y = x;
+}
+test2() {
+  var x = [1, 2.0, 3];
+  x.add(/*severe:STATIC_TYPE_ERROR*/'hi');
+  x.add(4.0);
+  List<int> y = /*info:ASSIGNMENT_CAST*/x;
+}
+    ''');
+  });
+
+  test('map literals', () {
+    checkFile(r'''
+test1() {
+  var x = { 1: 'x', 2: 'y' };
+  x[3] = 'z';
+  x[/*severe:STATIC_TYPE_ERROR*/'hi'] = 'w';
+  x[/*severe:STATIC_TYPE_ERROR*/4.0] = 'u';
+  x[3] = /*severe:STATIC_TYPE_ERROR*/42;
+  Map<num, String> y = x;
+}
+
+test2() {
+  var x = { 1: 'x', 2: 'y', 3.0: new RegExp('.') };
+  x[3] = 'z';
+  x[/*severe:STATIC_TYPE_ERROR*/'hi'] = 'w';
+  x[4.0] = 'u';
+  x[3] = /*severe:STATIC_TYPE_ERROR*/42;
+  Pattern p = null;
+  x[2] = p;
+  Map<int, String> y = /*info:ASSIGNMENT_CAST*/x;
+}
+    ''');
+  });
+
+
+  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 0141e38..e04fb30 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -6,135 +6,112 @@
 // package:dev_compiler's tests
 library analyzer.test.src.task.strong.strong_test_helper;
 
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer/src/context/context.dart' show SdkAnalysisContext;
-import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/type_system.dart';
-import 'package:analyzer/src/task/strong/checker.dart';
 import 'package:logging/logging.dart';
 import 'package:source_span/source_span.dart';
 import 'package:unittest/unittest.dart';
 
-const String GREEN_COLOR = '\u001b[32m';
+import '../../context/mock_sdk.dart';
 
-const String NO_COLOR = '\u001b[0m';
+MemoryResourceProvider files;
+bool _checkCalled;
 
-const String _CYAN_COLOR = '\u001b[36m';
-
-const String _MAGENTA_COLOR = '\u001b[35m';
-
-const String _RED_COLOR = '\u001b[31m';
-
-/// Sample mock SDK sources.
-final Map<String, String> mockSdkSources = {
-  // The list of types below is derived from:
-  //   * types we use via our smoke queries, including HtmlElement and
-  //     types from `_typeHandlers` (deserialize.dart)
-  //   * types that are used internally by the resolver (see
-  //   _initializeFrom in resolver.dart).
-  'dart:core': '''
-        library dart.core;
-
-        void print(Object o) {}
-
-        class Object {
-          int get hashCode {}
-          Type get runtimeType {}
-          String toString(){}
-          bool ==(other){}
-        }
-        class Function {}
-        class StackTrace {}
-        class Symbol {}
-        class Type {}
-
-        class String {
-          String operator +(String other) {}
-          String substring(int len) {}
-        }
-        class bool {}
-        class num {
-          num operator +(num other) {}
-        }
-        class int extends num {
-          bool operator<(num other) {}
-          int operator-() {}
-        }
-        class double extends num {}
-        class DateTime {}
-        class Null {}
-
-        class Deprecated {
-          final String expires;
-          const Deprecated(this.expires);
-        }
-        const Object deprecated = const Deprecated("next release");
-        class _Override { const _Override(); }
-        const Object override = const _Override();
-        class _Proxy { const _Proxy(); }
-        const Object proxy = const _Proxy();
-
-        class Iterable<E> {
-          Iterable/*<R>*/ map/*<R>*/(/*=R*/ f(E e));
-
-          /*=R*/ fold/*<R>*/(/*=R*/ initialValue,
-              /*=R*/ combine(/*=R*/ previousValue, E element));
-        }
-        class List<E> implements Iterable<E> {
-          List([int length]);
-          List.filled(int length, E fill);
-        }
-        class Map<K, V> {
-          Iterable<K> get keys {}
-        }
-        ''',
-  'dart:async': '''
-        class Future<T> {
-          Future(computation()) {}
-          Future.value(T t) {}
-          static Future<List/*<T>*/> wait/*<T>*/(
-              Iterable<Future/*<T>*/> futures) => null;
-          Future/*<R>*/ then/*<R>*/(/*=R*/ onValue(T value)) => null;
-        }
-        class Stream<T> {}
-  ''',
-  'dart:html': '''
-        library dart.html;
-        class HtmlElement {}
-        ''',
-  'dart:math': '''
-        library dart.math;
-        class Random {
-          bool nextBool() {}
-        }
-        num/*=T*/ min/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
-        num/*=T*/ max/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
-        ''',
-};
-
-/// Returns an ANSII color escape sequence corresponding to [levelName]. Colors
-/// are defined for: severe, error, warning, or info. Returns null if the level
-/// name is not recognized.
-String colorOf(String levelName) {
-  levelName = levelName.toLowerCase();
-  if (levelName == 'shout' || levelName == 'severe' || levelName == 'error') {
-    return _RED_COLOR;
-  }
-  if (levelName == 'warning') return _MAGENTA_COLOR;
-  if (levelName == 'info') return _CYAN_COLOR;
-  return null;
+/// Adds a file to check. The file should contain:
+///
+///   * all expected failures are listed in the source code using comments
+///     immediately in front of the AST node that should contain the error.
+///
+///   * errors are formatted as a token `level:Type`, where `level` is the
+///     logging level were the error would be reported at, and `Type` is the
+///     concrete subclass of [StaticInfo] that denotes the error.
+///
+/// For example to check that an assignment produces a type error, you can
+/// create a file like:
+///
+///     addFile('''
+///       String x = /*severe:STATIC_TYPE_ERROR*/3;
+///     ''');
+///     check();
+///
+/// For a single file, you may also use [checkFile].
+void addFile(String content, {String name: '/main.dart'}) {
+  name = name.replaceFirst('^package:', '/packages/');
+  files.newFile(name, content);
 }
 
-SourceSpanWithContext createSpanHelper(
-    LineInfo lineInfo, int start, int end, Source source, String content) {
-  var startLoc = locationForOffset(lineInfo, source.uri, start);
-  var endLoc = locationForOffset(lineInfo, source.uri, end);
+/// Run the checker on a program, staring from '/main.dart', and verifies that
+/// errors/warnings/hints match the expected value.
+///
+/// See [addFile] for more information about how to encode expectations in
+/// the file text.
+///
+/// Returns the main resolved library. This can be used for further checks.
+CompilationUnit check() {
+  _checkCalled = true;
+
+  expect(files.getFile('/main.dart').exists, true,
+      reason: '`/main.dart` is missing');
+
+  var uriResolver = new _TestUriResolver(files);
+  // Enable task model strong mode
+  var context = AnalysisEngine.instance.createAnalysisContext();
+  context.analysisOptions.strongMode = true;
+  (context.analysisOptions as AnalysisOptionsImpl).strongModeHints = true;
+  context.sourceFactory =
+      new SourceFactory([new DartUriResolver(new MockSdk()), uriResolver]);
+
+  // Run the checker on /main.dart.
+  Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart'));
+  var initialLibrary = context.resolveCompilationUnit2(mainSource, mainSource);
+
+  var collector = new _ErrorCollector();
+
+  // Extract expectations from the comments in the test files, and
+  // check that all errors we emit are included in the expected map.
+  var allLibraries = _reachableLibraries(initialLibrary.element.library);
+  for (var lib in allLibraries) {
+    for (var unit in lib.units) {
+      var errors = <AnalysisError>[];
+      collector.errors = errors;
+
+      var source = unit.source;
+      if (source.uri.scheme == 'dart') continue;
+
+      var librarySource = context.getLibrariesContaining(source).single;
+      var resolved = context.resolveCompilationUnit2(source, librarySource);
+      errors.addAll(context.getErrors(source).errors.where((e) =>
+          e.errorCode != HintCode.UNUSED_LOCAL_VARIABLE &&
+          // TODO(jmesserly): these are usually intentional dynamic calls.
+          e.errorCode.name != 'UNDEFINED_METHOD'));
+
+      _expectErrors(resolved, errors);
+    }
+  }
+
+  return initialLibrary;
+}
+
+/// Adds a file using [addFile] and calls [check].
+///
+/// Also returns the resolved compilation unit.
+CompilationUnit checkFile(String content) {
+  addFile(content);
+  return check();
+}
+
+SourceSpanWithContext _createSpanHelper(
+    LineInfo lineInfo, int start, Source source, String content,
+    {int end}) {
+  var startLoc = _locationForOffset(lineInfo, source.uri, start);
+  var endLoc = _locationForOffset(lineInfo, source.uri, end ?? start);
 
   var lineStart = startLoc.offset - startLoc.column;
   // Find the end of the line. This is not exposed directly on LineInfo, but
@@ -146,32 +123,48 @@
   while (lineEnd < content.length &&
       lineInfo.getLocation(++lineEnd).lineNumber == lineNum);
 
+  if (end == null) {
+    end = lineEnd;
+    endLoc = _locationForOffset(lineInfo, source.uri, lineEnd);
+  }
+
   var text = content.substring(start, end);
   var lineText = content.substring(lineStart, lineEnd);
   return new SourceSpanWithContext(startLoc, endLoc, text, lineText);
 }
 
-String errorCodeName(ErrorCode errorCode) {
+String _errorCodeName(ErrorCode errorCode) {
   var name = errorCode.name;
   final prefix = 'STRONG_MODE_';
   if (name.startsWith(prefix)) {
     return name.substring(prefix.length);
   } else {
-    // TODO(jmesserly): this is for backwards compat, but not sure it's very
-    // useful to log this.
-    return 'AnalyzerMessage';
+    return name;
   }
 }
 
-// TODO(jmesserly): can we reuse the same mock SDK as Analyzer tests?
-SourceLocation locationForOffset(LineInfo lineInfo, Uri uri, int offset) {
+void initStrongModeTests() {
+  setUp(() {
+    AnalysisEngine.instance.processRequiredPlugins();
+    files = new MemoryResourceProvider();
+    _checkCalled = false;
+  });
+
+  tearDown(() {
+    // This is a sanity check, in case only addFile is called.
+    expect(_checkCalled, true, reason: 'must call check() method in test case');
+    files = null;
+  });
+}
+
+SourceLocation _locationForOffset(LineInfo lineInfo, Uri uri, int offset) {
   var loc = lineInfo.getLocation(offset);
   return new SourceLocation(offset,
       sourceUrl: uri, line: loc.lineNumber - 1, column: loc.columnNumber - 1);
 }
 
 /// Returns all libraries transitively imported or exported from [start].
-List<LibraryElement> reachableLibraries(LibraryElement start) {
+List<LibraryElement> _reachableLibraries(LibraryElement start) {
   var results = <LibraryElement>[];
   var seen = new Set();
   void find(LibraryElement lib) {
@@ -185,164 +178,143 @@
   return results;
 }
 
-/// Run the checker on a program with files contents as indicated in
-/// [testFiles].
-///
-/// This function makes several assumptions to make it easier to describe error
-/// expectations:
-///
-///   * a file named `/main.dart` exists in [testFiles].
-///   * all expected failures are listed in the source code using comments
-///   immediately in front of the AST node that should contain the error.
-///   * errors are formatted as a token `level:Type`, where `level` is the
-///   logging level were the error would be reported at, and `Type` is the
-///   concrete subclass of [StaticInfo] that denotes the error.
-///
-/// For example, to check that an assignment produces a warning about a boxing
-/// conversion, you can describe the test as follows:
-///
-///     testChecker({
-///       '/main.dart': '''
-///           testMethod() {
-///             dynamic x = /*warning:Box*/3;
-///           }
-///       '''
-///     });
-///
-void testChecker(String name, Map<String, String> testFiles) {
-  test(name, () {
-    AnalysisEngine.instance.processRequiredPlugins();
-    expect(testFiles.containsKey('/main.dart'), isTrue,
-        reason: '`/main.dart` is missing in testFiles');
+Level _actualErrorLevel(AnalysisError actual) {
+  return const <ErrorSeverity, Level>{
+    ErrorSeverity.ERROR: Level.SEVERE,
+    ErrorSeverity.WARNING: Level.WARNING,
+    ErrorSeverity.INFO: Level.INFO
+  }[actual.errorCode.errorSeverity];
+}
 
-    var provider = new MemoryResourceProvider();
-    testFiles.forEach((key, value) {
-      var scheme = 'package:';
-      if (key.startsWith(scheme)) {
-        key = '/packages/${key.substring(scheme.length)}';
-      }
-      provider.newFile(key, value);
-    });
-    var uriResolver = new TestUriResolver(provider);
-    // Enable task model strong mode
-    var context = AnalysisEngine.instance.createAnalysisContext();
-    context.analysisOptions.strongMode = true;
-    context.analysisOptions.strongModeHints = true;
+void _expectErrors(CompilationUnit unit, List<AnalysisError> actualErrors) {
+  var expectedErrors = _findExpectedErrors(unit.beginToken);
 
-    context.sourceFactory = new SourceFactory([
-      new MockDartSdk(mockSdkSources, reportMissing: true).resolver,
-      uriResolver
-    ]);
+  // Sort both lists: by offset, then level, then name.
+  actualErrors.sort((x, y) {
+    int delta = x.offset.compareTo(y.offset);
+    if (delta != 0) return delta;
 
-    // Run the checker on /main.dart.
-    Source mainSource = uriResolver.resolveAbsolute(new Uri.file('/main.dart'));
-    var initialLibrary =
-        context.resolveCompilationUnit2(mainSource, mainSource);
+    delta = x.errorCode.errorSeverity.compareTo(y.errorCode.errorSeverity);
+    if (delta != 0) return delta;
 
-    var collector = new _ErrorCollector();
-    var checker = new CodeChecker(
-        context.typeProvider, new StrongTypeSystemImpl(), collector,
-        hints: true);
-
-    // Extract expectations from the comments in the test files, and
-    // check that all errors we emit are included in the expected map.
-    var allLibraries = reachableLibraries(initialLibrary.element.library);
-    for (var lib in allLibraries) {
-      for (var unit in lib.units) {
-        var errors = <AnalysisError>[];
-        collector.errors = errors;
-
-        var source = unit.source;
-        if (source.uri.scheme == 'dart') continue;
-
-        var librarySource = context.getLibrariesContaining(source).single;
-        var resolved = context.resolveCompilationUnit2(source, librarySource);
-        var analyzerErrors = context
-            .getErrors(source)
-            .errors
-            .where((error) =>
-                error.errorCode.name.startsWith('STRONG_MODE_INFERRED_TYPE'))
-            .toList();
-        errors.addAll(analyzerErrors);
-        checker.visitCompilationUnit(resolved);
-
-        new _ExpectedErrorVisitor(errors).validate(resolved);
-      }
-    }
+    return _errorCodeName(x.errorCode).compareTo(_errorCodeName(y.errorCode));
   });
+  expectedErrors.sort((x, y) {
+    int delta = x.offset.compareTo(y.offset);
+    if (delta != 0) return delta;
+
+    delta = x.level.compareTo(y.level);
+    if (delta != 0) return delta;
+
+    return x.typeName.compareTo(y.typeName);
+  });
+
+  // Categorize the differences, if any.
+  var unreported = <_ErrorExpectation>[];
+  var different = <_ErrorExpectation, AnalysisError>{};
+
+  for (var expected in expectedErrors) {
+    AnalysisError actual = expected._removeMatchingActual(actualErrors);
+    if (actual != null) {
+      if (_actualErrorLevel(actual) != expected.level ||
+          _errorCodeName(actual.errorCode) != expected.typeName) {
+        different[expected] = actual;
+      }
+    } else {
+      unreported.add(expected);
+    }
+  }
+
+  // Whatever is left was an unexpected error.
+  List<AnalysisError> unexpected = actualErrors;
+
+  if (unreported.isNotEmpty || unexpected.isNotEmpty || different.isNotEmpty) {
+    _reportFailure(unit, unreported, unexpected, different);
+  }
 }
 
-/// Dart SDK which contains a mock implementation of the SDK libraries. May be
-/// used to speed up execution when most of the core libraries is not needed.
-class MockDartSdk implements DartSdk {
-  final Map<Uri, _MockSdkSource> _sources = {};
-  final bool reportMissing;
-  final Map<String, SdkLibrary> _libs = {};
-  final String sdkVersion = '0';
-  final AnalysisContext context = new SdkAnalysisContext();
-  DartUriResolver _resolver;
-  MockDartSdk(Map<String, String> sources, {this.reportMissing}) {
-    sources.forEach((uriString, contents) {
-      var uri = Uri.parse(uriString);
-      _sources[uri] = new _MockSdkSource(uri, contents);
-      _libs[uriString] = new SdkLibraryImpl(uri.path)
-        ..setDart2JsLibrary()
-        ..setVmLibrary();
+List<_ErrorExpectation> _findExpectedErrors(Token beginToken) {
+  var expectedErrors = <_ErrorExpectation>[];
+
+  // Collect expectations like "severe:STATIC_TYPE_ERROR" from comment tokens.
+  for (Token t = beginToken; t.type != TokenType.EOF; t = t.next) {
+    for (CommentToken c = t.precedingComments; c != null; c = c.next) {
+      if (c.type == TokenType.MULTI_LINE_COMMENT) {
+        String value = c.lexeme.substring(2, c.lexeme.length - 2);
+        if (value.contains(':')) {
+          int offset = t.offset;
+          Token previous = t.previous;
+          while (previous != null && previous.offset > c.offset) {
+            offset = previous.offset;
+            previous = previous.previous;
+          }
+          for (var expectCode in value.split(',')) {
+            var expected = _ErrorExpectation.parse(offset, expectCode);
+            if (expected != null) {
+              expectedErrors.add(expected);
+            }
+          }
+        }
+      }
+    }
+  }
+  return expectedErrors;
+}
+
+void _reportFailure(
+    CompilationUnit unit,
+    List<_ErrorExpectation> unreported,
+    List<AnalysisError> unexpected,
+    Map<_ErrorExpectation, AnalysisError> different) {
+  // Get the source code. This reads the data again, but it's safe because
+  // all tests use memory file system.
+  var sourceCode = unit.element.source.contents.data;
+
+  String formatActualError(AnalysisError error) {
+    int offset = error.offset;
+    int length = error.length;
+    var span = _createSpanHelper(
+        unit.lineInfo, offset, unit.element.source, sourceCode,
+        end: offset + length);
+    var levelName = _actualErrorLevel(error).name.toLowerCase();
+    return '@$offset $levelName:${_errorCodeName(error.errorCode)}\n' +
+        span.message(error.message);
+  }
+
+  String formatExpectedError(_ErrorExpectation error) {
+    int offset = error.offset;
+    var span = _createSpanHelper(
+        unit.lineInfo, offset, unit.element.source, sourceCode);
+    var levelName = error.level.toString().toLowerCase();
+    return '@$offset $levelName:${error.typeName}\n' + span.message('');
+  }
+
+  var message = new StringBuffer();
+  if (unreported.isNotEmpty) {
+    message.writeln('Expected errors that were not reported:');
+    unreported.map(formatExpectedError).forEach(message.writeln);
+    message.writeln();
+  }
+  if (unexpected.isNotEmpty) {
+    message.writeln('Errors that were not expected:');
+    unexpected.map(formatActualError).forEach(message.writeln);
+    message.writeln();
+  }
+  if (different.isNotEmpty) {
+    message.writeln('Errors that were reported, but different than expected:');
+    different.forEach((expected, actual) {
+      message.writeln('Expected: ' + formatExpectedError(expected));
+      message.writeln('Actual: ' + formatActualError(actual));
     });
-    _resolver = new DartUriResolver(this);
-    context.sourceFactory = new SourceFactory([_resolver]);
+    message.writeln();
   }
-  DartUriResolver get resolver => _resolver;
-
-  List<SdkLibrary> get sdkLibraries => _libs.values.toList();
-
-  List<String> get uris => _sources.keys.map((uri) => '$uri').toList();
-  Source fromEncoding(UriKind kind, Uri uri) {
-    if (kind != UriKind.DART_URI) {
-      throw new UnsupportedError('expected dart: uri kind, got $kind.');
-    }
-    return _getSource(uri);
-  }
-
-  @override
-  Source fromFileUri(Uri uri) {
-    throw new UnsupportedError('MockDartSdk.fromFileUri');
-  }
-
-  SdkLibrary getSdkLibrary(String dartUri) => _libs[dartUri];
-
-  Source mapDartUri(String dartUri) => _getSource(Uri.parse(dartUri));
-
-  Source _getSource(Uri uri) {
-    var src = _sources[uri];
-    if (src == null) {
-      if (reportMissing) print('warning: missing mock for $uri.');
-      _sources[uri] =
-          src = new _MockSdkSource(uri, 'library dart.${uri.path};');
-    }
-    return src;
-  }
-}
-
-class TestUriResolver extends ResourceUriResolver {
-  final MemoryResourceProvider provider;
-  TestUriResolver(provider)
-      : provider = provider,
-        super(provider);
-
-  @override
-  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
-    if (uri.scheme == 'package') {
-      return (provider.getResource('/packages/' + uri.path) as File)
-          .createSource(uri);
-    }
-    return super.resolveAbsolute(uri, actualUri);
-  }
+  fail('Checker errors do not match expected errors:\n\n$message');
 }
 
 class _ErrorCollector implements AnalysisErrorListener {
   List<AnalysisError> errors;
   final bool hints;
+
   _ErrorCollector({this.hints: true});
 
   void onError(AnalysisError error) {
@@ -356,26 +328,39 @@
 
 /// Describes an expected message that should be produced by the checker.
 class _ErrorExpectation {
+  final int offset;
   final Level level;
   final String typeName;
-  _ErrorExpectation(this.level, this.typeName);
 
-  String toString() => '$level $typeName';
+  _ErrorExpectation(this.offset, this.level, this.typeName);
 
-  static _ErrorExpectation parse(String descriptor) {
+  String toString() =>
+      '@$offset ${level.toString().toLowerCase()}: [$typeName]';
+
+  AnalysisError _removeMatchingActual(List<AnalysisError> actualErrors) {
+    for (var actual in actualErrors) {
+      if (actual.offset == offset) {
+        actualErrors.remove(actual);
+        return actual;
+      }
+    }
+    return null;
+  }
+
+  static _ErrorExpectation parse(int offset, String descriptor) {
     descriptor = descriptor.trim();
     var tokens = descriptor.split(' ');
-    if (tokens.length == 1) return _parse(tokens[0]);
+    if (tokens.length == 1) return _parse(offset, tokens[0]);
     expect(tokens.length, 4, reason: 'invalid error descriptor');
     expect(tokens[1], "should", reason: 'invalid error descriptor');
     expect(tokens[2], "be", reason: 'invalid error descriptor');
     if (tokens[0] == "pass") return null;
     // TODO(leafp) For now, we just use whatever the current expectation is,
     // eventually we could do more automated reporting here.
-    return _parse(tokens[0]);
+    return _parse(offset, tokens[0]);
   }
 
-  static _ErrorExpectation _parse(String descriptor) {
+  static _ErrorExpectation _parse(offset, String descriptor) {
     var tokens = descriptor.split(':');
     expect(tokens.length, 2, reason: 'invalid error descriptor');
     var name = tokens[0].toUpperCase();
@@ -387,137 +372,22 @@
         reason: 'invalid level in error descriptor: `${tokens[0]}`');
     expect(typeName, isNotNull,
         reason: 'invalid type in error descriptor: ${tokens[1]}');
-    return new _ErrorExpectation(level, typeName);
+    return new _ErrorExpectation(offset, level, typeName);
   }
 }
 
-class _ExpectedErrorVisitor extends UnifyingAstVisitor {
-  final Set<AnalysisError> _actualErrors;
-  CompilationUnit _unit;
-  String _unitSourceCode;
+class _TestUriResolver extends ResourceUriResolver {
+  final MemoryResourceProvider provider;
+  _TestUriResolver(provider)
+      : provider = provider,
+        super(provider);
 
-  _ExpectedErrorVisitor(List<AnalysisError> actualErrors)
-      : _actualErrors = new Set.from(actualErrors);
-
-  validate(CompilationUnit unit) {
-    _unit = unit;
-    // This reads the file. Only safe because tests use MemoryFileSystem.
-    _unitSourceCode = unit.element.source.contents.data;
-
-    // Visit the compilation unit.
-    unit.accept(this);
-
-    if (_actualErrors.isNotEmpty) {
-      var actualMsgs = _actualErrors.map(_formatActualError).join('\n');
-      fail('Unexpected errors reported by checker:\n\n$actualMsgs');
+  @override
+  Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+    if (uri.scheme == 'package') {
+      return (provider.getResource('/packages/' + uri.path) as File)
+          .createSource(uri);
     }
+    return super.resolveAbsolute(uri, actualUri);
   }
-
-  visitNode(AstNode node) {
-    var token = node.beginToken;
-    var comment = token.precedingComments;
-    // Use error marker found in an immediately preceding comment,
-    // and attach it to the outermost expression that starts at that token.
-    if (comment != null) {
-      while (comment.next != null) {
-        comment = comment.next;
-      }
-      if (comment.end == token.offset && node.parent.beginToken != token) {
-        var commentText = '$comment';
-        var start = commentText.lastIndexOf('/*');
-        var end = commentText.lastIndexOf('*/');
-        if (start != -1 &&
-            end != -1 &&
-            !commentText.startsWith('/*<', start) &&
-            !commentText.startsWith('/*=', start)) {
-          expect(start, lessThan(end));
-          var errors = commentText.substring(start + 2, end).split(',');
-          var expectations =
-              errors.map(_ErrorExpectation.parse).where((x) => x != null);
-
-          for (var e in expectations) {
-            _expectError(node, e);
-          }
-        }
-      }
-    }
-    return super.visitNode(node);
-  }
-
-  Level _actualErrorLevel(AnalysisError actual) {
-    return const <ErrorSeverity, Level>{
-      ErrorSeverity.ERROR: Level.SEVERE,
-      ErrorSeverity.WARNING: Level.WARNING,
-      ErrorSeverity.INFO: Level.INFO
-    }[actual.errorCode.errorSeverity];
-  }
-
-  SourceSpan _createSpan(int offset, int len) {
-    return createSpanHelper(_unit.lineInfo, offset, offset + len,
-        _unit.element.source, _unitSourceCode);
-  }
-
-  void _expectError(AstNode node, _ErrorExpectation expected) {
-    // See if we can find the expected error in our actual errors
-    for (var actual in _actualErrors) {
-      if (actual.offset == node.offset && actual.length == node.length) {
-        var actualMsg = _formatActualError(actual);
-        expect(_actualErrorLevel(actual), expected.level,
-            reason: 'expected different error code at:\n\n$actualMsg');
-        expect(errorCodeName(actual.errorCode), expected.typeName,
-            reason: 'expected different error type at:\n\n$actualMsg');
-
-        // We found it. Stop the search.
-        _actualErrors.remove(actual);
-        return;
-      }
-    }
-
-    var span = _createSpan(node.offset, node.length);
-    var levelName = expected.level.name.toLowerCase();
-    var msg = span.message(expected.typeName, color: colorOf(levelName));
-    fail('expected error was not reported at:\n\n$levelName: $msg');
-  }
-
-  String _formatActualError(AnalysisError actual) {
-    var span = _createSpan(actual.offset, actual.length);
-    var levelName = _actualErrorLevel(actual).name.toLowerCase();
-    var msg = span.message(actual.message, color: colorOf(levelName));
-    return '$levelName: [${errorCodeName(actual.errorCode)}] $msg';
-  }
-}
-
-class _MockSdkSource implements Source {
-  /// Absolute URI which this source can be imported from.
-  final Uri uri;
-  final String _contents;
-
-  final int modificationStamp = 1;
-
-  _MockSdkSource(this.uri, this._contents);
-
-  TimestampedData<String> get contents =>
-      new TimestampedData(modificationStamp, _contents);
-
-  String get encoding => "${uriKind.encoding}$uri";
-
-  String get fullName => shortName;
-
-  int get hashCode => uri.hashCode;
-
-  bool get isInSystemLibrary => true;
-
-  String get shortName => uri.path;
-
-  Source get source => this;
-
-  UriKind get uriKind => UriKind.DART_URI;
-
-  bool exists() => true;
-
-  Source resolveRelative(Uri relativeUri) =>
-      throw new UnsupportedError('not expecting relative urls in dart: mocks');
-
-  Uri resolveRelativeUri(Uri relativeUri) =>
-      throw new UnsupportedError('not expecting relative urls in dart: mocks');
 }
diff --git a/pkg/analyzer/test/src/task/strong_mode_test.dart b/pkg/analyzer/test/src/task/strong_mode_test.dart
index 6859d48..097d5d4 100644
--- a/pkg/analyzer/test/src/task/strong_mode_test.dart
+++ b/pkg/analyzer/test/src/task/strong_mode_test.dart
@@ -4,9 +4,9 @@
 
 library analyzer.test.src.task.strong_mode_test;
 
+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/generated/ast.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/task/strong_mode.dart';
 import 'package:unittest/unittest.dart';
diff --git a/pkg/analyzer/test/src/task/test_all.dart b/pkg/analyzer/test/src/task/test_all.dart
index 41e568e..956a8e5 100644
--- a/pkg/analyzer/test/src/task/test_all.dart
+++ b/pkg/analyzer/test/src/task/test_all.dart
@@ -21,6 +21,7 @@
 import 'options_test.dart' as options_test;
 import 'options_work_manager_test.dart' as options_work_manager_test;
 import 'strong_mode_test.dart' as strong_mode_test;
+import 'yaml_test.dart' as yaml_test;
 
 /// Utility for manually running all tests.
 main() {
@@ -39,5 +40,6 @@
     options_test.main();
     options_work_manager_test.main();
     strong_mode_test.main();
+    yaml_test.main();
   });
 }
diff --git a/pkg/analyzer/test/src/task/yaml_test.dart b/pkg/analyzer/test/src/task/yaml_test.dart
new file mode 100644
index 0000000..5deb5f5
--- /dev/null
+++ b/pkg/analyzer/test/src/task/yaml_test.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer.test.src.task.yaml_test;
+
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/yaml.dart';
+import 'package:analyzer/task/general.dart';
+import 'package:analyzer/task/yaml.dart';
+import 'package:unittest/unittest.dart';
+import 'package:yaml/yaml.dart';
+
+import '../../reflective_tests.dart';
+import '../../utils.dart';
+import '../context/abstract_context.dart';
+
+main() {
+  initializeTestEnvironment();
+  runReflectiveTests(ParseYamlTaskTest);
+}
+
+isInstanceOf isParseYamlTask = new isInstanceOf<ParseYamlTask>();
+
+@reflectiveTest
+class ParseYamlTaskTest extends AbstractContextTest {
+  Source source;
+
+  test_perform() {
+    _performParseTask(r'''
+rules:
+  style_guide:
+    camel_case_types: false
+''');
+    expect(outputs, hasLength(3));
+    YamlDocument document = outputs[YAML_DOCUMENT];
+    expect(document, isNotNull);
+    var value = document.contents.value;
+    expect(value, new isInstanceOf<Map>());
+    expect(value['rules']['style_guide']['camel_case_types'], isFalse);
+    expect(outputs[YAML_ERRORS], hasLength(0));
+    LineInfo lineInfo = outputs[LINE_INFO];
+    expect(lineInfo, isNotNull);
+    expect(lineInfo.getOffsetOfLine(0), 0);
+    expect(lineInfo.getOffsetOfLine(1), 7);
+    expect(lineInfo.getOffsetOfLine(2), 22);
+    expect(lineInfo.getOffsetOfLine(3), 50);
+  }
+
+  test_perform_doesNotExist() {
+    _performParseTask(null);
+    expect(outputs, hasLength(3));
+    YamlDocument document = outputs[YAML_DOCUMENT];
+    expect(document, isNotNull);
+    expect(document.contents.value, isNull);
+    expect(outputs[YAML_ERRORS], hasLength(1));
+    LineInfo lineInfo = outputs[LINE_INFO];
+    expect(lineInfo, isNotNull);
+    expect(lineInfo.getOffsetOfLine(0), 0);
+  }
+
+  void _performParseTask(String content) {
+    if (content == null) {
+      source = resourceProvider.getFile('/test.yaml').createSource();
+    } else {
+      source = newSource('/test.yaml', content);
+    }
+    computeResult(source, YAML_DOCUMENT, matcher: isParseYamlTask);
+  }
+}
diff --git a/pkg/analyzer/test/src/test_all.dart b/pkg/analyzer/test/src/test_all.dart
index 14226d8..c92adfa 100644
--- a/pkg/analyzer/test/src/test_all.dart
+++ b/pkg/analyzer/test/src/test_all.dart
@@ -8,6 +8,7 @@
 
 import '../utils.dart';
 import 'context/test_all.dart' as context;
+import 'dart/test_all.dart' as dart;
 import 'plugin/plugin_config_test.dart' as plugin;
 import 'summary/test_all.dart' as summary;
 import 'task/test_all.dart' as task;
@@ -18,6 +19,7 @@
   initializeTestEnvironment();
   group('src tests', () {
     context.main();
+    dart.main();
     plugin.main();
     summary.main();
     task.main();
diff --git a/pkg/analyzer/test/utils.dart b/pkg/analyzer/test/utils.dart
index e162219..863b0ee 100644
--- a/pkg/analyzer/test/utils.dart
+++ b/pkg/analyzer/test/utils.dart
@@ -4,17 +4,17 @@
 
 library analyzer.test.utils;
 
+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/generated/ast.dart';
 import 'package:analyzer/src/generated/java_io.dart';
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:path/path.dart' as path;
 import 'package:unittest/unittest.dart';
 
-void initializeTestEnvironment() {
+void initializeTestEnvironment([path.Context context]) {
   groupSep = ' | ';
-  JavaFile.pathContext = path.posix;
+  JavaFile.pathContext = context ?? path.posix;
 }
 
 /**
diff --git a/pkg/analyzer/tool/summary/build_sdk_summaries.dart b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
new file mode 100644
index 0000000..29f49db
--- /dev/null
+++ b/pkg/analyzer/tool/summary/build_sdk_summaries.dart
@@ -0,0 +1,153 @@
+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';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/summary/format.dart';
+import 'package:analyzer/src/summary/index_unit.dart';
+import 'package:analyzer/src/summary/summarize_elements.dart';
+import 'package:path/path.dart';
+
+main(List<String> args) {
+  if (args.length < 1 || args.length > 2) {
+    _printUsage();
+    exitCode = 1;
+    return;
+  }
+  //
+  // Prepare output file path.
+  //
+  String outputDirectoryPath = args[0];
+  if (!FileSystemEntity.isDirectorySync(outputDirectoryPath)) {
+    print("'$outputDirectoryPath' is not a directory.");
+    _printUsage();
+    exitCode = 1;
+    return;
+  }
+  //
+  // Prepare SDK path.
+  //
+  String sdkPath;
+  if (args.length == 2) {
+    sdkPath = args[1];
+    if (!FileSystemEntity.isDirectorySync('$sdkPath/lib')) {
+      print("'$sdkPath/lib' does not exist.");
+      _printUsage();
+      exitCode = 1;
+      return;
+    }
+  } else {
+    sdkPath = DirectoryBasedDartSdk.defaultSdkDirectory.getAbsolutePath();
+  }
+  //
+  // Build spec and strong summaries.
+  //
+  new _Builder(sdkPath, outputDirectoryPath, false).build();
+  new _Builder(sdkPath, outputDirectoryPath, true).build();
+}
+
+/**
+ * The name of the SDK summaries builder application.
+ */
+const BINARY_NAME = "build_sdk_summaries";
+
+/**
+ * Print information about how to use the SDK summaries builder.
+ */
+void _printUsage() {
+  print('Usage: $BINARY_NAME output_directory_path [sdk_path]');
+  print('Build files spec.sum and strong.sum in the output directory.');
+}
+
+class _Builder {
+  final String sdkPath;
+  final String outputDirectoryPath;
+  final bool strongMode;
+
+  AnalysisContext context;
+  final Set<Source> processedSources = new Set<Source>();
+
+  final PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
+  final PackageIndexAssembler indexAssembler = new PackageIndexAssembler();
+
+  _Builder(this.sdkPath, this.outputDirectoryPath, this.strongMode);
+
+  /**
+   * Build a strong or spec mode summary for the Dart SDK at [sdkPath].
+   */
+  void build() {
+    String modeName = strongMode ? 'strong' : 'spec';
+    print('Generating $modeName mode summary and index.');
+    Stopwatch sw = new Stopwatch()..start();
+    //
+    // Prepare SDK.
+    //
+    DirectoryBasedDartSdk sdk =
+        new DirectoryBasedDartSdk(new JavaFile(sdkPath));
+    sdk.useSummary = false;
+    context = sdk.context;
+    context.analysisOptions = new AnalysisOptionsImpl()
+      ..strongMode = strongMode;
+    //
+    // Prepare 'dart:' URIs to serialize.
+    //
+    Set<String> uriSet =
+        sdk.sdkLibraries.map((SdkLibrary library) => library.shortName).toSet();
+    uriSet.add('dart:html/nativewrappers.dart');
+    uriSet.add('dart:html_common/html_common_dart2js.dart');
+    //
+    // Serialize each SDK library.
+    //
+    for (String uri in uriSet) {
+      Source libSource = sdk.mapDartUri(uri);
+      _serializeLibrary(libSource);
+    }
+    //
+    // Write the whole SDK bundle.
+    //
+    {
+      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.
+    //
+    print('\tDone in ${sw.elapsedMilliseconds} ms.');
+  }
+
+  /**
+   * Serialize the library with the given [source] and all its direct or
+   * indirect imports and exports.
+   */
+  void _serializeLibrary(Source source) {
+    if (!processedSources.add(source)) {
+      return;
+    }
+    LibraryElement element = context.computeLibraryElement(source);
+    bundleAssembler.serializeLibraryElement(element);
+    element.importedLibraries.forEach((e) => _serializeLibrary(e.source));
+    element.exportedLibraries.forEach((e) => _serializeLibrary(e.source));
+    // 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/build_sdk_summary.dart b/pkg/analyzer/tool/summary/build_sdk_summary.dart
deleted file mode 100644
index db17c57..0000000
--- a/pkg/analyzer/tool/summary/build_sdk_summary.dart
+++ /dev/null
@@ -1,87 +0,0 @@
-import 'dart:io';
-
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/java_io.dart';
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/sdk_io.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/summarize_elements.dart';
-
-main(List<String> args) {
-  if (args.length < 1 || args.length > 2) {
-    _printUsage();
-    return;
-  }
-  //
-  // Prepare output file path.
-  //
-  String outputFilePath = args[0];
-  if (FileSystemEntity.isDirectorySync(outputFilePath)) {
-    print("'$outputFilePath' is a directory.");
-    _printUsage();
-    return;
-  }
-  //
-  // Prepare SDK path.
-  //
-  String sdkPath;
-  if (args.length == 2) {
-    sdkPath = args[1];
-    if (!FileSystemEntity.isDirectorySync('$sdkPath/lib')) {
-      print("'$sdkPath/lib' does not exist.");
-      _printUsage();
-      return;
-    }
-  } else {
-    sdkPath = DirectoryBasedDartSdk.defaultSdkDirectory.getAbsolutePath();
-  }
-  //
-  // Prepare SDK.
-  //
-  DirectoryBasedDartSdk sdk = new DirectoryBasedDartSdk(new JavaFile(sdkPath));
-  AnalysisContext context = sdk.context;
-  //
-  // Serialize each SDK library.
-  //
-  List<String> prelinkedLibraryUris = <String>[];
-  List<PrelinkedLibraryBuilder> prelinkedLibraries =
-      <PrelinkedLibraryBuilder>[];
-  List<String> unlinkedUnitUris = <String>[];
-  List<UnlinkedUnitBuilder> unlinkedUnits = <UnlinkedUnitBuilder>[];
-  for (SdkLibrary lib in sdk.sdkLibraries) {
-    print('Resolving and serializing: ${lib.shortName}');
-    Source librarySource = sdk.mapDartUri(lib.shortName);
-    LibraryElement libraryElement =
-        context.computeLibraryElement(librarySource);
-    LibrarySerializationResult libraryResult =
-        serializeLibrary(libraryElement, context.typeProvider);
-    prelinkedLibraryUris.add(lib.shortName);
-    prelinkedLibraries.add(libraryResult.prelinked);
-    unlinkedUnitUris.addAll(libraryResult.unitUris);
-    unlinkedUnits.addAll(libraryResult.unlinkedUnits);
-  }
-  //
-  // Write the whole SDK bundle.
-  //
-  SdkBundleBuilder sdkBundle = encodeSdkBundle(
-      prelinkedLibraryUris: prelinkedLibraryUris,
-      prelinkedLibraries: prelinkedLibraries,
-      unlinkedUnitUris: unlinkedUnitUris,
-      unlinkedUnits: unlinkedUnits);
-  File file = new File(outputFilePath);
-  file.writeAsBytesSync(sdkBundle.toBuffer(), mode: FileMode.WRITE_ONLY);
-}
-
-/**
- * The name of the SDK summary builder application.
- */
-const BINARY_NAME = "build_sdk_summary";
-
-/**
- * Print information about how to use the SDK summary builder.
- */
-void _printUsage() {
-  print('Usage: $BINARY_NAME output_file_path [sdk_path]');
-}
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 1918074..cfa14a0 100644
--- a/pkg/analyzer/tool/summary/generate.dart
+++ b/pkg/analyzer/tool/summary/generate.dart
@@ -23,11 +23,13 @@
 import 'dart:io' hide File;
 
 import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/src/codegen/tools.dart';
+import 'package:analyzer/src/dart/scanner/reader.dart';
+import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:path/path.dart';
 
@@ -36,31 +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, 'tool', '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.
    */
@@ -76,20 +81,58 @@
    */
   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;
         idlModel.FieldType type = field.type;
         if (type.isList) {
           if (_idl.classes.containsKey(type.typeName)) {
             // 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') {
+            // List of doubles is ok
           } else if (type.typeName == 'String') {
             // List of strings is ok
           } else {
@@ -97,6 +140,16 @@
                 '$name.$fieldName: illegal type (list of ${type.typeName})');
           }
         }
+        if (idsUsed.containsKey(field.id)) {
+          throw new Exception('$name.$fieldName: id ${field.id} already used by'
+              ' ${idsUsed[field.id]}');
+        }
+        idsUsed[field.id] = fieldName;
+      }
+      for (int i = 0; i < idsUsed.length; i++) {
+        if (!idsUsed.containsKey(i)) {
+          throw new Exception('$name: no field uses id $i');
+        }
       }
     });
   }
@@ -106,22 +159,33 @@
    * represent [type] when deserialized.
    */
   String dartType(idlModel.FieldType type) {
+    String baseType = idlPrefix(type.typeName);
     if (type.isList) {
-      return 'List<${type.typeName}>';
+      return 'List<$baseType>';
     } else {
-      return type.typeName;
+      return baseType;
     }
   }
 
   /**
    * Generate a Dart expression representing the default value for a field
    * having the given [type], or `null` if there is no default value.
+   *
+   * If [builder] is `true`, the returned type should be appropriate for use in
+   * a builder class.
    */
-  String defaultValue(idlModel.FieldType type) {
+  String defaultValue(idlModel.FieldType type, bool builder) {
     if (type.isList) {
-      return 'const <${type.typeName}>[]';
+      if (builder) {
+        idlModel.FieldType elementType =
+            new idlModel.FieldType(type.typeName, false);
+        return '<${encodedType(elementType)}>[]';
+      } else {
+        return 'const <${idlPrefix(type.typeName)}>[]';
+      }
     } else if (_idl.enums.containsKey(type.typeName)) {
-      return '${type.typeName}.${_idl.enums[type.typeName].values[0]}';
+      return '${idlPrefix(type.typeName)}.'
+          '${_idl.enums[type.typeName].values[0].name}';
     } else if (type.typeName == 'int') {
       return '0';
     } else if (type.typeName == 'String') {
@@ -142,7 +206,7 @@
     if (_idl.classes.containsKey(type.typeName)) {
       typeStr = '${type.typeName}Builder';
     } else {
-      typeStr = type.typeName;
+      typeStr = idlPrefix(type.typeName);
     }
     if (type.isList) {
       return 'List<$typeStr>';
@@ -160,19 +224,53 @@
     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 `$clsName` needs to extend `$expectedBase`');
+        }
         for (ClassMember classMember in decl.members) {
-          if (classMember is FieldDeclaration) {
-            TypeName type = classMember.fields.type;
+          if (classMember is MethodDeclaration && classMember.isGetter) {
+            String desc = '$clsName.${classMember.name.name}';
+            TypeName type = classMember.returnType;
+            if (type == null) {
+              throw new Exception('Class member needs a type: $desc');
+            }
             bool isList = false;
             if (type.name.name == 'List' &&
                 type.typeArguments != null &&
@@ -183,13 +281,44 @@
             if (type.typeArguments != null) {
               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) {
+                  throw new Exception(
+                      'Duplicate @id annotation ($classMember)');
+                }
+                if (annotation.arguments.arguments.length != 1) {
+                  throw new Exception(
+                      '@Id must be passed exactly one argument ($desc)');
+                }
+                Expression expression = annotation.arguments.arguments[0];
+                if (expression is IntegerLiteral) {
+                  id = expression.value;
+                } else {
+                  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) {
+              throw new Exception('Missing @id annotation ($desc)');
+            }
             String doc = _getNodeDoc(lineInfo, classMember);
             idlModel.FieldType fieldType =
                 new idlModel.FieldType(type.name.name, isList);
-            for (VariableDeclaration field in classMember.fields.variables) {
-              cls.fields.add(new idlModel.FieldDeclaration(
-                  doc, field.name.name, fieldType));
-            }
+            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
+            // read functions generated by [_generateReadFunction].
           } else {
             throw new Exception('Unexpected class member `$classMember`');
           }
@@ -200,7 +329,9 @@
             new idlModel.EnumDeclaration(doc, decl.name.name);
         _idl.enums[enm.name] = enm;
         for (EnumConstantDeclaration constDecl in decl.constants) {
-          enm.values.add(constDecl.name.name);
+          String doc = _getNodeDoc(lineInfo, constDecl);
+          enm.values
+              .add(new idlModel.EnumValueDeclaration(doc, constDecl.name.name));
         }
       } else if (decl is TopLevelVariableDeclaration) {
         // Ignore top level variable declarations; they are present just to make
@@ -212,6 +343,144 @@
   }
 
   /**
+   * 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.
+   */
+  String idlPrefix(String s) {
+    switch (s) {
+      case 'bool':
+      case 'double':
+      case 'int':
+      case 'String':
+        return s;
+      default:
+        return 'idl.$s';
+    }
+  }
+
+  /**
    * Execute [callback] with two spaces added to [_indentation].
    */
   void indent(void callback()) {
@@ -242,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.');
@@ -256,34 +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 'base.dart' as base;");
-    out("import 'flat_buffers.dart' as fb;");
-    out();
-    _idl.enums.forEach((String name, idlModel.EnumDeclaration enm) {
-      outDoc(enm.documentation);
-      out('enum $name {');
-      indent(() {
-        for (String value in enm.values) {
-          out('$value,');
-        }
-      });
-      out('}');
-      out();
-    });
-    for (var cls in _idl.classes.values) {
-      List<String> builderParams = _generateBuilder(cls);
-      out();
-      _generateEncodeFunction(cls, builderParams);
-      out();
-      _generateInterface(cls);
-      out();
-      _generateReader(cls);
-      out();
-      _generateImpl(cls);
-      out();
-    }
   }
 
   /**
@@ -293,10 +528,13 @@
     return JSON.encode(s);
   }
 
-  List<String> _generateBuilder(idlModel.ClassDeclaration cls) {
-    String builderName = cls.name + 'Builder';
-    List<String> builderParams = <String>[];
-    out('class $builderName {');
+  void _generateBuilder(idlModel.ClassDeclaration cls) {
+    String name = cls.name;
+    String builderName = name + 'Builder';
+    String mixinName = '_${name}Mixin';
+    List<String> constructorParams = <String>[];
+    out('class $builderName extends Object with $mixinName '
+        'implements ${idlPrefix(name)} {');
     indent(() {
       out('bool _finished = false;');
       // Generate fields.
@@ -307,23 +545,49 @@
         String typeStr = encodedType(type);
         out('$typeStr _$fieldName;');
       }
+      // Generate getters and setters.
+      for (idlModel.FieldDeclaration field in cls.allFields) {
+        String fieldName = field.name;
+        idlModel.FieldType fieldType = field.type;
+        String typeStr = encodedType(fieldType);
+        String def = defaultValue(fieldType, true);
+        String defSuffix = def == null ? '' : ' ??= $def';
+        out();
+        out('@override');
+        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('}');
+        }
+      }
       // Generate constructor.
       out();
-      out('$builderName();');
-      // Generate setters.
-      for (idlModel.FieldDeclaration field in cls.fields) {
-        String fieldName = field.name;
-        String typeStr = encodedType(field.type);
-        out();
-        outDoc(field.documentation);
-        builderParams.add('$typeStr $fieldName');
-        out('void set $fieldName($typeStr _value) {');
-        indent(() {
-          String stateFieldName = '_' + fieldName;
-          out('assert(!_finished);');
-          out('$stateFieldName = _value;');
-        });
-        out('}');
+      out('$builderName({${constructorParams.join(', ')}})');
+      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 == fields.length - 1 ? ';' : ',';
+        out('${prefix}_${field.name} = ${field.name}$suffix');
       }
       // Generate finish.
       if (cls.isTopLevel) {
@@ -331,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('}');
       }
@@ -341,7 +608,7 @@
         out('assert(!_finished);');
         out('_finished = true;');
         // Write objects and remember Offset(s).
-        cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) {
+        for (idlModel.FieldDeclaration field in cls.fields) {
           idlModel.FieldType fieldType = field.type;
           String offsetName = 'offset_' + field.name;
           if (fieldType.isList ||
@@ -349,8 +616,8 @@
               _idl.classes.containsKey(fieldType.typeName)) {
             out('fb.Offset $offsetName;');
           }
-        });
-        cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) {
+        }
+        for (idlModel.FieldDeclaration field in cls.fields) {
           idlModel.FieldType fieldType = field.type;
           String valueName = '_' + field.name;
           String offsetName = 'offset_' + field.name;
@@ -362,8 +629,18 @@
               String itemCode = 'b.finish(fbBuilder)';
               String listCode = '$valueName.map((b) => $itemCode).toList()';
               writeCode = '$offsetName = fbBuilder.writeList($listCode);';
+            } else if (_idl.enums.containsKey(fieldType.typeName)) {
+              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.writeListInt32($valueName);';
+              writeCode =
+                  '$offsetName = fbBuilder.writeListUint32($valueName);';
+            } else if (fieldType.typeName == 'double') {
+              writeCode =
+                  '$offsetName = fbBuilder.writeListFloat64($valueName);';
             } else {
               assert(fieldType.typeName == 'String');
               String itemCode = 'fbBuilder.writeString(b)';
@@ -386,10 +663,11 @@
             });
             out('}');
           }
-        });
+        }
         // Write the table.
         out('fbBuilder.startTable();');
-        cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) {
+        for (idlModel.FieldDeclaration field in cls.fields) {
+          int index = field.id;
           idlModel.FieldType fieldType = field.type;
           String valueName = '_' + field.name;
           String condition = '$valueName != null';
@@ -404,11 +682,11 @@
             condition = '$valueName == true';
             writeCode = 'fbBuilder.addBool($index, true);';
           } else if (fieldType.typeName == 'int') {
-            condition += ' && $valueName != ${defaultValue(fieldType)}';
-            writeCode = 'fbBuilder.addInt32($index, $valueName);';
+            condition += ' && $valueName != ${defaultValue(fieldType, true)}';
+            writeCode = 'fbBuilder.addUint32($index, $valueName);';
           } else if (_idl.enums.containsKey(fieldType.typeName)) {
-            condition += ' && $valueName != ${defaultValue(fieldType)}';
-            writeCode = 'fbBuilder.addInt32($index, $valueName.index);';
+            condition += ' && $valueName != ${defaultValue(fieldType, true)}';
+            writeCode = 'fbBuilder.addUint8($index, $valueName.index);';
           }
           if (writeCode == null) {
             throw new UnimplementedError('Writing type ${fieldType.typeName}');
@@ -418,27 +696,33 @@
             out(writeCode);
           });
           out('}');
-        });
+        }
         out('return fbBuilder.endTable();');
       });
       out('}');
     });
     out('}');
-    return builderParams;
   }
 
-  void _generateEncodeFunction(
-      idlModel.ClassDeclaration cls, List<String> builderParams) {
-    String className = cls.name;
-    String builderName = className + 'Builder';
-    out('$builderName encode$className({${builderParams.join(', ')}}) {');
+  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('$builderName builder = new $builderName();');
-      for (idlModel.FieldDeclaration field in cls.fields) {
-        String fieldName = field.name;
-        out('builder.$fieldName = $fieldName;');
-      }
-      out('return builder;');
+      out('const $readerName() : super();');
+      out();
+      out('@override');
+      out('int get size => 1;');
+      out();
+      out('@override');
+      out('${idlPrefix(name)} read(fb.BufferPointer bp) {');
+      indent(() {
+        out('int index = const fb.Uint8Reader().read(bp);');
+        out('return index < $count ? ${idlPrefix(name)}.values[index] : $def;');
+      });
+      out('}');
     });
     out('}');
   }
@@ -446,7 +730,9 @@
   void _generateImpl(idlModel.ClassDeclaration cls) {
     String name = cls.name;
     String implName = '_${name}Impl';
-    out('class $implName implements $name {');
+    String mixinName = '_${name}Mixin';
+    out('class $implName extends Object with $mixinName'
+        ' implements ${idlPrefix(name)} {');
     indent(() {
       out('final fb.BufferPointer _bp;');
       out();
@@ -458,6 +744,108 @@
         String fieldName = field.name;
         out('$returnType _$fieldName;');
       }
+      // Write getters.
+      for (idlModel.FieldDeclaration field in cls.allFields) {
+        int index = field.id;
+        String fieldName = field.name;
+        idlModel.FieldType type = field.type;
+        String typeName = type.typeName;
+        // Prepare "readCode" + "def"
+        String readCode;
+        String def = defaultValue(type, false);
+        if (type.isList) {
+          if (typeName == 'bool') {
+            readCode = 'const fb.BoolListReader()';
+          } else if (typeName == 'int') {
+            readCode = 'const fb.Uint32ListReader()';
+          } else if (typeName == 'double') {
+            readCode = 'const fb.Float64ListReader()';
+          } else if (typeName == 'String') {
+            String itemCode = 'const fb.StringReader()';
+            readCode = 'const fb.ListReader<String>($itemCode)';
+          } else if (_idl.classes.containsKey(typeName)) {
+            String itemCode = 'const _${typeName}Reader()';
+            readCode = 'const fb.ListReader<${idlPrefix(typeName)}>($itemCode)';
+          } else {
+            assert(_idl.enums.containsKey(typeName));
+            String itemCode = 'const _${typeName}Reader()';
+            readCode = 'const fb.ListReader<${idlPrefix(typeName)}>($itemCode)';
+          }
+        } else if (typeName == 'bool') {
+          readCode = 'const fb.BoolReader()';
+        } else if (typeName == 'int') {
+          readCode = 'const fb.Uint32Reader()';
+        } else if (typeName == 'String') {
+          readCode = 'const fb.StringReader()';
+        } else if (_idl.enums.containsKey(typeName)) {
+          readCode = 'const _${typeName}Reader()';
+        } else if (_idl.classes.containsKey(typeName)) {
+          readCode = 'const _${typeName}Reader()';
+        }
+        assert(readCode != null);
+        // Write the getter implementation.
+        out();
+        out('@override');
+        String returnType = dartType(type);
+        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('}');
+  }
+
+  void _generateMixin(idlModel.ClassDeclaration cls) {
+    String name = cls.name;
+    String mixinName = '_${name}Mixin';
+    out('abstract class $mixinName implements ${idlPrefix(name)} {');
+    indent(() {
+      // Write toJson().
+      out('@override');
+      out('Map<String, Object> toJson() {');
+      indent(() {
+        out('Map<String, Object> _result = <String, Object>{};');
+        for (idlModel.FieldDeclaration field in cls.fields) {
+          String condition;
+          if (field.type.isList) {
+            condition = '${field.name}.isNotEmpty';
+          } else {
+            condition = '${field.name} != ${defaultValue(field.type, false)}';
+          }
+          _StringToString convertItem;
+          if (_idl.classes.containsKey(field.type.typeName)) {
+            convertItem = (String name) => '$name.toJson()';
+          } else if (_idl.enums.containsKey(field.type.typeName)) {
+            // TODO(paulberry): it would be better to generate a const list of
+            // strings so that we don't have to do this kludge.
+            convertItem = (String name) => "$name.toString().split('.')[1]";
+          } else if (field.type.typeName == 'double') {
+            convertItem =
+                (String name) => '$name.isFinite ? $name : $name.toString()';
+          }
+          String convertField;
+          if (convertItem == null) {
+            convertField = field.name;
+          } else if (field.type.isList) {
+            convertField = '${field.name}.map((_value) =>'
+                ' ${convertItem('_value')}).toList()';
+          } else {
+            convertField = convertItem(field.name);
+          }
+          String storeField = '_result[${quoted(field.name)}] = $convertField';
+          out('if ($condition) $storeField;');
+        }
+        out('return _result;');
+      });
+      out('}');
       out();
       // Write toMap().
       out('@override');
@@ -469,77 +857,10 @@
         }
       });
       out('};');
-      // Write getters.
-      cls.fields.asMap().forEach((index, field) {
-        String fieldName = field.name;
-        idlModel.FieldType type = field.type;
-        String typeName = type.typeName;
-        // Prepare "readExpr" or "readCode" + "def"
-        String readExpr;
-        String readCode;
-        String def = defaultValue(type);
-        if (type.isList) {
-          if (typeName == 'int') {
-            String itemCode = 'const fb.Int32Reader()';
-            readCode = 'const fb.ListReader<int>($itemCode)';
-          } else if (typeName == 'String') {
-            String itemCode = 'const fb.StringReader()';
-            readCode = 'const fb.ListReader<String>($itemCode)';
-          } else {
-            String itemCode = '$typeName>(const _${typeName}Reader()';
-            readCode = 'const fb.ListReader<$itemCode)';
-          }
-        } else if (typeName == 'bool') {
-          readCode = 'const fb.BoolReader()';
-        } else if (typeName == 'int') {
-          readCode = 'const fb.Int32Reader()';
-        } else if (typeName == 'String') {
-          readCode = 'const fb.StringReader()';
-        } else if (_idl.enums.containsKey(typeName)) {
-          readExpr =
-              '$typeName.values[const fb.Int32Reader().vTableGet(_bp, $index, 0)]';
-        } else if (_idl.classes.containsKey(typeName)) {
-          readCode = 'const _${typeName}Reader()';
-        }
-        if (readExpr == null) {
-          assert(readCode != null);
-          readExpr = '$readCode.vTableGet(_bp, $index, $def)';
-        }
-        // Write the getter implementation.
-        out();
-        out('@override');
-        String returnType = dartType(type);
-        out('$returnType get $fieldName {');
-        indent(() {
-          out('_$fieldName ??= $readExpr;');
-          out('return _$fieldName;');
-        });
-        out('}');
-      });
-    });
-    out('}');
-  }
-
-  void _generateInterface(idlModel.ClassDeclaration cls) {
-    String name = cls.name;
-    outDoc(cls.documentation);
-    out('abstract class $name extends base.SummaryClass {');
-    indent(() {
-      if (cls.isTopLevel) {
-        out('factory $name.fromBuffer(List<int> buffer) {');
-        indent(() {
-          out('fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);');
-          out('return const _${name}Reader().read(rootRef);');
-        });
-        out('}');
-      }
-      cls.fields.asMap().forEach((index, field) {
-        String fieldName = field.name;
-        idlModel.FieldType type = field.type;
-        out();
-        outDoc(field.documentation);
-        out('${dartType(type)} get $fieldName;');
-      });
+      out();
+      // Write toString().
+      out('@override');
+      out('String toString() => convert.JSON.encode(toJson());');
     });
     out('}');
   }
@@ -558,6 +879,16 @@
     out('}');
   }
 
+  void _generateReadFunction(idlModel.ClassDeclaration cls) {
+    String name = cls.name;
+    out('${idlPrefix(name)} read$name(List<int> buffer) {');
+    indent(() {
+      out('fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer);');
+      out('return const _${name}Reader().read(rootRef);');
+    });
+    out('}');
+  }
+
   /**
    * Return the documentation text of the given [node], or `null` if the [node]
    * does not have a comment.  Each line is `\n` separated.
diff --git a/pkg/analyzer/tool/summary/idl.dart b/pkg/analyzer/tool/summary/idl.dart
deleted file mode 100644
index 39e7a4a..0000000
--- a/pkg/analyzer/tool/summary/idl.dart
+++ /dev/null
@@ -1,1012 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * This file is an "idl" style description of the summary format.  It is not
- * executed directly; instead it is parsed and transformed into code that
- * implements the summary format.
- *
- * The code generation process introduces the following non-typical semantics:
- * - Fields of type List are never null, and have a default value of the empty
- *   list.
- * - Fields of type int are never null, and have a default value of zero.
- * - Fields of type String are never null, and have a default value of ''.
- * - Fields of type bool are never null, and have a default value of false.
- * - Fields whose type is an enum are never null, and have a default value of
- *   the first value declared in the enum.
- *
- * Terminology used in this document:
- * - "Unlinked" refers to information that can be determined from reading the
- *   .dart file for the library itself (including all parts) and no other
- *   files.
- * - "Prelinked" refers to information that can be determined from reading the
- *   unlinked information for the library itself and the unlinked information
- *   for all direct imports (plus the transitive closure of exports reachable
- *   from those direct imports).
- * - "Linked" refers to information that can be determined only from reading
- *   the unlinked and prelinked information for the library itself and the
- *   transitive closure of its imports.
- *
- * TODO(paulberry): currently the summary format only contains unlinked and
- * prelinked information.
- *
- * Except as otherwise noted, synthetic elements are not stored in the summary;
- * they are re-synthesized at the time the summary is read.
- */
-library analyzer.tool.summary.idl;
-
-/**
- * Annotation describing information which is not part of Dart semantics; in
- * other words, if this information (or any information it refers to) changes,
- * static analysis and runtime behavior of the library are unaffected.
- *
- * TODO(paulberry): some informative information is currently missing from the
- * summary format.
- */
-const informative = null;
-
-/**
- * Annotation describing information which is not part of the public API to a
- * library; in other words, if this information (or any information it refers
- * to) changes, libraries outside this one are unaffected.
- *
- * TODO(paulberry): currently the summary format does not contain private
- * information.
- */
-const private = null;
-
-/**
- * Annotation describing a class which can be the top level object in an
- * encoded summary.
- */
-const topLevel = null;
-
-/**
- * Information about a dependency that exists between one library and another
- * due to an "import" declaration.
- */
-class PrelinkedDependency {
-  /**
-   * 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`.
-   */
-  String uri;
-
-  /**
-   * URI for the compilation units listed in the library's `part` declarations.
-   * These URIs are relative to the importing library.
-   */
-  List<String> parts;
-}
-
-/**
- * Pre-linked summary of a library.
- */
-@topLevel
-class PrelinkedLibrary {
-  /**
-   * The pre-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.
-   */
-  List<PrelinkedUnit> units;
-
-  /**
-   * 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").
-   *
-   * TODO(paulberry): consider removing this entirely and just using
-   * [UnlinkedLibrary.imports].
-   */
-  List<PrelinkedDependency> dependencies;
-
-  /**
-   * For each import in [UnlinkedUnit.imports], an index into [dependencies]
-   * of the library being imported.
-   *
-   * TODO(paulberry): if [dependencies] is removed, this can be removed as
-   * well, since there will effectively be a one-to-one mapping.
-   */
-  List<int> importDependencies;
-}
-
-/**
- * Information about the resolution of an [UnlinkedReference].
- */
-class PrelinkedReference {
-  /**
-   * Index into [PrelinkedLibrary.dependencies] indicating which imported library
-   * declares the entity being referred to.
-   */
-  int dependency;
-
-  /**
-   * The kind of the entity being referred to.  For the pseudo-type `dynamic`,
-   * the kind is [PrelinkedReferenceKind.classOrEnum].
-   */
-  PrelinkedReferenceKind kind;
-
-  /**
-   * Integer index indicating which unit in the imported library contains the
-   * definition of the entity.  As with indices into [PrelinkedLibrary.units],
-   * zero represents the defining compilation unit, and nonzero values
-   * represent parts in the order of the corresponding `part` declarations.
-   */
-  int unit;
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  int numTypeParameters;
-}
-
-/**
- * Enum used to indicate the kind of entity referred to by a
- * [PrelinkedReference].
- */
-enum PrelinkedReferenceKind {
-  /**
-   * The entity is a class or enum.
-   */
-  classOrEnum,
-
-  /**
-   * The entity is a typedef.
-   */
-  typedef,
-
-  /**
-   * The entity is a variable or executable.
-   */
-  other,
-
-  /**
-   * The entity is a prefix.
-   */
-  prefix,
-
-  /**
-   * The entity being referred to does not exist.
-   */
-  unresolved
-}
-
-/**
- * Pre-linked summary of a compilation unit.
- */
-class PrelinkedUnit {
-  /**
-   * For each reference in [UnlinkedUnit.references], information about how
-   * that reference is resolved.
-   */
-  List<PrelinkedReference> references;
-}
-
-/**
- * Information about SDK.
- */
-@topLevel
-class SdkBundle {
-  /**
-   * The list of URIs of items in [prelinkedLibraries], e.g. `dart:core`.
-   */
-  List<String> prelinkedLibraryUris;
-
-  /**
-   * Pre-linked libraries.
-   */
-  List<PrelinkedLibrary> prelinkedLibraries;
-
-  /**
-   * The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
-   */
-  List<String> unlinkedUnitUris;
-
-  /**
-   * Unlinked information for the compilation units constituting the SDK.
-   */
-  List<UnlinkedUnit> unlinkedUnits;
-}
-
-/**
- * Unlinked summary information about a class declaration.
- */
-class UnlinkedClass {
-  /**
-   * Name of the class.
-   */
-  String name;
-
-  /**
-   * Offset of the class name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
-
-  /**
-   * Documentation comment for the class, or `null` if there is no
-   * documentation comment.
-   */
-  @informative
-  UnlinkedDocumentationComment documentationComment;
-
-  /**
-   * Type parameters of the class, if any.
-   */
-  List<UnlinkedTypeParam> typeParameters;
-
-  /**
-   * 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).
-   */
-  UnlinkedTypeRef supertype;
-
-  /**
-   * Mixins appearing in a `with` clause, if any.
-   */
-  List<UnlinkedTypeRef> mixins;
-
-  /**
-   * Interfaces appearing in an `implements` clause, if any.
-   */
-  List<UnlinkedTypeRef> interfaces;
-
-  /**
-   * Field declarations contained in the class.
-   */
-  List<UnlinkedVariable> fields;
-
-  /**
-   * Executable objects (methods, getters, and setters) contained in the class.
-   */
-  List<UnlinkedExecutable> executables;
-
-  /**
-   * Indicates whether the class is declared with the `abstract` keyword.
-   */
-  bool isAbstract;
-
-  /**
-   * Indicates whether the class is declared using mixin application syntax.
-   */
-  bool isMixinApplication;
-
-  /**
-   * Indicates whether this class is the core "Object" class (and hence has no
-   * supertype)
-   */
-  bool hasNoSupertype;
-}
-
-/**
- * Unlinked summary information about a `show` or `hide` combinator in an
- * import or export declaration.
- */
-class UnlinkedCombinator {
-  /**
-   * List of names which are shown.  Empty if this is a `hide` combinator.
-   */
-  List<String> shows;
-
-  /**
-   * List of names which are hidden.  Empty if this is a `show` combinator.
-   */
-  List<String> hides;
-}
-
-/**
- * Unlinked summary information about a documentation comment.
- */
-class UnlinkedDocumentationComment {
-  /**
-   * Text of the documentation comment, with '\r\n' replaced by '\n'.
-   *
-   * References appearing within the doc comment in square brackets are not
-   * specially encoded.
-   */
-  String text;
-
-  /**
-   * Offset of the beginning of the documentation comment relative to the
-   * beginning of the file.
-   */
-  int offset;
-
-  /**
-   * Length of the documentation comment (prior to replacing '\r\n' with '\n').
-   */
-  int length;
-}
-
-/**
- * Unlinked summary information about an enum declaration.
- */
-class UnlinkedEnum {
-  /**
-   * Name of the enum type.
-   */
-  String name;
-
-  /**
-   * Offset of the enum name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
-
-  /**
-   * Documentation comment for the enum, or `null` if there is no documentation
-   * comment.
-   */
-  @informative
-  UnlinkedDocumentationComment documentationComment;
-
-  /**
-   * Values listed in the enum declaration, in declaration order.
-   */
-  List<UnlinkedEnumValue> values;
-}
-
-/**
- * Unlinked summary information about a single enumerated value in an enum
- * declaration.
- */
-class UnlinkedEnumValue {
-  /**
-   * Name of the enumerated value.
-   */
-  String name;
-
-  /**
-   * Offset of the enum value name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
-
-  /**
-   * Documentation comment for the enum value, or `null` if there is no
-   * documentation comment.
-   */
-  @informative
-  UnlinkedDocumentationComment documentationComment;
-}
-
-/**
- * Unlinked summary information about a function, method, getter, or setter
- * declaration.
- */
-class UnlinkedExecutable {
-  /**
-   * 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.
-   */
-  String name;
-
-  /**
-   * 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(); }").
-   */
-  @informative
-  int nameOffset;
-
-  /**
-   * Documentation comment for the executable, or `null` if there is no
-   * documentation comment.
-   */
-  @informative
-  UnlinkedDocumentationComment documentationComment;
-
-  /**
-   * Type parameters of the executable, if any.  Empty if support for generic
-   * method syntax is disabled.
-   */
-  List<UnlinkedTypeParam> typeParameters;
-
-  /**
-   * Declared return type of the executable.  Absent if the return type is
-   * `void` or the executable is a constructor.  Note that when strong mode is
-   * enabled, the actual return type may be different due to type inference.
-   */
-  UnlinkedTypeRef returnType;
-
-  /**
-   * 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.
-   */
-  List<UnlinkedParam> parameters;
-
-  /**
-   * The kind of the executable (function/method, getter, setter, or
-   * constructor).
-   */
-  UnlinkedExecutableKind kind;
-
-  /**
-   * Indicates whether the executable is declared using the `abstract` keyword.
-   */
-  bool isAbstract;
-
-  /**
-   * 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).
-   */
-  bool isStatic;
-
-  /**
-   * Indicates whether the executable is declared using the `const` keyword.
-   */
-  bool isConst;
-
-  /**
-   * Indicates whether the executable is declared using the `factory` keyword.
-   */
-  bool isFactory;
-
-  /**
-   * Indicates whether the executable lacks an explicit return type
-   * declaration.  False for constructors and setters.
-   */
-  bool hasImplicitReturnType;
-
-  /**
-   * Indicates whether the executable is declared using the `external` keyword.
-   */
-  bool isExternal;
-}
-
-/**
- * Enum used to indicate the kind of an executable.
- */
-enum UnlinkedExecutableKind {
-  /**
-   * Executable is a function or method.
-   */
-  functionOrMethod,
-
-  /**
-   * Executable is a getter.
-   */
-  getter,
-
-  /**
-   * Executable is a setter.
-   */
-  setter,
-
-  /**
-   * Executable is a constructor.
-   */
-  constructor
-}
-
-/**
- * Unlinked summary information about an export declaration (stored outside
- * [UnlinkedPublicNamespace]).
- */
-class UnlinkedExportNonPublic {
-  /**
-   * Offset of the "export" keyword.
-   */
-  @informative
-  int offset;
-
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.
-   */
-  @informative
-  int uriOffset;
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.
-   */
-  @informative
-  int uriEnd;
-}
-
-/**
- * Unlinked summary information about an export declaration (stored inside
- * [UnlinkedPublicNamespace]).
- */
-class UnlinkedExportPublic {
-  /**
-   * URI used in the source code to reference the exported library.
-   */
-  String uri;
-
-  /**
-   * Combinators contained in this import declaration.
-   */
-  List<UnlinkedCombinator> combinators;
-}
-
-/**
- * Unlinked summary information about an import declaration.
- */
-class UnlinkedImport {
-  /**
-   * URI used in the source code to reference the imported library.
-   */
-  String uri;
-
-  /**
-   * If [isImplicit] is false, offset of the "import" keyword.  If [isImplicit]
-   * is true, zero.
-   */
-  @informative
-  int offset;
-
-  /**
-   * 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.
-   */
-  int prefixReference;
-
-  /**
-   * Combinators contained in this import declaration.
-   */
-  List<UnlinkedCombinator> combinators;
-
-  /**
-   * Indicates whether the import declaration uses the `deferred` keyword.
-   */
-  bool isDeferred;
-
-  /**
-   * Indicates whether the import declaration is implicit.
-   */
-  bool isImplicit;
-
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.  If [isImplicit] is true, zero.
-   */
-  @informative
-  int uriOffset;
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.  If [isImplicit] is true, zero.
-   */
-  @informative
-  int uriEnd;
-
-  /**
-   * Offset of the prefix name relative to the beginning of the file, or zero
-   * if there is no prefix.
-   */
-  @informative
-  int prefixOffset;
-}
-
-/**
- * Unlinked summary information about a function parameter.
- */
-class UnlinkedParam {
-  /**
-   * Name of the parameter.
-   */
-  String name;
-
-  /**
-   * Offset of the parameter name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
-
-  /**
-   * If [isFunctionTyped] is `true`, the declared return type.  If
-   * [isFunctionTyped] is `false`, the declared type.  Absent if
-   * [isFunctionTyped] is `true` and the declared return type is `void`.  Note
-   * that when strong mode is enabled, the actual type may be different due to
-   * type inference.
-   */
-  UnlinkedTypeRef type;
-
-  /**
-   * If [isFunctionTyped] is `true`, the parameters of the function type.
-   */
-  List<UnlinkedParam> parameters;
-
-  /**
-   * Kind of the parameter.
-   */
-  UnlinkedParamKind kind;
-
-  /**
-   * Indicates whether this is a function-typed parameter.
-   */
-  bool isFunctionTyped;
-
-  /**
-   * Indicates whether this is an initializing formal parameter (i.e. it is
-   * declared using `this.` syntax).
-   */
-  bool isInitializingFormal;
-
-  /**
-   * Indicates whether this parameter lacks an explicit type declaration.
-   * Always false for a function-typed parameter.
-   */
-  bool hasImplicitType;
-}
-
-/**
- * Enum used to indicate the kind of a parameter.
- */
-enum UnlinkedParamKind {
-  /**
-   * Parameter is required.
-   */
-  required,
-
-  /**
-   * Parameter is positional optional (enclosed in `[]`)
-   */
-  positional,
-
-  /**
-   * Parameter is named optional (enclosed in `{}`)
-   */
-  named
-}
-
-/**
- * Unlinked summary information about a part declaration.
- */
-class UnlinkedPart {
-  /**
-   * Offset of the URI string (including quotes) relative to the beginning of
-   * the file.
-   */
-  @informative
-  int uriOffset;
-
-  /**
-   * End of the URI string (including quotes) relative to the beginning of the
-   * file.
-   */
-  @informative
-  int uriEnd;
-}
-
-/**
- * Unlinked summary information about a specific name contributed by a
- * compilation unit to a library's public namespace.
- *
- * TODO(paulberry): add a count of generic parameters, so that resynthesis
- * doesn't have to peek into the library to obtain this info.
- *
- * TODO(paulberry): for classes, add info about static members and
- * constructors, since this will be needed to prelink info about constants.
- *
- * TODO(paulberry): some of this information is redundant with information
- * elsewhere in the summary.  Consider reducing the redundancy to reduce
- * summary size.
- */
-class UnlinkedPublicName {
-  /**
-   * The name itself.
-   */
-  String name;
-
-  /**
-   * The kind of object referred to by the name.
-   */
-  PrelinkedReferenceKind kind;
-
-  /**
-   * If the entity being referred to is generic, the number of type parameters
-   * it accepts.  Otherwise zero.
-   */
-  int numTypeParameters;
-}
-
-/**
- * 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.
- */
-@topLevel
-class UnlinkedPublicNamespace {
-  /**
-   * Public names defined in the compilation unit.
-   *
-   * TODO(paulberry): consider sorting these names to reduce unnecessary
-   * relinking.
-   */
-  List<UnlinkedPublicName> names;
-
-  /**
-   * Export declarations in the compilation unit.
-   */
-  List<UnlinkedExportPublic> exports;
-
-  /**
-   * URIs referenced by part declarations in the compilation unit.
-   */
-  List<String> parts;
-}
-
-/**
- * Unlinked summary information about a name referred to in one library that
- * might be defined in another.
- */
-class UnlinkedReference {
-  /**
-   * Name of the entity being referred to.  The empty string refers to the
-   * pseudo-type `dynamic`.
-   */
-  String name;
-
-  /**
-   * 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.
-   */
-  int prefixReference;
-}
-
-/**
- * Unlinked summary information about a typedef declaration.
- */
-class UnlinkedTypedef {
-  /**
-   * Name of the typedef.
-   */
-  String name;
-
-  /**
-   * Offset of the typedef name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
-
-  /**
-   * Documentation comment for the typedef, or `null` if there is no
-   * documentation comment.
-   */
-  @informative
-  UnlinkedDocumentationComment documentationComment;
-
-  /**
-   * Type parameters of the typedef, if any.
-   */
-  List<UnlinkedTypeParam> typeParameters;
-
-  /**
-   * Return type of the typedef.  Absent if the return type is `void`.
-   */
-  UnlinkedTypeRef returnType;
-
-  /**
-   * Parameters of the executable, if any.
-   */
-  List<UnlinkedParam> parameters;
-}
-
-/**
- * Unlinked summary information about a type parameter declaration.
- */
-class UnlinkedTypeParam {
-  /**
-   * Name of the type parameter.
-   */
-  String name;
-
-  /**
-   * Offset of the type parameter name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
-
-  /**
-   * Bound of the type parameter, if a bound is explicitly declared.  Otherwise
-   * null.
-   */
-  UnlinkedTypeRef bound;
-}
-
-/**
- * Unlinked summary information about a reference to a type.
- */
-class UnlinkedTypeRef {
-  /**
-   * Index into [UnlinkedUnit.references] for the type being referred to, or
-   * zero if this is a reference to a type parameter.
-   *
-   * Note that since zero is also a valid index into
-   * [UnlinkedUnit.references], we cannot distinguish between references to
-   * type parameters and references to types by checking [reference] against
-   * zero.  To distinguish between references to type parameters and references
-   * to types, check whether [paramReference] is zero.
-   */
-  int reference;
-
-  /**
-   * 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.
-   */
-  int paramReference;
-
-  /**
-   * If this is an instantiation of a generic type, the type arguments used to
-   * instantiate it.  Trailing type arguments of type `dynamic` are omitted.
-   */
-  List<UnlinkedTypeRef> typeArguments;
-}
-
-/**
- * Unlinked summary information about a compilation unit ("part file").
- */
-@topLevel
-class UnlinkedUnit {
-  /**
-   * Name of the library (from a "library" declaration, if present).
-   */
-  String libraryName;
-
-  /**
-   * Offset of the library name relative to the beginning of the file (or 0 if
-   * the library has no name).
-   */
-  @informative
-  int libraryNameOffset;
-
-  /**
-   * Length of the library name as it appears in the source code (or 0 if the
-   * library has no name).
-   */
-  @informative
-  int libraryNameLength;
-
-  /**
-   * Documentation comment for the library, or `null` if there is no
-   * documentation comment.
-   */
-  @informative
-  UnlinkedDocumentationComment libraryDocumentationComment;
-
-  /**
-   * Unlinked public namespace of this compilation unit.
-   */
-  UnlinkedPublicNamespace publicNamespace;
-
-  /**
-   * Top level and prefixed names referred to by this compilation unit.  The
-   * zeroth element of this array is always populated and always represents a
-   * reference to the pseudo-type "dynamic".
-   */
-  List<UnlinkedReference> references;
-
-  /**
-   * Classes declared in the compilation unit.
-   */
-  List<UnlinkedClass> classes;
-
-  /**
-   * Enums declared in the compilation unit.
-   */
-  List<UnlinkedEnum> enums;
-
-  /**
-   * Top level executable objects (functions, getters, and setters) declared in
-   * the compilation unit.
-   */
-  List<UnlinkedExecutable> executables;
-
-  /**
-   * Export declarations in the compilation unit.
-   */
-  List<UnlinkedExportNonPublic> exports;
-
-  /**
-   * Import declarations in the compilation unit.
-   */
-  List<UnlinkedImport> imports;
-
-  /**
-   * Part declarations in the compilation unit.
-   */
-  List<UnlinkedPart> parts;
-
-  /**
-   * Typedefs declared in the compilation unit.
-   */
-  List<UnlinkedTypedef> typedefs;
-
-  /**
-   * Top level variables declared in the compilation unit.
-   */
-  List<UnlinkedVariable> variables;
-}
-
-/**
- * Unlinked summary information about a top level variable, local variable, or
- * a field.
- */
-class UnlinkedVariable {
-  /**
-   * Name of the variable.
-   */
-  String name;
-
-  /**
-   * Offset of the variable name relative to the beginning of the file.
-   */
-  @informative
-  int nameOffset;
-
-  /**
-   * Documentation comment for the variable, or `null` if there is no
-   * documentation comment.
-   */
-  @informative
-  UnlinkedDocumentationComment documentationComment;
-
-  /**
-   * Declared type of the variable.  Note that when strong mode is enabled, the
-   * actual type of the variable may be different due to type inference.
-   */
-  UnlinkedTypeRef type;
-
-  /**
-   * 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).
-   */
-  bool isStatic;
-
-  /**
-   * Indicates whether the variable is declared using the `final` keyword.
-   */
-  bool isFinal;
-
-  /**
-   * Indicates whether the variable is declared using the `const` keyword.
-   */
-  bool isConst;
-
-  /**
-   * Indicates whether this variable lacks an explicit type declaration.
-   */
-  bool hasImplicitType;
-}
diff --git a/pkg/analyzer/tool/summary/idl_model.dart b/pkg/analyzer/tool/summary/idl_model.dart
index 07be039..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);
 }
 
 /**
@@ -51,13 +64,21 @@
   /**
    * List of enumerated values.
    */
-  final List<String> values = <String>[];
+  final List<EnumValueDeclaration> values = <EnumValueDeclaration>[];
 
   EnumDeclaration(String documentation, String name)
       : super(documentation, name);
 }
 
 /**
+ * Information about a single enum value defined in the IDL.
+ */
+class EnumValueDeclaration extends Declaration {
+  EnumValueDeclaration(String documentation, String name)
+      : super(documentation, name);
+}
+
+/**
  * Information about a single class field defined in the IDL.
  */
 class FieldDeclaration extends Declaration {
@@ -66,7 +87,18 @@
    */
   final FieldType type;
 
-  FieldDeclaration(String documentation, String name, this.type)
+  /**
+   * The id of the field.
+   */
+  final int 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/tool/summary/stats.dart b/pkg/analyzer/tool/summary/stats.dart
new file mode 100644
index 0000000..b8f5dd7
--- /dev/null
+++ b/pkg/analyzer/tool/summary/stats.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * This file contains code for collecting statistics about the use of fields in
+ * a summary file.
+ */
+library analyzer.tool.summary.stats;
+
+import 'dart:io';
+import 'dart:mirrors';
+
+import 'package:analyzer/src/summary/base.dart';
+import 'package:analyzer/src/summary/idl.dart';
+
+main(List<String> args) {
+  if (args.length != 1) {
+    _printUsage();
+    exitCode = 1;
+    return;
+  }
+
+  String inputFilePath = args[0];
+
+  // Read the input.
+  PackageBundle bundle =
+      new PackageBundle.fromBuffer(new File(inputFilePath).readAsBytesSync());
+
+  // Compute and output stats.
+  Stats stats = new Stats();
+  stats.record(bundle);
+  stats.dump();
+}
+
+/**
+ * The name of the stats tool.
+ */
+const String BINARY_NAME = "stats";
+
+/**
+ * Print information about how to use the stats tool.
+ */
+void _printUsage() {
+  print('Usage: $BINARY_NAME input_file_path');
+}
+
+/**
+ * An instance of [Stats] keeps track of statistics about the use of fields in
+ * summary objects.
+ */
+class Stats {
+  /**
+   * Map from type to field name to a count of how often the field is used.
+   */
+  Map<Type, Map<String, int>> counts = <Type, Map<String, int>>{};
+
+  /**
+   * Print out statistics gathered so far.
+   */
+  void dump() {
+    counts.forEach((Type type, Map<String, int> typeCounts) {
+      print(type);
+      List<String> keys = typeCounts.keys.toList();
+      keys.sort((String a, String b) => typeCounts[b].compareTo(typeCounts[a]));
+      for (String key in keys) {
+        print('  $key: ${typeCounts[key]}');
+      }
+      print('');
+    });
+  }
+
+  /**
+   * Record statistics for [obj] and all objects it refers to.
+   */
+  void record(SummaryClass obj) {
+    Map<String, int> typeCounts =
+        counts.putIfAbsent(obj.runtimeType, () => <String, int>{});
+    obj.toMap().forEach((String key, Object value) {
+      if (value == null ||
+          value == 0 ||
+          value == false ||
+          value == '' ||
+          value is List && value.isEmpty ||
+          reflect(value).type.isEnum && (value as dynamic).index == 0) {
+        return;
+      }
+      if (!typeCounts.containsKey(key)) {
+        typeCounts[key] = 0;
+      }
+      typeCounts[key]++;
+      if (value is SummaryClass) {
+        record(value);
+      } else if (value is List) {
+        value.forEach((Object element) {
+          if (element is SummaryClass) {
+            record(element);
+          }
+        });
+      }
+    });
+  }
+}
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index 49a1c1a..d77151b 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -35,6 +35,8 @@
   CONSTANT_DEPENDENCIES [shape=box]
   CONSTANT_EXPRESSIONS_DEPENDENCIES -> EvaluateUnitConstantsTask
   CONSTANT_EXPRESSIONS_DEPENDENCIES [shape=box]
+  CONSTANT_EXPRESSION_RESOLVED -> ComputeConstantDependenciesTask
+  CONSTANT_EXPRESSION_RESOLVED [shape=box]
   CONSTANT_VALUE -> ComputeConstantValueTask
   CONSTANT_VALUE -> EvaluateUnitConstantsTask
   CONSTANT_VALUE [shape=box]
@@ -44,6 +46,7 @@
   CONTENT [shape=box]
   CREATED_RESOLVED_UNIT [shape=box]
   CREATED_RESOLVED_UNIT1 [shape=box]
+  CREATED_RESOLVED_UNIT10 -> ResolveConstantExpressionTask
   CREATED_RESOLVED_UNIT10 [shape=box]
   CREATED_RESOLVED_UNIT11 [shape=box]
   CREATED_RESOLVED_UNIT2 [shape=box]
@@ -79,8 +82,6 @@
   EXPORTED_LIBRARIES -> ReadyLibraryElement2Task
   EXPORTED_LIBRARIES -> ReadyLibraryElement5Task
   EXPORTED_LIBRARIES -> ReadyLibraryElement6Task
-  EXPORTED_LIBRARIES -> ReadyResolvedUnit10Task
-  EXPORTED_LIBRARIES -> ReadyResolvedUnit11Task
   EXPORTED_LIBRARIES [shape=box]
   EXPORT_SOURCE_CLOSURE -> BuildExportNamespaceTask
   EXPORT_SOURCE_CLOSURE [shape=box]
@@ -96,8 +97,6 @@
   IMPORTED_LIBRARIES -> ReadyLibraryElement2Task
   IMPORTED_LIBRARIES -> ReadyLibraryElement5Task
   IMPORTED_LIBRARIES -> ReadyLibraryElement6Task
-  IMPORTED_LIBRARIES -> ReadyResolvedUnit10Task
-  IMPORTED_LIBRARIES -> ReadyResolvedUnit11Task
   IMPORTED_LIBRARIES -> ResolveUnitTypeNamesTask
   IMPORTED_LIBRARIES [shape=box]
   INCLUDED_PARTS -> BuildLibraryElementTask
@@ -158,14 +157,13 @@
   LIBRARY_ERRORS_READY [shape=box]
   LIBRARY_SPECIFIC_UNITS -> GenerateHintsTask
   LIBRARY_SPECIFIC_UNITS -> PropagateVariableTypesInLibraryTask
-  LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnit10Task
-  LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnit11Task
   LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnitTask
   LIBRARY_SPECIFIC_UNITS -> ResolveLibraryReferencesTask
   LIBRARY_SPECIFIC_UNITS -> ResolveLibraryTypeNamesTask
   LIBRARY_SPECIFIC_UNITS [shape=box]
   LIBRARY_UNIT_ERRORS -> dartErrorsForUnit
   LIBRARY_UNIT_ERRORS [shape=box]
+  LINE_INFO -> DartErrorsTask
   LINE_INFO -> ParseDartTask
   LINE_INFO [shape=box]
   LINTS -> LibraryUnitErrorsTask
@@ -175,6 +173,7 @@
   MODIFICATION_TIME -> ParseDartTask
   MODIFICATION_TIME [shape=box]
   PARSED_UNIT -> BuildCompilationUnitElementTask
+  PARSED_UNIT -> DartErrorsTask
   PARSED_UNIT [shape=box]
   PARSE_ERRORS -> dartErrorsForSource
   PARSE_ERRORS [shape=box]
@@ -215,10 +214,6 @@
   READY_RESOLVED_UNIT -> ResolveLibraryTask
   READY_RESOLVED_UNIT -> VerifyUnitTask
   READY_RESOLVED_UNIT [shape=box]
-  READY_RESOLVED_UNIT10 -> ReadyResolvedUnit10Task
-  READY_RESOLVED_UNIT10 [shape=box]
-  READY_RESOLVED_UNIT11 -> ReadyResolvedUnit11Task
-  READY_RESOLVED_UNIT11 [shape=box]
   REFERENCED_NAMES [shape=box]
   RESOLVED_UNIT -> GenerateHintsTask
   RESOLVED_UNIT -> GenerateLintsTask
@@ -229,14 +224,11 @@
   RESOLVED_UNIT1 -> BuildEnumMemberElementsTask
   RESOLVED_UNIT1 -> BuildLibraryElementTask
   RESOLVED_UNIT1 [shape=box]
-  RESOLVED_UNIT10 -> ComputeConstantDependenciesTask
   RESOLVED_UNIT10 -> EvaluateUnitConstantsTask
   RESOLVED_UNIT10 -> GatherUsedImportedElementsTask
   RESOLVED_UNIT10 -> GatherUsedLocalElementsTask
-  RESOLVED_UNIT10 -> ReadyResolvedUnit10Task
   RESOLVED_UNIT10 -> ResolveLibraryReferencesTask
   RESOLVED_UNIT10 [shape=box]
-  RESOLVED_UNIT11 -> ReadyResolvedUnit11Task
   RESOLVED_UNIT11 -> StrongModeVerifyUnitTask
   RESOLVED_UNIT11 [shape=box]
   RESOLVED_UNIT2 -> ResolveUnitTypeNamesTask
@@ -268,9 +260,8 @@
   ReadyLibraryElement2Task -> READY_LIBRARY_ELEMENT2
   ReadyLibraryElement5Task -> READY_LIBRARY_ELEMENT5
   ReadyLibraryElement6Task -> READY_LIBRARY_ELEMENT6
-  ReadyResolvedUnit10Task -> READY_RESOLVED_UNIT10
-  ReadyResolvedUnit11Task -> READY_RESOLVED_UNIT11
   ReadyResolvedUnitTask -> READY_RESOLVED_UNIT
+  ResolveConstantExpressionTask -> CONSTANT_EXPRESSION_RESOLVED
   ResolveInstanceFieldsInUnitTask -> CREATED_RESOLVED_UNIT8
   ResolveInstanceFieldsInUnitTask -> RESOLVED_UNIT8
   ResolveLibraryReferencesTask -> LIBRARY_ELEMENT8
diff --git a/pkg/analyzer_cli/bin/analyzer.dart b/pkg/analyzer_cli/bin/analyzer.dart
index b0a32fe..3172b0f 100644
--- a/pkg/analyzer_cli/bin/analyzer.dart
+++ b/pkg/analyzer_cli/bin/analyzer.dart
@@ -3,14 +3,10 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:analyzer_cli/src/driver.dart';
+import 'package:analyzer_cli/starter.dart';
 
-
-
-
-/// The entry point for the analyzer.
+/// The entry point for the command-line analyzer.
 void main(List<String> args) {
-  var starter = new Driver();
+  CommandLineStarter starter = new CommandLineStarter();
   starter.start(args);
-  
 }
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
index 75cbe52..56eaa2f 100644
--- a/pkg/analyzer_cli/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -224,35 +224,8 @@
     formatter.formatErrors(errorInfos);
   }
 
-  /// Check various configuration options to get a desired severity for this
-  /// [error] (or `null` if it's to be suppressed).
-  ProcessedSeverity _processError(AnalysisError error) {
-    ErrorSeverity severity = computeSeverity(error, options, context);
-    bool isOverridden = false;
-
-    // First check for a filter.
-    if (severity == null) {
-      // Null severity means the error has been explicitly ignored.
-      return null;
-    } else {
-      isOverridden = true;
-    }
-
-    // If not overridden, some "natural" severities get globally filtered.
-    if (!isOverridden) {
-      // Check for global hint filtering.
-      if (severity == ErrorSeverity.INFO && options.disableHints) {
-        return null;
-      }
-
-      // Skip TODOs.
-      if (severity == ErrorType.TODO) {
-        return null;
-      }
-    }
-
-    return new ProcessedSeverity(severity, isOverridden);
-  }
+  ProcessedSeverity _processError(AnalysisError error) =>
+      processError(error, options, context);
 
   LibraryElement _resolveLibrary() {
     return _resolveLibraryTag.makeCurrentWhile(() {
@@ -303,6 +276,37 @@
     // Not found.
     return null;
   }
+
+  /// Check various configuration options to get a desired severity for this
+  /// [error] (or `null` if it's to be suppressed).
+  static ProcessedSeverity processError(AnalysisError error,
+      CommandLineOptions options, AnalysisContext context) {
+    ErrorSeverity severity = computeSeverity(error, options, context);
+    bool isOverridden = false;
+
+    // First check for a filter.
+    if (severity == null) {
+      // Null severity means the error has been explicitly ignored.
+      return null;
+    } else {
+      isOverridden = true;
+    }
+
+    // If not overridden, some "natural" severities get globally filtered.
+    if (!isOverridden) {
+      // Check for global hint filtering.
+      if (severity == ErrorSeverity.INFO && options.disableHints) {
+        return null;
+      }
+
+      // Skip TODOs.
+      if (severity == ErrorType.TODO) {
+        return null;
+      }
+    }
+
+    return new ProcessedSeverity(severity, isOverridden);
+  }
 }
 
 /// This [Logger] prints out information comments to [outSink] and error messages
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 0b6ae40..85c53ee 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -10,8 +10,11 @@
 
 import 'package:analyzer/file_system/file_system.dart' as fileSystem;
 import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/plugin/embedded_resolver_provider.dart';
 import 'package:analyzer/plugin/options.dart';
+import 'package:analyzer/plugin/resolver_provider.dart';
 import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/source/embedder.dart';
 import 'package:analyzer/source/package_map_provider.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/source/pub_package_map_provider.dart';
@@ -31,7 +34,9 @@
 import 'package:analyzer/src/task/options.dart';
 import 'package:analyzer_cli/src/analyzer_impl.dart';
 import 'package:analyzer_cli/src/options.dart';
+import 'package:analyzer_cli/src/package_analyzer.dart';
 import 'package:analyzer_cli/src/perf_report.dart';
+import 'package:analyzer_cli/starter.dart';
 import 'package:linter/src/plugin/linter_plugin.dart';
 import 'package:package_config/discovery.dart' as pkgDiscovery;
 import 'package:package_config/packages.dart' show Packages;
@@ -60,7 +65,7 @@
 
 typedef ErrorSeverity _BatchRunnerHandler(List<String> args);
 
-class Driver {
+class Driver implements CommandLineStarter {
   static final PerformanceTag _analyzeAllTag =
       new PerformanceTag("Driver._analyzeAll");
 
@@ -78,17 +83,23 @@
   /// creation.
   CommandLineOptions _previousOptions;
 
+  @override
+  EmbeddedResolverProvider embeddedUriResolverProvider;
+
+  @override
+  ResolverProvider packageResolverProvider;
+
   /// This Driver's current analysis context.
   ///
   /// *Visible for testing.*
   AnalysisContext get context => _context;
 
-  /// Set the [plugins] that are defined outside the `analyzer_cli` package.
+  @override
   void set userDefinedPlugins(List<Plugin> plugins) {
     _userDefinedPlugins = plugins == null ? <Plugin>[] : plugins;
   }
 
-  /// Use the given command-line [args] to start this analysis driver.
+  @override
   void start(List<String> args) {
     int startTime = new DateTime.now().millisecondsSinceEpoch;
 
@@ -103,7 +114,13 @@
     _setupEnv(options);
 
     // Do analysis.
-    if (_isBatch) {
+    if (options.packageMode) {
+      ErrorSeverity severity = _analyzePackage(options);
+      // In case of error propagate exit code.
+      if (severity == ErrorSeverity.ERROR) {
+        exitCode = severity.ordinal;
+      }
+    } else if (_isBatch) {
       _BatchRunner.runAsBatch(args, (List<String> args) {
         CommandLineOptions options = CommandLineOptions.parse(args);
         return _analyzeAll(options);
@@ -205,6 +222,13 @@
     return allResult;
   }
 
+  /// Perform package analysis according to the given [options].
+  ErrorSeverity _analyzePackage(CommandLineOptions options) {
+    return _analyzeAllTag.makeCurrentWhile(() {
+      return new PackageAnalyzer(options).analyze();
+    });
+  }
+
   /// Determine whether the context created during a previous call to
   /// [_analyzeAll] can be re-used in order to analyze using [options].
   bool _canContextBeReused(CommandLineOptions options) {
@@ -280,7 +304,9 @@
       packagesRequiringFullParse = null;
     }
     return (Source source) {
-      if (source.uri.scheme == 'dart') {
+      if (options.sourceFiles.contains(source.fullName)) {
+        return true;
+      } else if (source.uri.scheme == 'dart') {
         return options.showSdkWarnings;
       } else if (source.uri.scheme == 'package') {
         if (packagesRequiringFullParse == null) {
@@ -302,11 +328,41 @@
   /// Decide on the appropriate method for resolving URIs based on the given
   /// [options] and [customUrlMappings] settings, and return a
   /// [SourceFactory] that has been configured accordingly.
-  SourceFactory _chooseUriResolutionPolicy(CommandLineOptions options) {
+  SourceFactory _chooseUriResolutionPolicy(
+      CommandLineOptions options, EmbedderYamlLocator yamlLocator) {
     Packages packages;
     Map<String, List<fileSystem.Folder>> packageMap;
     UriResolver packageUriResolver;
 
+    // Create a custom package resolver if one has been specified.
+    if (packageResolverProvider != null) {
+      fileSystem.Folder folder =
+          PhysicalResourceProvider.INSTANCE.getResource('.');
+      UriResolver resolver = packageResolverProvider(folder);
+      if (resolver != null) {
+        UriResolver sdkResolver;
+
+        // Check for a resolver provider.
+        if (embeddedUriResolverProvider != null) {
+          EmbedderUriResolver embedderUriResolver =
+              embeddedUriResolverProvider(folder);
+          if (embedderUriResolver != null && embedderUriResolver.length != 0) {
+            sdkResolver = embedderUriResolver;
+          }
+        }
+
+        // Default to a Dart URI resolver if no embedder is found.
+        sdkResolver ??= new DartUriResolver(sdk);
+
+        // TODO(brianwilkerson) This doesn't sdk extensions.
+        List<UriResolver> resolvers = <UriResolver>[
+          sdkResolver,
+          resolver,
+          new FileUriResolver()
+        ];
+        return new SourceFactory(resolvers);
+      }
+    }
     // Process options, caching package resolution details.
     if (options.packageConfigPath != null) {
       String packageConfigPath = options.packageConfigPath;
@@ -356,9 +412,24 @@
     }
 
     // Now, build our resolver list.
+    List<UriResolver> resolvers = [];
 
     // 'dart:' URIs come first.
-    List<UriResolver> resolvers = [new DartUriResolver(sdk)];
+
+    // Setup embedding.
+    yamlLocator.refresh(packageMap);
+
+    EmbedderUriResolver embedderUriResolver =
+        new EmbedderUriResolver(yamlLocator.embedderYamls);
+    if (embedderUriResolver.length == 0) {
+      // The embedder uri resolver has no mappings. Use the default Dart SDK
+      // uri resolver.
+      resolvers.add(new DartUriResolver(sdk));
+    } else {
+      // The embedder uri resolver has mappings, use it instead of the default
+      // Dart SDK uri resolver.
+      resolvers.add(embedderUriResolver);
+    }
 
     // Next SdkExts.
     if (packageMap != null) {
@@ -401,43 +472,24 @@
       return;
     }
     _previousOptions = options;
+
+    // Create a context.
+    AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+    _context = context;
+
     // Choose a package resolution policy and a diet parsing policy based on
     // the command-line options.
-    SourceFactory sourceFactory = _chooseUriResolutionPolicy(options);
+    SourceFactory sourceFactory = _chooseUriResolutionPolicy(
+        options, (context as InternalAnalysisContext).embedderYamlLocator);
     AnalyzeFunctionBodiesPredicate dietParsingPolicy =
         _chooseDietParsingPolicy(options);
-    // Create a context using these policies.
-    AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
 
     context.sourceFactory = sourceFactory;
 
-    Map<String, String> definedVariables = options.definedVariables;
-    if (!definedVariables.isEmpty) {
-      DeclaredVariables declaredVariables = context.declaredVariables;
-      definedVariables.forEach((String variableName, String value) {
-        declaredVariables.define(variableName, value);
-      });
-    }
-
-    if (options.log) {
-      AnalysisEngine.instance.logger = new StdLogger();
-    }
-
-    // Set context options.
-    AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl();
-    contextOptions.hint = !options.disableHints;
-    contextOptions.enableStrictCallChecks = options.enableStrictCallChecks;
-    contextOptions.enableSuperMixins = options.enableSuperMixins;
-    contextOptions.analyzeFunctionBodiesPredicate = dietParsingPolicy;
-    contextOptions.generateImplicitErrors = options.showPackageWarnings;
-    contextOptions.generateSdkErrors = options.showSdkWarnings;
-    contextOptions.lint = options.lints;
-    contextOptions.strongMode = options.strongMode;
-    context.analysisOptions = contextOptions;
-    _context = context;
-
-    // Process analysis options file (and notify all interested parties).
-    _processAnalysisOptions(options, context);
+    setAnalysisContextOptions(_context, options,
+        (AnalysisOptionsImpl contextOptions) {
+      contextOptions.analyzeFunctionBodiesPredicate = dietParsingPolicy;
+    });
   }
 
   /// Return discovered packagespec, or `null` if none is found.
@@ -454,22 +506,6 @@
     return null;
   }
 
-  fileSystem.File _getOptionsFile(CommandLineOptions options) {
-    fileSystem.File file;
-    String filePath = options.analysisOptionsFile;
-    if (filePath != null) {
-      file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
-      if (!file.exists) {
-        printAndFail('Options file not found: $filePath',
-            exitCode: ErrorSeverity.ERROR.ordinal);
-      }
-    } else {
-      filePath = AnalysisEngine.ANALYSIS_OPTIONS_FILE;
-      file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
-    }
-    return file;
-  }
-
   Map<String, List<fileSystem.Folder>> _getPackageMap(Packages packages) {
     if (packages == null) {
       return null;
@@ -485,34 +521,6 @@
     return folderMap;
   }
 
-  void _processAnalysisOptions(
-      CommandLineOptions options, AnalysisContext context) {
-    fileSystem.File file = _getOptionsFile(options);
-    List<OptionsProcessor> optionsProcessors =
-        AnalysisEngine.instance.optionsPlugin.optionsProcessors;
-    try {
-      AnalysisOptionsProvider analysisOptionsProvider =
-          new AnalysisOptionsProvider();
-      Map<String, YamlNode> optionMap =
-          analysisOptionsProvider.getOptionsFromFile(file);
-      optionsProcessors.forEach(
-          (OptionsProcessor p) => p.optionsProcessed(context, optionMap));
-
-      // Fill in lint rule defaults in case lints are enabled and rules are
-      // not specified in an options file.
-      if (options.lints && !containsLintRuleEntry(optionMap)) {
-        setLints(context, linterPlugin.contributedRules);
-      }
-
-      // Ask engine to further process options.
-      if (optionMap != null) {
-        configureContextOptions(context, optionMap);
-      }
-    } on Exception catch (e) {
-      optionsProcessors.forEach((OptionsProcessor p) => p.onError(e));
-    }
-  }
-
   void _processPlugins() {
     List<Plugin> plugins = <Plugin>[];
     plugins.addAll(AnalysisEngine.instance.requiredPlugins);
@@ -550,6 +558,41 @@
     _isBatch = options.shouldBatch;
   }
 
+  static void setAnalysisContextOptions(
+      AnalysisContext context,
+      CommandLineOptions options,
+      void configureContextOptions(AnalysisOptionsImpl contextOptions)) {
+    Map<String, String> definedVariables = options.definedVariables;
+    if (!definedVariables.isEmpty) {
+      DeclaredVariables declaredVariables = context.declaredVariables;
+      definedVariables.forEach((String variableName, String value) {
+        declaredVariables.define(variableName, value);
+      });
+    }
+
+    if (options.log) {
+      AnalysisEngine.instance.logger = new StdLogger();
+    }
+
+    // Prepare context options.
+    AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl();
+    contextOptions.hint = !options.disableHints;
+    contextOptions.enableStrictCallChecks = options.enableStrictCallChecks;
+    contextOptions.enableSuperMixins = options.enableSuperMixins;
+    contextOptions.generateImplicitErrors = options.showPackageWarnings;
+    contextOptions.generateSdkErrors = options.showSdkWarnings;
+    contextOptions.lint = options.lints;
+    contextOptions.strongMode = options.strongMode;
+    configureContextOptions(contextOptions);
+
+    // Set context options.
+    context.analysisOptions = contextOptions;
+    context.sourceFactory.dartSdk.context.analysisOptions = contextOptions;
+
+    // Process analysis options file (and notify all interested parties).
+    _processAnalysisOptions(context, options);
+  }
+
   /// Perform a deep comparison of two string maps.
   static bool _equalMaps(Map<String, String> m1, Map<String, String> m2) {
     if (m1.length != m2.length) {
@@ -563,9 +606,53 @@
     return true;
   }
 
+  static fileSystem.File _getOptionsFile(CommandLineOptions options) {
+    fileSystem.File file;
+    String filePath = options.analysisOptionsFile;
+    if (filePath != null) {
+      file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+      if (!file.exists) {
+        printAndFail('Options file not found: $filePath',
+            exitCode: ErrorSeverity.ERROR.ordinal);
+      }
+    } else {
+      filePath = AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+      file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+    }
+    return file;
+  }
+
   /// Convert [sourcePath] into an absolute path.
   static String _normalizeSourcePath(String sourcePath) =>
       path.normalize(new File(sourcePath).absolute.path);
+
+  static void _processAnalysisOptions(
+      AnalysisContext context, CommandLineOptions options) {
+    fileSystem.File file = _getOptionsFile(options);
+    List<OptionsProcessor> optionsProcessors =
+        AnalysisEngine.instance.optionsPlugin.optionsProcessors;
+    try {
+      AnalysisOptionsProvider analysisOptionsProvider =
+          new AnalysisOptionsProvider();
+      Map<String, YamlNode> optionMap =
+          analysisOptionsProvider.getOptionsFromFile(file);
+      optionsProcessors.forEach(
+          (OptionsProcessor p) => p.optionsProcessed(context, optionMap));
+
+      // Fill in lint rule defaults in case lints are enabled and rules are
+      // not specified in an options file.
+      if (options.lints && !containsLintRuleEntry(optionMap)) {
+        setLints(context, linterPlugin.contributedRules);
+      }
+
+      // Ask engine to further process options.
+      if (optionMap != null) {
+        configureContextOptions(context, optionMap);
+      }
+    } on Exception catch (e) {
+      optionsProcessors.forEach((OptionsProcessor p) => p.onError(e));
+    }
+  }
 }
 
 /// Provides a framework to read command line options from stdin and feed them
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index 2bc48b9..732fc63 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -74,6 +74,21 @@
   /// Whether to use machine format for error display
   final bool machineFormat;
 
+  /// Whether to use the whole package analysis mode.
+  final bool packageMode;
+
+  /// The path of the root folder of the package to analyze.
+  final String packageModePath;
+
+  /// The name of the package being analyzed.
+  final String packageName;
+
+  /// Mapping of package names to package summary file paths.
+  final Map<String, String> packageSummaryInputs;
+
+  /// The path to find the package summary.
+  final String packageSummaryOutput;
+
   /// The path to the package root
   final String packageRootPath;
 
@@ -106,7 +121,7 @@
   CommandLineOptions._fromArgs(
       ArgResults args, Map<String, String> definedVariables)
       : dartSdkPath = args['dart-sdk'],
-        this.definedVariables = definedVariables,
+        definedVariables = definedVariables,
         analysisOptionsFile = args['options'],
         disableHints = args['no-hints'],
         displayVersion = args['version'],
@@ -119,6 +134,11 @@
         lints = args['lints'],
         log = args['log'],
         machineFormat = args['machine'] || args['format'] == 'machine',
+        packageMode = args['package-mode'],
+        packageModePath = args['package-mode-path'],
+        packageName = args['package-name'],
+        packageSummaryInputs = _parsePackageSummaryInputs(args),
+        packageSummaryOutput = args['package-summary-output'],
         packageConfigPath = args['packages'],
         packageRootPath = args['package-root'],
         perfReport = args['x-perf-report'],
@@ -267,6 +287,33 @@
           allowMultiple: true,
           splitCommas: false)
       //
+      // Package analysis mode and summary.
+      //
+      ..addFlag('package-mode',
+          help: 'Enable the whole package analysis mode. '
+              'Exactly one input path must be specified, which must be a path '
+              'to the folder with a Pub package.',
+          defaultsTo: false,
+          negatable: false,
+          hide: true)
+      ..addOption('package-mode-path',
+          help: 'The path of the root folder of the package to analyze.',
+          hide: true)
+      ..addOption('package-name',
+          help: 'The name of the package to analyze, as it is used by clients.',
+          hide: true)
+      ..addOption('package-summary-input',
+          help: '--package-summary-input=packageName,/path/to/package.sum '
+              'specifies the summary file that contains information about '
+              'every library of the specified package.',
+          allowMultiple: true,
+          splitCommas: false,
+          hide: true)
+      ..addOption('package-summary-output',
+          help: 'Specifies the path to the file where the summary information '
+              'about the package should be written to.',
+          hide: true)
+      //
       // Hidden flags.
       //
       ..addFlag('enable-async',
@@ -352,6 +399,27 @@
     }
   }
 
+  /// Parse the `--package-summary-input` arguments into a Map of package
+  /// names to summary paths.
+  static Map<String, String> _parsePackageSummaryInputs(ArgResults args) {
+    Map<String, String> result = <String, String>{};
+    List<String> argList = args['package-summary-input'];
+    for (String arg in argList) {
+      int index = arg.indexOf(',');
+      if (index == -1) {
+        errorSink.writeln(
+            'The syntax is --package-summary-input=packageName,/path/to/pkg.sum');
+        errorSink.writeln('No comma found in: $arg');
+        exitHandler(15);
+        return null; // Only reachable in testing.
+      }
+      String packageName = arg.substring(0, index);
+      String summaryPath = arg.substring(index + 1);
+      result[packageName] = summaryPath;
+    }
+    return result;
+  }
+
   static _showUsage(parser) {
     errorSink
         .writeln('Usage: $_binaryName [options...] <libraries to analyze...>');
@@ -409,7 +477,8 @@
       String defaultsTo,
       void callback(value),
       bool allowMultiple: false,
-      bool splitCommas}) {
+      bool splitCommas,
+      bool hide: false}) {
     _knownFlags.add(name);
     _parser.addOption(name,
         abbr: abbr,
@@ -419,7 +488,8 @@
         defaultsTo: defaultsTo,
         callback: callback,
         allowMultiple: allowMultiple,
-        splitCommas: splitCommas);
+        splitCommas: splitCommas,
+        hide: hide);
   }
 
   /// Generates a string displaying usage information for the defined options.
diff --git a/pkg/analyzer_cli/lib/src/package_analyzer.dart b/pkg/analyzer_cli/lib/src/package_analyzer.dart
new file mode 100644
index 0000000..746c77a
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/package_analyzer.dart
@@ -0,0 +1,183 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.package_analyzer;
+
+import 'dart:core' hide Resource;
+import 'dart:io' as io;
+
+import 'package:analyzer/dart/element/element.dart';
+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/generated/engine.dart';
+import 'package:analyzer/src/generated/error.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/package_bundle_reader.dart';
+import 'package:analyzer/src/summary/summarize_elements.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:path/path.dart' as pathos;
+
+/**
+ * The hermetic whole package analyzer.
+ */
+class PackageAnalyzer {
+  final CommandLineOptions options;
+
+  String packagePath;
+  String packageLibPath;
+
+  final ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
+  InternalAnalysisContext context;
+  final List<Source> explicitSources = <Source>[];
+
+  PackageAnalyzer(this.options);
+
+  /**
+   * Perform package analysis according to the given [options].
+   */
+  ErrorSeverity analyze() {
+    packagePath = options.packageModePath;
+    packageLibPath = resourceProvider.pathContext.join(packagePath, 'lib');
+    if (packageLibPath == null) {
+      errorSink.writeln('--package-mode-path must be set to the root '
+          'folder of the package to analyze.');
+      io.exitCode = ErrorSeverity.ERROR.ordinal;
+      return ErrorSeverity.ERROR;
+    }
+
+    // Write the progress message.
+    if (!options.machineFormat) {
+      outSink.writeln("Analyzing sources ${options.sourceFiles}...");
+    }
+
+    // Prepare the analysis context.
+    _createContext();
+
+    // Add sources.
+    ChangeSet changeSet = new ChangeSet();
+    for (String path in options.sourceFiles) {
+      if (AnalysisEngine.isDartFileName(path)) {
+        path = resourceProvider.pathContext.absolute(path);
+        File file = resourceProvider.getFile(path);
+        if (!file.exists) {
+          errorSink.writeln('File not found: $path');
+          io.exitCode = ErrorSeverity.ERROR.ordinal;
+          return ErrorSeverity.ERROR;
+        }
+        Source source = _createSourceInContext(file);
+        explicitSources.add(source);
+        changeSet.addedSource(source);
+      }
+    }
+    context.applyChanges(changeSet);
+
+    // Perform full analysis.
+    while (true) {
+      AnalysisResult analysisResult = context.performAnalysisTask();
+      if (!analysisResult.hasMoreWork) {
+        break;
+      }
+    }
+
+    // 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) {
+            assembler.serializeLibraryElement(libraryElement);
+          }
+        }
+      }
+      // Write the whole package bundle.
+      PackageBundleBuilder sdkBundle = assembler.assemble();
+      io.File file = new io.File(options.packageSummaryOutput);
+      file.writeAsBytesSync(sdkBundle.toBuffer(), mode: io.FileMode.WRITE_ONLY);
+    }
+
+    // Process errors.
+    _printErrors();
+    return _computeMaxSeverity();
+  }
+
+  ErrorSeverity _computeMaxSeverity() {
+    ErrorSeverity maxSeverity = ErrorSeverity.NONE;
+    for (Source source in explicitSources) {
+      AnalysisErrorInfo errorInfo = context.getErrors(source);
+      for (AnalysisError error in errorInfo.errors) {
+        ProcessedSeverity processedSeverity =
+            AnalyzerImpl.processError(error, options, context);
+        if (processedSeverity != null) {
+          maxSeverity = maxSeverity.max(processedSeverity.severity);
+        }
+      }
+    }
+    return maxSeverity;
+  }
+
+  void _createContext() {
+    DirectoryBasedDartSdk sdk =
+        new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
+
+    // Create the context.
+    context = AnalysisEngine.instance.createAnalysisContext();
+    context.sourceFactory = new SourceFactory(<UriResolver>[
+      new DartUriResolver(sdk),
+      new InSummaryPackageUriResolver(options.packageSummaryInputs),
+      new PackageMapUriResolver(resourceProvider, <String, List<Folder>>{
+        options.packageName: <Folder>[
+          resourceProvider.getFolder(packageLibPath)
+        ],
+      }),
+      new FileUriResolver()
+    ]);
+
+    // Set context options.
+    Driver.setAnalysisContextOptions(
+        context, options, (AnalysisOptionsImpl contextOptions) {});
+
+    // Configure using summaries.
+    sdk.useSummary = true;
+    context.typeProvider = sdk.context.typeProvider;
+    context.resultProvider =
+        new InputPackagesResultProvider(context, options.packageSummaryInputs);
+  }
+
+  /**
+   * Create and return a source representing the given [file].
+   */
+  Source _createSourceInContext(File file) {
+    Source source = file.createSource();
+    if (context == null) {
+      return source;
+    }
+    Uri uri = context.sourceFactory.restoreUri(source);
+    return file.createSource(uri);
+  }
+
+  /**
+   * Print errors for all explicit sources.
+   */
+  void _printErrors() {
+    StringSink sink = options.machineFormat ? errorSink : outSink;
+    ErrorFormatter formatter = new ErrorFormatter(
+        sink,
+        options,
+        (AnalysisError error) =>
+            AnalyzerImpl.processError(error, options, context));
+    for (Source source in explicitSources) {
+      AnalysisErrorInfo errorInfo = context.getErrors(source);
+      formatter.formatErrors([errorInfo]);
+    }
+  }
+}
diff --git a/pkg/analyzer_cli/lib/starter.dart b/pkg/analyzer_cli/lib/starter.dart
new file mode 100644
index 0000000..e42d39a
--- /dev/null
+++ b/pkg/analyzer_cli/lib/starter.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.starter;
+
+import 'package:analyzer/plugin/embedded_resolver_provider.dart';
+import 'package:analyzer/plugin/resolver_provider.dart';
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:plugin/plugin.dart';
+
+/**
+ * An object that can be used to start a command-line analysis. This class
+ * exists so that clients can configure a command-line analyzer before starting
+ * it.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class CommandLineStarter {
+  /**
+   * Initialize a newly created starter to start up a command-line analysis.
+   */
+  factory CommandLineStarter() = Driver;
+
+  /**
+   * Set the embedded resolver provider used to override the way embedded
+   * library URI's are resolved in some contexts. The provider should return
+   * `null` if the embedded library URI resolution scheme should be used
+   * instead.
+   */
+  void set embeddedUriResolverProvider(EmbeddedResolverProvider provider);
+
+  /**
+   * Set the package resolver provider used to override the way package URI's
+   * are resolved in some contexts. The provider should return `null` if the
+   * default package resolution scheme should be used instead.
+   */
+  void set packageResolverProvider(ResolverProvider provider);
+
+  /**
+   * Set the [plugins] that are defined outside the analyzer_cli package.
+   */
+  void set userDefinedPlugins(List<Plugin> plugins);
+
+  /**
+   * Use the given command-line [arguments] to start this analyzer.
+   */
+  void start(List<String> arguments);
+}
diff --git a/pkg/analyzer_cli/pubspec.yaml b/pkg/analyzer_cli/pubspec.yaml
index 0fe04f6..6e59161 100644
--- a/pkg/analyzer_cli/pubspec.yaml
+++ b/pkg/analyzer_cli/pubspec.yaml
@@ -14,5 +14,6 @@
   plugin: ^0.1.0
   yaml: ^2.1.2
 dev_dependencies:
+  test_reflective_loader: '>=0.0.3 <0.1.0'
   typed_mock: '>=0.0.4 <1.0.0'
   unittest: '>=0.9.0 <0.12.0'
diff --git a/pkg/analyzer_cli/test/data/embedder_client/_packages b/pkg/analyzer_cli/test/data/embedder_client/_packages
new file mode 100644
index 0000000..03ed0f7
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/embedder_client/_packages
@@ -0,0 +1 @@
+package_with_embedder_yaml:../package_with_embedder_yaml/lib/
diff --git a/pkg/analyzer_cli/test/data/embedder_client/embedder_yaml_user.dart b/pkg/analyzer_cli/test/data/embedder_client/embedder_yaml_user.dart
new file mode 100644
index 0000000..2d88a2a
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/embedder_client/embedder_yaml_user.dart
@@ -0,0 +1,9 @@
+// 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:bear'; // Defined in package_with_embedder_yaml/lib/_embedder.yaml
+
+main() {
+  print(new Bear()); // Defined in 'dart:bear'
+}
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/_embedder.yaml b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/_embedder.yaml
new file mode 100644
index 0000000..64fc9ed
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/_embedder.yaml
@@ -0,0 +1,4 @@
+embedded_libs:
+  "dart:bear": "grizzly.dart"
+  "dart:core": "core.dart"
+  "dart:async": "async.dart"
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart
new file mode 100644
index 0000000..3b69a2a
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/async.dart
@@ -0,0 +1,9 @@
+// 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 dart.async;
+
+abstract class Future<T> {}
+
+abstract class Stream<T> {}
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/core.dart b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/core.dart
new file mode 100644
index 0000000..a7fa657
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/core.dart
@@ -0,0 +1,106 @@
+// 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 dart.core;
+
+class Object {
+  bool operator ==(other) => identical(this, other);
+  String toString() => 'a string';
+  int get hashCode => 0;
+}
+
+class Function {}
+
+class StackTrace {}
+
+class Symbol {}
+
+class Type {}
+
+abstract class Comparable<T> {
+  int compareTo(T other);
+}
+
+abstract class String implements Comparable<String> {
+  external factory String.fromCharCodes(Iterable<int> charCodes,
+      [int start = 0, int end]);
+  bool get isEmpty => false;
+  bool get isNotEmpty => false;
+  int get length => 0;
+  String toUpperCase();
+  List<int> get codeUnits;
+}
+
+class bool extends Object {}
+
+abstract class num implements Comparable<num> {
+  bool operator <(num other);
+  bool operator <=(num other);
+  bool operator >(num other);
+  bool operator >=(num other);
+  num operator +(num other);
+  num operator -(num other);
+  num operator *(num other);
+  num operator %(num other);
+  num operator /(num other);
+  int toInt();
+  num abs();
+  int round();
+}
+
+abstract class int extends num {
+  bool get isEven => false;
+  int operator -();
+  external static int parse(String source,
+      {int radix, int onError(String source)});
+}
+
+class double extends num {}
+
+class DateTime extends Object {}
+
+class Null extends Object {}
+
+class Deprecated extends Object {
+  final String expires;
+  const Deprecated(this.expires);
+}
+
+const Object deprecated = const Deprecated("next release");
+
+class Iterator<E> {
+  bool moveNext();
+  E get current;
+}
+
+abstract class Iterable<E> {
+  Iterator<E> get iterator;
+  bool get isEmpty;
+}
+
+abstract class List<E> implements Iterable<E> {
+  void add(E value);
+  E operator [](int index);
+  void operator []=(int index, E value);
+  Iterator<E> get iterator => null;
+  void clear();
+}
+
+abstract class Map<K, V> extends Object {
+  bool containsKey(Object key);
+  Iterable<K> get keys;
+}
+
+external bool identical(Object a, Object b);
+
+void print(Object object) {}
+
+class Uri {
+  static List<int> parseIPv6Address(String host, [int start = 0, int end]) {
+    int parseHex(int start, int end) {
+      return 0;
+    }
+    return null;
+  }
+}
diff --git a/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/grizzly.dart b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/grizzly.dart
new file mode 100644
index 0000000..d575643
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_embedder_yaml/lib/grizzly.dart
@@ -0,0 +1,7 @@
+// 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 grizzly;
+
+class Bear {}
diff --git a/pkg/analyzer_cli/test/embedder_test.dart b/pkg/analyzer_cli/test/embedder_test.dart
new file mode 100644
index 0000000..ded83fd
--- /dev/null
+++ b/pkg/analyzer_cli/test/embedder_test.dart
@@ -0,0 +1,64 @@
+// 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:io';
+
+import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+main() {
+  initializeTestEnvironment();
+
+  group('_embedder.yaml', () {
+    StringSink savedOutSink, savedErrorSink;
+    int savedExitCode;
+
+    setUp(() {
+      savedOutSink = outSink;
+      savedErrorSink = errorSink;
+      savedExitCode = exitCode;
+      outSink = new StringBuffer();
+      errorSink = new StringBuffer();
+    });
+    tearDown(() {
+      outSink = savedOutSink;
+      errorSink = savedErrorSink;
+      exitCode = savedExitCode;
+    });
+
+    test('resolution', wrap(() {
+      var testDir = path.join(testDirectory, 'data', 'embedder_client');
+      new Driver().start([
+        '--packages',
+        path.join(testDir, '_packages'),
+        path.join(testDir, 'embedder_yaml_user.dart')
+      ]);
+
+      expect(exitCode, 0);
+      expect(outSink.toString(), contains('No issues found'));
+    }));
+  });
+}
+
+/// Wrap a function call to dump stdout and stderr in case of an exception.
+Function wrap(Function f) {
+  return () {
+    try {
+      f();
+    } catch (e) {
+      if (outSink.toString().isNotEmpty) {
+        print('stdout:');
+        print(outSink);
+      }
+      if (errorSink.toString().isNotEmpty) {
+        print('stderr:');
+        print(errorSink);
+      }
+      throw e;
+    }
+  };
+}
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
index 900747b..1c6aa76 100644
--- a/pkg/analyzer_cli/test/options_test.dart
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -4,8 +4,12 @@
 
 library analyzer_cli.test.options;
 
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart';
 import 'package:analyzer_cli/src/options.dart';
 import 'package:args/args.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
 main() {
@@ -26,7 +30,9 @@
         expect(options.ignoreUnrecognizedFlags, isFalse);
         expect(options.log, isFalse);
         expect(options.machineFormat, isFalse);
+        expect(options.packageMode, isFalse);
         expect(options.packageRootPath, isNull);
+        expect(options.packageSummaryInputs, isEmpty);
         expect(options.shouldBatch, isFalse);
         expect(options.showPackageWarnings, isFalse);
         expect(options.showSdkWarnings, isFalse);
@@ -165,8 +171,8 @@
       });
 
       test('strong mode', () {
-        CommandLineOptions options = CommandLineOptions
-            .parse(['--strong', 'foo.dart']);
+        CommandLineOptions options =
+            CommandLineOptions.parse(['--strong', 'foo.dart']);
         expect(options.strongMode, isTrue);
       });
 
@@ -187,4 +193,85 @@
       });
     });
   });
+  defineReflectiveTests(CommandLineOptionsTest);
+}
+
+@reflectiveTest
+class AbstractStatusTest {
+  int lastExitHandlerCode;
+  StringBuffer outStringBuffer = new StringBuffer();
+  StringBuffer errorStringBuffer = new StringBuffer();
+
+  StringSink savedOutSink, savedErrorSink;
+  int savedExitCode;
+  ExitHandler savedExitHandler;
+
+  setUp() {
+    savedOutSink = outSink;
+    savedErrorSink = errorSink;
+    savedExitHandler = exitHandler;
+    savedExitCode = exitCode;
+    exitHandler = (int code) {
+      lastExitHandlerCode = code;
+    };
+    outSink = outStringBuffer;
+    errorSink = errorStringBuffer;
+  }
+
+  tearDown() {
+    outSink = savedOutSink;
+    errorSink = savedErrorSink;
+    exitCode = savedExitCode;
+    exitHandler = savedExitHandler;
+  }
+}
+
+@reflectiveTest
+class CommandLineOptionsTest extends AbstractStatusTest {
+  CommandLineOptions options;
+
+  test_packageMode() {
+    _parse(['--package-mode', '/path/to/pkg']);
+    expect(options.packageMode, isTrue);
+    print(options.packageSummaryInputs);
+  }
+
+  test_packageSummaryInput() {
+    _parse([
+      '--package-mode',
+      '--package-summary-input=aaa,/path/to/aaa.sum',
+      '--package-summary-input=long.package.bbb,/path/to/bbb.sum',
+      '/path/to/pkg'
+    ]);
+    expect(options.packageMode, isTrue);
+    Map<String, String> map = options.packageSummaryInputs;
+    expect(map, hasLength(2));
+    expect(map, containsPair('aaa', '/path/to/aaa.sum'));
+    expect(map, containsPair('long.package.bbb', '/path/to/bbb.sum'));
+  }
+
+  test_packageSummaryInput_noComma() {
+    _parse([
+      '--package-mode',
+      '--package-summary-input=noCommaInMapping',
+      '/path/to/pkg'
+    ]);
+    expect(lastExitHandlerCode, 15);
+    expect(errorStringBuffer.toString(), contains('--package-summary-input'));
+    expect(errorStringBuffer.toString(), contains('noCommaInMapping'));
+  }
+
+  test_packageSummaryOutput() {
+    _parse([
+      '--package-mode',
+      '--package-summary-output=/path/to/output.sum',
+      '/path/to/pkg'
+    ]);
+    expect(options.packageMode, isTrue);
+    expect(options.packageSummaryOutput, '/path/to/output.sum');
+  }
+
+  void _parse(List<String> args) {
+    options = CommandLineOptions.parse(args);
+  }
 }
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 8f81d15..73bbc60 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -33,6 +33,14 @@
 const bool forceIncrementalSupport =
     const bool.fromEnvironment('DART2JS_EXPERIMENTAL_INCREMENTAL_SUPPORT');
 
+/// For every 'dart:' library, a corresponding environment variable is set
+/// to "true". The environment variable's name is the concatenation of
+/// this prefix and the name (without the 'dart:'.
+///
+/// For example 'dart:html' has the environment variable 'dart.library.html' set
+/// to "true".
+const String dartLibraryEnvironmentPrefix = 'dart.library.';
+
 /// Locations of the platform descriptor files relative to the library root.
 const String _clientPlatform = "lib/dart_client.platform";
 const String _serverPlatform = "lib/dart_server.platform";
@@ -580,7 +588,30 @@
     }
   }
 
-  fromEnvironment(String name) => environment[name];
+  fromEnvironment(String name) {
+    assert(invariant(NO_LOCATION_SPANNABLE,
+        sdkLibraries != null, message: "setupSdk() has not been run"));
+
+    var result = environment[name];
+    if (result != null || environment.containsKey(name)) return result;
+    if (!name.startsWith(dartLibraryEnvironmentPrefix)) return null;
+
+    String libraryName = name.substring(dartLibraryEnvironmentPrefix.length);
+
+    // Private libraries are not exposed to the users.
+    if (libraryName.startsWith("_")) return null;
+
+    if (sdkLibraries.containsKey(libraryName)) {
+      // Dart2js always "supports" importing 'dart:mirrors' but will abort
+      // the compilation at a later point if the backend doesn't support
+      // mirrors. In this case 'mirrors' should not be in the environment.
+      if (libraryName == 'mirrors') {
+        return backend.supportsReflection ? "true" : null;
+      }
+      return "true";
+    }
+    return null;
+  }
 
   Uri lookupLibraryUri(String libraryName) {
     assert(invariant(NO_LOCATION_SPANNABLE,
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index d2fa5ec..3063616 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -31,7 +31,8 @@
     Element,
     FunctionElement,
     LibraryElement,
-    MetadataAnnotation;
+    MetadataAnnotation,
+    MethodElement;
 import '../enqueue.dart' show
     Enqueuer,
     CodegenEnqueuer,
@@ -282,9 +283,9 @@
     return native.maybeEnableNative(compiler, library);
   }
 
-  /// Processes [element] for resolution and returns the [FunctionElement] that
+  /// Processes [element] for resolution and returns the [MethodElement] that
   /// defines the implementation of [element].
-  FunctionElement resolveExternalFunction(FunctionElement element) => element;
+  MethodElement resolveExternalFunction(MethodElement element) => element;
 
   /// Returns `true` if [library] is a backend specific library whose members
   /// have special treatment, such as being allowed to extends blacklisted
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 53be699..3df2ba4 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -1073,6 +1073,8 @@
       dumpInfoTask.dumpInfo();
     }
 
+    backend.sourceInformationStrategy.onComplete();
+
     checkQueues();
   }
 
@@ -1793,6 +1795,17 @@
       uri = currentElement.compilationUnit.script.resourceUri;
       assert(invariant(currentElement, () {
 
+        bool sameToken(Token token, Token sought) {
+          if (token == sought) return true;
+          if (token.stringValue == '>>') {
+            // `>>` is converted to `>` in the parser when needed.
+            return sought.stringValue == '>' &&
+                token.charOffset <= sought.charOffset &&
+                sought.charOffset < token.charEnd;
+          }
+          return false;
+        }
+
         /// Check that [begin] and [end] can be found between [from] and [to].
         validateToken(Token from, Token to) {
           if (from == null || to == null) return true;
@@ -1800,10 +1813,10 @@
           bool foundEnd = false;
           Token token = from;
           while (true) {
-            if (token == begin) {
+            if (sameToken(token, begin)) {
               foundBegin = true;
             }
-            if (token == end) {
+            if (sameToken(token, end)) {
               foundEnd = true;
             }
             if (foundBegin && foundEnd) {
@@ -1857,7 +1870,7 @@
   }
 
   SourceSpan spanFromNode(Node node) {
-    return spanFromTokens(node.getBeginToken(), node.getEndToken());
+    return spanFromTokens(node.getBeginToken(), node.getPrefixEndToken());
   }
 
   SourceSpan spanFromElement(Element element) {
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 945aaba..fde5cde 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -64,6 +64,8 @@
   bool get isMinusZero => false;
   bool get isZero => false;
   bool get isOne => false;
+  bool get isPositiveInfinity => false;
+  bool get isNegativeInfinity => false;
 
   // TODO(johnniwinther): Replace with a 'type' getter.
   DartType getType(CoreTypes types);
@@ -279,6 +281,10 @@
 
   bool get isOne => primitiveValue == 1.0;
 
+  bool get isPositiveInfinity => primitiveValue == double.INFINITY;
+
+  bool get isNegativeInfinity => primitiveValue == -double.INFINITY;
+
   DartType getType(CoreTypes types) => types.doubleType;
 
   bool operator ==(var other) {
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 422aaa3..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
@@ -19,11 +19,11 @@
 ///
 ///     print(x.length);
 ///
-/// `x.length` will throw when x is null, so the original [NullCheck] is not
+/// `x.length` will throw when x is null, so the original [ReceiverCheck] is not
 /// needed.  This changes the error message, but at least for now we are
 /// willing to accept this.
 ///
-/// Note that code motion may not occur after this pass, since the [NullCheck]
+/// Note that code motion may not occur after this pass, since the [ReceiverCheck]
 /// nodes are not there to restrict it.
 //
 // TODO(asgerf): It would be nice with a clear specification of when we allow
@@ -50,20 +50,19 @@
     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) {
-    if (prim is NullCheck) return prim.value;
+  /// 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;
     if (prim is GetIndex) return prim.object;
     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;
   }
@@ -71,13 +70,13 @@
   /// It has been determined that the null check in [prim] made redundant by
   /// [newNullCheck].  Eliminate [prim] if it is not needed any more.
   void tryEliminateRedundantNullCheck(Primitive prim, Primitive newNullCheck) {
-    if (prim is NullCheck) {
-      Primitive value = prim.value.definition;
+    if (prim is ReceiverCheck && prim.isNullCheck) {
+      Primitive value = prim.value;
       LetPrim let = prim.parent;
       prim..replaceUsesWith(value)..destroy();
       let.remove();
     } else if (prim is GetLength || prim is GetField || prim is GetIndex) {
-      if (prim.hasNoEffectiveUses) {
+      if (prim.hasNoRefinedUses) {
         destroyRefinementsOfDeadPrimitive(prim);
         LetPrim let = prim.parent;
         prim..destroy();
@@ -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 44cbbb0..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,71 +614,34 @@
   // ---------------- 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) {
-    // TODO(asgerf): What we really need is a "changes length" side effect flag.
-    if (world
-        .getSideEffectsOfSelector(node.selector, node.mask)
-        .changesIndex()) {
-      currentEffectNumber = makeNewEffect();
+    if (node.selector.isGetter && node.selector.name == 'length') {
+      // If the receiver type is not known to be indexable, the length call
+      // was not rewritten to GetLength.  But if we can prove that the call only
+      // succeeds for indexables, we can trust that it returns the length.
+      TypeMask successType =
+          types.receiverTypeFor(node.selector, node.dartReceiver.type);
+      if (types.isDefinitelyIndexable(successType)) {
+        valueOf[node] = getLength(node.dartReceiver, currentEffectNumber);
+      }
     }
   }
 
   @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;
@@ -686,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;
 
@@ -694,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 2db4ac5..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.
 ///
@@ -18,7 +20,7 @@
 /// In all cases, the word "null" refers to the Dart null object, corresponding
 /// to both JS null and JS undefined.
 ///
-/// Some operators, notably [IsFloor] and [IsNumberAndFloor], take "repeated"
+/// Some operators, notably [IsFloor] and [IsInteger], take "repeated"
 /// arguments to reflect the number of times the given value is referenced
 /// by the generated code. The tree IR needs to know the number of references
 /// to safely propagate assignments.
@@ -133,7 +135,28 @@
   /// The argument must be repeated 3 times.
   ///
   /// Compiles to `typeof x === 'number' && Math.floor(x) === x`
-  IsNumberAndFloor,
+  IsInteger,
+
+  /// Returns true if the argument is not an integer.
+  ///
+  /// The argument must be repeated 3 times.
+  ///
+  /// Compiles to `typeof x !== 'number' || Math.floor(x) !== x`
+  IsNotInteger,
+
+  /// Returns true if `x` is an unsigned 32-bit integer.
+  ///
+  /// The argument must be repeated 2 times.
+  ///
+  /// Compiles to `x >>> 0 === x`
+  IsUnsigned32BitInteger,
+
+  /// Returns false if `x` is an unsigned 32-bit integer.
+  ///
+  /// The argument must be repeated 2 times.
+  ///
+  /// Compiles to `x >>> 0 !== x`
+  IsNotUnsigned32BitInteger,
 
   /// Returns true if the argument is a fixed length Array.
   ///
@@ -166,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).
@@ -174,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.
@@ -196,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 0a80f33..95fa11a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -20,8 +20,12 @@
 import '../io/source_information.dart';
 import '../js/js.dart' as js show
     js,
+    objectLiteral,
+    Expression,
     LiteralStatement,
-    Template;
+    Template,
+    InterpolatedExpression,
+    isIdentityTemplate;
 import '../native/native.dart' show
     NativeBehavior;
 import '../tree/tree.dart' as ast;
@@ -166,6 +170,11 @@
   JumpCollector.retrn(this._continuation)
       : _continuationEnvironment = null, target = null;
 
+  /// Construct a collector for collecting goto jumps.
+  ///
+  /// There is no continuation or environment at the destination.
+  JumpCollector.goto(this.target) : _continuationEnvironment = null;
+
   /// True if the collector has not recorded any jumps to its continuation.
   bool get isEmpty;
 
@@ -334,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;
     }
   }
 }
@@ -421,6 +430,31 @@
   }
 }
 
+/// Collect 'goto' jumps, continue to a labeled case from within a switch.
+///
+/// These jumps are unrestricted within the switch.  They can be forward or
+/// backward.  They are implemented by assigning to a state variable.
+class GotoJumpCollector extends JumpCollector {
+  bool isEmpty = true;
+  final ir.Continuation continuation = null;
+  final Environment environment = null;
+
+  int _stateVariableIndex;
+  int _stateValue;
+  JumpCollector _breakJoin;
+
+  GotoJumpCollector(JumpTarget target, this._stateVariableIndex,
+      this._stateValue, this._breakJoin) : super.goto(target);
+
+  void addJump(IrBuilder builder,
+      [ir.Primitive value, SourceInformation sourceInformation]) {
+    isEmpty = false;
+    ir.Primitive constant = builder.buildIntegerConstant(_stateValue);
+    builder.environment.index2value[_stateVariableIndex] = constant;
+    builder.jumpTo(_breakJoin);
+  }
+}
+
 /// Function for building a node in the context of the current builder.
 typedef ir.Node BuildFunction(node);
 
@@ -532,7 +566,7 @@
 ///
 /// The IR fragment is an expression with a hole in it. The hole represents
 /// the focus where new expressions can be added. The fragment is implemented
-/// by [_root] which is the root of the expression and [_current] which is the
+/// by [root] which is the root of the expression and [_current] which is the
 /// expression that immediately contains the hole. Not all expressions have a
 /// hole (e.g., invocations, which always occur in tail position, do not have a
 /// hole). Expressions with a hole have a plug method.
@@ -559,7 +593,7 @@
   /// side effects.
   Map<Local, ir.MutableVariable> mutableVariables;
 
-  ir.Expression _root = null;
+  ir.Expression root = null;
   ir.Expression _current = null;
 
   GlobalProgramInformation get program => state.program;
@@ -613,7 +647,7 @@
     return mutableVariables[local];
   }
 
-  bool get isOpen => _root == null || _current != null;
+  bool get isOpen => root == null || _current != null;
 
   List<ir.Primitive> buildFunctionHeader(Iterable<Local> parameters,
                                         {ClosureScope closureScope,
@@ -640,8 +674,8 @@
   /// new value of current.
   void add(ir.Expression expr) {
     assert(isOpen);
-    if (_root == null) {
-      _root = _current = expr;
+    if (root == null) {
+      root = _current = expr;
     } else {
       _current = _current.plug(expr);
     }
@@ -660,6 +694,9 @@
     assert(!element.isLocal);
     assert(!element.isInstanceMember);
     assert(isOpen);
+    if (program.isJsInterop(element)) {
+      return buildInvokeJsInteropMember(element, arguments);
+    }
     return addPrimitive(
         new ir.InvokeStatic(element, selector, arguments, sourceInformation));
   }
@@ -789,8 +826,8 @@
     //     if condition (then, else)
     ir.Continuation thenContinuation = new ir.Continuation([]);
     ir.Continuation elseContinuation = new ir.Continuation([]);
-    thenContinuation.body = thenBuilder._root;
-    elseContinuation.body = elseBuilder._root;
+    thenContinuation.body = thenBuilder.root;
+    elseContinuation.body = elseBuilder.root;
     add(new ir.LetCont(join.continuation,
             new ir.LetCont.two(thenContinuation, elseContinuation,
                 new ir.Branch.strict(condition,
@@ -812,7 +849,7 @@
     _current = null;
   }
 
-  /// Create a [ir.FunctionDefinition] using [_root] as the body.
+  /// Create a [ir.FunctionDefinition] using [root] as the body.
   ///
   /// The protocol for building a function is:
   /// 1. Call [buildFunctionHeader].
@@ -825,7 +862,7 @@
         state.thisParameter,
         state.functionParameters,
         state.returnContinuation,
-        _root);
+        root);
   }
 
   /// Create a invocation of the [method] on the super class where the call
@@ -1107,17 +1144,17 @@
     // case that one of them is null, it must be the only one that is open
     // and thus contains the new hole in the context.  This case is handled
     // after the branch is plugged into the current hole.
-    thenContinuation.body = thenBuilder._root;
-    elseContinuation.body = elseBuilder._root;
+    thenContinuation.body = thenBuilder.root;
+    elseContinuation.body = elseBuilder.root;
 
     add(result);
     if (join == null) {
       // At least one subexpression is closed.
       if (thenBuilder.isOpen) {
-        if (thenBuilder._root != null) _current = thenBuilder._current;
+        if (thenBuilder.root != null) _current = thenBuilder._current;
         environment = thenBuilder.environment;
       } else if (elseBuilder.isOpen) {
-        if (elseBuilder._root != null) _current = elseBuilder._current;
+        if (elseBuilder.root != null) _current = elseBuilder._current;
         environment = elseBuilder.environment;
       } else {
         _current = null;
@@ -1243,16 +1280,16 @@
     // it is guaranteed that the updateBuilder has a non-empty term.
     if (hasContinues) {
       outerBodyBuilder.add(new ir.LetCont(continueCollector.continuation,
-          innerBodyBuilder._root));
-      continueCollector.continuation.body = updateBuilder._root;
+          innerBodyBuilder.root));
+      continueCollector.continuation.body = updateBuilder.root;
     } else {
-      outerBodyBuilder.add(innerBodyBuilder._root);
+      outerBodyBuilder.add(innerBodyBuilder.root);
     }
 
     // Create loop exit and body entry continuations and a branch to them.
     ir.Continuation exitContinuation = new ir.Continuation([]);
     ir.Continuation bodyContinuation = new ir.Continuation([]);
-    bodyContinuation.body = outerBodyBuilder._root;
+    bodyContinuation.body = outerBodyBuilder.root;
     // Note the order of continuations: the first one is the one that will
     // be filled by LetCont.plug.
     ir.LetCont branch =
@@ -1268,7 +1305,7 @@
     if (hasBreaks) {
       IrBuilder exitBuilder = makeDelimitedBuilder();
       exitBuilder.jumpTo(breakCollector);
-      exitContinuation.body = exitBuilder._root;
+      exitContinuation.body = exitBuilder.root;
       letBreak = new ir.LetCont(breakCollector.continuation, branch);
       add(letBreak);
       environment = breakCollector.environment;
@@ -1370,8 +1407,8 @@
       Selector selector = new Selector.setter(
           new Name(variableElement.name, variableElement.library));
       List<ir.Primitive> value = <ir.Primitive>[currentValue];
-      // Note the order of the comparisons below.  It can be the case that an
-      // element isError and isMalformed.
+      // Note the comparison below.  It can be the case that an element isError
+      // and isMalformed.
       if (Elements.isError(variableElement)) {
         bodyBuilder.buildStaticNoSuchMethod(selector, value);
       } else {
@@ -1411,7 +1448,7 @@
     // in branch condition (body, exit)
     ir.Continuation exitContinuation = new ir.Continuation([]);
     ir.Continuation bodyContinuation = new ir.Continuation([]);
-    bodyContinuation.body = bodyBuilder._root;
+    bodyContinuation.body = bodyBuilder.root;
     // Note the order of continuations: the first one is the one that will
     // be filled by LetCont.plug.
     ir.LetCont branch =
@@ -1427,7 +1464,7 @@
     if (hasBreaks) {
       IrBuilder exitBuilder = makeDelimitedBuilder();
       exitBuilder.jumpTo(breakCollector);
-      exitContinuation.body = exitBuilder._root;
+      exitContinuation.body = exitBuilder.root;
       letBreak = new ir.LetCont(breakCollector.continuation, branch);
       add(letBreak);
       environment = breakCollector.environment;
@@ -1486,7 +1523,7 @@
     // Create body entry and loop exit continuations and a branch to them.
     ir.Continuation exitContinuation = new ir.Continuation([]);
     ir.Continuation bodyContinuation = new ir.Continuation([]);
-    bodyContinuation.body = bodyBuilder._root;
+    bodyContinuation.body = bodyBuilder.root;
     // Note the order of continuations: the first one is the one that will
     // be filled by LetCont.plug.
     ir.LetCont branch =
@@ -1502,7 +1539,7 @@
     if (hasBreaks) {
       IrBuilder exitBuilder = makeDelimitedBuilder();
       exitBuilder.jumpTo(breakCollector);
-      exitContinuation.body = exitBuilder._root;
+      exitContinuation.body = exitBuilder.root;
       letBreak = new ir.LetCont(breakCollector.continuation, branch);
       add(letBreak);
       environment = breakCollector.environment;
@@ -1569,18 +1606,18 @@
     ir.Continuation exitContinuation = new ir.Continuation([]);
     IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder();
     exitBuilder.jumpTo(breakCollector);
-    exitContinuation.body = exitBuilder._root;
+    exitContinuation.body = exitBuilder.root;
     ir.Continuation repeatContinuation = new ir.Continuation([]);
     IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder();
     repeatBuilder.jumpTo(loop);
-    repeatContinuation.body = repeatBuilder._root;
+    repeatContinuation.body = repeatBuilder.root;
 
     continueBuilder.add(
         new ir.LetCont.two(exitContinuation, repeatContinuation,
             new ir.Branch.strict(condition,
                                  repeatContinuation,
                                  exitContinuation)));
-    continueCollector.continuation.body = continueBuilder._root;
+    continueCollector.continuation.body = continueBuilder.root;
 
     // Construct the loop continuation (i.e., the body and condition).
     // <Loop> =
@@ -1589,56 +1626,25 @@
     // in [[body]]; continue(v, ...)
     loopBuilder.add(
         new ir.LetCont(continueCollector.continuation,
-            bodyBuilder._root));
+            bodyBuilder.root));
 
     // And tie it all together.
-    add(new ir.LetCont(breakCollector.continuation, loopBuilder._root));
+    add(new ir.LetCont(breakCollector.continuation, loopBuilder.root));
     environment = breakCollector.environment;
   }
 
-  void buildSimpleSwitch(JumpTarget target,
-                         ir.Primitive value,
+  void buildSimpleSwitch(JumpCollector join,
                          List<SwitchCaseInfo> cases,
-                         SwitchCaseInfo defaultCase,
-                         Element error,
-                         SourceInformation sourceInformation) {
-    assert(isOpen);
-    JumpCollector join = new ForwardJumpCollector(environment, target: target);
-
+                         SubbuildFunction buildDefaultBody) {
     IrBuilder casesBuilder = makeDelimitedBuilder();
-    casesBuilder.state.breakCollectors.add(join);
     for (SwitchCaseInfo caseInfo in cases) {
-      buildConditionsFrom(int index) => (IrBuilder builder) {
-        ir.Primitive comparison = builder.buildIdentical(
-            value, caseInfo.constants[index]);
-        return (index == caseInfo.constants.length - 1)
-            ? comparison
-            : builder.buildLogicalOperator(
-                comparison, buildConditionsFrom(index + 1), isLazyOr: true);
-      };
-
-      ir.Primitive condition = buildConditionsFrom(0)(casesBuilder);
+      ir.Primitive condition = caseInfo.buildCondition(casesBuilder);
       IrBuilder thenBuilder = makeDelimitedBuilder();
       caseInfo.buildBody(thenBuilder);
-      if (thenBuilder.isOpen) {
-        // It is a runtime error to reach the end of a switch case, unless
-        // it is the last case.
-        if (caseInfo == cases.last && defaultCase == null) {
-          thenBuilder.jumpTo(join);
-        } else {
-          ir.Primitive exception = thenBuilder.buildInvokeStatic(
-              error,
-              new Selector.fromElement(error),
-              <ir.Primitive>[],
-              sourceInformation);
-          thenBuilder.buildThrow(exception);
-        }
-      }
-
       ir.Continuation thenContinuation = new ir.Continuation([]);
-      thenContinuation.body = thenBuilder._root;
+      thenContinuation.body = thenBuilder.root;
       ir.Continuation elseContinuation = new ir.Continuation([]);
-      // A LetCont.many term has a hole as the body of the first listed
+      // A LetCont.two term has a hole as the body of the first listed
       // continuation, to be plugged by the translation.  Therefore put the
       // else continuation first.
       casesBuilder.add(
@@ -1648,18 +1654,17 @@
                                    elseContinuation)));
     }
 
-    if (defaultCase != null) {
-      defaultCase.buildBody(casesBuilder);
+    if (buildDefaultBody == null) {
+      casesBuilder.jumpTo(join);
+    } else {
+      buildDefaultBody(casesBuilder);
     }
-    if (casesBuilder.isOpen) casesBuilder.jumpTo(join);
-
-    casesBuilder.state.breakCollectors.removeLast();
 
     if (!join.isEmpty) {
-      add(new ir.LetCont(join.continuation, casesBuilder._root));
+      add(new ir.LetCont(join.continuation, casesBuilder.root));
       environment = join.environment;
-    } else if (casesBuilder._root != null) {
-      add(casesBuilder._root);
+    } else if (casesBuilder.root != null) {
+      add(casesBuilder.root);
       _current = casesBuilder._current;
       environment = casesBuilder.environment;
     } else {
@@ -1721,11 +1726,11 @@
 
     List<ir.Parameter> catchParameters = buildCatch(catchBuilder, join);
     ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
-    catchContinuation.body = catchBuilder._root;
+    catchContinuation.body = catchBuilder.root;
     tryCatchBuilder.add(
-        new ir.LetHandler(catchContinuation, tryBuilder._root));
+        new ir.LetHandler(catchContinuation, tryBuilder.root));
 
-    leaveTryCatch(this, join, tryCatchBuilder._root);
+    leaveTryCatch(this, join, tryCatchBuilder.root);
   }
 
   /// Translates a try/catch.
@@ -1829,7 +1834,7 @@
         }
         clause.buildCatchBlock(clauseBuilder);
         if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join);
-        return clauseBuilder._root;
+        return clauseBuilder.root;
       }
 
       // Expand multiple catch clauses into an explicit if/then/else.  Iterate
@@ -1855,7 +1860,7 @@
             new ir.Branch.strict(typeMatches,
                                  thenContinuation,
                                  elseContinuation)));
-        catchBody = checkBuilder._root;
+        catchBody = checkBuilder.root;
       }
       builder.add(catchBody);
 
@@ -1960,7 +1965,7 @@
         IrBuilder builder = makeDelimitedBuilder(newCollector.environment);
         buildFinallyBlock(builder);
         if (builder.isOpen) builder.jumpTo(originalCollector);
-        newCollector.continuation.body = builder._root;
+        newCollector.continuation.body = builder.root;
         exits.add(newCollector.continuation);
       }
       for (int i = 0; i < newBreaks.length; ++i) {
@@ -1974,7 +1979,7 @@
         ir.Primitive value = builder.environment.discard(1);
         buildFinallyBlock(builder);
         if (builder.isOpen) builder.buildReturn(value: value);
-        newReturn.continuation.body = builder._root;
+        newReturn.continuation.body = builder.root;
         exits.add(newReturn.continuation);
       }
       builder.add(new ir.LetCont.many(exits, body));
@@ -2062,10 +2067,91 @@
     ir.Primitive value = buildForeignCode(
         js.js.uncachedExpressionTemplate(code),
         arguments,
-        behavior);
+        behavior,
+        type: program.getTypeMaskForNativeFunction(function));
     buildReturn(value: value, sourceInformation: source);
   }
 
+  static _isNotNull(ir.Primitive value) =>
+      !(value is ir.Constant && value.value.isNull);
+
+  /// Builds a call to a resolved js-interop element.
+  ir.Primitive buildInvokeJsInteropMember(FunctionElement element,
+      List<ir.Primitive> arguments) {
+    program.addNativeMethod(element);
+    String target = program.getJsInteropTargetPath(element);
+    // Strip off trailing arguments that were not specified.
+    // TODO(jacobr,sigmund): assert that the trailing arguments are all null.
+    // TODO(jacobr): rewrite named arguments to an object literal matching
+    // the factory constructor case.
+    var inputs = arguments.where(_isNotNull).toList();
+
+    var behavior = new NativeBehavior()..sideEffects.setAllSideEffects();
+    DartType type = element.isConstructor ?
+        element.enclosingClass.thisType : element.type.returnType;
+    // Native behavior effects here are similar to native/behavior.dart.
+    // The return type is dynamic if we don't trust js-interop type
+    // declarations.
+    behavior.typesReturned.add(
+        program.trustJSInteropTypeAnnotations ? type : const DynamicType());
+
+    // The allocation effects include the declared type if it is native (which
+    // includes js interop types).
+    if (type.element != null && program.isNative(type.element)) {
+      behavior.typesInstantiated.add(type);
+    }
+
+    // It also includes any other JS interop type if we don't trust the
+    // annotation or if is declared too broad.
+    if (!program.trustJSInteropTypeAnnotations || type.isObject ||
+        type.isDynamic) {
+      behavior.typesInstantiated.add(program.jsJavascriptObjectType);
+    }
+
+    String code;
+    if (element.isGetter) {
+      code = target;
+    } else if (element.isSetter) {
+      code = "$target = #";
+    } else {
+      var args = new List.filled(inputs.length, '#').join(',');
+      code = element.isConstructor ? "new $target($args)" : "$target($args)";
+    }
+    return buildForeignCode(js.js.parseForeignJS(code), inputs, behavior);
+    // TODO(sigmund): should we record the source-information here?
+  }
+
+  /// Builds an object literal that results from invoking a factory constructor
+  /// of a js-interop anonymous type.
+  ir.Primitive buildJsInteropObjectLiteral(ConstructorElement constructor,
+      List<ir.Primitive> arguments, {SourceInformation source}) {
+    assert(program.isJsInteropAnonymous(constructor));
+    program.addNativeMethod(constructor);
+    FunctionSignature params = constructor.functionSignature;
+    int i = 0;
+    var filteredArguments = <ir.Primitive>[];
+    var entries = new Map<String, js.Expression>();
+    params.orderedForEachParameter((ParameterElement parameter) {
+      // TODO(jacobr): throw if parameter names do not match names of property
+      // names in the class.
+      assert (parameter.isNamed);
+      ir.Primitive argument = arguments[i++];
+      if (_isNotNull(argument)) {
+        filteredArguments.add(argument);
+        entries[parameter.name] =
+            new js.InterpolatedExpression(filteredArguments.length - 1);
+      }
+    });
+    var code = new js.Template(null, js.objectLiteral(entries));
+    var behavior = new NativeBehavior();
+    if (program.trustJSInteropTypeAnnotations) {
+      behavior.typesReturned.add(constructor.enclosingClass.thisType);
+    }
+
+    // TODO(sigmund): should we record the source-information here?
+    return buildForeignCode(code, filteredArguments, behavior);
+  }
+
   /// Create a blocks of [statements] by applying [build] to all reachable
   /// statements. The first statement is assumed to be reachable.
   // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses
@@ -2100,10 +2186,10 @@
     bool hasBreaks = !join.isEmpty;
     if (hasBreaks) {
       if (innerBuilder.isOpen) innerBuilder.jumpTo(join);
-      add(new ir.LetCont(join.continuation, innerBuilder._root));
+      add(new ir.LetCont(join.continuation, innerBuilder.root));
       environment = join.environment;
-    } else if (innerBuilder._root != null) {
-      add(innerBuilder._root);
+    } else if (innerBuilder.root != null) {
+      add(innerBuilder.root);
       _current = innerBuilder._current;
       environment = innerBuilder.environment;
     } else {
@@ -2239,8 +2325,8 @@
     ir.Continuation leftFalseContinuation = new ir.Continuation([]);
     ir.Continuation rightTrueContinuation = new ir.Continuation([]);
     ir.Continuation rightFalseContinuation = new ir.Continuation([]);
-    rightTrueContinuation.body = rightTrueBuilder._root;
-    rightFalseContinuation.body = rightFalseBuilder._root;
+    rightTrueContinuation.body = rightTrueBuilder.root;
+    rightFalseContinuation.body = rightFalseBuilder.root;
     // The right subexpression has two continuations.
     rightBuilder.add(
         new ir.LetCont.two(rightTrueContinuation, rightFalseContinuation,
@@ -2251,11 +2337,11 @@
     // either the right subexpression or an invocation of the join-point
     // continuation.
     if (isLazyOr) {
-      leftTrueContinuation.body = emptyBuilder._root;
-      leftFalseContinuation.body = rightBuilder._root;
+      leftTrueContinuation.body = emptyBuilder.root;
+      leftFalseContinuation.body = rightBuilder.root;
     } else {
-      leftTrueContinuation.body = rightBuilder._root;
-      leftFalseContinuation.body = emptyBuilder._root;
+      leftTrueContinuation.body = rightBuilder.root;
+      leftFalseContinuation.body = emptyBuilder.root;
     }
 
     add(new ir.LetCont(join.continuation,
@@ -2411,7 +2497,7 @@
       arguments.add(value);
     }
     return addPrimitive(new ir.CreateInstance(
-        classElement, arguments, const <ir.Primitive>[], sourceInformation));
+        classElement, arguments, null, sourceInformation));
   }
 
   /// Create a read access of [local] function, variable, or parameter.
@@ -2502,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,
@@ -2551,6 +2638,13 @@
     Selector selector =
         new Selector(SelectorKind.CALL, element.memberName, callStructure);
     ClassElement cls = element.enclosingClass;
+    if (program.isJsInterop(element)) {
+      if (program.isJsInteropAnonymous(element)) {
+        return buildJsInteropObjectLiteral(element, arguments,
+            source: sourceInformation);
+      }
+      return buildInvokeJsInteropMember(element, arguments);
+    }
     if (program.requiresRuntimeTypesFor(cls)) {
       InterfaceType interface = type;
       Iterable<ir.Primitive> typeArguments =
@@ -2577,7 +2671,8 @@
         ir.Primitive value = buildTypeVariableAccess(variable);
         arguments.add(value);
       });
-      return addPrimitive(new ir.TypeExpression(type, arguments));
+      return addPrimitive(new ir.TypeExpression(ir.TypeExpressionKind.COMPLETE,
+                                                type, arguments));
     } else if (type.treatAsDynamic) {
       return buildNullConstant();
     } else {
@@ -2634,9 +2729,19 @@
   ir.Primitive buildForeignCode(js.Template codeTemplate,
                                 List<ir.Primitive> arguments,
                                 NativeBehavior behavior,
-                                {Element dependency}) {
+                                {Element dependency,
+                                 TypeMask type}) {
     assert(behavior != null);
-    TypeMask type = program.getTypeMaskForForeign(behavior);
+    if (type == null) {
+      type = program.getTypeMaskForForeign(behavior);
+    }
+    if (js.isIdentityTemplate(codeTemplate) && !program.isArrayType(type)) {
+      // JS expression is just a refinement.
+      // Do not do this for arrays - those are special because array types can
+      // change after creation.  The input and output must therefore be modeled
+      // as distinct values.
+      return addPrimitive(new ir.Refinement(arguments.single, type));
+    }
     ir.Primitive result = addPrimitive(new ir.ForeignCode(
         codeTemplate,
         type,
@@ -2834,10 +2939,8 @@
 }
 
 class SwitchCaseInfo {
-  final List<ir.Primitive> constants = <ir.Primitive>[];
+  final SubbuildFunction buildCondition;
   final SubbuildFunction buildBody;
 
-  SwitchCaseInfo(this.buildBody);
-
-  void addConstant(ir.Primitive constant) => constants.add(constant);
+  SwitchCaseInfo(this.buildCondition, this.buildBody);
 }
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 5c55f63..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
@@ -7,6 +7,7 @@
 import '../closure.dart' as closure;
 import '../common.dart';
 import '../common/names.dart' show
+    Identifiers,
     Names,
     Selectors;
 import '../common/tasks.dart' show
@@ -382,7 +383,7 @@
     IrBuilder builder = getBuilderFor(constructor);
 
     final bool requiresTypeInformation =
-    builder.program.requiresRuntimeTypesFor(classElement);
+        builder.program.requiresRuntimeTypesFor(classElement);
 
     return withBuilder(builder, () {
       // Setup parameters and create a box if anything is captured.
@@ -410,11 +411,15 @@
           closureScope: getClosureScopeForFunction(constructor));
 
       // Create a list of the values of all type argument parameters, if any.
-      List<ir.Primitive> typeInformation;
+      ir.Primitive typeInformation;
       if (requiresTypeInformation) {
-        typeInformation = irParameters.sublist(firstTypeArgumentParameterIndex);
+        typeInformation = new ir.TypeExpression(
+            ir.TypeExpressionKind.INSTANCE,
+            classElement.thisType,
+            irParameters.sublist(firstTypeArgumentParameterIndex));
+        irBuilder.add(new ir.LetPrim(typeInformation));
       } else {
-        typeInformation = const <ir.Primitive>[];
+        typeInformation = null;
       }
 
       // -- Load values for type variables declared on super classes --
@@ -426,7 +431,7 @@
 
       /// Maps each field from this class or a superclass to its initial value.
       Map<FieldElement, ir.Primitive> fieldValues =
-      <FieldElement, ir.Primitive>{};
+          <FieldElement, ir.Primitive>{};
 
       // -- Evaluate field initializers ---
       // Evaluate field initializers in constructor and super constructors.
@@ -753,7 +758,8 @@
     TryBoxedVariables variables = _analyzeTryBoxedVariables(node);
     tryStatements = variables.tryStatements;
     IrBuilder builder = getBuilderFor(element);
-    return withBuilder(builder, () => _makeFunctionBody(element, node));
+    return withBuilder(builder,
+        () => _makeFunctionBody(builder, element, node));
   }
 
   ir.FunctionDefinition buildStaticFieldInitializer(FieldElement element) {
@@ -790,7 +796,10 @@
 
   /// Creates a primitive for the default value of [parameter].
   ir.Primitive translateDefaultValue(ParameterElement parameter) {
-    if (parameter.initializer == null) {
+    if (parameter.initializer == null ||
+        // TODO(sigmund): JS doesn't support default values, so this should be
+        // reported as an error earlier (Issue #25759).
+        backend.isJsInterop(parameter.functionDeclaration)) {
       return irBuilder.buildNullConstant();
     } else {
       return inlineConstant(parameter.executableContext, parameter.initializer);
@@ -869,23 +878,34 @@
       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)));
     }
   }
 
-  ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
-                                          ast.FunctionExpression node) {
+  ir.FunctionDefinition _makeFunctionBody(
+      IrBuilder builder,
+      FunctionElement element,
+      ast.FunctionExpression node) {
     FunctionSignature signature = element.functionSignature;
     List<Local> parameters = <Local>[];
     signature.orderedForEachParameter(
         (LocalParameterElement e) => parameters.add(e));
 
+    bool requiresRuntimeTypes = false;
     if (element.isFactoryConstructor) {
-      // Type arguments are passed in as extra parameters.
-      for (DartType typeVariable in element.enclosingClass.typeVariables) {
-        parameters.add(new closure.TypeVariableLocal(typeVariable, element));
+      requiresRuntimeTypes =
+          builder.program.requiresRuntimeTypesFor(element.enclosingElement);
+      if (requiresRuntimeTypes) {
+        // Type arguments are passed in as extra parameters.
+        for (DartType typeVariable in element.enclosingClass.typeVariables) {
+          parameters.add(new closure.TypeVariableLocal(typeVariable, element));
+        }
       }
     }
 
@@ -893,7 +913,45 @@
                                   closureScope: getClosureScopeForNode(node),
                                   env: getClosureEnvironment());
 
-    visit(node.body);
+    if (element == helpers.jsArrayTypedConstructor) {
+      // Generate a body for JSArray<E>.typed(allocation):
+      //
+      //    t1 = setRuntimeTypeInfo(allocation, TypeExpression($E));
+      //    return Refinement(t1, <JSArray>);
+      //
+      assert(parameters.length == 1 || parameters.length == 2);
+      ir.Primitive allocation = irBuilder.buildLocalGet(parameters[0]);
+      ClassElement classElement = element.enclosingElement;
+
+      // Only call setRuntimeTypeInfo if JSArray requires the type parameter.
+      if (requiresRuntimeTypes) {
+        assert(parameters.length == 2);
+        closure.TypeVariableLocal typeParameter = parameters[1];
+        ir.Primitive typeArgument =
+            irBuilder.buildTypeVariableAccess(typeParameter.typeVariable);
+
+        ir.Primitive typeInformation = irBuilder.addPrimitive(
+            new ir.TypeExpression(ir.TypeExpressionKind.INSTANCE,
+                                  element.enclosingClass.thisType,
+                                  <ir.Primitive>[typeArgument]));
+
+        MethodElement helper = helpers.setRuntimeTypeInfo;
+        CallStructure callStructure = CallStructure.TWO_ARGS;
+        Selector selector = new Selector.call(helper.memberName, callStructure);
+        allocation = irBuilder.buildInvokeStatic(
+            helper, selector, <ir.Primitive>[allocation, typeInformation],
+            sourceInformationBuilder.buildGeneric(node));
+      }
+
+      ir.Primitive refinement = irBuilder.addPrimitive(
+          new ir.Refinement(allocation, typeMaskSystem.arrayType));
+
+      irBuilder.buildReturn(value: refinement,
+          sourceInformation:
+              sourceInformationBuilder.buildImplicitReturn(element));
+    } else {
+      visit(node.body);
+    }
     return irBuilder.makeFunctionDefinition();
   }
 
@@ -1060,8 +1118,105 @@
   }
 
   visitAsyncForIn(ast.AsyncForIn node) {
-    // await for is not yet implemented.
-    return giveup(node, 'await for');
+    // Translate await for into a loop over a StreamIterator.  The source
+    // statement:
+    //
+    // await for (<decl> in <stream>) <body>
+    //
+    // is translated as if it were:
+    //
+    // var iterator = new StreamIterator(<stream>);
+    // try {
+    //   while (await iterator.hasNext()) {
+    //     <decl> = await iterator.current;
+    //     <body>
+    //   }
+    // } finally {
+    //   await iterator.cancel();
+    // }
+    ir.Primitive stream = visit(node.expression);
+    ir.Primitive dummyTypeArgument = irBuilder.buildNullConstant();
+    ConstructorElement constructor = helpers.streamIteratorConstructor;
+    ir.Primitive iterator = irBuilder.addPrimitive(new ir.InvokeConstructor(
+        constructor.enclosingClass.thisType,
+        constructor,
+        new Selector.callConstructor(constructor.memberName, 1),
+        <ir.Primitive>[stream, dummyTypeArgument],
+        sourceInformationBuilder.buildGeneric(node)));
+
+    ir.Node buildTryBody(IrBuilder builder) {
+      ir.Node buildLoopCondition(IrBuilder builder) {
+        ir.Primitive moveNext = builder.buildDynamicInvocation(
+            iterator,
+            Selectors.moveNext,
+            elements.getMoveNextTypeMask(node),
+            <ir.Primitive>[]);
+        return builder.addPrimitive(new ir.Await(moveNext));
+      }
+
+      ir.Node buildLoopBody(IrBuilder builder) {
+        return withBuilder(builder, () {
+          ir.Primitive current = irBuilder.buildDynamicInvocation(
+              iterator,
+              Selectors.current,
+              elements.getCurrentTypeMask(node),
+              <ir.Primitive>[]);
+          Element variable = elements.getForInVariable(node);
+          if (Elements.isLocal(variable)) {
+            if (node.declaredIdentifier.asVariableDefinitions() != null) {
+              irBuilder.declareLocalVariable(variable);
+            }
+            irBuilder.buildLocalVariableSet(variable, current);
+          } else if (Elements.isError(variable) ||
+                     Elements.isMalformed(variable)) {
+            Selector selector =
+                new Selector.setter(new Name(variable.name, variable.library));
+            List<ir.Primitive> args = <ir.Primitive>[current];
+            // Note the comparison below.  It can be the case that an element
+            // isError and isMalformed.
+            if (Elements.isError(variable)) {
+              irBuilder.buildStaticNoSuchMethod(selector, args);
+            } else {
+              irBuilder.buildErroneousInvocation(variable, selector, args);
+            }
+          } else if (Elements.isStaticOrTopLevel(variable)) {
+            if (variable.isField) {
+              irBuilder.addPrimitive(new ir.SetStatic(variable, current));
+            } else {
+              irBuilder.buildStaticSetterSet(variable, current);
+            }
+          } else {
+            ir.Primitive receiver = irBuilder.buildThis();
+            ast.Node identifier = node.declaredIdentifier;
+            irBuilder.buildDynamicSet(
+                receiver,
+                elements.getSelector(identifier),
+                elements.getTypeMask(identifier),
+                current);
+          }
+          visit(node.body);
+        });
+      }
+
+      builder.buildWhile(
+          buildCondition: buildLoopCondition,
+          buildBody: buildLoopBody,
+          target: elements.getTargetDefinition(node),
+          closureScope: getClosureScopeForNode(node));
+    }
+
+    ir.Node buildFinallyBody(IrBuilder builder) {
+      ir.Primitive cancellation = builder.buildDynamicInvocation(
+          iterator,
+          Selectors.cancel,
+          backend.dynamicType,
+          <ir.Primitive>[],
+          sourceInformation: sourceInformationBuilder.buildGeneric(node));
+      return builder.addPrimitive(new ir.Await(cancellation));
+    }
+
+    irBuilder.buildTryFinally(new TryStatementInfo(), buildTryBody,
+        buildFinallyBody);
   }
 
   visitAwait(ast.Await node) {
@@ -1172,44 +1327,270 @@
   }
 
   visitSwitchStatement(ast.SwitchStatement node) {
+    // Dart switch cases can be labeled and be the target of continue from
+    // within the switch.  Such cases are 'recursive'.  If there are any
+    // recursive cases, we implement the switch using a pair of switches with
+    // the second one switching over a state variable in a loop.  The first
+    // switch contains the non-recursive cases, and the second switch contains
+    // the recursive ones.
+    //
+    // For example, for the Dart switch:
+    //
+    // switch (E) {
+    //   case 0:
+    //     BODY0;
+    //     break;
+    //   LABEL0: case 1:
+    //     BODY1;
+    //     break;
+    //   case 2:
+    //     BODY2;
+    //     continue LABEL1;
+    //   LABEL1: case 3:
+    //     BODY3;
+    //     continue LABEL0;
+    //   default:
+    //     BODY4;
+    // }
+    //
+    // We translate it as if it were the JavaScript:
+    //
+    // var state = -1;
+    // switch (E) {
+    //   case 0:
+    //     BODY0;
+    //     break;
+    //   case 1:
+    //     state = 0;  // Recursive, label ID = 0.
+    //     break;
+    //   case 2:
+    //     BODY2;
+    //     state = 1;  // Continue to label ID = 1.
+    //     break;
+    //   case 3:
+    //     state = 1;  // Recursive, label ID = 1.
+    //     break;
+    //   default:
+    //     BODY4;
+    // }
+    // L: while (state != -1) {
+    //   case 0:
+    //     BODY1;
+    //     break L;  // Break from switch becomes break from loop.
+    //   case 1:
+    //     BODY2;
+    //     state = 0;  // Continue to label ID = 0.
+    //     break;
+    // }
     assert(irBuilder.isOpen);
-    // We do not handle switch statements with continue to labeled cases.
-    for (ast.SwitchCase switchCase in node.cases) {
+    // Preprocess: compute a list of cases that are the target of continue.
+    // These are the so-called 'recursive' cases.
+    List<JumpTarget> continueTargets = <JumpTarget>[];
+    List<ast.Node> switchCases = node.cases.nodes.toList();
+    for (ast.SwitchCase switchCase in switchCases) {
       for (ast.Node labelOrCase in switchCase.labelsAndCases) {
         if (labelOrCase is ast.Label) {
           LabelDefinition definition = elements.getLabelDefinition(labelOrCase);
           if (definition != null && definition.isContinueTarget) {
-            return giveup(node, "continue to a labeled switch case");
+            continueTargets.add(definition.target);
           }
         }
       }
     }
 
-    // Each switch case contains a list of interleaved labels and expressions
-    // and a non-empty body.  We can ignore the labels because they are not
-    // jump targets.
-    List<SwitchCaseInfo> cases = <SwitchCaseInfo>[];
-    SwitchCaseInfo defaultCase;
-    for (ast.SwitchCase switchCase in node.cases) {
-      SwitchCaseInfo caseInfo =
-          new SwitchCaseInfo(subbuildSequence(switchCase.statements));
-      if (switchCase.isDefaultCase) {
-        defaultCase = caseInfo;
-      } else {
-        cases.add(caseInfo);
-        for (ast.Node labelOrCase in switchCase.labelsAndCases) {
-          if (labelOrCase is ast.CaseMatch) {
-            ir.Primitive constant = translateConstant(labelOrCase.expression);
-            caseInfo.addConstant(constant);
-          }
-        }
-      }
+    // If any cases are continue targets, use an anonymous local value to
+    // implement a state machine.  The initial value is -1.
+    ir.Primitive initial;
+    int stateIndex;
+    if (continueTargets.isNotEmpty) {
+      initial = irBuilder.buildIntegerConstant(-1);
+      stateIndex = irBuilder.environment.length;
+      irBuilder.environment.extend(null, initial);
     }
+
+    // Use a simple switch for the non-recursive cases.  A break will go to the
+    // join-point after the switch.  A continue to a labeled case will assign
+    // to the state variable and go to the join-point.
     ir.Primitive value = visit(node.expression);
-    JumpTarget target = elements.getTargetDefinition(node);
-    Element error = helpers.fallThroughError;
-    irBuilder.buildSimpleSwitch(target, value, cases, defaultCase, error,
-        sourceInformationBuilder.buildGeneric(node));
+    JumpCollector join = new ForwardJumpCollector(irBuilder.environment,
+        target: elements.getTargetDefinition(node));
+    irBuilder.state.breakCollectors.add(join);
+    for (int i = 0; i < continueTargets.length; ++i) {
+      // The state value is i, the case's position in the list of recursive
+      // cases.
+      irBuilder.state.continueCollectors.add(new GotoJumpCollector(
+          continueTargets[i], stateIndex, i, join));
+    }
+
+    // For each non-default case use a pair of functions, one to translate the
+    // condition and one to translate the body.  For the default case use a
+    // function to translate the body.  Use continueTargetIterator as a pointer
+    // to the next recursive case.
+    Iterator<JumpTarget> continueTargetIterator = continueTargets.iterator;
+    continueTargetIterator.moveNext();
+    List<SwitchCaseInfo> cases = <SwitchCaseInfo>[];
+    SubbuildFunction buildDefaultBody;
+    for (ast.SwitchCase switchCase in switchCases) {
+      JumpTarget nextContinueTarget = continueTargetIterator.current;
+      if (switchCase.isDefaultCase) {
+        if (nextContinueTarget != null &&
+            switchCase == nextContinueTarget.statement) {
+          // In this simple switch, recursive cases are as if they immediately
+          // continued to themselves.
+          buildDefaultBody = nested(() {
+            irBuilder.buildContinue(nextContinueTarget);
+          });
+          continueTargetIterator.moveNext();
+        } else {
+          // Non-recursive cases consist of the translation of the body.
+          // For the default case, there is implicitly a break if control
+          // flow reaches the end.
+          buildDefaultBody = nested(() {
+            irBuilder.buildSequence(switchCase.statements, visit);
+            if (irBuilder.isOpen) irBuilder.jumpTo(join);
+          });
+        }
+        continue;
+      }
+
+      ir.Primitive buildCondition(IrBuilder builder) {
+        // There can be multiple cases sharing the same body, because empty
+        // cases are allowed to fall through to the next one.  Each case is
+        // a comparison, build a short-circuited disjunction of all of them.
+        return withBuilder(builder, () {
+          ir.Primitive condition;
+          for (ast.Node labelOrCase in switchCase.labelsAndCases) {
+            if (labelOrCase is ast.CaseMatch) {
+              ir.Primitive buildComparison() {
+                ir.Primitive constant =
+                    translateConstant(labelOrCase.expression);
+                return irBuilder.buildIdentical(value, constant);
+              }
+
+              if (condition == null) {
+                condition = buildComparison();
+              } else {
+                condition = irBuilder.buildLogicalOperator(condition,
+                    nested(buildComparison), isLazyOr: true);
+              }
+            }
+          }
+          return condition;
+        });
+      }
+
+      SubbuildFunction buildBody;
+      if (nextContinueTarget != null &&
+          switchCase == nextContinueTarget.statement) {
+        // Recursive cases are as if they immediately continued to themselves.
+        buildBody = nested(() {
+          irBuilder.buildContinue(nextContinueTarget);
+        });
+        continueTargetIterator.moveNext();
+      } else {
+        // Non-recursive cases consist of the translation of the body.  It is a
+        // runtime error if control-flow reaches the end of the body of any but
+        // the last case.
+        buildBody = (IrBuilder builder) {
+          withBuilder(builder, () {
+            irBuilder.buildSequence(switchCase.statements, visit);
+            if (irBuilder.isOpen) {
+              if (switchCase == switchCases.last) {
+                irBuilder.jumpTo(join);
+              } else {
+                Element error = helpers.fallThroughError;
+                ir.Primitive exception = irBuilder.buildInvokeStatic(
+                    error,
+                    new Selector.fromElement(error),
+                    <ir.Primitive>[],
+                    sourceInformationBuilder.buildGeneric(node));
+                irBuilder.buildThrow(exception);
+              }
+            }
+          });
+          return null;
+        };
+      }
+
+      cases.add(new SwitchCaseInfo(buildCondition, buildBody));
+    }
+
+    irBuilder.buildSimpleSwitch(join, cases, buildDefaultBody);
+    irBuilder.state.breakCollectors.removeLast();
+    irBuilder.state.continueCollectors.length -= continueTargets.length;
+    if (continueTargets.isEmpty) return;
+
+    // If there were recursive cases build a while loop whose body is a
+    // switch containing (only) the recursive cases.  The condition is
+    // 'state != initialValue' so the loop is not taken when the state variable
+    // has not been assigned.
+    //
+    // 'loop' is the join-point of the exits from the inner switch which will
+    // perform another iteration of the loop.  'exit' is the join-point of the
+    // breaks from the switch, outside the loop.
+    JumpCollector loop = new ForwardJumpCollector(irBuilder.environment);
+    JumpCollector exit = new ForwardJumpCollector(irBuilder.environment,
+        target: elements.getTargetDefinition(node));
+    irBuilder.state.breakCollectors.add(exit);
+    for (int i = 0; i < continueTargets.length; ++i) {
+      irBuilder.state.continueCollectors.add(new GotoJumpCollector(
+          continueTargets[i], stateIndex, i, loop));
+    }
+    cases.clear();
+    for (int i = 0; i < continueTargets.length; ++i) {
+      // The conditions compare to the recursive case index.
+      ir.Primitive buildCondition(IrBuilder builder) {
+        ir.Primitive constant = builder.buildIntegerConstant(i);
+        return builder.buildIdentical(
+            builder.environment.index2value[stateIndex], constant);
+      }
+
+      ir.Primitive buildBody(IrBuilder builder) {
+        withBuilder(builder, () {
+          ast.SwitchCase switchCase = continueTargets[i].statement;
+          irBuilder.buildSequence(switchCase.statements, visit);
+          if (irBuilder.isOpen) {
+            if (switchCase == switchCases.last) {
+              irBuilder.jumpTo(exit);
+            } else {
+              Element error = helpers.fallThroughError;
+              ir.Primitive exception = irBuilder.buildInvokeStatic(
+                  error,
+                  new Selector.fromElement(error),
+                  <ir.Primitive>[],
+                  sourceInformationBuilder.buildGeneric(node));
+              irBuilder.buildThrow(exception);
+            }
+          }
+        });
+        return null;
+      }
+
+      cases.add(new SwitchCaseInfo(buildCondition, buildBody));
+    }
+
+    // A loop with a simple switch in the body.
+    IrBuilder whileBuilder = irBuilder.makeDelimitedBuilder();
+    whileBuilder.buildWhile(
+        buildCondition: (IrBuilder builder) {
+          ir.Primitive condition = builder.buildIdentical(
+              builder.environment.index2value[stateIndex], initial);
+          return builder.buildNegation(condition);
+        },
+        buildBody: (IrBuilder builder) {
+          builder.buildSimpleSwitch(loop, cases, null);
+        });
+    // Jump to the exit continuation.  This jump is the body of the loop exit
+    // continuation, so the loop exit continuation can be eta-reduced.  The
+    // jump is here for simplicity because `buildWhile` does not expose the
+    // loop's exit continuation directly and has already emitted all jumps
+    // to it anyway.
+    whileBuilder.jumpTo(exit);
+    irBuilder.add(new ir.LetCont(exit.continuation, whileBuilder.root));
+    irBuilder.environment = exit.environment;
+    irBuilder.environment.discard(1);  // Discard the state variable.
+    irBuilder.state.breakCollectors.removeLast();
+    irBuilder.state.continueCollectors.length -= continueTargets.length;
   }
 
   visitTryStatement(ast.TryStatement node) {
@@ -1325,8 +1706,25 @@
     }
     List<ir.Primitive> values = node.elements.nodes.mapToList(visit);
     InterfaceType type = elements.getType(node);
-    return irBuilder.buildListLiteral(type, values,
-        allocationSiteType: getAllocationSiteType(node));
+    TypeMask allocationSiteType = getAllocationSiteType(node);
+    // TODO(sra): In checked mode, the elements must be checked as though
+    // operator[]= is called.
+    ir.Primitive list = irBuilder.buildListLiteral(type, values,
+          allocationSiteType: allocationSiteType);
+    if (type.treatAsRaw) return list;
+    // Call JSArray<E>.typed(allocation) to install the reified type.
+    ConstructorElement constructor = helpers.jsArrayTypedConstructor;
+    ir.Primitive tagged = irBuilder.buildConstructorInvocation(
+        constructor.effectiveTarget,
+        CallStructure.ONE_ARG,
+        constructor.computeEffectiveTargetType(type),
+        <ir.Primitive>[list],
+        sourceInformationBuilder.buildNew(node));
+
+    if (allocationSiteType == null) return tagged;
+
+    return irBuilder.addPrimitive(
+        new ir.Refinement(tagged, allocationSiteType));
   }
 
   ir.Primitive visitLiteralMap(ast.LiteralMap node) {
@@ -1334,12 +1732,48 @@
     if (node.isConst) {
       return translateConstant(node);
     }
+
     InterfaceType type = elements.getType(node);
-    List<ir.LiteralMapEntry> entries =
-        node.entries.nodes.mapToList((ast.LiteralMapEntry e) {
-          return new ir.LiteralMapEntry(visit(e.key), visit(e.value));
-        });
-    return irBuilder.addPrimitive(new ir.LiteralMap(type, entries));
+
+    if (node.entries.nodes.isEmpty) {
+      if (type.treatAsRaw) {
+        return irBuilder.buildStaticFunctionInvocation(
+            helpers.mapLiteralUntypedEmptyMaker,
+            <ir.Primitive>[],
+            sourceInformation: sourceInformationBuilder.buildNew(node));
+      } else {
+        ConstructorElement constructor = helpers.mapLiteralConstructorEmpty;
+        return irBuilder.buildConstructorInvocation(
+            constructor.effectiveTarget,
+            CallStructure.NO_ARGS,
+            constructor.computeEffectiveTargetType(type),
+            <ir.Primitive>[],
+            sourceInformationBuilder.buildNew(node));
+      }
+    }
+
+    List<ir.Primitive> keysAndValues = <ir.Primitive>[];
+    for (ast.LiteralMapEntry entry in node.entries.nodes.toList()) {
+      keysAndValues.add(visit(entry.key));
+      keysAndValues.add(visit(entry.value));
+    }
+    ir.Primitive keysAndValuesList =
+        irBuilder.buildListLiteral(null, keysAndValues);
+
+    if (type.treatAsRaw) {
+      return irBuilder.buildStaticFunctionInvocation(
+          helpers.mapLiteralUntypedMaker,
+          <ir.Primitive>[keysAndValuesList],
+          sourceInformation: sourceInformationBuilder.buildNew(node));
+    } else {
+      ConstructorElement constructor = helpers.mapLiteralConstructor;
+      return irBuilder.buildConstructorInvocation(
+          constructor.effectiveTarget,
+          CallStructure.ONE_ARG,
+          constructor.computeEffectiveTargetType(type),
+          <ir.Primitive>[keysAndValuesList],
+          sourceInformationBuilder.buildNew(node));
+    }
   }
 
   ir.Primitive visitLiteralSymbol(ast.LiteralSymbol node) {
@@ -1506,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
@@ -1565,11 +1999,20 @@
   ir.Primitive visitUnresolvedSuperGet(
       ast.Send node,
       Element element, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         elements.getSelector(node), elements.getTypeMask(node), []);
   }
 
   @override
+  ir.Primitive visitUnresolvedSuperSet(
+      ast.Send node,
+      Element element,
+      ast.Node rhs, _) {
+    return buildSuperNoSuchMethod(
+        elements.getSelector(node), elements.getTypeMask(node), [visit(rhs)]);
+  }
+
+  @override
   ir.Primitive visitThisGet(ast.Identifier node, _) {
     if (irBuilder.state.thisParameter == null) {
       // TODO(asgerf,johnniwinther): Should be in a visitInvalidThis method.
@@ -1869,7 +2312,20 @@
 
     List<ir.Primitive> arguments = argumentsNode.nodes.mapToList(visit);
     // Use default values from the effective target, not the immediate target.
-    ConstructorElement target = constructor.effectiveTarget;
+    ConstructorElement target;
+    if (constructor == compiler.symbolConstructor) {
+      // The Symbol constructor should perform validation of its argument
+      // which is not expressible as a Dart const constructor.  Instead, the
+      // libraries contain a dummy const constructor implementation that
+      // doesn't perform validation and the compiler compiles a call to
+      // (non-const) Symbol.validated when it sees new Symbol(...).
+      target = compiler.symbolValidatedConstructor;
+    } else {
+      target = constructor.implementation;
+    }
+    while (target.isRedirectingFactory && !target.isCyclicRedirection) {
+      target = target.effectiveTarget.implementation;
+    }
 
     callStructure = normalizeStaticArguments(callStructure, target, arguments);
     TypeMask allocationSiteType;
@@ -1880,10 +2336,11 @@
         Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) {
       allocationSiteType = getAllocationSiteType(send);
     }
+    ConstructorElement constructorImplementation = constructor.implementation;
     return irBuilder.buildConstructorInvocation(
         target,
         callStructure,
-        constructor.computeEffectiveTargetType(type),
+        constructorImplementation.computeEffectiveTargetType(type),
         arguments,
         sourceInformationBuilder.buildNew(node),
         allocationSiteType: allocationSiteType);
@@ -2085,7 +2542,7 @@
     List<ir.Primitive> normalizedArguments = <ir.Primitive>[];
     CallStructure normalizedCallStructure =
       translateDynamicArguments(arguments, callStructure, normalizedArguments);
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.call(method.memberName, normalizedCallStructure),
         elements.getTypeMask(node),
         normalizedArguments);
@@ -2102,7 +2559,7 @@
         argumentsNode, selector.callStructure, arguments);
     // TODO(johnniwinther): Supply a member name to the visit function instead
     // of looking it up in elements.
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.call(elements.getSelector(node).memberName, callStructure),
         elements.getTypeMask(node),
         arguments);
@@ -2449,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)),
@@ -2489,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)),
@@ -2513,7 +2972,7 @@
   }
 
   ir.Primitive buildSuperNoSuchGetter(Element element, TypeMask mask) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.getter(new Name(element.name, element.library)),
         mask,
         const <ir.Primitive>[]);
@@ -2522,7 +2981,7 @@
   ir.Primitive buildSuperNoSuchSetter(Element element,
                                       TypeMask mask,
                                       ir.Primitive value) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(new Name(element.name, element.library)),
         mask,
         <ir.Primitive>[value]);
@@ -2675,7 +3134,7 @@
     return translateCompounds(node, () {
       return isGetterValid
           ? irBuilder.buildSuperIndex(indexFunction, indexValue)
-          : buildInstanceNoSuchMethod(
+          : buildSuperNoSuchMethod(
               new Selector.index(),
               elements.getGetterTypeMaskInComplexSendSet(node),
               <ir.Primitive>[indexValue]);
@@ -2683,7 +3142,7 @@
       if (isSetterValid) {
         irBuilder.buildSuperIndexSet(indexSetFunction, indexValue, result);
       } else {
-        buildInstanceNoSuchMethod(
+        buildSuperNoSuchMethod(
             new Selector.indexSet(),
             elements.getTypeMask(node),
             <ir.Primitive>[indexValue, result]);
@@ -2900,7 +3359,7 @@
         return irBuilder.buildForeignCode(
             js.js.parseForeignJS(backend.namer.staticStateHolder),
             const <ir.Primitive>[],
-            NativeBehavior.PURE);
+            NativeBehavior.DEPENDS_OTHER);
 
       case 'JS_SET_STATIC_STATE':
         validateArgumentCount(exactly: 1);
@@ -2910,7 +3369,7 @@
         return irBuilder.buildForeignCode(
             js.js.parseForeignJS("$isolateName = #"),
             <ir.Primitive>[value],
-            NativeBehavior.PURE);
+            NativeBehavior.CHANGES_OTHER);
 
       case 'JS_CALL_IN_ISOLATE':
         validateArgumentCount(exactly: 2);
@@ -2984,13 +3443,18 @@
     return irBuilder.buildNonTailThrow(visit(node.expression));
   }
 
-  ir.Primitive buildInstanceNoSuchMethod(Selector selector,
+  ir.Primitive buildSuperNoSuchMethod(Selector selector,
       TypeMask mask,
       List<ir.Primitive> arguments) {
-    return irBuilder.buildDynamicInvocation(
-        irBuilder.buildThis(),
-        Selectors.noSuchMethod_,
-        mask,
+    ClassElement cls = elements.analyzedElement.enclosingClass;
+    MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_);
+    if (!Selectors.noSuchMethod_.signatureApplies(element)) {
+      element = compiler.coreClasses.objectClass.lookupMember(
+          Identifiers.noSuchMethod_);
+    }
+    return irBuilder.buildSuperMethodInvocation(
+        element,
+        Selectors.noSuchMethod_.callStructure,
         [irBuilder.buildInvocationMirror(selector, arguments)]);
   }
 
@@ -3099,7 +3563,7 @@
       Element function,
       ast.Node index, _) {
     // Assume the index getter is missing.
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.index(), elements.getTypeMask(node), [visit(index)]);
   }
 
@@ -3109,7 +3573,7 @@
       Element element,
       op.BinaryOperator operator,
       ast.Node argument, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         elements.getSelector(node),
         elements.getTypeMask(node),
         [visit(argument)]);
@@ -3120,7 +3584,7 @@
       ast.Send node,
       op.UnaryOperator operator,
       Element element, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         elements.getSelector(node), elements.getTypeMask(node), []);
   }
 
@@ -3207,7 +3671,7 @@
       ast.SendSet node,
       FieldElement field,
       ast.Node rhs, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(field.memberName),
         elements.getTypeMask(node),
         [visit(rhs)]);
@@ -3274,7 +3738,7 @@
       GetterElement getter,
       ast.Node rhs,
       _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(getter.memberName),
         elements.getTypeMask(node),
         [visit(rhs)]);
@@ -3286,7 +3750,7 @@
       MethodElement method,
       ast.Node rhs,
       _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(method.memberName),
         elements.getTypeMask(node),
         [visit(rhs)]);
@@ -3296,7 +3760,7 @@
   ir.Primitive visitSuperSetterGet(
       ast.Send node,
       SetterElement setter, _) {
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.setter(setter.memberName),
         elements.getTypeMask(node),
         []);
@@ -3311,7 +3775,7 @@
     List<ir.Primitive> arguments = <ir.Primitive>[];
     callStructure =
         translateDynamicArguments(argumentsNode, callStructure, arguments);
-    return buildInstanceNoSuchMethod(
+    return buildSuperNoSuchMethod(
         new Selector.call(setter.memberName, callStructure),
         elements.getTypeMask(node),
         arguments);
@@ -3544,10 +4008,22 @@
     return TypeMaskFactory.fromNativeBehavior(behavior, _compiler);
   }
 
+  bool isArrayType(TypeMask type) {
+    return type.satisfies(_backend.helpers.jsArrayClass, _compiler.world);
+  }
+
+  TypeMask getTypeMaskForNativeFunction(FunctionElement function) {
+    return  _compiler.typesTask.getGuaranteedReturnTypeOfElement(function);
+  }
+
   FieldElement locateSingleField(Selector selector, TypeMask type) {
     return _compiler.world.locateSingleField(selector, type);
   }
 
+  bool fieldNeverChanges(FieldElement field) {
+    return _compiler.world.fieldNeverChanges(field);
+  }
+
   Element get closureConverter {
     return _backend.helpers.closureConverter;
   }
@@ -3555,4 +4031,22 @@
   void addNativeMethod(FunctionElement function) {
     _backend.emitter.nativeEmitter.nativeMethods.add(function);
   }
+
+  bool get trustJSInteropTypeAnnotations =>
+      _compiler.trustJSInteropTypeAnnotations;
+
+  bool isNative(ClassElement element) => _backend.isNative(element);
+
+  bool isJsInterop(FunctionElement element) => _backend.isJsInterop(element);
+
+  bool isJsInteropAnonymous(FunctionElement element) =>
+    _backend.jsInteropAnalysis.hasAnonymousAnnotation(element.contextClass);
+
+  String getJsInteropTargetPath(FunctionElement element) {
+    return '${_backend.namer.fixedBackendPath(element)}.'
+      '${_backend.getFixedBackendName(element)}';
+  }
+
+  DartType get jsJavascriptObjectType =>
+    _backend.helpers.jsJavaScriptObjectClass.thisType;
 }
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 49c8a6b..61a5ddd 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -5,16 +5,20 @@
 
 import 'dart:collection';
 import 'cps_fragment.dart' show CpsFragment;
+import 'cps_ir_nodes_sexpr.dart';
 import '../constants/values.dart' as values;
 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType;
 import '../elements/elements.dart';
 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.
@@ -39,6 +43,38 @@
   ///
   /// All constructors call this method to initialize parent pointers.
   void setParentPointers();
+
+  /// Returns the SExpression for the subtree rooted at this node.
+  ///
+  /// [annotations] maps strings to nodes and/or nodes to values that will be
+  /// converted to strings. Each binding causes the annotation to appear on the
+  /// given node.
+  ///
+  /// For example, the following could be used to diagnose a problem with nodes
+  /// not appearing in an environment map:
+  ///
+  ///     if (environment[node] == null)
+  ///       root.debugPrint({
+  ///         'currentNode': node,
+  ///         'caller': someContinuation
+  ///       });
+  ///       throw 'Node was not in environment';
+  ///     }
+  ///
+  /// If two strings map to the same node, it will be given both annotations.
+  ///
+  /// Avoid using nodes as keys if there is a chance that two keys are the
+  /// same node.
+  String debugString([Map annotations]) {
+    return new SExpressionStringifier()
+        .withAnnotations(annotations)
+        .visit(this);
+  }
+
+  /// Prints the result of [debugString].
+  void debugPrint([Map annotations]) {
+    print(debugString(annotations));
+  }
 }
 
 /// Expressions can be evaluated, and may diverge, throw, and/or have
@@ -83,6 +119,1663 @@
   accept(BlockVisitor visitor);
 }
 
+/// 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 hasExactlyOneUse => firstRef != null && firstRef.next == null;
+  bool get hasNoUses => firstRef == null;
+  bool get hasAtLeastOneUse => firstRef != null;
+  bool get hasMultipleUses => !hasAtMostOneUse;
+
+  void replaceUsesWith(Definition<T> newDefinition) {
+    if (newDefinition == this) return;
+    if (hasNoUses) return;
+    Reference<T> previous, current = firstRef;
+    do {
+      current.definition = newDefinition;
+      previous = current;
+      current = current.next;
+    } while (current != null);
+    previous.next = newDefinition.firstRef;
+    if (newDefinition.firstRef != null) {
+      newDefinition.firstRef.previous = previous;
+    }
+    newDefinition.firstRef = firstRef;
+    firstRef = null;
+  }
+}
+
+/// 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;
+  final List<Refinement> stack = <Refinement>[];
+
+  EffectiveUseIterator(Primitive prim) : next = prim.firstRef;
+
+  bool moveNext() {
+    Reference<Primitive> ref = next;
+    while (true) {
+      if (ref == null) {
+        if (stack.isNotEmpty) {
+          ref = stack.removeLast().firstRef;
+        } else {
+          current = null;
+          return false;
+        }
+      } else if (ref.parent is Refinement) {
+        stack.add(ref.parent);
+        ref = ref.next;
+      } else {
+        current = ref;
+        next = current.next;
+        return true;
+      }
+    }
+  }
+}
+
+class RefinedUseIterable extends IterableBase<Reference<Primitive>> {
+  Primitive primitive;
+  RefinedUseIterable(this.primitive);
+  EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive);
+}
+
+/// A named value.
+///
+/// The identity of the [Primitive] object is the name of the value.
+/// The subclass describes how to compute the value.
+///
+/// All primitives except [Parameter] must be bound by a [LetPrim].
+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;
+
+  /// True if the primitive can be removed, assuming it has no uses
+  /// (this getter does not check if there are any uses).
+  ///
+  /// False must be returned for primitives that may throw, diverge, or have
+  /// observable side-effects.
+  bool get isSafeForElimination;
+
+  /// True if time-of-evaluation is irrelevant for the given primitive,
+  /// assuming its inputs are the same values.
+  bool get isSafeForReordering;
+
+  /// The source information associated with this primitive.
+  // 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
+  /// that was checked to be non-null, respectively.
+  ///
+  /// Those instructions all return the corresponding operand directly, and
+  /// this getter can be used to get (closer to) where the value came from.
+  //
+  // TODO(asgerf): Also do this for [TypeCast]?
+  Primitive get effectiveDefinition => this;
+
+  /// Like [effectiveDefinition] but only unfolds [Refinement] nodes.
+  Primitive get unrefined => this;
+
+  /// True if the two primitives are (refinements of) the same value.
+  bool sameValue(Primitive other) {
+    return effectiveDefinition == other.effectiveDefinition;
+  }
+
+  /// Iterates all non-refinement uses of the primitive and all uses of
+  /// a [Refinement] of this primitive (transitively).
+  ///
+  /// Notes regarding concurrent modification:
+  /// - The current reference may safely be unlinked.
+  /// - Yet unvisited references may not be unlinked.
+  /// - References to this primitive created during iteration will not be seen.
+  /// - References to a refinement of this primitive may not be created during
+  ///   iteration.
+  RefinedUseIterable get refinedUses => new RefinedUseIterable(this);
+
+  bool get hasMultipleRefinedUses {
+    Iterator it = refinedUses.iterator;
+    return it.moveNext() && it.moveNext();
+  }
+
+  bool get hasNoRefinedUses {
+    return refinedUses.isEmpty;
+  }
+
+  /// Unlinks all references contained in this node.
+  void destroy() {
+    assert(hasNoUses);
+    RemovalVisitor.remove(this);
+  }
+
+  /// Replaces this definition, both at the binding site and at all uses sites.
+  ///
+  /// This can be thought of as changing the definition of a `let` while
+  /// preserving the variable name:
+  ///
+  ///     let x = OLD in BODY
+  ///       ==>
+  ///     let x = NEW in BODY
+  ///
+  void replaceWith(Primitive newDefinition) {
+    assert(this is! Parameter);
+    assert(newDefinition is! Parameter);
+    assert(newDefinition.parent == null);
+    replaceUsesWith(newDefinition);
+    destroy();
+    LetPrim let = parent;
+    let.primitive = newDefinition;
+    newDefinition.parent = let;
+    newDefinition.useElementAsHint(hint);
+  }
+
+  /// Replaces this definition with a CPS fragment (a term with a hole in it),
+  /// given the value to replace the uses of the definition with.
+  ///
+  /// This can be thought of as substituting:
+  ///
+  ///     let x = OLD in BODY
+  ///       ==>
+  ///     FRAGMENT[BODY{newPrimitive/x}]
+  void replaceWithFragment(CpsFragment fragment, Primitive newPrimitive) {
+    assert(this is! Parameter);
+    replaceUsesWith(newPrimitive);
+    destroy();
+    LetPrim let = parent;
+    fragment.insertBelow(let);
+    let.remove();
+  }
+}
+
+/// 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'.
+class Continuation extends Definition<Continuation> implements InteriorNode {
+  final List<Parameter> parameters;
+  Expression body = null;
+
+  // A continuation is recursive if it has any recursive invocations.
+  bool isRecursive;
+
+  /// True if this is the return continuation.  The return continuation is bound
+  /// by [FunctionDefinition].
+  bool get isReturnContinuation => body == null;
+
+  /// True if this is a branch continuation.  Branch continuations are bound
+  /// by [LetCont] and can only have one use.
+  bool get isBranchContinuation => firstRef?.parent is Branch;
+
+  /// True if this is the exception handler bound by a [LetHandler].
+  bool get isHandlerContinuation => parent is LetHandler;
+
+  /// True if this is a non-return continuation that can be targeted by
+  /// [InvokeContinuation].
+  bool get isJoinContinuation {
+    return body != null &&
+        parent is! LetHandler &&
+        (firstRef == null || firstRef.parent is InvokeContinuation);
+  }
+
+  Continuation(this.parameters, {this.isRecursive: false});
+
+  Continuation.retrn()
+      : parameters = <Parameter>[new Parameter(null)],
+        isRecursive = false;
+
+  accept(BlockVisitor visitor) => visitor.visitContinuation(this);
+
+  void setParentPointers() {
+    _setParentsOnNodes(parameters, this);
+    if (body != null) body.parent = this;
+  }
+}
+
+/// Common interface for [Primitive] and [MutableVariable].
+abstract class Variable<T extends Variable<T>> extends Definition<T> {
+  /// Type of value held in the variable.
+  ///
+  /// Is `null` until initialized by type propagation.
+  TypeMask type;
+
+  /// The [VariableElement] or [ParameterElement] from which the variable
+  /// binding originated.
+  Entity hint;
+
+  Variable(this.hint);
+
+  /// Use the given element as a hint for naming this primitive.
+  ///
+  /// Has no effect if this primitive already has a non-null [element].
+  void useElementAsHint(Entity hint) {
+    this.hint ??= hint;
+  }
+}
+
+/// Identifies a mutable variable.
+class MutableVariable extends Variable<MutableVariable> {
+  MutableVariable(Entity hint) : super(hint);
+
+  accept(Visitor v) => v.visitMutableVariable(this);
+
+  void setParentPointers() {}
+}
+
+/// A function definition, consisting of parameters and a body.
+///
+/// There is an explicit parameter for the `this` argument, and a return
+/// continuation to invoke when returning from the function.
+class FunctionDefinition extends InteriorNode {
+  final ExecutableElement element;
+  final Parameter thisParameter;
+  final List<Parameter> parameters;
+  final Continuation returnContinuation;
+  Expression body;
+
+  FunctionDefinition(this.element, this.thisParameter, this.parameters,
+      this.returnContinuation, this.body);
+
+  accept(BlockVisitor visitor) => visitor.visitFunctionDefinition(this);
+
+  void setParentPointers() {
+    if (thisParameter != null) thisParameter.parent = this;
+    _setParentsOnNodes(parameters, this);
+    returnContinuation.parent = this;
+    if (body != null) body.parent = this;
+  }
+}
+
+// ----------------------------------------------------------------------------
+//                            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> valueRef;
+
+  final SourceInformation sourceInformation;
+
+  Primitive get value => valueRef.definition;
+
+  ReifyRuntimeType(Primitive value, this.sourceInformation)
+      : this.valueRef = new Reference<Primitive>(value);
+
+  @override
+  accept(Visitor visitor) => visitor.visitReifyRuntimeType(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    valueRef.parent = this;
+  }
+}
+
+/// Read the value the type variable [variable] from the target object.
+///
+/// The resulting value is an internal representation (and not neccessarily a
+/// Dart object), and must be reified by [ReifyRuntimeType], if it should be
+/// used as a Dart value.
+class ReadTypeVariable extends Primitive {
+  final TypeVariableType variable;
+  final Reference<Primitive> targetRef;
+  final SourceInformation sourceInformation;
+
+  Primitive get target => targetRef.definition;
+
+  ReadTypeVariable(this.variable, Primitive target, this.sourceInformation)
+      : this.targetRef = new Reference<Primitive>(target);
+
+  @override
+  accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    targetRef.parent = this;
+  }
+}
+
+enum TypeExpressionKind { COMPLETE, INSTANCE }
+
+/// Constructs a representation of a closed or ground-term type (that is, a type
+/// without type variables).
+///
+/// There are two forms:
+///
+/// - COMPLETE: A complete form that is self contained, used for the values of
+///   type parameters and non-raw is-checks.
+///
+/// - INSTANCE: A headless flat form for representing the sequence of values of
+///   the type parameters of an instance of a generic type.
+///
+/// The COMPLETE form value is constructed from [dartType] by replacing the type
+/// variables with consecutive values from [arguments], in the order generated
+/// by [DartType.forEachTypeVariable].  The type variables in [dartType] are
+/// treated as 'holes' in the term, which means that it must be ensured at
+/// construction, that duplicate occurences of a type variable in [dartType]
+/// are assigned the same value.
+///
+/// The INSTANCE form is constructed as a list of [arguments]. This is the same
+/// as the COMPLETE form for the 'thisType', except the root term's type is
+/// missing; this is implicit as the raw type of instance.  The [dartType] of
+/// the INSTANCE form must be the thisType of some class.
+///
+/// While we would like to remove the constrains on the INSTANCE form, we can
+/// get by with a tree of TypeExpressions.  Consider:
+///
+///     class Foo<T> {
+///       ... new Set<List<T>>()
+///     }
+///     class Set<E1> {
+///       factory Set() => new _LinkedHashSet<E1>();
+///     }
+///     class List<E2> { ... }
+///     class _LinkedHashSet<E3> { ... }
+///
+/// After inlining the factory constructor for `Set<E1>`, the CreateInstance
+/// should have type `_LinkedHashSet<List<T>>` and the TypeExpression should be
+/// a tree:
+///
+///    CreateInstance(dartType: _LinkedHashSet<List<T>>,
+///        [], // No arguments
+///        TypeExpression(INSTANCE,
+///            dartType: _LinkedHashSet<E3>, // _LinkedHashSet's thisType
+///            TypeExpression(COMPLETE,  // E3 = List<T>
+///                dartType: List<E2>,
+///                ReadTypeVariable(this, T)))) // E2 = T
+//
+// TODO(sra): The INSTANCE form requires the actual instance for full
+// interpretation. I want to move to a representation where the INSTANCE form is
+// also a complete form (possibly the same).
+class TypeExpression extends Primitive {
+  final TypeExpressionKind kind;
+  final DartType dartType;
+  final List<Reference<Primitive>> argumentRefs;
+
+  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);
+  }
+
+  @override
+  accept(Visitor visitor) {
+    return visitor.visitTypeExpression(this);
+  }
+
+  bool get hasValue => true;
+  bool get isSafeForElimination => true;
+  bool get isSafeForReordering => true;
+
+  void setParentPointers() {
+    _setParentsOnList(argumentRefs, this);
+  }
+
+  String get kindAsString {
+    switch (kind) {
+      case TypeExpressionKind.COMPLETE:
+        return 'COMPLETE';
+      case TypeExpressionKind.INSTANCE:
+        return 'INSTANCE';
+    }
+  }
+}
+
+class Await extends UnsafePrimitive {
+  final Reference<Primitive> inputRef;
+
+  Primitive get input => inputRef.definition;
+
+  Await(Primitive input) : this.inputRef = new Reference<Primitive>(input);
+
+  @override
+  accept(Visitor visitor) {
+    return visitor.visitAwait(this);
+  }
+
+  bool get hasValue => true;
+
+  void setParentPointers() {
+    inputRef.parent = this;
+  }
+}
+
+class Yield extends UnsafePrimitive {
+  final Reference<Primitive> inputRef;
+  final bool hasStar;
+
+  Primitive get input => inputRef.definition;
+
+  Yield(Primitive input, this.hasStar)
+      : this.inputRef = new Reference<Primitive>(input);
+
+  @override
+  accept(Visitor visitor) {
+    return visitor.visitYield(this);
+  }
+
+  bool get hasValue => true;
+
+  void setParentPointers() {
+    inputRef.parent = this;
+  }
+}
+
+// ---------------------------------------------------------------------------
+//                            EXPRESSIONS
+// ---------------------------------------------------------------------------
+
 /// An expression that creates new bindings and continues evaluation in
 /// a subexpression.
 ///
@@ -136,227 +1829,6 @@
   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 hasExactlyOneUse => firstRef != null && firstRef.next == null;
-  bool get hasNoUses => firstRef == null;
-  bool get hasAtLeastOneUse => firstRef != null;
-  bool get hasMultipleUses  => !hasAtMostOneUse;
-
-  void replaceUsesWith(Definition<T> newDefinition) {
-    if (newDefinition == this) return;
-    if (hasNoUses) return;
-    Reference<T> previous, current = firstRef;
-    do {
-      current.definition = newDefinition;
-      previous = current;
-      current = current.next;
-    } while (current != null);
-    previous.next = newDefinition.firstRef;
-    if (newDefinition.firstRef != null) {
-      newDefinition.firstRef.previous = previous;
-    }
-    newDefinition.firstRef = firstRef;
-    firstRef = null;
-  }
-}
-
-class EffectiveUseIterator extends Iterator<Reference<Primitive>> {
-  Reference<Primitive> current;
-  Reference<Primitive> next;
-  final List<Refinement> stack = <Refinement>[];
-
-  EffectiveUseIterator(Primitive prim) : next = prim.firstRef;
-
-  bool moveNext() {
-    Reference<Primitive> ref = next;
-    while (true) {
-      if (ref == null) {
-        if (stack.isNotEmpty) {
-          ref = stack.removeLast().firstRef;
-        } else {
-          current = null;
-          return false;
-        }
-      } else if (ref.parent is Refinement) {
-        stack.add(ref.parent);
-        ref = ref.next;
-      } else {
-        current = ref;
-        next = current.next;
-        return true;
-      }
-    }
-  }
-}
-
-class EffectiveUseIterable extends IterableBase<Reference<Primitive>> {
-  Primitive primitive;
-  EffectiveUseIterable(this.primitive);
-  EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive);
-}
-
-/// A named value.
-///
-/// The identity of the [Primitive] object is the name of the value.
-/// The subclass describes how to compute the value.
-///
-/// All primitives except [Parameter] must be bound by a [LetPrim].
-abstract class Primitive extends Variable<Primitive> {
-  Primitive() : super(null);
-
-  /// True if this primitive has a value that can be used by other expressions.
-  bool get hasValue;
-
-  /// True if the primitive can be removed, assuming it has no uses
-  /// (this getter does not check if there are any uses).
-  ///
-  /// False must be returned for primitives that may throw, diverge, or have
-  /// observable side-effects.
-  bool get isSafeForElimination;
-
-  /// True if time-of-evaluation is irrelevant for the given primitive,
-  /// assuming its inputs are the same values.
-  bool get isSafeForReordering;
-
-  /// The source information associated with this primitive.
-  // TODO(johnniwinther): Require source information for all primitives.
-  SourceInformation get sourceInformation => null;
-
-  /// If this is a [Refinement], [BoundsCheck] or [NullCheck] 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
-  /// this getter can be used to get (closer to) where the value came from.
-  //
-  // TODO(asgerf): Also do this for [TypeCast]?
-  Primitive get effectiveDefinition => this;
-
-  /// True if the two primitives are (refinements of) the same value.
-  bool sameValue(Primitive other) {
-    return effectiveDefinition == other.effectiveDefinition;
-  }
-
-  /// Iterates all non-refinement uses of the primitive and all uses of
-  /// a [Refinement] of this primitive (transitively).
-  ///
-  /// Notes regarding concurrent modification:
-  /// - The current reference may safely be unlinked.
-  /// - Yet unvisited references may not be unlinked.
-  /// - References to this primitive created during iteration will not be seen.
-  /// - References to a refinement of this primitive may not be created during
-  ///   iteration.
-  EffectiveUseIterable get effectiveUses => new EffectiveUseIterable(this);
-
-  bool get hasMultipleEffectiveUses {
-    Iterator it = effectiveUses.iterator;
-    return it.moveNext() && it.moveNext();
-  }
-
-  bool get hasNoEffectiveUses {
-    return effectiveUses.isEmpty;
-  }
-
-  /// Unlinks all references contained in this node.
-  void destroy() {
-    assert(hasNoUses);
-    RemovalVisitor.remove(this);
-  }
-
-  /// Replaces this definition, both at the binding site and at all uses sites.
-  ///
-  /// This can be thought of as changing the definition of a `let` while
-  /// preserving the variable name:
-  ///
-  ///     let x = OLD in BODY
-  ///       ==>
-  ///     let x = NEW in BODY
-  ///
-  void replaceWith(Primitive newDefinition) {
-    assert(this is! Parameter);
-    assert(newDefinition is! Parameter);
-    assert(newDefinition.parent == null);
-    replaceUsesWith(newDefinition);
-    destroy();
-    LetPrim let = parent;
-    let.primitive = newDefinition;
-    newDefinition.parent = let;
-    newDefinition.useElementAsHint(hint);
-  }
-
-  /// Replaces this definition with a CPS fragment (a term with a hole in it),
-  /// given the value to replace the uses of the definition with.
-  ///
-  /// This can be thought of as substituting:
-  ///
-  ///     let x = OLD in BODY
-  ///       ==>
-  ///     FRAGMENT[BODY{newPrimitive/x}]
-  void replaceWithFragment(CpsFragment fragment, Primitive newPrimitive) {
-    assert(this is! Parameter);
-    replaceUsesWith(newPrimitive);
-    destroy();
-    LetPrim let = parent;
-    fragment.insertBelow(let);
-    let.remove();
-  }
-}
-
-/// 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.
@@ -409,8 +1881,8 @@
 
   Expression plug(Expression expr) {
     assert(continuations != null &&
-           continuations.isNotEmpty &&
-           continuations.first.body == null);
+        continuations.isNotEmpty &&
+        continuations.first.body == null);
     return continuations.first.body = expr;
   }
 
@@ -456,11 +1928,13 @@
 /// one-hole context 'let mutable v = P in []'.
 class LetMutable extends InteriorExpression {
   final MutableVariable variable;
-  final Reference<Primitive> value;
+  final Reference<Primitive> valueRef;
   Expression body;
 
+  Primitive get value => valueRef.definition;
+
   LetMutable(this.variable, Primitive value)
-      : this.value = new Reference<Primitive>(value);
+      : this.valueRef = new Reference<Primitive>(value);
 
   Expression plug(Expression expr) {
     return body = expr;
@@ -470,597 +1944,26 @@
 
   void setParentPointers() {
     variable.parent = this;
-    value.parent = this;
+    valueRef.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);
-  }
-}
-
-/// 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;
-
-  void setParentPointers() {
-    value.parent = this;
-  }
-}
-
-/// Checks that [index] is a valid index on a given indexable [object].
-///
-/// Compiles to the following, with a subset of the conditions in the `if`:
-///
-///     if (index < 0 || index >= object.length || object.length === 0)
-///         ThrowIndexOutOfRangeException(object, index);
-///
-/// [index] must be an integer, 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; // FIXME write docs for 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;
-
-  /// 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 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 (hasUpperBoundCheck && hasLowerBoundCheck) {
-      return 'upper-lower-checks';
-    } else if (hasUpperBoundCheck) {
-      return 'upper-check';
-    } else if (hasLowerBoundCheck) {
-      return 'lower-check';
-    } else if (hasEmptinessCheck) {
-      return 'emptiness-check';
-    } else {
-      return 'no-check';
-    }
-  }
-
-  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 an exception if [value] is `null`.
-///
-/// Returns [value] so this can be used to restrict code motion.
-///
-/// In the simplest form this compiles to `value.toString;`.
-///
-/// [selector] holds the selector that is the cause of the null check. This is
-/// usually a method that was inlined where [value] the receiver.
-///
-/// If [selector] is set and [useSelector] is true, `toString` is replaced with
-/// the (possibly minified) invocation name of the selector.  This can be
-/// shorter and generate a more meaningful error message, but is expensive if
-/// [value] is non-null and does not have that property at runtime.
-///
-/// If [condition] is set, it is assumed that [condition] is true if and only
-/// if [value] is null.  The check then compiles to:
-///
-///     if (condition) value.toString;  (or .selector if non-null)
-///
-/// The latter form is useful when [condition] is a form understood by the JS
-/// runtime, such as a `typeof` test.
-class NullCheck extends Primitive {
-  final Reference<Primitive> value;
-  final Selector selector;
-  final bool useSelector;
-  final Reference<Primitive> condition;
-  final SourceInformation sourceInformation;
-
-  NullCheck(Primitive value, this.sourceInformation,
-            {Primitive condition,
-             this.selector,
-             this.useSelector: false})
-      : this.value = new Reference<Primitive>(value),
-        this.condition =
-            condition == null ? null : new Reference<Primitive>(condition);
-
-  NullCheck.guarded(Primitive condition, Primitive value, this.selector,
-        this.sourceInformation)
-      : this.condition = new Reference<Primitive>(condition),
-        this.value = new Reference<Primitive>(value),
-        this.useSelector = true;
-
-  bool get isSafeForElimination => false;
-  bool get isSafeForReordering => false;
-  bool get hasValue => true;
-
-  accept(Visitor visitor) => visitor.visitNullCheck(this);
-
-  void setParentPointers() {
-    value.parent = this;
-    if (condition != null) {
-      condition.parent = this;
-    }
-  }
-
-  Primitive get effectiveDefinition => value.definition.effectiveDefinition;
-}
-
-/// 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;
+  Reference<Primitive> valueRef;
 
-  Throw(Primitive value) : value = new Reference<Primitive>(value);
+  Primitive get value => valueRef.definition;
+
+  Throw(Primitive value) : valueRef = new Reference<Primitive>(value);
 
   accept(BlockVisitor visitor) => visitor.visitThrow(this);
 
   void setParentPointers() {
-    value.parent = this;
+    valueRef.parent = this;
   }
 }
 
@@ -1083,62 +1986,16 @@
   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;
+  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;
@@ -1148,11 +2005,11 @@
   bool isEscapingTry;
 
   InvokeContinuation(Continuation cont, List<Primitive> args,
-                     {this.isRecursive: false,
-                      this.isEscapingTry: false,
-                      this.sourceInformation})
-      : continuation = new Reference<Continuation>(cont),
-        arguments = _referenceList(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;
   }
@@ -1162,17 +2019,17 @@
   ///
   /// 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,
+  InvokeContinuation.uninitialized(
+      {this.isRecursive: false, this.isEscapingTry: false})
+      : continuationRef = null,
+        argumentRefs = null,
         sourceInformation = null;
 
   accept(BlockVisitor visitor) => visitor.visitInvokeContinuation(this);
 
   void setParentPointers() {
-    if (continuation != null) continuation.parent = this;
-    if (arguments != null) _setParentsOnList(arguments, this);
+    if (continuationRef != null) continuationRef.parent = this;
+    if (argumentRefs != null) _setParentsOnList(argumentRefs, this);
   }
 }
 
@@ -1180,9 +2037,13 @@
 ///
 /// The two continuations must not declare any parameters.
 class Branch extends TailExpression {
-  final Reference<Primitive> condition;
-  final Reference<Continuation> trueContinuation;
-  final Reference<Continuation> falseContinuation;
+  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.
@@ -1191,659 +2052,52 @@
   /// 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),
+  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.strict(
+      Primitive condition, Continuation trueCont, Continuation falseCont)
+      : this(condition, trueCont, falseCont, strict: true);
 
-  Branch.loose(Primitive condition,
-               Continuation trueCont,
-               Continuation falseCont)
+  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;
+    conditionRef.parent = this;
+    trueContinuationRef.parent = this;
+    falseContinuationRef.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;
+// ----------------------------------------------------------------------------
+//                            UTILITY STUFF
+// ----------------------------------------------------------------------------
 
-  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;
-  }
+Reference<Primitive> _reference(Primitive definition) {
+  return new Reference<Primitive>(definition);
 }
 
-/// 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 List<Reference<Primitive>> typeInformation;
-
-  final SourceInformation sourceInformation;
-
-  CreateInstance(this.classElement, List<Primitive> arguments,
-      List<Primitive> typeInformation,
-      this.sourceInformation)
-      : this.arguments = _referenceList(arguments),
-        this.typeInformation = _referenceList(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) _setParentsOnList(typeInformation, 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 type;
-  final List<Reference<Primitive>> arguments;
-  final native.NativeBehavior nativeBehavior;
-  final FunctionElement dependency;
-
-  ForeignCode(this.codeTemplate, this.type, 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 LiteralMapEntry {
-  final Reference<Primitive> key;
-  final Reference<Primitive> value;
-
-  LiteralMapEntry(Primitive key, Primitive value)
-      : this.key = new Reference<Primitive>(key),
-        this.value = new Reference<Primitive>(value);
-}
-
-class LiteralMap extends Primitive {
-  final InterfaceType dartType;
-  final List<LiteralMapEntry> entries;
-
-  LiteralMap(this.dartType, this.entries);
-
-  accept(Visitor visitor) => visitor.visitLiteralMap(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    for (LiteralMapEntry entry in entries) {
-      entry.key.parent = this;
-      entry.value.parent = 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'.
-class Continuation extends Definition<Continuation> implements InteriorNode {
-  final List<Parameter> parameters;
-  Expression body = null;
-
-  // A continuation is recursive if it has any recursive invocations.
-  bool isRecursive;
-
-  bool get isReturnContinuation => body == null;
-
-  Continuation(this.parameters, {this.isRecursive: false});
-
-  Continuation.retrn()
-    : parameters = <Parameter>[new Parameter(null)],
-      isRecursive = false;
-
-  accept(BlockVisitor visitor) => visitor.visitContinuation(this);
-
-  void setParentPointers() {
-    _setParentsOnNodes(parameters, this);
-    if (body != null) body.parent = this;
-  }
-}
-
-/// Common interface for [Primitive] and [MutableVariable].
-abstract class Variable<T extends Variable<T>> extends Definition<T> {
-  /// Type of value held in the variable.
-  ///
-  /// Is `null` until initialized by type propagation.
-  TypeMask type;
-
-  /// The [VariableElement] or [ParameterElement] from which the variable
-  /// binding originated.
-  Entity hint;
-
-  Variable(this.hint);
-
-  /// Use the given element as a hint for naming this primitive.
-  ///
-  /// Has no effect if this primitive already has a non-null [element].
-  void useElementAsHint(Entity hint) {
-    this.hint ??= hint;
-  }
-}
-
-/// Identifies a mutable variable.
-class MutableVariable extends Variable<MutableVariable> {
-  MutableVariable(Entity hint) : super(hint);
-
-  accept(Visitor v) => v.visitMutableVariable(this);
-
-  void setParentPointers() {}
-}
-
-/// A function definition, consisting of parameters and a body.
-///
-/// There is an explicit parameter for the `this` argument, and a return
-/// continuation to invoke when returning from the function.
-class FunctionDefinition extends InteriorNode {
-  final ExecutableElement element;
-  final Parameter thisParameter;
-  final List<Parameter> parameters;
-  final Continuation returnContinuation;
-  Expression body;
-
-  FunctionDefinition(this.element,
-      this.thisParameter,
-      this.parameters,
-      this.returnContinuation,
-      this.body);
-
-  accept(BlockVisitor visitor) => visitor.visitFunctionDefinition(this);
-
-  void setParentPointers() {
-    if (thisParameter != null) thisParameter.parent = this;
-    _setParentsOnNodes(parameters, this);
-    returnContinuation.parent = this;
-    if (body != null) body.parent = 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 SourceInformation sourceInformation;
-
-  ReifyRuntimeType(Primitive value, this.sourceInformation)
-    : this.value = new Reference<Primitive>(value);
-
-  @override
-  accept(Visitor visitor) => visitor.visitReifyRuntimeType(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    value.parent = this;
-  }
-}
-
-/// Read the value the type variable [variable] from the target object.
-///
-/// The resulting value is an internal representation (and not neccessarily a
-/// Dart object), and must be reified by [ReifyRuntimeType], if it should be
-/// used as a Dart value.
-class ReadTypeVariable extends Primitive {
-  final TypeVariableType variable;
-  final Reference<Primitive> target;
-  final SourceInformation sourceInformation;
-
-  ReadTypeVariable(this.variable, Primitive target, this.sourceInformation)
-      : this.target = new Reference<Primitive>(target);
-
-  @override
-  accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    target.parent = this;
-  }
-}
-
-/// Representation of a closed type (that is, a type without type variables).
-///
-/// The resulting value is constructed from [dartType] by replacing the type
-/// variables with consecutive values from [arguments], in the order generated
-/// by [DartType.forEachTypeVariable].  The type variables in [dartType] are
-/// treated as 'holes' in the term, which means that it must be ensured at
-/// construction, that duplicate occurences of a type variable in [dartType]
-/// are assigned the same value.
-class TypeExpression extends Primitive {
-  final DartType dartType;
-  final List<Reference<Primitive>> arguments;
-
-  TypeExpression(this.dartType,
-                 [List<Primitive> arguments = const <Primitive>[]])
-      : this.arguments = _referenceList(arguments);
-
-  @override
-  accept(Visitor visitor) {
-    return visitor.visitTypeExpression(this);
-  }
-
-  bool get hasValue => true;
-  bool get isSafeForElimination => true;
-  bool get isSafeForReordering => true;
-
-  void setParentPointers() {
-    _setParentsOnList(arguments, this);
-  }
-}
-
-class Await extends UnsafePrimitive {
-  final Reference<Primitive> input;
-
-  Await(Primitive input)
-    : this.input = new Reference<Primitive>(input);
-
-  @override
-  accept(Visitor visitor) {
-    return visitor.visitAwait(this);
-  }
-
-  bool get hasValue => true;
-
-  void setParentPointers() {
-    input.parent = this;
-  }
-}
-
-class Yield extends UnsafePrimitive {
-  final Reference<Primitive> input;
-  final bool hasStar;
-
-  Yield(Primitive input, this.hasStar)
-    : this.input = new Reference<Primitive>(input);
-
-  @override
-  accept(Visitor visitor) {
-    return visitor.visitYield(this);
-  }
-
-  bool get hasValue => true;
-
-  void setParentPointers() {
-    input.parent = this;
-  }
+Reference<Primitive> _optionalReference(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;
@@ -1856,6 +2110,10 @@
   }
 }
 
+// ----------------------------------------------------------------------------
+//                                 VISITORS
+// ----------------------------------------------------------------------------
+
 /// Visitor for block-level traversals that do not need to dispatch on
 /// primitives.
 abstract class BlockVisitor<T> {
@@ -1921,23 +2179,25 @@
 
   /// Visits block-level nodes in lexical pre-order.
   ///
-  /// The IR may be transformed during the traversal, but the currently
-  /// visited node should not be removed, as its 'body' pointer is needed
-  /// for the traversal.
+  /// Traversal continues at the original success for the current node, so:
+  /// - The current node can safely be removed.
+  /// - Nodes inserted immediately below the current node will not be seen.
+  /// - The body of the current node should not be moved/removed, as traversal
+  ///   would otherwise continue into an orphaned or relocated node.
   static void traverseInPreOrder(FunctionDefinition root, BlockVisitor v) {
     List<Continuation> stack = <Continuation>[];
     void walkBlock(InteriorNode block) {
       v.visit(block);
       Expression node = block.body;
-      v.visit(node);
-      while (node.next != null) {
+      while (node != null) {
         if (node is LetCont) {
           stack.addAll(node.continuations);
         } else if (node is LetHandler) {
           stack.add(node.handler);
         }
-        node = node.next;
+        Expression next = node.next;
         v.visit(node);
+        node = next;
       }
     }
     walkBlock(root);
@@ -1965,7 +2225,6 @@
   T visitAwait(Await node);
   T visitYield(Yield node);
   T visitLiteralList(LiteralList node);
-  T visitLiteralMap(LiteralMap node);
   T visitConstant(Constant node);
   T visitGetMutable(GetMutable node);
   T visitParameter(Parameter node);
@@ -1988,7 +2247,7 @@
   T visitSetIndex(SetIndex node);
   T visitRefinement(Refinement node);
   T visitBoundsCheck(BoundsCheck node);
-  T visitNullCheck(NullCheck node);
+  T visitReceiverCheck(ReceiverCheck node);
   T visitForeignCode(ForeignCode node);
 }
 
@@ -2016,7 +2275,6 @@
     processFunctionDefinition(node);
     if (node.thisParameter != null) visit(node.thisParameter);
     node.parameters.forEach(visit);
-    visit(node.returnContinuation);
     visit(node.body);
   }
 
@@ -2053,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) {}
@@ -2104,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) {}
@@ -2144,20 +2402,11 @@
   processLiteralList(LiteralList node) {}
   visitLiteralList(LiteralList node) {
     processLiteralList(node);
-    node.values.forEach(processReference);
-  }
-
-  processLiteralMap(LiteralMap node) {}
-  visitLiteralMap(LiteralMap node) {
-    processLiteralMap(node);
-    for (LiteralMapEntry entry in node.entries) {
-      processReference(entry.key);
-      processReference(entry.value);
-    }
+    node.valueRefs.forEach(processReference);
   }
 
   processConstant(Constant node) {}
-  visitConstant(Constant node)  {
+  visitConstant(Constant node) {
     processConstant(node);
   }
 
@@ -2169,7 +2418,7 @@
   processGetMutable(GetMutable node) {}
   visitGetMutable(GetMutable node) {
     processGetMutable(node);
-    processReference(node.variable);
+    processReference(node.variableRef);
   }
 
   processParameter(Parameter node) {}
@@ -2180,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);
-    node.typeInformation.forEach(processReference);
+    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) {}
@@ -2225,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) {}
@@ -2273,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) {}
@@ -2312,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(NullCheck node) {}
-  visitNullCheck(NullCheck node) {
+  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);
     }
   }
 }
@@ -2377,7 +2628,6 @@
     processFunctionDefinition(node);
     if (node.thisParameter != null) visit(node.thisParameter);
     node.parameters.forEach(visit);
-    visit(node.returnContinuation);
     visit(node.body);
   }
 
@@ -2423,7 +2673,7 @@
   Expression traverseLetMutable(LetMutable node) {
     processLetMutable(node);
     visit(node.variable);
-    processReference(node.value);
+    processReference(node.valueRef);
     return node.body;
   }
 
@@ -2489,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));
   }
 
@@ -2513,72 +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;
-  }
-
-  Definition visitLiteralMap(LiteralMap node) {
-    List<LiteralMapEntry> entries = node.entries.map((LiteralMapEntry entry) {
-      return new LiteralMapEntry(getCopy(entry.key), getCopy(entry.value));
-    }).toList();
-    return new LiteralMap(node.dartType, entries);
+    return new LiteralList(node.dartType, getList(node.valueRefs))
+      ..allocationSiteType = node.allocationSiteType;
   }
 
   Definition visitConstant(Constant node) {
@@ -2586,7 +2835,7 @@
   }
 
   Definition visitGetMutable(GetMutable node) {
-    return new GetMutable(getCopy(node.variable));
+    return new GetMutable(getCopy(node.variableRef));
   }
 
   Definition visitParameter(Parameter node) {
@@ -2598,22 +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),
-        getList(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) {
@@ -2621,54 +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.dartType, getList(node.arguments));
+    return new TypeExpression(
+        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) {
@@ -2677,27 +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 visitNullCheck(NullCheck node) {
-    return new NullCheck(getCopy(node.value), node.sourceInformation,
-        condition: node.condition == null ? null : getCopy(node.condition),
-        selector: node.selector,
-        useSelector: node.useSelector);
+  Definition visitReceiverCheck(ReceiverCheck node) {
+    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.type,
-        getList(node.arguments),
-        node.nativeBehavior,
+    return new ForeignCode(node.codeTemplate, node.storedType,
+        getList(node.argumentRefs), node.nativeBehavior,
         dependency: node.dependency);
   }
 }
@@ -2723,6 +2976,7 @@
       assert(_current != null);
       InteriorExpression interior = _current;
       interior.body = body;
+      body.parent = interior;
     }
     _current = body;
   }
@@ -2740,7 +2994,9 @@
       Expression savedFirst = _first;
       _first = _current = null;
       _processBlock(cont.body);
-      _copies[cont].body = _first;
+      Continuation contCopy = _copies[cont];
+      contCopy.body = _first;
+      _first.parent = contCopy;
       _first = savedFirst;
       _current = null;
     });
@@ -2761,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;
   }
@@ -2792,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;
   }
@@ -2805,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) {
@@ -2829,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 bde9b0e..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
@@ -29,7 +29,52 @@
     }
   }
 
+  /// Create a stringifier with an extra layer of decoration.
+  SExpressionStringifier withDecorator(Decorator subDecorator) {
+    return new SExpressionStringifier((node, String s) {
+      return subDecorator(node, decorator(node, s));
+    });
+  }
+
+  /// Create a stringifier that displays type information.
+  SExpressionStringifier withTypes() => withDecorator(typeDecorator);
+
+  /// Creates a stringifier that adds annotations from a map;
+  /// see [Node.debugString].
+  SExpressionStringifier withAnnotations(Map annotations) {
+    return withDecorator(decoratorFromMap(annotations));
+  }
+
+  static Decorator decoratorFromMap(Map annotations) {
+    Map<Node, String> nodeMap = {};
+    for (var key in annotations.keys) {
+      if (key is Node) {
+        nodeMap[key] = '${annotations[key]}';
+      } else {
+        String text = key;
+        Node node = annotations[key];
+        if (nodeMap.containsKey(node)) {
+          // In case two annotations belong to the same node,
+          // put both annotations on that node.
+          nodeMap[node] += ' $text';
+        } else {
+          nodeMap[node] = text;
+        }
+      }
+    }
+    return (node, string) {
+      String text = nodeMap[node];
+      if (text != null) return '***$string*** $text';
+      return string;
+    };
+  }
+
+  static String typeDecorator(node, String string) {
+    return node is Variable ? '$string:${node.type}' : string;
+  }
+
   String access(Reference<Definition> r) {
+    if (r == null) return '**** NULL ****';
     return decorator(r, namer.getName(r.definition));
   }
 
@@ -71,24 +116,42 @@
   String visitLetPrim(LetPrim node) {
     String name = newValueName(node.primitive);
     String value = visit(node.primitive);
+    String bindings = '($name $value)';
+    String skip = ' ' * '(LetPrim ('.length;
+    while (node.body is LetPrim) {
+      node = node.body;
+      name = newValueName(node.primitive);
+      value = visit(node.primitive);
+      String binding = decorator(node, '($name $value)');
+      bindings += '\n${indentation}$skip$binding';
+    }
     String body = indentBlock(() => visit(node.body));
-    return '$indentation(LetPrim ($name $value)\n$body)';
+    return '$indentation(LetPrim ($bindings)\n$body)';
+  }
+
+  bool isBranchTarget(Continuation cont) {
+    return cont.hasExactlyOneUse && cont.firstRef.parent is Branch;
   }
 
   String visitLetCont(LetCont node) {
     String conts;
     bool first = true;
+    String skip = ' ' * '(LetCont ('.length;
     for (Continuation continuation in node.continuations) {
+      // Branch continuations will be printed at their use site.
+      if (isBranchTarget(continuation)) continue;
       if (first) {
         first = false;
         conts = visit(continuation);
       } else {
         // Each subsequent line is indented additional spaces to align it
         // with the previous continuation.
-        String indent = '$indentation${' ' * '(LetCont ('.length}';
-        conts = '$conts\n$indent${visit(continuation)}';
+        conts += '\n${indentation}$skip${visit(continuation)}';
       }
     }
+    // If there were no continuations printed, just print the body.
+    if (first) return visit(node.body);
+
     String body = indentBlock(() => visit(node.body));
     return '$indentation(LetCont ($conts)\n$body)';
   }
@@ -107,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)';
   }
@@ -137,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)';
   }
@@ -168,20 +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.map(access).join(' ');
+    String args = node.argumentRefs == null
+        ? '**** NULL ****'
+	: 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)';
   }
 
@@ -190,11 +255,15 @@
   }
 
   String visitBranch(Branch node) {
-    String condition = access(node.condition);
-    String trueCont = access(node.trueContinuation);
-    String falseCont = access(node.falseContinuation);
+    String condition = access(node.conditionRef);
+    assert(isBranchTarget(node.trueContinuation));
+    assert(isBranchTarget(node.falseContinuation));
+    String trueCont =
+        indentBlock(() => visit(node.trueContinuation));
+    String falseCont =
+        indentBlock(() => visit(node.falseContinuation));
     String strict = node.isStrictCheck ? 'Strict' : 'NonStrict';
-    return '$indentation(Branch $condition $trueCont $falseCont $strict)';
+    return '$indentation(Branch $strict $condition\n$trueCont\n$falseCont)';
   }
 
   String visitUnreachable(Unreachable node) {
@@ -207,11 +276,17 @@
   }
 
   String visitContinuation(Continuation node) {
+    if (isBranchTarget(node)) {
+      assert(node.parameters.isEmpty);
+      assert(!node.isRecursive);
+      return indentBlock(() => visit(node.body));
+    }
     String name = newContinuationName(node);
     if (node.isRecursive) name = 'rec $name';
-    // TODO(karlklose): this should be changed to `.map(visit).join(' ')`  and
-    // should recurse to [visit].  Currently we can't do that, because the
-    // unstringifier_test produces [LetConts] with dummy arguments on them.
+    // TODO(karlklose): this should be changed to `.map(visit).join(' ')`
+    // and should recurse to [visit].  Currently we can't do that, because
+    // the unstringifier_test produces [LetConts] with dummy arguments on
+    // them.
     String parameters = node.parameters
         .map((p) => '${decorator(p, newValueName(p))}')
         .join(' ');
@@ -220,51 +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 visitLiteralMap(LiteralMap node) {
-    String keys = node.entries.map((e) => access(e.key)).join(' ');
-    String values = node.entries.map((e) => access(e.value)).join(' ');
-    return '(LiteralMap ($keys) ($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)';
   }
@@ -276,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)';
   }
 
@@ -291,79 +360,79 @@
 
   String visitCreateInstance(CreateInstance node) {
     String className = node.classElement.name;
-    String arguments = node.arguments.map(access).join(' ');
-    String typeInformation = node.typeInformation.map(access).join(' ');
+    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(' ');
-    return '(TypeExpression ${node.dartType} ($args))';
+    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)';
   }
 
@@ -373,16 +442,17 @@
   }
 
   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 visitNullCheck(NullCheck node) {
-    String value = access(node.value);
-    String condition = optionalAccess(node.condition);
-    return '(NullCheck $value $condition (${node.selector ?? ""}))';
+  String visitReceiverCheck(ReceiverCheck node) {
+    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 e732f3d..1c7779b 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -29,7 +29,7 @@
       builder.visit(node);
 
       for (Block block in builder.entries) {
-        printBlock(block, entryPointParameters: node.parameters);
+        printBlock(block, entryPoint: node);
       }
       for (Block block in builder.cont2block.values) {
         printBlock(block);
@@ -63,9 +63,8 @@
     return count;
   }
 
-  /// If [entryPointParameters] is given, this block is an entry point
-  /// and [entryPointParameters] is the list of function parameters.
-  printBlock(Block block, {List<cps_ir.Definition> entryPointParameters}) {
+  /// If [entryPoint] is given, this block is an entry point.
+  printBlock(Block block, {cps_ir.FunctionDefinition entryPoint}) {
     tag("block", () {
       printProperty("name", block.name);
       printProperty("from_bci", -1);
@@ -84,9 +83,12 @@
         String formatParameter(cps_ir.Parameter param) {
           return '${names.name(param)} ${param.type}';
         }
-        if (entryPointParameters != null) {
-          String params = entryPointParameters.map(formatParameter).join(', ');
-          printStmt('x0', 'Entry ($params)');
+        if (entryPoint != null) {
+          String thisParam = entryPoint.thisParameter != null
+              ? formatParameter(entryPoint.thisParameter)
+              : 'no receiver';
+          String params = entryPoint.parameters.map(formatParameter).join(', ');
+          printStmt('x0', 'Entry ($thisParam) ($params)');
         }
         String params = block.parameters.map(formatParameter).join(', ');
         printStmt('x0', 'Parameters ($params)');
@@ -135,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)";
   }
 
@@ -167,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");
   }
 
@@ -188,56 +190,46 @@
   }
 
   visitLiteralList(cps_ir.LiteralList node) {
-    String values = node.values.map(formatReference).join(', ');
+    String values = node.valueRefs.map(formatReference).join(', ');
     return "LiteralList ($values)";
   }
 
-  visitLiteralMap(cps_ir.LiteralMap node) {
-    List<String> entries = new List<String>();
-    for (cps_ir.LiteralMapEntry entry in node.entries) {
-      String key = formatReference(entry.key);
-      String value = formatReference(entry.value);
-      entries.add("$key: $value");
-    }
-    return "LiteralMap (${entries.join(', ')})";
-  }
-
   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';
   }
 
@@ -268,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) {
@@ -302,87 +297,87 @@
 
   visitCreateInstance(cps_ir.CreateInstance node) {
     String className = node.classElement.name;
-    String arguments = node.arguments.map(formatReference).join(', ');
-    String typeInformation =
-        node.typeInformation.map(formatReference).join(', ');
+    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.dartType} "
-        "${node.arguments.map(formatReference).join(', ')}";
+    return "TypeExpression ${node.kindAsString} ${node.dartType}"
+        "${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';
   }
 
@@ -392,20 +387,21 @@
   }
 
   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}';
   }
 
-  visitNullCheck(cps_ir.NullCheck node) {
-    String value = formatReference(node.value);
-    String condition = formatReference(node.condition);
-    return 'NullCheck $value condition:$condition selector:${node.selector}';
+  visitReceiverCheck(cps_ir.ReceiverCheck node) {
+    String value = formatReference(node.valueRef);
+    String condition = formatReference(node.conditionRef);
+    return 'ReceiverCheck $value $condition ${node.selector} '
+        '${node.flagString}';
   }
 }
 
@@ -514,7 +510,7 @@
   }
 
   visitInvokeContinuation(cps_ir.InvokeContinuation exp) {
-    addEdgeToContinuation(exp.continuation);
+    addEdgeToContinuation(exp.continuationRef);
   }
 
   visitInvokeStatic(cps_ir.InvokeStatic node) {
@@ -547,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));
     }
@@ -578,10 +574,6 @@
     unexpectedNode(node);
   }
 
-  visitLiteralMap(cps_ir.LiteralMap node) {
-    unexpectedNode(node);
-  }
-
   visitConstant(cps_ir.Constant node) {
     unexpectedNode(node);
   }
@@ -694,7 +686,7 @@
     unexpectedNode(node);
   }
 
-  visitNullCheck(cps_ir.NullCheck node) {
+  visitReceiverCheck(cps_ir.ReceiverCheck node) {
     unexpectedNode(node);
   }
 }
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 1406a58..9376800 100644
--- a/pkg/compiler/lib/src/cps_ir/finalize.dart
+++ b/pkg/compiler/lib/src/cps_ir/finalize.dart
@@ -5,6 +5,7 @@
 import 'optimizers.dart' show Pass;
 import '../js_backend/js_backend.dart' show JavaScriptBackend;
 import '../js_backend/backend_helpers.dart';
+import '../js/js.dart' as js;
 
 /// A transformation pass that must run immediately before the tree IR builder.
 ///
@@ -37,17 +38,22 @@
   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();
-    if (node.hasLowerBoundCheck) {
+    Primitive index = node.index;
+    if (node.hasIntegerCheck) {
+      cps.ifTruthy(cps.applyBuiltin(BuiltinOperator.IsNotUnsigned32BitInteger,
+          [index, index]))
+          .invokeContinuation(fail);
+    } else if (node.hasLowerBoundCheck) {
       cps.ifTruthy(cps.applyBuiltin(BuiltinOperator.NumLt,
-          [node.index.definition, cps.makeZero()]))
+          [index, cps.makeZero()]))
           .invokeContinuation(fail);
     }
     if (node.hasUpperBoundCheck) {
-      Primitive length = node.length.definition;
+      Primitive length = node.length;
       if (length is GetLength &&
           length.hasExactlyOneUse &&
           areAdjacent(length, node)) {
@@ -58,24 +64,37 @@
         cps.letPrim(length);
       }
       cps.ifTruthy(cps.applyBuiltin(BuiltinOperator.NumGe,
-          [node.index.definition, length]))
+          [index, length]))
           .invokeContinuation(fail);
     }
     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, node.index.definition]);
-    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;
+    }
+  }
+
+  void visitForeignCode(ForeignCode node) {
+    if (js.isIdentityTemplate(node.codeTemplate)) {
+      // The CPS builder replaces identity templates with refinements, except
+      // when the refined type is an array type.  Some optimizations assume the
+      // 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.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 a4a591f..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) {
@@ -192,7 +188,7 @@
 
   bool isHoistablePrimitive(Primitive prim) {
     if (prim.isSafeForElimination) return true;
-    if (prim is NullCheck ||
+    if (prim is ReceiverCheck ||
         prim is BoundsCheck ||
         prim is GetLength ||
         prim is GetField ||
@@ -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 cc046ee..6c9f30c 100644
--- a/pkg/compiler/lib/src/cps_ir/inline.dart
+++ b/pkg/compiler/lib/src/cps_ir/inline.dart
@@ -18,6 +18,7 @@
     FlatTypeMask, ForwardingTypeMask, TypeMask, UnionTypeMask;
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/selector.dart' show Selector;
+import 'package:js_ast/js_ast.dart' as js;
 
 /// Inlining stack entries.
 ///
@@ -86,6 +87,9 @@
   static const int ABSENT = -1;
   static const int NO_INLINE = 0;
 
+  final Map<ExecutableElement, FunctionDefinition> unoptimized =
+      <ExecutableElement, FunctionDefinition>{};
+
   final Map<ExecutableElement, List<CacheEntry>> map =
       <ExecutableElement, List<CacheEntry>>{};
 
@@ -144,6 +148,29 @@
     }
     return ABSENT;
   }
+
+  /// Cache the unoptimized CPS term for a function.
+  ///
+  /// The unoptimized term should not have any inlining-context-specific
+  /// optimizations applied to it.  It will be used to compile the
+  /// non-specialized version of the function.
+  void putUnoptimized(ExecutableElement element, FunctionDefinition function) {
+    unoptimized.putIfAbsent(element, () => copier.copy(function));
+  }
+
+  /// Look up the unoptimized CPS term for a function.
+  ///
+  /// The unoptimized term will not have any inlining-context-specific
+  /// optimizations applied to it.  It can be used to compile the
+  /// non-specialized version of the function.
+  FunctionDefinition getUnoptimized(ExecutableElement element) {
+    FunctionDefinition function = unoptimized[element];
+    if (function != null) {
+      function = copier.copy(function);
+      ParentVisitor.setParents(function);
+    }
+    return function;
+  }
 }
 
 class Inliner implements Pass {
@@ -210,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;
   }
@@ -220,17 +247,45 @@
   // Inlining a function incurs a cost equal to the number of primitives and
   // non-jump tail expressions.
   // TODO(kmillikin): Tune the size computation and size bound.
-  processLetPrim(LetPrim node) {
-    if (node.primitive is! Refinement) {
-      ++size;
-    }
-  }
+  processLetPrim(LetPrim node) => ++size;
   processLetMutable(LetMutable node) => ++size;
   processBranch(Branch node) => ++size;
   processThrow(Throw nose) => ++size;
   processRethrow(Rethrow node) => ++size;
+
+  // Discount primitives that do not generate code.
+  processRefinement(Refinement node) => --size;
+  processBoundsCheck(BoundsCheck node) {
+    if (node.hasNoChecks) {
+      --size;
+    }
+  }
+
+  processForeignCode(ForeignCode node) {
+    // Count the number of nodes in the JS fragment, and discount the size
+    // originally added by LetPrim.
+    JsSizeVisitor visitor = new JsSizeVisitor();
+    node.codeTemplate.ast.accept(visitor);
+    size += visitor.size - 1;
+  }
 }
 
+class JsSizeVisitor extends js.BaseVisitor {
+  int size = 0;
+
+  visitNode(js.Node node) {
+    ++size;
+    return super.visitNode(node);
+  }
+
+  visitInterpolatedExpression(js.InterpolatedExpression node) {
+    // Suppress call to visitNode.  Placeholders should not be counted, because
+    // the argument has already been counted, and will in most cases be inserted
+    // directly in the placeholder.
+  }
+}
+
+
 class InliningVisitor extends TrampolineRecursiveVisitor {
   final Inliner _inliner;
 
@@ -281,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();
@@ -323,7 +378,7 @@
         outgoingNames.add(formal.name);
       });
       newCallStructure =
-      new CallStructure(signature.parameterCount, outgoingNames);
+          new CallStructure(signature.parameterCount, outgoingNames);
     } else {
       signature.forEachOptionalParameter((ParameterElement formal) {
         if (parameterIndex < parameters.length) {
@@ -344,6 +399,7 @@
     Primitive result = cps.invokeMethod(thisParameter, newSelector, node.mask,
         arguments, node.callingConvention);
     result.type = typeSystem.getInvokeReturnType(node.selector, node.mask);
+    returnContinuation.parameters.single.type = result.type;
     cps.invokeContinuation(returnContinuation, <Primitive>[result]);
     return new FunctionDefinition(target, thisParameter, parameters,
         returnContinuation,
@@ -364,6 +420,7 @@
     // AST node, targets that are asynchronous or generator functions, or
     // targets containing a try statement.
     if (!target.hasNode) return null;
+    if (backend.isJsInterop(target)) return null;
     if (target.asyncMarker != AsyncMarker.SYNC) return null;
     // V8 does not optimize functions containing a try statement.  Inlining
     // code containing a try statement will make the optimizable calling code
@@ -372,7 +429,22 @@
       return null;
     }
 
-    Reference<Primitive> dartReceiver = invoke.dartReceiverReference;
+    // Don't inline methods that never return. They are usually helper functions
+    // that throw an exception.
+    if (invoke.type.isEmpty && !invoke.type.isNullable) {
+      // TODO(sra): It would be ok to inline if doing so was shrinking.
+      return null;
+    }
+
+    if (isBlacklisted(target)) return null;
+
+    if (invoke.callingConvention == CallingConvention.OneShotIntercepted) {
+      // One-shot interceptor calls with a known target are only inserted on
+      // uncommon code paths, so they should not be inlined.
+      return null;
+    }
+
+    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
@@ -383,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);
@@ -393,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) {
@@ -434,24 +505,29 @@
       // The argument count at the call site does not match the target's
       // formal parameter count.  Build the IR term for an adapter function
       // body.
-      function = buildAdapter(invoke, target);
+      if (backend.isNative(target)) {
+        // TODO(25548): Generate correct adaptor for native methods.
+        return doNotInline();
+      } else {
+        function = buildAdapter(invoke, target);
+      }
     } else {
-      function = _inliner.functionCompiler.compileToCpsIr(target);
+      function = compileToCpsIr(target);
       void setValue(Variable variable, Reference<Primitive> value) {
         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);
@@ -474,7 +550,9 @@
                               CpsFragment fragment,
                               Primitive dartReceiver,
                               TypeMask abstractReceiver) {
-    Selector selector = invoke is InvokeMethod ? invoke.selector : null;
+    if (invoke is! InvokeMethod) return dartReceiver;
+    InvokeMethod invokeMethod = invoke;
+    Selector selector = invokeMethod.selector;
     if (typeSystem.isDefinitelyNum(abstractReceiver, allowNull: true)) {
       Primitive condition = _fragment.letPrim(
           new ApplyBuiltinOperator(BuiltinOperator.IsNotNumber,
@@ -482,15 +560,16 @@
                                    invoke.sourceInformation));
       condition.type = typeSystem.boolType;
       Primitive check = _fragment.letPrim(
-          new NullCheck.guarded(
-              condition, dartReceiver, selector, invoke.sourceInformation));
+          new ReceiverCheck.nullCheck(dartReceiver, selector,
+              invoke.sourceInformation,
+              condition: condition));
       check.type = abstractReceiver.nonNullable();
       return check;
     }
 
     Primitive check = _fragment.letPrim(
-        new NullCheck(dartReceiver, invoke.sourceInformation,
-                      selector: selector));
+        new ReceiverCheck.nullCheck(dartReceiver, selector,
+            invoke.sourceInformation));
     check.type = abstractReceiver.nonNullable();
     return check;
   }
@@ -533,4 +612,17 @@
     }
     return tryInlining(node, node.target, null);
   }
+
+  bool isBlacklisted(FunctionElement target) {
+    ClassElement enclosingClass = target.enclosingClass;
+    if (target.isOperator &&
+        (enclosingClass == backend.helpers.jsNumberClass ||
+         enclosingClass == backend.helpers.jsDoubleClass ||
+         enclosingClass == backend.helpers.jsIntClass)) {
+      // These should be handled by operator specialization.
+      return true;
+    }
+    if (target == backend.helpers.stringInterpolationHelper) return true;
+    return false;
+  }
 }
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/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index 812b204..2b248fe 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -25,6 +25,8 @@
 export 'inline.dart' show Inliner;
 export 'eagerly_load_statics.dart' show EagerlyLoadStatics;
 export 'loop_invariant_branch.dart' show LoopInvariantBranchMotion;
+export 'path_based_optimizer.dart' show PathBasedOptimizer;
+export 'use_field_initializers.dart' show UseFieldInitializers;
 export 'parent_visitor.dart' show ParentVisitor;
 
 /// An optimization pass over the CPS IR.
diff --git a/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart b/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
new file mode 100644
index 0000000..aed13e6
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/path_based_optimizer.dart
@@ -0,0 +1,184 @@
+// 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.path_based_optimizer;
+
+import 'cps_ir_nodes.dart';
+import 'optimizers.dart';
+import 'cps_fragment.dart';
+import '../js_backend/js_backend.dart';
+import '../constants/values.dart';
+import '../elements/elements.dart';
+import '../universe/selector.dart';
+import '../types/types.dart';
+import 'type_mask_system.dart';
+
+/// Optimizations based on intraprocedural forward dataflow analysis, taking
+/// into account path information that is not expressed by [Refinement] nodes.
+///
+/// ---
+///
+/// Removes branches that branch on the same value as a previously seen branch.
+/// For example:
+///
+///     if (x == y) {
+///       if (x == y) TRUE else FALSE
+///     }
+///
+/// ==> ([GVN] pass merges identical expressions)
+///
+///     var b = (x == y)
+///     if (b) {
+///       if (b) TRUE else FALSE
+///     }
+///
+///  ==> (this pass removes the duplicate branch)
+///
+///     var b = (x == y)
+///     if (b) {
+///       TRUE
+///     }
+///
+/// ---
+///
+/// Removes interceptors for method calls whose receiver is known to be a
+/// self-interceptor. For example:
+///
+///     x.foo$1();
+///     getInterceptor(x).$eq(x, y);
+///
+/// ==> (`x` is a self-interceptor, remove the `getInterceptor` call)
+///
+///     x.foo$1();
+///     x.$eq(0, y);
+///
+/// Although there is a [Refinement] node after the call to `x.foo$1()`, the
+/// refined type cannot always be represented exactly, and type propagation
+/// may therefore not see that `x` is a self-interceptor.
+//
+// TODO(asgerf): A kind of redundant join can arise where a branching condition
+// is known to be true/false on all but one predecessor for a branch. We could
+// try to reduce those.
+//
+// TODO(asgerf): Could be more precise if GVN shared expressions that are not
+// in direct scope of one another, e.g. by using phis pass the shared value.
+//
+class PathBasedOptimizer extends TrampolineRecursiveVisitor
+                         implements Pass {
+  String get passName => 'Path-based optimizations';
+
+  // Classification of all values.
+  static const int TRUE = 1 << 0;
+  static const int SELF_INTERCEPTOR = 1 << 1;
+  static const int INTERCEPTED_TRUTHY = 1 << 2;
+  static const int FALSE = 1 << 3;
+  static const int OTHER_FALSY = 1 << 4;
+
+  static const int TRUTHY = TRUE | SELF_INTERCEPTOR | INTERCEPTED_TRUTHY;
+  static const int FALSY = FALSE | OTHER_FALSY;
+  static const int ANY = TRUTHY | FALSY;
+
+  final JavaScriptBackend backend;
+  final TypeMaskSystem typeSystem;
+
+  PathBasedOptimizer(this.backend, this.typeSystem);
+
+  /// The possible values of the given primitive (or ANY if absent) at the
+  /// current traversal position.
+  Map<Primitive, int> valueOf = <Primitive, int>{};
+
+  /// The possible values of each primitive at the entry to a continuation.
+  ///
+  /// Unreachable continuations are absent from the map.
+  final Map<Continuation, Map<Primitive, int>> valuesAt =
+      <Continuation, Map<Primitive, int>>{};
+
+  void rewrite(FunctionDefinition node) {
+    visit(node);
+  }
+
+  Map<Primitive, int> copy(Map<Primitive, int> map) {
+    return new Map<Primitive, int>.from(map);
+  }
+
+  Expression traverseLetHandler(LetHandler node) {
+    valuesAt[node.handler] = copy(valueOf);
+    push(node.handler);
+    return node.body;
+  }
+
+  Expression traverseContinuation(Continuation cont) {
+    valueOf = valuesAt[cont];
+    if (valueOf == null) {
+      // Do not go into unreachable code.
+      destroyAndReplace(cont.body, new Unreachable());
+    }
+    return cont.body;
+  }
+
+  void visitInvokeContinuation(InvokeContinuation node) {
+    Continuation cont = node.continuation;
+    if (cont.isReturnContinuation) return;
+    if (node.isRecursive) return;
+    Map<Primitive, int> target = valuesAt[cont];
+    if (target == null) {
+      valuesAt[cont] = valueOf;
+    } else {
+      for (Primitive prim in target.keys) {
+        target[prim] |= valueOf[prim] ?? ANY;
+      }
+    }
+  }
+
+  visitBranch(Branch node) {
+    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.
+      valuesAt[trueCont] = copy(valueOf);
+      valuesAt[falseCont] = valueOf;
+      return;
+    }
+    int values = valueOf[condition] ?? ANY;
+    int positiveValues = node.isStrictCheck ? TRUE : TRUTHY;
+    int negativeValues = (~positiveValues) & ANY;
+    if (values & positiveValues == 0) {
+      destroyAndReplace(node, new InvokeContinuation(falseCont, []));
+      valuesAt[falseCont] = valueOf;
+    } else if (values & negativeValues == 0) {
+      destroyAndReplace(node, new InvokeContinuation(trueCont, []));
+      valuesAt[trueCont] = valueOf;
+    } else {
+      valuesAt[trueCont] = copy(valueOf)..[condition] = values & positiveValues;
+      valuesAt[falseCont] = valueOf..[condition] = values & negativeValues;
+    }
+  }
+
+  void visitInvokeMethod(InvokeMethod node) {
+    int receiverValue = valueOf[node.dartReceiver] ?? ANY;
+    if (!backend.isInterceptedSelector(node.selector)) {
+      // Only self-interceptors can respond to a non-intercepted selector.
+      valueOf[node.dartReceiver] = receiverValue & SELF_INTERCEPTOR;
+    } else if (receiverValue & ~SELF_INTERCEPTOR == 0 &&
+               node.callingConvention == CallingConvention.Intercepted) {
+      // This is an intercepted call whose receiver is definitely a
+      // self-interceptor.
+      // TODO(25646): If TypeMasks could represent "any self-interceptor" this
+      //   optimization should be subsumed by type propagation.
+      node.receiverRef.changeTo(node.dartReceiver);
+
+      // Replace the extra receiver argument with a dummy value if the
+      // target definitely does not use it.
+      if (typeSystem.targetIgnoresReceiverArgument(node.dartReceiver.type,
+            node.selector)) {
+        Constant dummy = new Constant(new IntConstantValue(0))
+            ..type = typeSystem.intType;
+        new LetPrim(dummy).insertAbove(node.parent);
+        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 92f64ae..59cac26 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_join.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_join.dart
@@ -8,18 +8,19 @@
 import 'optimizers.dart';
 
 /// Eliminates redundant join points.
-/// 
+///
 /// A redundant join point is a continuation that immediately branches
 /// based on one of its parameters, and that parameter is a constant value
 /// at every invocation. Each invocation is redirected to jump directly
 /// to the branch target.
-/// 
+///
 /// Internally in this pass, parameters are treated as names with lexical
 /// scoping, and a given parameter "name" may be declared by more than
-/// one continuation. The reference chains for parameters are therefore 
+/// 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)) {
@@ -113,11 +114,11 @@
       return;
     }
 
-    // Lift any continuations bound inside branchCont so they are in scope at 
+    // Lift any continuations bound inside branchCont so they are in scope at
     // the call sites. When lifting, the parameters of branchCont fall out of
     // scope, so they are added as parameters on each lifted continuation.
     // Schematically:
-    // 
+    //
     //   (LetCont (branchCont (x1, x2, x3) =
     //        (LetCont (innerCont (y) = ...) in
     //        [... innerCont(y') ...]))
@@ -127,8 +128,8 @@
     //   (LetCont (innerCont (y, x1, x2, x3) = ...) in
     //   (LetCont (branchCont (x1, x2, x3) =
     //        [... innerCont(y', x1, x2, x3) ...])
-    // 
-    // Parameter objects become shared between branchCont and the lifted 
+    //
+    // Parameter objects become shared between branchCont and the lifted
     // continuations. [AlphaRenamer] will clean up at the end of this pass.
     LetCont outerLetCont = branchCont.parent;
     while (branchCont.body is LetCont) {
@@ -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();
@@ -202,17 +204,17 @@
 /// Ensures parameter objects are not shared between different continuations,
 /// akin to alpha-renaming variables so every variable is named uniquely.
 /// For example:
-/// 
+///
 ///   LetCont (k1 x = (return x)) in
 ///   LetCont (k2 x = (InvokeContinuation k3 x)) in ...
-///     => 
+///     =>
 ///   LetCont (k1 x = (return x)) in
 ///   LetCont (k2 x' = (InvokeContinuation k3 x')) in ...
-/// 
+///
 /// After lifting LetConts in the main pass above, parameter objects can have
 /// multiple bindings. Each reference implicitly refers to the binding that
 /// is currently in scope.
-/// 
+///
 /// This returns the IR to its normal form after redundant joins have been
 /// eliminated.
 class AlphaRenamer extends TrampolineRecursiveVisitor {
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
index 7f16af9..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.
@@ -61,10 +61,10 @@
     /// Returns the unique definition of parameter i if it exists and null
     /// otherwise. A definition is unique if it is the only value used to
     /// invoke the continuation, excluding feedback.
-    Definition uniqueDefinitionOf(int i) {
-      Definition value = null;
+    Primitive uniqueDefinitionOf(int i) {
+      Primitive value = null;
       for (InvokeContinuation invoke in invokes) {
-        Definition def = invoke.arguments[i].definition;
+        Primitive def = invoke.argument(i).effectiveDefinition;
 
         if (cont.parameters[i] == def) {
           // Invocation param == param in LetCont (i.e. a recursive call).
@@ -104,20 +104,20 @@
     int dst = 0;
     for (int src = 0; src < cont.parameters.length; src++) {
       // Is the current phi redundant?
-      Definition uniqueDefinition = uniqueDefinitionOf(src);
+      Primitive uniqueDefinition = uniqueDefinitionOf(src);
       if (uniqueDefinition == null || !safeForHandlers(uniqueDefinition)) {
         // Reorganize parameters and arguments in case of deletions.
         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++;
         continue;
       }
 
-      Definition oldDefinition = cont.parameters[src];
+      Primitive oldDefinition = cont.parameters[src];
 
       // Add continuations of about-to-be modified invokes to worklist since
       // we might introduce new optimization opportunities.
@@ -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 16a1d15..1c84ca6 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -6,7 +6,6 @@
 
 import 'cps_ir_nodes.dart';
 import 'optimizers.dart';
-import 'cps_fragment.dart';
 
 /**
  * [ShrinkingReducer] applies shrinking reductions to CPS terms as described
@@ -15,26 +14,68 @@
 class ShrinkingReducer extends Pass {
   String get passName => 'Shrinking reductions';
 
-  List<_ReductionTask> _worklist;
-
-  static final _DeletedNode _DELETED = new _DeletedNode();
+  final List<_ReductionTask> _worklist = new List<_ReductionTask>();
 
   /// Applies shrinking reductions to root, mutating root in the process.
   @override
   void rewrite(FunctionDefinition root) {
-    _worklist = new List<_ReductionTask>();
     _RedexVisitor redexVisitor = new _RedexVisitor(_worklist);
 
     // Sweep over the term, collecting redexes into the worklist.
     redexVisitor.visit(root);
 
-    // Process the worklist.
+    _iterateWorklist();
+  }
+
+  void _iterateWorklist() {
     while (_worklist.isNotEmpty) {
       _ReductionTask task = _worklist.removeLast();
       _processTask(task);
     }
   }
 
+  /// Call instead of [_iterateWorklist] to check at every step that no
+  /// redex was missed.
+  void _debugWorklist(FunctionDefinition root) {
+    while (_worklist.isNotEmpty) {
+      _ReductionTask task = _worklist.removeLast();
+      String irBefore = root.debugString({
+        task.node: '${task.kind} applied here'
+      });
+      _processTask(task);
+      Set seenRedexes = _worklist.where(isValidTask).toSet();
+      Set actualRedexes = (new _RedexVisitor([])..visit(root)).worklist.toSet();
+      if (!seenRedexes.containsAll(actualRedexes)) {
+        _ReductionTask missedTask =
+            actualRedexes.firstWhere((x) => !seenRedexes.contains(x));
+        print('\nBEFORE $task:\n');
+        print(irBefore);
+        print('\nAFTER $task:\n');
+        root.debugPrint({
+          missedTask.node: 'MISSED ${missedTask.kind}'
+        });
+        throw 'Missed $missedTask after processing $task';
+      }
+    }
+  }
+
+  bool isValidTask(_ReductionTask task) {
+    switch (task.kind) {
+      case _ReductionKind.DEAD_VAL:
+        return _isDeadVal(task.node);
+      case _ReductionKind.DEAD_CONT:
+        return _isDeadCont(task.node);
+      case _ReductionKind.BETA_CONT_LIN:
+        return _isBetaContLin(task.node);
+      case _ReductionKind.ETA_CONT:
+        return _isEtaCont(task.node);
+      case _ReductionKind.DEAD_PARAMETER:
+        return _isDeadParameter(task.node);
+      case _ReductionKind.BRANCH:
+        return _isBranchRedex(task.node);
+    }
+  }
+
   /// Removes the given node from the CPS graph, replacing it with its body
   /// and marking it as deleted. The node's parent must be a [[InteriorNode]].
   void _removeNode(InteriorNode node) {
@@ -44,7 +85,14 @@
 
     body.parent = parent;
     parent.body = body;
-    node.parent = _DELETED;
+    node.parent = null;
+
+    // The removed node could be the last node between a continuation and
+    // an InvokeContinuation in the body.
+    if (parent is Continuation) {
+      _checkEtaCont(parent);
+      _checkUselessBranchTarget(parent);
+    }
   }
 
   /// Remove a given continuation from the CPS graph.  The LetCont itself is
@@ -56,12 +104,12 @@
     } else {
       parent.continuations.remove(cont);
     }
-    cont.parent = _DELETED;
+    cont.parent = null;
   }
 
   void _processTask(_ReductionTask task) {
     // Skip tasks for deleted nodes.
-    if (task.node.parent == _DELETED) {
+    if (task.node.parent == null) {
       return;
     }
 
@@ -81,23 +129,40 @@
       case _ReductionKind.DEAD_PARAMETER:
         _reduceDeadParameter(task);
         break;
-      default:
-        assert(false);
+      case _ReductionKind.BRANCH:
+        _reduceBranch(task);
+        break;
     }
   }
 
   /// Applies the dead-val reduction:
   ///   letprim x = V in E -> E (x not free in E).
   void _reduceDeadVal(_ReductionTask task) {
+    if (_isRemoved(task.node)) return;
     assert(_isDeadVal(task.node));
 
-    // Remove dead primitive.
-    LetPrim letPrim = task.node;
-    destroyRefinementsOfDeadPrimitive(letPrim.primitive);
-    _removeNode(letPrim);
+    LetPrim deadLet = task.node;
+    Primitive deadPrim = deadLet.primitive;
+    assert(deadPrim.hasNoRefinedUses);
+    // The node has no effective uses but can have refinement uses, which
+    // themselves can have more refinements uses (but only refinement uses).
+    // We must remove the entire refinement tree while looking for redexes
+    // whenever we remove one.
+    List<Primitive> deadlist = <Primitive>[deadPrim];
+    while (deadlist.isNotEmpty) {
+      Primitive node = deadlist.removeLast();
+      while (node.firstRef != null) {
+        Reference ref = node.firstRef;
+        Refinement use = ref.parent;
+        deadlist.add(use);
+        ref.unlink();
+      }
+      LetPrim binding = node.parent;
+      _removeNode(binding); // Remove the binding and check for eta redexes.
+    }
 
     // Perform bookkeeping on removed body and scan for new redexes.
-    new _RemovalVisitor(_worklist).visit(letPrim.primitive);
+    new _RemovalVisitor(_worklist).visit(deadPrim);
   }
 
   /// Applies the dead-cont reduction:
@@ -127,25 +192,36 @@
       return;
     }
 
-    // Remove the continuation.
     Continuation cont = task.node;
-    _removeContinuation(cont);
-
-    // Replace its invocation with the continuation body.
     InvokeContinuation invoke = cont.firstRef.parent;
     InteriorNode invokeParent = invoke.parent;
+    Expression body = cont.body;
 
-    cont.body.parent = invokeParent;
-    invokeParent.body = cont.body;
+    // Replace the invocation with the continuation body.
+    invokeParent.body = body;
+    body.parent = invokeParent;
+    cont.body = null;
 
     // Substitute the invocation argument for the continuation parameter.
-    for (int i = 0; i < invoke.arguments.length; i++) {
-      cont.parameters[i].replaceUsesWith(invoke.arguments[i].definition);
-      invoke.arguments[i].definition.useElementAsHint(cont.parameters[i].hint);
+    for (int i = 0; i < invoke.argumentRefs.length; i++) {
+      Parameter param = cont.parameters[i];
+      Primitive argument = invoke.argument(i);
+      param.replaceUsesWith(argument);
+      argument.useElementAsHint(param.hint);
+      _checkConstantBranchCondition(argument);
     }
 
+    // Remove the continuation after inlining it so we can check for eta redexes
+    // which may arise after removing the LetCont.
+    _removeContinuation(cont);
+
     // Perform bookkeeping on substituted body and scan for new redexes.
     new _RemovalVisitor(_worklist).visit(invoke);
+
+    if (invokeParent is Continuation) {
+      _checkEtaCont(invokeParent);
+      _checkUselessBranchTarget(invokeParent);
+    }
   }
 
   /// Applies the eta-cont reduction:
@@ -167,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);
@@ -184,13 +260,48 @@
       }
     }
 
-    // Replace all occurrences with the wrapped continuation.
-    cont.replaceUsesWith(wrappedCont);
+    // Replace all occurrences with the wrapped continuation and find redexes.
+    while (cont.firstRef != null) {
+      Reference ref = cont.firstRef;
+      ref.changeTo(wrappedCont);
+      Node use = ref.parent;
+      if (use is InvokeContinuation && use.parent is Continuation) {
+        _checkUselessBranchTarget(use.parent);
+      }
+    }
 
     // Perform bookkeeping on removed body and scan for new redexes.
     new _RemovalVisitor(_worklist).visit(cont);
   }
 
+  void _reduceBranch(_ReductionTask task) {
+    Branch branch = task.node;
+    // Replace Branch with InvokeContinuation of one of the targets. When the
+    // 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;
+    if (condition is Constant) {
+      target = isTruthyConstant(condition.value, strict: branch.isStrictCheck)
+          ? branch.trueContinuation
+          : branch.falseContinuation;
+    } else if (_isBranchTargetOfUselessIf(branch.trueContinuation)) {
+      target = branch.trueContinuation;
+    } else {
+      return;
+    }
+
+    InvokeContinuation invoke = new InvokeContinuation(
+        target, <Primitive>[]
+        // TODO(sra): Add sourceInformation.
+        /*, sourceInformation: branch.sourceInformation*/);
+    branch.parent.body = invoke;
+    invoke.parent = branch.parent;
+    branch.parent = null;
+
+    new _RemovalVisitor(_worklist).visit(branch);
+  }
+
   void _reduceDeadParameter(_ReductionTask task) {
     // Continuation eta-reduction can destroy a dead parameter redex.  For
     // example, in the term:
@@ -207,61 +318,105 @@
     // Where the dead parameter reduction is no longer valid because we do not
     // allow removing the paramter of call continuations.  We disallow such eta
     // reductions in [_isEtaCont].
-    assert(_isDeadParameter(task.node));
-
     Parameter parameter = task.node;
+    if (_isParameterRemoved(parameter)) return;
+    assert(_isDeadParameter(parameter));
+
     Continuation continuation = parameter.parent;
     int index = continuation.parameters.indexOf(parameter);
     assert(index != -1);
+    continuation.parameters.removeAt(index);
+    parameter.parent = null; // Mark as removed.
 
     // Remove the index'th argument from each invocation.
-    Reference<Continuation> current = continuation.firstRef;
-    while (current != null) {
-      InvokeContinuation invoke = current.parent;
-      Reference<Primitive> argument = invoke.arguments[index];
+    for (Reference ref = continuation.firstRef; ref != null; ref = ref.next) {
+      InvokeContinuation invoke = ref.parent;
+      Reference<Primitive> argument = invoke.argumentRefs[index];
       argument.unlink();
-      // Removing an argument can create a dead parameter or dead value redex.
-      if (argument.definition is Parameter) {
-        if (_isDeadParameter(argument.definition)) {
-          _worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER,
-                                           argument.definition));
-        }
-      } else {
-        Node parent = argument.definition.parent;
-        if (parent is LetPrim) {
-          if (_isDeadVal(parent)) {
-            _worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
-          }
-        }
+      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);
+      if (invoke.parent is Continuation) {
+        _checkEtaCont(invoke.parent);
+        _checkUselessBranchTarget(invoke.parent);
       }
-      invoke.arguments.removeAt(index);
-      current = current.next;
     }
-    continuation.parameters.removeAt(index);
 
-    // Removing an unused parameter can create an eta-redex.
+    // Removing an unused parameter can create an eta-redex, in case the
+    // body is an InvokeContinuation that now has matching arguments.
+    _checkEtaCont(continuation);
+  }
+
+  void _checkEtaCont(Continuation continuation) {
     if (_isEtaCont(continuation)) {
       _worklist.add(new _ReductionTask(_ReductionKind.ETA_CONT, continuation));
     }
   }
+
+  void _checkUselessBranchTarget(Continuation continuation) {
+    if (_isBranchTargetOfUselessIf(continuation)) {
+      _worklist.add(new _ReductionTask(_ReductionKind.BRANCH,
+          continuation.firstRef.parent));
+    }
+  }
+
+  void _checkConstantBranchCondition(Primitive primitive) {
+    if (primitive is! Constant) return;
+    for (Reference ref = primitive.firstRef; ref != null; ref = ref.next) {
+      Node use = ref.parent;
+      if (use is Branch) {
+        _worklist.add(new _ReductionTask(_ReductionKind.BRANCH, use));
+      }
+    }
+  }
+
+  void _checkDeadPrimitive(Primitive primitive) {
+    primitive = primitive.unrefined;
+    if (primitive is Parameter) {
+      if (_isDeadParameter(primitive)) {
+        _worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER,
+                                         primitive));
+      }
+    } else if (primitive.parent is LetPrim) {
+      LetPrim letPrim = primitive.parent;
+      if (_isDeadVal(letPrim)) {
+        _worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, letPrim));
+      }
+    }
+  }
+}
+
+bool _isRemoved(InteriorNode node) {
+  return node.parent == null;
+}
+
+bool _isParameterRemoved(Parameter parameter) {
+  // A parameter can be removed directly or because its continuation is removed.
+  return parameter.parent == null || _isRemoved(parameter.parent);
 }
 
 /// Returns true iff the bound primitive is unused, and has no effects
 /// preventing it from being eliminated.
 bool _isDeadVal(LetPrim node) {
-  return node.primitive.hasNoEffectiveUses &&
+  return !_isRemoved(node) &&
+         node.primitive.hasNoRefinedUses &&
          node.primitive.isSafeForElimination;
 }
 
 /// Returns true iff the continuation is unused.
 bool _isDeadCont(Continuation cont) {
-  return !cont.isReturnContinuation && !cont.hasAtLeastOneUse;
+  return !_isRemoved(cont) &&
+         !cont.isReturnContinuation &&
+         !cont.hasAtLeastOneUse;
 }
 
 /// Returns true iff the continuation has a body (i.e., it is not the return
 /// continuation), it is used exactly once, and that use is as the continuation
 /// of a continuation invocation.
 bool _isBetaContLin(Continuation cont) {
+  if (_isRemoved(cont)) return false;
+
   // There is a restriction on continuation eta-redexes that the body is not an
   // invocation of the return continuation, because that leads to worse code
   // when translating back to direct style (it duplicates returns).  There is no
@@ -275,31 +430,26 @@
   if (cont.firstRef.parent is! InvokeContinuation) return false;
 
   InvokeContinuation invoke = cont.firstRef.parent;
-  if (cont != invoke.continuation.definition) return false;
 
   // Beta-reduction will move the continuation's body to its unique invocation
   // site.  This is not safe if the body is moved into an exception handler
-  // binding.  Search from the invocation to the continuation binding to
-  // make sure that there is no binding for a handler.
-  Node current = invoke.parent;
-  while (current != cont.parent) {
-    // There is no need to reduce a beta-redex inside a deleted subterm.
-    if (current == ShrinkingReducer._DELETED) return false;
-    if (current is LetHandler) return false;
-    current = current.parent;
-  }
+  // binding.
+  if (invoke.isEscapingTry) return false;
+
   return true;
 }
 
 /// Returns true iff the continuation consists of a continuation
 /// invocation, passing on all parameters. Special cases exist (see below).
 bool _isEtaCont(Continuation cont) {
-  if (cont.isReturnContinuation || cont.body is! InvokeContinuation) {
+  if (_isRemoved(cont)) return false;
+
+  if (!cont.isJoinContinuation || cont.body is! InvokeContinuation) {
     return false;
   }
 
   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).
@@ -307,25 +457,6 @@
     return false;
   }
 
-  // Do not perform reductions replace a function call continuation with a
-  // non-call continuation.  The invoked continuation is definitely not a call
-  // continuation, because it has a direct invocation in this continuation's
-  // body.
-  bool isCallContinuation(Continuation continuation) {
-    Reference<Continuation> current = cont.firstRef;
-    while (current != null) {
-      if (current.parent is InvokeContinuation) {
-        InvokeContinuation invoke = current.parent;
-        if (invoke.continuation.definition == continuation) return false;
-      }
-      current = current.next;
-    }
-    return true;
-  }
-  if (isCallContinuation(cont)) {
-    return false;
-  }
-
   // Translation to direct style generates different statements for recursive
   // and non-recursive invokes. It should still be possible to apply eta-cont if
   // this is not a self-invocation.
@@ -356,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;
     }
   }
@@ -371,15 +502,65 @@
   return true;
 }
 
-bool _isDeadParameter(Parameter parameter) {
-  // We cannot remove function parameters as an intraprocedural optimization.
-  if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) {
+Expression _unfoldDeadRefinements(Expression node) {
+  while (node is LetPrim) {
+    LetPrim let = node;
+    Primitive prim = let.primitive;
+    if (prim.hasAtLeastOneUse || prim is! Refinement) return node;
+    node = node.next;
+  }
+  return node;
+}
+
+bool _isBranchRedex(Branch branch) {
+  return _isUselessIf(branch) || branch.condition is Constant;
+}
+
+bool _isBranchTargetOfUselessIf(Continuation cont) {
+  // A useless-if has an empty then and else branch, e.g. `if (cond);`.
+  //
+  // Detect T or F in
+  //
+  //     let cont Join() = ...
+  //       in let cont T() = Join()
+  //                   F() = Join()
+  //         in branch condition T F
+  //
+  if (!cont.hasExactlyOneUse) return false;
+  Node use = cont.firstRef.parent;
+  if (use is! Branch) return false;
+  return _isUselessIf(use);
+}
+
+bool _isUselessIf(Branch branch) {
+  Continuation trueCont = branch.trueContinuation;
+  Expression trueBody = _unfoldDeadRefinements(trueCont.body);
+  if (trueBody is! InvokeContinuation) return false;
+  Continuation falseCont = branch.falseContinuation;
+  Expression falseBody = _unfoldDeadRefinements(falseCont.body);
+  if (falseBody is! InvokeContinuation) return false;
+  InvokeContinuation trueInvoke = trueBody;
+  InvokeContinuation falseInvoke = falseBody;
+  if (trueInvoke.continuation !=
+      falseInvoke.continuation) {
     return false;
   }
+  // Matching zero arguments should be adequate, since isomorphic true and false
+  // invocations should result in redundant phis which are removed elsewhere.
+  //
+  // Note that the argument lists are not necessarily the same length here,
+  // because we could be looking for new redexes in the middle of performing a
+  // 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.argumentRefs.isEmpty && falseInvoke.argumentRefs.isEmpty;
+}
 
-  // We cannot remove exception handler parameters, they have a fixed arity
-  // of two.
-  if (parameter.parent.parent is LetHandler) {
+bool _isDeadParameter(Parameter parameter) {
+  if (_isParameterRemoved(parameter)) return false;
+
+  // We cannot remove function parameters as an intraprocedural optimization.
+  if (parameter.parent is! Continuation || parameter.hasAtLeastOneUse) {
     return false;
   }
 
@@ -388,14 +569,8 @@
   // exactly one argument).  The return continuation is a call continuation, so
   // we cannot remove its dummy parameter.
   Continuation continuation = parameter.parent;
-  if (continuation.isReturnContinuation) return false;
-  Reference<Continuation> current = continuation.firstRef;
-  while (current != null) {
-    if (current.parent is! InvokeContinuation) return false;
-    InvokeContinuation invoke = current.parent;
-    if (invoke.continuation.definition != continuation) return false;
-    current = current.next;
-  }
+  if (!continuation.isJoinContinuation) return false;
+
   return true;
 }
 
@@ -411,6 +586,12 @@
     }
   }
 
+  void processBranch(Branch node) {
+    if (_isBranchRedex(node)) {
+      worklist.add(new _ReductionTask(_ReductionKind.BRANCH, node));
+    }
+  }
+
   void processContinuation(Continuation node) {
     // While it would be nice to remove exception handlers that are provably
     // unnecessary (e.g., the body cannot throw), that takes more sophisticated
@@ -452,23 +633,30 @@
   _RemovalVisitor(this.worklist);
 
   void processLetPrim(LetPrim node) {
-    node.parent = ShrinkingReducer._DELETED;
+    node.parent = null;
   }
 
   void processContinuation(Continuation node) {
-    node.parent = ShrinkingReducer._DELETED;
+    node.parent = null;
+  }
+
+  void processBranch(Branch node) {
+    node.parent = null;
   }
 
   void processReference(Reference reference) {
     reference.unlink();
 
     if (reference.definition is Primitive) {
-      Primitive primitive = reference.definition;
+      Primitive primitive = reference.definition.unrefined;
       Node parent = primitive.parent;
       // The parent might be the deleted sentinel, or it might be a
       // Continuation or FunctionDefinition if the primitive is an argument.
       if (parent is LetPrim && _isDeadVal(parent)) {
         worklist.add(new _ReductionTask(_ReductionKind.DEAD_VAL, parent));
+      } else if (primitive is Parameter && _isDeadParameter(primitive)) {
+        worklist.add(new _ReductionTask(_ReductionKind.DEAD_PARAMETER,
+            primitive));
       }
     } else if (reference.definition is Continuation) {
       Continuation cont = reference.definition;
@@ -486,29 +674,22 @@
           worklist.add(new _ReductionTask(_ReductionKind.DEAD_CONT, cont));
         } else if (_isBetaContLin(cont)) {
           worklist.add(new _ReductionTask(_ReductionKind.BETA_CONT_LIN, cont));
+        } else if (_isBranchTargetOfUselessIf(cont)) {
+          worklist.add(
+              new _ReductionTask(_ReductionKind.BRANCH, cont.firstRef.parent));
         }
       }
     }
   }
 }
 
-
-
-class _ReductionKind {
-  final String name;
-  final int hashCode;
-
-  const _ReductionKind(this.name, this.hashCode);
-
-  static const _ReductionKind DEAD_VAL = const _ReductionKind('dead-val', 0);
-  static const _ReductionKind DEAD_CONT = const _ReductionKind('dead-cont', 1);
-  static const _ReductionKind BETA_CONT_LIN =
-      const _ReductionKind('beta-cont-lin', 2);
-  static const _ReductionKind ETA_CONT = const _ReductionKind('eta-cont', 3);
-  static const _ReductionKind DEAD_PARAMETER =
-      const _ReductionKind('dead-parameter', 4);
-
-  String toString() => name;
+enum _ReductionKind {
+  DEAD_VAL,
+  DEAD_CONT,
+  BETA_CONT_LIN,
+  ETA_CONT,
+  DEAD_PARAMETER,
+  BRANCH
 }
 
 /// Represents a reduction task on the worklist. Implements both hashCode and
@@ -518,12 +699,12 @@
   final Node node;
 
   int get hashCode {
-    assert(kind.hashCode < (1 << 3));
-    return (node.hashCode << 3) | kind.hashCode;
+    return (node.hashCode << 3) | kind.index;
   }
 
   _ReductionTask(this.kind, this.node) {
-    assert(node is Continuation || node is LetPrim || node is Parameter);
+    assert(node is Continuation || node is LetPrim || node is Parameter ||
+           node is Branch);
   }
 
   bool operator==(_ReductionTask that) {
@@ -532,10 +713,3 @@
 
   String toString() => "$kind: $node";
 }
-
-/// A dummy class used solely to mark nodes as deleted once they are removed
-/// from a term.
-class _DeletedNode extends Node {
-  accept(_) {}
-  setParentPointers() {}
-}
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
index 25fb1c9..2042320 100644
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -173,11 +173,27 @@
   }
 
   @override
-  bool methodUsesReceiverArgument(FunctionElement function) {
+  bool methodIgnoresReceiverArgument(FunctionElement function) {
     assert(backend.isInterceptedMethod(function));
     ClassElement clazz = function.enclosingClass.declaration;
-    return clazz.isSubclassOf(helpers.jsInterceptorClass) ||
-           classWorld.isUsedAsMixin(clazz);
+    return !clazz.isSubclassOf(helpers.jsInterceptorClass) &&
+           !classWorld.isUsedAsMixin(clazz);
+  }
+
+  @override
+  bool targetIgnoresReceiverArgument(TypeMask type, Selector selector) {
+    // Check if any of the possible targets depend on the extra receiver
+    // argument. Mixins do this, and tear-offs always needs the extra receiver
+    // argument because BoundClosure uses it for equality and hash code.
+    // TODO(15933): Make automatically generated property extraction
+    // closures work with the dummy receiver optimization.
+    bool needsReceiver(Element target) {
+      if (target is! FunctionElement) return false;
+      FunctionElement function = target;
+      return selector.isGetter && !function.isGetter ||
+             !methodIgnoresReceiverArgument(function);
+    }
+    return !classWorld.allFunctions.filter(selector, type).any(needsReceiver);
   }
 
   @override
@@ -434,6 +450,13 @@
     return interceptedTypes.containsMask(t.nonNullable(), classWorld);
   }
 
+  @override
+  bool isDefinitelySelfInterceptor(TypeMask t, {bool allowNull: false}) {
+    assert(allowNull != null);
+    if (!allowNull && t.isNullable) return false;
+    return areDisjoint(t, interceptorType);
+  }
+
   /// Given a class from the interceptor hierarchy, returns a [TypeMask]
   /// matching all values with that interceptor (or a subtype thereof).
   @override
@@ -448,10 +471,8 @@
   }
 
   @override
-  bool areDisjoint(TypeMask leftType, TypeMask rightType) {
-    TypeMask intersected = intersection(leftType, rightType);
-    return intersected.isEmpty && !intersected.isNullable;
-  }
+  bool areDisjoint(TypeMask leftType, TypeMask rightType) =>
+      leftType.isDisjoint(rightType, classWorld);
 
   @override
   bool isMorePreciseOrEqual(TypeMask t1, TypeMask t2) {
@@ -468,8 +489,8 @@
     }
     if (type is types.InterfaceType) {
       TypeMask typeAsMask = allowNull
-      ? new TypeMask.subtype(type.element, classWorld)
-      : new TypeMask.nonNullSubtype(type.element, classWorld);
+          ? new TypeMask.subtype(type.element, classWorld)
+          : new TypeMask.nonNullSubtype(type.element, classWorld);
       if (areDisjoint(value, typeAsMask)) {
         // Disprove the subtype relation based on the class alone.
         return AbstractBool.False;
@@ -561,11 +582,8 @@
     if (isDefinitelyString(type)) {
       return stringType;
     }
-    if (type.satisfies(helpers.typedArrayClass, classWorld)) {
-      if (type.satisfies(helpers.typedArrayOfIntClass, classWorld)) {
-        return intType;
-      }
-      return numType;
+    if (type.satisfies(helpers.jsIndexingBehaviorInterface, classWorld)) {
+      return getInvokeReturnType(new Selector.index(), type);
     }
     return dynamicType;
   }
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index aa26e31..6b09771 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -38,13 +38,17 @@
 import 'cps_fragment.dart';
 import 'cps_ir_nodes.dart';
 import 'type_mask_system.dart';
+import 'effects.dart';
 
 class ConstantPropagationLattice {
   final TypeMaskSystem typeSystem;
   final ConstantSystem constantSystem;
   final types.DartTypes dartTypes;
   final AbstractConstantValue anything;
+  final AbstractConstantValue nothing = new AbstractConstantValue.nothing();
   final AbstractConstantValue nullValue;
+  final AbstractConstantValue trueValue;
+  final AbstractConstantValue falseValue;
 
   ConstantPropagationLattice(CpsFunctionCompiler functionCompiler)
     : typeSystem = functionCompiler.typeSystem,
@@ -53,9 +57,11 @@
       anything = new AbstractConstantValue.nonConstant(
           functionCompiler.typeSystem.dynamicType),
       nullValue = new AbstractConstantValue.constantValue(
-          new NullConstantValue(), new TypeMask.empty());
-
-  final AbstractConstantValue nothing = new AbstractConstantValue.nothing();
+          new NullConstantValue(), new TypeMask.empty()),
+      trueValue = new AbstractConstantValue.constantValue(
+          new TrueConstantValue(), functionCompiler.typeSystem.boolType),
+      falseValue = new AbstractConstantValue.constantValue(
+          new FalseConstantValue(), functionCompiler.typeSystem.boolType);
 
   AbstractConstantValue constant(ConstantValue value, [TypeMask type]) {
     if (type == null) type = typeSystem.getTypeOf(value);
@@ -368,7 +374,9 @@
   AbstractConstantValue negateSpecial(AbstractConstantValue value) {
     AbstractConstantValue folded = foldUnary(constantSystem.negate, value);
     if (folded != null) return folded;
-    if (isDefinitelyInt(value)) return nonConstant(typeSystem.intType);
+    if (isDefinitelyInt(value, allowNull: true)) {
+      return nonConstant(typeSystem.intType);
+    }
     return null;
   }
 
@@ -385,7 +393,8 @@
 
   AbstractConstantValue closedOnInt(AbstractConstantValue left,
                                     AbstractConstantValue right) {
-    if (isDefinitelyInt(left) && isDefinitelyInt(right, allowNull: true)) {
+    if (isDefinitelyInt(left, allowNull: true) &&
+        isDefinitelyInt(right, allowNull: true)) {
       return nonConstant(typeSystem.intType);
     }
     return null;
@@ -393,7 +402,8 @@
 
   AbstractConstantValue closedOnUint(AbstractConstantValue left,
                                      AbstractConstantValue right) {
-    if (isDefinitelyUint(left) && isDefinitelyUint(right, allowNull: true)) {
+    if (isDefinitelyUint(left, allowNull: true) &&
+        isDefinitelyUint(right, allowNull: true)) {
       return nonConstant(typeSystem.uintType);
     }
     return null;
@@ -401,7 +411,8 @@
 
   AbstractConstantValue closedOnUint31(AbstractConstantValue left,
                                        AbstractConstantValue right) {
-    if (isDefinitelyUint31(left) && isDefinitelyUint31(right, allowNull: true)) {
+    if (isDefinitelyUint31(left, allowNull: true) &&
+        isDefinitelyUint31(right, allowNull: true)) {
       return nonConstant(typeSystem.uint31Type);
     }
     return null;
@@ -411,8 +422,8 @@
                                    AbstractConstantValue right) {
     AbstractConstantValue folded = foldBinary(constantSystem.add, left, right);
     if (folded != null) return folded;
-    if (isDefinitelyNum(left)) {
-      if (isDefinitelyUint31(left) &&
+    if (isDefinitelyNum(left, allowNull: true)) {
+      if (isDefinitelyUint31(left, allowNull: true) &&
           isDefinitelyUint31(right, allowNull: true)) {
         return nonConstant(typeSystem.uint32Type);
       }
@@ -445,15 +456,22 @@
     AbstractConstantValue folded =
         foldBinary(constantSystem.truncatingDivide, left, right);
     if (folded != null) return folded;
-    if (isDefinitelyNum(left)) {
-      if (isDefinitelyUint32(left) && isDefinitelyIntInRange(right, min: 2)) {
+    if (isDefinitelyNum(left, allowNull: true)) {
+      if (isDefinitelyUint32(left, allowNull: true) &&
+          isDefinitelyIntInRange(right, min: 2)) {
         return nonConstant(typeSystem.uint31Type);
       }
       if (isDefinitelyUint(right, allowNull: true)) {
         // `0` will be an exception, other values will shrink the result.
-        if (isDefinitelyUint31(left)) return nonConstant(typeSystem.uint31Type);
-        if (isDefinitelyUint32(left)) return nonConstant(typeSystem.uint32Type);
-        if (isDefinitelyUint(left)) return nonConstant(typeSystem.uintType);
+        if (isDefinitelyUint31(left, allowNull: true)) {
+          return nonConstant(typeSystem.uint31Type);
+        }
+        if (isDefinitelyUint32(left, allowNull: true)) {
+          return nonConstant(typeSystem.uint32Type);
+        }
+        if (isDefinitelyUint(left, allowNull: true)) {
+          return nonConstant(typeSystem.uintType);
+        }
       }
       return nonConstant(typeSystem.intType);
     }
@@ -499,8 +517,8 @@
     AbstractConstantValue folded =
         foldBinary(constantSystem.bitAnd, left, right);
     if (folded != null) return folded;
-    if (isDefinitelyNum(left)) {
-      if (isDefinitelyUint31(left) ||
+    if (isDefinitelyNum(left, allowNull: true)) {
+      if (isDefinitelyUint31(left, allowNull: true) ||
           isDefinitelyUint31(right, allowNull: true)) {
         // Either 31-bit argument will truncate the other.
         return nonConstant(typeSystem.uint31Type);
@@ -533,9 +551,9 @@
     AbstractConstantValue folded =
         foldBinary(constantSystem.shiftRight, left, right);
     if (folded != null) return folded;
-    if (isDefinitelyUint31(left)) {
+    if (isDefinitelyUint31(left, allowNull: true)) {
       return nonConstant(typeSystem.uint31Type);
-    } else if (isDefinitelyUint32(left)) {
+    } else if (isDefinitelyUint32(left, allowNull: true)) {
       if (isDefinitelyIntInRange(right, min: 1, max: 31)) {
         // A zero will be shifted into the 'sign' bit.
         return nonConstant(typeSystem.uint31Type);
@@ -547,21 +565,41 @@
 
   AbstractConstantValue lessSpecial(AbstractConstantValue left,
                                     AbstractConstantValue right) {
+    if (isDefinitelyUint(left) && right.isZeroOrNegativeConstant) {
+      return falseValue; // "uint < 0" is false.
+    } else if (left.isNegativeConstant && isDefinitelyUint(right)) {
+      return trueValue; // "-1 < uint" is true.
+    }
     return foldBinary(constantSystem.less, left, right);
   }
 
   AbstractConstantValue lessEqualSpecial(AbstractConstantValue left,
                                          AbstractConstantValue right) {
+    if (isDefinitelyUint(left) && right.isNegativeConstant) {
+      return falseValue; // "uint <= -1" is false.
+    } else if (left.isZeroOrNegativeConstant && isDefinitelyUint(right)) {
+      return trueValue; // "0 <= uint" is true.
+    }
     return foldBinary(constantSystem.lessEqual, left, right);
   }
 
   AbstractConstantValue greaterSpecial(AbstractConstantValue left,
                                        AbstractConstantValue right) {
+    if (left.isZeroOrNegativeConstant && isDefinitelyUint(right)) {
+      return falseValue; // "0 > uint" is false
+    } else if (isDefinitelyUint(left) && right.isNegativeConstant) {
+      return trueValue; // "uint > -1" is true
+    }
     return foldBinary(constantSystem.greater, left, right);
   }
 
   AbstractConstantValue greaterEqualSpecial(AbstractConstantValue left,
                                             AbstractConstantValue right) {
+    if (left.isNegativeConstant && isDefinitelyUint(right)) {
+      return falseValue; // "-1 >= uint" is false
+    } else if (isDefinitelyUint(left) && right.isZeroOrNegativeConstant) {
+      return trueValue; // "uint >= 0" is true
+    }
     return foldBinary(constantSystem.greaterEqual, left, right);
   }
 
@@ -626,6 +664,8 @@
       TypeMask type = typeSystem.indexWithConstant(left.type, index);
       if (type != null) return nonConstant(type);
     }
+    // TODO(asgerf): Handle case where 'left' is a List or Map constant but
+    //               the index is unknown.
     return null;  // The caller will use return type from type inference.
   }
 
@@ -688,6 +728,17 @@
     return nonConstant(value.type.nonNullable());
   }
 
+  AbstractConstantValue intersectWithType(AbstractConstantValue value,
+        TypeMask type) {
+    if (value.isNothing || typeSystem.areDisjoint(value.type, type)) {
+      return nothing;
+    } else if (value.isConstant) {
+      return value;
+    } else {
+      return nonConstant(typeSystem.intersection(value.type, type));
+    }
+  }
+
   /// If [value] is an integer constant, returns its value, otherwise `null`.
   int intValue(AbstractConstantValue value) {
     if (value.isConstant && value.constant.isInt) {
@@ -714,8 +765,10 @@
   final CpsFunctionCompiler _functionCompiler;
   final Map<Variable, ConstantValue> _values= <Variable, ConstantValue>{};
   final ConstantPropagationLattice _lattice;
+  final bool recomputeAll;
 
-  TypePropagator(CpsFunctionCompiler functionCompiler)
+  TypePropagator(CpsFunctionCompiler functionCompiler,
+      {this.recomputeAll: false})
       : _functionCompiler = functionCompiler,
         _lattice = new ConstantPropagationLattice(functionCompiler);
 
@@ -731,7 +784,7 @@
         _values,
         _internalError);
 
-    analyzer.analyze(root);
+    analyzer.analyze(root, recomputeAll);
 
     // Transform. Uses the data acquired in the previous analysis phase to
     // replace branches with fixed targets and side-effect-free expressions
@@ -782,11 +835,17 @@
 
   final List<Node> stack = <Node>[];
 
+  TypeCheckOperator checkIsNumber;
+
   TransformingVisitor(this.compiler,
                       this.functionCompiler,
                       this.lattice,
                       this.analyzer,
-                      this.internalError);
+                      this.internalError) {
+    checkIsNumber = new ClassTypeCheckOperator(
+        helpers.jsNumberClass,
+        BuiltinOperator.IsNotNumber);
+  }
 
   void transform(FunctionDefinition root) {
     // If one of the parameters has no value, the function is unreachable.
@@ -902,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.
@@ -1019,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.
@@ -1047,6 +1106,16 @@
       push(invoke);
       return;
     }
+
+    // Shortcut negation to help simplify control flow. The tree IR will insert
+    // a negation again if that's useful.
+    if (condition is ApplyBuiltinOperator &&
+        condition.operator == BuiltinOperator.IsFalsy) {
+      node.conditionRef.changeTo(condition.argument(0));
+      node.trueContinuationRef.changeTo(falseCont);
+      node.falseContinuationRef.changeTo(trueCont);
+      return;
+    }
   }
 
   void visitInvokeContinuation(InvokeContinuation node) {
@@ -1055,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;
@@ -1090,41 +1159,99 @@
   ///
   /// Returns `true` if the node was replaced.
   specializeOperatorCall(InvokeMethod node) {
+    if (!backend.isInterceptedSelector(node.selector)) return null;
+    if (node.dartArgumentsLength > 1) return null;
+    if (node.callingConvention == CallingConvention.OneShotIntercepted) {
+      return null;
+    }
+
     bool trustPrimitives = compiler.trustPrimitives;
 
-    /// Throws a [NoSuchMethodError] if the receiver is null, where [guard]
-    /// is a predicate that is true if and only if the receiver is null.
-    ///
-    /// See [NullCheck.guarded].
-    Primitive guardReceiver(CpsFragment cps, BuiltinOperator guard) {
-      if (guard == null || getValue(node.dartReceiver).isDefinitelyNotNull) {
-        return node.dartReceiver;
+    /// Check that the receiver and argument satisfy the given type checks, and
+    /// throw a [NoSuchMethodError] or [ArgumentError] if the check fails.
+    CpsFragment makeGuard(TypeCheckOperator receiverGuard,
+                          [TypeCheckOperator argumentGuard]) {
+      CpsFragment cps = new CpsFragment(node.sourceInformation);
+
+      // Make no guards if trusting primitives.
+      if (trustPrimitives) return cps;
+
+      // Determine which guards are needed.
+      ChecksNeeded receiverChecks =
+          receiverGuard.getChecksNeeded(node.dartReceiver, classWorld);
+      bool needReceiverGuard = receiverChecks != ChecksNeeded.None;
+      bool needArgumentGuard =
+          argumentGuard != null &&
+          argumentGuard.needsCheck(node.dartArgument(0), classWorld);
+
+      if (!needReceiverGuard && !needArgumentGuard) return cps;
+
+      // If we only need the receiver check, emit the specialized receiver
+      // check instruction. Examples:
+      //
+      //   if (typeof receiver !== "number") return receiver.$lt;
+      //   if (typeof receiver !== "number") return receiver.$lt();
+      //
+      if (!needArgumentGuard) {
+        Primitive condition = receiverGuard.makeCheck(cps, node.dartReceiver);
+        cps.letPrim(new ReceiverCheck(
+            node.dartReceiver,
+            node.selector,
+            node.sourceInformation,
+            condition: condition,
+            useSelector: true,
+            isNullCheck: receiverChecks == ChecksNeeded.Null
+        ));
+        return cps;
       }
-      if (!trustPrimitives) {
-        // TODO(asgerf): Perhaps a separate optimization should decide that
-        // the guarded check is better based on the type?
-        Primitive check = cps.applyBuiltin(guard, [node.dartReceiver]);
-        return cps.letPrim(new NullCheck.guarded(check, node.dartReceiver,
-          node.selector, node.sourceInformation));
-      } else {
-        // Refine the receiver to be non-null for use in the operator.
-        // This restricts code motion and improves the type computed for the
-        // built-in operator that depends on it.
-        // This must be done even if trusting primitives.
-        return cps.letPrim(
-            new Refinement(node.dartReceiver, typeSystem.nonNullType));
+
+      // TODO(asgerf): We should consider specialized instructions for
+      //   argument checks and receiver+argument checks, to avoid breaking up
+      //   basic blocks.
+
+      // Emit as `H.iae(x)` if only the argument check may fail. For example:
+      //
+      //   if (typeof argument !== "number") return H.iae(argument);
+      //
+      if (!needReceiverGuard) {
+        cps.ifTruthy(argumentGuard.makeCheck(cps, node.dartArgument(0)))
+           .invokeStaticThrower(helpers.throwIllegalArgumentException,
+              [node.dartArgument(0)]);
+        return cps;
       }
+
+      // Both receiver and argument check is needed. Emit as a combined check
+      // using a one-shot interceptor to produce the exact error message in
+      // the error case.  For example:
+      //
+      //   if (typeof receiver !== "number" || typeof argument !== "number")
+      //       return J.$lt(receiver, argument);
+      //
+      Continuation fail = cps.letCont();
+      cps.ifTruthy(receiverGuard.makeCheck(cps, node.dartReceiver))
+         .invokeContinuation(fail);
+      cps.ifTruthy(argumentGuard.makeCheck(cps, node.dartArgument(0)))
+         .invokeContinuation(fail);
+
+      cps.insideContinuation(fail)
+         ..invokeMethod(node.dartReceiver, node.selector, node.mask,
+             [node.dartArgument(0)], CallingConvention.OneShotIntercepted)
+         ..put(new Unreachable());
+
+      return cps;
     }
 
     /// Replaces the call with [operator], using the receiver and first argument
     /// as operands (in that order).
     ///
-    /// If [guard] is given, the receiver is checked using [guardReceiver],
-    /// unless it is known not to be null.
-    CpsFragment makeBinary(BuiltinOperator operator, {BuiltinOperator guard}) {
-      CpsFragment cps = new CpsFragment(node.sourceInformation);
-      Primitive left = guardReceiver(cps, guard);
-      Primitive right = node.dartArgument(0);
+    /// If [guard] is given, the receiver and argument are both checked using
+    /// that operator.
+    CpsFragment makeBinary(BuiltinOperator operator,
+                           {TypeCheckOperator guard: TypeCheckOperator.none}) {
+      CpsFragment cps = makeGuard(guard, guard);
+      Primitive left = guard.makeRefinement(cps, node.dartReceiver, classWorld);
+      Primitive right =
+          guard.makeRefinement(cps, node.dartArgument(0), classWorld);
       Primitive result = cps.applyBuiltin(operator, [left, right]);
       result.hint = node.hint;
       node.replaceUsesWith(result);
@@ -1133,16 +1260,37 @@
 
     /// Like [makeBinary] but for unary operators with the receiver as the
     /// argument.
-    CpsFragment makeUnary(BuiltinOperator operator, {BuiltinOperator guard}) {
-      CpsFragment cps = new CpsFragment(node.sourceInformation);
-      Primitive argument = guardReceiver(cps, guard);
+    CpsFragment makeUnary(BuiltinOperator operator,
+                          {TypeCheckOperator guard: TypeCheckOperator.none}) {
+      CpsFragment cps = makeGuard(guard);
+      Primitive argument =
+          guard.makeRefinement(cps, node.dartReceiver, classWorld);
       Primitive result = cps.applyBuiltin(operator, [argument]);
       result.hint = node.hint;
       node.replaceUsesWith(result);
       return cps;
     }
 
-    if (node.selector.isOperator && node.arguments.length == 2) {
+    Selector renameToOptimizedSelector(String name) {
+      return new Selector.call(
+          new Name(name, backend.helpers.interceptorsLibrary),
+          node.selector.callStructure);
+    }
+
+    /// Replaces the call with a call to [name] with the same inputs.
+    InvokeMethod makeRenamedInvoke(String name) {
+      return new InvokeMethod(node.receiver,
+          renameToOptimizedSelector(name),
+          node.mask,
+          node.arguments.toList(),
+          sourceInformation: node.sourceInformation,
+          callingConvention: node.callingConvention);
+    }
+
+    TypeMask successType =
+        typeSystem.receiverTypeFor(node.selector, node.dartReceiver.type);
+
+    if (node.selector.isOperator && node.dartArgumentsLength == 1) {
       Primitive leftArg = node.dartReceiver;
       Primitive rightArg = node.dartArgument(0);
       AbstractConstantValue left = getValue(leftArg);
@@ -1172,13 +1320,17 @@
           return makeBinary(BuiltinOperator.Identical);
         }
       } else {
-        if (lattice.isDefinitelyNum(left, allowNull: true) &&
-            lattice.isDefinitelyNum(right, allowNull: trustPrimitives)) {
+        if (typeSystem.isDefinitelyNum(successType)) {
           // Try to insert a numeric operator.
           BuiltinOperator operator = NumBinaryBuiltins[opname];
           if (operator != null) {
-            return makeBinary(operator, guard: BuiltinOperator.IsNotNumber);
+            return makeBinary(operator, guard: checkIsNumber);
           }
+
+          // The following specializations only apply to integers.
+          // The Math.floor test is quite large, so we only apply these in cases
+          // where the guard does not involve Math.floor.
+
           // Shift operators are not in [NumBinaryBuiltins] because Dart shifts
           // behave different to JS shifts, especially in the handling of the
           // shift count.
@@ -1186,17 +1338,25 @@
           if (opname == '<<' &&
               lattice.isDefinitelyInt(left, allowNull: true) &&
               lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
-            return makeBinary(BuiltinOperator.NumShl,
-                guard: BuiltinOperator.IsNotNumber);
+            return makeBinary(BuiltinOperator.NumShl, guard: checkIsNumber);
           }
           // Try to insert a shift-right operator. JavaScript's right shift is
           // consistent with Dart's only for left operands in the unsigned
           // 32-bit range.
-          if (opname == '>>' &&
-              lattice.isDefinitelyUint32(left, allowNull: true) &&
-              lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
-            return makeBinary(BuiltinOperator.NumShr,
-                guard: BuiltinOperator.IsNotNumber);
+          if (opname == '>>') {
+            if (lattice.isDefinitelyUint32(left, allowNull: true) &&
+                lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
+              return makeBinary(BuiltinOperator.NumShr, guard: checkIsNumber);
+            } else if (lattice.isDefinitelyUint(left) &&
+                       lattice.isDefinitelyUint(right)) {
+              return makeRenamedInvoke('_shrBothPositive');
+            } else if (lattice.isDefinitelyUint(left) &&
+                       lattice.isDefinitelyNum(right)) {
+              return makeRenamedInvoke('_shrReceiverPositive');
+            } else if (lattice.isDefinitelyNum(left) &&
+                       lattice.isDefinitelyUint(right)) {
+              return makeRenamedInvoke('_shrOtherPositive');
+            }
           }
           // Try to use remainder for '%'. Both operands must be non-negative
           // and the divisor must be non-zero.
@@ -1205,14 +1365,14 @@
               lattice.isDefinitelyUint(right) &&
               lattice.isDefinitelyIntInRange(right, min: 1)) {
             return makeBinary(BuiltinOperator.NumRemainder,
-                guard: BuiltinOperator.IsNotNumber);
+                guard: checkIsNumber);
           }
 
           if (opname == '~/' &&
               lattice.isDefinitelyUint32(left, allowNull: true) &&
               lattice.isDefinitelyIntInRange(right, min: 2)) {
             return makeBinary(BuiltinOperator.NumTruncatingDivideToSigned32,
-                guard: BuiltinOperator.IsNotNumber);
+                guard: checkIsNumber);
           }
         }
         if (lattice.isDefinitelyString(left, allowNull: trustPrimitives) &&
@@ -1223,19 +1383,14 @@
         }
       }
     }
-    if (node.selector.isOperator && node.arguments.length == 1) {
-      Primitive argument = node.dartReceiver;
-      AbstractConstantValue value = getValue(argument);
-
-      if (lattice.isDefinitelyNum(value, allowNull: true)) {
+    if (node.selector.isOperator && node.dartArgumentsLength == 0) {
+      if (typeSystem.isDefinitelyNum(successType)) {
         String opname = node.selector.name;
         if (opname == '~') {
-          return makeUnary(BuiltinOperator.NumBitNot,
-              guard: BuiltinOperator.IsNotNumber);
+          return makeUnary(BuiltinOperator.NumBitNot, guard: checkIsNumber);
         }
         if (opname == 'unary-') {
-          return makeUnary(BuiltinOperator.NumNegate,
-              guard: BuiltinOperator.IsNotNumber);
+          return makeUnary(BuiltinOperator.NumNegate, guard: checkIsNumber);
         }
       }
     }
@@ -1244,18 +1399,18 @@
       Primitive receiver = node.dartReceiver;
       AbstractConstantValue receiverValue = getValue(receiver);
       if (name == 'remainder') {
-        if (node.arguments.length == 2) {
+        if (node.dartArgumentsLength == 1) {
           Primitive arg = node.dartArgument(0);
           AbstractConstantValue argValue = getValue(arg);
           if (lattice.isDefinitelyInt(receiverValue, allowNull: true) &&
               lattice.isDefinitelyInt(argValue) &&
               isIntNotZero(argValue)) {
             return makeBinary(BuiltinOperator.NumRemainder,
-                guard: BuiltinOperator.IsNotNumber);
+                guard: checkIsNumber);
           }
         }
       } else if (name == 'codeUnitAt') {
-        if (node.arguments.length == 2) {
+        if (node.dartArgumentsLength == 1) {
           Primitive index = node.dartArgument(0);
           if (lattice.isDefinitelyString(receiverValue) &&
               lattice.isDefinitelyInt(getValue(index))) {
@@ -1317,16 +1472,24 @@
   /// Returns a CPS fragment whose context is the branch where no error
   /// was thrown.
   Primitive makeBoundsCheck(CpsFragment cps,
-                            Primitive list,
-                            Primitive index,
-                            [int checkKind = BoundsCheck.BOTH_BOUNDS]) {
+        Primitive list,
+        Primitive index,
+        [int checkKind = BoundsCheck.BOTH_BOUNDS | BoundsCheck.INTEGER]) {
     if (compiler.trustPrimitives) {
       return cps.letPrim(new BoundsCheck.noCheck(list, cps.sourceInformation));
     } else {
       GetLength length = cps.letPrim(new GetLength(list));
       list = cps.refine(list, typeSystem.nonNullType);
-      return cps.letPrim(new BoundsCheck(list, index, length, checkKind,
-          cps.sourceInformation));
+      BoundsCheck check = cps.letPrim(new BoundsCheck(list, index, length,
+          checkKind, cps.sourceInformation));
+      if (check.hasIntegerCheck) {
+        if (typeSystem.isDefinitelyInt(index.type)) {
+          check.checks &= ~BoundsCheck.INTEGER;
+        } else {
+          cps.refine(index, typeSystem.uint32Type);
+        }
+      }
+      return check;
     }
   }
 
@@ -1360,12 +1523,41 @@
     }
     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);
-        if (!lattice.isDefinitelyInt(getValue(index))) return null;
         CpsFragment cps = new CpsFragment(node.sourceInformation);
         receiver = makeBoundsCheck(cps, receiver, index);
         GetIndex get = cps.letPrim(new GetIndex(receiver, index));
@@ -1381,7 +1573,6 @@
         }
         Primitive index = node.dartArgument(0);
         Primitive value = node.dartArgument(1);
-        if (!lattice.isDefinitelyInt(getValue(index))) return null;
         CpsFragment cps = new CpsFragment(node.sourceInformation);
         receiver = makeBoundsCheck(cps, receiver, index);
         cps.letPrim(new SetIndex(receiver, index, value));
@@ -1480,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]);
@@ -1518,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;
@@ -1534,10 +1725,10 @@
         // Check that all uses of the iterator are 'moveNext' and 'current'.
         assert(!isInterceptedSelector(Selectors.moveNext));
         assert(!isInterceptedSelector(Selectors.current));
-        for (Reference ref in iterator.effectiveUses) {
+        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;
@@ -1551,7 +1742,7 @@
         MutableVariable current = new MutableVariable(new LoopItemEntity());
 
         // Rewrite all uses of the iterator.
-        for (Reference ref in iterator.effectiveUses) {
+        for (Reference ref in iterator.refinedUses) {
           InvokeMethod use = ref.parent;
           if (use.selector == Selectors.current) {
             // Rewrite iterator.current to a use of the 'current' variable.
@@ -1705,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.
@@ -1726,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) {
@@ -1737,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.
@@ -1760,7 +1951,7 @@
 
       // If there are multiple uses, we cannot eliminate the getter call and
       // therefore risk duplicating its side effects.
-      if (!isPure && tearOff.hasMultipleEffectiveUses) return null;
+      if (!isPure && tearOff.hasMultipleRefinedUses) return null;
 
       // If the getter call is impure, we risk reordering side effects,
       // unless it is immediately prior to the closure call.
@@ -1772,11 +1963,11 @@
         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.hasNoEffectiveUses) {
+      if (tearOff.hasNoRefinedUses) {
         // Eliminate the getter call if it has no more uses.
         // This cannot be delegated to other optimizations because we need to
         // avoid duplication of side effects.
@@ -1802,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;
@@ -1844,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;
@@ -1863,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);
     }
   }
 
@@ -1894,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;
@@ -1903,32 +2109,22 @@
         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);
 
-      // Check if any of the possible targets depend on the extra receiver
-      // argument. Mixins do this, and tear-offs always needs the extra receiver
-      // argument because BoundClosure uses it for equality and hash code.
-      // TODO(15933): Make automatically generated property extraction
-      // closures work with the dummy receiver optimization.
-      bool needsReceiver(Element target) {
-        if (target is! FunctionElement) return false;
-        FunctionElement function = target;
-        return typeSystem.methodUsesReceiverArgument(function) ||
-               node.selector.isGetter && !function.isGetter;
-      }
-      if (!getAllTargets(receiverType, node.selector).any(needsReceiver)) {
-        // Replace the extra receiver argument with a dummy value if the
-        // target definitely does not use it.
+      // Replace the extra receiver argument with a dummy value if the
+      // target definitely does not use it.
+      if (typeSystem.targetIgnoresReceiverArgument(receiverType,
+            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:
@@ -1936,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:
@@ -1949,15 +2145,29 @@
   /// Specialize calls to internal static methods.
   specializeInternalMethodCall(InvokeStatic node) {
     if (node.target == backend.helpers.stringInterpolationHelper) {
-      AbstractConstantValue value = getValue(node.arguments[0].definition);
+      Primitive argument = node.argument(0);
+      AbstractConstantValue value = getValue(argument);
       if (lattice.isDefinitelyString(value)) {
-        node.replaceUsesWith(node.arguments[0].definition);
+        node.replaceUsesWith(argument);
         return new CpsFragment();
+      } else if (typeSystem.isDefinitelySelfInterceptor(value.type)) {
+        TypeMask toStringReturn = typeSystem.getInvokeReturnType(
+            Selectors.toString_, value.type);
+        if (typeSystem.isDefinitelyString(toStringReturn)) {
+          CpsFragment cps = new CpsFragment(node.sourceInformation);
+          Primitive invoke = cps.invokeMethod(argument,
+              Selectors.toString_,
+              value.type,
+              [cps.makeZero()],
+              CallingConvention.DummyIntercepted);
+          node.replaceUsesWith(invoke);
+          return cps;
+        }
       }
     } 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);
       }
     }
@@ -1965,6 +2175,8 @@
   }
 
   visitInvokeStatic(InvokeStatic node) {
+    node.effects = Effects.from(
+        compiler.world.getSideEffectsOfElement(node.target));
     return specializeInternalMethodCall(node);
   }
 
@@ -1991,7 +2203,7 @@
   //     Nothing happens. The primitive remains as it is.
   //
 
-  void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
+  visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
     ast.DartString getString(AbstractConstantValue value) {
       StringConstantValue constant = value.constant;
       return constant.primitiveValue;
@@ -2001,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 =
@@ -2016,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;
@@ -2027,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);
         }
@@ -2047,53 +2256,81 @@
         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);
-        if (lattice.isDefinitelyBool(left) &&
-            right.isConstant &&
-            right.constant.isTrue) {
-          // Replace identical(x, true) by x when x is known to be a boolean.
-          // Note that this is not safe if x is null, because the value might
-          // not be used as a condition.
-          node.replaceUsesWith(leftArg);
-        } else if (lattice.isDefinitelyBool(right) &&
-            left.isConstant &&
-            left.constant.isTrue) {
-          node.replaceUsesWith(rightArg);
-        } else if (left.isNullConstant || right.isNullConstant) {
+        BuiltinOperator newOperator;
+        if (left.isNullConstant || right.isNullConstant) {
           // Use `==` for comparing against null, so JS undefined and JS null
           // are considered equal.
-          node.operator = BuiltinOperator.LooseEq;
+          newOperator = BuiltinOperator.LooseEq;
         } else if (!left.isNullable || !right.isNullable) {
           // If at most one operand can be Dart null, we can use `===`.
           // This is not safe when we might compare JS null and JS undefined.
-          node.operator = BuiltinOperator.StrictEq;
+          newOperator = BuiltinOperator.StrictEq;
         } else if (lattice.isDefinitelyNum(left, allowNull: true) &&
                    lattice.isDefinitelyNum(right, allowNull: true)) {
           // If both operands can be null, but otherwise are of the same type,
           // we can use `==` for comparison.
           // This is not safe e.g. for comparing strings against numbers.
-          node.operator = BuiltinOperator.LooseEq;
+          newOperator = BuiltinOperator.LooseEq;
         } else if (lattice.isDefinitelyString(left, allowNull: true) &&
                    lattice.isDefinitelyString(right, allowNull: true)) {
-          node.operator = BuiltinOperator.LooseEq;
+          newOperator = BuiltinOperator.LooseEq;
         } else if (lattice.isDefinitelyBool(left, allowNull: true) &&
                    lattice.isDefinitelyBool(right, allowNull: true)) {
-          node.operator = BuiltinOperator.LooseEq;
+          newOperator = BuiltinOperator.LooseEq;
+        }
+        if (newOperator != null) {
+          return new ApplyBuiltinOperator(newOperator,
+              node.arguments.toList(),
+              node.sourceInformation);
+        }
+        break;
+
+      case BuiltinOperator.StrictEq:
+      case BuiltinOperator.LooseEq:
+      case BuiltinOperator.StrictNeq:
+      case BuiltinOperator.LooseNeq:
+        bool negated =
+            node.operator == BuiltinOperator.StrictNeq ||
+            node.operator == BuiltinOperator.LooseNeq;
+        for (int firstIndex in [0, 1]) {
+          int secondIndex = 1 - firstIndex;
+          Primitive firstArg = node.argument(firstIndex);
+          Primitive secondArg = node.argument(secondIndex);
+          AbstractConstantValue first = getValue(firstArg);
+          if (!lattice.isDefinitelyBool(first)) continue;
+          AbstractConstantValue second = getValue(secondArg);
+          if (!second.isConstant || !second.constant.isBool) continue;
+          bool isTrueConstant = second.constant.isTrue;
+          if (isTrueConstant == !negated) {
+            // (x === true) ==> x
+            // (x !== false) ==> x
+            node.replaceUsesWith(firstArg);
+            return null;
+          } else {
+            // (x === false) ==> !x
+            // (x !== true) ==> !x
+            return new ApplyBuiltinOperator(
+                BuiltinOperator.IsFalsy,
+                [firstArg],
+                node.sourceInformation);
+          }
         }
         break;
 
       default:
     }
+    return null;
   }
 
   void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
   }
 
   visitTypeTest(TypeTest node) {
-    Primitive prim = node.value.definition;
+    Primitive prim = node.value;
 
     Primitive unaryBuiltinOperator(BuiltinOperator operator) =>
         new ApplyBuiltinOperator(
@@ -2123,7 +2360,7 @@
         return unaryBuiltinOperator(BuiltinOperator.IsNumber);
       }
       return new ApplyBuiltinOperator(
-          BuiltinOperator.IsNumberAndFloor,
+          BuiltinOperator.IsInteger,
           <Primitive>[prim, prim, prim],
           node.sourceInformation);
     }
@@ -2199,10 +2436,11 @@
     // The [BoundsChecker] pass does not try to eliminate checks that could be
     // eliminated by constant folding.
     if (node.hasNoChecks) return;
-    int index = lattice.intValue(getValue(node.index.definition));
-    int length = node.length == null
+    Primitive indexPrim = node.index;
+    int index = lattice.intValue(getValue(indexPrim));
+    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;
     }
@@ -2212,8 +2450,11 @@
     if (length != null && length > 0) {
       node.checks &= ~BoundsCheck.EMPTINESS;
     }
-    if (!node.lengthUsedInCheck && node.length != null) {
-      node..length.unlink()..length = null;
+    if (typeSystem.isDefinitelyInt(indexPrim.type)) {
+      node.checks &= ~BoundsCheck.INTEGER;
+    }
+    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
@@ -2224,17 +2465,63 @@
       //     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;
     }
   }
 
-  visitNullCheck(NullCheck node) {
-    if (!getValue(node.value.definition).isNullable) {
-      node.replaceUsesWith(node.value.definition);
+  visitReceiverCheck(ReceiverCheck node) {
+    Primitive input = node.value;
+    if (!input.type.isNullable &&
+        (node.isNullCheck ||
+         !input.type.needsNoSuchMethodHandling(node.selector, classWorld))) {
+      node.replaceUsesWith(input);
       return new CpsFragment();
     }
     return null;
   }
+
+  visitGetLength(GetLength node) {
+    node.isFinal = typeSystem.isDefinitelyFixedLengthIndexable(
+        node.object.type, allowNull: true);
+  }
+
+  visitReadTypeVariable(ReadTypeVariable node) {
+    // Pattern match on
+    //
+    //    ReadTypeVariable(var, CreateInstance(..., TypeExpression(arguments)))
+    //
+    // and extract the argument that corresponds to the type variable. This is a
+    // shrinking reduction.
+    //
+    // TODO(sra): This is a shrinking reduction that does not depend on inferred
+    // types so it should be done in the shrinking reductions pass.
+    //
+    // TODO(sra): A non-shrinking version of this rewrite could be done as part
+    // of scalar replacement.
+
+    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
+        // term. Avoid this by restricting to direct indexing.
+        // TODO(sra): Also include cases that require substitution but the end
+        // result is the same as some indexing or a simple constant type.
+        if (!functionCompiler.glue.needsSubstitutionForTypeVariableAccess(
+                context)) {
+          int index = functionCompiler.glue.getTypeVariableIndex(node.variable);
+          if (0 <= index && index < typeExpression.argumentRefs.length) {
+            node.replaceUsesWith(typeExpression.argument(index));
+            return new CpsFragment();
+          }
+        }
+      }
+    }
+    return null;
+  }
 }
 
 /**
@@ -2288,8 +2575,11 @@
                          this.values,
                          this.internalError);
 
-  void analyze(FunctionDefinition root) {
+  void analyze(FunctionDefinition root, bool recomputeAll) {
     reachableContinuations.clear();
+    if (recomputeAll) {
+      new ResetAnalysisInfo(reachableContinuations, values).visit(root);
+    }
 
     // Initially, only the root node is reachable.
     push(root);
@@ -2397,7 +2687,7 @@
     // change the abstract value.
     if (node.thisParameter != null && getValue(node.thisParameter).isNothing) {
       if (isIntercepted &&
-          typeSystem.methodUsesReceiverArgument(node.element)) {
+          !typeSystem.methodIgnoresReceiverArgument(node.element)) {
         setValue(node.thisParameter, nonConstant(typeSystem.nonNullType));
       } else {
         setValue(node.thisParameter,
@@ -2405,11 +2695,11 @@
       }
     }
     if (isIntercepted && getValue(node.parameters[0]).isNothing) {
-      if (typeSystem.methodUsesReceiverArgument(node.element)) {
+      if (typeSystem.methodIgnoresReceiverArgument(node.element)) {
+        setValue(node.parameters[0], nonConstant());
+      } else {
         setValue(node.parameters[0],
             nonConstant(typeSystem.getReceiverType(node.element)));
-      } else {
-        setValue(node.parameters[0], nonConstant());
       }
     }
     bool hasParameterWithoutValue = false;
@@ -2456,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;
     }
@@ -2472,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);
     }
@@ -2486,7 +2776,6 @@
 
   void visitInvokeMethod(InvokeMethod node) {
     AbstractConstantValue receiver = getValue(node.dartReceiver);
-    node.receiverIsNotNull = receiver.isDefinitelyNotNull;
     if (receiver.isNothing) {
       return setResult(node, lattice.nothing);
     }
@@ -2532,7 +2821,7 @@
 
     // Calculate the resulting constant if possible.
     String opname = node.selector.name;
-    if (node.arguments.length == 1) {
+    if (node.dartArgumentsLength == 0) {
       // Unary operator.
       if (opname == "unary-") {
         opname = "-";
@@ -2540,7 +2829,7 @@
       UnaryOperator operator = UnaryOperator.parse(opname);
       AbstractConstantValue result = lattice.unaryOp(operator, receiver);
       return finish(result, canReplace: !receiver.isNullable);
-    } else if (node.arguments.length == 2) {
+    } else if (node.dartArgumentsLength == 1) {
       // Binary operator.
       AbstractConstantValue right = getValue(node.dartArgument(0));
       BinaryOperator operator = BinaryOperator.parse(opname);
@@ -2556,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));
     }
 
@@ -2564,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));
     }
 
@@ -2590,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);
@@ -2619,37 +2908,34 @@
 
       case BuiltinOperator.Identical:
       case BuiltinOperator.StrictEq:
+      case BuiltinOperator.StrictNeq:
       case BuiltinOperator.LooseEq:
-        AbstractConstantValue leftConst =
-            getValue(node.arguments[0].definition);
-        AbstractConstantValue rightConst =
-            getValue(node.arguments[1].definition);
-        ConstantValue leftValue = leftConst.constant;
-        ConstantValue rightValue = rightConst.constant;
-        if (leftConst.isNothing || rightConst.isNothing) {
+      case BuiltinOperator.LooseNeq:
+        bool negated =
+            node.operator == BuiltinOperator.StrictNeq ||
+            node.operator == BuiltinOperator.LooseNeq;
+        AbstractConstantValue left = getValue(node.argument(0));
+        AbstractConstantValue right = getValue(node.argument(1));
+        if (left.isNothing || right.isNothing) {
           setValue(node, lattice.nothing);
-          return; // And come back later.
-        } else if (!leftConst.isConstant || !rightConst.isConstant) {
-          TypeMask leftType = leftConst.type;
-          TypeMask rightType = rightConst.type;
-          if (typeSystem.areDisjoint(leftType, rightType)) {
-            setValue(node,
-                constantValue(new FalseConstantValue(), typeSystem.boolType));
-          } else {
-            setValue(node, nonConstant(typeSystem.boolType));
-          }
           return;
-        } else if (leftValue.isPrimitive && rightValue.isPrimitive) {
-          assert(leftConst.isConstant && rightConst.isConstant);
-          PrimitiveConstantValue left = leftValue;
-          PrimitiveConstantValue right = rightValue;
-          // Should this be constantSystem.identity.fold(left, right)?
-          ConstantValue result =
-            new BoolConstantValue(left.primitiveValue == right.primitiveValue);
-          setValue(node, constantValue(result, typeSystem.boolType));
-        } else {
-          setValue(node, nonConstant(typeSystem.boolType));
         }
+        if (left.isConstant && right.isConstant) {
+          ConstantValue equal = lattice.constantSystem.identity.fold(
+              left.constant, right.constant);
+          if (equal != null && equal.isBool) {
+            ConstantValue result =
+                new BoolConstantValue(equal.isTrue == !negated);
+            setValue(node, constantValue(result, typeSystem.boolType));
+            return;
+          }
+        }
+        if (typeSystem.areDisjoint(left.type, right.type)) {
+          ConstantValue result = new BoolConstantValue(negated);
+          setValue(node, constantValue(result, typeSystem.boolType));
+          return;
+        }
+        setValue(node, nonConstant(typeSystem.boolType));
         break;
 
       case BuiltinOperator.NumAdd:
@@ -2725,8 +3011,11 @@
       case BuiltinOperator.IsFalsy:
       case BuiltinOperator.IsNumber:
       case BuiltinOperator.IsNotNumber:
+      case BuiltinOperator.IsNotInteger:
       case BuiltinOperator.IsFloor:
-      case BuiltinOperator.IsNumberAndFloor:
+      case BuiltinOperator.IsInteger:
+      case BuiltinOperator.IsUnsigned32BitInteger:
+      case BuiltinOperator.IsNotUnsigned32BitInteger:
         setValue(node, nonConstant(typeSystem.boolType));
         break;
 
@@ -2740,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)));
@@ -2750,8 +3039,13 @@
   }
 
   void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
-    // TODO(karlklose): lookup the function and get ites return type.
-    setResult(node, nonConstant());
+    if (node.isConstructorBodyCall) {
+      setResult(node, lattice.nullValue);
+    } else if (node.isTearOff) {
+      setResult(node, nonConstant(typeSystem.functionType));
+    } else {
+      setResult(node, nonConstant(typeSystem.getReturnType(node.target)));
+    }
   }
 
   void visitInvokeConstructor(InvokeConstructor node) {
@@ -2772,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);
@@ -2780,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) {
@@ -2826,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);
@@ -2851,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) {
@@ -2862,12 +3156,6 @@
     }
   }
 
-  void visitLiteralMap(LiteralMap node) {
-    // Constant maps are translated into (Constant MapConstant(...)) IR nodes,
-    // and thus LiteralMap nodes are NonConst.
-    setValue(node, nonConstant(typeSystem.mapType));
-  }
-
   void visitConstant(Constant node) {
     ConstantValue value = node.value;
     if (value.isDummy || !value.isConstant) {
@@ -2879,7 +3167,7 @@
   }
 
   void visitGetMutable(GetMutable node) {
-    setValue(node, getValue(node.variable.definition));
+    setValue(node, getValue(node.variable));
   }
 
   void visitMutableVariable(MutableVariable node) {
@@ -2911,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 &&
@@ -2928,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;
@@ -2980,12 +3268,26 @@
 
   @override
   void visitForeignCode(ForeignCode node) {
-    setValue(node, nonConstant(node.type));
+    bool firstArgumentIsNullable = false;
+    if (node.argumentRefs.length > 0) {
+      AbstractConstantValue first = getValue(node.argumentRefs.first.definition);
+      if (first.isNothing) {
+        setValue(node, nothing);
+        return;
+      }
+      firstArgumentIsNullable = first.isNullable;
+    }
+    setValue(node, nonConstant(node.storedType));
+    node.isSafeForElimination =
+        !node.nativeBehavior.sideEffects.hasSideEffects() &&
+        (!node.nativeBehavior.throwBehavior.canThrow ||
+         (!firstArgumentIsNullable &&
+          node.nativeBehavior.throwBehavior.isOnlyNullNSMGuard));
   }
 
   @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) {
@@ -2999,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 {
@@ -3023,26 +3325,30 @@
 
   @override
   void visitRefinement(Refinement node) {
-    AbstractConstantValue value = getValue(node.value.definition);
-    if (value.isNothing ||
-        typeSystem.areDisjoint(value.type, node.refineType)) {
-      setValue(node, nothing);
-    } else if (value.isConstant) {
-      setValue(node, value);
-    } else {
-      setValue(node,
-          nonConstant(value.type.intersection(node.refineType, classWorld)));
-    }
+    setValue(node, lattice.intersectWithType(
+        getValue(node.value.definition),
+        node.refineType));
   }
 
   @override
   void visitBoundsCheck(BoundsCheck node) {
-    setValue(node, getValue(node.object.definition));
+    setValue(node, getValue(node.object));
   }
 
   @override
-  void visitNullCheck(NullCheck node) {
-    setValue(node, lattice.nonNullable(getValue(node.value.definition)));
+  void visitReceiverCheck(ReceiverCheck node) {
+    AbstractConstantValue value = getValue(node.value);
+    if (node.isNullCheck) {
+      // Avoid expensive TypeMask operations for null checks.
+      setValue(node, lattice.nonNullable(value));
+    } else if (value.isConstant &&
+        !value.type.needsNoSuchMethodHandling(node.selector, classWorld)) {
+      // Preserve constants, unless the check fails for the constant.
+      setValue(node, value);
+    } else {
+      setValue(node,
+          nonConstant(typeSystem.receiverTypeFor(node.selector, value.type)));
+    }
   }
 }
 
@@ -3093,6 +3399,17 @@
   bool get isNullConstant => kind == CONSTANT && constant.isNull;
   bool get isTrueConstant => kind == CONSTANT && constant.isTrue;
   bool get isFalseConstant => kind == CONSTANT && constant.isFalse;
+  bool get isZeroConstant => kind == CONSTANT && constant.isZero;
+  bool get isZeroOrNegativeConstant {
+    if (kind != CONSTANT || !constant.isNum) return false;
+    PrimitiveConstantValue value = constant;
+    return value.primitiveValue <= 0;
+  }
+  bool get isNegativeConstant {
+    if (kind != CONSTANT || !constant.isNum) return false;
+    PrimitiveConstantValue value = constant;
+    return value.primitiveValue < 0;
+  }
 
   bool get isNullable => kind != NOTHING && type.isNullable;
   bool get isDefinitelyNotNull => kind == NOTHING || !type.isNullable;
@@ -3141,18 +3458,112 @@
 
   ResetAnalysisInfo(this.reachableContinuations, this.values);
 
+  void clear(Variable variable) {
+    variable.type = null;
+    values[variable] = null;
+  }
+
+  processFunctionDefinition(FunctionDefinition node) {
+    clear(node.returnContinuation.parameters.single);
+    node.parameters.forEach(clear);
+  }
+
   processContinuation(Continuation cont) {
     reachableContinuations.remove(cont);
-    cont.parameters.forEach(values.remove);
+    cont.parameters.forEach(clear);
   }
 
   processLetPrim(LetPrim node) {
-    node.primitive.type = null;
-    values[node.primitive] = null;
+    clear(node.primitive);
   }
 
   processLetMutable(LetMutable node) {
-    node.variable.type = null;
-    values[node.variable] = null;
+    clear(node.variable);
+  }
+}
+
+enum ChecksNeeded {
+  /// No check is needed.
+  None,
+
+  /// Only null may fail the check.
+  Null,
+
+  /// Full check required.
+  Complete,
+}
+
+/// Generates runtime checks against a some type criteria, and determines at
+/// compile-time if the check is needed.
+///
+/// This class only generates the condition for determining if a check should
+/// fail.  Throwing the appropriate error in response to a failure is handled
+/// elsewhere.
+abstract class TypeCheckOperator {
+  const TypeCheckOperator();
+  static const TypeCheckOperator none = const NoTypeCheckOperator();
+
+  /// Determines to what extent a runtime check is needed.
+  ///
+  /// Sometimes a check can be slightly improved if it is known that null is the
+  /// only possible input that fails the check.
+  ChecksNeeded getChecksNeeded(Primitive value, World world);
+
+  /// Make an expression that returns `true` if [value] should fail the check.
+  ///
+  /// The result should be used in a check of the form:
+  ///
+  ///     if (makeCheck(value)) throw Error(value);
+  ///
+  Primitive makeCheck(CpsFragment cps, Primitive value);
+
+  /// Refine [value] after a succesful check.
+  Primitive makeRefinement(CpsFragment cps, Primitive value, World world);
+
+  bool needsCheck(Primitive value, World world) {
+    return getChecksNeeded(value, world) != ChecksNeeded.None;
+  }
+}
+
+/// Check that always passes.
+class NoTypeCheckOperator extends TypeCheckOperator {
+  const NoTypeCheckOperator();
+
+  ChecksNeeded getChecksNeeded(Primitive value, World world) {
+    return ChecksNeeded.None;
+  }
+
+  Primitive makeCheck(CpsFragment cps, Primitive value) {
+    return cps.makeFalse();
+  }
+
+  Primitive makeRefinement(CpsFragment cps, Primitive value, World world) {
+    return value;
+  }
+}
+
+/// Checks using a built-in operator that a value is an instance of a given
+/// class.
+class ClassTypeCheckOperator extends TypeCheckOperator {
+  ClassElement classElement;
+  BuiltinOperator negatedOperator;
+
+  ClassTypeCheckOperator(this.classElement, this.negatedOperator);
+
+  ChecksNeeded getChecksNeeded(Primitive value, World world) {
+    TypeMask type = value.type;
+    if (type.satisfies(classElement, world)) {
+      return type.isNullable ? ChecksNeeded.Null : ChecksNeeded.None;
+    } else {
+      return ChecksNeeded.Complete;
+    }
+  }
+
+  Primitive makeCheck(CpsFragment cps, Primitive value) {
+    return cps.applyBuiltin(negatedOperator, [value]);
+  }
+
+  Primitive makeRefinement(CpsFragment cps, Primitive value, World world) {
+    return cps.refine(value, new TypeMask.nonNullSubclass(classElement, world));
   }
 }
diff --git a/pkg/compiler/lib/src/cps_ir/update_refinements.dart b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
index d93e747..313f2cb 100644
--- a/pkg/compiler/lib/src/cps_ir/update_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/update_refinements.dart
@@ -3,6 +3,7 @@
 import 'cps_ir_nodes.dart';
 import 'optimizers.dart' show Pass;
 import 'type_mask_system.dart';
+import '../world.dart';
 
 /// Updates all references to use the most refined version in scope.
 ///
@@ -19,8 +20,9 @@
   String get passName => 'Update refinements';
 
   final TypeMaskSystem typeSystem;
+  World get classWorld => typeSystem.classWorld;
 
-  Map<Primitive, Refinement> refinementFor = <Primitive, Refinement>{};
+  Map<Primitive, Primitive> refinementFor = <Primitive, Primitive>{};
 
   UpdateRefinements(this.typeSystem);
 
@@ -29,11 +31,34 @@
   }
 
   Expression traverseLetPrim(LetPrim node) {
+    Expression next = node.body;
     visit(node.primitive);
-    return node.body;
+    return next;
   }
 
-  @override
+  visitReceiverCheck(ReceiverCheck node) {
+    if (refine(node.valueRef)) {
+      // Update the type if the input has changed.
+      Primitive value = node.value;
+      if (value.type.needsNoSuchMethodHandling(node.selector, classWorld)) {
+        node.type = typeSystem.receiverTypeFor(node.selector, value.type);
+      } else {
+        // Check is no longer needed.
+        node..replaceUsesWith(value)..destroy();
+        LetPrim letPrim = node.parent;
+        letPrim.remove();
+        return;
+      }
+    }
+    // Use the ReceiverCheck as a refinement.
+    Primitive value = node.effectiveDefinition;
+    Primitive old = refinementFor[value];
+    refinementFor[value] = node;
+    pushAction(() {
+      refinementFor[value] = old;
+    });
+  }
+
   visitRefinement(Refinement node) {
     if (refine(node.value)) {
       // Update the type if the input has changed.
@@ -41,14 +66,21 @@
           node.refineType);
     }
     Primitive value = node.effectiveDefinition;
-    Refinement old = refinementFor[value];
+    Primitive old = refinementFor[value];
     refinementFor[value] = node;
     pushAction(() {
       refinementFor[value] = old;
     });
   }
 
-  @override
+  visitBoundsCheck(BoundsCheck node) {
+    super.visitBoundsCheck(node);
+    if (node.hasIntegerCheck &&
+        typeSystem.isDefinitelyInt(node.index.type)) {
+      node.checks &= ~BoundsCheck.INTEGER;
+    }
+  }
+
   processReference(Reference ref) {
     refine(ref);
   }
@@ -56,7 +88,7 @@
   bool refine(Reference ref) {
     Definition def = ref.definition;
     if (def is Primitive) {
-      Refinement refinement = refinementFor[def.effectiveDefinition];
+      Primitive refinement = refinementFor[def.effectiveDefinition];
       if (refinement != null && refinement != ref.definition) {
         ref.changeTo(refinement);
         return true;
diff --git a/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
new file mode 100644
index 0000000..ca510f7
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/use_field_initializers.dart
@@ -0,0 +1,212 @@
+// 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.use_field_initializers;
+
+import 'cps_ir_nodes.dart';
+import 'optimizers.dart';
+import '../elements/elements.dart';
+import '../js_backend/js_backend.dart';
+
+/// Eliminates [SetField] instructions when the value can instead be passed into
+/// the field initializer of a [CreateInstance] instruction.
+///
+/// This compensates for a somewhat common pattern where fields are initialized
+/// in the constructor body instead of using intializers. For example:
+///
+///     class Foo {
+///       var x, y;
+///       Foo(x, y) {
+///          this.x = x;
+///          this.y = y;
+///        }
+///      }
+///
+///   ==> (IR for Foo constructor)
+///
+///      foo = new D.Foo(null, null);
+///      foo.x = 'a';
+///      foo.y = 'b';
+///
+///   ==> (after this pass)
+///
+///      foo = new D.Foo('a', 'b');
+//
+// TODO(asgerf): Store forwarding and load elimination could most likely
+//   handle this more generally.
+//
+class UseFieldInitializers extends BlockVisitor implements Pass {
+  String get passName => 'Use field initializers';
+
+  final JavaScriptBackend backend;
+
+  final Set<CreateInstance> unescaped = new Set<CreateInstance>();
+
+  /// Continuation bindings separating the current traversal position from an
+  /// unescaped [CreateInstance].  When [CreateInstance] is sunk, these
+  /// continuations must sink as well to ensure the object remains in scope
+  /// inside the bound continuations.
+  final List<LetCont> letConts = <LetCont>[];
+
+  /// If non-null, the bindings in [letConts] should sink to immediately below
+  /// this node.
+  InteriorNode letContSinkTarget = null;
+  EscapeVisitor escapeVisitor;
+
+  UseFieldInitializers(this.backend);
+
+  void rewrite(FunctionDefinition node) {
+    escapeVisitor = new EscapeVisitor(this);
+    BlockVisitor.traverseInPreOrder(node, this);
+  }
+
+  void escape(Reference ref) {
+    Definition def = ref.definition;
+    if (def is CreateInstance) {
+      unescaped.remove(def);
+      if (unescaped.isEmpty) {
+        sinkLetConts();
+        letConts.clear();
+      }
+    }
+  }
+
+  void visitContinuation(Continuation node) {
+    endBasicBlock();
+  }
+  void visitLetHandler(LetHandler node) {
+    endBasicBlock();
+  }
+  void visitInvokeContinuation(InvokeContinuation node) {
+    endBasicBlock();
+  }
+  void visitBranch(Branch node) {
+    endBasicBlock();
+  }
+  void visitRethrow(Rethrow node) {
+    endBasicBlock();
+  }
+  void visitThrow(Throw node) {
+    endBasicBlock();
+  }
+  void visitUnreachable(Unreachable node) {
+    endBasicBlock();
+  }
+
+  void visitLetMutable(LetMutable node) {
+    escape(node.valueRef);
+  }
+
+  void visitLetCont(LetCont node) {
+    if (unescaped.isNotEmpty) {
+      // Ensure we do not lift a LetCont if there is a sink target set above
+      // the current node.
+      sinkLetConts();
+      letConts.add(node);
+    }
+  }
+
+  void sinkLetConts() {
+    if (letContSinkTarget != null) {
+      for (LetCont letCont in letConts.reversed) {
+        letCont..remove()..insertBelow(letContSinkTarget);
+      }
+      letContSinkTarget = null;
+    }
+  }
+
+  void endBasicBlock() {
+    sinkLetConts();
+    letConts.clear();
+    unescaped.clear();
+  }
+
+  void visitLetPrim(LetPrim node) {
+    Primitive prim = node.primitive;
+    if (prim is CreateInstance) {
+      unescaped.add(prim);
+      prim.argumentRefs.forEach(escape);
+      return;
+    }
+    if (unescaped.isEmpty) return;
+    if (prim is SetField) {
+      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.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.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.
+          rebindCreateInstanceAt(object, node);
+          letContSinkTarget = node;
+        }
+      }
+      return;
+    }
+    if (prim is GetField) {
+      // 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;
+      if (object is CreateInstance && unescaped.contains(object)) {
+        int index = getFieldIndex(object.classElement, prim.field);
+        if (index == -1) {
+          escape(prim.objectRef);
+        } else {
+          prim.replaceUsesWith(object.argument(index));
+          prim.destroy();
+          node.remove();
+        }
+      }
+      return;
+    }
+    escapeVisitor.visit(node.primitive);
+  }
+
+  void rebindCreateInstanceAt(CreateInstance prim, LetPrim newBinding) {
+    removeBinding(prim);
+    newBinding.primitive = prim;
+    prim.parent = newBinding;
+  }
+
+  /// Returns the index of [field] in the canonical initialization order in
+  /// [classElement], or -1 if the field is not initialized at creation time
+  /// for that class.
+  int getFieldIndex(ClassElement classElement, FieldElement field) {
+    // There is no stored map from a field to its index in a given class, so we
+    // have to iterate over all instance fields until we find it.
+    int current = -1, index = -1;
+    classElement.forEachInstanceField((host, currentField) {
+      if (!backend.isNativeOrExtendsNative(host)) {
+        ++current;
+        if (currentField == field) {
+          index = current;
+        }
+      }
+    }, includeSuperAndInjectedMembers: true);
+    return index;
+  }
+
+  void removeBinding(Primitive prim) {
+    LetPrim node = prim.parent;
+    node.remove();
+  }
+}
+
+class EscapeVisitor extends DeepRecursiveVisitor {
+  final UseFieldInitializers main;
+  EscapeVisitor(this.main);
+
+  processReference(Reference ref) {
+    main.escape(ref);
+  }
+}
diff --git a/pkg/compiler/lib/src/diagnostics/dart2js_messages.dart b/pkg/compiler/lib/src/diagnostics/dart2js_messages.dart
deleted file mode 100644
index 90d4ecf..0000000
--- a/pkg/compiler/lib/src/diagnostics/dart2js_messages.dart
+++ /dev/null
@@ -1,3732 +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.
-
-// The messages in this file should meet the following guide lines:
-//
-// 1. The message should be a complete sentence starting with an uppercase
-// letter, and ending with a period.
-//
-// 2. Reserved words and embedded identifiers should be in single quotes, so
-// prefer double quotes for the complete message. For example, "The
-// class '#{className}' can't use 'super'." Notice that the word 'class' in the
-// preceding message is not quoted as it refers to the concept 'class', not the
-// reserved word. On the other hand, 'super' refers to the reserved word. Do
-// not quote 'null' and numeric literals.
-//
-// 3. Do not try to compose messages, as it can make translating them hard.
-//
-// 4. Try to keep the error messages short, but informative.
-//
-// 5. Use simple words and terminology, assume the reader of the message
-// doesn't have an advanced degree in math, and that English is not the
-// reader's native language. Do not assume any formal computer science
-// training. For example, do not use Latin abbreviations (prefer "that is" over
-// "i.e.", and "for example" over "e.g."). Also avoid phrases such as "if and
-// only if" and "iff", that level of precision is unnecessary.
-//
-// 6. Prefer contractions when they are in common use, for example, prefer
-// "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is
-// off-putting to people new to programming.
-//
-// 7. Use common terminology, preferably from the Dart Language
-// Specification. This increases the user's chance of finding a good
-// explanation on the web.
-//
-// 8. Do not try to be cute or funny. It is extremely frustrating to work on a
-// product that crashes with a "tongue-in-cheek" message, especially if you did
-// not want to use this product to begin with.
-//
-// 9. Do not lie, that is, do not write error messages containing phrases like
-// "can't happen".  If the user ever saw this message, it would be a
-// lie. Prefer messages like: "Internal error: This function should not be
-// called when 'x' is null.".
-//
-// 10. Prefer to not use imperative tone. That is, the message should not sound
-// accusing or like it is ordering the user around. The computer should
-// describe the problem, not criticize for violating the specification.
-//
-// Other things to keep in mind:
-//
-// An INFO message should always be preceded by a non-INFO message, and the
-// INFO messages are additional details about the preceding non-INFO
-// message. For example, consider duplicated elements. First report a WARNING
-// or ERROR about the duplicated element, and then report an INFO about the
-// location of the existing element.
-//
-// Generally, we want to provide messages that consists of three sentences:
-// 1. what is wrong, 2. why is it wrong, 3. how do I fix it. However, we
-// combine the first two in [template] and the last in [howToFix].
-
-/// Padding used before and between import chains in the message for
-/// [MessageKind.IMPORT_EXPERIMENTAL_MIRRORS].
-const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n*   ';
-
-/// Padding used before and between import chains in the message for
-/// [MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND].
-const String MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING = '\n   ';
-
-/// Padding used before and between import chains in the message for
-/// [MessageKind.DISALLOWED_LIBRARY_IMPORT].
-const String DISALLOWED_LIBRARY_IMPORT_PADDING = '\n  ';
-
-const DONT_KNOW_HOW_TO_FIX = "Computer says no!";
-
-final Map<String, Map> MESSAGES = {
-  /// Do not use this. It is here for legacy and debugging. It violates item
-  /// 4 of the guide lines for error messages in the beginning of the file.
-  'GENERIC': {'id': 'SOWPSL', 'template': "#{text}",},
-
-  'NOT_ASSIGNABLE': {
-    'id': 'VYNMAP',
-    'template': "'#{fromType}' is not assignable to '#{toType}'.",
-  },
-
-  'FORIN_NOT_ASSIGNABLE': {
-    'id': 'XQSRXO',
-    'template': "The element type '#{currentType}' of '#{expressionType}' "
-        "is not assignable to '#{elementType}'.",
-  },
-
-  'VOID_EXPRESSION': {
-    'id': 'QHEVSC',
-    'template': "Expression does not yield a value.",
-  },
-
-  'VOID_VARIABLE': {
-    'id': 'RFEURK',
-    'template': "Variable cannot be of type void.",
-  },
-
-  'RETURN_VALUE_IN_VOID': {
-    'id': 'FUNYDS',
-    'template': "Cannot return value from void function.",
-  },
-
-  'RETURN_NOTHING': {
-    'id': 'HPPODJ',
-    'template': "Value of type '#{returnType}' expected.",
-  },
-
-  'MISSING_ARGUMENT': {
-    'id': 'LHMCIK',
-    'template': "Missing argument of type '#{argumentType}'.",
-  },
-
-  'ADDITIONAL_ARGUMENT': {'id': 'GMITMA', 'template': "Additional argument.",},
-
-  'NAMED_ARGUMENT_NOT_FOUND': {
-    'id': 'UCEARQ',
-    'template': "No named argument '#{argumentName}' found on method.",
-  },
-
-  'MEMBER_NOT_FOUND': {
-    'id': 'MMQODC',
-    'template': "No member named '#{memberName}' in class '#{className}'.",
-  },
-
-  'AWAIT_MEMBER_NOT_FOUND': {
-    'id': 'XIDLIP',
-    'template': "No member named 'await' in class '#{className}'.",
-    'howToFix': "Did you mean to add the 'async' marker "
-        "to '#{functionName}'?",
-    'examples': [
-      """
-class A {
-m() => await -3;
-}
-main() => new A().m();
-"""
-    ],
-  },
-
-  'AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE': {
-    'id': 'HBIYGN',
-    'template': "No member named 'await' in class '#{className}'.",
-    'howToFix': "Did you mean to add the 'async' marker "
-        "to the enclosing function?",
-    'examples': [
-      """
-class A {
-m() => () => await -3;
-}
-main() => new A().m();
-"""
-    ],
-  },
-
-  'METHOD_NOT_FOUND': {
-    'id': 'QYYHBU',
-    'template': "No method named '#{memberName}' in class '#{className}'.",
-  },
-
-  'OPERATOR_NOT_FOUND': {
-    'id': 'SXGOYS',
-    'template': "No operator '#{memberName}' in class '#{className}'.",
-  },
-
-  'SETTER_NOT_FOUND': {
-    'id': 'ADFRVF',
-    'template': "No setter named '#{memberName}' in class '#{className}'.",
-  },
-
-  'SETTER_NOT_FOUND_IN_SUPER': {
-    'id': 'OCVRNJ',
-    'template': "No setter named '#{name}' in superclass of '#{className}'.",
-  },
-
-  'GETTER_NOT_FOUND': {
-    'id': 'PBNXAC',
-    'template': "No getter named '#{memberName}' in class '#{className}'.",
-  },
-
-  'NOT_CALLABLE': {
-    'id': 'SEMKJO',
-    'template': "'#{elementName}' is not callable.",
-  },
-
-  'MEMBER_NOT_STATIC': {
-    'id': 'QIOISX',
-    'template': "'#{className}.#{memberName}' is not static.",
-  },
-
-  'NO_INSTANCE_AVAILABLE': {
-    'id': 'FQPYLR',
-    'template': "'#{name}' is only available in instance methods.",
-  },
-
-  'NO_THIS_AVAILABLE': {
-    'id': 'LXPXKG',
-    'template': "'this' is only available in instance methods.",
-  },
-
-  'PRIVATE_ACCESS': {
-    'id': 'DIMHCR',
-    'template': "'#{name}' is declared private within library "
-        "'#{libraryName}'.",
-  },
-
-  'THIS_IS_THE_DECLARATION': {
-    'id': 'YIJWTO',
-    'template': "This is the declaration of '#{name}'.",
-  },
-
-  'THIS_IS_THE_METHOD': {
-    'id': 'PYXWLF',
-    'template': "This is the method declaration.",
-  },
-
-  'CANNOT_RESOLVE': {'id': 'SPVJYO', 'template': "Cannot resolve '#{name}'.",},
-
-  'CANNOT_RESOLVE_AWAIT': {
-    'id': 'YQYLRS',
-    'template': "Cannot resolve '#{name}'.",
-    'howToFix': "Did you mean to add the 'async' marker "
-        "to '#{functionName}'?",
-    'examples': ["main() => await -3;", "foo() => await -3; main() => foo();"],
-  },
-
-  'CANNOT_RESOLVE_AWAIT_IN_CLOSURE': {
-    'id': 'SIXRAA',
-    'template': "Cannot resolve '#{name}'.",
-    'howToFix': "Did you mean to add the 'async' marker "
-        "to the enclosing function?",
-    'examples': ["main() { (() => await -3)(); }",],
-  },
-
-  'CANNOT_RESOLVE_IN_INITIALIZER': {
-    'id': 'VVEQFD',
-    'template':
-        "Cannot resolve '#{name}'. It would be implicitly looked up on this "
-        "instance, but instances are not available in initializers.",
-    'howToFix': "Try correcting the unresolved reference or move the "
-        "initialization to a constructor body.",
-    'examples': [
-      """
-class A {
-var test = unresolvedName;
-}
-main() => new A();
-"""
-    ],
-  },
-
-  'CANNOT_RESOLVE_CONSTRUCTOR': {
-    'id': 'QRPATN',
-    'template': "Cannot resolve constructor '#{constructorName}'.",
-  },
-
-  'CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT': {
-    'id': 'IFKCHF',
-    'template': "cannot resolve constructor '#{constructorName}' "
-        "for implicit super call.",
-    'howToFix': "Try explicitly invoking a constructor of the super class",
-    'examples': [
-      """
-class A {
-A.foo() {}
-}
-class B extends A {
-B();
-}
-main() => new B();
-"""
-    ],
-  },
-
-  'INVALID_UNNAMED_CONSTRUCTOR_NAME': {
-    'id': 'VPJLVI',
-    'template': "Unnamed constructor name must be '#{name}'.",
-  },
-
-  'INVALID_CONSTRUCTOR_NAME': {
-    'id': 'LMDCAS',
-    'template': "Constructor name must start with '#{name}'.",
-  },
-
-  'CANNOT_RESOLVE_TYPE': {
-    'id': 'PQIAPG',
-    'template': "Cannot resolve type '#{typeName}'.",
-  },
-
-  'DUPLICATE_DEFINITION': {
-    'id': 'LVTYNW',
-    'template': "Duplicate definition of '#{name}'.",
-    'howToFix': "Try to rename or remove this definition.",
-    'examples': [
-      """
-class C {
-void f() {}
-int get f => 1;
-}
-
-main() {
-new C();
-}
-
-"""
-    ],
-  },
-
-  'EXISTING_DEFINITION': {
-    'id': 'DAUYKK',
-    'template': "Existing definition of '#{name}'.",
-  },
-
-  'DUPLICATE_IMPORT': {
-    'id': 'KYJFJN',
-    'template': "Duplicate import of '#{name}'.",
-  },
-
-  'HIDDEN_IMPORT': {
-    'id': 'ACRDPR',
-    'template': "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
-        "from library '#{hidingUri}'.",
-    'howToFix': "Try adding 'hide #{name}' to the import of '#{hiddenUri}'.",
-    'examples': [
-      {
-        'main.dart': """
-import 'dart:async'; // This imports a class Future.
-import 'future.dart';
-
-void main() => new Future();""",
-        'future.dart': """
-library future;
-
-class Future {}"""
-      },
-      {
-        'main.dart': """
-import 'future.dart';
-import 'dart:async'; // This imports a class Future.
-
-void main() => new Future();""",
-        'future.dart': """
-library future;
-
-class Future {}"""
-      },
-      {
-        'main.dart': """
-import 'export.dart';
-import 'dart:async'; // This imports a class Future.
-
-void main() => new Future();""",
-        'future.dart': """
-library future;
-
-class Future {}""",
-        'export.dart': """
-library export;
-
-export 'future.dart';"""
-      },
-      {
-        'main.dart': """
-import 'future.dart' as prefix;
-import 'dart:async' as prefix; // This imports a class Future.
-
-void main() => new prefix.Future();""",
-        'future.dart': """
-library future;
-
-class Future {}"""
-      }
-    ],
-  },
-
-  'HIDDEN_IMPLICIT_IMPORT': {
-    'id': 'WDNFSI',
-    'template': "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
-        "from library '#{hidingUri}'.",
-    'howToFix': "Try adding an explicit "
-        "'import \"#{hiddenUri}\" hide #{name}'.",
-    'examples': [
-      {
-        'main.dart': """
-// This hides the implicit import of class Type from dart:core.
-import 'type.dart';
-
-void main() => new Type();""",
-        'type.dart': """
-library type;
-
-class Type {}"""
-      },
-      {
-        'conflictsWithDart.dart': """
-library conflictsWithDart;
-
-class Duration {
-static var x = 100;
-}
-""",
-        'conflictsWithDartAsWell.dart': """
-library conflictsWithDartAsWell;
-
-class Duration {
-static var x = 100;
-}
-""",
-        'main.dart': r"""
-library testDartConflicts;
-
-import 'conflictsWithDart.dart';
-import 'conflictsWithDartAsWell.dart';
-
-main() {
-print("Hail Caesar ${Duration.x}");
-}
-"""
-      }
-    ],
-  },
-
-  'DUPLICATE_EXPORT': {
-    'id': 'XGNOCL',
-    'template': "Duplicate export of '#{name}'.",
-    'howToFix': "Try adding 'hide #{name}' to one of the exports.",
-    'examples': [
-      {
-        'main.dart': """
-export 'decl1.dart';
-export 'decl2.dart';
-
-main() {}""",
-        'decl1.dart': "class Class {}",
-        'decl2.dart': "class Class {}"
-      }
-    ],
-  },
-
-  'DUPLICATE_EXPORT_CONT': {
-    'id': 'BDROED',
-    'template': "This is another export of '#{name}'.",
-  },
-
-  'DUPLICATE_EXPORT_DECL': {
-    'id': 'GFFLMA',
-    'template':
-        "The exported '#{name}' from export #{uriString} is defined here.",
-  },
-
-  'EMPTY_HIDE': {
-    'id': 'ODFAOC',
-    'template': "Library '#{uri}' doesn't export a '#{name}' declaration.",
-    'howToFix': "Try removing '#{name}' the 'hide' clause.",
-    'examples': [
-      {
-        'main.dart': """
-import 'dart:core' hide Foo;
-
-main() {}"""
-      },
-      {
-        'main.dart': """
-export 'dart:core' hide Foo;
-
-main() {}"""
-      },
-    ],
-  },
-
-  'EMPTY_SHOW': {
-    'id': 'EXONIK',
-    'template': "Library '#{uri}' doesn't export a '#{name}' declaration.",
-    'howToFix': "Try removing '#{name}' from the 'show' clause.",
-    'examples': [
-      {
-        'main.dart': """
-import 'dart:core' show Foo;
-
-main() {}"""
-      },
-      {
-        'main.dart': """
-export 'dart:core' show Foo;
-
-main() {}"""
-      },
-    ],
-  },
-
-  'NOT_A_TYPE': {'id': 'CTTAXD', 'template': "'#{node}' is not a type.",},
-
-  'NOT_A_PREFIX': {'id': 'LKEUMI', 'template': "'#{node}' is not a prefix.",},
-
-  'PREFIX_AS_EXPRESSION': {
-    'id': 'CYIMBJ',
-    'template': "Library prefix '#{prefix}' is not a valid expression.",
-  },
-
-  'CANNOT_FIND_CONSTRUCTOR': {
-    'id': 'DROVNH',
-    'template': "Cannot find constructor '#{constructorName}' in class "
-        "'#{className}'.",
-  },
-
-  'CANNOT_FIND_UNNAMED_CONSTRUCTOR': {
-    'id': 'GDCTGB',
-    'template': "Cannot find unnamed constructor in class "
-        "'#{className}'.",
-  },
-
-  'CYCLIC_CLASS_HIERARCHY': {
-    'id': 'HKFYOA',
-    'template': "'#{className}' creates a cycle in the class hierarchy.",
-  },
-
-  'CYCLIC_REDIRECTING_FACTORY': {
-    'id': 'QGETJC',
-    'template': "Redirecting factory leads to a cyclic redirection.",
-  },
-
-  'INVALID_RECEIVER_IN_INITIALIZER': {
-    'id': 'SYUTHA',
-    'template': "Field initializer expected.",
-  },
-
-  'NO_SUPER_IN_STATIC': {
-    'id': 'HSCESG',
-    'template': "'super' is only available in instance methods.",
-  },
-
-  'DUPLICATE_INITIALIZER': {
-    'id': 'GKVFEP',
-    'template': "Field '#{fieldName}' is initialized more than once.",
-  },
-
-  'ALREADY_INITIALIZED': {
-    'id': 'NCRMVD',
-    'template': "'#{fieldName}' was already initialized here.",
-  },
-
-  'INIT_STATIC_FIELD': {
-    'id': 'DBSRHA',
-    'template': "Cannot initialize static field '#{fieldName}'.",
-  },
-
-  'NOT_A_FIELD': {
-    'id': 'FYEPLC',
-    'template': "'#{fieldName}' is not a field.",
-  },
-
-  'CONSTRUCTOR_CALL_EXPECTED': {
-    'id': 'GEJCDX',
-    'template': "only call to 'this' or 'super' constructor allowed.",
-  },
-
-  'INVALID_FOR_IN': {
-    'id': 'AUQJBG',
-    'template': "Invalid for-in variable declaration.",
-  },
-
-  'INVALID_INITIALIZER': {'id': 'JKUKSA', 'template': "Invalid initializer.",},
-
-  'FUNCTION_WITH_INITIALIZER': {
-    'id': 'BNRDDK',
-    'template': "Only constructors can have initializers.",
-  },
-
-  'REDIRECTING_CONSTRUCTOR_CYCLE': {
-    'id': 'CQTMEP',
-    'template': "Cyclic constructor redirection.",
-  },
-
-  'REDIRECTING_CONSTRUCTOR_HAS_BODY': {
-    'id': 'WXJQNE',
-    'template': "Redirecting constructor can't have a body.",
-  },
-
-  'CONST_CONSTRUCTOR_HAS_BODY': {
-    'id': 'GNEFQG',
-    'template': "Const constructor or factory can't have a body.",
-    'howToFix': "Remove the 'const' keyword or the body",
-    'examples': [
-      """
-class C {
-const C() {}
-}
-
-main() => new C();"""
-    ],
-  },
-
-  'REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER': {
-    'id': 'NUIDSF',
-    'template': "Redirecting constructor cannot have other initializers.",
-  },
-
-  'SUPER_INITIALIZER_IN_OBJECT': {
-    'id': 'DXYGND',
-    'template': "'Object' cannot have a super initializer.",
-  },
-
-  'DUPLICATE_SUPER_INITIALIZER': {
-    'id': 'FFKOWP',
-    'template': "Cannot have more than one super initializer.",
-  },
-
-  'SUPER_CALL_TO_FACTORY': {
-    'id': 'YTOWGV',
-    'template': "The target of the superinitializer must be a generative "
-        "constructor.",
-    'howToFix': "Try calling another constructor on the superclass.",
-    'examples': [
-      """
-class Super {
-factory Super() => null;
-}
-class Class extends Super {}
-main() => new Class();
-""",
-      """
-class Super {
-factory Super() => null;
-}
-class Class extends Super {
-Class();
-}
-main() => new Class();
-""",
-      """
-class Super {
-factory Super() => null;
-}
-class Class extends Super {
-Class() : super();
-}
-main() => new Class();
-""",
-      """
-class Super {
-factory Super.foo() => null;
-}
-class Class extends Super {
-Class() : super.foo();
-}
-main() => new Class();
-"""
-    ],
-  },
-
-  'THIS_CALL_TO_FACTORY': {
-    'id': 'JLATDB',
-    'template': "The target of the redirection clause must be a generative "
-        "constructor",
-    'howToFix': "Try redirecting to another constructor.",
-    'examples': [
-      """
-class Class {
-factory Class() => null;
-Class.foo() : this();
-}
-main() => new Class.foo();
-""",
-      """
-class Class {
-factory Class.foo() => null;
-Class() : this.foo();
-}
-main() => new Class();
-"""
-    ],
-  },
-
-  'INVALID_CONSTRUCTOR_ARGUMENTS': {
-    'id': 'WVPLKL',
-    'template': "Arguments do not match the expected parameters of constructor "
-        "'#{constructorName}'.",
-  },
-
-  'NO_MATCHING_CONSTRUCTOR': {
-    'id': 'OJQQLE',
-    'template':
-        "'super' call arguments and constructor parameters do not match.",
-  },
-
-  'NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT': {
-    'id': 'WHCVID',
-    'template': "Implicit 'super' call arguments and constructor parameters "
-        "do not match.",
-  },
-
-  'CONST_CALLS_NON_CONST': {
-    'id': 'CQFHXC',
-    'template': "'const' constructor cannot call a non-const constructor.",
-  },
-
-  'CONST_CALLS_NON_CONST_FOR_IMPLICIT': {
-    'id': 'SFCEXS',
-    'template': "'const' constructor cannot call a non-const constructor. "
-        "This constructor has an implicit call to a "
-        "super non-const constructor.",
-    'howToFix': "Try making the super constructor const.",
-    'examples': [
-      """
-class C {
-C(); // missing const
-}
-class D extends C {
-final d;
-const D(this.d);
-}
-main() => new D(0);"""
-    ],
-  },
-
-  'CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS': {
-    'id': 'XBHUDL',
-    'template': "Can't declare constructor 'const' on class #{className} "
-        "because the class contains non-final instance fields.",
-    'howToFix': "Try making all fields final.",
-    'examples': [
-      """
-class C {
-// 'a' must be declared final to allow for the const constructor.
-var a;
-const C(this.a);
-}
-
-main() => new C(0);"""
-    ],
-  },
-
-  'CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD': {
-    'id': 'YYAHVD',
-    'template': "This non-final field prevents using const constructors.",
-  },
-
-  'CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR': {
-    'id': 'FROWJB',
-    'template': "This const constructor is not allowed due to "
-        "non-final fields.",
-  },
-
-  'INITIALIZING_FORMAL_NOT_ALLOWED': {
-    'id': 'YIPXYP',
-    'template': "Initializing formal parameter only allowed in generative "
-        "constructor.",
-  },
-
-  'INVALID_PARAMETER': {
-    'id': 'OWWLIX',
-    'template': "Cannot resolve parameter.",
-  },
-
-  'NOT_INSTANCE_FIELD': {
-    'id': 'VSPKMU',
-    'template': "'#{fieldName}' is not an instance field.",
-  },
-
-  'THIS_PROPERTY': {'id': 'MWFIGH', 'template': "Expected an identifier.",},
-
-  'NO_CATCH_NOR_FINALLY': {
-    'id': 'OPJXPP',
-    'template': "Expected 'catch' or 'finally'.",
-  },
-
-  'EMPTY_CATCH_DECLARATION': {
-    'id': 'UNHCPY',
-    'template': "Expected an identifier in catch declaration.",
-  },
-
-  'EXTRA_CATCH_DECLARATION': {
-    'id': 'YGGRAK',
-    'template': "Extra parameter in catch declaration.",
-  },
-
-  'PARAMETER_WITH_TYPE_IN_CATCH': {
-    'id': 'EXQVDU',
-    'template': "Cannot use type annotations in catch.",
-  },
-
-  'PARAMETER_WITH_MODIFIER_IN_CATCH': {
-    'id': 'BQLKRF',
-    'template': "Cannot use modifiers in catch.",
-  },
-
-  'OPTIONAL_PARAMETER_IN_CATCH': {
-    'id': 'DAICPP',
-    'template': "Cannot use optional parameters in catch.",
-  },
-
-  'THROW_WITHOUT_EXPRESSION': {
-    'id': 'YHACYV',
-    'template': "Cannot use re-throw outside of catch block "
-        "(expression expected after 'throw').",
-  },
-
-  'UNBOUND_LABEL': {
-    'id': 'GLDXHY',
-    'template': "Cannot resolve label '#{labelName}'.",
-  },
-
-  'NO_BREAK_TARGET': {
-    'id': 'VBXXBE',
-    'template': "'break' statement not inside switch or loop.",
-  },
-
-  'NO_CONTINUE_TARGET': {
-    'id': 'JTTHHM',
-    'template': "'continue' statement not inside loop.",
-  },
-
-  'EXISTING_LABEL': {
-    'id': 'AHCSXF',
-    'template': "Original declaration of duplicate label '#{labelName}'.",
-  },
-
-  'DUPLICATE_LABEL': {
-    'id': 'HPULLI',
-    'template': "Duplicate declaration of label '#{labelName}'.",
-  },
-
-  'UNUSED_LABEL': {'id': 'KFREJO', 'template': "Unused label '#{labelName}'.",},
-
-  'INVALID_CONTINUE': {
-    'id': 'DSKTPX',
-    'template': "Target of continue is not a loop or switch case.",
-  },
-
-  'INVALID_BREAK': {
-    'id': 'MFCCWX',
-    'template': "Target of break is not a statement.",
-  },
-
-  'DUPLICATE_TYPE_VARIABLE_NAME': {
-    'id': 'BAYCCM',
-    'template': "Type variable '#{typeVariableName}' already declared.",
-  },
-
-  'TYPE_VARIABLE_WITHIN_STATIC_MEMBER': {
-    'id': 'XQLXRL',
-    'template': "Cannot refer to type variable '#{typeVariableName}' "
-        "within a static member.",
-  },
-
-  'TYPE_VARIABLE_IN_CONSTANT': {
-    'id': 'ANDEVG',
-    'template': "Constant expressions can't refer to type variables.",
-    'howToFix': "Try removing the type variable or replacing it with a "
-        "concrete type.",
-    'examples': [
-      """
-class C<T> {
-const C();
-
-m(T t) => const C<T>();
-}
-
-void main() => new C().m(null);
-"""
-    ],
-  },
-
-  'INVALID_TYPE_VARIABLE_BOUND': {
-    'id': 'WQAEDK',
-    'template': "'#{typeArgument}' is not a subtype of bound '#{bound}' for "
-        "type variable '#{typeVariable}' of type '#{thisType}'.",
-    'howToFix': "Try to change or remove the type argument.",
-    'examples': [
-      """
-class C<T extends num> {}
-
-// 'String' is not a valid instantiation of T with bound num.'.
-main() => new C<String>();
-"""
-    ],
-  },
-
-  'INVALID_USE_OF_SUPER': {
-    'id': 'JKYYSN',
-    'template': "'super' not allowed here.",
-  },
-
-  'INVALID_CASE_DEFAULT': {
-    'id': 'ABSPBM',
-    'template': "'default' only allowed on last case of a switch.",
-  },
-
-  'SWITCH_CASE_TYPES_NOT_EQUAL': {
-    'id': 'UFQPBC',
-    'template': "'case' expressions do not all have type '#{type}'.",
-  },
-
-  'SWITCH_CASE_TYPES_NOT_EQUAL_CASE': {
-    'id': 'RDMVAC',
-    'template': "'case' expression of type '#{type}'.",
-  },
-
-  'SWITCH_CASE_FORBIDDEN': {
-    'id': 'UHSCSU',
-    'template': "'case' expression may not be of type '#{type}'.",
-  },
-
-  'SWITCH_CASE_VALUE_OVERRIDES_EQUALS': {
-    'id': 'NRTWXL',
-    'template': "'case' expression type '#{type}' overrides 'operator =='.",
-  },
-
-  'INVALID_ARGUMENT_AFTER_NAMED': {
-    'id': 'WAJURC',
-    'template': "Unnamed argument after named argument.",
-  },
-
-  'NOT_A_COMPILE_TIME_CONSTANT': {
-    'id': 'SBCHWL',
-    'template': "Not a compile-time constant.",
-  },
-
-  'DEFERRED_COMPILE_TIME_CONSTANT': {
-    'id': 'FHXTCK',
-    'template': "A deferred value cannot be used as a compile-time constant.",
-  },
-
-  'DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION': {
-    'id': 'TSBXLG',
-    'template': "A deferred class cannot be used to create a "
-        "compile-time constant.",
-  },
-
-  'CYCLIC_COMPILE_TIME_CONSTANTS': {
-    'id': 'JJWJYE',
-    'template': "Cycle in the compile-time constant computation.",
-  },
-
-  'CONSTRUCTOR_IS_NOT_CONST': {
-    'id': 'DOJCUX',
-    'template': "Constructor is not a 'const' constructor.",
-  },
-
-  'CONST_MAP_KEY_OVERRIDES_EQUALS': {
-    'id': 'VJNWEL',
-    'template': "Const-map key type '#{type}' overrides 'operator =='.",
-  },
-
-  'NO_SUCH_LIBRARY_MEMBER': {
-    'id': 'IOXVBA',
-    'template': "'#{libraryName}' has no member named '#{memberName}'.",
-  },
-
-  'CANNOT_INSTANTIATE_TYPEDEF': {
-    'id': 'KOYNMU',
-    'template': "Cannot instantiate typedef '#{typedefName}'.",
-  },
-
-  'REQUIRED_PARAMETER_WITH_DEFAULT': {
-    'id': 'CJWECI',
-    'template': "Non-optional parameters can't have a default value.",
-    'howToFix':
-        "Try removing the default value or making the parameter optional.",
-    'examples': [
-      """
-main() {
-foo(a: 1) => print(a);
-foo(2);
-}""",
-      """
-main() {
-foo(a = 1) => print(a);
-foo(2);
-}"""
-    ],
-  },
-
-  'NAMED_PARAMETER_WITH_EQUALS': {
-    'id': 'RPJDXD',
-    'template': "Named optional parameters can't use '=' to specify a default "
-        "value.",
-    'howToFix': "Try replacing '=' with ':'.",
-    'examples': [
-      """
-main() {
-foo({a = 1}) => print(a);
-foo(a: 2);
-}"""
-    ],
-  },
-
-  'POSITIONAL_PARAMETER_WITH_EQUALS': {
-    'id': 'JMSSDX',
-    'template': "Positional optional parameters can't use ':' to specify a "
-        "default value.",
-    'howToFix': "Try replacing ':' with '='.",
-    'examples': [
-      """
-main() {
-foo([a: 1]) => print(a);
-foo(2);
-}"""
-    ],
-  },
-
-  'TYPEDEF_FORMAL_WITH_DEFAULT': {
-    'id': 'NABHHS',
-    'template': "A parameter of a typedef can't specify a default value.",
-    'howToFix': "Try removing the default value.",
-    'examples': [
-      """
-typedef void F([int arg = 0]);
-
-main() {
-F f;
-}""",
-      """
-typedef void F({int arg: 0});
-
-main() {
-F f;
-}"""
-    ],
-  },
-
-  'FUNCTION_TYPE_FORMAL_WITH_DEFAULT': {
-    'id': 'APKYLU',
-    'template': "A function type parameter can't specify a default value.",
-    'howToFix': "Try removing the default value.",
-    'examples': [
-      """
-foo(f(int i, [a = 1])) {}
-
-main() {
-foo(1, 2);
-}""",
-      """
-foo(f(int i, {a: 1})) {}
-
-main() {
-foo(1, a: 2);
-}"""
-    ],
-  },
-
-  'REDIRECTING_FACTORY_WITH_DEFAULT': {
-    'id': 'AWSSEY',
-    'template':
-        "A parameter of a redirecting factory constructor can't specify a "
-        "default value.",
-    'howToFix': "Try removing the default value.",
-    'examples': [
-      """
-class A {
-A([a]);
-factory A.foo([a = 1]) = A;
-}
-
-main() {
-new A.foo(1);
-}""",
-      """
-class A {
-A({a});
-factory A.foo({a: 1}) = A;
-}
-
-main() {
-new A.foo(a: 1);
-}"""
-    ],
-  },
-
-  'FORMAL_DECLARED_CONST': {
-    'id': 'AVPRDK',
-    'template': "A formal parameter can't be declared const.",
-    'howToFix': "Try removing 'const'.",
-    'examples': [
-      """
-foo(const x) {}
-main() => foo(42);
-""",
-      """
-foo({const x}) {}
-main() => foo(42);
-""",
-      """
-foo([const x]) {}
-main() => foo(42);
-"""
-    ],
-  },
-
-  'FORMAL_DECLARED_STATIC': {
-    'id': 'PJKDMX',
-    'template': "A formal parameter can't be declared static.",
-    'howToFix': "Try removing 'static'.",
-    'examples': [
-      """
-foo(static x) {}
-main() => foo(42);
-""",
-      """
-foo({static x}) {}
-main() => foo(42);
-""",
-      """
-foo([static x]) {}
-main() => foo(42);
-"""
-    ],
-  },
-
-  'FINAL_FUNCTION_TYPE_PARAMETER': {
-    'id': 'JIOPIQ',
-    'template': "A function type parameter can't be declared final.",
-    'howToFix': "Try removing 'final'.",
-    'examples': [
-      """
-foo(final int x(int a)) {}
-main() => foo((y) => 42);
-""",
-      """
-foo({final int x(int a)}) {}
-main() => foo((y) => 42);
-""",
-      """
-foo([final int x(int a)]) {}
-main() => foo((y) => 42);
-"""
-    ],
-  },
-
-  'VAR_FUNCTION_TYPE_PARAMETER': {
-    'id': 'FOQOHK',
-    'template': "A function type parameter can't be declared with 'var'.",
-    'howToFix': "Try removing 'var'.",
-    'examples': [
-      """
-foo(var int x(int a)) {}
-main() => foo((y) => 42);
-""",
-      """
-foo({var int x(int a)}) {}
-main() => foo((y) => 42);
-""",
-      """
-foo([var int x(int a)]) {}
-main() => foo((y) => 42);
-"""
-    ],
-  },
-
-  'CANNOT_INSTANTIATE_TYPE_VARIABLE': {
-    'id': 'JAYHCH',
-    'template': "Cannot instantiate type variable '#{typeVariableName}'.",
-  },
-
-  'CYCLIC_TYPE_VARIABLE': {
-    'id': 'RQMPSO',
-    'template': "Type variable '#{typeVariableName}' is a supertype of itself.",
-  },
-
-  'CYCLIC_TYPEDEF': {
-    'id': 'VFERCQ',
-    'template': "A typedef can't refer to itself.",
-    'howToFix': "Try removing all references to '#{typedefName}' "
-        "in the definition of '#{typedefName}'.",
-    'examples': [
-      """
-typedef F F(); // The return type 'F' is a self-reference.
-main() { F f = null; }"""
-    ],
-  },
-
-  'CYCLIC_TYPEDEF_ONE': {
-    'id': 'ASWLWR',
-    'template': "A typedef can't refer to itself through another typedef.",
-    'howToFix': "Try removing all references to "
-        "'#{otherTypedefName}' in the definition of '#{typedefName}'.",
-    'examples': [
-      """
-typedef G F(); // The return type 'G' is a self-reference through typedef 'G'.
-typedef F G(); // The return type 'F' is a self-reference through typedef 'F'.
-main() { F f = null; }""",
-      """
-typedef G F(); // The return type 'G' creates a self-reference.
-typedef H G(); // The return type 'H' creates a self-reference.
-typedef H(F f); // The argument type 'F' creates a self-reference.
-main() { F f = null; }"""
-    ],
-  },
-
-  'CLASS_NAME_EXPECTED': {'id': 'DPKNHY', 'template': "Class name expected.",},
-
-  'CANNOT_EXTEND': {
-    'id': 'GCIQXD',
-    'template': "'#{type}' cannot be extended.",
-  },
-
-  'CANNOT_IMPLEMENT': {
-    'id': 'IBOQKV',
-    'template': "'#{type}' cannot be implemented.",
-  },
-
-  // TODO(johnnwinther): Split messages into reasons for malformedness.
-  'CANNOT_EXTEND_MALFORMED': {
-    'id': 'YPFJBD',
-    'template': "Class '#{className}' can't extend the type '#{malformedType}' "
-        "because it is malformed.",
-    'howToFix': "Try correcting the malformed type annotation or removing the "
-        "'extends' clause.",
-    'examples': [
-      """
-class A extends Malformed {}
-main() => new A();"""
-    ],
-  },
-
-  'CANNOT_IMPLEMENT_MALFORMED': {
-    'id': 'XJUIAQ',
-    'template':
-        "Class '#{className}' can't implement the type '#{malformedType}' "
-        "because it is malformed.",
-    'howToFix': "Try correcting the malformed type annotation or removing the "
-        "type from the 'implements' clause.",
-    'examples': [
-      """
-class A implements Malformed {}
-main() => new A();"""
-    ],
-  },
-
-  'CANNOT_MIXIN_MALFORMED': {
-    'id': 'SSMNXN',
-    'template': "Class '#{className}' can't mixin the type '#{malformedType}' "
-        "because it is malformed.",
-    'howToFix': "Try correcting the malformed type annotation or removing the "
-        "type from the 'with' clause.",
-    'examples': [
-      """
-class A extends Object with Malformed {}
-main() => new A();"""
-    ],
-  },
-
-  'CANNOT_MIXIN': {
-    'id': 'KLSXDQ',
-    'template': "The type '#{type}' can't be mixed in.",
-    'howToFix': "Try removing '#{type}' from the 'with' clause.",
-    'examples': [
-      """
-class C extends Object with String {}
-
-main() => new C();
-""",
-      """
-typedef C = Object with String;
-
-main() => new C();
-"""
-    ],
-  },
-
-  'CANNOT_EXTEND_ENUM': {
-    'id': 'JEPRST',
-    'template':
-        "Class '#{className}' can't extend the type '#{enumType}' because "
-        "it is declared by an enum.",
-    'howToFix': "Try making '#{enumType}' a normal class or removing the "
-        "'extends' clause.",
-    'examples': [
-      """
-enum Enum { A }
-class B extends Enum {}
-main() => new B();"""
-    ],
-  },
-
-  'CANNOT_IMPLEMENT_ENUM': {
-    'id': 'JMJMSH',
-    'template': "Class '#{className}' can't implement the type '#{enumType}' "
-        "because it is declared by an enum.",
-    'howToFix': "Try making '#{enumType}' a normal class or removing the "
-        "type from the 'implements' clause.",
-    'examples': [
-      """
-enum Enum { A }
-class B implements Enum {}
-main() => new B();"""
-    ],
-  },
-
-  'CANNOT_MIXIN_ENUM': {
-    'id': 'YSYDIM',
-    'template':
-        "Class '#{className}' can't mixin the type '#{enumType}' because it "
-        "is declared by an enum.",
-    'howToFix': "Try making '#{enumType}' a normal class or removing the "
-        "type from the 'with' clause.",
-    'examples': [
-      """
-enum Enum { A }
-class B extends Object with Enum {}
-main() => new B();"""
-    ],
-  },
-
-  'CANNOT_INSTANTIATE_ENUM': {
-    'id': 'CQYIFU',
-    'template': "Enum type '#{enumName}' cannot be instantiated.",
-    'howToFix': "Try making '#{enumType}' a normal class or use an enum "
-        "constant.",
-    'examples': [
-      """
-enum Enum { A }
-main() => new Enum(0);""",
-      """
-enum Enum { A }
-main() => const Enum(0);"""
-    ],
-  },
-
-  'EMPTY_ENUM_DECLARATION': {
-    'id': 'JFPDOH',
-    'template': "Enum '#{enumName}' must contain at least one value.",
-    'howToFix': "Try adding an enum constant or making #{enumName} a "
-        "normal class.",
-    'examples': [
-      """
-enum Enum {}
-main() { Enum e; }"""
-    ],
-  },
-
-  'MISSING_ENUM_CASES': {
-    'id': 'HHEOIW',
-    'template': "Missing enum constants in switch statement: #{enumValues}.",
-    'howToFix': "Try adding the missing constants or a default case.",
-    'examples': [
-      """
-enum Enum { A, B }
-main() {
-switch (Enum.A) {
-case Enum.B: break;
-}
-}""",
-      """
-enum Enum { A, B, C }
-main() {
-switch (Enum.A) {
-case Enum.B: break;
-}
-}"""
-    ],
-  },
-
-  'DUPLICATE_EXTENDS_IMPLEMENTS': {
-    'id': 'BKRKEO',
-    'template': "'#{type}' can not be both extended and implemented.",
-  },
-
-  'DUPLICATE_IMPLEMENTS': {
-    'id': 'IWJFTU',
-    'template': "'#{type}' must not occur more than once "
-        "in the implements clause.",
-  },
-
-  'MULTI_INHERITANCE': {
-    'id': 'NWXGOI',
-    'template':
-        "Dart2js does not currently support inheritance of the same class "
-        "with different type arguments: Both #{firstType} and #{secondType} "
-        "are supertypes of #{thisType}.",
-  },
-
-  'ILLEGAL_SUPER_SEND': {
-    'id': 'LDRGIU',
-    'template': "'#{name}' cannot be called on super.",
-  },
-
-  'NO_SUCH_SUPER_MEMBER': {
-    'id': 'HIJJVG',
-    'template':
-        "Cannot resolve '#{memberName}' in a superclass of '#{className}'.",
-  },
-
-  'ADDITIONAL_TYPE_ARGUMENT': {
-    'id': 'HWYHWH',
-    'template': "Additional type argument.",
-  },
-
-  'MISSING_TYPE_ARGUMENT': {
-    'id': 'KYTQWA',
-    'template': "Missing type argument.",
-  },
-
-  // TODO(johnniwinther): Use ADDITIONAL_TYPE_ARGUMENT or
-  // MISSING_TYPE_ARGUMENT instead.
-  'TYPE_ARGUMENT_COUNT_MISMATCH': {
-    'id': 'ECXGRM',
-    'template': "Incorrect number of type arguments on '#{type}'.",
-  },
-
-  'GETTER_MISMATCH': {
-    'id': 'MNODFW',
-    'template': "Setter disagrees on: '#{modifiers}'.",
-  },
-
-  'SETTER_MISMATCH': {
-    'id': 'FMNHPL',
-    'template': "Getter disagrees on: '#{modifiers}'.",
-  },
-
-  'ILLEGAL_SETTER_FORMALS': {
-    'id': 'COTPVN',
-    'template': "A setter must have exactly one argument.",
-  },
-
-  'NO_STATIC_OVERRIDE': {
-    'id': 'EHINXB',
-    'template':
-        "Static member cannot override instance member '#{memberName}' of "
-        "'#{className}'.",
-  },
-
-  'NO_STATIC_OVERRIDE_CONT': {
-    'id': 'TEVJMA',
-    'template': "This is the instance member that cannot be overridden "
-        "by a static member.",
-  },
-
-  'INSTANCE_STATIC_SAME_NAME': {
-    'id': 'LTBFBO',
-    'template': "Instance member '#{memberName}' and static member of "
-        "superclass '#{className}' have the same name.",
-  },
-
-  'INSTANCE_STATIC_SAME_NAME_CONT': {
-    'id': 'CHSUCQ',
-    'template': "This is the static member with the same name.",
-  },
-
-  'INVALID_OVERRIDE_METHOD': {
-    'id': 'NINKPI',
-    'template': "The type '#{declaredType}' of method '#{name}' declared in "
-        "'#{class}' is not a subtype of the overridden method type "
-        "'#{inheritedType}' inherited from '#{inheritedClass}'.",
-  },
-
-  'INVALID_OVERRIDDEN_METHOD': {
-    'id': 'BQHUPY',
-    'template': "This is the overridden method '#{name}' declared in class "
-        "'#{class}'.",
-  },
-
-  'INVALID_OVERRIDE_GETTER': {
-    'id': 'KLMPWO',
-    'template': "The type '#{declaredType}' of getter '#{name}' declared in "
-        "'#{class}' is not assignable to the type '#{inheritedType}' of the "
-        "overridden getter inherited from '#{inheritedClass}'.",
-  },
-
-  'INVALID_OVERRIDDEN_GETTER': {
-    'id': 'ASSKCT',
-    'template': "This is the overridden getter '#{name}' declared in class "
-        "'#{class}'.",
-  },
-
-  'INVALID_OVERRIDE_GETTER_WITH_FIELD': {
-    'id': 'TCCGXU',
-    'template': "The type '#{declaredType}' of field '#{name}' declared in "
-        "'#{class}' is not assignable to the type '#{inheritedType}' of the "
-        "overridden getter inherited from '#{inheritedClass}'.",
-  },
-
-  'INVALID_OVERRIDE_FIELD_WITH_GETTER': {
-    'id': 'UMMEXO',
-    'template': "The type '#{declaredType}' of getter '#{name}' declared in "
-        "'#{class}' is not assignable to the type '#{inheritedType}' of the "
-        "overridden field inherited from '#{inheritedClass}'.",
-  },
-
-  'INVALID_OVERRIDE_SETTER': {
-    'id': 'BWRGEC',
-    'template': "The type '#{declaredType}' of setter '#{name}' declared in "
-        "'#{class}' is not assignable to the type '#{inheritedType}' of the "
-        "overridden setter inherited from '#{inheritedClass}'.",
-  },
-
-  'INVALID_OVERRIDDEN_SETTER': {
-    'id': 'XQUOLL',
-    'template': "This is the overridden setter '#{name}' declared in class "
-        "'#{class}'.",
-  },
-
-  'INVALID_OVERRIDE_SETTER_WITH_FIELD': {
-    'id': 'GKGOFA',
-    'template': "The type '#{declaredType}' of field '#{name}' declared in "
-        "'#{class}' is not assignable to the type '#{inheritedType}' of the "
-        "overridden setter inherited from '#{inheritedClass}'.",
-  },
-
-  'INVALID_OVERRIDE_FIELD_WITH_SETTER': {
-    'id': 'OOXKHQ',
-    'template': "The type '#{declaredType}' of setter '#{name}' declared in "
-        "'#{class}' is not assignable to the type '#{inheritedType}' of the "
-        "overridden field inherited from '#{inheritedClass}'.",
-  },
-
-  'INVALID_OVERRIDE_FIELD': {
-    'id': 'LDPKOL',
-    'template': "The type '#{declaredType}' of field '#{name}' declared in "
-        "'#{class}' is not assignable to the type '#{inheritedType}' of the "
-        "overridden field inherited from '#{inheritedClass}'.",
-  },
-
-  'INVALID_OVERRIDDEN_FIELD': {
-    'id': 'UNQFWX',
-    'template': "This is the overridden field '#{name}' declared in class "
-        "'#{class}'.",
-  },
-
-  'CANNOT_OVERRIDE_FIELD_WITH_METHOD': {
-    'id': 'SYKCSK',
-    'template': "Method '#{name}' in '#{class}' can't override field from "
-        "'#{inheritedClass}'.",
-  },
-
-  'CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT': {
-    'id': 'HYHQSO',
-    'template': "This is the field that cannot be overridden by a method.",
-  },
-
-  'CANNOT_OVERRIDE_METHOD_WITH_FIELD': {
-    'id': 'UROMAS',
-    'template': "Field '#{name}' in '#{class}' can't override method from "
-        "'#{inheritedClass}'.",
-  },
-
-  'CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT': {
-    'id': 'NSORYS',
-    'template': "This is the method that cannot be overridden by a field.",
-  },
-
-  'CANNOT_OVERRIDE_GETTER_WITH_METHOD': {
-    'id': 'MMFIOH',
-    'template': "Method '#{name}' in '#{class}' can't override getter from "
-        "'#{inheritedClass}'.",
-  },
-
-  'CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT': {
-    'id': 'YGWPDH',
-    'template': "This is the getter that cannot be overridden by a method.",
-  },
-
-  'CANNOT_OVERRIDE_METHOD_WITH_GETTER': {
-    'id': 'BNKNXO',
-    'template': "Getter '#{name}' in '#{class}' can't override method from "
-        "'#{inheritedClass}'.",
-  },
-
-  'CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT': {
-    'id': 'KFBCYX',
-    'template': "This is the method that cannot be overridden by a getter.",
-  },
-
-  'MISSING_FORMALS': {
-    'id': 'BOERAF',
-    'template': "Formal parameters are missing.",
-  },
-
-  'EXTRA_FORMALS': {
-    'id': 'UTWRIU',
-    'template': "Formal parameters are not allowed here.",
-  },
-
-  'UNARY_OPERATOR_BAD_ARITY': {
-    'id': 'TNHLAL',
-    'template': "Operator '#{operatorName}' must have no parameters.",
-  },
-
-  'MINUS_OPERATOR_BAD_ARITY': {
-    'id': 'SXDRRU',
-    'template': "Operator '-' must have 0 or 1 parameters.",
-  },
-
-  'BINARY_OPERATOR_BAD_ARITY': {
-    'id': 'QKWAUM',
-    'template': "Operator '#{operatorName}' must have exactly 1 parameter.",
-  },
-
-  'TERNARY_OPERATOR_BAD_ARITY': {
-    'id': 'LSMQGF',
-    'template': "Operator '#{operatorName}' must have exactly 2 parameters.",
-  },
-
-  'OPERATOR_OPTIONAL_PARAMETERS': {
-    'id': 'HSGRBV',
-    'template': "Operator '#{operatorName}' cannot have optional parameters.",
-  },
-
-  'OPERATOR_NAMED_PARAMETERS': {
-    'id': 'EACWGS',
-    'template': "Operator '#{operatorName}' cannot have named parameters.",
-  },
-
-  'CONSTRUCTOR_WITH_RETURN_TYPE': {
-    'id': 'OPMBHF',
-    'template': "Cannot have return type for constructor.",
-  },
-
-  'CANNOT_RETURN_FROM_CONSTRUCTOR': {
-    'id': 'NFUGNH',
-    'template': "Constructors can't return values.",
-    'howToFix': "Remove the return statement or use a factory constructor.",
-    'examples': [
-      """
-class C {
-C() {
-  return 1;
-}
-}
-
-main() => new C();"""
-    ],
-  },
-
-  'ILLEGAL_FINAL_METHOD_MODIFIER': {
-    'id': 'YUKCVU',
-    'template': "Cannot have final modifier on method.",
-  },
-
-  'ILLEGAL_CONST_FIELD_MODIFIER': {
-    'id': 'JGFAGV',
-    'template': "Cannot have const modifier on non-static field.",
-    'howToFix': "Try adding a static modifier, or removing the const modifier.",
-    'examples': [
-      """
-class C {
-const int a = 1;
-}
-
-main() => new C();"""
-    ],
-  },
-
-  'ILLEGAL_CONSTRUCTOR_MODIFIERS': {
-    'id': 'WODRHN',
-    'template': "Illegal constructor modifiers: '#{modifiers}'.",
-  },
-
-  'ILLEGAL_MIXIN_APPLICATION_MODIFIERS': {
-    'id': 'OFLFHN',
-    'template': "Illegal mixin application modifiers: '#{modifiers}'.",
-  },
-
-  'ILLEGAL_MIXIN_SUPERCLASS': {
-    'id': 'TPVVYN',
-    'template': "Class used as mixin must have Object as superclass.",
-  },
-
-  'ILLEGAL_MIXIN_OBJECT': {
-    'id': 'CMVTLF',
-    'template': "Cannot use Object as mixin.",
-  },
-
-  'ILLEGAL_MIXIN_CONSTRUCTOR': {
-    'id': 'HXBUIB',
-    'template': "Class used as mixin cannot have non-factory constructor.",
-  },
-
-  'ILLEGAL_MIXIN_CYCLE': {
-    'id': 'ANXAMU',
-    'template': "Class used as mixin introduces mixin cycle: "
-        "'#{mixinName1}' <-> '#{mixinName2}'.",
-  },
-
-  'ILLEGAL_MIXIN_WITH_SUPER': {
-    'id': 'KIEUGK',
-    'template': "Cannot use class '#{className}' as a mixin because it uses "
-        "'super'.",
-  },
-
-  'ILLEGAL_MIXIN_SUPER_USE': {
-    'id': 'QKUPLH',
-    'template': "Use of 'super' in class used as mixin.",
-  },
-
-  'PARAMETER_NAME_EXPECTED': {
-    'id': 'JOUOBT',
-    'template': "parameter name expected.",
-  },
-
-  'CANNOT_RESOLVE_GETTER': {
-    'id': 'TDHKSW',
-    'template': "Cannot resolve getter.",
-  },
-
-  'CANNOT_RESOLVE_SETTER': {
-    'id': 'QQFANP',
-    'template': "Cannot resolve setter.",
-  },
-
-  'ASSIGNING_FINAL_FIELD_IN_SUPER': {
-    'id': 'LXUPCC',
-    'template': "Cannot assign a value to final field '#{name}' "
-        "in superclass '#{superclassName}'.",
-  },
-
-  'ASSIGNING_METHOD': {
-    'id': 'JUVMYC',
-    'template': "Cannot assign a value to a method.",
-  },
-
-  'ASSIGNING_METHOD_IN_SUPER': {
-    'id': 'AGMAXN',
-    'template': "Cannot assign a value to method '#{name}' "
-        "in superclass '#{superclassName}'.",
-  },
-
-  'ASSIGNING_TYPE': {
-    'id': 'VXTPWE',
-    'template': "Cannot assign a value to a type.",
-  },
-
-  'IF_NULL_ASSIGNING_TYPE': {
-    'id': 'XBRHGK',
-    'template':
-        "Cannot assign a value to a type. Note that types are never null, "
-        "so this ??= assignment has no effect.",
-    'howToFix': "Try removing the '??=' assignment.",
-    'examples': ["class A {} main() { print(A ??= 3);}",],
-  },
-
-  'VOID_NOT_ALLOWED': {
-    'id': 'DMMDXT',
-    'template':
-        "Type 'void' can't be used here because it isn't a return type.",
-    'howToFix':
-        "Try removing 'void' keyword or replace it with 'var', 'final', "
-        "or a type.",
-    'examples': ["void x; main() {}", "foo(void x) {} main() { foo(null); }",],
-  },
-
-  'NULL_NOT_ALLOWED': {
-    'id': 'STYNSK',
-    'template': "`null` can't be used here.",
-  },
-
-  'BEFORE_TOP_LEVEL': {
-    'id': 'GRCXQF',
-    'template': "Part header must come before top-level definitions.",
-  },
-
-  'IMPORT_PART_OF': {
-    'id': 'VANCWE',
-    'template': "The imported library must not have a 'part-of' directive.",
-    'howToFix': "Try removing the 'part-of' directive or replacing the "
-        "import of the library with a 'part' directive.",
-    'examples': [
-      {
-        'main.dart': """
-library library;
-
-import 'part.dart';
-
-main() {}
-""",
-        'part.dart': """
-part of library;
-"""
-      }
-    ],
-  },
-
-  'IMPORT_PART_OF_HERE': {
-    'id': 'TRSZOJ',
-    'template': 'The library is imported here.',
-  },
-
-  'MAIN_HAS_PART_OF': {
-    'id': 'MFMRRL',
-    'template': "The main application file must not have a 'part-of' "
-                "directive.",
-    'howToFix': "Try removing the 'part-of' directive or starting compilation "
-                "from another file.",
-    'examples': [
-      {
-        'main.dart': """
-part of library;
-
-main() {}
-"""
-      }
-    ],
-  },
-
-  'LIBRARY_NAME_MISMATCH': {
-    'id': 'AXGYPQ',
-    'template': "Expected part of library name '#{libraryName}'.",
-    'howToFix': "Try changing the directive to 'part of #{libraryName};'.",
-    'examples': [
-      {
-        'main.dart': """
-library lib.foo;
-
-part 'part.dart';
-
-main() {}
-""",
-        'part.dart': """
-part of lib.bar;
-"""
-      }
-    ],
-  },
-
-  'MISSING_LIBRARY_NAME': {
-    'id': 'NYQNCA',
-    'template': "Library has no name. Part directive expected library name "
-        "to be '#{libraryName}'.",
-    'howToFix': "Try adding 'library #{libraryName};' to the library.",
-    'examples': [
-      {
-        'main.dart': """
-part 'part.dart';
-
-main() {}
-""",
-        'part.dart': """
-part of lib.foo;
-"""
-      }
-    ],
-  },
-
-  'THIS_IS_THE_PART_OF_TAG': {
-    'id': 'RPSJRS',
-    'template': "This is the part of directive.",
-  },
-
-  'MISSING_PART_OF_TAG': {
-    'id': 'QNYCMV',
-    'template': "This file has no part-of tag, but it is being used as a part.",
-  },
-
-  'DUPLICATED_PART_OF': {
-    'id': 'UJDYHF',
-    'template': "Duplicated part-of directive.",
-  },
-
-  'DUPLICATED_LIBRARY_NAME': {
-    'id': 'OSEHXI',
-    'template': "Duplicated library name '#{libraryName}'.",
-  },
-
-  'DUPLICATED_RESOURCE': {
-    'id': 'UFWKBY',
-    'template': "The resource '#{resourceUri}' is loaded through both "
-        "'#{canonicalUri1}' and '#{canonicalUri2}'.",
-  },
-
-  'DUPLICATED_LIBRARY_RESOURCE': {
-    'id': 'KYGYTT',
-    'template':
-        "The library '#{libraryName}' in '#{resourceUri}' is loaded through "
-        "both '#{canonicalUri1}' and '#{canonicalUri2}'.",
-  },
-
-  // This is used as an exception.
-  'INVALID_SOURCE_FILE_LOCATION': {
-    'id': 'WIGJFG',
-    'template': """
-Invalid offset (#{offset}) in source map.
-File: #{fileName}
-Length: #{length}""",
-  },
-
-  'TOP_LEVEL_VARIABLE_DECLARED_STATIC': {
-    'id': 'IVNDML',
-    'template': "Top-level variable cannot be declared static.",
-  },
-
-  'REFERENCE_IN_INITIALIZATION': {
-    'id': 'OVWTEU',
-    'template': "Variable '#{variableName}' is referenced during its "
-        "initialization.",
-    'howToFix': "If you are trying to reference a shadowed variable, rename "
-        "one of the variables.",
-    'examples': [
-      """
-foo(t) {
-var t = t;
-return t;
-}
-
-main() => foo(1);
-"""
-    ],
-  },
-
-  'CONST_WITHOUT_INITIALIZER': {
-    'id': 'UDWCNH',
-    'template': "A constant variable must be initialized.",
-    'howToFix': "Try adding an initializer or "
-        "removing the 'const' modifier.",
-    'examples': [
-      """
-void main() {
-const c; // This constant variable must be initialized.
-}"""
-    ],
-  },
-
-  'FINAL_WITHOUT_INITIALIZER': {
-    'id': 'YMESFI',
-    'template': "A final variable must be initialized.",
-    'howToFix': "Try adding an initializer or "
-        "removing the 'final' modifier.",
-    'examples': ["class C { static final field; } main() => C.field;"],
-  },
-
-  'CONST_LOOP_VARIABLE': {
-    'id': 'WUSKMG',
-    'template': "A loop variable cannot be constant.",
-    'howToFix': "Try remove the 'const' modifier or "
-        "replacing it with a 'final' modifier.",
-    'examples': [
-      """
-void main() {
-  for (const c in []) {}
-}"""
-    ],
-  },
-
-  'MEMBER_USES_CLASS_NAME': {
-    'id': 'TVFYRK',
-    'template': "Member variable can't have the same name as the class it is "
-        "declared in.",
-    'howToFix': "Try renaming the variable.",
-    'examples': [
-      """
-class A { var A; }
-main() {
-var a = new A();
-a.A = 1;
-}
-""",
-      """
-class A { static var A; }
-main() => A.A = 1;
-"""
-    ],
-  },
-
-  'WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT': {
-    'id': 'IXYNUF',
-    'template': "Wrong number of arguments to assert. Should be 1, but given "
-        "#{argumentCount}.",
-  },
-
-  'ASSERT_IS_GIVEN_NAMED_ARGUMENTS': {
-    'id': 'EJFDTO',
-    'template':
-        "'assert' takes no named arguments, but given #{argumentCount}.",
-  },
-
-  'FACTORY_REDIRECTION_IN_NON_FACTORY': {
-    'id': 'DTBWEX',
-    'template': "Factory redirection only allowed in factories.",
-  },
-
-  'MISSING_FACTORY_KEYWORD': {
-    'id': 'HOQYYA',
-    'template': "Did you forget a factory keyword here?",
-  },
-
-  'NO_SUCH_METHOD_IN_NATIVE': {
-    'id': 'MSDDBX',
-    'template':
-        "'NoSuchMethod' is not supported for classes that extend native "
-        "classes.",
-  },
-
-  'DEFERRED_LIBRARY_DART_2_DART': {
-    'id': 'RIRQAH',
-    'template': "Deferred loading is not supported by the dart backend yet. "
-        "The output will not be split.",
-  },
-
-  'DEFERRED_LIBRARY_WITHOUT_PREFIX': {
-    'id': 'CARRII',
-    'template': "This import is deferred but there is no prefix keyword.",
-    'howToFix': "Try adding a prefix to the import."
-  },
-
-  'DEFERRED_OLD_SYNTAX': {
-    'id': 'QCBRAE',
-    'template': "The DeferredLibrary annotation is obsolete.",
-    'howToFix':
-        "Use the \"import 'lib.dart' deferred as prefix\" syntax instead.",
-  },
-
-  'DEFERRED_LIBRARY_DUPLICATE_PREFIX': {
-    'id': 'BBMJTD',
-    'template': "The prefix of this deferred import is not unique.",
-    'howToFix': "Try changing the import prefix."
-  },
-
-  'DEFERRED_TYPE_ANNOTATION': {
-    'id': 'JOUEFD',
-    'template': "The type #{node} is deferred. "
-        "Deferred types are not valid as type annotations.",
-    'howToFix': "Try using a non-deferred abstract class as an interface.",
-  },
-
-  'ILLEGAL_STATIC': {
-    'id': 'HFBHVE',
-    'template': "Modifier static is only allowed on functions declared in "
-        "a class.",
-  },
-
-  'STATIC_FUNCTION_BLOAT': {
-    'id': 'SJHTKF',
-    'template': "Using '#{class}.#{name}' may lead to unnecessarily large "
-        "generated code.",
-    'howToFix': "Try adding '@MirrorsUsed(...)' as described at "
-        "https://goo.gl/Akrrog.",
-  },
-
-  'NON_CONST_BLOAT': {
-    'id': 'RDRSHO',
-    'template': "Using 'new #{name}' may lead to unnecessarily large generated "
-        "code.",
-    'howToFix': "Try using 'const #{name}' or adding '@MirrorsUsed(...)' as "
-        "described at https://goo.gl/Akrrog.",
-  },
-
-  'STRING_EXPECTED': {
-    'id': 'OEJOOI',
-    'template': "Expected a 'String', but got an instance of '#{type}'.",
-  },
-
-  'PRIVATE_IDENTIFIER': {
-    'id': 'XAHVWI',
-    'template': "'#{value}' is not a valid Symbol name because it starts with "
-        "'_'.",
-  },
-
-  'PRIVATE_NAMED_PARAMETER': {
-    'id': 'VFGCLK',
-    'template': "Named optional parameter can't have a library private name.",
-    'howToFix': "Try removing the '_' or making the parameter positional or "
-        "required.",
-    'examples': ["""foo({int _p}) {} main() => foo();"""],
-  },
-
-  'UNSUPPORTED_LITERAL_SYMBOL': {
-    'id': 'OYCDII',
-    'template':
-        "Symbol literal '##{value}' is currently unsupported by dart2js.",
-  },
-
-  'INVALID_SYMBOL': {
-    'id': 'RUXMBL',
-    'template': '''
-'#{value}' is not a valid Symbol name because is not:
-* an empty String,
-* a user defined operator,
-* a qualified non-private identifier optionally followed by '=', or
-* a qualified non-private identifier followed by '.' and a user-defined '''
-        "operator.",
-  },
-
-  'AMBIGUOUS_REEXPORT': {
-    'id': 'YNTOND',
-    'template': "'#{name}' is (re)exported by multiple libraries.",
-  },
-
-  'AMBIGUOUS_LOCATION': {
-    'id': 'SKLTYA',
-    'template': "'#{name}' is defined here.",
-  },
-
-  'IMPORTED_HERE': {'id': 'IMUXAE', 'template': "'#{name}' is imported here.",},
-
-  'OVERRIDE_EQUALS_NOT_HASH_CODE': {
-    'id': 'MUHYXI',
-    'template': "The class '#{class}' overrides 'operator==', "
-        "but not 'get hashCode'.",
-  },
-
-  'INTERNAL_LIBRARY_FROM': {
-    'id': 'RXOCLX',
-    'template': "Internal library '#{resolvedUri}' is not accessible from "
-        "'#{importingUri}'.",
-  },
-
-  'INTERNAL_LIBRARY': {
-    'id': 'SYLJAV',
-    'template': "Internal library '#{resolvedUri}' is not accessible.",
-  },
-
-  'JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS': {
-    'id': 'LSHKJK',
-    'template':
-        "Js-interop class '#{cls}' cannot extend from the non js-interop "
-        "class '#{superclass}'.",
-    'howToFix': "Annotate the superclass with @JS.",
-    'examples': [
-      """
-            import 'package:js/js.dart';
-
-            class Foo { }
-
-            @JS()
-            class Bar extends Foo { }
-
-            main() {
-              new Bar();
-            }
-            """
-    ],
-  },
-
-  'JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER': {
-    'id': 'QLLLEE',
-    'template':
-        "Member '#{member}' in js-interop class '#{cls}' is not external.",
-    'howToFix': "Mark all interop methods external",
-    'examples': [
-      """
-            import 'package:js/js.dart';
-
-            @JS()
-            class Foo {
-              bar() {}
-            }
-
-            main() {
-              new Foo().bar();
-            }
-            """
-    ],
-  },
-
-  'JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS': {
-    'id': 'TDQHRY',
-    'template': "Js-interop method '#{method}' has named arguments but is not "
-        "a factory constructor of an @anonymous @JS class.",
-    'howToFix': "Remove all named arguments from js-interop method or "
-        "in the case of a factory constructor annotate the class "
-        "as @anonymous.",
-    'examples': [
-      """
-            import 'package:js/js.dart';
-
-            @JS()
-            class Foo {
-              external bar(foo, {baz});
-            }
-
-            main() {
-              new Foo().bar(4, baz: 5);
-            }
-            """
-    ],
-  },
-
-  'JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS': {
-    'id': 'EHEKUY',
-    'template':
-        "Parameter '#{parameter}' in anonymous js-interop class '#{cls}' "
-        "object literal constructor is positional instead of named."
-        ".",
-    'howToFix': "Make all arguments in external factory object literal "
-        "constructors named.",
-    'examples': [
-      """
-            import 'package:js/js.dart';
-
-            @anonymous
-            @JS()
-            class Foo {
-              external factory Foo(foo, {baz});
-            }
-
-            main() {
-              new Foo(5, baz: 5);
-            }
-            """
-    ],
-  },
-
-  'LIBRARY_NOT_FOUND': {
-    'id': 'BARPSL',
-    'template': "Library not found '#{resolvedUri}'.",
-  },
-
-  'LIBRARY_NOT_SUPPORTED': {
-    'id': 'GDXUNS',
-    'template': "Library not supported '#{resolvedUri}'.",
-    'howToFix': "Try removing the dependency or enabling support using "
-        "the '--categories' option.",
-    'examples': [
-//            """
-//            import 'dart:io';
-//            main() {}
-//            """
-    ],
-    // TODO(johnniwinther): Enable example when message_kind_test.dart
-    // supports library loader callbacks.
-  },
-
-  'UNSUPPORTED_EQ_EQ_EQ': {
-    'id': 'GPOVNO',
-    'template': "'===' is not an operator. "
-        "Did you mean '#{lhs} == #{rhs}' or 'identical(#{lhs}, #{rhs})'?",
-  },
-
-  'UNSUPPORTED_BANG_EQ_EQ': {
-    'id': 'HDYKMV',
-    'template': "'!==' is not an operator. "
-        "Did you mean '#{lhs} != #{rhs}' or '!identical(#{lhs}, #{rhs})'?",
-  },
-
-  'UNSUPPORTED_PREFIX_PLUS': {
-    'id': 'LSQTHP',
-    'template': "'+' is not a prefix operator. ",
-    'howToFix': "Try removing '+'.",
-    'examples': ["main() => +2;  // No longer a valid way to write '2'"],
-  },
-
-  'UNSUPPORTED_THROW_WITHOUT_EXP': {
-    'id': 'QOAKGE',
-    'template': "No expression after 'throw'. "
-        "Did you mean 'rethrow'?",
-  },
-
-  'DEPRECATED_TYPEDEF_MIXIN_SYNTAX': {
-    'id': 'BBGGFE',
-    'template': "'typedef' not allowed here. ",
-    'howToFix': "Try replacing 'typedef' with 'class'.",
-    'examples': [
-      """
-class B { }
-class M1 {  }
-typedef C = B with M1;  // Need to replace 'typedef' with 'class'.
-main() { new C(); }
-"""
-    ],
-  },
-
-  'MIRRORS_EXPECTED_STRING': {
-    'id': 'XSKTIB',
-    'template':
-        "Can't use '#{name}' here because it's an instance of '#{type}' "
-        "and a 'String' value is expected.",
-    'howToFix': "Did you forget to add quotes?",
-    'examples': [
-      """
-// 'Foo' is a type literal, not a string.
-@MirrorsUsed(symbols: const [Foo])
-import 'dart:mirrors';
-
-class Foo {}
-
-main() {}
-"""
-    ],
-  },
-
-  'MIRRORS_EXPECTED_STRING_OR_TYPE': {
-    'id': 'JQDJPL',
-    'template':
-        "Can't use '#{name}' here because it's an instance of '#{type}' "
-        "and a 'String' or 'Type' value is expected.",
-    'howToFix': "Did you forget to add quotes?",
-    'examples': [
-      """
-// 'main' is a method, not a class.
-@MirrorsUsed(targets: const [main])
-import 'dart:mirrors';
-
-main() {}
-"""
-    ],
-  },
-
-  'MIRRORS_EXPECTED_STRING_OR_LIST': {
-    'id': 'UVYCOE',
-    'template':
-        "Can't use '#{name}' here because it's an instance of '#{type}' "
-        "and a 'String' or 'List' value is expected.",
-    'howToFix': "Did you forget to add quotes?",
-    'examples': [
-      """
-// 'Foo' is not a string.
-@MirrorsUsed(symbols: Foo)
-import 'dart:mirrors';
-
-class Foo {}
-
-main() {}
-"""
-    ],
-  },
-
-  'MIRRORS_EXPECTED_STRING_TYPE_OR_LIST': {
-    'id': 'WSYDFL',
-    'template':
-        "Can't use '#{name}' here because it's an instance of '#{type}' "
-        "but a 'String', 'Type', or 'List' value is expected.",
-    'howToFix': "Did you forget to add quotes?",
-    'examples': [
-      """
-// '1' is not a string.
-@MirrorsUsed(targets: 1)
-import 'dart:mirrors';
-
-main() {}
-"""
-    ],
-  },
-
-  'MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY': {
-    'id': 'VDBBNE',
-    'template': "Can't find '#{name}' in the current library.",
-    // TODO(ahe): The closest identifiers in edit distance would be nice.
-    'howToFix': "Did you forget to add an import?",
-    'examples': [
-      """
-// 'window' is not in scope because dart:html isn't imported.
-@MirrorsUsed(targets: 'window')
-import 'dart:mirrors';
-
-main() {}
-"""
-    ],
-  },
-
-  'MIRRORS_CANNOT_RESOLVE_IN_LIBRARY': {
-    'id': 'RUEKXE',
-    'template': "Can't find '#{name}' in the library '#{library}'.",
-    // TODO(ahe): The closest identifiers in edit distance would be nice.
-    'howToFix': "Is '#{name}' spelled right?",
-    'examples': [
-      """
-// 'List' is misspelled.
-@MirrorsUsed(targets: 'dart.core.Lsit')
-import 'dart:mirrors';
-
-main() {}
-"""
-    ],
-  },
-
-  'MIRRORS_CANNOT_FIND_IN_ELEMENT': {
-    'id': 'ACPDCS',
-    'template': "Can't find '#{name}' in '#{element}'.",
-    // TODO(ahe): The closest identifiers in edit distance would be nice.
-    'howToFix': "Is '#{name}' spelled right?",
-    'examples': [
-      """
-// 'addAll' is misspelled.
-@MirrorsUsed(targets: 'dart.core.List.addAl')
-import 'dart:mirrors';
-
-main() {}
-"""
-    ],
-  },
-
-  'INVALID_URI': {
-    'id': 'QQEQMK',
-    'template': "'#{uri}' is not a valid URI.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': [
-      """
-// can't have a '[' in a URI
-import '../../Udyn[mic ils/expect.dart';
-
-main() {}
-"""
-    ],
-  },
-
-  'INVALID_PACKAGE_CONFIG': {
-    'id': 'XKFAJO',
-    'template': """Package config file '#{uri}' is invalid.
-#{exception}""",
-    'howToFix': DONT_KNOW_HOW_TO_FIX
-  },
-
-  'INVALID_PACKAGE_URI': {
-    'id': 'MFVNNJ',
-    'template': "'#{uri}' is not a valid package URI (#{exception}).",
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': [
-      """
-// can't have a 'top level' package URI
-import 'package:foo.dart';
-
-main() {}
-""",
-      """
-// can't have 2 slashes
-import 'package://foo/foo.dart';
-
-main() {}
-""",
-      """
-// package name must be valid
-import 'package:not\valid/foo.dart';
-
-main() {}
-"""
-    ],
-  },
-
-  'READ_SCRIPT_ERROR': {
-    'id': 'JDDYLH',
-    'template': "Can't read '#{uri}' (#{exception}).",
-    // Don't know how to fix since the underlying error is unknown.
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': [
-      """
-// 'foo.dart' does not exist.
-import 'foo.dart';
-
-main() {}
-"""
-    ],
-  },
-
-  'READ_SELF_ERROR': {
-    'id': 'CRJUAV',
-    'template': "#{exception}",
-    // Don't know how to fix since the underlying error is unknown.
-    'howToFix': DONT_KNOW_HOW_TO_FIX
-  },
-
-  'EXTRANEOUS_MODIFIER': {
-    'id': 'DPLVJG',
-    'template': "Can't have modifier '#{modifier}' here.",
-    'howToFix': "Try removing '#{modifier}'.",
-    'examples': [
-      "var String foo; main(){}",
-      // "var get foo; main(){}",
-      "var set foo; main(){}",
-      "var final foo; main(){}",
-      "var var foo; main(){}",
-      "var const foo; main(){}",
-      "var abstract foo; main(){}",
-      "var static foo; main(){}",
-      "var external foo; main(){}",
-      "get var foo; main(){}",
-      "set var foo; main(){}",
-      "final var foo; main(){}",
-      "var var foo; main(){}",
-      "const var foo; main(){}",
-      "abstract var foo; main(){}",
-      "static var foo; main(){}",
-      "external var foo; main(){}"
-    ],
-  },
-
-  'EXTRANEOUS_MODIFIER_REPLACE': {
-    'id': 'SSXDLN',
-    'template': "Can't have modifier '#{modifier}' here.",
-    'howToFix': "Try replacing modifier '#{modifier}' with 'var', 'final', "
-        "or a type.",
-    'examples': [
-      // "get foo; main(){}",
-      "set foo; main(){}",
-      "abstract foo; main(){}",
-      "static foo; main(){}",
-      "external foo; main(){}"
-    ],
-  },
-
-  'ABSTRACT_CLASS_INSTANTIATION': {
-    'id': 'KOBCRO',
-    'template': "Can't instantiate abstract class.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': ["abstract class A {} main() { new A(); }"],
-  },
-
-  'BODY_EXPECTED': {
-    'id': 'YXCAHO',
-    'template': "Expected a function body or '=>'.",
-    // TODO(ahe): In some scenarios, we can suggest removing the 'static'
-    // keyword.
-    'howToFix': "Try adding {}.",
-    'examples': ["main();"],
-  },
-
-  'MIRROR_BLOAT': {
-    'id': 'BSEAIT',
-    'template':
-        "#{count} methods retained for use by dart:mirrors out of #{total}"
-        " total methods (#{percentage}%).",
-  },
-
-  'MIRROR_IMPORT': {'id': 'BDAETE', 'template': "Import of 'dart:mirrors'.",},
-
-  'MIRROR_IMPORT_NO_USAGE': {
-    'id': 'OJOHTR',
-    'template':
-        "This import is not annotated with @MirrorsUsed, which may lead to "
-        "unnecessarily large generated code.",
-    'howToFix': "Try adding '@MirrorsUsed(...)' as described at "
-        "https://goo.gl/Akrrog.",
-  },
-
-  'JS_PLACEHOLDER_CAPTURE': {
-    'id': 'EJXEGQ',
-    'template': "JS code must not use '#' placeholders inside functions.",
-    'howToFix': "Use an immediately called JavaScript function to capture the"
-        " the placeholder values as JavaScript function parameters.",
-  },
-
-  'WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT': {
-    'id': 'JHRISO',
-    'template':
-        "Argument for 'JS_INTERCEPTOR_CONSTANT' must be a type constant.",
-  },
-
-  'EXPECTED_IDENTIFIER_NOT_RESERVED_WORD': {
-    'id': 'FEJXJF',
-    'template': "'#{keyword}' is a reserved word and can't be used here.",
-    'howToFix': "Try using a different name.",
-    'examples': ["do() {} main() {}"],
-  },
-
-  'NAMED_FUNCTION_EXPRESSION': {
-    'id': 'CTHFPI',
-    'template': "Function expression '#{name}' cannot be named.",
-    'howToFix': "Try removing the name.",
-    'examples': ["main() { var f = func() {}; }"],
-  },
-
-  'UNUSED_METHOD': {
-    'id': 'PKLRQL',
-    'template': "The method '#{name}' is never called.",
-    'howToFix': "Consider deleting it.",
-    'examples': ["deadCode() {} main() {}"],
-  },
-
-  'UNUSED_CLASS': {
-    'id': 'TBIECC',
-    'template': "The class '#{name}' is never used.",
-    'howToFix': "Consider deleting it.",
-    'examples': ["class DeadCode {} main() {}"],
-  },
-
-  'UNUSED_TYPEDEF': {
-    'id': 'JBIPCN',
-    'template': "The typedef '#{name}' is never used.",
-    'howToFix': "Consider deleting it.",
-    'examples': ["typedef DeadCode(); main() {}"],
-  },
-
-  'ABSTRACT_METHOD': {
-    'id': 'HOKOBG',
-    'template': "The method '#{name}' has no implementation in "
-        "class '#{class}'.",
-    'howToFix': "Try adding a body to '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-class Class {
-method();
-}
-main() => new Class().method();
-"""
-    ],
-  },
-
-  'ABSTRACT_GETTER': {
-    'id': 'VKTRNK',
-    'template': "The getter '#{name}' has no implementation in "
-        "class '#{class}'.",
-    'howToFix': "Try adding a body to '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-class Class {
-get getter;
-}
-main() => new Class();
-"""
-    ],
-  },
-
-  'ABSTRACT_SETTER': {
-    'id': 'XGDGKK',
-    'template': "The setter '#{name}' has no implementation in "
-        "class '#{class}'.",
-    'howToFix': "Try adding a body to '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-class Class {
-set setter(_);
-}
-main() => new Class();
-"""
-    ],
-  },
-
-  'INHERIT_GETTER_AND_METHOD': {
-    'id': 'UMEUEG',
-    'template': "The class '#{class}' can't inherit both getters and methods "
-        "by the named '#{name}'.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': [
-      """
-class A {
-get member => null;
-}
-class B {
-member() {}
-}
-class Class implements A, B {
-}
-main() => new Class();
-"""
-    ],
-  },
-
-  'INHERITED_METHOD': {
-    'id': 'GMSVBM',
-    'template': "The inherited method '#{name}' is declared here in class "
-        "'#{class}'.",
-  },
-
-  'INHERITED_EXPLICIT_GETTER': {
-    'id': 'KKAVRS',
-    'template': "The inherited getter '#{name}' is declared here in class "
-        "'#{class}'.",
-  },
-
-  'INHERITED_IMPLICIT_GETTER': {
-    'id': 'JBAMEJ',
-    'template': "The inherited getter '#{name}' is implicitly declared by this "
-        "field in class '#{class}'.",
-  },
-
-  'UNIMPLEMENTED_METHOD_ONE': {
-    'id': 'CMCLWO',
-    'template': "'#{class}' doesn't implement '#{method}' "
-        "declared in '#{declarer}'.",
-    'howToFix': "Try adding an implementation of '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-abstract class I {
-m();
-}
-class C implements I {}
-main() => new C();
-""",
-      """
-abstract class I {
-m();
-}
-class C extends I {}
-main() => new C();
-"""
-    ],
-  },
-
-  'UNIMPLEMENTED_METHOD': {
-    'id': 'IJSNQB',
-    'template': "'#{class}' doesn't implement '#{method}'.",
-    'howToFix': "Try adding an implementation of '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-abstract class I {
-m();
-}
-
-abstract class J {
-m();
-}
-
-class C implements I, J {}
-
-main() {
-new C();
-}
-""",
-      """
-abstract class I {
-m();
-}
-
-abstract class J {
-m();
-}
-
-class C extends I implements J {}
-
-main() {
-new C();
-}
-"""
-    ],
-  },
-
-  'UNIMPLEMENTED_METHOD_CONT': {
-    'id': 'KFBKPO',
-    'template': "The method '#{name}' is declared here in class '#{class}'.",
-  },
-
-  'UNIMPLEMENTED_SETTER_ONE': {
-    'id': 'QGKTEA',
-    'template': "'#{class}' doesn't implement the setter '#{name}' "
-        "declared in '#{declarer}'.",
-    'howToFix': "Try adding an implementation of '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-abstract class I {
-set m(_);
-}
-class C implements I {}
-class D implements I {
-set m(_) {}
-}
-main() {
-new D().m = 0;
-new C();
-}
-"""
-    ],
-  },
-
-  'UNIMPLEMENTED_SETTER': {
-    'id': 'VEEGJQ',
-    'template': "'#{class}' doesn't implement the setter '#{name}'.",
-    'howToFix': "Try adding an implementation of '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-abstract class I {
-set m(_);
-}
-abstract class J {
-set m(_);
-}
-class C implements I, J {}
-main() => new C();
-""",
-      """
-abstract class I {
-set m(_);
-}
-abstract class J {
-set m(_);
-}
-class C extends I implements J {}
-main() => new C();
-"""
-    ],
-  },
-
-  'UNIMPLEMENTED_EXPLICIT_SETTER': {
-    'id': 'SABABA',
-    'template': "The setter '#{name}' is declared here in class '#{class}'.",
-  },
-
-  'UNIMPLEMENTED_IMPLICIT_SETTER': {
-    'id': 'SWESAQ',
-    'template': "The setter '#{name}' is implicitly declared by this field "
-        "in class '#{class}'.",
-  },
-
-  'UNIMPLEMENTED_GETTER_ONE': {
-    'id': 'ODEPFW',
-    'template': "'#{class}' doesn't implement the getter '#{name}' "
-        "declared in '#{declarer}'.",
-    'howToFix': "Try adding an implementation of '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-abstract class I {
-get m;
-}
-class C implements I {}
-main() => new C();
-""",
-      """
-abstract class I {
-get m;
-}
-class C extends I {}
-main() => new C();
-"""
-    ],
-  },
-
-  'UNIMPLEMENTED_GETTER': {
-    'id': 'VHSECG',
-    'template': "'#{class}' doesn't implement the getter '#{name}'.",
-    'howToFix': "Try adding an implementation of '#{name}' or declaring "
-        "'#{class}' to be 'abstract'.",
-    'examples': [
-      """
-abstract class I {
-get m;
-}
-abstract class J {
-get m;
-}
-class C implements I, J {}
-main() => new C();
-""",
-      """
-abstract class I {
-get m;
-}
-abstract class J {
-get m;
-}
-class C extends I implements J {}
-main() => new C();
-"""
-    ],
-  },
-
-  'UNIMPLEMENTED_EXPLICIT_GETTER': {
-    'id': 'HFDJPP',
-    'template': "The getter '#{name}' is declared here in class '#{class}'.",
-  },
-
-  'UNIMPLEMENTED_IMPLICIT_GETTER': {
-    'id': 'BSCQNO',
-    'template': "The getter '#{name}' is implicitly declared by this field "
-        "in class '#{class}'.",
-  },
-
-  'INVALID_METADATA': {
-    'id': 'RKJGDE',
-    'template':
-        "A metadata annotation must be either a reference to a compile-time "
-        "constant variable or a call to a constant constructor.",
-    'howToFix':
-        "Try using a different constant value or referencing it through a "
-        "constant variable.",
-    'examples': [
-'@Object main() {}',
-'@print main() {}']
-  },
-
-  'INVALID_METADATA_GENERIC': {
-    'id': 'WEEDQD',
-    'template':
-        "A metadata annotation using a constant constructor cannot use type "
-        "arguments.",
-    'howToFix':
-        "Try removing the type arguments or referencing the constant "
-        "through a constant variable.",
-    'examples': [
-      '''
-class C<T> {
-  const C();
-}
-@C<int>() main() {}
-'''],
-  },
-
-  'EQUAL_MAP_ENTRY_KEY': {
-    'id': 'KIDLPM',
-    'template': "An entry with the same key already exists in the map.",
-    'howToFix': "Try removing the previous entry or changing the key in one "
-        "of the entries.",
-    'examples': [
-      """
-main() {
-var m = const {'foo': 1, 'foo': 2};
-}"""
-    ],
-  },
-
-  'BAD_INPUT_CHARACTER': {
-    'id': 'SHQWJY',
-    'template': "Character U+#{characterHex} isn't allowed here.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': [
-      """
-main() {
-String x = ç;
-}
-"""
-    ],
-  },
-
-  'UNTERMINATED_STRING': {
-    'id': 'TRLTHK',
-    'template': "String must end with #{quote}.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': [
-      """
-main() {
-return '
-;
-}
-""",
-      """
-main() {
-return \"
-;
-}
-""",
-      """
-main() {
-return r'
-;
-}
-""",
-      """
-main() {
-return r\"
-;
-}
-""",
-      """
-main() => '''
-""",
-      """
-main() => \"\"\"
-""",
-      """
-main() => r'''
-""",
-      """
-main() => r\"\"\"
-"""
-    ],
-  },
-
-  'UNMATCHED_TOKEN': {
-    'id': 'AGJKMQ',
-    'template': "Can't find '#{end}' to match '#{begin}'.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': ["main(", "main(){", "main(){]}",],
-  },
-
-  'UNTERMINATED_TOKEN': {
-    'id': 'VIIXHQ',
-    'template':
-        // This is a fall-back message that shouldn't happen.
-        "Incomplete token.",
-  },
-
-  'EXPONENT_MISSING': {
-    'id': 'CXPLCR',
-    'template':
-        "Numbers in exponential notation should always contain an exponent"
-        " (an integer number with an optional sign).",
-    'howToFix': "Make sure there is an exponent, and remove any whitespace "
-        "before it.",
-    'examples': [
-      """
-main() {
-var i = 1e;
-}
-"""
-    ],
-  },
-
-  'HEX_DIGIT_EXPECTED': {
-    'id': 'GKCAGV',
-    'template': "A hex digit (0-9 or A-F) must follow '0x'.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX, // Seems obvious from the error message.
-    'examples': [
-      """
-main() {
-var i = 0x;
-}
-"""
-    ],
-  },
-
-  'MALFORMED_STRING_LITERAL': {
-    'id': 'DULNSD',
-    'template':
-        r"A '$' has special meaning inside a string, and must be followed by "
-        "an identifier or an expression in curly braces ({}).",
-    'howToFix': r"Try adding a backslash (\) to escape the '$'.",
-    'examples': [
-      r"""
-main() {
-return '$';
-}
-""",
-      r'''
-main() {
-return "$";
-}
-''',
-      r"""
-main() {
-return '''$''';
-}
-""",
-      r'''
-main() {
-return """$""";
-}
-'''
-    ],
-  },
-
-  'UNTERMINATED_COMMENT': {
-    'id': 'NECJNM',
-    'template': "Comment starting with '/*' must end with '*/'.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': [
-      r"""
-main() {
-}
-/*"""
-    ],
-  },
-
-  'MISSING_TOKEN_BEFORE_THIS': {
-    'id': 'AFKXGU',
-    'template': "Expected '#{token}' before this.",
-    // Consider the second example below: the parser expects a ')' before
-    // 'y', but a ',' would also have worked. We don't have enough
-    // information to give a good suggestion.
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': ["main() => true ? 1;", "main() => foo(x: 1 y: 2);",],
-  },
-
-  'MISSING_TOKEN_AFTER_THIS': {
-    'id': 'FMUFJL',
-    'template': "Expected '#{token}' after this.",
-    // See [MISSING_TOKEN_BEFORE_THIS], we don't have enough information
-    // to give a good suggestion.
-    'howToFix': DONT_KNOW_HOW_TO_FIX,
-    'examples': [
-      "main(x) {x}",
-      """
-class S1 {}
-class S2 {}
-class S3 {}
-class A = S1 with S2, S3
-main() => new A();
-"""
-    ],
-  },
-
-  'CONSIDER_ANALYZE_ALL': {
-    'id': 'HHILSH',
-    'template': "Could not find '#{main}'.  Nothing will be analyzed.",
-    'howToFix': "Try using '--analyze-all' to analyze everything.",
-    'examples': [''],
-  },
-
-  'MISSING_MAIN': {
-    'id': 'HNAOPV',
-    'template': "Could not find '#{main}'.",
-    // No example, test uses '--analyze-only' which will produce the above
-    // message [CONSIDER_ANALYZE_ALL].  An example for a human operator
-    // would be an empty file.
-    'howToFix': "Try adding a method named '#{main}' to your program."
-  },
-
-  'MAIN_NOT_A_FUNCTION': {
-    'id': 'PIURPA',
-    'template': "'#{main}' is not a function.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX, // Don't state the obvious.
-    'examples': ['var main;'],
-  },
-
-  'MAIN_WITH_EXTRA_PARAMETER': {
-    'id': 'ONOGQB',
-    'template': "'#{main}' cannot have more than two parameters.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX, // Don't state the obvious.
-    'examples': ['main(a, b, c) {}'],
-  },
-
-  'COMPILER_CRASHED': {
-    'id': 'MHDWAV',
-    'template': "The compiler crashed when compiling this element.",
-  },
-
-  'PLEASE_REPORT_THE_CRASH': {
-    'id': 'UUTHXX',
-    'template': '''
-The compiler is broken.
-
-When compiling the above element, the compiler crashed. It is not
-possible to tell if this is caused by a problem in your program or
-not. Regardless, the compiler should not crash.
-
-The Dart team would greatly appreciate if you would take a moment to
-report this problem at http://dartbug.com/new.
-
-Please include the following information:
-
-* the name and version of your operating system,
-
-* the Dart SDK build number (#{buildId}), and
-
-* the entire message you see here (including the full stack trace
-below as well as the source location above).
-''',
-  },
-
-  'POTENTIAL_MUTATION': {
-    'id': 'YGNLLB',
-    'template': "Variable '#{variableName}' is not known to be of type "
-        "'#{shownType}' because it is potentially mutated in the scope for "
-        "promotion.",
-  },
-
-  'POTENTIAL_MUTATION_HERE': {
-    'id': 'ATMSVX',
-    'template': "Variable '#{variableName}' is potentially mutated here.",
-  },
-
-  'POTENTIAL_MUTATION_IN_CLOSURE': {
-    'id': 'XUAHTW',
-    'template': "Variable '#{variableName}' is not known to be of type "
-        "'#{shownType}' because it is potentially mutated within a closure.",
-  },
-
-  'POTENTIAL_MUTATION_IN_CLOSURE_HERE': {
-    'id': 'UHFXLG',
-    'template': "Variable '#{variableName}' is potentially mutated in a "
-        "closure here.",
-  },
-
-  'ACCESSED_IN_CLOSURE': {
-    'id': 'JJHKSF',
-    'template': "Variable '#{variableName}' is not known to be of type "
-        "'#{shownType}' because it is accessed by a closure in the scope for "
-        "promotion and potentially mutated in the scope of "
-        "'#{variableName}'.",
-  },
-
-  'ACCESSED_IN_CLOSURE_HERE': {
-    'id': 'KMJVEA',
-    'template': "Variable '#{variableName}' is accessed in a closure here.",
-  },
-
-  'NOT_MORE_SPECIFIC': {
-    'id': 'EJHQAG',
-    'template': "Variable '#{variableName}' is not shown to have type "
-        "'#{shownType}' because '#{shownType}' is not more specific than the "
-        "known type '#{knownType}' of '#{variableName}'.",
-  },
-
-  'NOT_MORE_SPECIFIC_SUBTYPE': {
-    'id': 'APICDL',
-    'template': "Variable '#{variableName}' is not shown to have type "
-        "'#{shownType}' because '#{shownType}' is not a subtype of the "
-        "known type '#{knownType}' of '#{variableName}'.",
-  },
-
-  'NOT_MORE_SPECIFIC_SUGGESTION': {
-    'id': 'FFNCJX',
-    'template': "Variable '#{variableName}' is not shown to have type "
-        "'#{shownType}' because '#{shownType}' is not more specific than the "
-        "known type '#{knownType}' of '#{variableName}'.",
-    'howToFix': "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'.",
-  },
-
-  'NO_COMMON_SUBTYPES': {
-    'id': 'XKJOEC',
-    'template': "Types '#{left}' and '#{right}' have no common subtypes.",
-  },
-
-  'HIDDEN_WARNINGS_HINTS': {
-    'id': 'JBAWEK',
-    'template':
-        "#{warnings} warning(s) and #{hints} hint(s) suppressed in #{uri}.",
-  },
-
-  'HIDDEN_WARNINGS': {
-    'id': 'JIYWDC',
-    'template': "#{warnings} warning(s) suppressed in #{uri}.",
-  },
-
-  'HIDDEN_HINTS': {
-    'id': 'RHNXQT',
-    'template': "#{hints} hint(s) suppressed in #{uri}.",
-  },
-
-  'PREAMBLE': {
-    'id': 'GXGWIF',
-    'template': "When run on the command-line, the compiled output might"
-        " require a preamble file located in:\n"
-        "  <sdk>/lib/_internal/js_runtime/lib/preambles.",
-  },
-
-  'INVALID_SYNC_MODIFIER': {
-    'id': 'FNYUYU',
-    'template': "Invalid modifier 'sync'.",
-    'howToFix': "Try replacing 'sync' with 'sync*'.",
-    'examples': ["main() sync {}"],
-  },
-
-  'INVALID_AWAIT_FOR': {
-    'id': 'IEYGCY',
-    'template': "'await' is only supported on for-in loops.",
-    'howToFix': "Try rewriting the loop as a for-in loop or removing the "
-        "'await' keyword.",
-    'examples': [
-      """
-main() async* {
-await for (int i = 0; i < 10; i++) {}
-}
-"""
-    ],
-  },
-
-  'INVALID_AWAIT_FOR_IN': {
-    'id': 'FIEYGC',
-    'template': "'await' is only supported in methods with an 'async' or "
-                "'async*' body modifier.",
-    'howToFix': "Try adding 'async' or 'async*' to the method body or "
-                "removing the 'await' keyword.",
-    'examples': [
-      """
-main(o) sync* {
-  await for (var e in o) {}
-}
-"""
-    ],
-  },
-
-  'INVALID_AWAIT': {
-    'id': 'IEYHYD',
-    'template': "'await' is only supported in methods with an 'async' or "
-                "'async*' body modifier.",
-    'howToFix': "Try adding 'async' or 'async*' to the method body.",
-    'examples': [
-      """
-main() sync* {
-  await null;
-}
-"""
-    ],
-  },
-
-  'INVALID_YIELD': {
-    'id': 'IPGGCY',
-    'template': "'yield' is only supported in methods with a 'sync*' or "
-                "'async*' body modifier.",
-    'howToFix': "Try adding 'sync*' or 'async*' to the method body.",
-    'examples': [
-      """
-main() async {
-  yield 0;
-}
-"""
-    ],
-  },
-
-  'ASYNC_MODIFIER_ON_ABSTRACT_METHOD': {
-    'id': 'VRISLY',
-    'template':
-        "The modifier '#{modifier}' is not allowed on an abstract method.",
-    'options': ['--enable-async'],
-    'howToFix': "Try removing the '#{modifier}' modifier or adding a "
-        "body to the method.",
-    'examples': [
-      """
-abstract class A {
-method() async;
-}
-class B extends A {
-method() {}
-}
-main() {
-A a = new B();
-a.method();
-}
-"""
-    ],
-  },
-
-  'ASYNC_MODIFIER_ON_CONSTRUCTOR': {
-    'id': 'DHCFON',
-    'template': "The modifier '#{modifier}' is not allowed on constructors.",
-    'options': ['--enable-async'],
-    'howToFix': "Try removing the '#{modifier}' modifier.",
-    'examples': [
-      """
-class A {
-A() async;
-}
-main() => new A();""",
-      """
-class A {
-A();
-factory A.a() async* {}
-}
-main() => new A.a();"""
-    ],
-  },
-
-  'ASYNC_MODIFIER_ON_SETTER': {
-    'id': 'NMJLJE',
-    'template': "The modifier '#{modifier}' is not allowed on setters.",
-    'options': ['--enable-async'],
-    'howToFix': "Try removing the '#{modifier}' modifier.",
-    'examples': [
-      """
-class A {
-set foo(v) async {}
-}
-main() => new A().foo = 0;"""
-    ],
-  },
-
-  'YIELDING_MODIFIER_ON_ARROW_BODY': {
-    'id': 'UOGLUX',
-    'template':
-        "The modifier '#{modifier}' is not allowed on methods implemented "
-        "using '=>'.",
-    'options': ['--enable-async'],
-    'howToFix': "Try removing the '#{modifier}' modifier or implementing "
-        "the method body using a block: '{ ... }'.",
-    'examples': ["main() sync* => null;", "main() async* => null;"],
-  },
-
-  // TODO(johnniwinther): Check for 'async' as identifier.
-  'ASYNC_KEYWORD_AS_IDENTIFIER': {
-    'id': 'VTWSMA',
-    'template':
-        "'#{keyword}' cannot be used as an identifier in a function body "
-        "marked with '#{modifier}'.",
-    'options': ['--enable-async'],
-    'howToFix': "Try removing the '#{modifier}' modifier or renaming the "
-        "identifier.",
-    'examples': [
-      """
-main() async {
-var await;
-}""",
-      """
-main() async* {
-var yield;
-}""",
-      """
-main() sync* {
-var yield;
-}"""
-    ],
-  },
-
-  'RETURN_IN_GENERATOR': {
-    'id': 'AWGUVF',
-    'template':
-        "'return' with a value is not allowed in a method body using the "
-        "'#{modifier}' modifier.",
-    'howToFix': "Try removing the value, replacing 'return' with 'yield' "
-        "or changing the method body modifier.",
-    'examples': [
-      """
-foo() async* { return 0; }
-main() => foo();
-""",
-      """
-foo() sync* { return 0; }
-main() => foo();
-"""
-    ],
-  },
-
-  'NATIVE_NOT_SUPPORTED': {
-    'id': 'QMMLUT',
-    'template': "'native' modifier is not supported.",
-    'howToFix': "Try removing the 'native' implementation or analyzing the "
-        "code with the --allow-native-extensions option.",
-    'examples': [
-      """
-main() native "Main";
-"""
-    ],
-  },
-
-  'DART_EXT_NOT_SUPPORTED': {
-    'id': 'JLPQFJ',
-    'template': "The 'dart-ext' scheme is not supported.",
-    'howToFix': "Try analyzing the code with the --allow-native-extensions "
-        "option.",
-    'examples': [
-      """
-import 'dart-ext:main';
-
-main() {}
-"""
-    ],
-  },
-
-  'LIBRARY_TAG_MUST_BE_FIRST': {
-    'id': 'JFUSRX',
-    'template':
-        "The library declaration should come before other declarations.",
-    'howToFix': "Try moving the declaration to the top of the file.",
-    'examples': [
-      """
-import 'dart:core';
-library foo;
-main() {}
-""",
-    ],
-  },
-
-  'ONLY_ONE_LIBRARY_TAG': {
-    'id': 'CCXFMY',
-    'template': "There can only be one library declaration.",
-    'howToFix': "Try removing all other library declarations.",
-    'examples': [
-      """
-library foo;
-library bar;
-main() {}
-""",
-      """
-library foo;
-import 'dart:core';
-library bar;
-main() {}
-""",
-    ],
-  },
-
-  'IMPORT_BEFORE_PARTS': {
-    'id': 'NSMOQI',
-    'template': "Import declarations should come before parts.",
-    'howToFix': "Try moving this import further up in the file.",
-    'examples': [
-      {
-        'main.dart': """
-library test.main;
-part 'part.dart';
-import 'dart:core';
-main() {}
-""",
-        'part.dart': """
-part of test.main;
-""",
-      }
-    ],
-  },
-
-  'EXPORT_BEFORE_PARTS': {
-    'id': 'KYJTTC',
-    'template': "Export declarations should come before parts.",
-    'howToFix': "Try moving this export further up in the file.",
-    'examples': [
-      {
-        'main.dart': """
-library test.main;
-part 'part.dart';
-export 'dart:core';
-main() {}
-""",
-        'part.dart': """
-part of test.main;
-""",
-      }
-    ],
-
-//////////////////////////////////////////////////////////////////////////////
-// Patch errors start.
-//////////////////////////////////////////////////////////////////////////////
-  },
-
-  'PATCH_RETURN_TYPE_MISMATCH': {
-    'id': 'DTOQDU',
-    'template': "Patch return type '#{patchReturnType}' does not match "
-        "'#{originReturnType}' on origin method '#{methodName}'.",
-  },
-
-  'PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH': {
-    'id': 'KJUUYC',
-    'template': "Required parameter count of patch method "
-        "(#{patchParameterCount}) does not match parameter count on origin "
-        "method '#{methodName}' (#{originParameterCount}).",
-  },
-
-  'PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH': {
-    'id': 'GUTGTE',
-    'template': "Optional parameter count of patch method "
-        "(#{patchParameterCount}) does not match parameter count on origin "
-        "method '#{methodName}' (#{originParameterCount}).",
-  },
-
-  'PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH': {
-    'id': 'MCHEIC',
-    'template': "Optional parameters of origin and patch method "
-        "'#{methodName}' must both be either named or positional.",
-  },
-
-  'PATCH_PARAMETER_MISMATCH': {
-    'id': 'XISHPB',
-    'template': "Patch method parameter '#{patchParameter}' does not match "
-        "'#{originParameter}' on origin method '#{methodName}'.",
-  },
-
-  'PATCH_PARAMETER_TYPE_MISMATCH': {
-    'id': 'UGRBYD',
-    'template': "Patch method parameter '#{parameterName}' type "
-        "'#{patchParameterType}' does not match '#{originParameterType}' on "
-        "origin method '#{methodName}'.",
-  },
-
-  'PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION': {
-    'id': 'WSNMKD',
-    'template': "External method without an implementation.",
-  },
-
-  'PATCH_POINT_TO_FUNCTION': {
-    'id': 'CAVBPN',
-    'template': "This is the function patch '#{functionName}'.",
-  },
-
-  'PATCH_POINT_TO_CLASS': {
-    'id': 'TWDLDX',
-    'template': "This is the class patch '#{className}'.",
-  },
-
-  'PATCH_POINT_TO_GETTER': {
-    'id': 'TRBBNY',
-    'template': "This is the getter patch '#{getterName}'.",
-  },
-
-  'PATCH_POINT_TO_SETTER': {
-    'id': 'DAXDLW',
-    'template': "This is the setter patch '#{setterName}'.",
-  },
-
-  'PATCH_POINT_TO_CONSTRUCTOR': {
-    'id': 'VYQISY',
-    'template': "This is the constructor patch '#{constructorName}'.",
-  },
-
-  'PATCH_POINT_TO_PARAMETER': {
-    'id': 'TFPAGO',
-    'template': "This is the patch parameter '#{parameterName}'.",
-  },
-
-  'PATCH_NON_EXISTING': {
-    'id': 'AWOACF',
-    'template': "Origin does not exist for patch '#{name}'.",
-  },
-
-  // TODO(ahe): Eventually, this error should be removed as it will be
-  // handled by the regular parser.
-  'PATCH_NONPATCHABLE': {
-    'id': 'WQEPJI',
-    'template': "Only classes and functions can be patched.",
-  },
-
-  'PATCH_NON_EXTERNAL': {
-    'id': 'MHLXNK',
-    'template': "Only external functions can be patched.",
-  },
-
-  'PATCH_NON_CLASS': {
-    'id': 'UIALAB',
-    'template': "Patching non-class with class patch '#{className}'.",
-  },
-
-  'PATCH_NON_GETTER': {
-    'id': 'VTNQCJ',
-    'template': "Cannot patch non-getter '#{name}' with getter patch.",
-  },
-
-  'PATCH_NO_GETTER': {
-    'id': 'XOPDHD',
-    'template': "No getter found for getter patch '#{getterName}'.",
-  },
-
-  'PATCH_NON_SETTER': {
-    'id': 'XBOMMN',
-    'template': "Cannot patch non-setter '#{name}' with setter patch.",
-  },
-
-  'PATCH_NO_SETTER': {
-    'id': 'YITARQ',
-    'template': "No setter found for setter patch '#{setterName}'.",
-  },
-
-  'PATCH_NON_CONSTRUCTOR': {
-    'id': 'TWAEQV',
-    'template': "Cannot patch non-constructor with constructor patch "
-        "'#{constructorName}'.",
-  },
-
-  'PATCH_NON_FUNCTION': {
-    'id': 'EDXBPI',
-    'template': "Cannot patch non-function with function patch "
-        "'#{functionName}'.",
-  },
-
-  'INJECTED_PUBLIC_MEMBER': {
-    'id': 'JGMXMI',
-    'template': "Non-patch members in patch libraries must be private.",
-  },
-
-  'EXTERNAL_WITH_BODY': {
-    'id': 'GAVMSQ',
-    'template':
-        "External function '#{functionName}' cannot have a function body.",
-    'options': ["--output-type=dart"],
-    'howToFix': "Try removing the 'external' modifier or the function body.",
-    'examples': [
-      """
-external foo() => 0;
-main() => foo();
-""",
-      """
-external foo() {}
-main() => foo();
-"""
-    ],
-
-//////////////////////////////////////////////////////////////////////////////
-// Patch errors end.
-//////////////////////////////////////////////////////////////////////////////
-  },
-
-  'EXPERIMENTAL_ASSERT_MESSAGE': {
-    'id': 'NENGIS',
-    'template': "Experimental language feature 'assertion with message'"
-        " is not supported.",
-    'howToFix':
-        "Use option '--assert-message' to use assertions with messages.",
-    'examples': [
-      r'''
-main() {
-int n = -7;
-assert(n > 0, 'must be positive: $n');
-}
-'''
-    ],
-  },
-
-  'IMPORT_EXPERIMENTAL_MIRRORS': {
-    'id': 'SCJYPH',
-    'template': '''
-
-****************************************************************
-* WARNING: dart:mirrors support in dart2js is experimental,
-*          and not recommended.
-*          This implementation of mirrors is incomplete,
-*          and often greatly increases the size of the generated
-*          JavaScript code.
-*
-* Your app imports dart:mirrors via:'''
-        '''
-$IMPORT_EXPERIMENTAL_MIRRORS_PADDING#{importChain}
-*
-* You can disable this message by using the --enable-experimental-mirrors
-* command-line flag.
-*
-* To learn what to do next, please visit:
-*    http://dartlang.org/dart2js-reflection
-****************************************************************
-''',
-  },
-
-  'DISALLOWED_LIBRARY_IMPORT': {
-    'id': 'OCSFJU',
-    'template': '''
-Your app imports the unsupported library '#{uri}' via:
-'''
-        '''
-$DISALLOWED_LIBRARY_IMPORT_PADDING#{importChain}
-
-Use the --categories option to support import of '#{uri}'.
-''',
-  },
-
-  'MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND': {
-    'id': 'JBTRRM',
-    'template': """
-dart:mirrors library is not supported when using this backend.
-
-Your app imports dart:mirrors via:"""
-        """
-$MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING#{importChain}""",
-  },
-
-  'CALL_NOT_SUPPORTED_ON_NATIVE_CLASS': {
-    'id': 'HAULDW',
-    'template': "Non-supported 'call' member on a native class, or a "
-        "subclass of a native class.",
-  },
-
-  'DIRECTLY_THROWING_NSM': {
-    'id': 'XLTPCS',
-    'template': "This 'noSuchMethod' implementation is guaranteed to throw an "
-        "exception. The generated code will be smaller if it is "
-        "rewritten.",
-    'howToFix': "Rewrite to "
-        "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'.",
-  },
-
-  'COMPLEX_THROWING_NSM': {
-    'id': 'PLCXVX',
-    'template': "This 'noSuchMethod' implementation is guaranteed to throw an "
-        "exception. The generated code will be smaller and the compiler "
-        "will be able to perform more optimizations if it is rewritten.",
-    'howToFix': "Rewrite to "
-        "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'.",
-  },
-
-  'COMPLEX_RETURNING_NSM': {
-    'id': 'HUTCTQ',
-    'template': "Overriding 'noSuchMethod' causes the compiler to generate "
-        "more code and prevents the compiler from doing some optimizations.",
-    'howToFix': "Consider removing this 'noSuchMethod' implementation."
-  },
-
-  'UNRECOGNIZED_VERSION_OF_LOOKUP_MAP': {
-    'id': 'OVAFEW',
-    'template': "Unsupported version of package:lookup_map.",
-    'howToFix': DONT_KNOW_HOW_TO_FIX
-  },
-};
diff --git a/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart b/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart
new file mode 100644
index 0000000..13d4c95
--- /dev/null
+++ b/pkg/compiler/lib/src/diagnostics/generated/shared_messages.dart
@@ -0,0 +1,123 @@
+// 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.
+/*
+DON'T EDIT. GENERATED. DON'T EDIT.
+This file has been generated by 'publish.dart' in the dart_messages package.
+
+Messages are maintained in `lib/shared_messages.dart` of that same package.
+After any change to that file, run `bin/publish.dart` to generate a new version
+of the json, dart2js and analyzer representations.
+*/
+import '../messages.dart' show MessageKind, MessageTemplate;
+
+const Map<MessageKind, MessageTemplate> TEMPLATES = const <MessageKind, MessageTemplate>{ 
+  MessageKind.CONST_CONSTRUCTOR_OR_FACTORY_WITH_BODY: const MessageTemplate(
+    MessageKind.CONST_CONSTRUCTOR_OR_FACTORY_WITH_BODY,
+    "Const constructor or factory can't have a body.",
+    howToFix: "Remove the 'const' keyword or the body.",
+    examples: const [
+      r"""
+         class C {
+           const C() {}
+         }
+
+         main() => new C();""",
+      r"""
+         class C {
+           const factory C() {}
+         }
+
+         main() => new C();""",
+    ]
+  ),  // Generated. Don't edit.
+  MessageKind.EXTRANEOUS_MODIFIER: const MessageTemplate(
+    MessageKind.EXTRANEOUS_MODIFIER,
+    "Can't have modifier '#{modifier}' here.",
+    howToFix: "Try removing '#{modifier}'.",
+    examples: const [
+      "var String foo; main(){}",
+      "var set foo; main(){}",
+      "var final foo; main(){}",
+      "var var foo; main(){}",
+      "var const foo; main(){}",
+      "var abstract foo; main(){}",
+      "var static foo; main(){}",
+      "var external foo; main(){}",
+      "get var foo; main(){}",
+      "set var foo; main(){}",
+      "final var foo; main(){}",
+      "var var foo; main(){}",
+      "const var foo; main(){}",
+      "abstract var foo; main(){}",
+      "static var foo; main(){}",
+      "external var foo; main(){}",
+    ]
+  ),  // Generated. Don't edit.
+  MessageKind.EXTRANEOUS_MODIFIER_REPLACE: const MessageTemplate(
+    MessageKind.EXTRANEOUS_MODIFIER_REPLACE,
+    "Can't have modifier '#{modifier}' here.",
+    howToFix: "Try replacing modifier '#{modifier}' with 'var', 'final', or a type.",
+    examples: const [
+      "set foo; main(){}",
+      "abstract foo; main(){}",
+      "static foo; main(){}",
+      "external foo; main(){}",
+    ]
+  ),  // Generated. Don't edit.
+  MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE: const MessageTemplate(
+    MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE,
+    "Constructors can't have a return type",
+    howToFix: "Try removing the return type.",
+    examples: const [
+      "class A { int A() {} } main() { new A(); }",
+    ]
+  ),  // Generated. Don't edit.
+  MessageKind.MISSING_EXPRESSION_IN_THROW: const MessageTemplate(
+    MessageKind.MISSING_EXPRESSION_IN_THROW,
+    "Missing expression after 'throw'.",
+    howToFix: "Did you mean 'rethrow'?",
+    examples: const [
+      "main() { throw; }",
+      "main() { try { throw 0; } catch(e) { throw; } }",
+    ]
+  ),  // Generated. Don't edit.
+  MessageKind.RETHROW_OUTSIDE_CATCH: const MessageTemplate(
+    MessageKind.RETHROW_OUTSIDE_CATCH,
+    "Rethrow must be inside of catch clause",
+    howToFix: "Try moving the expression into a catch clause, or using a 'throw' expression.",
+    examples: const [
+      "main() { rethrow; }",
+    ]
+  ),  // Generated. Don't edit.
+  MessageKind.RETURN_IN_GENERATIVE_CONSTRUCTOR: const MessageTemplate(
+    MessageKind.RETURN_IN_GENERATIVE_CONSTRUCTOR,
+    "Constructors can't return values.",
+    howToFix: "Try removing the return statement or using a factory constructor.",
+    examples: const [
+      r"""
+        class C {
+          C() {
+            return 1;
+          }
+        }
+
+        main() => new C();""",
+    ]
+  ),  // Generated. Don't edit.
+  MessageKind.RETURN_IN_GENERATOR: const MessageTemplate(
+    MessageKind.RETURN_IN_GENERATOR,
+    "Can't return a value from a generator function (using the '#{modifier}' modifier).",
+    howToFix: "Try removing the value, replacing 'return' with 'yield' or changing the method body modifier",
+    examples: const [
+      r"""
+        foo() async* { return 0; }
+        main() => foo();
+        """,
+      r"""
+        foo() sync* { return 0; }
+        main() => foo();
+        """,
+    ]
+  ),  // Generated. Don't edit.
+};
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index b529e1c..84e9cc2 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -2,16 +2,79 @@
 // 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.
 
+
+/**
+ * The messages in this file should meet the following guide lines:
+ *
+ * 1. The message should be a complete sentence starting with an uppercase
+ * letter, and ending with a period.
+ *
+ * 2. Reserved words and embedded identifiers should be in single quotes, so
+ * prefer double quotes for the complete message. For example, "The
+ * class '#{className}' can't use 'super'." Notice that the word 'class' in the
+ * preceding message is not quoted as it refers to the concept 'class', not the
+ * reserved word. On the other hand, 'super' refers to the reserved word. Do
+ * not quote 'null' and numeric literals.
+ *
+ * 3. Do not try to compose messages, as it can make translating them hard.
+ *
+ * 4. Try to keep the error messages short, but informative.
+ *
+ * 5. Use simple words and terminology, assume the reader of the message
+ * doesn't have an advanced degree in math, and that English is not the
+ * reader's native language. Do not assume any formal computer science
+ * training. For example, do not use Latin abbreviations (prefer "that is" over
+ * "i.e.", and "for example" over "e.g."). Also avoid phrases such as "if and
+ * only if" and "iff", that level of precision is unnecessary.
+ *
+ * 6. Prefer contractions when they are in common use, for example, prefer
+ * "can't" over "cannot". Using "cannot", "must not", "shall not", etc. is
+ * off-putting to people new to programming.
+ *
+ * 7. Use common terminology, preferably from the Dart Language
+ * Specification. This increases the user's chance of finding a good
+ * explanation on the web.
+ *
+ * 8. Do not try to be cute or funny. It is extremely frustrating to work on a
+ * product that crashes with a "tongue-in-cheek" message, especially if you did
+ * not want to use this product to begin with.
+ *
+ * 9. Do not lie, that is, do not write error messages containing phrases like
+ * "can't happen".  If the user ever saw this message, it would be a
+ * lie. Prefer messages like: "Internal error: This function should not be
+ * called when 'x' is null.".
+ *
+ * 10. Prefer to not use imperative tone. That is, the message should not sound
+ * accusing or like it is ordering the user around. The computer should
+ * describe the problem, not criticize for violating the specification.
+ *
+ * Other things to keep in mind:
+ *
+ * An INFO message should always be preceded by a non-INFO message, and the
+ * INFO messages are additional details about the preceding non-INFO
+ * message. For example, consider duplicated elements. First report a WARNING
+ * or ERROR about the duplicated element, and then report an INFO about the
+ * location of the existing element.
+ *
+ * Generally, we want to provide messages that consists of three sentences:
+ * 1. what is wrong, 2. why is it wrong, 3. how do I fix it. However, we
+ * combine the first two in [template] and the last in [howToFix].
+ */
+
 library dart2js.messages;
 
-import 'package:dart_messages/shared_messages.dart' as shared_messages;
+import '../tokens/token.dart' show
+    ErrorToken,
+    Token;
 
-import '../tokens/token.dart' show ErrorToken, Token;
+import 'invariant.dart' show
+    invariant;
+import 'spannable.dart' show
+    CURRENT_ELEMENT_SPANNABLE;
 
-import 'invariant.dart' show invariant;
-import 'spannable.dart' show CURRENT_ELEMENT_SPANNABLE;
+import 'generated/shared_messages.dart' as shared_messages;
 
-import 'dart2js_messages.dart' as dart2js_messages;
+const DONT_KNOW_HOW_TO_FIX = "Computer says no!";
 
 /// Keys for the [MessageTemplate]s.
 enum MessageKind {
@@ -73,7 +136,7 @@
   CANNOT_RESOLVE_IN_INITIALIZER,
   CANNOT_RESOLVE_SETTER,
   CANNOT_RESOLVE_TYPE,
-  CANNOT_RETURN_FROM_CONSTRUCTOR,
+  RETURN_IN_GENERATIVE_CONSTRUCTOR,
   CLASS_NAME_EXPECTED,
   COMPILER_CRASHED,
   COMPLEX_RETURNING_NSM,
@@ -81,7 +144,7 @@
   CONSIDER_ANALYZE_ALL,
   CONST_CALLS_NON_CONST,
   CONST_CALLS_NON_CONST_FOR_IMPLICIT,
-  CONST_CONSTRUCTOR_HAS_BODY,
+  CONST_CONSTRUCTOR_OR_FACTORY_WITH_BODY,
   CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
   CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR,
   CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD,
@@ -225,8 +288,9 @@
   INVALID_YIELD,
   JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS,
   JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER,
-  JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS,
+  JS_INTEROP_INDEX_NOT_SUPPORTED,
   JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS,
+  JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS,
   JS_PLACEHOLDER_CAPTURE,
   LIBRARY_NAME_MISMATCH,
   LIBRARY_NOT_FOUND,
@@ -364,7 +428,7 @@
   THIS_IS_THE_METHOD,
   THIS_IS_THE_PART_OF_TAG,
   THIS_PROPERTY,
-  THROW_WITHOUT_EXPRESSION,
+  RETHROW_OUTSIDE_CATCH,
   TOP_LEVEL_VARIABLE_DECLARED_STATIC,
   TYPE_ARGUMENT_COUNT_MISMATCH,
   TYPE_VARIABLE_IN_CONSTANT,
@@ -389,7 +453,7 @@
   UNSUPPORTED_EQ_EQ_EQ,
   UNSUPPORTED_LITERAL_SYMBOL,
   UNSUPPORTED_PREFIX_PLUS,
-  UNSUPPORTED_THROW_WITHOUT_EXP,
+  MISSING_EXPRESSION_IN_THROW,
   UNTERMINATED_COMMENT,
   UNTERMINATED_STRING,
   UNTERMINATED_TOKEN,
@@ -406,463 +470,6 @@
   YIELDING_MODIFIER_ON_ARROW_BODY,
 }
 
-const _KIND_TO_STRING_MAP = const <MessageKind, String>{
-  MessageKind.ABSTRACT_CLASS_INSTANTIATION: "ABSTRACT_CLASS_INSTANTIATION",
-  MessageKind.ABSTRACT_GETTER: "ABSTRACT_GETTER",
-  MessageKind.ABSTRACT_METHOD: "ABSTRACT_METHOD",
-  MessageKind.ABSTRACT_SETTER: "ABSTRACT_SETTER",
-  MessageKind.ACCESSED_IN_CLOSURE: "ACCESSED_IN_CLOSURE",
-  MessageKind.ACCESSED_IN_CLOSURE_HERE: "ACCESSED_IN_CLOSURE_HERE",
-  MessageKind.ADDITIONAL_ARGUMENT: "ADDITIONAL_ARGUMENT",
-  MessageKind.ADDITIONAL_TYPE_ARGUMENT: "ADDITIONAL_TYPE_ARGUMENT",
-  MessageKind.ALREADY_INITIALIZED: "ALREADY_INITIALIZED",
-  MessageKind.AMBIGUOUS_LOCATION: "AMBIGUOUS_LOCATION",
-  MessageKind.AMBIGUOUS_REEXPORT: "AMBIGUOUS_REEXPORT",
-  MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS:
-      "ASSERT_IS_GIVEN_NAMED_ARGUMENTS",
-  MessageKind.ASSIGNING_FINAL_FIELD_IN_SUPER: "ASSIGNING_FINAL_FIELD_IN_SUPER",
-  MessageKind.ASSIGNING_METHOD: "ASSIGNING_METHOD",
-  MessageKind.ASSIGNING_METHOD_IN_SUPER: "ASSIGNING_METHOD_IN_SUPER",
-  MessageKind.ASSIGNING_TYPE: "ASSIGNING_TYPE",
-  MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER: "ASYNC_KEYWORD_AS_IDENTIFIER",
-  MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD:
-      "ASYNC_MODIFIER_ON_ABSTRACT_METHOD",
-  MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR: "ASYNC_MODIFIER_ON_CONSTRUCTOR",
-  MessageKind.ASYNC_MODIFIER_ON_SETTER: "ASYNC_MODIFIER_ON_SETTER",
-  MessageKind.AWAIT_MEMBER_NOT_FOUND: "AWAIT_MEMBER_NOT_FOUND",
-  MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE:
-      "AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE",
-  MessageKind.BAD_INPUT_CHARACTER: "BAD_INPUT_CHARACTER",
-  MessageKind.BEFORE_TOP_LEVEL: "BEFORE_TOP_LEVEL",
-  MessageKind.BINARY_OPERATOR_BAD_ARITY: "BINARY_OPERATOR_BAD_ARITY",
-  MessageKind.BODY_EXPECTED: "BODY_EXPECTED",
-  MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS:
-      "CALL_NOT_SUPPORTED_ON_NATIVE_CLASS",
-  MessageKind.CANNOT_EXTEND: "CANNOT_EXTEND",
-  MessageKind.CANNOT_EXTEND_ENUM: "CANNOT_EXTEND_ENUM",
-  MessageKind.CANNOT_EXTEND_MALFORMED: "CANNOT_EXTEND_MALFORMED",
-  MessageKind.CANNOT_FIND_CONSTRUCTOR: "CANNOT_FIND_CONSTRUCTOR",
-  MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR:
-      "CANNOT_FIND_UNNAMED_CONSTRUCTOR",
-  MessageKind.CANNOT_IMPLEMENT: "CANNOT_IMPLEMENT",
-  MessageKind.CANNOT_IMPLEMENT_ENUM: "CANNOT_IMPLEMENT_ENUM",
-  MessageKind.CANNOT_IMPLEMENT_MALFORMED: "CANNOT_IMPLEMENT_MALFORMED",
-  MessageKind.CANNOT_INSTANTIATE_ENUM: "CANNOT_INSTANTIATE_ENUM",
-  MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE:
-      "CANNOT_INSTANTIATE_TYPE_VARIABLE",
-  MessageKind.CANNOT_INSTANTIATE_TYPEDEF: "CANNOT_INSTANTIATE_TYPEDEF",
-  MessageKind.CANNOT_MIXIN: "CANNOT_MIXIN",
-  MessageKind.CANNOT_MIXIN_ENUM: "CANNOT_MIXIN_ENUM",
-  MessageKind.CANNOT_MIXIN_MALFORMED: "CANNOT_MIXIN_MALFORMED",
-  MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD:
-      "CANNOT_OVERRIDE_FIELD_WITH_METHOD",
-  MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT:
-      "CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT",
-  MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD:
-      "CANNOT_OVERRIDE_GETTER_WITH_METHOD",
-  MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT:
-      "CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT",
-  MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD:
-      "CANNOT_OVERRIDE_METHOD_WITH_FIELD",
-  MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT:
-      "CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT",
-  MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER:
-      "CANNOT_OVERRIDE_METHOD_WITH_GETTER",
-  MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT:
-      "CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT",
-  MessageKind.CANNOT_RESOLVE: "CANNOT_RESOLVE",
-  MessageKind.CANNOT_RESOLVE_AWAIT: "CANNOT_RESOLVE_AWAIT",
-  MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE:
-      "CANNOT_RESOLVE_AWAIT_IN_CLOSURE",
-  MessageKind.CANNOT_RESOLVE_CONSTRUCTOR: "CANNOT_RESOLVE_CONSTRUCTOR",
-  MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT:
-      "CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT",
-  MessageKind.CANNOT_RESOLVE_GETTER: "CANNOT_RESOLVE_GETTER",
-  MessageKind.CANNOT_RESOLVE_IN_INITIALIZER: "CANNOT_RESOLVE_IN_INITIALIZER",
-  MessageKind.CANNOT_RESOLVE_SETTER: "CANNOT_RESOLVE_SETTER",
-  MessageKind.CANNOT_RESOLVE_TYPE: "CANNOT_RESOLVE_TYPE",
-  MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR: "CANNOT_RETURN_FROM_CONSTRUCTOR",
-  MessageKind.CLASS_NAME_EXPECTED: "CLASS_NAME_EXPECTED",
-  MessageKind.COMPILER_CRASHED: "COMPILER_CRASHED",
-  MessageKind.COMPLEX_RETURNING_NSM: "COMPLEX_RETURNING_NSM",
-  MessageKind.COMPLEX_THROWING_NSM: "COMPLEX_THROWING_NSM",
-  MessageKind.CONSIDER_ANALYZE_ALL: "CONSIDER_ANALYZE_ALL",
-  MessageKind.CONST_CALLS_NON_CONST: "CONST_CALLS_NON_CONST",
-  MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT:
-      "CONST_CALLS_NON_CONST_FOR_IMPLICIT",
-  MessageKind.CONST_CONSTRUCTOR_HAS_BODY: "CONST_CONSTRUCTOR_HAS_BODY",
-  MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS:
-      "CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS",
-  MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR:
-      "CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR",
-  MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD:
-      "CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD",
-  MessageKind.CONST_LOOP_VARIABLE: "CONST_LOOP_VARIABLE",
-  MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS: "CONST_MAP_KEY_OVERRIDES_EQUALS",
-  MessageKind.CONST_WITHOUT_INITIALIZER: "CONST_WITHOUT_INITIALIZER",
-  MessageKind.CONSTRUCTOR_CALL_EXPECTED: "CONSTRUCTOR_CALL_EXPECTED",
-  MessageKind.CONSTRUCTOR_IS_NOT_CONST: "CONSTRUCTOR_IS_NOT_CONST",
-  MessageKind.CONSTRUCTOR_WITH_RETURN_TYPE: "CONSTRUCTOR_WITH_RETURN_TYPE",
-  MessageKind.CYCLIC_CLASS_HIERARCHY: "CYCLIC_CLASS_HIERARCHY",
-  MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS: "CYCLIC_COMPILE_TIME_CONSTANTS",
-  MessageKind.CYCLIC_REDIRECTING_FACTORY: "CYCLIC_REDIRECTING_FACTORY",
-  MessageKind.CYCLIC_TYPE_VARIABLE: "CYCLIC_TYPE_VARIABLE",
-  MessageKind.CYCLIC_TYPEDEF: "CYCLIC_TYPEDEF",
-  MessageKind.CYCLIC_TYPEDEF_ONE: "CYCLIC_TYPEDEF_ONE",
-  MessageKind.DART_EXT_NOT_SUPPORTED: "DART_EXT_NOT_SUPPORTED",
-  MessageKind.DEFERRED_COMPILE_TIME_CONSTANT: "DEFERRED_COMPILE_TIME_CONSTANT",
-  MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION:
-      "DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION",
-  MessageKind.DEFERRED_LIBRARY_DART_2_DART: "DEFERRED_LIBRARY_DART_2_DART",
-  MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX:
-      "DEFERRED_LIBRARY_DUPLICATE_PREFIX",
-  MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX:
-      "DEFERRED_LIBRARY_WITHOUT_PREFIX",
-  MessageKind.DEFERRED_OLD_SYNTAX: "DEFERRED_OLD_SYNTAX",
-  MessageKind.DEFERRED_TYPE_ANNOTATION: "DEFERRED_TYPE_ANNOTATION",
-  MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX:
-      "DEPRECATED_TYPEDEF_MIXIN_SYNTAX",
-  MessageKind.DIRECTLY_THROWING_NSM: "DIRECTLY_THROWING_NSM",
-  MessageKind.DISALLOWED_LIBRARY_IMPORT: "DISALLOWED_LIBRARY_IMPORT",
-  MessageKind.DUPLICATE_DEFINITION: "DUPLICATE_DEFINITION",
-  MessageKind.DUPLICATE_EXPORT: "DUPLICATE_EXPORT",
-  MessageKind.DUPLICATE_EXPORT_CONT: "DUPLICATE_EXPORT_CONT",
-  MessageKind.DUPLICATE_EXPORT_DECL: "DUPLICATE_EXPORT_DECL",
-  MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS: "DUPLICATE_EXTENDS_IMPLEMENTS",
-  MessageKind.DUPLICATE_IMPLEMENTS: "DUPLICATE_IMPLEMENTS",
-  MessageKind.DUPLICATE_IMPORT: "DUPLICATE_IMPORT",
-  MessageKind.DUPLICATE_INITIALIZER: "DUPLICATE_INITIALIZER",
-  MessageKind.DUPLICATE_LABEL: "DUPLICATE_LABEL",
-  MessageKind.DUPLICATE_SUPER_INITIALIZER: "DUPLICATE_SUPER_INITIALIZER",
-  MessageKind.DUPLICATE_TYPE_VARIABLE_NAME: "DUPLICATE_TYPE_VARIABLE_NAME",
-  MessageKind.DUPLICATED_LIBRARY_NAME: "DUPLICATED_LIBRARY_NAME",
-  MessageKind.DUPLICATED_LIBRARY_RESOURCE: "DUPLICATED_LIBRARY_RESOURCE",
-  MessageKind.DUPLICATED_PART_OF: "DUPLICATED_PART_OF",
-  MessageKind.DUPLICATED_RESOURCE: "DUPLICATED_RESOURCE",
-  MessageKind.EMPTY_CATCH_DECLARATION: "EMPTY_CATCH_DECLARATION",
-  MessageKind.EMPTY_ENUM_DECLARATION: "EMPTY_ENUM_DECLARATION",
-  MessageKind.EMPTY_HIDE: "EMPTY_HIDE",
-  MessageKind.EQUAL_MAP_ENTRY_KEY: "EQUAL_MAP_ENTRY_KEY",
-  MessageKind.EMPTY_SHOW: "EMPTY_SHOW",
-  MessageKind.EXISTING_DEFINITION: "EXISTING_DEFINITION",
-  MessageKind.EXISTING_LABEL: "EXISTING_LABEL",
-  MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD:
-      "EXPECTED_IDENTIFIER_NOT_RESERVED_WORD",
-  MessageKind.EXPERIMENTAL_ASSERT_MESSAGE: "EXPERIMENTAL_ASSERT_MESSAGE",
-  MessageKind.EXPONENT_MISSING: "EXPONENT_MISSING",
-  MessageKind.EXPORT_BEFORE_PARTS: "EXPORT_BEFORE_PARTS",
-  MessageKind.EXTERNAL_WITH_BODY: "EXTERNAL_WITH_BODY",
-  MessageKind.EXTRA_CATCH_DECLARATION: "EXTRA_CATCH_DECLARATION",
-  MessageKind.EXTRA_FORMALS: "EXTRA_FORMALS",
-  MessageKind.EXTRANEOUS_MODIFIER: "EXTRANEOUS_MODIFIER",
-  MessageKind.EXTRANEOUS_MODIFIER_REPLACE: "EXTRANEOUS_MODIFIER_REPLACE",
-  MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY:
-      "FACTORY_REDIRECTION_IN_NON_FACTORY",
-  MessageKind.FINAL_FUNCTION_TYPE_PARAMETER: "FINAL_FUNCTION_TYPE_PARAMETER",
-  MessageKind.FINAL_WITHOUT_INITIALIZER: "FINAL_WITHOUT_INITIALIZER",
-  MessageKind.FORIN_NOT_ASSIGNABLE: "FORIN_NOT_ASSIGNABLE",
-  MessageKind.FORMAL_DECLARED_CONST: "FORMAL_DECLARED_CONST",
-  MessageKind.FORMAL_DECLARED_STATIC: "FORMAL_DECLARED_STATIC",
-  MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT:
-      "FUNCTION_TYPE_FORMAL_WITH_DEFAULT",
-  MessageKind.FUNCTION_WITH_INITIALIZER: "FUNCTION_WITH_INITIALIZER",
-  MessageKind.GENERIC: "GENERIC",
-  MessageKind.GETTER_MISMATCH: "GETTER_MISMATCH",
-  MessageKind.GETTER_NOT_FOUND: "GETTER_NOT_FOUND",
-  MessageKind.HEX_DIGIT_EXPECTED: "HEX_DIGIT_EXPECTED",
-  MessageKind.HIDDEN_HINTS: "HIDDEN_HINTS",
-  MessageKind.HIDDEN_IMPLICIT_IMPORT: "HIDDEN_IMPLICIT_IMPORT",
-  MessageKind.HIDDEN_IMPORT: "HIDDEN_IMPORT",
-  MessageKind.HIDDEN_WARNINGS: "HIDDEN_WARNINGS",
-  MessageKind.HIDDEN_WARNINGS_HINTS: "HIDDEN_WARNINGS_HINTS",
-  MessageKind.IF_NULL_ASSIGNING_TYPE: "IF_NULL_ASSIGNING_TYPE",
-  MessageKind.ILLEGAL_CONST_FIELD_MODIFIER: "ILLEGAL_CONST_FIELD_MODIFIER",
-  MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS: "ILLEGAL_CONSTRUCTOR_MODIFIERS",
-  MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER: "ILLEGAL_FINAL_METHOD_MODIFIER",
-  MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS:
-      "ILLEGAL_MIXIN_APPLICATION_MODIFIERS",
-  MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR: "ILLEGAL_MIXIN_CONSTRUCTOR",
-  MessageKind.ILLEGAL_MIXIN_CYCLE: "ILLEGAL_MIXIN_CYCLE",
-  MessageKind.ILLEGAL_MIXIN_OBJECT: "ILLEGAL_MIXIN_OBJECT",
-  MessageKind.ILLEGAL_MIXIN_SUPER_USE: "ILLEGAL_MIXIN_SUPER_USE",
-  MessageKind.ILLEGAL_MIXIN_SUPERCLASS: "ILLEGAL_MIXIN_SUPERCLASS",
-  MessageKind.ILLEGAL_MIXIN_WITH_SUPER: "ILLEGAL_MIXIN_WITH_SUPER",
-  MessageKind.ILLEGAL_SETTER_FORMALS: "ILLEGAL_SETTER_FORMALS",
-  MessageKind.ILLEGAL_STATIC: "ILLEGAL_STATIC",
-  MessageKind.ILLEGAL_SUPER_SEND: "ILLEGAL_SUPER_SEND",
-  MessageKind.IMPORT_BEFORE_PARTS: "IMPORT_BEFORE_PARTS",
-  MessageKind.IMPORT_EXPERIMENTAL_MIRRORS: "IMPORT_EXPERIMENTAL_MIRRORS",
-  MessageKind.IMPORT_PART_OF: "IMPORT_PART_OF",
-  MessageKind.IMPORT_PART_OF_HERE: "IMPORT_PART_OF_HERE",
-  MessageKind.IMPORTED_HERE: "IMPORTED_HERE",
-  MessageKind.INHERIT_GETTER_AND_METHOD: "INHERIT_GETTER_AND_METHOD",
-  MessageKind.INHERITED_EXPLICIT_GETTER: "INHERITED_EXPLICIT_GETTER",
-  MessageKind.INHERITED_IMPLICIT_GETTER: "INHERITED_IMPLICIT_GETTER",
-  MessageKind.INHERITED_METHOD: "INHERITED_METHOD",
-  MessageKind.INJECTED_PUBLIC_MEMBER: "INJECTED_PUBLIC_MEMBER",
-  MessageKind.INIT_STATIC_FIELD: "INIT_STATIC_FIELD",
-  MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED:
-      "INITIALIZING_FORMAL_NOT_ALLOWED",
-  MessageKind.INSTANCE_STATIC_SAME_NAME: "INSTANCE_STATIC_SAME_NAME",
-  MessageKind.INSTANCE_STATIC_SAME_NAME_CONT: "INSTANCE_STATIC_SAME_NAME_CONT",
-  MessageKind.INTERNAL_LIBRARY: "INTERNAL_LIBRARY",
-  MessageKind.INTERNAL_LIBRARY_FROM: "INTERNAL_LIBRARY_FROM",
-  MessageKind.INVALID_ARGUMENT_AFTER_NAMED: "INVALID_ARGUMENT_AFTER_NAMED",
-  MessageKind.INVALID_AWAIT: "INVALID_AWAIT",
-  MessageKind.INVALID_AWAIT_FOR: "INVALID_AWAIT_FOR",
-  MessageKind.INVALID_AWAIT_FOR_IN: "INVALID_AWAIT_FOR_IN",
-  MessageKind.INVALID_BREAK: "INVALID_BREAK",
-  MessageKind.INVALID_CASE_DEFAULT: "INVALID_CASE_DEFAULT",
-  MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS: "INVALID_CONSTRUCTOR_ARGUMENTS",
-  MessageKind.INVALID_CONSTRUCTOR_NAME: "INVALID_CONSTRUCTOR_NAME",
-  MessageKind.INVALID_CONTINUE: "INVALID_CONTINUE",
-  MessageKind.INVALID_FOR_IN: "INVALID_FOR_IN",
-  MessageKind.INVALID_INITIALIZER: "INVALID_INITIALIZER",
-  MessageKind.INVALID_METADATA: "INVALID_METADATA",
-  MessageKind.INVALID_METADATA_GENERIC: "INVALID_METADATA_GENERIC",
-  MessageKind.INVALID_OVERRIDDEN_FIELD: "INVALID_OVERRIDDEN_FIELD",
-  MessageKind.INVALID_OVERRIDDEN_GETTER: "INVALID_OVERRIDDEN_GETTER",
-  MessageKind.INVALID_OVERRIDDEN_METHOD: "INVALID_OVERRIDDEN_METHOD",
-  MessageKind.INVALID_OVERRIDDEN_SETTER: "INVALID_OVERRIDDEN_SETTER",
-  MessageKind.INVALID_OVERRIDE_FIELD: "INVALID_OVERRIDE_FIELD",
-  MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER:
-      "INVALID_OVERRIDE_FIELD_WITH_GETTER",
-  MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER:
-      "INVALID_OVERRIDE_FIELD_WITH_SETTER",
-  MessageKind.INVALID_OVERRIDE_GETTER: "INVALID_OVERRIDE_GETTER",
-  MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD:
-      "INVALID_OVERRIDE_GETTER_WITH_FIELD",
-  MessageKind.INVALID_OVERRIDE_METHOD: "INVALID_OVERRIDE_METHOD",
-  MessageKind.INVALID_OVERRIDE_SETTER: "INVALID_OVERRIDE_SETTER",
-  MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD:
-      "INVALID_OVERRIDE_SETTER_WITH_FIELD",
-  MessageKind.INVALID_PACKAGE_CONFIG: "INVALID_PACKAGE_CONFIG",
-  MessageKind.INVALID_PACKAGE_URI: "INVALID_PACKAGE_URI",
-  MessageKind.INVALID_PARAMETER: "INVALID_PARAMETER",
-  MessageKind.INVALID_RECEIVER_IN_INITIALIZER:
-      "INVALID_RECEIVER_IN_INITIALIZER",
-  MessageKind.INVALID_SOURCE_FILE_LOCATION: "INVALID_SOURCE_FILE_LOCATION",
-  MessageKind.INVALID_SYMBOL: "INVALID_SYMBOL",
-  MessageKind.INVALID_SYNC_MODIFIER: "INVALID_SYNC_MODIFIER",
-  MessageKind.INVALID_TYPE_VARIABLE_BOUND: "INVALID_TYPE_VARIABLE_BOUND",
-  MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME:
-      "INVALID_UNNAMED_CONSTRUCTOR_NAME",
-  MessageKind.INVALID_URI: "INVALID_URI",
-  MessageKind.INVALID_USE_OF_SUPER: "INVALID_USE_OF_SUPER",
-  MessageKind.INVALID_YIELD: "INVALID_YIELD",
-  MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS:
-      "JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS",
-  MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER:
-      "JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER",
-  MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS:
-      "JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS",
-  MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS:
-      "JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS",
-  MessageKind.JS_PLACEHOLDER_CAPTURE: "JS_PLACEHOLDER_CAPTURE",
-  MessageKind.LIBRARY_NAME_MISMATCH: "LIBRARY_NAME_MISMATCH",
-  MessageKind.LIBRARY_NOT_FOUND: "LIBRARY_NOT_FOUND",
-  MessageKind.LIBRARY_NOT_SUPPORTED: "LIBRARY_NOT_SUPPORTED",
-  MessageKind.LIBRARY_TAG_MUST_BE_FIRST: "LIBRARY_TAG_MUST_BE_FIRST",
-  MessageKind.MAIN_HAS_PART_OF: "MAIN_HAS_PART_OF",
-  MessageKind.MAIN_NOT_A_FUNCTION: "MAIN_NOT_A_FUNCTION",
-  MessageKind.MAIN_WITH_EXTRA_PARAMETER: "MAIN_WITH_EXTRA_PARAMETER",
-  MessageKind.MALFORMED_STRING_LITERAL: "MALFORMED_STRING_LITERAL",
-  MessageKind.MEMBER_NOT_FOUND: "MEMBER_NOT_FOUND",
-  MessageKind.MEMBER_NOT_STATIC: "MEMBER_NOT_STATIC",
-  MessageKind.MEMBER_USES_CLASS_NAME: "MEMBER_USES_CLASS_NAME",
-  MessageKind.METHOD_NOT_FOUND: "METHOD_NOT_FOUND",
-  MessageKind.MINUS_OPERATOR_BAD_ARITY: "MINUS_OPERATOR_BAD_ARITY",
-  MessageKind.MIRROR_BLOAT: "MIRROR_BLOAT",
-  MessageKind.MIRROR_IMPORT: "MIRROR_IMPORT",
-  MessageKind.MIRROR_IMPORT_NO_USAGE: "MIRROR_IMPORT_NO_USAGE",
-  MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT: "MIRRORS_CANNOT_FIND_IN_ELEMENT",
-  MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY:
-      "MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY",
-  MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY:
-      "MIRRORS_CANNOT_RESOLVE_IN_LIBRARY",
-  MessageKind.MIRRORS_EXPECTED_STRING: "MIRRORS_EXPECTED_STRING",
-  MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST:
-      "MIRRORS_EXPECTED_STRING_OR_LIST",
-  MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE:
-      "MIRRORS_EXPECTED_STRING_OR_TYPE",
-  MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST:
-      "MIRRORS_EXPECTED_STRING_TYPE_OR_LIST",
-  MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
-      "MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND",
-  MessageKind.MISSING_ARGUMENT: "MISSING_ARGUMENT",
-  MessageKind.MISSING_ENUM_CASES: "MISSING_ENUM_CASES",
-  MessageKind.MISSING_FACTORY_KEYWORD: "MISSING_FACTORY_KEYWORD",
-  MessageKind.MISSING_FORMALS: "MISSING_FORMALS",
-  MessageKind.MISSING_LIBRARY_NAME: "MISSING_LIBRARY_NAME",
-  MessageKind.MISSING_MAIN: "MISSING_MAIN",
-  MessageKind.MISSING_PART_OF_TAG: "MISSING_PART_OF_TAG",
-  MessageKind.MISSING_TOKEN_AFTER_THIS: "MISSING_TOKEN_AFTER_THIS",
-  MessageKind.MISSING_TOKEN_BEFORE_THIS: "MISSING_TOKEN_BEFORE_THIS",
-  MessageKind.MISSING_TYPE_ARGUMENT: "MISSING_TYPE_ARGUMENT",
-  MessageKind.MULTI_INHERITANCE: "MULTI_INHERITANCE",
-  MessageKind.NAMED_ARGUMENT_NOT_FOUND: "NAMED_ARGUMENT_NOT_FOUND",
-  MessageKind.NAMED_FUNCTION_EXPRESSION: "NAMED_FUNCTION_EXPRESSION",
-  MessageKind.NAMED_PARAMETER_WITH_EQUALS: "NAMED_PARAMETER_WITH_EQUALS",
-  MessageKind.NATIVE_NOT_SUPPORTED: "NATIVE_NOT_SUPPORTED",
-  MessageKind.NO_BREAK_TARGET: "NO_BREAK_TARGET",
-  MessageKind.NO_CATCH_NOR_FINALLY: "NO_CATCH_NOR_FINALLY",
-  MessageKind.NO_COMMON_SUBTYPES: "NO_COMMON_SUBTYPES",
-  MessageKind.NO_CONTINUE_TARGET: "NO_CONTINUE_TARGET",
-  MessageKind.NO_INSTANCE_AVAILABLE: "NO_INSTANCE_AVAILABLE",
-  MessageKind.NO_MATCHING_CONSTRUCTOR: "NO_MATCHING_CONSTRUCTOR",
-  MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT:
-      "NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT",
-  MessageKind.NO_STATIC_OVERRIDE: "NO_STATIC_OVERRIDE",
-  MessageKind.NO_STATIC_OVERRIDE_CONT: "NO_STATIC_OVERRIDE_CONT",
-  MessageKind.NO_SUCH_LIBRARY_MEMBER: "NO_SUCH_LIBRARY_MEMBER",
-  MessageKind.NO_SUCH_METHOD_IN_NATIVE: "NO_SUCH_METHOD_IN_NATIVE",
-  MessageKind.NO_SUCH_SUPER_MEMBER: "NO_SUCH_SUPER_MEMBER",
-  MessageKind.NO_SUPER_IN_STATIC: "NO_SUPER_IN_STATIC",
-  MessageKind.NO_THIS_AVAILABLE: "NO_THIS_AVAILABLE",
-  MessageKind.NON_CONST_BLOAT: "NON_CONST_BLOAT",
-  MessageKind.NOT_A_COMPILE_TIME_CONSTANT: "NOT_A_COMPILE_TIME_CONSTANT",
-  MessageKind.NOT_A_FIELD: "NOT_A_FIELD",
-  MessageKind.NOT_A_PREFIX: "NOT_A_PREFIX",
-  MessageKind.NOT_A_TYPE: "NOT_A_TYPE",
-  MessageKind.NOT_ASSIGNABLE: "NOT_ASSIGNABLE",
-  MessageKind.NOT_CALLABLE: "NOT_CALLABLE",
-  MessageKind.NOT_INSTANCE_FIELD: "NOT_INSTANCE_FIELD",
-  MessageKind.NOT_MORE_SPECIFIC: "NOT_MORE_SPECIFIC",
-  MessageKind.NOT_MORE_SPECIFIC_SUBTYPE: "NOT_MORE_SPECIFIC_SUBTYPE",
-  MessageKind.NOT_MORE_SPECIFIC_SUGGESTION: "NOT_MORE_SPECIFIC_SUGGESTION",
-  MessageKind.NULL_NOT_ALLOWED: "NULL_NOT_ALLOWED",
-  MessageKind.ONLY_ONE_LIBRARY_TAG: "ONLY_ONE_LIBRARY_TAG",
-  MessageKind.OPERATOR_NAMED_PARAMETERS: "OPERATOR_NAMED_PARAMETERS",
-  MessageKind.OPERATOR_NOT_FOUND: "OPERATOR_NOT_FOUND",
-  MessageKind.OPERATOR_OPTIONAL_PARAMETERS: "OPERATOR_OPTIONAL_PARAMETERS",
-  MessageKind.OPTIONAL_PARAMETER_IN_CATCH: "OPTIONAL_PARAMETER_IN_CATCH",
-  MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE: "OVERRIDE_EQUALS_NOT_HASH_CODE",
-  MessageKind.PARAMETER_NAME_EXPECTED: "PARAMETER_NAME_EXPECTED",
-  MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH:
-      "PARAMETER_WITH_MODIFIER_IN_CATCH",
-  MessageKind.PARAMETER_WITH_TYPE_IN_CATCH: "PARAMETER_WITH_TYPE_IN_CATCH",
-  MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION:
-      "PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION",
-  MessageKind.PATCH_NO_GETTER: "PATCH_NO_GETTER",
-  MessageKind.PATCH_NO_SETTER: "PATCH_NO_SETTER",
-  MessageKind.PATCH_NON_CLASS: "PATCH_NON_CLASS",
-  MessageKind.PATCH_NON_CONSTRUCTOR: "PATCH_NON_CONSTRUCTOR",
-  MessageKind.PATCH_NON_EXISTING: "PATCH_NON_EXISTING",
-  MessageKind.PATCH_NON_EXTERNAL: "PATCH_NON_EXTERNAL",
-  MessageKind.PATCH_NON_FUNCTION: "PATCH_NON_FUNCTION",
-  MessageKind.PATCH_NON_GETTER: "PATCH_NON_GETTER",
-  MessageKind.PATCH_NON_SETTER: "PATCH_NON_SETTER",
-  MessageKind.PATCH_NONPATCHABLE: "PATCH_NONPATCHABLE",
-  MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH:
-      "PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH",
-  MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH:
-      "PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH",
-  MessageKind.PATCH_PARAMETER_MISMATCH: "PATCH_PARAMETER_MISMATCH",
-  MessageKind.PATCH_PARAMETER_TYPE_MISMATCH: "PATCH_PARAMETER_TYPE_MISMATCH",
-  MessageKind.PATCH_POINT_TO_CLASS: "PATCH_POINT_TO_CLASS",
-  MessageKind.PATCH_POINT_TO_CONSTRUCTOR: "PATCH_POINT_TO_CONSTRUCTOR",
-  MessageKind.PATCH_POINT_TO_FUNCTION: "PATCH_POINT_TO_FUNCTION",
-  MessageKind.PATCH_POINT_TO_GETTER: "PATCH_POINT_TO_GETTER",
-  MessageKind.PATCH_POINT_TO_PARAMETER: "PATCH_POINT_TO_PARAMETER",
-  MessageKind.PATCH_POINT_TO_SETTER: "PATCH_POINT_TO_SETTER",
-  MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH:
-      "PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH",
-  MessageKind.PATCH_RETURN_TYPE_MISMATCH: "PATCH_RETURN_TYPE_MISMATCH",
-  MessageKind.PLEASE_REPORT_THE_CRASH: "PLEASE_REPORT_THE_CRASH",
-  MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS:
-      "POSITIONAL_PARAMETER_WITH_EQUALS",
-  MessageKind.POTENTIAL_MUTATION: "POTENTIAL_MUTATION",
-  MessageKind.POTENTIAL_MUTATION_HERE: "POTENTIAL_MUTATION_HERE",
-  MessageKind.POTENTIAL_MUTATION_IN_CLOSURE: "POTENTIAL_MUTATION_IN_CLOSURE",
-  MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE:
-      "POTENTIAL_MUTATION_IN_CLOSURE_HERE",
-  MessageKind.PREAMBLE: "PREAMBLE",
-  MessageKind.PREFIX_AS_EXPRESSION: "PREFIX_AS_EXPRESSION",
-  MessageKind.PRIVATE_ACCESS: "PRIVATE_ACCESS",
-  MessageKind.PRIVATE_IDENTIFIER: "PRIVATE_IDENTIFIER",
-  MessageKind.PRIVATE_NAMED_PARAMETER: "PRIVATE_NAMED_PARAMETER",
-  MessageKind.READ_SCRIPT_ERROR: "READ_SCRIPT_ERROR",
-  MessageKind.READ_SELF_ERROR: "READ_SELF_ERROR",
-  MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE: "REDIRECTING_CONSTRUCTOR_CYCLE",
-  MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY:
-      "REDIRECTING_CONSTRUCTOR_HAS_BODY",
-  MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER:
-      "REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER",
-  MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT:
-      "REDIRECTING_FACTORY_WITH_DEFAULT",
-  MessageKind.REFERENCE_IN_INITIALIZATION: "REFERENCE_IN_INITIALIZATION",
-  MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT:
-      "REQUIRED_PARAMETER_WITH_DEFAULT",
-  MessageKind.RETURN_IN_GENERATOR: "RETURN_IN_GENERATOR",
-  MessageKind.RETURN_NOTHING: "RETURN_NOTHING",
-  MessageKind.RETURN_VALUE_IN_VOID: "RETURN_VALUE_IN_VOID",
-  MessageKind.SETTER_MISMATCH: "SETTER_MISMATCH",
-  MessageKind.SETTER_NOT_FOUND: "SETTER_NOT_FOUND",
-  MessageKind.SETTER_NOT_FOUND_IN_SUPER: "SETTER_NOT_FOUND_IN_SUPER",
-  MessageKind.STATIC_FUNCTION_BLOAT: "STATIC_FUNCTION_BLOAT",
-  MessageKind.STRING_EXPECTED: "STRING_EXPECTED",
-  MessageKind.SUPER_CALL_TO_FACTORY: "SUPER_CALL_TO_FACTORY",
-  MessageKind.SUPER_INITIALIZER_IN_OBJECT: "SUPER_INITIALIZER_IN_OBJECT",
-  MessageKind.SWITCH_CASE_FORBIDDEN: "SWITCH_CASE_FORBIDDEN",
-  MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL: "SWITCH_CASE_TYPES_NOT_EQUAL",
-  MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE:
-      "SWITCH_CASE_TYPES_NOT_EQUAL_CASE",
-  MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS:
-      "SWITCH_CASE_VALUE_OVERRIDES_EQUALS",
-  MessageKind.TERNARY_OPERATOR_BAD_ARITY: "TERNARY_OPERATOR_BAD_ARITY",
-  MessageKind.THIS_CALL_TO_FACTORY: "THIS_CALL_TO_FACTORY",
-  MessageKind.THIS_IS_THE_DECLARATION: "THIS_IS_THE_DECLARATION",
-  MessageKind.THIS_IS_THE_METHOD: "THIS_IS_THE_METHOD",
-  MessageKind.THIS_IS_THE_PART_OF_TAG: "THIS_IS_THE_PART_OF_TAG",
-  MessageKind.THIS_PROPERTY: "THIS_PROPERTY",
-  MessageKind.THROW_WITHOUT_EXPRESSION: "THROW_WITHOUT_EXPRESSION",
-  MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC:
-      "TOP_LEVEL_VARIABLE_DECLARED_STATIC",
-  MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH: "TYPE_ARGUMENT_COUNT_MISMATCH",
-  MessageKind.TYPE_VARIABLE_IN_CONSTANT: "TYPE_VARIABLE_IN_CONSTANT",
-  MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER:
-      "TYPE_VARIABLE_WITHIN_STATIC_MEMBER",
-  MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT: "TYPEDEF_FORMAL_WITH_DEFAULT",
-  MessageKind.UNARY_OPERATOR_BAD_ARITY: "UNARY_OPERATOR_BAD_ARITY",
-  MessageKind.UNBOUND_LABEL: "UNBOUND_LABEL",
-  MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER: "UNIMPLEMENTED_EXPLICIT_GETTER",
-  MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER: "UNIMPLEMENTED_EXPLICIT_SETTER",
-  MessageKind.UNIMPLEMENTED_GETTER: "UNIMPLEMENTED_GETTER",
-  MessageKind.UNIMPLEMENTED_GETTER_ONE: "UNIMPLEMENTED_GETTER_ONE",
-  MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER: "UNIMPLEMENTED_IMPLICIT_GETTER",
-  MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER: "UNIMPLEMENTED_IMPLICIT_SETTER",
-  MessageKind.UNIMPLEMENTED_METHOD: "UNIMPLEMENTED_METHOD",
-  MessageKind.UNIMPLEMENTED_METHOD_CONT: "UNIMPLEMENTED_METHOD_CONT",
-  MessageKind.UNIMPLEMENTED_METHOD_ONE: "UNIMPLEMENTED_METHOD_ONE",
-  MessageKind.UNIMPLEMENTED_SETTER: "UNIMPLEMENTED_SETTER",
-  MessageKind.UNIMPLEMENTED_SETTER_ONE: "UNIMPLEMENTED_SETTER_ONE",
-  MessageKind.UNMATCHED_TOKEN: "UNMATCHED_TOKEN",
-  MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP:
-      "UNRECOGNIZED_VERSION_OF_LOOKUP_MAP",
-  MessageKind.UNSUPPORTED_BANG_EQ_EQ: "UNSUPPORTED_BANG_EQ_EQ",
-  MessageKind.UNSUPPORTED_EQ_EQ_EQ: "UNSUPPORTED_EQ_EQ_EQ",
-  MessageKind.UNSUPPORTED_LITERAL_SYMBOL: "UNSUPPORTED_LITERAL_SYMBOL",
-  MessageKind.UNSUPPORTED_PREFIX_PLUS: "UNSUPPORTED_PREFIX_PLUS",
-  MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP: "UNSUPPORTED_THROW_WITHOUT_EXP",
-  MessageKind.UNTERMINATED_COMMENT: "UNTERMINATED_COMMENT",
-  MessageKind.UNTERMINATED_STRING: "UNTERMINATED_STRING",
-  MessageKind.UNTERMINATED_TOKEN: "UNTERMINATED_TOKEN",
-  MessageKind.UNUSED_CLASS: "UNUSED_CLASS",
-  MessageKind.UNUSED_LABEL: "UNUSED_LABEL",
-  MessageKind.UNUSED_METHOD: "UNUSED_METHOD",
-  MessageKind.UNUSED_TYPEDEF: "UNUSED_TYPEDEF",
-  MessageKind.VAR_FUNCTION_TYPE_PARAMETER: "VAR_FUNCTION_TYPE_PARAMETER",
-  MessageKind.VOID_EXPRESSION: "VOID_EXPRESSION",
-  MessageKind.VOID_NOT_ALLOWED: "VOID_NOT_ALLOWED",
-  MessageKind.VOID_VARIABLE: "VOID_VARIABLE",
-  MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT:
-      "WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT",
-  MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT:
-      "WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT",
-  MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY:
-      "YIELDING_MODIFIER_ON_ARROW_BODY",
-};
-
 /// A message template for an error, warning, hint or info message generated
 /// by the compiler. Each template is associated with a [MessageKind] that
 /// uniquely identifies the message template.
@@ -871,8 +478,6 @@
 class MessageTemplate {
   final MessageKind kind;
 
-  final String id;
-
   /// Should describe what is wrong and why.
   final String template;
 
@@ -892,8 +497,3115 @@
   /// Additional options needed for the examples to work.
   final List<String> options;
 
-  const MessageTemplate(this.kind, this.id, this.template, this.howToFix,
-      this.examples, this.options);
+  const MessageTemplate(
+      this.kind,
+      this.template,
+      {this.howToFix,
+       this.examples,
+       this.options: const <String>[]});
+
+  /// All templates used by the compiler.
+  ///
+  /// The map is complete mapping from [MessageKind] to their corresponding
+  /// [MessageTemplate].
+  // The key type is a union of MessageKind and SharedMessageKind.
+  static final Map<dynamic, MessageTemplate> TEMPLATES =
+      <dynamic, MessageTemplate>{}
+    ..addAll(shared_messages.TEMPLATES)
+    ..addAll(const<MessageKind, MessageTemplate>{
+      /// Do not use this. It is here for legacy and debugging. It violates item
+      /// 4 of the guide lines for error messages in the beginning of the file.
+      MessageKind.GENERIC:
+        const MessageTemplate(MessageKind.GENERIC, '#{text}'),
+
+      MessageKind.NOT_ASSIGNABLE:
+        const MessageTemplate(MessageKind.NOT_ASSIGNABLE,
+          "'#{fromType}' is not assignable to '#{toType}'."),
+
+      MessageKind.FORIN_NOT_ASSIGNABLE:
+        const MessageTemplate(MessageKind.FORIN_NOT_ASSIGNABLE,
+          "The element type '#{currentType}' of '#{expressionType}' "
+          "is not assignable to '#{elementType}'."),
+
+      MessageKind.VOID_EXPRESSION:
+        const MessageTemplate(MessageKind.VOID_EXPRESSION,
+          "Expression does not yield a value."),
+
+      MessageKind.VOID_VARIABLE:
+        const MessageTemplate(MessageKind.VOID_VARIABLE,
+          "Variable cannot be of type void."),
+
+      MessageKind.RETURN_VALUE_IN_VOID:
+        const MessageTemplate(MessageKind.RETURN_VALUE_IN_VOID,
+          "Cannot return value from void function."),
+
+      MessageKind.RETURN_NOTHING:
+        const MessageTemplate(MessageKind.RETURN_NOTHING,
+          "Value of type '#{returnType}' expected."),
+
+      MessageKind.MISSING_ARGUMENT:
+        const MessageTemplate(MessageKind.MISSING_ARGUMENT,
+          "Missing argument of type '#{argumentType}'."),
+
+      MessageKind.ADDITIONAL_ARGUMENT:
+        const MessageTemplate(MessageKind.ADDITIONAL_ARGUMENT,
+          "Additional argument."),
+
+      MessageKind.NAMED_ARGUMENT_NOT_FOUND:
+        const MessageTemplate(MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+          "No named argument '#{argumentName}' found on method."),
+
+      MessageKind.MEMBER_NOT_FOUND:
+        const MessageTemplate(MessageKind.MEMBER_NOT_FOUND,
+          "No member named '#{memberName}' in class '#{className}'."),
+
+      MessageKind.AWAIT_MEMBER_NOT_FOUND:
+        const MessageTemplate(MessageKind.AWAIT_MEMBER_NOT_FOUND,
+          "No member named 'await' in class '#{className}'.",
+          howToFix: "Did you mean to add the 'async' marker "
+                    "to '#{functionName}'?",
+          examples: const ["""
+class A {
+  m() => await -3;
+}
+main() => new A().m();
+"""]),
+
+      MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE:
+        const MessageTemplate(MessageKind.AWAIT_MEMBER_NOT_FOUND_IN_CLOSURE,
+          "No member named 'await' in class '#{className}'.",
+          howToFix: "Did you mean to add the 'async' marker "
+                    "to the enclosing function?",
+          examples: const ["""
+class A {
+  m() => () => await -3;
+}
+main() => new A().m();
+"""]),
+
+      MessageKind.METHOD_NOT_FOUND:
+        const MessageTemplate(MessageKind.METHOD_NOT_FOUND,
+          "No method named '#{memberName}' in class '#{className}'."),
+
+      MessageKind.OPERATOR_NOT_FOUND:
+        const MessageTemplate(MessageKind.OPERATOR_NOT_FOUND,
+          "No operator '#{memberName}' in class '#{className}'."),
+
+      MessageKind.SETTER_NOT_FOUND:
+        const MessageTemplate(MessageKind.SETTER_NOT_FOUND,
+          "No setter named '#{memberName}' in class '#{className}'."),
+
+      MessageKind.SETTER_NOT_FOUND_IN_SUPER:
+        const MessageTemplate(MessageKind.SETTER_NOT_FOUND_IN_SUPER,
+          "No setter named '#{name}' in superclass of '#{className}'."),
+
+      MessageKind.GETTER_NOT_FOUND:
+        const MessageTemplate(MessageKind.GETTER_NOT_FOUND,
+          "No getter named '#{memberName}' in class '#{className}'."),
+
+      MessageKind.NOT_CALLABLE:
+        const MessageTemplate(MessageKind.NOT_CALLABLE,
+          "'#{elementName}' is not callable."),
+
+      MessageKind.MEMBER_NOT_STATIC:
+        const MessageTemplate(MessageKind.MEMBER_NOT_STATIC,
+          "'#{className}.#{memberName}' is not static."),
+
+      MessageKind.NO_INSTANCE_AVAILABLE:
+        const MessageTemplate(MessageKind.NO_INSTANCE_AVAILABLE,
+          "'#{name}' is only available in instance methods."),
+
+      MessageKind.NO_THIS_AVAILABLE:
+        const MessageTemplate(MessageKind.NO_THIS_AVAILABLE,
+          "'this' is only available in instance methods."),
+
+      MessageKind.PRIVATE_ACCESS:
+        const MessageTemplate(MessageKind.PRIVATE_ACCESS,
+          "'#{name}' is declared private within library "
+          "'#{libraryName}'."),
+
+      MessageKind.THIS_IS_THE_DECLARATION:
+        const MessageTemplate(MessageKind.THIS_IS_THE_DECLARATION,
+          "This is the declaration of '#{name}'."),
+
+      MessageKind.THIS_IS_THE_METHOD:
+        const MessageTemplate(MessageKind.THIS_IS_THE_METHOD,
+          "This is the method declaration."),
+
+      MessageKind.CANNOT_RESOLVE:
+        const MessageTemplate(MessageKind.CANNOT_RESOLVE,
+          "Cannot resolve '#{name}'."),
+
+      MessageKind.CANNOT_RESOLVE_AWAIT:
+        const MessageTemplate(MessageKind.CANNOT_RESOLVE_AWAIT,
+          "Cannot resolve '#{name}'.",
+          howToFix: "Did you mean to add the 'async' marker "
+                    "to '#{functionName}'?",
+          examples: const [
+              "main() => await -3;",
+              "foo() => await -3; main() => foo();"
+          ]),
+
+      MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE:
+        const MessageTemplate(MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE,
+          "Cannot resolve '#{name}'.",
+          howToFix: "Did you mean to add the 'async' marker "
+                    "to the enclosing function?",
+          examples: const [
+              "main() { (() => await -3)(); }",
+          ]),
+
+      MessageKind.CANNOT_RESOLVE_IN_INITIALIZER:
+        const MessageTemplate(MessageKind.CANNOT_RESOLVE_IN_INITIALIZER,
+          "Cannot resolve '#{name}'. It would be implicitly looked up on this "
+          "instance, but instances are not available in initializers.",
+          howToFix: "Try correcting the unresolved reference or move the "
+              "initialization to a constructor body.",
+          examples: const ["""
+class A {
+  var test = unresolvedName;
+}
+main() => new A();
+"""]),
+
+      MessageKind.CANNOT_RESOLVE_CONSTRUCTOR:
+        const MessageTemplate(MessageKind.CANNOT_RESOLVE_CONSTRUCTOR,
+          "Cannot resolve constructor '#{constructorName}'."),
+
+      MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT:
+        const MessageTemplate(
+          MessageKind.CANNOT_RESOLVE_CONSTRUCTOR_FOR_IMPLICIT,
+          "cannot resolve constructor '#{constructorName}' "
+          "for implicit super call.",
+          howToFix: "Try explicitly invoking a constructor of the super class",
+          examples: const ["""
+class A {
+  A.foo() {}
+}
+class B extends A {
+  B();
+}
+main() => new B();
+"""]),
+
+      MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME:
+        const MessageTemplate(MessageKind.INVALID_UNNAMED_CONSTRUCTOR_NAME,
+          "Unnamed constructor name must be '#{name}'."),
+
+      MessageKind.INVALID_CONSTRUCTOR_NAME:
+        const MessageTemplate(MessageKind.INVALID_CONSTRUCTOR_NAME,
+          "Constructor name must start with '#{name}'."),
+
+      MessageKind.CANNOT_RESOLVE_TYPE:
+        const MessageTemplate(MessageKind.CANNOT_RESOLVE_TYPE,
+          "Cannot resolve type '#{typeName}'."),
+
+      MessageKind.DUPLICATE_DEFINITION:
+        const MessageTemplate(MessageKind.DUPLICATE_DEFINITION,
+          "Duplicate definition of '#{name}'.",
+          howToFix: "Try to rename or remove this definition.",
+          examples: const ["""
+class C {
+  void f() {}
+  int get f => 1;
+}
+
+main() {
+  new C();
+}
+
+"""]),
+
+      MessageKind.EXISTING_DEFINITION:
+        const MessageTemplate(MessageKind.EXISTING_DEFINITION,
+          "Existing definition of '#{name}'."),
+
+      MessageKind.DUPLICATE_IMPORT:
+        const MessageTemplate(MessageKind.DUPLICATE_IMPORT,
+          "Duplicate import of '#{name}'."),
+
+      MessageKind.HIDDEN_IMPORT:
+        const MessageTemplate(MessageKind.HIDDEN_IMPORT,
+          "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
+          "from library '#{hidingUri}'.",
+          howToFix:
+            "Try adding 'hide #{name}' to the import of '#{hiddenUri}'.",
+          examples: const [
+              const {
+'main.dart':
+"""
+import 'dart:async'; // This imports a class Future.
+import 'future.dart';
+
+void main() => new Future();""",
+
+'future.dart':
+"""
+library future;
+
+class Future {}"""},
+
+          const {
+'main.dart':
+"""
+import 'future.dart';
+import 'dart:async'; // This imports a class Future.
+
+void main() => new Future();""",
+
+'future.dart':
+"""
+library future;
+
+class Future {}"""},
+
+          const {
+'main.dart':
+"""
+import 'export.dart';
+import 'dart:async'; // This imports a class Future.
+
+void main() => new Future();""",
+
+'future.dart':
+"""
+library future;
+
+class Future {}""",
+
+'export.dart':
+"""
+library export;
+
+export 'future.dart';"""},
+
+         const {
+'main.dart':
+"""
+import 'future.dart' as prefix;
+import 'dart:async' as prefix; // This imports a class Future.
+
+void main() => new prefix.Future();""",
+
+'future.dart':
+"""
+library future;
+
+class Future {}"""}]),
+
+
+      MessageKind.HIDDEN_IMPLICIT_IMPORT:
+        const MessageTemplate(MessageKind.HIDDEN_IMPLICIT_IMPORT,
+          "'#{name}' from library '#{hiddenUri}' is hidden by '#{name}' "
+          "from library '#{hidingUri}'.",
+          howToFix: "Try adding an explicit "
+                    "'import \"#{hiddenUri}\" hide #{name}'.",
+          examples: const [
+              const {
+'main.dart':
+"""
+// This hides the implicit import of class Type from dart:core.
+import 'type.dart';
+
+void main() => new Type();""",
+
+'type.dart':
+"""
+library type;
+
+class Type {}"""},
+          const {
+'conflictsWithDart.dart':
+"""
+library conflictsWithDart;
+
+class Duration {
+  static var x = 100;
+}
+""",
+
+'conflictsWithDartAsWell.dart':
+"""
+library conflictsWithDartAsWell;
+
+class Duration {
+  static var x = 100;
+}
+""",
+
+'main.dart':
+r"""
+library testDartConflicts;
+
+import 'conflictsWithDart.dart';
+import 'conflictsWithDartAsWell.dart';
+
+main() {
+  print("Hail Caesar ${Duration.x}");
+}
+"""}]),
+
+      MessageKind.DUPLICATE_EXPORT:
+        const MessageTemplate(MessageKind.DUPLICATE_EXPORT,
+          "Duplicate export of '#{name}'.",
+          howToFix: "Try adding 'hide #{name}' to one of the exports.",
+          examples: const [const {
+'main.dart': """
+export 'decl1.dart';
+export 'decl2.dart';
+
+main() {}""",
+'decl1.dart': "class Class {}",
+'decl2.dart': "class Class {}"}]),
+
+      MessageKind.DUPLICATE_EXPORT_CONT:
+        const MessageTemplate(MessageKind.DUPLICATE_EXPORT_CONT,
+          "This is another export of '#{name}'."),
+
+      MessageKind.DUPLICATE_EXPORT_DECL:
+        const MessageTemplate(MessageKind.DUPLICATE_EXPORT_DECL,
+          "The exported '#{name}' from export #{uriString} is defined here."),
+
+      MessageKind.EMPTY_HIDE:
+        const MessageTemplate(MessageKind.EMPTY_HIDE,
+            "Library '#{uri}' doesn't export a '#{name}' declaration.",
+      howToFix: "Try removing '#{name}' the 'hide' clause.",
+      examples: const [
+        const {
+            'main.dart': """
+import 'dart:core' hide Foo;
+
+main() {}"""},
+        const {
+'main.dart': """
+export 'dart:core' hide Foo;
+
+main() {}"""},
+]),
+
+      MessageKind.EMPTY_SHOW:
+        const MessageTemplate(MessageKind.EMPTY_SHOW,
+            "Library '#{uri}' doesn't export a '#{name}' declaration.",
+      howToFix: "Try removing '#{name}' from the 'show' clause.",
+      examples: const [
+        const {
+            'main.dart': """
+import 'dart:core' show Foo;
+
+main() {}"""},
+        const {
+'main.dart': """
+export 'dart:core' show Foo;
+
+main() {}"""},
+]),
+
+      MessageKind.NOT_A_TYPE:
+        const MessageTemplate(MessageKind.NOT_A_TYPE,
+          "'#{node}' is not a type."),
+
+      MessageKind.NOT_A_PREFIX:
+        const MessageTemplate(MessageKind.NOT_A_PREFIX,
+          "'#{node}' is not a prefix."),
+
+      MessageKind.PREFIX_AS_EXPRESSION:
+        const MessageTemplate(MessageKind.PREFIX_AS_EXPRESSION,
+          "Library prefix '#{prefix}' is not a valid expression."),
+
+      MessageKind.CANNOT_FIND_CONSTRUCTOR:
+        const MessageTemplate(MessageKind.CANNOT_FIND_CONSTRUCTOR,
+          "Cannot find constructor '#{constructorName}' in class "
+          "'#{className}'."),
+
+      MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR:
+        const MessageTemplate(MessageKind.CANNOT_FIND_UNNAMED_CONSTRUCTOR,
+          "Cannot find unnamed constructor in class "
+          "'#{className}'."),
+
+      MessageKind.CYCLIC_CLASS_HIERARCHY:
+        const MessageTemplate(MessageKind.CYCLIC_CLASS_HIERARCHY,
+          "'#{className}' creates a cycle in the class hierarchy."),
+
+      MessageKind.CYCLIC_REDIRECTING_FACTORY:
+        const MessageTemplate(MessageKind.CYCLIC_REDIRECTING_FACTORY,
+          'Redirecting factory leads to a cyclic redirection.'),
+
+      MessageKind.INVALID_RECEIVER_IN_INITIALIZER:
+        const MessageTemplate(MessageKind.INVALID_RECEIVER_IN_INITIALIZER,
+          "Field initializer expected."),
+
+      MessageKind.NO_SUPER_IN_STATIC:
+        const MessageTemplate(MessageKind.NO_SUPER_IN_STATIC,
+          "'super' is only available in instance methods."),
+
+      MessageKind.DUPLICATE_INITIALIZER:
+        const MessageTemplate(MessageKind.DUPLICATE_INITIALIZER,
+          "Field '#{fieldName}' is initialized more than once."),
+
+      MessageKind.ALREADY_INITIALIZED:
+        const MessageTemplate(MessageKind.ALREADY_INITIALIZED,
+          "'#{fieldName}' was already initialized here."),
+
+      MessageKind.INIT_STATIC_FIELD:
+        const MessageTemplate(MessageKind.INIT_STATIC_FIELD,
+          "Cannot initialize static field '#{fieldName}'."),
+
+      MessageKind.NOT_A_FIELD:
+        const MessageTemplate(MessageKind.NOT_A_FIELD,
+          "'#{fieldName}' is not a field."),
+
+      MessageKind.CONSTRUCTOR_CALL_EXPECTED:
+        const MessageTemplate(MessageKind.CONSTRUCTOR_CALL_EXPECTED,
+          "only call to 'this' or 'super' constructor allowed."),
+
+      MessageKind.INVALID_FOR_IN:
+        const MessageTemplate(MessageKind.INVALID_FOR_IN,
+          "Invalid for-in variable declaration."),
+
+      MessageKind.INVALID_INITIALIZER:
+        const MessageTemplate(MessageKind.INVALID_INITIALIZER,
+          "Invalid initializer."),
+
+      MessageKind.FUNCTION_WITH_INITIALIZER:
+        const MessageTemplate(MessageKind.FUNCTION_WITH_INITIALIZER,
+          "Only constructors can have initializers."),
+
+      MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE:
+        const MessageTemplate(MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE,
+          "Cyclic constructor redirection."),
+
+      MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY:
+        const MessageTemplate(MessageKind.REDIRECTING_CONSTRUCTOR_HAS_BODY,
+          "Redirecting constructor can't have a body."),
+
+      MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER:
+        const MessageTemplate(
+          MessageKind.REDIRECTING_CONSTRUCTOR_HAS_INITIALIZER,
+          "Redirecting constructor cannot have other initializers."),
+
+      MessageKind.SUPER_INITIALIZER_IN_OBJECT:
+        const MessageTemplate(MessageKind.SUPER_INITIALIZER_IN_OBJECT,
+          "'Object' cannot have a super initializer."),
+
+      MessageKind.DUPLICATE_SUPER_INITIALIZER:
+        const MessageTemplate(MessageKind.DUPLICATE_SUPER_INITIALIZER,
+          "Cannot have more than one super initializer."),
+
+      MessageKind.SUPER_CALL_TO_FACTORY:
+        const MessageTemplate(MessageKind.SUPER_CALL_TO_FACTORY,
+          "The target of the superinitializer must be a generative "
+          "constructor.",
+          howToFix: "Try calling another constructor on the superclass.",
+          examples: const ["""
+class Super {
+  factory Super() => null;
+}
+class Class extends Super {}
+main() => new Class();
+""", """
+class Super {
+  factory Super() => null;
+}
+class Class extends Super {
+  Class();
+}
+main() => new Class();
+""", """
+class Super {
+  factory Super() => null;
+}
+class Class extends Super {
+  Class() : super();
+}
+main() => new Class();
+""", """
+class Super {
+  factory Super.foo() => null;
+}
+class Class extends Super {
+  Class() : super.foo();
+}
+main() => new Class();
+"""]),
+
+      MessageKind.THIS_CALL_TO_FACTORY:
+        const MessageTemplate(MessageKind.THIS_CALL_TO_FACTORY,
+          "The target of the redirection clause must be a generative "
+          "constructor",
+        howToFix: "Try redirecting to another constructor.",
+        examples: const ["""
+class Class {
+  factory Class() => null;
+  Class.foo() : this();
+}
+main() => new Class.foo();
+""", """
+class Class {
+  factory Class.foo() => null;
+  Class() : this.foo();
+}
+main() => new Class();
+"""]),
+
+      MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS:
+        const MessageTemplate(MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
+          "Arguments do not match the expected parameters of constructor "
+          "'#{constructorName}'."),
+
+      MessageKind.NO_MATCHING_CONSTRUCTOR:
+        const MessageTemplate(MessageKind.NO_MATCHING_CONSTRUCTOR,
+          "'super' call arguments and constructor parameters do not match."),
+
+      MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT:
+        const MessageTemplate(MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT,
+              "Implicit 'super' call arguments and constructor parameters "
+              "do not match."),
+
+      MessageKind.CONST_CALLS_NON_CONST:
+        const MessageTemplate(MessageKind.CONST_CALLS_NON_CONST,
+          "'const' constructor cannot call a non-const constructor."),
+
+      MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT:
+        const MessageTemplate(MessageKind.CONST_CALLS_NON_CONST_FOR_IMPLICIT,
+              "'const' constructor cannot call a non-const constructor. "
+              "This constructor has an implicit call to a "
+              "super non-const constructor.",
+              howToFix: "Try making the super constructor const.",
+              examples: const ["""
+class C {
+  C(); // missing const
+}
+class D extends C {
+  final d;
+  const D(this.d);
+}
+main() => new D(0);"""]),
+
+      MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS:
+        const MessageTemplate(
+          MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS,
+          "Can't declare constructor 'const' on class #{className} "
+          "because the class contains non-final instance fields.",
+          howToFix: "Try making all fields final.",
+          examples: const ["""
+class C {
+  // 'a' must be declared final to allow for the const constructor.
+  var a;
+  const C(this.a);
+}
+
+main() => new C(0);"""]),
+
+      MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD:
+        const MessageTemplate(
+          MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_FIELD,
+          "This non-final field prevents using const constructors."),
+
+      MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR:
+        const MessageTemplate(
+          MessageKind.CONST_CONSTRUCTOR_WITH_NONFINAL_FIELDS_CONSTRUCTOR,
+          "This const constructor is not allowed due to "
+          "non-final fields."),
+
+
+      MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED:
+        const MessageTemplate(MessageKind.INITIALIZING_FORMAL_NOT_ALLOWED,
+          "Initializing formal parameter only allowed in generative "
+          "constructor."),
+
+      MessageKind.INVALID_PARAMETER:
+        const MessageTemplate(MessageKind.INVALID_PARAMETER,
+          "Cannot resolve parameter."),
+
+      MessageKind.NOT_INSTANCE_FIELD:
+        const MessageTemplate(MessageKind.NOT_INSTANCE_FIELD,
+          "'#{fieldName}' is not an instance field."),
+
+      MessageKind.THIS_PROPERTY:
+        const MessageTemplate(MessageKind.THIS_PROPERTY,
+          "Expected an identifier."),
+
+      MessageKind.NO_CATCH_NOR_FINALLY:
+        const MessageTemplate(MessageKind.NO_CATCH_NOR_FINALLY,
+          "Expected 'catch' or 'finally'."),
+
+      MessageKind.EMPTY_CATCH_DECLARATION:
+        const MessageTemplate(MessageKind.EMPTY_CATCH_DECLARATION,
+          "Expected an identifier in catch declaration."),
+
+      MessageKind.EXTRA_CATCH_DECLARATION:
+        const MessageTemplate(MessageKind.EXTRA_CATCH_DECLARATION,
+          "Extra parameter in catch declaration."),
+
+      MessageKind.PARAMETER_WITH_TYPE_IN_CATCH:
+        const MessageTemplate(MessageKind.PARAMETER_WITH_TYPE_IN_CATCH,
+          "Cannot use type annotations in catch."),
+
+      MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH:
+        const MessageTemplate(MessageKind.PARAMETER_WITH_MODIFIER_IN_CATCH,
+          "Cannot use modifiers in catch."),
+
+      MessageKind.OPTIONAL_PARAMETER_IN_CATCH:
+        const MessageTemplate(MessageKind.OPTIONAL_PARAMETER_IN_CATCH,
+          "Cannot use optional parameters in catch."),
+
+      MessageKind.UNBOUND_LABEL:
+        const MessageTemplate(MessageKind.UNBOUND_LABEL,
+          "Cannot resolve label '#{labelName}'."),
+
+      MessageKind.NO_BREAK_TARGET:
+        const MessageTemplate(MessageKind.NO_BREAK_TARGET,
+          "'break' statement not inside switch or loop."),
+
+      MessageKind.NO_CONTINUE_TARGET:
+        const MessageTemplate(MessageKind.NO_CONTINUE_TARGET,
+          "'continue' statement not inside loop."),
+
+      MessageKind.EXISTING_LABEL:
+        const MessageTemplate(MessageKind.EXISTING_LABEL,
+          "Original declaration of duplicate label '#{labelName}'."),
+
+      MessageKind.DUPLICATE_LABEL:
+        const MessageTemplate(MessageKind.DUPLICATE_LABEL,
+          "Duplicate declaration of label '#{labelName}'."),
+
+      MessageKind.UNUSED_LABEL:
+        const MessageTemplate(MessageKind.UNUSED_LABEL,
+          "Unused label '#{labelName}'."),
+
+      MessageKind.INVALID_CONTINUE:
+        const MessageTemplate(MessageKind.INVALID_CONTINUE,
+          "Target of continue is not a loop or switch case."),
+
+      MessageKind.INVALID_BREAK:
+        const MessageTemplate(MessageKind.INVALID_BREAK,
+          "Target of break is not a statement."),
+
+      MessageKind.DUPLICATE_TYPE_VARIABLE_NAME:
+        const MessageTemplate(MessageKind.DUPLICATE_TYPE_VARIABLE_NAME,
+          "Type variable '#{typeVariableName}' already declared."),
+
+      MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER:
+        const MessageTemplate(MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,
+              "Cannot refer to type variable '#{typeVariableName}' "
+              "within a static member."),
+
+      MessageKind.TYPE_VARIABLE_IN_CONSTANT:
+        const MessageTemplate(MessageKind.TYPE_VARIABLE_IN_CONSTANT,
+          "Constant expressions can't refer to type variables.",
+          howToFix: "Try removing the type variable or replacing it with a "
+                    "concrete type.",
+          examples: const ["""
+class C<T> {
+  const C();
+
+  m(T t) => const C<T>();
+}
+
+void main() => new C().m(null);
+"""
+]),
+
+      MessageKind.INVALID_TYPE_VARIABLE_BOUND:
+        const MessageTemplate(MessageKind.INVALID_TYPE_VARIABLE_BOUND,
+          "'#{typeArgument}' is not a subtype of bound '#{bound}' for "
+          "type variable '#{typeVariable}' of type '#{thisType}'.",
+          howToFix: "Try to change or remove the type argument.",
+          examples: const ["""
+class C<T extends num> {}
+
+// 'String' is not a valid instantiation of T with bound num.'.
+main() => new C<String>();
+"""]),
+
+      MessageKind.INVALID_USE_OF_SUPER:
+        const MessageTemplate(MessageKind.INVALID_USE_OF_SUPER,
+          "'super' not allowed here."),
+
+      MessageKind.INVALID_CASE_DEFAULT:
+        const MessageTemplate(MessageKind.INVALID_CASE_DEFAULT,
+          "'default' only allowed on last case of a switch."),
+
+      MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL:
+        const MessageTemplate(MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL,
+          "'case' expressions do not all have type '#{type}'."),
+
+      MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE:
+        const MessageTemplate(MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL_CASE,
+          "'case' expression of type '#{type}'."),
+
+      MessageKind.SWITCH_CASE_FORBIDDEN:
+        const MessageTemplate(MessageKind.SWITCH_CASE_FORBIDDEN,
+          "'case' expression may not be of type '#{type}'."),
+
+      MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS:
+        const MessageTemplate(MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS,
+              "'case' expression type '#{type}' overrides 'operator =='."),
+
+      MessageKind.INVALID_ARGUMENT_AFTER_NAMED:
+        const MessageTemplate(MessageKind.INVALID_ARGUMENT_AFTER_NAMED,
+          "Unnamed argument after named argument."),
+
+      MessageKind.INVALID_AWAIT_FOR_IN:
+        const MessageTemplate(MessageKind.INVALID_AWAIT_FOR_IN,
+          "'await' is only supported in methods with an 'async' or "
+              "'async*' body modifier.",
+          howToFix: "Try adding 'async' or 'async*' to the method body or "
+              "removing the 'await' keyword.",
+          examples: const [
+            """
+main(o) sync* {
+  await for (var e in o) {}
+}"""]),
+
+      MessageKind.INVALID_AWAIT:
+        const MessageTemplate(MessageKind.INVALID_AWAIT,
+          "'await' is only supported in methods with an 'async' or "
+              "'async*' body modifier.",
+          howToFix: "Try adding 'async' or 'async*' to the method body.",
+          examples: const [
+          """
+main(o) sync* {
+  await null;
+}"""]),
+
+      MessageKind.INVALID_YIELD:
+        const MessageTemplate(MessageKind.INVALID_YIELD,
+          "'yield' is only supported in methods with a 'sync*' or "
+              "'async*' body modifier.",
+          howToFix: "Try adding 'sync*' or 'async*' to the method body.",
+          examples: const [
+            """
+main(o) async {
+  yield 0;
+}"""]),
+
+      MessageKind.NOT_A_COMPILE_TIME_CONSTANT:
+        const MessageTemplate(MessageKind.NOT_A_COMPILE_TIME_CONSTANT,
+          "Not a compile-time constant."),
+
+      MessageKind.DEFERRED_COMPILE_TIME_CONSTANT:
+        const MessageTemplate(MessageKind.DEFERRED_COMPILE_TIME_CONSTANT,
+          "A deferred value cannot be used as a compile-time constant."),
+
+      MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION:
+        const MessageTemplate(
+          MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION,
+          "A deferred class cannot be used to create a "
+          "compile-time constant."),
+
+      MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS:
+        const MessageTemplate(MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS,
+          "Cycle in the compile-time constant computation."),
+
+      MessageKind.CONSTRUCTOR_IS_NOT_CONST:
+        const MessageTemplate(MessageKind.CONSTRUCTOR_IS_NOT_CONST,
+          "Constructor is not a 'const' constructor."),
+
+      MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS:
+        const MessageTemplate(MessageKind.CONST_MAP_KEY_OVERRIDES_EQUALS,
+              "Const-map key type '#{type}' overrides 'operator =='."),
+
+      MessageKind.NO_SUCH_LIBRARY_MEMBER:
+        const MessageTemplate(MessageKind.NO_SUCH_LIBRARY_MEMBER,
+          "'#{libraryName}' has no member named '#{memberName}'."),
+
+      MessageKind.CANNOT_INSTANTIATE_TYPEDEF:
+        const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_TYPEDEF,
+          "Cannot instantiate typedef '#{typedefName}'."),
+
+      MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT:
+        const MessageTemplate(MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT,
+          "Non-optional parameters can't have a default value.",
+          howToFix:
+            "Try removing the default value or making the parameter optional.",
+          examples: const ["""
+main() {
+  foo(a: 1) => print(a);
+  foo(2);
+}""", """
+main() {
+  foo(a = 1) => print(a);
+  foo(2);
+}"""]),
+
+      MessageKind.NAMED_PARAMETER_WITH_EQUALS:
+        const MessageTemplate(MessageKind.NAMED_PARAMETER_WITH_EQUALS,
+          "Named optional parameters can't use '=' to specify a default "
+          "value.",
+          howToFix: "Try replacing '=' with ':'.",
+          examples: const ["""
+main() {
+  foo({a = 1}) => print(a);
+  foo(a: 2);
+}"""]),
+
+      MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS:
+        const MessageTemplate(MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS,
+          "Positional optional parameters can't use ':' to specify a "
+          "default value.",
+          howToFix: "Try replacing ':' with '='.",
+          examples: const ["""
+main() {
+  foo([a: 1]) => print(a);
+  foo(2);
+}"""]),
+
+      MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT:
+        const MessageTemplate(MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT,
+          "A parameter of a typedef can't specify a default value.",
+          howToFix:
+            "Try removing the default value.",
+          examples: const ["""
+typedef void F([int arg = 0]);
+
+main() {
+  F f;
+}""", """
+typedef void F({int arg: 0});
+
+main() {
+  F f;
+}"""]),
+
+      MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT:
+        const MessageTemplate(MessageKind.FUNCTION_TYPE_FORMAL_WITH_DEFAULT,
+          "A function type parameter can't specify a default value.",
+          howToFix:
+            "Try removing the default value.",
+          examples: const ["""
+foo(f(int i, [a = 1])) {}
+
+main() {
+  foo(1, 2);
+}""", """
+foo(f(int i, {a: 1})) {}
+
+main() {
+  foo(1, a: 2);
+}"""]),
+
+      MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT:
+        const MessageTemplate(MessageKind.REDIRECTING_FACTORY_WITH_DEFAULT,
+          "A parameter of a redirecting factory constructor can't specify a "
+          "default value.",
+          howToFix:
+            "Try removing the default value.",
+          examples: const ["""
+class A {
+  A([a]);
+  factory A.foo([a = 1]) = A;
+}
+
+main() {
+  new A.foo(1);
+}""", """
+class A {
+  A({a});
+  factory A.foo({a: 1}) = A;
+}
+
+main() {
+  new A.foo(a: 1);
+}"""]),
+
+      MessageKind.FORMAL_DECLARED_CONST:
+        const MessageTemplate(MessageKind.FORMAL_DECLARED_CONST,
+          "A formal parameter can't be declared const.",
+          howToFix: "Try removing 'const'.",
+          examples: const ["""
+foo(const x) {}
+main() => foo(42);
+""", """
+foo({const x}) {}
+main() => foo(42);
+""", """
+foo([const x]) {}
+main() => foo(42);
+"""]),
+
+      MessageKind.FORMAL_DECLARED_STATIC:
+        const MessageTemplate(MessageKind.FORMAL_DECLARED_STATIC,
+          "A formal parameter can't be declared static.",
+          howToFix: "Try removing 'static'.",
+          examples: const ["""
+foo(static x) {}
+main() => foo(42);
+""", """
+foo({static x}) {}
+main() => foo(42);
+""", """
+foo([static x]) {}
+main() => foo(42);
+"""]),
+
+      MessageKind.FINAL_FUNCTION_TYPE_PARAMETER:
+        const MessageTemplate(MessageKind.FINAL_FUNCTION_TYPE_PARAMETER,
+          "A function type parameter can't be declared final.",
+          howToFix: "Try removing 'final'.",
+          examples: const ["""
+foo(final int x(int a)) {}
+main() => foo((y) => 42);
+""", """
+foo({final int x(int a)}) {}
+main() => foo((y) => 42);
+""", """
+foo([final int x(int a)]) {}
+main() => foo((y) => 42);
+"""]),
+
+      MessageKind.VAR_FUNCTION_TYPE_PARAMETER:
+        const MessageTemplate(MessageKind.VAR_FUNCTION_TYPE_PARAMETER,
+          "A function type parameter can't be declared with 'var'.",
+          howToFix: "Try removing 'var'.",
+          examples: const ["""
+foo(var int x(int a)) {}
+main() => foo((y) => 42);
+""", """
+foo({var int x(int a)}) {}
+main() => foo((y) => 42);
+""", """
+foo([var int x(int a)]) {}
+main() => foo((y) => 42);
+"""]),
+
+      MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE:
+        const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_TYPE_VARIABLE,
+          "Cannot instantiate type variable '#{typeVariableName}'."),
+
+      MessageKind.CYCLIC_TYPE_VARIABLE:
+        const MessageTemplate(MessageKind.CYCLIC_TYPE_VARIABLE,
+          "Type variable '#{typeVariableName}' is a supertype of itself."),
+
+      MessageKind.CYCLIC_TYPEDEF:
+        const MessageTemplate(MessageKind.CYCLIC_TYPEDEF,
+          "A typedef can't refer to itself.",
+          howToFix: "Try removing all references to '#{typedefName}' "
+                    "in the definition of '#{typedefName}'.",
+          examples: const ["""
+typedef F F(); // The return type 'F' is a self-reference.
+main() { F f = null; }"""]),
+
+      MessageKind.CYCLIC_TYPEDEF_ONE:
+        const MessageTemplate(MessageKind.CYCLIC_TYPEDEF_ONE,
+          "A typedef can't refer to itself through another typedef.",
+          howToFix:
+            "Try removing all references to "
+            "'#{otherTypedefName}' in the definition of '#{typedefName}'.",
+          examples: const ["""
+typedef G F(); // The return type 'G' is a self-reference through typedef 'G'.
+typedef F G(); // The return type 'F' is a self-reference through typedef 'F'.
+main() { F f = null; }""",
+"""
+typedef G F(); // The return type 'G' creates a self-reference.
+typedef H G(); // The return type 'H' creates a self-reference.
+typedef H(F f); // The argument type 'F' creates a self-reference.
+main() { F f = null; }"""]),
+
+      MessageKind.CLASS_NAME_EXPECTED:
+        const MessageTemplate(MessageKind.CLASS_NAME_EXPECTED,
+          "Class name expected."),
+
+      MessageKind.CANNOT_EXTEND:
+        const MessageTemplate(MessageKind.CANNOT_EXTEND,
+          "'#{type}' cannot be extended."),
+
+      MessageKind.CANNOT_IMPLEMENT:
+        const MessageTemplate(MessageKind.CANNOT_IMPLEMENT,
+          "'#{type}' cannot be implemented."),
+
+      // TODO(johnnwinther): Split messages into reasons for malformedness.
+      MessageKind.CANNOT_EXTEND_MALFORMED:
+        const MessageTemplate(MessageKind.CANNOT_EXTEND_MALFORMED,
+          "Class '#{className}' can't extend the type '#{malformedType}' "
+          "because it is malformed.",
+          howToFix:
+            "Try correcting the malformed type annotation or removing the "
+            "'extends' clause.",
+          examples: const ["""
+class A extends Malformed {}
+main() => new A();"""]),
+
+      MessageKind.CANNOT_IMPLEMENT_MALFORMED:
+        const MessageTemplate(MessageKind.CANNOT_IMPLEMENT_MALFORMED,
+          "Class '#{className}' can't implement the type '#{malformedType}' "
+          "because it is malformed.",
+          howToFix:
+            "Try correcting the malformed type annotation or removing the "
+            "type from the 'implements' clause.",
+          examples: const ["""
+class A implements Malformed {}
+main() => new A();"""]),
+
+      MessageKind.CANNOT_MIXIN_MALFORMED:
+        const MessageTemplate(MessageKind.CANNOT_MIXIN_MALFORMED,
+          "Class '#{className}' can't mixin the type '#{malformedType}' "
+          "because it is malformed.",
+          howToFix:
+            "Try correcting the malformed type annotation or removing the "
+            "type from the 'with' clause.",
+          examples: const ["""
+class A extends Object with Malformed {}
+main() => new A();"""]),
+
+      MessageKind.CANNOT_MIXIN:
+        const MessageTemplate(MessageKind.CANNOT_MIXIN,
+          "The type '#{type}' can't be mixed in.",
+          howToFix: "Try removing '#{type}' from the 'with' clause.",
+          examples: const ["""
+class C extends Object with String {}
+
+main() => new C();
+""", """
+typedef C = Object with String;
+
+main() => new C();
+"""]),
+
+      MessageKind.CANNOT_EXTEND_ENUM:
+        const MessageTemplate(MessageKind.CANNOT_EXTEND_ENUM,
+          "Class '#{className}' can't extend the type '#{enumType}' because "
+          "it is declared by an enum.",
+          howToFix: "Try making '#{enumType}' a normal class or removing the "
+            "'extends' clause.",
+          examples: const ["""
+enum Enum { A }
+class B extends Enum {}
+main() => new B();"""]),
+
+      MessageKind.CANNOT_IMPLEMENT_ENUM:
+        const MessageTemplate(MessageKind.CANNOT_IMPLEMENT_ENUM,
+          "Class '#{className}' can't implement the type '#{enumType}' "
+          "because it is declared by an enum.",
+          howToFix: "Try making '#{enumType}' a normal class or removing the "
+            "type from the 'implements' clause.",
+          examples: const ["""
+enum Enum { A }
+class B implements Enum {}
+main() => new B();"""]),
+
+      MessageKind.CANNOT_MIXIN_ENUM:
+        const MessageTemplate(MessageKind.CANNOT_MIXIN_ENUM,
+          "Class '#{className}' can't mixin the type '#{enumType}' because it "
+          "is declared by an enum.",
+          howToFix: "Try making '#{enumType}' a normal class or removing the "
+            "type from the 'with' clause.",
+          examples: const ["""
+enum Enum { A }
+class B extends Object with Enum {}
+main() => new B();"""]),
+
+      MessageKind.CANNOT_INSTANTIATE_ENUM:
+        const MessageTemplate(MessageKind.CANNOT_INSTANTIATE_ENUM,
+          "Enum type '#{enumName}' cannot be instantiated.",
+          howToFix: "Try making '#{enumType}' a normal class or use an enum "
+                    "constant.",
+          examples: const ["""
+enum Enum { A }
+main() => new Enum(0);""", """
+enum Enum { A }
+main() => const Enum(0);"""]),
+
+      MessageKind.EMPTY_ENUM_DECLARATION:
+        const MessageTemplate(MessageKind.EMPTY_ENUM_DECLARATION,
+          "Enum '#{enumName}' must contain at least one value.",
+          howToFix: "Try adding an enum constant or making #{enumName} a "
+                    "normal class.",
+          examples: const ["""
+enum Enum {}
+main() { Enum e; }"""]),
+
+      MessageKind.MISSING_ENUM_CASES:
+        const MessageTemplate(MessageKind.MISSING_ENUM_CASES,
+          "Missing enum constants in switch statement: #{enumValues}.",
+          howToFix: "Try adding the missing constants or a default case.",
+          examples: const ["""
+enum Enum { A, B }
+main() {
+  switch (Enum.A) {
+  case Enum.B: break;
+  }
+}""", """
+enum Enum { A, B, C }
+main() {
+  switch (Enum.A) {
+  case Enum.B: break;
+  }
+}"""]),
+
+      MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS:
+        const MessageTemplate(MessageKind.DUPLICATE_EXTENDS_IMPLEMENTS,
+          "'#{type}' can not be both extended and implemented."),
+
+      MessageKind.DUPLICATE_IMPLEMENTS:
+        const MessageTemplate(MessageKind.DUPLICATE_IMPLEMENTS,
+          "'#{type}' must not occur more than once "
+          "in the implements clause."),
+
+      MessageKind.MULTI_INHERITANCE:
+        const MessageTemplate(MessageKind.MULTI_INHERITANCE,
+          "Dart2js does not currently support inheritance of the same class "
+          "with different type arguments: Both #{firstType} and #{secondType} "
+          "are supertypes of #{thisType}."),
+
+      MessageKind.ILLEGAL_SUPER_SEND:
+        const MessageTemplate(MessageKind.ILLEGAL_SUPER_SEND,
+          "'#{name}' cannot be called on super."),
+
+      MessageKind.NO_SUCH_SUPER_MEMBER:
+        const MessageTemplate(MessageKind.NO_SUCH_SUPER_MEMBER,
+          "Cannot resolve '#{memberName}' in a superclass of '#{className}'."),
+
+      MessageKind.ADDITIONAL_TYPE_ARGUMENT:
+        const MessageTemplate(MessageKind.ADDITIONAL_TYPE_ARGUMENT,
+          "Additional type argument."),
+
+      MessageKind.MISSING_TYPE_ARGUMENT:
+        const MessageTemplate(MessageKind.MISSING_TYPE_ARGUMENT,
+          "Missing type argument."),
+
+      // TODO(johnniwinther): Use ADDITIONAL_TYPE_ARGUMENT or
+      // MISSING_TYPE_ARGUMENT instead.
+      MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH:
+        const MessageTemplate(MessageKind.TYPE_ARGUMENT_COUNT_MISMATCH,
+          "Incorrect number of type arguments on '#{type}'."),
+
+      MessageKind.GETTER_MISMATCH:
+        const MessageTemplate(MessageKind.GETTER_MISMATCH,
+          "Setter disagrees on: '#{modifiers}'."),
+
+      MessageKind.SETTER_MISMATCH:
+        const MessageTemplate(MessageKind.SETTER_MISMATCH,
+          "Getter disagrees on: '#{modifiers}'."),
+
+      MessageKind.ILLEGAL_SETTER_FORMALS:
+        const MessageTemplate(MessageKind.ILLEGAL_SETTER_FORMALS,
+          "A setter must have exactly one argument."),
+
+      MessageKind.NO_STATIC_OVERRIDE:
+        const MessageTemplate(MessageKind.NO_STATIC_OVERRIDE,
+          "Static member cannot override instance member '#{memberName}' of "
+          "'#{className}'."),
+
+      MessageKind.NO_STATIC_OVERRIDE_CONT:
+        const MessageTemplate(MessageKind.NO_STATIC_OVERRIDE_CONT,
+          "This is the instance member that cannot be overridden "
+          "by a static member."),
+
+      MessageKind.INSTANCE_STATIC_SAME_NAME:
+        const MessageTemplate(MessageKind.INSTANCE_STATIC_SAME_NAME,
+          "Instance member '#{memberName}' and static member of "
+          "superclass '#{className}' have the same name."),
+
+      MessageKind.INSTANCE_STATIC_SAME_NAME_CONT:
+        const MessageTemplate(MessageKind.INSTANCE_STATIC_SAME_NAME_CONT,
+          "This is the static member with the same name."),
+
+      MessageKind.INVALID_OVERRIDE_METHOD:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDE_METHOD,
+          "The type '#{declaredType}' of method '#{name}' declared in "
+          "'#{class}' is not a subtype of the overridden method type "
+          "'#{inheritedType}' inherited from '#{inheritedClass}'."),
+
+      MessageKind.INVALID_OVERRIDDEN_METHOD:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_METHOD,
+          "This is the overridden method '#{name}' declared in class "
+          "'#{class}'."),
+
+      MessageKind.INVALID_OVERRIDE_GETTER:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDE_GETTER,
+          "The type '#{declaredType}' of getter '#{name}' declared in "
+          "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+          "overridden getter inherited from '#{inheritedClass}'."),
+
+      MessageKind.INVALID_OVERRIDDEN_GETTER:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_GETTER,
+          "This is the overridden getter '#{name}' declared in class "
+          "'#{class}'."),
+
+      MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD,
+          "The type '#{declaredType}' of field '#{name}' declared in "
+          "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+          "overridden getter inherited from '#{inheritedClass}'."),
+
+      MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER,
+          "The type '#{declaredType}' of getter '#{name}' declared in "
+          "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+          "overridden field inherited from '#{inheritedClass}'."),
+
+      MessageKind.INVALID_OVERRIDE_SETTER:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDE_SETTER,
+          "The type '#{declaredType}' of setter '#{name}' declared in "
+          "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+          "overridden setter inherited from '#{inheritedClass}'."),
+
+      MessageKind.INVALID_OVERRIDDEN_SETTER:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_SETTER,
+          "This is the overridden setter '#{name}' declared in class "
+          "'#{class}'."),
+
+      MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD,
+          "The type '#{declaredType}' of field '#{name}' declared in "
+          "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+          "overridden setter inherited from '#{inheritedClass}'."),
+
+      MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER,
+          "The type '#{declaredType}' of setter '#{name}' declared in "
+          "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+          "overridden field inherited from '#{inheritedClass}'."),
+
+      MessageKind.INVALID_OVERRIDE_FIELD:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDE_FIELD,
+          "The type '#{declaredType}' of field '#{name}' declared in "
+          "'#{class}' is not assignable to the type '#{inheritedType}' of the "
+          "overridden field inherited from '#{inheritedClass}'."),
+
+      MessageKind.INVALID_OVERRIDDEN_FIELD:
+        const MessageTemplate(MessageKind.INVALID_OVERRIDDEN_FIELD,
+          "This is the overridden field '#{name}' declared in class "
+          "'#{class}'."),
+
+      MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD:
+        const MessageTemplate(MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD,
+          "Method '#{name}' in '#{class}' can't override field from "
+          "'#{inheritedClass}'."),
+
+      MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT:
+        const MessageTemplate(
+          MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT,
+          "This is the field that cannot be overridden by a method."),
+
+      MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD:
+        const MessageTemplate(
+          MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD,
+          "Field '#{name}' in '#{class}' can't override method from "
+          "'#{inheritedClass}'."),
+
+      MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT:
+        const MessageTemplate(
+          MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT,
+          "This is the method that cannot be overridden by a field."),
+
+      MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD:
+        const MessageTemplate(MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD,
+              "Method '#{name}' in '#{class}' can't override getter from "
+              "'#{inheritedClass}'."),
+
+      MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT:
+        const MessageTemplate(
+          MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT,
+          "This is the getter that cannot be overridden by a method."),
+
+      MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER:
+        const MessageTemplate(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER,
+          "Getter '#{name}' in '#{class}' can't override method from "
+          "'#{inheritedClass}'."),
+
+      MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT:
+        const MessageTemplate(
+          MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT,
+          "This is the method that cannot be overridden by a getter."),
+
+      MessageKind.MISSING_FORMALS:
+        const MessageTemplate(MessageKind.MISSING_FORMALS,
+          "Formal parameters are missing."),
+
+      MessageKind.EXTRA_FORMALS:
+        const MessageTemplate(MessageKind.EXTRA_FORMALS,
+          "Formal parameters are not allowed here."),
+
+      MessageKind.UNARY_OPERATOR_BAD_ARITY:
+        const MessageTemplate(MessageKind.UNARY_OPERATOR_BAD_ARITY,
+          "Operator '#{operatorName}' must have no parameters."),
+
+      MessageKind.MINUS_OPERATOR_BAD_ARITY:
+        const MessageTemplate(MessageKind.MINUS_OPERATOR_BAD_ARITY,
+          "Operator '-' must have 0 or 1 parameters."),
+
+      MessageKind.BINARY_OPERATOR_BAD_ARITY:
+        const MessageTemplate(MessageKind.BINARY_OPERATOR_BAD_ARITY,
+          "Operator '#{operatorName}' must have exactly 1 parameter."),
+
+      MessageKind.TERNARY_OPERATOR_BAD_ARITY:
+        const MessageTemplate(MessageKind.TERNARY_OPERATOR_BAD_ARITY,
+          "Operator '#{operatorName}' must have exactly 2 parameters."),
+
+      MessageKind.OPERATOR_OPTIONAL_PARAMETERS:
+        const MessageTemplate(MessageKind.OPERATOR_OPTIONAL_PARAMETERS,
+          "Operator '#{operatorName}' cannot have optional parameters."),
+
+      MessageKind.OPERATOR_NAMED_PARAMETERS:
+        const MessageTemplate(MessageKind.OPERATOR_NAMED_PARAMETERS,
+          "Operator '#{operatorName}' cannot have named parameters."),
+
+      MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER:
+        const MessageTemplate(MessageKind.ILLEGAL_FINAL_METHOD_MODIFIER,
+          "Cannot have final modifier on method."),
+
+      MessageKind.ILLEGAL_CONST_FIELD_MODIFIER:
+        const MessageTemplate(MessageKind.ILLEGAL_CONST_FIELD_MODIFIER,
+          "Cannot have const modifier on non-static field.",
+          howToFix:
+            "Try adding a static modifier, or removing the const modifier.",
+          examples: const ["""
+class C {
+  const int a = 1;
+}
+
+main() => new C();"""]),
+
+      MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS:
+        const MessageTemplate(MessageKind.ILLEGAL_CONSTRUCTOR_MODIFIERS,
+          "Illegal constructor modifiers: '#{modifiers}'."),
+
+      MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS:
+        const MessageTemplate(MessageKind.ILLEGAL_MIXIN_APPLICATION_MODIFIERS,
+              "Illegal mixin application modifiers: '#{modifiers}'."),
+
+      MessageKind.ILLEGAL_MIXIN_SUPERCLASS:
+        const MessageTemplate(MessageKind.ILLEGAL_MIXIN_SUPERCLASS,
+          "Class used as mixin must have Object as superclass."),
+
+      MessageKind.ILLEGAL_MIXIN_OBJECT:
+        const MessageTemplate(MessageKind.ILLEGAL_MIXIN_OBJECT,
+          "Cannot use Object as mixin."),
+
+      MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR:
+        const MessageTemplate(MessageKind.ILLEGAL_MIXIN_CONSTRUCTOR,
+          "Class used as mixin cannot have non-factory constructor."),
+
+      MessageKind.ILLEGAL_MIXIN_CYCLE:
+        const MessageTemplate(MessageKind.ILLEGAL_MIXIN_CYCLE,
+          "Class used as mixin introduces mixin cycle: "
+          "'#{mixinName1}' <-> '#{mixinName2}'."),
+
+      MessageKind.ILLEGAL_MIXIN_WITH_SUPER:
+        const MessageTemplate(MessageKind.ILLEGAL_MIXIN_WITH_SUPER,
+          "Cannot use class '#{className}' as a mixin because it uses "
+          "'super'."),
+
+      MessageKind.ILLEGAL_MIXIN_SUPER_USE:
+        const MessageTemplate(MessageKind.ILLEGAL_MIXIN_SUPER_USE,
+          "Use of 'super' in class used as mixin."),
+
+      MessageKind.PARAMETER_NAME_EXPECTED:
+        const MessageTemplate(MessageKind.PARAMETER_NAME_EXPECTED,
+          "parameter name expected."),
+
+      MessageKind.CANNOT_RESOLVE_GETTER:
+        const MessageTemplate(MessageKind.CANNOT_RESOLVE_GETTER,
+          "Cannot resolve getter."),
+
+      MessageKind.CANNOT_RESOLVE_SETTER:
+        const MessageTemplate(MessageKind.CANNOT_RESOLVE_SETTER,
+          "Cannot resolve setter."),
+
+      MessageKind.ASSIGNING_FINAL_FIELD_IN_SUPER:
+        const MessageTemplate(MessageKind.ASSIGNING_FINAL_FIELD_IN_SUPER,
+          "Cannot assign a value to final field '#{name}' "
+          "in superclass '#{superclassName}'."),
+
+      MessageKind.ASSIGNING_METHOD:
+        const MessageTemplate(MessageKind.ASSIGNING_METHOD,
+          "Cannot assign a value to a method."),
+
+      MessageKind.ASSIGNING_METHOD_IN_SUPER:
+        const MessageTemplate(MessageKind.ASSIGNING_METHOD_IN_SUPER,
+          "Cannot assign a value to method '#{name}' "
+          "in superclass '#{superclassName}'."),
+
+      MessageKind.ASSIGNING_TYPE:
+        const MessageTemplate(MessageKind.ASSIGNING_TYPE,
+          "Cannot assign a value to a type."),
+
+      MessageKind.IF_NULL_ASSIGNING_TYPE:
+        const MessageTemplate(MessageKind.IF_NULL_ASSIGNING_TYPE,
+          "Cannot assign a value to a type. Note that types are never null, "
+          "so this ??= assignment has no effect.",
+          howToFix: "Try removing the '??=' assignment.",
+          examples: const [
+              "class A {} main() { print(A ??= 3);}",
+          ]),
+
+      MessageKind.VOID_NOT_ALLOWED:
+        const MessageTemplate(MessageKind.VOID_NOT_ALLOWED,
+          "Type 'void' can't be used here because it isn't a return type.",
+          howToFix:
+            "Try removing 'void' keyword or replace it with 'var', 'final', "
+            "or a type.",
+          examples: const [
+              "void x; main() {}",
+              "foo(void x) {} main() { foo(null); }",
+          ]),
+
+      MessageKind.NULL_NOT_ALLOWED:
+        const MessageTemplate(MessageKind.NULL_NOT_ALLOWED,
+          "`null` can't be used here."),
+
+      MessageKind.BEFORE_TOP_LEVEL:
+        const MessageTemplate(MessageKind.BEFORE_TOP_LEVEL,
+          "Part header must come before top-level definitions."),
+
+      MessageKind.IMPORT_PART_OF:
+        const MessageTemplate(MessageKind.IMPORT_PART_OF,
+          "The imported library must not have a 'part-of' directive.",
+          howToFix: "Try removing the 'part-of' directive or replacing the "
+                    "import of the library with a 'part' directive.",
+          examples: const [const {
+'main.dart': """
+library library;
+
+import 'part.dart';
+
+main() {}
+""",
+
+'part.dart': """
+part of library;
+"""}]),
+
+      MessageKind.IMPORT_PART_OF_HERE:
+        const MessageTemplate(MessageKind.IMPORT_PART_OF_HERE,
+          "The library is imported here."),
+
+      MessageKind.MAIN_HAS_PART_OF:
+        const MessageTemplate(MessageKind.MAIN_HAS_PART_OF,
+          "The main application file must not have a 'part-of' directive.",
+          howToFix:  "Try removing the 'part-of' directive or starting "
+              "compilation from another file.",
+          examples: const [const {
+'main.dart': """
+part of library;
+
+main() {}
+"""}]),
+
+      MessageKind.LIBRARY_NAME_MISMATCH:
+        const MessageTemplate(MessageKind.LIBRARY_NAME_MISMATCH,
+          "Expected part of library name '#{libraryName}'.",
+          howToFix: "Try changing the directive to 'part of #{libraryName};'.",
+          examples: const [const {
+'main.dart': """
+library lib.foo;
+
+part 'part.dart';
+
+main() {}
+""",
+
+'part.dart': """
+part of lib.bar;
+"""}]),
+
+      MessageKind.MISSING_LIBRARY_NAME:
+        const MessageTemplate(MessageKind.MISSING_LIBRARY_NAME,
+          "Library has no name. Part directive expected library name "
+          "to be '#{libraryName}'.",
+          howToFix: "Try adding 'library #{libraryName};' to the library.",
+          examples: const [const {
+'main.dart': """
+part 'part.dart';
+
+main() {}
+""",
+
+'part.dart': """
+part of lib.foo;
+"""}]),
+
+      MessageKind.THIS_IS_THE_PART_OF_TAG:
+        const MessageTemplate(MessageKind.THIS_IS_THE_PART_OF_TAG,
+          "This is the part of directive."),
+
+      MessageKind.MISSING_PART_OF_TAG:
+        const MessageTemplate(MessageKind.MISSING_PART_OF_TAG,
+          "This file has no part-of tag, but it is being used as a part."),
+
+      MessageKind.DUPLICATED_PART_OF:
+        const MessageTemplate(MessageKind.DUPLICATED_PART_OF,
+          "Duplicated part-of directive."),
+
+      MessageKind.DUPLICATED_LIBRARY_NAME:
+        const MessageTemplate(MessageKind.DUPLICATED_LIBRARY_NAME,
+          "Duplicated library name '#{libraryName}'."),
+
+      MessageKind.DUPLICATED_RESOURCE:
+        const MessageTemplate(MessageKind.DUPLICATED_RESOURCE,
+          "The resource '#{resourceUri}' is loaded through both "
+          "'#{canonicalUri1}' and '#{canonicalUri2}'."),
+
+      MessageKind.DUPLICATED_LIBRARY_RESOURCE:
+        const MessageTemplate(MessageKind.DUPLICATED_LIBRARY_RESOURCE,
+          "The library '#{libraryName}' in '#{resourceUri}' is loaded through "
+          "both '#{canonicalUri1}' and '#{canonicalUri2}'."),
+
+      // This is used as an exception.
+      MessageKind.INVALID_SOURCE_FILE_LOCATION:
+        const MessageTemplate(MessageKind.INVALID_SOURCE_FILE_LOCATION, '''
+Invalid offset (#{offset}) in source map.
+File: #{fileName}
+Length: #{length}'''),
+
+      MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC:
+        const MessageTemplate(MessageKind.TOP_LEVEL_VARIABLE_DECLARED_STATIC,
+              "Top-level variable cannot be declared static."),
+
+      MessageKind.REFERENCE_IN_INITIALIZATION:
+        const MessageTemplate(MessageKind.REFERENCE_IN_INITIALIZATION,
+           "Variable '#{variableName}' is referenced during its "
+           "initialization.",
+           howToFix:
+             "If you are trying to reference a shadowed variable, rename "
+             "one of the variables.",
+           examples: const ["""
+foo(t) {
+  var t = t;
+  return t;
+}
+
+main() => foo(1);
+"""]),
+
+      MessageKind.CONST_WITHOUT_INITIALIZER:
+        const MessageTemplate(MessageKind.CONST_WITHOUT_INITIALIZER,
+          "A constant variable must be initialized.",
+          howToFix: "Try adding an initializer or "
+                    "removing the 'const' modifier.",
+          examples: const ["""
+void main() {
+  const c; // This constant variable must be initialized.
+}"""]),
+
+      MessageKind.FINAL_WITHOUT_INITIALIZER:
+        const MessageTemplate(MessageKind.FINAL_WITHOUT_INITIALIZER,
+          "A final variable must be initialized.",
+          howToFix: "Try adding an initializer or "
+                    "removing the 'final' modifier.",
+          examples: const [
+              "class C { static final field; } main() => C.field;"]),
+
+      MessageKind.CONST_LOOP_VARIABLE:
+        const MessageTemplate(MessageKind.CONST_LOOP_VARIABLE,
+          "A loop variable cannot be constant.",
+          howToFix: "Try remove the 'const' modifier or "
+                    "replacing it with a 'final' modifier.",
+          examples: const ["""
+void main() {
+  for (const c in []) {}
+}"""]),
+
+      MessageKind.MEMBER_USES_CLASS_NAME:
+        const MessageTemplate(MessageKind.MEMBER_USES_CLASS_NAME,
+          "Member variable can't have the same name as the class it is "
+          "declared in.",
+          howToFix: "Try renaming the variable.",
+          examples: const ["""
+class A { var A; }
+main() {
+  var a = new A();
+  a.A = 1;
+}
+""", """
+class A { static var A; }
+main() => A.A = 1;
+"""]),
+
+      MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT:
+        const MessageTemplate(
+          MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
+          "Wrong number of arguments to assert. Should be 1, but given "
+          "#{argumentCount}."),
+
+      MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS:
+        const MessageTemplate(MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
+          "'assert' takes no named arguments, but given #{argumentCount}."),
+
+      MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY:
+        const MessageTemplate(MessageKind.FACTORY_REDIRECTION_IN_NON_FACTORY,
+          "Factory redirection only allowed in factories."),
+
+      MessageKind.MISSING_FACTORY_KEYWORD:
+        const MessageTemplate(MessageKind.MISSING_FACTORY_KEYWORD,
+          "Did you forget a factory keyword here?"),
+
+      MessageKind.NO_SUCH_METHOD_IN_NATIVE:
+        const MessageTemplate(MessageKind.NO_SUCH_METHOD_IN_NATIVE,
+          "'NoSuchMethod' is not supported for classes that extend native "
+          "classes."),
+
+      MessageKind.DEFERRED_LIBRARY_DART_2_DART:
+        const MessageTemplate(MessageKind.DEFERRED_LIBRARY_DART_2_DART,
+          "Deferred loading is not supported by the dart backend yet. "
+          "The output will not be split."),
+
+      MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX:
+        const MessageTemplate(MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX,
+          "This import is deferred but there is no prefix keyword.",
+          howToFix: "Try adding a prefix to the import."),
+
+      MessageKind.DEFERRED_OLD_SYNTAX:
+        const MessageTemplate(MessageKind.DEFERRED_OLD_SYNTAX,
+          "The DeferredLibrary annotation is obsolete.",
+          howToFix:
+            "Use the \"import 'lib.dart' deferred as prefix\" syntax instead."),
+
+      MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX:
+        const MessageTemplate(MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX,
+          "The prefix of this deferred import is not unique.",
+          howToFix: "Try changing the import prefix."),
+
+      MessageKind.DEFERRED_TYPE_ANNOTATION:
+        const MessageTemplate(MessageKind.DEFERRED_TYPE_ANNOTATION,
+          "The type #{node} is deferred. "
+          "Deferred types are not valid as type annotations.",
+          howToFix:
+            "Try using a non-deferred abstract class as an interface."),
+
+      MessageKind.ILLEGAL_STATIC:
+        const MessageTemplate(MessageKind.ILLEGAL_STATIC,
+          "Modifier static is only allowed on functions declared in "
+          "a class."),
+
+      MessageKind.STATIC_FUNCTION_BLOAT:
+        const MessageTemplate(MessageKind.STATIC_FUNCTION_BLOAT,
+          "Using '#{class}.#{name}' may lead to unnecessarily large "
+          "generated code.",
+          howToFix:
+              "Try adding '@MirrorsUsed(...)' as described at "
+              "https://goo.gl/Akrrog."),
+
+      MessageKind.NON_CONST_BLOAT:
+        const MessageTemplate(MessageKind.NON_CONST_BLOAT,
+          "Using 'new #{name}' may lead to unnecessarily large generated "
+          "code.",
+          howToFix:
+              "Try using 'const #{name}' or adding '@MirrorsUsed(...)' as "
+              "described at https://goo.gl/Akrrog."),
+
+      MessageKind.STRING_EXPECTED:
+        const MessageTemplate(MessageKind.STRING_EXPECTED,
+          "Expected a 'String', but got an instance of '#{type}'."),
+
+      MessageKind.PRIVATE_IDENTIFIER:
+        const MessageTemplate(MessageKind.PRIVATE_IDENTIFIER,
+          "'#{value}' is not a valid Symbol name because it starts with "
+          "'_'."),
+
+      MessageKind.PRIVATE_NAMED_PARAMETER:
+        const MessageTemplate(MessageKind.PRIVATE_NAMED_PARAMETER,
+          "Named optional parameter can't have a library private name.",
+          howToFix:
+            "Try removing the '_' or making the parameter positional or "
+            "required.",
+          examples: const ["""foo({int _p}) {} main() => foo();"""]),
+
+      MessageKind.UNSUPPORTED_LITERAL_SYMBOL:
+        const MessageTemplate(MessageKind.UNSUPPORTED_LITERAL_SYMBOL,
+          "Symbol literal '##{value}' is currently unsupported by dart2js."),
+
+      MessageKind.INVALID_SYMBOL:
+        const MessageTemplate(MessageKind.INVALID_SYMBOL, '''
+'#{value}' is not a valid Symbol name because is not:
+ * an empty String,
+ * a user defined operator,
+ * a qualified non-private identifier optionally followed by '=', or
+ * a qualified non-private identifier followed by '.' and a user-defined '''
+"operator."),
+
+      MessageKind.AMBIGUOUS_REEXPORT:
+        const MessageTemplate(MessageKind.AMBIGUOUS_REEXPORT,
+          "'#{name}' is (re)exported by multiple libraries."),
+
+      MessageKind.AMBIGUOUS_LOCATION:
+        const MessageTemplate(MessageKind.AMBIGUOUS_LOCATION,
+          "'#{name}' is defined here."),
+
+      MessageKind.IMPORTED_HERE:
+        const MessageTemplate(MessageKind.IMPORTED_HERE,
+          "'#{name}' is imported here."),
+
+      MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE:
+        const MessageTemplate(MessageKind.OVERRIDE_EQUALS_NOT_HASH_CODE,
+          "The class '#{class}' overrides 'operator==', "
+          "but not 'get hashCode'."),
+
+      MessageKind.INTERNAL_LIBRARY_FROM:
+        const MessageTemplate(MessageKind.INTERNAL_LIBRARY_FROM,
+          "Internal library '#{resolvedUri}' is not accessible from "
+          "'#{importingUri}'."),
+
+      MessageKind.INTERNAL_LIBRARY:
+        const MessageTemplate(MessageKind.INTERNAL_LIBRARY,
+          "Internal library '#{resolvedUri}' is not accessible."),
+
+      MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS:
+        const MessageTemplate(
+          MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS,
+          "Js-interop class '#{cls}' cannot extend from the non js-interop "
+          "class '#{superclass}'.",
+          howToFix: "Annotate the superclass with @JS.",
+          examples: const [
+              """
+              import 'package:js/js.dart';
+
+              class Foo { }
+
+              @JS()
+              class Bar extends Foo { }
+
+              main() {
+                new Bar();
+              }
+              """]),
+
+      MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER:
+        const MessageTemplate(
+          MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER,
+          "Member '#{member}' in js-interop class '#{cls}' is not external.",
+          howToFix: "Mark all interop methods external",
+          examples: const [
+              """
+              import 'package:js/js.dart';
+
+              @JS()
+              class Foo {
+                bar() {}
+              }
+
+              main() {
+                new Foo().bar();
+              }
+              """]),
+
+      MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS:
+        const MessageTemplate(
+          MessageKind.JS_INTEROP_METHOD_WITH_NAMED_ARGUMENTS,
+          "Js-interop method '#{method}' has named arguments but is not "
+          "a factory constructor of an @anonymous @JS class.",
+          howToFix: "Remove all named arguments from js-interop method or "
+                    "in the case of a factory constructor annotate the class "
+                    "as @anonymous.",
+          examples: const [
+              """
+              import 'package:js/js.dart';
+
+              @JS()
+              class Foo {
+                external bar(foo, {baz});
+              }
+
+              main() {
+                new Foo().bar(4, baz: 5);
+              }
+              """]),
+      MessageKind.JS_INTEROP_INDEX_NOT_SUPPORTED:
+        const MessageTemplate(
+           MessageKind.JS_INTEROP_INDEX_NOT_SUPPORTED,
+           "Js-interop does not support [] and []= operator methods.",
+           howToFix: "Try replacing [] and []= operator methods with normal "
+                     "methods.",
+           examples: const [
+               """
+        import 'package:js/js.dart';
+
+        @JS()
+        class Foo {
+          external operator [](arg);
+        }
+
+        main() {
+          new Foo()[0];
+        }
+        """, """
+        import 'package:js/js.dart';
+
+        @JS()
+        class Foo {
+          external operator []=(arg, value);
+        }
+
+        main() {
+          new Foo()[0] = 1;
+        }
+        """]),
+
+      MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS:
+        const MessageTemplate(
+          MessageKind.JS_OBJECT_LITERAL_CONSTRUCTOR_WITH_POSITIONAL_ARGUMENTS,
+          "Parameter '#{parameter}' in anonymous js-interop class '#{cls}' "
+          "object literal constructor is positional instead of named."
+          ".",
+          howToFix: "Make all arguments in external factory object literal "
+                    "constructors named.",
+          examples: const [
+              """
+              import 'package:js/js.dart';
+
+              @anonymous
+              @JS()
+              class Foo {
+                external factory Foo(foo, {baz});
+              }
+
+              main() {
+                new Foo(5, baz: 5);
+              }
+              """]),
+
+      MessageKind.LIBRARY_NOT_FOUND:
+        const MessageTemplate(MessageKind.LIBRARY_NOT_FOUND,
+          "Library not found '#{resolvedUri}'."),
+
+      MessageKind.LIBRARY_NOT_SUPPORTED:
+        const MessageTemplate(MessageKind.LIBRARY_NOT_SUPPORTED,
+          "Library not supported '#{resolvedUri}'.",
+          howToFix: "Try removing the dependency or enabling support using "
+                    "the '--categories' option.",
+          examples: const [/*
+              """
+              import 'dart:io';
+              main() {}
+              """
+          */]),
+          // TODO(johnniwinther): Enable example when message_kind_test.dart
+          // supports library loader callbacks.
+
+      MessageKind.UNSUPPORTED_EQ_EQ_EQ:
+        const MessageTemplate(MessageKind.UNSUPPORTED_EQ_EQ_EQ,
+          "'===' is not an operator. "
+          "Did you mean '#{lhs} == #{rhs}' or 'identical(#{lhs}, #{rhs})'?"),
+
+      MessageKind.UNSUPPORTED_BANG_EQ_EQ:
+        const MessageTemplate(MessageKind.UNSUPPORTED_BANG_EQ_EQ,
+          "'!==' is not an operator. "
+          "Did you mean '#{lhs} != #{rhs}' or '!identical(#{lhs}, #{rhs})'?"),
+
+      MessageKind.UNSUPPORTED_PREFIX_PLUS:
+        const MessageTemplate(MessageKind.UNSUPPORTED_PREFIX_PLUS,
+          "'+' is not a prefix operator. ",
+          howToFix: "Try removing '+'.",
+          examples: const [
+              "main() => +2;  // No longer a valid way to write '2'"
+          ]),
+
+      MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX:
+        const MessageTemplate(MessageKind.DEPRECATED_TYPEDEF_MIXIN_SYNTAX,
+          "'typedef' not allowed here. ",
+          howToFix: "Try replacing 'typedef' with 'class'.",
+          examples: const [
+              """
+class B { }
+class M1 {  }
+typedef C = B with M1;  // Need to replace 'typedef' with 'class'.
+main() { new C(); }
+"""]),
+
+      MessageKind.MIRRORS_EXPECTED_STRING:
+        const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING,
+          "Can't use '#{name}' here because it's an instance of '#{type}' "
+          "and a 'String' value is expected.",
+          howToFix: "Did you forget to add quotes?",
+          examples: const [
+              """
+// 'Foo' is a type literal, not a string.
+@MirrorsUsed(symbols: const [Foo])
+import 'dart:mirrors';
+
+class Foo {}
+
+main() {}
+"""]),
+
+      MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE:
+        const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_OR_TYPE,
+          "Can't use '#{name}' here because it's an instance of '#{type}' "
+          "and a 'String' or 'Type' value is expected.",
+          howToFix: "Did you forget to add quotes?",
+          examples: const [
+              """
+// 'main' is a method, not a class.
+@MirrorsUsed(targets: const [main])
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+      MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST:
+        const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_OR_LIST,
+          "Can't use '#{name}' here because it's an instance of '#{type}' "
+          "and a 'String' or 'List' value is expected.",
+          howToFix: "Did you forget to add quotes?",
+          examples: const [
+              """
+// 'Foo' is not a string.
+@MirrorsUsed(symbols: Foo)
+import 'dart:mirrors';
+
+class Foo {}
+
+main() {}
+"""]),
+
+      MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST:
+        const MessageTemplate(MessageKind.MIRRORS_EXPECTED_STRING_TYPE_OR_LIST,
+          "Can't use '#{name}' here because it's an instance of '#{type}' "
+          "but a 'String', 'Type', or 'List' value is expected.",
+          howToFix: "Did you forget to add quotes?",
+          examples: const [
+              """
+// '1' is not a string.
+@MirrorsUsed(targets: 1)
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+      MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY:
+        const MessageTemplate(
+          MessageKind.MIRRORS_CANNOT_RESOLVE_IN_CURRENT_LIBRARY,
+          "Can't find '#{name}' in the current library.",
+          // TODO(ahe): The closest identifiers in edit distance would be nice.
+          howToFix: "Did you forget to add an import?",
+          examples: const [
+              """
+// 'window' is not in scope because dart:html isn't imported.
+@MirrorsUsed(targets: 'window')
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+      MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY:
+        const MessageTemplate(MessageKind.MIRRORS_CANNOT_RESOLVE_IN_LIBRARY,
+          "Can't find '#{name}' in the library '#{library}'.",
+          // TODO(ahe): The closest identifiers in edit distance would be nice.
+          howToFix: "Is '#{name}' spelled right?",
+          examples: const [
+              """
+// 'List' is misspelled.
+@MirrorsUsed(targets: 'dart.core.Lsit')
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+      MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT:
+        const MessageTemplate(MessageKind.MIRRORS_CANNOT_FIND_IN_ELEMENT,
+          "Can't find '#{name}' in '#{element}'.",
+          // TODO(ahe): The closest identifiers in edit distance would be nice.
+          howToFix: "Is '#{name}' spelled right?",
+          examples: const [
+              """
+// 'addAll' is misspelled.
+@MirrorsUsed(targets: 'dart.core.List.addAl')
+import 'dart:mirrors';
+
+main() {}
+"""]),
+
+      MessageKind.INVALID_URI:
+        const MessageTemplate(MessageKind.INVALID_URI,
+          "'#{uri}' is not a valid URI.",
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const [
+            """
+// can't have a '[' in a URI
+import '../../Udyn[mic ils/expect.dart';
+
+main() {}
+"""]),
+
+      MessageKind.INVALID_PACKAGE_CONFIG:
+          const MessageTemplate(MessageKind.INVALID_PACKAGE_CONFIG,
+            """Package config file '#{uri}' is invalid.
+#{exception}""",
+            howToFix: DONT_KNOW_HOW_TO_FIX
+      ),
+
+      MessageKind.INVALID_PACKAGE_URI:
+        const MessageTemplate(MessageKind.INVALID_PACKAGE_URI,
+          "'#{uri}' is not a valid package URI (#{exception}).",
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const [
+            """
+// can't have a 'top level' package URI
+import 'package:foo.dart';
+
+main() {}
+""", """
+// can't have 2 slashes
+import 'package://foo/foo.dart';
+
+main() {}
+""", """
+// package name must be valid
+import 'package:not\valid/foo.dart';
+
+main() {}
+"""]),
+
+      MessageKind.READ_SCRIPT_ERROR:
+        const MessageTemplate(MessageKind.READ_SCRIPT_ERROR,
+          "Can't read '#{uri}' (#{exception}).",
+          // Don't know how to fix since the underlying error is unknown.
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const [
+              """
+// 'foo.dart' does not exist.
+import 'foo.dart';
+
+main() {}
+"""]),
+
+      MessageKind.READ_SELF_ERROR:
+        const MessageTemplate(MessageKind.READ_SELF_ERROR,
+          "#{exception}",
+          // Don't know how to fix since the underlying error is unknown.
+          howToFix: DONT_KNOW_HOW_TO_FIX),
+
+      MessageKind.ABSTRACT_CLASS_INSTANTIATION:
+        const MessageTemplate(MessageKind.ABSTRACT_CLASS_INSTANTIATION,
+          "Can't instantiate abstract class.",
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const ["abstract class A {} main() { new A(); }"]),
+
+      MessageKind.BODY_EXPECTED:
+        const MessageTemplate(MessageKind.BODY_EXPECTED,
+          "Expected a function body or '=>'.",
+          // TODO(ahe): In some scenarios, we can suggest removing the 'static'
+          // keyword.
+          howToFix: "Try adding {}.",
+          examples: const [
+              "main();"]),
+
+      MessageKind.MIRROR_BLOAT:
+        const MessageTemplate(MessageKind.MIRROR_BLOAT,
+          "#{count} methods retained for use by dart:mirrors out of #{total}"
+          " total methods (#{percentage}%)."),
+
+      MessageKind.MIRROR_IMPORT:
+        const MessageTemplate(MessageKind.MIRROR_IMPORT,
+          "Import of 'dart:mirrors'."),
+
+      MessageKind.MIRROR_IMPORT_NO_USAGE:
+        const MessageTemplate(MessageKind.MIRROR_IMPORT_NO_USAGE,
+          "This import is not annotated with @MirrorsUsed, which may lead to "
+          "unnecessarily large generated code.",
+          howToFix:
+              "Try adding '@MirrorsUsed(...)' as described at "
+              "https://goo.gl/Akrrog."),
+
+      MessageKind.JS_PLACEHOLDER_CAPTURE:
+        const MessageTemplate(
+            MessageKind.JS_PLACEHOLDER_CAPTURE,
+            "JS code must not use '#' placeholders inside functions.",
+            howToFix:
+            "Use an immediately called JavaScript function to capture the"
+            " the placeholder values as JavaScript function parameters."),
+
+      MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT:
+        const MessageTemplate(
+          MessageKind.WRONG_ARGUMENT_FOR_JS_INTERCEPTOR_CONSTANT,
+          "Argument for 'JS_INTERCEPTOR_CONSTANT' must be a type constant."),
+
+      MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD:
+        const MessageTemplate(MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
+              "'#{keyword}' is a reserved word and can't be used here.",
+              howToFix: "Try using a different name.",
+              examples: const ["do() {} main() {}"]),
+
+      MessageKind. NAMED_FUNCTION_EXPRESSION:
+        const MessageTemplate(MessageKind.NAMED_FUNCTION_EXPRESSION,
+          "Function expression '#{name}' cannot be named.",
+          howToFix: "Try removing the name.",
+          examples: const ["main() { var f = func() {}; }"]),
+
+      MessageKind.UNUSED_METHOD:
+        const MessageTemplate(MessageKind.UNUSED_METHOD,
+          "The method '#{name}' is never called.",
+          howToFix: "Consider deleting it.",
+          examples: const ["deadCode() {} main() {}"]),
+
+      MessageKind.UNUSED_CLASS:
+        const MessageTemplate(MessageKind.UNUSED_CLASS,
+          "The class '#{name}' is never used.",
+          howToFix: "Consider deleting it.",
+          examples: const ["class DeadCode {} main() {}"]),
+
+      MessageKind.UNUSED_TYPEDEF:
+        const MessageTemplate(MessageKind.UNUSED_TYPEDEF,
+          "The typedef '#{name}' is never used.",
+          howToFix: "Consider deleting it.",
+          examples: const ["typedef DeadCode(); main() {}"]),
+
+      MessageKind.ABSTRACT_METHOD:
+        const MessageTemplate(MessageKind.ABSTRACT_METHOD,
+          "The method '#{name}' has no implementation in "
+          "class '#{class}'.",
+          howToFix: "Try adding a body to '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+class Class {
+  method();
+}
+main() => new Class().method();
+"""]),
+
+      MessageKind.ABSTRACT_GETTER:
+        const MessageTemplate(MessageKind.ABSTRACT_GETTER,
+          "The getter '#{name}' has no implementation in "
+          "class '#{class}'.",
+          howToFix: "Try adding a body to '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+class Class {
+  get getter;
+}
+main() => new Class();
+"""]),
+
+      MessageKind.ABSTRACT_SETTER:
+        const MessageTemplate(MessageKind.ABSTRACT_SETTER,
+          "The setter '#{name}' has no implementation in "
+          "class '#{class}'.",
+          howToFix: "Try adding a body to '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+class Class {
+  set setter(_);
+}
+main() => new Class();
+"""]),
+
+      MessageKind.INHERIT_GETTER_AND_METHOD:
+        const MessageTemplate(MessageKind.INHERIT_GETTER_AND_METHOD,
+          "The class '#{class}' can't inherit both getters and methods "
+          "by the named '#{name}'.",
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const ["""
+class A {
+  get member => null;
+}
+class B {
+  member() {}
+}
+class Class implements A, B {
+}
+main() => new Class();
+"""]),
+
+      MessageKind.INHERITED_METHOD:
+        const MessageTemplate(MessageKind.INHERITED_METHOD,
+          "The inherited method '#{name}' is declared here in class "
+          "'#{class}'."),
+
+      MessageKind.INHERITED_EXPLICIT_GETTER:
+        const MessageTemplate(MessageKind.INHERITED_EXPLICIT_GETTER,
+          "The inherited getter '#{name}' is declared here in class "
+          "'#{class}'."),
+
+      MessageKind.INHERITED_IMPLICIT_GETTER:
+        const MessageTemplate(MessageKind.INHERITED_IMPLICIT_GETTER,
+          "The inherited getter '#{name}' is implicitly declared by this "
+          "field in class '#{class}'."),
+
+      MessageKind.UNIMPLEMENTED_METHOD_ONE:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD_ONE,
+          "'#{class}' doesn't implement '#{method}' "
+          "declared in '#{declarer}'.",
+          howToFix: "Try adding an implementation of '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+abstract class I {
+  m();
+}
+class C implements I {}
+main() => new C();
+""", """
+abstract class I {
+  m();
+}
+class C extends I {}
+main() => new C();
+"""]),
+
+      MessageKind.UNIMPLEMENTED_METHOD:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD,
+          "'#{class}' doesn't implement '#{method}'.",
+          howToFix: "Try adding an implementation of '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+abstract class I {
+  m();
+}
+
+abstract class J {
+  m();
+}
+
+class C implements I, J {}
+
+main() {
+ new C();
+}
+""", """
+abstract class I {
+  m();
+}
+
+abstract class J {
+  m();
+}
+
+class C extends I implements J {}
+
+main() {
+ new C();
+}
+"""]),
+
+      MessageKind.UNIMPLEMENTED_METHOD_CONT:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_METHOD_CONT,
+          "The method '#{name}' is declared here in class '#{class}'."),
+
+      MessageKind.UNIMPLEMENTED_SETTER_ONE:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_SETTER_ONE,
+          "'#{class}' doesn't implement the setter '#{name}' "
+          "declared in '#{declarer}'.",
+          howToFix: "Try adding an implementation of '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+abstract class I {
+  set m(_);
+}
+class C implements I {}
+class D implements I {
+  set m(_) {}
+}
+main() {
+ new D().m = 0;
+ new C();
+}
+"""]),
+
+      MessageKind.UNIMPLEMENTED_SETTER:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_SETTER,
+          "'#{class}' doesn't implement the setter '#{name}'.",
+          howToFix: "Try adding an implementation of '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+abstract class I {
+  set m(_);
+}
+abstract class J {
+  set m(_);
+}
+class C implements I, J {}
+main() => new C();
+""", """
+abstract class I {
+  set m(_);
+}
+abstract class J {
+  set m(_);
+}
+class C extends I implements J {}
+main() => new C();
+"""]),
+
+      MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER,
+          "The setter '#{name}' is declared here in class '#{class}'."),
+
+      MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER,
+          "The setter '#{name}' is implicitly declared by this field "
+          "in class '#{class}'."),
+
+      MessageKind.UNIMPLEMENTED_GETTER_ONE:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_GETTER_ONE,
+          "'#{class}' doesn't implement the getter '#{name}' "
+          "declared in '#{declarer}'.",
+          howToFix: "Try adding an implementation of '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+abstract class I {
+  get m;
+}
+class C implements I {}
+main() => new C();
+""", """
+abstract class I {
+  get m;
+}
+class C extends I {}
+main() => new C();
+"""]),
+
+      MessageKind.UNIMPLEMENTED_GETTER:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_GETTER,
+          "'#{class}' doesn't implement the getter '#{name}'.",
+          howToFix: "Try adding an implementation of '#{name}' or declaring "
+                    "'#{class}' to be 'abstract'.",
+          examples: const ["""
+abstract class I {
+  get m;
+}
+abstract class J {
+  get m;
+}
+class C implements I, J {}
+main() => new C();
+""", """
+abstract class I {
+  get m;
+}
+abstract class J {
+  get m;
+}
+class C extends I implements J {}
+main() => new C();
+"""]),
+
+      MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER,
+          "The getter '#{name}' is declared here in class '#{class}'."),
+
+      MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER:
+        const MessageTemplate(MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER,
+          "The getter '#{name}' is implicitly declared by this field "
+          "in class '#{class}'."),
+
+      MessageKind.INVALID_METADATA:
+        const MessageTemplate(MessageKind.INVALID_METADATA,
+          "A metadata annotation must be either a reference to a compile-time "
+          "constant variable or a call to a constant constructor.",
+          howToFix:
+            "Try using a different constant value or referencing it through a "
+            "constant variable.",
+          examples: const [
+'@Object main() {}',
+'@print main() {}']),
+
+      MessageKind.INVALID_METADATA_GENERIC:
+        const MessageTemplate(MessageKind.INVALID_METADATA_GENERIC,
+          "A metadata annotation using a constant constructor cannot use type "
+          "arguments.",
+          howToFix:
+            "Try removing the type arguments or referencing the constant "
+            "through a constant variable.",
+          examples: const ['''
+class C<T> {
+  const C();
+}
+@C<int>() main() {}
+''']),
+
+      MessageKind.EQUAL_MAP_ENTRY_KEY:
+        const MessageTemplate(MessageKind.EQUAL_MAP_ENTRY_KEY,
+          "An entry with the same key already exists in the map.",
+          howToFix:
+            "Try removing the previous entry or changing the key in one "
+            "of the entries.",
+          examples: const ["""
+main() {
+  var m = const {'foo': 1, 'foo': 2};
+}"""]),
+
+      MessageKind.BAD_INPUT_CHARACTER:
+        const MessageTemplate(MessageKind.BAD_INPUT_CHARACTER,
+          "Character U+#{characterHex} isn't allowed here.",
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const ["""
+main() {
+  String x = ç;
+}
+"""]),
+
+      MessageKind.UNTERMINATED_STRING:
+        const MessageTemplate(MessageKind.UNTERMINATED_STRING,
+          "String must end with #{quote}.",
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const ["""
+main() {
+  return '
+;
+}
+""",
+"""
+main() {
+  return \"
+;
+}
+""",
+"""
+main() {
+  return r'
+;
+}
+""",
+"""
+main() {
+  return r\"
+;
+}
+""",
+"""
+main() => '''
+""",
+"""
+main() => \"\"\"
+""",
+"""
+main() => r'''
+""",
+"""
+main() => r\"\"\"
+"""]),
+
+      MessageKind.UNMATCHED_TOKEN:
+        const MessageTemplate(MessageKind.UNMATCHED_TOKEN,
+          "Can't find '#{end}' to match '#{begin}'.",
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const[
+              "main(",
+              "main(){",
+              "main(){]}",
+            ]),
+
+      MessageKind.UNTERMINATED_TOKEN:
+        const MessageTemplate(MessageKind.UNTERMINATED_TOKEN,
+          // This is a fall-back message that shouldn't happen.
+          "Incomplete token."),
+
+      MessageKind.EXPONENT_MISSING:
+        const MessageTemplate(MessageKind.EXPONENT_MISSING,
+          "Numbers in exponential notation should always contain an exponent"
+          " (an integer number with an optional sign).",
+          howToFix:
+            "Make sure there is an exponent, and remove any whitespace "
+            "before it.",
+          examples: const ["""
+main() {
+  var i = 1e;
+}
+"""]),
+
+      MessageKind.HEX_DIGIT_EXPECTED:
+        const MessageTemplate(MessageKind.HEX_DIGIT_EXPECTED,
+          "A hex digit (0-9 or A-F) must follow '0x'.",
+          howToFix:
+            DONT_KNOW_HOW_TO_FIX, // Seems obvious from the error message.
+          examples: const ["""
+main() {
+  var i = 0x;
+}
+"""]),
+
+      MessageKind.MALFORMED_STRING_LITERAL:
+        const MessageTemplate(MessageKind.MALFORMED_STRING_LITERAL,
+          r"A '$' has special meaning inside a string, and must be followed by "
+          "an identifier or an expression in curly braces ({}).",
+          howToFix: r"Try adding a backslash (\) to escape the '$'.",
+          examples: const [r"""
+main() {
+  return '$';
+}
+""",
+r'''
+main() {
+  return "$";
+}
+''',
+r"""
+main() {
+  return '''$''';
+}
+""",
+r'''
+main() {
+  return """$""";
+}
+''']),
+
+      MessageKind.UNTERMINATED_COMMENT:
+        const MessageTemplate(MessageKind.UNTERMINATED_COMMENT,
+          "Comment starting with '/*' must end with '*/'.",
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const [r"""
+main() {
+}
+/*"""]),
+
+      MessageKind.MISSING_TOKEN_BEFORE_THIS:
+        const MessageTemplate(MessageKind.MISSING_TOKEN_BEFORE_THIS,
+          "Expected '#{token}' before this.",
+          // Consider the second example below: the parser expects a ')' before
+          // 'y', but a ',' would also have worked. We don't have enough
+          // information to give a good suggestion.
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const [
+              "main() => true ? 1;",
+              "main() => foo(x: 1 y: 2);",
+            ]),
+
+      MessageKind.MISSING_TOKEN_AFTER_THIS:
+        const MessageTemplate(MessageKind.MISSING_TOKEN_AFTER_THIS,
+          "Expected '#{token}' after this.",
+          // See [MISSING_TOKEN_BEFORE_THIS], we don't have enough information
+          // to give a good suggestion.
+          howToFix: DONT_KNOW_HOW_TO_FIX,
+          examples: const [
+              "main(x) {x}",
+"""
+class S1 {}
+class S2 {}
+class S3 {}
+class A = S1 with S2, S3
+main() => new A();
+"""
+]),
+
+      MessageKind.CONSIDER_ANALYZE_ALL:
+        const MessageTemplate(MessageKind.CONSIDER_ANALYZE_ALL,
+          "Could not find '#{main}'.  Nothing will be analyzed.",
+          howToFix: "Try using '--analyze-all' to analyze everything.",
+          examples: const ['']),
+
+      MessageKind.MISSING_MAIN:
+        const MessageTemplate(MessageKind.MISSING_MAIN,
+          "Could not find '#{main}'.",
+          howToFix: "Try adding a method named '#{main}' to your program."
+          /* No example, test uses '--analyze-only' which will produce the above
+           * message [CONSIDER_ANALYZE_ALL].  An example for a human operator
+           * would be an empty file.*/),
+
+      MessageKind.MAIN_NOT_A_FUNCTION:
+        const MessageTemplate(MessageKind.MAIN_NOT_A_FUNCTION,
+          "'#{main}' is not a function.",
+          howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
+          examples: const ['var main;']),
+
+      MessageKind.MAIN_WITH_EXTRA_PARAMETER:
+        const MessageTemplate(MessageKind.MAIN_WITH_EXTRA_PARAMETER,
+          "'#{main}' cannot have more than two parameters.",
+          howToFix: DONT_KNOW_HOW_TO_FIX, /* Don't state the obvious. */
+          examples: const ['main(a, b, c) {}']),
+
+      MessageKind.COMPILER_CRASHED:
+        const MessageTemplate(MessageKind.COMPILER_CRASHED,
+          "The compiler crashed when compiling this element."),
+
+      MessageKind.PLEASE_REPORT_THE_CRASH:
+        const MessageTemplate(MessageKind.PLEASE_REPORT_THE_CRASH, '''
+The compiler is broken.
+
+When compiling the above element, the compiler crashed. It is not
+possible to tell if this is caused by a problem in your program or
+not. Regardless, the compiler should not crash.
+
+The Dart team would greatly appreciate if you would take a moment to
+report this problem at http://dartbug.com/new.
+
+Please include the following information:
+
+* the name and version of your operating system,
+
+* the Dart SDK build number (#{buildId}), and
+
+* the entire message you see here (including the full stack trace
+  below as well as the source location above).
+'''),
+
+      MessageKind.POTENTIAL_MUTATION:
+        const MessageTemplate(MessageKind.POTENTIAL_MUTATION,
+          "Variable '#{variableName}' is not known to be of type "
+          "'#{shownType}' because it is potentially mutated in the scope for "
+          "promotion."),
+
+      MessageKind.POTENTIAL_MUTATION_HERE:
+        const MessageTemplate(MessageKind.POTENTIAL_MUTATION_HERE,
+          "Variable '#{variableName}' is potentially mutated here."),
+
+      MessageKind.POTENTIAL_MUTATION_IN_CLOSURE:
+        const MessageTemplate(MessageKind.POTENTIAL_MUTATION_IN_CLOSURE,
+          "Variable '#{variableName}' is not known to be of type "
+          "'#{shownType}' because it is potentially mutated within a closure."),
+
+      MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE:
+        const MessageTemplate(MessageKind.POTENTIAL_MUTATION_IN_CLOSURE_HERE,
+              "Variable '#{variableName}' is potentially mutated in a "
+              "closure here."),
+
+      MessageKind.ACCESSED_IN_CLOSURE:
+        const MessageTemplate(MessageKind.ACCESSED_IN_CLOSURE,
+          "Variable '#{variableName}' is not known to be of type "
+          "'#{shownType}' because it is accessed by a closure in the scope for "
+          "promotion and potentially mutated in the scope of "
+          "'#{variableName}'."),
+
+      MessageKind.ACCESSED_IN_CLOSURE_HERE:
+        const MessageTemplate(MessageKind.ACCESSED_IN_CLOSURE_HERE,
+          "Variable '#{variableName}' is accessed in a closure here."),
+
+      MessageKind.NOT_MORE_SPECIFIC:
+        const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC,
+          "Variable '#{variableName}' is not shown to have type "
+          "'#{shownType}' because '#{shownType}' is not more specific than the "
+          "known type '#{knownType}' of '#{variableName}'."),
+
+      MessageKind.NOT_MORE_SPECIFIC_SUBTYPE:
+        const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC_SUBTYPE,
+          "Variable '#{variableName}' is not shown to have type "
+          "'#{shownType}' because '#{shownType}' is not a subtype of the "
+          "known type '#{knownType}' of '#{variableName}'."),
+
+      MessageKind.NOT_MORE_SPECIFIC_SUGGESTION:
+        const MessageTemplate(MessageKind.NOT_MORE_SPECIFIC_SUGGESTION,
+          "Variable '#{variableName}' is not shown to have type "
+          "'#{shownType}' because '#{shownType}' is not more specific than the "
+          "known type '#{knownType}' of '#{variableName}'.",
+          howToFix:
+            "Try replacing '#{shownType}' with '#{shownTypeSuggestion}'."),
+
+      MessageKind.NO_COMMON_SUBTYPES:
+        const MessageTemplate(MessageKind.NO_COMMON_SUBTYPES,
+           "Types '#{left}' and '#{right}' have no common subtypes."),
+
+      MessageKind.HIDDEN_WARNINGS_HINTS:
+        const MessageTemplate(MessageKind.HIDDEN_WARNINGS_HINTS,
+          "#{warnings} warning(s) and #{hints} hint(s) suppressed in #{uri}."),
+
+      MessageKind.HIDDEN_WARNINGS:
+        const MessageTemplate(MessageKind.HIDDEN_WARNINGS,
+          "#{warnings} warning(s) suppressed in #{uri}."),
+
+      MessageKind.HIDDEN_HINTS:
+        const MessageTemplate(MessageKind.HIDDEN_HINTS,
+          "#{hints} hint(s) suppressed in #{uri}."),
+
+      MessageKind.PREAMBLE:
+        const MessageTemplate(MessageKind.PREAMBLE,
+        "When run on the command-line, the compiled output might"
+        " require a preamble file located in:\n"
+        "  <sdk>/lib/_internal/js_runtime/lib/preambles."),
+
+      MessageKind.INVALID_SYNC_MODIFIER:
+        const MessageTemplate(MessageKind.INVALID_SYNC_MODIFIER,
+          "Invalid modifier 'sync'.",
+          howToFix: "Try replacing 'sync' with 'sync*'.",
+          examples: const [
+            "main() sync {}"
+          ]),
+
+      MessageKind.INVALID_AWAIT_FOR:
+        const MessageTemplate(MessageKind.INVALID_AWAIT_FOR,
+          "'await' is only supported on for-in loops.",
+          howToFix: "Try rewriting the loop as a for-in loop or removing the "
+                    "'await' keyword.",
+          examples: const ["""
+main() async* {
+  await for (int i = 0; i < 10; i++) {}
+}
+"""]),
+
+      MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD:
+        const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_ABSTRACT_METHOD,
+          "The modifier '#{modifier}' is not allowed on an abstract method.",
+          options: const ['--enable-async'],
+          howToFix: "Try removing the '#{modifier}' modifier or adding a "
+                    "body to the method.",
+          examples: const ["""
+abstract class A {
+  method() async;
+}
+class B extends A {
+  method() {}
+}
+main() {
+  A a = new B();
+  a.method();
+}
+"""]),
+
+      MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR:
+        const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_CONSTRUCTOR,
+              "The modifier '#{modifier}' is not allowed on constructors.",
+              options: const ['--enable-async'],
+              howToFix: "Try removing the '#{modifier}' modifier.",
+              examples: const ["""
+class A {
+  A() async;
+}
+main() => new A();""",
+
+"""
+class A {
+  A();
+  factory A.a() async* {}
+}
+main() => new A.a();"""]),
+
+      MessageKind.ASYNC_MODIFIER_ON_SETTER:
+        const MessageTemplate(MessageKind.ASYNC_MODIFIER_ON_SETTER,
+              "The modifier '#{modifier}' is not allowed on setters.",
+              options: const ['--enable-async'],
+              howToFix: "Try removing the '#{modifier}' modifier.",
+              examples: const ["""
+class A {
+  set foo(v) async {}
+}
+main() => new A().foo = 0;"""]),
+
+      MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY:
+        const MessageTemplate(MessageKind.YIELDING_MODIFIER_ON_ARROW_BODY,
+          "The modifier '#{modifier}' is not allowed on methods implemented "
+          "using '=>'.",
+          options: const ['--enable-async'],
+          howToFix: "Try removing the '#{modifier}' modifier or implementing "
+                    "the method body using a block: '{ ... }'.",
+          examples: const ["main() sync* => null;", "main() async* => null;"]),
+
+      // TODO(johnniwinther): Check for 'async' as identifier.
+      MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER:
+        const MessageTemplate(MessageKind.ASYNC_KEYWORD_AS_IDENTIFIER,
+          "'#{keyword}' cannot be used as an identifier in a function body "
+          "marked with '#{modifier}'.",
+          options: const ['--enable-async'],
+          howToFix: "Try removing the '#{modifier}' modifier or renaming the "
+                    "identifier.",
+          examples: const ["""
+main() async {
+ var await;
+}""",
+"""
+main() async* {
+ var yield;
+}""",
+"""
+main() sync* {
+ var yield;
+}"""]),
+
+      MessageKind.NATIVE_NOT_SUPPORTED:
+        const MessageTemplate(MessageKind.NATIVE_NOT_SUPPORTED,
+          "'native' modifier is not supported.",
+          howToFix: "Try removing the 'native' implementation or analyzing the "
+                    "code with the --allow-native-extensions option.",
+          examples: const ["""
+main() native "Main";
+"""]),
+
+      MessageKind.DART_EXT_NOT_SUPPORTED:
+        const MessageTemplate(MessageKind.DART_EXT_NOT_SUPPORTED,
+          "The 'dart-ext' scheme is not supported.",
+          howToFix: "Try analyzing the code with the --allow-native-extensions "
+                    "option.",
+          examples: const ["""
+import 'dart-ext:main';
+
+main() {}
+"""]),
+
+      MessageKind.LIBRARY_TAG_MUST_BE_FIRST:
+        const MessageTemplate(MessageKind.LIBRARY_TAG_MUST_BE_FIRST,
+          "The library declaration should come before other declarations.",
+          howToFix: "Try moving the declaration to the top of the file.",
+          examples: const [
+"""
+import 'dart:core';
+library foo;
+main() {}
+""",
+      ]),
+
+      MessageKind.ONLY_ONE_LIBRARY_TAG:
+        const MessageTemplate(MessageKind.ONLY_ONE_LIBRARY_TAG,
+          "There can only be one library declaration.",
+          howToFix: "Try removing all other library declarations.",
+          examples: const [
+"""
+library foo;
+library bar;
+main() {}
+""",
+"""
+library foo;
+import 'dart:core';
+library bar;
+main() {}
+""",
+      ]),
+
+      MessageKind.IMPORT_BEFORE_PARTS:
+        const MessageTemplate(MessageKind.IMPORT_BEFORE_PARTS,
+          "Import declarations should come before parts.",
+          howToFix: "Try moving this import further up in the file.",
+          examples: const [
+              const <String, String>{
+                'main.dart': """
+library test.main;
+part 'part.dart';
+import 'dart:core';
+main() {}
+""",
+                'part.dart': """
+part of test.main;
+""",
+          }]),
+
+      MessageKind.EXPORT_BEFORE_PARTS:
+        const MessageTemplate(MessageKind.EXPORT_BEFORE_PARTS,
+          "Export declarations should come before parts.",
+          howToFix: "Try moving this export further up in the file.",
+          examples: const [
+              const <String, String>{
+                'main.dart': """
+library test.main;
+part 'part.dart';
+export 'dart:core';
+main() {}
+""",
+               'part.dart': """
+part of test.main;
+""",
+          }]),
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Patch errors start.
+  //////////////////////////////////////////////////////////////////////////////
+
+      MessageKind.PATCH_RETURN_TYPE_MISMATCH:
+        const MessageTemplate(MessageKind.PATCH_RETURN_TYPE_MISMATCH,
+          "Patch return type '#{patchReturnType}' does not match "
+          "'#{originReturnType}' on origin method '#{methodName}'."),
+
+      MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH:
+        const MessageTemplate(
+          MessageKind.PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH,
+          "Required parameter count of patch method "
+          "(#{patchParameterCount}) does not match parameter count on origin "
+          "method '#{methodName}' (#{originParameterCount})."),
+
+      MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH:
+        const MessageTemplate(
+          MessageKind.PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH,
+          "Optional parameter count of patch method "
+          "(#{patchParameterCount}) does not match parameter count on origin "
+          "method '#{methodName}' (#{originParameterCount})."),
+
+      MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH:
+        const MessageTemplate(
+          MessageKind.PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH,
+          "Optional parameters of origin and patch method "
+          "'#{methodName}' must both be either named or positional."),
+
+      MessageKind.PATCH_PARAMETER_MISMATCH:
+        const MessageTemplate(MessageKind.PATCH_PARAMETER_MISMATCH,
+          "Patch method parameter '#{patchParameter}' does not match "
+          "'#{originParameter}' on origin method '#{methodName}'."),
+
+      MessageKind.PATCH_PARAMETER_TYPE_MISMATCH:
+        const MessageTemplate(MessageKind.PATCH_PARAMETER_TYPE_MISMATCH,
+          "Patch method parameter '#{parameterName}' type "
+          "'#{patchParameterType}' does not match '#{originParameterType}' on "
+          "origin method '#{methodName}'."),
+
+      MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION:
+        const MessageTemplate(MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION,
+          "External method without an implementation."),
+
+      MessageKind.PATCH_POINT_TO_FUNCTION:
+        const MessageTemplate(MessageKind.PATCH_POINT_TO_FUNCTION,
+          "This is the function patch '#{functionName}'."),
+
+      MessageKind.PATCH_POINT_TO_CLASS:
+        const MessageTemplate(MessageKind.PATCH_POINT_TO_CLASS,
+          "This is the class patch '#{className}'."),
+
+      MessageKind.PATCH_POINT_TO_GETTER:
+        const MessageTemplate(MessageKind.PATCH_POINT_TO_GETTER,
+          "This is the getter patch '#{getterName}'."),
+
+      MessageKind.PATCH_POINT_TO_SETTER:
+        const MessageTemplate(MessageKind.PATCH_POINT_TO_SETTER,
+          "This is the setter patch '#{setterName}'."),
+
+      MessageKind.PATCH_POINT_TO_CONSTRUCTOR:
+        const MessageTemplate(MessageKind.PATCH_POINT_TO_CONSTRUCTOR,
+          "This is the constructor patch '#{constructorName}'."),
+
+      MessageKind.PATCH_POINT_TO_PARAMETER:
+        const MessageTemplate(MessageKind.PATCH_POINT_TO_PARAMETER,
+          "This is the patch parameter '#{parameterName}'."),
+
+      MessageKind.PATCH_NON_EXISTING:
+        const MessageTemplate(MessageKind.PATCH_NON_EXISTING,
+          "Origin does not exist for patch '#{name}'."),
+
+      // TODO(ahe): Eventually, this error should be removed as it will be
+      // handled by the regular parser.
+      MessageKind.PATCH_NONPATCHABLE:
+        const MessageTemplate(MessageKind.PATCH_NONPATCHABLE,
+          "Only classes and functions can be patched."),
+
+      MessageKind.PATCH_NON_EXTERNAL:
+        const MessageTemplate(MessageKind.PATCH_NON_EXTERNAL,
+          "Only external functions can be patched."),
+
+      MessageKind.PATCH_NON_CLASS:
+        const MessageTemplate(MessageKind.PATCH_NON_CLASS,
+          "Patching non-class with class patch '#{className}'."),
+
+      MessageKind.PATCH_NON_GETTER:
+        const MessageTemplate(MessageKind.PATCH_NON_GETTER,
+          "Cannot patch non-getter '#{name}' with getter patch."),
+
+      MessageKind.PATCH_NO_GETTER:
+        const MessageTemplate(MessageKind.PATCH_NO_GETTER,
+          "No getter found for getter patch '#{getterName}'."),
+
+      MessageKind.PATCH_NON_SETTER:
+        const MessageTemplate(MessageKind.PATCH_NON_SETTER,
+          "Cannot patch non-setter '#{name}' with setter patch."),
+
+      MessageKind.PATCH_NO_SETTER:
+        const MessageTemplate(MessageKind.PATCH_NO_SETTER,
+          "No setter found for setter patch '#{setterName}'."),
+
+      MessageKind.PATCH_NON_CONSTRUCTOR:
+        const MessageTemplate(MessageKind.PATCH_NON_CONSTRUCTOR,
+          "Cannot patch non-constructor with constructor patch "
+          "'#{constructorName}'."),
+
+      MessageKind.PATCH_NON_FUNCTION:
+        const MessageTemplate(MessageKind.PATCH_NON_FUNCTION,
+          "Cannot patch non-function with function patch "
+          "'#{functionName}'."),
+
+      MessageKind.INJECTED_PUBLIC_MEMBER:
+        const MessageTemplate(MessageKind.INJECTED_PUBLIC_MEMBER,
+            "Non-patch members in patch libraries must be private."),
+
+      MessageKind.EXTERNAL_WITH_BODY:
+        const MessageTemplate(MessageKind.EXTERNAL_WITH_BODY,
+          "External function '#{functionName}' cannot have a function body.",
+          options: const ["--output-type=dart"],
+          howToFix:
+            "Try removing the 'external' modifier or the function body.",
+          examples: const ["""
+external foo() => 0;
+main() => foo();
+""", """
+external foo() {}
+main() => foo();
+"""]),
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Patch errors end.
+  //////////////////////////////////////////////////////////////////////////////
+
+      MessageKind.EXPERIMENTAL_ASSERT_MESSAGE:
+        const MessageTemplate(MessageKind.EXPERIMENTAL_ASSERT_MESSAGE,
+          "Experimental language feature 'assertion with message'"
+          " is not supported.",
+          howToFix:
+            "Use option '--assert-message' to use assertions with messages.",
+          examples: const [r'''
+main() {
+  int n = -7;
+  assert(n > 0, 'must be positive: $n');
+}
+''']),
+
+      MessageKind.IMPORT_EXPERIMENTAL_MIRRORS:
+        const MessageTemplate(MessageKind.IMPORT_EXPERIMENTAL_MIRRORS, r'''
+
+****************************************************************
+* WARNING: dart:mirrors support in dart2js is experimental,
+*          and not recommended.
+*          This implementation of mirrors is incomplete,
+*          and often greatly increases the size of the generated
+*          JavaScript code.
+*
+* Your app imports dart:mirrors via:''''''
+$IMPORT_EXPERIMENTAL_MIRRORS_PADDING#{importChain}
+*
+* You can disable this message by using the --enable-experimental-mirrors
+* command-line flag.
+*
+* To learn what to do next, please visit:
+*    http://dartlang.org/dart2js-reflection
+****************************************************************
+'''),
+
+      MessageKind.DISALLOWED_LIBRARY_IMPORT:
+        const MessageTemplate(MessageKind.DISALLOWED_LIBRARY_IMPORT, '''
+Your app imports the unsupported library '#{uri}' via:
+''''''
+$DISALLOWED_LIBRARY_IMPORT_PADDING#{importChain}
+
+Use the --categories option to support import of '#{uri}'.
+'''),
+
+      MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
+        const MessageTemplate(
+          MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
+          """
+dart:mirrors library is not supported when using this backend.
+
+Your app imports dart:mirrors via:""""""
+$MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING#{importChain}"""),
+
+      MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS:
+        const MessageTemplate(MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS,
+          "Non-supported 'call' member on a native class, or a "
+          "subclass of a native class."),
+
+      MessageKind.DIRECTLY_THROWING_NSM:
+        const MessageTemplate(MessageKind.DIRECTLY_THROWING_NSM,
+          "This 'noSuchMethod' implementation is guaranteed to throw an "
+          "exception. The generated code will be smaller if it is "
+          "rewritten.",
+          howToFix: "Rewrite to "
+                    "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'."),
+
+      MessageKind.COMPLEX_THROWING_NSM:
+        const MessageTemplate(MessageKind.COMPLEX_THROWING_NSM,
+          "This 'noSuchMethod' implementation is guaranteed to throw an "
+          "exception. The generated code will be smaller and the compiler "
+          "will be able to perform more optimizations if it is rewritten.",
+          howToFix: "Rewrite to "
+                    "'noSuchMethod(Invocation i) => super.noSuchMethod(i);'."),
+
+      MessageKind.COMPLEX_RETURNING_NSM:
+        const MessageTemplate(MessageKind.COMPLEX_RETURNING_NSM,
+          "Overriding 'noSuchMethod' causes the compiler to generate "
+          "more code and prevents the compiler from doing some optimizations.",
+          howToFix: "Consider removing this 'noSuchMethod' implementation."),
+
+      MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP:
+        const MessageTemplate(MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP,
+          "Unsupported version of package:lookup_map.",
+          howToFix: DONT_KNOW_HOW_TO_FIX),
+
+  }); // End of TEMPLATES.
+
+  /// Padding used before and between import chains in the message for
+  /// [MessageKind.IMPORT_EXPERIMENTAL_MIRRORS].
+  static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n*   ';
+
+  /// Padding used before and between import chains in the message for
+  /// [MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND].
+  static const String MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING = '\n   ';
+
+  /// Padding used before and between import chains in the message for
+  /// [MessageKind.DISALLOWED_LIBRARY_IMPORT].
+  static const String DISALLOWED_LIBRARY_IMPORT_PADDING = '\n  ';
 
   toString() => template;
 
@@ -901,42 +3613,7 @@
     return new Message(this, arguments, terse);
   }
 
-  bool get hasHowToFix =>
-      howToFix != null && howToFix != dart2js_messages.DONT_KNOW_HOW_TO_FIX;
-
-  static final Map<MessageKind, MessageTemplate> TEMPLATES =
-      _constructMessageTemplates();
-
-  static String get IMPORT_EXPERIMENTAL_MIRRORS_PADDING =>
-      dart2js_messages.IMPORT_EXPERIMENTAL_MIRRORS_PADDING;
-
-  static String get MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING =>
-      dart2js_messages.MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING;
-
-  static String get DISALLOWED_LIBRARY_IMPORT_PADDING =>
-      dart2js_messages.DISALLOWED_LIBRARY_IMPORT_PADDING;
-
-  static Map<MessageKind, MessageTemplate> _constructMessageTemplates() {
-    Map<MessageKind, MessageTemplate> result = <MessageKind, MessageTemplate>{};
-    for (MessageKind kind in MessageKind.values) {
-      String name = _KIND_TO_STRING_MAP[kind];
-      if (name == null) {
-        throw new ArgumentError("No mapping for $kind in _KIND_TO_STRING_MAP");
-      }
-      Map data =
-          shared_messages.MESSAGES[name] ?? dart2js_messages.MESSAGES[name];
-      if (data == null) throw new ArgumentError.value(name);
-
-      String id = data['id'];
-      String template = data['template'];
-      String howToFix = data['howToFix'];
-      List examples = data['examples'];
-      List<String> options = data['options'] ?? const <String>[];
-      result[kind] =
-          new MessageTemplate(kind, id, template, howToFix, examples, options);
-    }
-    return result;
-  }
+  bool get hasHowToFix => howToFix != null && howToFix != DONT_KNOW_HOW_TO_FIX;
 }
 
 class Message {
@@ -946,10 +3623,7 @@
   String message;
 
   Message(this.template, this.arguments, this.terse) {
-    assert(() {
-      computeMessage();
-      return true;
-    });
+    assert(() { computeMessage(); return true; });
   }
 
   MessageKind get kind => template.kind;
@@ -963,7 +3637,7 @@
       assert(invariant(
           CURRENT_ELEMENT_SPANNABLE,
           kind == MessageKind.GENERIC ||
-              !message.contains(new RegExp(r'#\{.+\}')),
+            !message.contains(new RegExp(r'#\{.+\}')),
           message: 'Missing arguments in error message: "$message"'));
       if (!terse && template.hasHowToFix) {
         String howToFix = template.howToFix;
@@ -980,8 +3654,8 @@
     return computeMessage();
   }
 
-  bool operator ==(other) {
-    if (other is! Message) return false;
+  bool operator==(other) {
+    if (other is !Message) return false;
     return (template == other.template) && (toString() == other.toString());
   }
 
diff --git a/pkg/compiler/lib/src/diagnostics/source_span.dart b/pkg/compiler/lib/src/diagnostics/source_span.dart
index 95c3c75..25bdc6c 100644
--- a/pkg/compiler/lib/src/diagnostics/source_span.dart
+++ b/pkg/compiler/lib/src/diagnostics/source_span.dart
@@ -20,7 +20,7 @@
 
   factory SourceSpan.fromNode(Uri uri, Node node) {
     return new SourceSpan.fromTokens(
-        uri, node.getBeginToken(), node.getEndToken());
+        uri, node.getBeginToken(), node.getPrefixEndToken());
   }
 
   factory SourceSpan.fromTokens(Uri uri, Token begin, Token end) {
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 207954d..d909a47 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -54,7 +54,7 @@
     compiler.dumpInfoTask._constantToNode.forEach((constant, node) {
       // TODO(sigmund): add dependencies on other constants
       var size = compiler.dumpInfoTask._nodeToSize[node];
-      var code = jsAst.prettyPrint(node, compiler).getText();
+      var code = jsAst.prettyPrint(node, compiler);
       var info = new ConstantInfo(
           size: size, code: code, outputUnit: _unitInfoForConstant(constant));
       _constantToInfo[constant] = info;
@@ -529,7 +529,7 @@
     // Concatenate rendered ASTs.
     StringBuffer sb = new StringBuffer();
     for (jsAst.Node ast in code) {
-      sb.writeln(jsAst.prettyPrint(ast, compiler).getText());
+      sb.writeln(jsAst.prettyPrint(ast, compiler));
     }
     return sb.toString();
   }
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index c25e955..469081c 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -11,6 +11,8 @@
     Compiler;
 import '../constants/constructors.dart';
 import '../constants/expressions.dart';
+import '../core_types.dart' show
+    CoreClasses;
 import '../dart_types.dart';
 import '../resolution/scope.dart' show
     Scope;
@@ -1430,7 +1432,7 @@
 
   /// Returns `true` if this class implements [Function] either by directly
   /// implementing the interface or by providing a [call] method.
-  bool implementsFunction(Compiler compiler);
+  bool implementsFunction(CoreClasses coreClasses);
 
   /// Returns `true` if this class extends [cls] directly or indirectly.
   ///
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index 550b3c9..121a882 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -13,6 +13,8 @@
 import '../constants/constant_constructors.dart';
 import '../constants/constructors.dart';
 import '../constants/expressions.dart';
+import '../core_types.dart' show
+    CoreClasses;
 import '../dart_types.dart';
 import '../diagnostics/messages.dart' show
     MessageTemplate;
@@ -2113,14 +2115,7 @@
     if (span != null && hasNode) {
       FunctionExpression functionExpression = node.asFunctionExpression();
       if (functionExpression != null) {
-        Token begin = functionExpression.getBeginToken();
-        Token end;
-        if (functionExpression.parameters != null) {
-          end = functionExpression.parameters.getEndToken();
-        } else {
-          end = functionExpression.name.getEndToken();
-        }
-        span = new SourceSpan.fromTokens(span.uri, begin, end);
+        span = new SourceSpan.fromNode(span.uri, functionExpression);
       }
     }
     return span;
@@ -2706,8 +2701,8 @@
     backendMembers.forEach(f);
   }
 
-  bool implementsFunction(Compiler compiler) {
-    return asInstanceOf(compiler.coreClasses.functionClass) != null ||
+  bool implementsFunction(CoreClasses coreClasses) {
+    return asInstanceOf(coreClasses.functionClass) != null ||
         callType != null;
   }
 
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index f897876..9628684 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -413,6 +413,9 @@
     FunctionSignature signature = function.functionSignature;
     signature.forEachOptionalParameter((ParameterElement element) {
       ast.Expression defaultValue = element.initializer;
+      // TODO(25566): The default value of a parameter of a redirecting factory
+      // constructor comes from the corresponding parameter of the target.
+
       // If this is a default value from a different context (because
       // the current function is synthetic, e.g., a constructor from
       // a mixin application), we have to start a new inferrer visitor
@@ -1309,6 +1312,24 @@
   }
 
   @override
+  T visitSuperGetterSet(
+      ast.Send node,
+      MethodElement getter,
+      ast.Node rhs,
+      _) {
+    return handleErroneousSuperSend(node);
+  }
+
+  @override
+  T visitUnresolvedSuperSet(
+      ast.Send node,
+      Element element,
+      ast.Node rhs,
+      _) {
+    return handleErroneousSuperSend(node);
+  }
+
+  @override
   T visitUnresolvedSuperInvoke(
       ast.Send node,
       Element element,
@@ -1482,54 +1503,50 @@
     return super.handleTypeLiteralInvoke(arguments);
   }
 
-  /// Handle constructor invocation of [element].
-  T handleConstructorSend(ast.Send node, ConstructorElement element) {
+  /// Handle constructor invocation of [constructor].
+  T handleConstructorSend(ast.Send node, ConstructorElement constructor) {
+    ConstructorElement target = constructor.implementation;
     ArgumentsTypes arguments = analyzeArguments(node.arguments);
     if (visitingInitializers) {
       if (ast.Initializers.isConstructorRedirect(node)) {
         isConstructorRedirect = true;
       } else if (ast.Initializers.isSuperConstructorCall(node)) {
         seenSuperConstructorCall = true;
-        analyzeSuperConstructorCall(element, arguments);
+        analyzeSuperConstructorCall(constructor, arguments);
       }
     }
-    // If we are looking at a new expression on a forwarding factory,
-    // we have to forward the call to the effective target of the
-    // factory.
-    if (element.isFactoryConstructor) {
-      // TODO(herhut): Remove the while loop once effectiveTarget forwards to
-      //               patches.
-      while (element.isFactoryConstructor) {
-        ConstructorElement constructor = element;
-        if (!constructor.isRedirectingFactory) break;
-        element = constructor.effectiveTarget.implementation;
-      }
+    // If we are looking at a new expression on a forwarding factory, we have to
+    // forward the call to the effective target of the factory.
+    // TODO(herhut): Remove the loop once effectiveTarget forwards to patches.
+    while (target.isFactoryConstructor) {
+      if (!target.isRedirectingFactory) break;
+      target = target.effectiveTarget.implementation;
     }
-    if (compiler.backend.isForeign(element)) {
-      return handleForeignSend(node, element);
+    if (compiler.backend.isForeign(target)) {
+      return handleForeignSend(node, target);
     }
     Selector selector = elements.getSelector(node);
     TypeMask mask = elements.getTypeMask(node);
     // In erroneous code the number of arguments in the selector might not
     // match the function element.
     // TODO(polux): return nonNullEmpty and check it doesn't break anything
-    if (!selector.applies(element, compiler.world) ||
-        (mask != null && !mask.canHit(element, selector, compiler.world))) {
+    if (!selector.applies(target, compiler.world) ||
+        (mask != null && !mask.canHit(target, selector, compiler.world))) {
       return types.dynamicType;
     }
 
-    T returnType = handleStaticSend(node, selector, mask, element, arguments);
-    if (Elements.isGrowableListConstructorCall(element, node, compiler)) {
+    T returnType = handleStaticSend(node, selector, mask, target, arguments);
+    if (Elements.isGrowableListConstructorCall(constructor, node, compiler)) {
       return inferrer.concreteTypes.putIfAbsent(
           node, () => types.allocateList(
               types.growableListType, node, outermostElement,
               types.nonNullEmpty(), 0));
-    } else if (Elements.isFixedListConstructorCall(element, node, compiler)
-        || Elements.isFilledListConstructorCall(element, node, compiler)) {
+    } else if (Elements.isFixedListConstructorCall(constructor, node, compiler)
+        || Elements.isFilledListConstructorCall(constructor, node, compiler)) {
 
       int length = findLength(node);
       T elementType =
-          Elements.isFixedListConstructorCall(element, node, compiler)
+          Elements.isFixedListConstructorCall(constructor, node, compiler)
               ? types.nullType
               : arguments.positional[1];
 
@@ -1537,15 +1554,14 @@
           node, () => types.allocateList(
               types.fixedListType, node, outermostElement,
               elementType, length));
-    } else if (Elements.isConstructorOfTypedArraySubclass(element, compiler)) {
+    } else if (
+        Elements.isConstructorOfTypedArraySubclass(constructor, compiler)) {
       int length = findLength(node);
-      ConstructorElement constructor = element.implementation;
-      constructor = constructor.effectiveTarget;
       T elementType = inferrer.returnTypeOfElement(
-          constructor.enclosingClass.lookupMember('[]'));
+          target.enclosingClass.lookupMember('[]'));
       return inferrer.concreteTypes.putIfAbsent(
         node, () => types.allocateList(
-          types.nonNullExact(constructor.enclosingClass), node,
+          types.nonNullExact(target.enclosingClass), node,
           outermostElement, elementType, length));
     } else {
       return returnType;
diff --git a/pkg/compiler/lib/src/info/send_info.dart b/pkg/compiler/lib/src/info/send_info.dart
index 8292be4..96e0e98 100644
--- a/pkg/compiler/lib/src/info/send_info.dart
+++ b/pkg/compiler/lib/src/info/send_info.dart
@@ -1619,6 +1619,10 @@
     handleNSMSuper(node, element.enclosingClass);
   }
 
+  void visitUnresolvedSuperSet(Send node, Element element, Node rhs, T arg) {
+    handleNSMSuper(node, element.enclosingClass);
+  }
+
   void visitUnresolvedSuperSetIfNull(
       Send node, Element element, Node rhs, T arg) {
     handleNSMSuper(node, element.enclosingClass);
diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
index 967de65..7f5b996 100644
--- a/pkg/compiler/lib/src/io/code_output.dart
+++ b/pkg/compiler/lib/src/io/code_output.dart
@@ -102,8 +102,12 @@
   }
 }
 
+abstract class BufferedCodeOutput {
+  String getText();
+}
+
 /// [CodeOutput] using a [StringBuffer] as backend.
-class CodeBuffer extends AbstractCodeOutput {
+class CodeBuffer extends AbstractCodeOutput implements BufferedCodeOutput {
   StringBuffer buffer = new StringBuffer();
 
   @override
diff --git a/pkg/compiler/lib/src/io/position_information.dart b/pkg/compiler/lib/src/io/position_information.dart
index 0e384c3..8966763 100644
--- a/pkg/compiler/lib/src/io/position_information.dart
+++ b/pkg/compiler/lib/src/io/position_information.dart
@@ -10,14 +10,18 @@
 import '../common.dart';
 import '../elements/elements.dart' show
     AstElement,
+    FieldElement,
     LocalElement;
 import '../js/js.dart' as js;
 import '../js/js_source_mapping.dart';
 import '../js/js_debug.dart';
 import '../tree/tree.dart' show
+    FunctionExpression,
     Node,
     Send;
 
+import 'code_output.dart' show
+    CodeBuffer;
 import 'source_file.dart';
 import 'source_information.dart';
 
@@ -113,15 +117,43 @@
   SourceInformationProcessor createProcessor(SourceMapper mapper) {
     return new PositionSourceInformationProcessor(mapper);
   }
+
+  @override
+  void onComplete() {}
+
+  @override
+  SourceInformation buildSourceMappedMarker() {
+    return const SourceMappedMarker();
+  }
+}
+
+/// Marker used to tag the root nodes of source-mapped code.
+///
+/// This is needed to be able to distinguish JavaScript nodes that shouldn't
+/// have source locations (like the premable) from the nodes that should
+/// (like functions compiled from Dart code).
+class SourceMappedMarker extends SourceInformation {
+  const SourceMappedMarker();
+
+  @override
+  String get shortText => '';
+
+  @override
+  List<SourceLocation> get sourceLocations => const <SourceLocation>[];
+
+  @override
+  SourceSpan get sourceSpan => new SourceSpan(null, null, null);
 }
 
 /// [SourceInformationBuilder] that generates [PositionSourceInformation].
 class PositionSourceInformationBuilder implements SourceInformationBuilder {
   final SourceFile sourceFile;
   final String name;
+  final AstElement element;
 
   PositionSourceInformationBuilder(AstElement element)
-      : sourceFile = element.implementation.compilationUnit.script.file,
+      : this.element = element,
+        sourceFile = element.implementation.compilationUnit.script.file,
         name = computeElementNameForSourceMaps(element);
 
   SourceInformation buildDeclaration(AstElement element) {
@@ -213,6 +245,23 @@
   SourceInformation buildAssignment(Node node) => buildBegin(node);
 
   @override
+  SourceInformation buildVariableDeclaration() {
+    if (element.hasNode) {
+      Node node = element.node;
+      if (node is FunctionExpression) {
+        return buildBegin(node.body);
+      } else if (element.isField) {
+        FieldElement field = element;
+        if (field.initializer != null) {
+          return buildBegin(field.initializer);
+        }
+      }
+      // TODO(johnniwinther): Are there other cases?
+    }
+    return null;
+  }
+
+  @override
   SourceInformationBuilder forContext(AstElement element) {
     return new PositionSourceInformationBuilder(element);
   }
@@ -225,10 +274,31 @@
   final int closingPosition;
 
   CodePosition(this.startPosition, this.endPosition, this.closingPosition);
+
+  int getPosition(CodePositionKind kind) {
+    switch (kind) {
+      case CodePositionKind.START:
+        return startPosition;
+      case CodePositionKind.END:
+        return endPosition;
+      case CodePositionKind.CLOSING:
+        return closingPosition;
+    }
+  }
+
+  String toString() {
+    return 'CodePosition(start=$startPosition,'
+           'end=$endPosition,closing=$closingPosition)';
+  }
+}
+
+/// A map from a [js.Node] to its [CodePosition].
+abstract class CodePositionMap {
+  CodePosition operator [](js.Node node);
 }
 
 /// Registry for mapping [js.Node]s to their [CodePosition].
-class CodePositionRecorder {
+class CodePositionRecorder implements CodePositionMap {
   Map<js.Node, CodePosition> _codePositionMap =
       new Map<js.Node, CodePosition>.identity();
 
@@ -247,204 +317,107 @@
   CodePosition operator [](js.Node node) => _codePositionMap[node];
 }
 
+/// Enum values for the part of a Dart node used for the source location offset.
 enum SourcePositionKind {
+  /// The source mapping should point to the start of the Dart node.
+  ///
+  /// For instance the first '(' for the `(*)()` call and 'f' of both the
+  /// `foo()` and the `*.bar()` call:
+  ///
+  ///     (foo().bar())()
+  ///     ^                       // the start of the `(*)()` node
+  ///      ^                      // the start of the `foo()` node
+  ///      ^                      // the start of the `*.bar()` node
+  ///
   START,
-  CLOSING,
-  END,
+
+  /// The source mapping should point an inner position of the Dart node.
+  ///
+  /// For instance the second '(' of the `(*)()` call, the 'f' of the `foo()`
+  /// call and the 'b' of the `*.bar()` call:
+  ///
+  ///     (foo().bar())()
+  ///                  ^          // the inner position of the `(*)()` node
+  ///      ^                      // the inner position of the `foo()` node
+  ///            ^                // the inner position of the `*.bar()` node
+  ///
+  /// For function expressions the inner position is the closing brace or the
+  /// arrow:
+  ///
+  ///     foo() => () {}
+  ///           ^                 // the inner position of the 'foo' function
+  ///                  ^          // the inner position of the closure
+  ///
+  INNER,
 }
 
+SourceLocation getSourceLocation(
+    SourceInformation sourceInformation,
+    [SourcePositionKind sourcePositionKind = SourcePositionKind.START]) {
+  if (sourceInformation == null) return null;
+  switch (sourcePositionKind) {
+    case SourcePositionKind.START:
+      return sourceInformation.startPosition;
+    case SourcePositionKind.INNER:
+      return sourceInformation.closingPosition;
+  }
+}
+
+/// Enum values for the part of the JavaScript node used for the JavaScript
+/// code offset of a source mapping.
 enum CodePositionKind {
+  /// The source mapping is put on left-most offset of the node.
+  ///
+  /// For instance on the 'f' of a function or 'r' of a return statement:
+  ///
+  ///     foo: function() { return 0; }
+  ///          ^                              // the function start position
+  ///                       ^                 // the return start position
   START,
+
+  /// The source mapping is put on the closing token.
+  ///
+  /// For instance on the '}' of a function or the ';' of a return statement:
+  ///
+  ///     foo: function() { return 0; }
+  ///                                 ^       // the function closing position
+  ///                               ^         // the return closing position
+  ///
   CLOSING,
+
+  /// The source mapping is put at the end of the code for the node.
+  ///
+  /// For instance after '}' of a function or after the ';' of a return
+  /// statement:
+  ///
+  ///     foo: function() { return 0; }
+  ///                                  ^       // the function end position
+  ///                                ^         // the return end position
+  ///
   END,
 }
 
 /// Processor that associates [SourceLocation]s from [SourceInformation] on
 /// [js.Node]s with the target offsets in a [SourceMapper].
-class PositionSourceInformationProcessor
-    extends js.BaseVisitor implements SourceInformationProcessor {
-  final CodePositionRecorder codePositions = new CodePositionRecorder();
-  final SourceMapper sourceMapper;
+class PositionSourceInformationProcessor implements SourceInformationProcessor {
+  final CodePositionRecorder codePositionRecorder = new CodePositionRecorder();
+  CodePositionMap codePositionMap;
+  List<TraceListener> traceListeners;
 
-  PositionSourceInformationProcessor(this.sourceMapper);
-
-  void process(js.Node node) {
-    node.accept(this);
-  }
-
-  void visitChildren(js.Node node) {
-    node.visitChildren(this);
-  }
-
-  CodePosition getCodePosition(js.Node node) {
-    return codePositions[node];
-  }
-
-  /// Associates [sourceInformation] with the JavaScript [node].
-  ///
-  /// The offset into the JavaScript code is computed by pulling the
-  /// [codePositionKind] from the code positions associated with
-  /// [codePositionNode].
-  ///
-  /// The mapped Dart source location is computed by pulling the
-  /// [sourcePositionKind] source location from [sourceInformation].
-  void apply(js.Node node,
-             js.Node codePositionNode,
-             CodePositionKind codePositionKind,
-             SourceInformation sourceInformation,
-             SourcePositionKind sourcePositionKind) {
-    if (sourceInformation != null) {
-      CodePosition codePosition = getCodePosition(codePositionNode);
-      // We should always have recorded the needed code positions.
-      assert(invariant(
-          NO_LOCATION_SPANNABLE,
-          codePosition != null,
-          message:
-            "Code position missing for "
-            "${nodeToString(codePositionNode)}:\n"
-            "${DebugPrinter.prettyPrint(node)}"));
-      if (codePosition == null) return;
-      int codeLocation;
-      SourceLocation sourceLocation;
-      switch (codePositionKind) {
-        case CodePositionKind.START:
-          codeLocation = codePosition.startPosition;
-          break;
-        case CodePositionKind.CLOSING:
-          codeLocation = codePosition.closingPosition;
-          break;
-        case CodePositionKind.END:
-          codeLocation = codePosition.endPosition;
-          break;
-      }
-      switch (sourcePositionKind) {
-        case SourcePositionKind.START:
-          sourceLocation = sourceInformation.startPosition;
-          break;
-        case SourcePositionKind.CLOSING:
-          sourceLocation = sourceInformation.closingPosition;
-          break;
-        case SourcePositionKind.END:
-          sourceLocation = sourceInformation.endPosition;
-          break;
-      }
-      if (codeLocation != null && sourceLocation != null) {
-        sourceMapper.register(node, codeLocation, sourceLocation);
-      }
+  PositionSourceInformationProcessor(
+      SourceMapper sourceMapper,
+      [Coverage coverage]) {
+    codePositionMap = coverage != null
+              ? new CodePositionCoverage(codePositionRecorder, coverage)
+              : codePositionRecorder;
+    traceListeners = [new PositionTraceListener(sourceMapper)];
+    if (coverage != null) {
+      traceListeners.add(new CoverageListener(coverage));
     }
   }
 
-  @override
-  visitNode(js.Node node) {
-    SourceInformation sourceInformation = node.sourceInformation;
-    if (sourceInformation != null) {
-      /// Associates the left-most position of the JS code with the left-most
-      /// position of the Dart code.
-      apply(node,
-          node, CodePositionKind.START,
-          sourceInformation, SourcePositionKind.START);
-    }
-    visitChildren(node);
-  }
-
-  @override
-  visitFun(js.Fun node) {
-    SourceInformation sourceInformation = node.sourceInformation;
-    if (sourceInformation != null) {
-      /// Associates the end brace of the JavaScript function with the end brace
-      /// of the Dart function (or the `;` in case of arrow notation).
-      apply(node,
-          node, CodePositionKind.CLOSING,
-          sourceInformation, SourcePositionKind.CLOSING);
-    }
-
-    visitChildren(node);
-  }
-
-  @override
-  visitExpressionStatement(js.ExpressionStatement node) {
-    visitChildren(node);
-  }
-
-  @override
-  visitBinary(js.Binary node) {
-    visitChildren(node);
-  }
-
-  @override
-  visitAccess(js.PropertyAccess node) {
-    visitChildren(node);
-  }
-
-  @override
-  visitCall(js.Call node) {
-    SourceInformation sourceInformation = node.sourceInformation;
-    if (sourceInformation != null) {
-      if (node.target is js.PropertyAccess) {
-        js.PropertyAccess access = node.target;
-        js.Node target = access;
-        bool pureAccess = false;
-        while (target is js.PropertyAccess) {
-          js.PropertyAccess targetAccess = target;
-          if (targetAccess.receiver is js.VariableUse ||
-              targetAccess.receiver is js.This) {
-            pureAccess = true;
-            break;
-          } else {
-            target = targetAccess.receiver;
-          }
-        }
-        if (pureAccess) {
-          // a.m()   this.m()  a.b.c.d.m()
-          // ^       ^         ^
-          apply(
-              node,
-              node,
-              CodePositionKind.START,
-              sourceInformation,
-              SourcePositionKind.START);
-        } else {
-          // *.m()  *.a.b.c.d.m()
-          //   ^              ^
-          apply(
-              node,
-              access.selector,
-              CodePositionKind.START,
-              sourceInformation,
-              SourcePositionKind.CLOSING);
-        }
-      } else if (node.target is js.VariableUse) {
-        // m()
-        // ^
-        apply(
-            node,
-            node,
-            CodePositionKind.START,
-            sourceInformation,
-            SourcePositionKind.START);
-      } else if (node.target is js.Fun || node.target is js.New) {
-        // function(){}()  new Function("...")()
-        //             ^                      ^
-        apply(
-            node,
-            node.target,
-            CodePositionKind.END,
-            sourceInformation,
-            SourcePositionKind.CLOSING);
-      } else {
-        assert(invariant(NO_LOCATION_SPANNABLE, false,
-            message: "Unexpected property access ${nodeToString(node)}:\n"
-                     "${DebugPrinter.prettyPrint(node)}"));
-        // Don't know....
-        apply(
-            node,
-            node,
-            CodePositionKind.START,
-            sourceInformation,
-            SourcePositionKind.START);
-      }
-    }
-    visitChildren(node);
+  void process(js.Node node, CodeBuffer codeBuffer) {
+    new JavaScriptTracer(codePositionMap, traceListeners).apply(node);
   }
 
   @override
@@ -452,7 +425,852 @@
                    int startPosition,
                    int endPosition,
                    int closingPosition) {
-    codePositions.registerPositions(
+    codePositionRecorder.registerPositions(
         node, startPosition, endPosition, closingPosition);
   }
 }
+
+/// Visitor that computes [SourceInformation] for a [js.Node] using information
+/// attached to the node itself or alternatively from child nodes.
+class NodeSourceInformation extends js.BaseVisitor<SourceInformation> {
+  const NodeSourceInformation();
+
+  SourceInformation visit(js.Node node) => node?.accept(this);
+
+  @override
+  SourceInformation visitNode(js.Node node) => node.sourceInformation;
+
+  @override
+  SourceInformation visitExpressionStatement(js.ExpressionStatement node) {
+    if (node.sourceInformation != null) {
+      return node.sourceInformation;
+    }
+    return visit(node.expression);
+  }
+
+  @override
+  SourceInformation visitVariableDeclarationList(
+      js.VariableDeclarationList node) {
+    if (node.sourceInformation != null) {
+      return node.sourceInformation;
+    }
+    for (js.Node declaration in node.declarations) {
+      SourceInformation sourceInformation = visit(declaration);
+      if (sourceInformation != null) {
+        return sourceInformation;
+      }
+    }
+    return null;
+  }
+
+  @override
+  SourceInformation visitVariableInitialization(
+      js.VariableInitialization node) {
+    if (node.sourceInformation != null) {
+      return node.sourceInformation;
+    }
+    return visit(node.value);
+  }
+
+  @override
+  SourceInformation visitAssignment(js.Assignment node) {
+    if (node.sourceInformation != null) {
+      return node.sourceInformation;
+    }
+    return visit(node.value);
+  }
+
+}
+
+/// Mixin that add support for computing [SourceInformation] for a [js.Node].
+class NodeToSourceInformationMixin {
+  SourceInformation computeSourceInformation(js.Node node) {
+    return const NodeSourceInformation().visit(node);
+  }
+}
+
+/// [TraceListener] that register [SourceLocation]s with a [SourceMapper].
+class PositionTraceListener extends TraceListener with
+    NodeToSourceInformationMixin {
+  final SourceMapper sourceMapper;
+
+  PositionTraceListener(this.sourceMapper);
+
+  @override
+  void onStep(js.Node node, Offset offset, StepKind kind) {
+    SourceInformation sourceInformation = computeSourceInformation(node);
+    if (sourceInformation == null) return;
+
+    SourcePositionKind sourcePositionKind = SourcePositionKind.START;
+    switch (kind) {
+      case StepKind.FUN:
+        sourcePositionKind = SourcePositionKind.INNER;
+        break;
+      case StepKind.CALL:
+        CallPosition callPosition =
+            CallPosition.getSemanticPositionForCall(node);
+        sourcePositionKind = callPosition.sourcePositionKind;
+        break;
+      case StepKind.NEW:
+      case StepKind.RETURN:
+      case StepKind.BREAK:
+      case StepKind.CONTINUE:
+      case StepKind.THROW:
+      case StepKind.EXPRESSION_STATEMENT:
+      case StepKind.IF_CONDITION:
+      case StepKind.FOR_INITIALIZER:
+      case StepKind.FOR_CONDITION:
+      case StepKind.FOR_UPDATE:
+      case StepKind.WHILE_CONDITION:
+      case StepKind.DO_CONDITION:
+      case StepKind.SWITCH_EXPRESSION:
+        break;
+    }
+    int codeLocation = offset.subexpressionOffset;
+    SourceLocation sourceLocation =
+        getSourceLocation(sourceInformation, sourcePositionKind);
+    if (codeLocation != null && sourceLocation != null) {
+      sourceMapper.register(node, codeLocation, sourceLocation);
+    }
+  }
+}
+
+/// The position of a [js.Call] node.
+class CallPosition {
+  final js.Node node;
+  final CodePositionKind codePositionKind;
+  final SourcePositionKind sourcePositionKind;
+
+  CallPosition(this.node, this.codePositionKind, this.sourcePositionKind);
+
+  /// Computes the [CallPosition] for [node].
+  static CallPosition getSemanticPositionForCall(js.Call node) {
+    if (node.target is js.PropertyAccess) {
+      js.PropertyAccess access = node.target;
+      js.Node target = access;
+      bool pureAccess = false;
+      while (target is js.PropertyAccess) {
+        js.PropertyAccess targetAccess = target;
+        if (targetAccess.receiver is js.VariableUse ||
+            targetAccess.receiver is js.This) {
+          pureAccess = true;
+          break;
+        } else {
+          target = targetAccess.receiver;
+        }
+      }
+      if (pureAccess) {
+        // a.m()   this.m()  a.b.c.d.m()
+        // ^       ^         ^
+        return new CallPosition(
+            node,
+            CodePositionKind.START,
+            SourcePositionKind.START);
+      } else {
+        // *.m()  *.a.b.c.d.m()
+        //   ^              ^
+        return new CallPosition(
+            access.selector,
+            CodePositionKind.START,
+            SourcePositionKind.INNER);
+      }
+    } else if (node.target is js.VariableUse) {
+      // m()
+      // ^
+      return new CallPosition(
+          node,
+          CodePositionKind.START,
+          SourcePositionKind.START);
+    } else if (node.target is js.Fun || node.target is js.New) {
+      // function(){}()  new Function("...")()
+      //             ^                      ^
+      return new CallPosition(
+          node.target,
+          CodePositionKind.END,
+          SourcePositionKind.INNER);
+    } else if (node.target is js.Binary || node.target is js.Call) {
+      // (0,a)()   m()()
+      //      ^       ^
+      return new CallPosition(
+          node.target,
+          CodePositionKind.END,
+          SourcePositionKind.INNER);
+    } else {
+      assert(invariant(NO_LOCATION_SPANNABLE, false,
+          message: "Unexpected property access ${nodeToString(node)}:\n"
+                   "${DebugPrinter.prettyPrint(node)}"));
+      // Don't know....
+      return new CallPosition(
+          node,
+          CodePositionKind.START,
+          SourcePositionKind.START);
+    }
+  }
+}
+
+class Offset {
+  /// The offset of the enclosing statement relative to the beginning of the
+  /// file.
+  ///
+  /// For instance:
+  ///
+  ///     foo().bar(baz());
+  ///     ^                  // the statement offset of the `foo()` call
+  ///     ^                  // the statement offset of the `*.bar()` call
+  ///     ^                  // the statement offset of the `baz()` call
+  ///
+  final int statementOffset;
+
+  /// The `subexpression` offset of the step. This is the (mostly) unique
+  /// offset relative to the beginning of the file, that identifies the
+  /// current of execution.
+  ///
+  /// For instance:
+  ///
+  ///     foo().bar(baz());
+  ///     ^                   // the subexpression offset of the `foo()` call
+  ///           ^             // the subexpression offset of the `*.bar()` call
+  ///               ^         // the subexpression offset of the `baz()` call
+  ///
+  /// Here, even though the JavaScript node for the `*.bar()` call contains
+  /// the `foo()` its execution is identified by the `bar` identifier more than
+  /// the foo identifier.
+  ///
+  final int subexpressionOffset;
+
+  /// The `left-to-right` offset of the step. This is like [subexpressionOffset]
+  /// bute restricted so that the offset of each subexpression in execution
+  /// order is monotonically increasing.
+  ///
+  /// For instance:
+  ///
+  ///     foo().bar(baz());
+  ///     ^                   // the left-to-right offset of the `foo()` call
+  ///           ^             // the left-to-right offset of the `*.bar()` call
+  ///     ^                   // the left-to-right offset of the `baz()` call
+  ///
+  /// Here, `baz()` is executed before `foo()` so we need to use 'f' as its best
+  /// position under the restriction.
+  ///
+  final int leftToRightOffset;
+
+  Offset(this.statementOffset, this.leftToRightOffset, this.subexpressionOffset);
+
+  String toString() {
+    return 'Offset[statementOffset=$statementOffset,'
+        'leftToRightOffset=$leftToRightOffset,'
+        'subexpressionOffset=$subexpressionOffset]';
+  }
+}
+
+enum BranchKind {
+  CONDITION,
+  LOOP,
+  CATCH,
+  FINALLY,
+  CASE,
+}
+
+enum StepKind {
+  FUN,
+  CALL,
+  NEW,
+  RETURN,
+  BREAK,
+  CONTINUE,
+  THROW,
+  EXPRESSION_STATEMENT,
+  IF_CONDITION,
+  FOR_INITIALIZER,
+  FOR_CONDITION,
+  FOR_UPDATE,
+  WHILE_CONDITION,
+  DO_CONDITION,
+  SWITCH_EXPRESSION,
+}
+
+/// Listener for the [JavaScriptTracer].
+abstract class TraceListener {
+  /// Called before [root] node is procesed by the [JavaScriptTracer].
+  void onStart(js.Node root) {}
+
+  /// Called after [root] node has been procesed by the [JavaScriptTracer].
+  void onEnd(js.Node root) {}
+
+  /// Called when a branch of the given [kind] is started. [value] is provided
+  /// to distinguish true/false branches of [BranchKind.CONDITION] and cases of
+  /// [Branch.CASE].
+  void pushBranch(BranchKind kind, [value]) {}
+
+  /// Called when the current branch ends.
+  void popBranch() {}
+
+  /// Called when [node] defines a step of the given [kind] at the given
+  /// [offset] when the generated JavaScript code.
+  void onStep(js.Node node, Offset offset, StepKind kind) {}
+}
+
+/// Visitor that computes the [js.Node]s the are part of the JavaScript
+/// steppable execution and thus needs source mapping locations.
+class JavaScriptTracer extends js.BaseVisitor  {
+  final CodePositionMap codePositions;
+  final List<TraceListener> listeners;
+
+  /// The steps added by subexpressions.
+  List steps = [];
+
+  /// The offset of the current statement.
+  int statementOffset;
+
+  /// The current offset in left-to-right progression.
+  int leftToRightOffset;
+
+  /// The offset of the surrounding statement, used for the first subexpression.
+  int offsetPosition;
+
+  bool active;
+
+  JavaScriptTracer(this.codePositions,
+           this.listeners,
+           {this.active: false});
+
+  void notifyStart(js.Node node) {
+    listeners.forEach((listener) => listener.onStart(node));
+  }
+
+  void notifyEnd(js.Node node) {
+    listeners.forEach((listener) => listener.onEnd(node));
+  }
+
+  void notifyPushBranch(BranchKind kind, [value]) {
+    if (active) {
+      listeners.forEach((listener) => listener.pushBranch(kind, value));
+    }
+  }
+
+  void notifyPopBranch() {
+    if (active) {
+      listeners.forEach((listener) => listener.popBranch());
+    }
+  }
+
+  void notifyStep(js.Node node, Offset offset, StepKind kind) {
+    if (active) {
+      listeners.forEach((listener) => listener.onStep(node, offset, kind));
+    }
+  }
+
+  void apply(js.Node node) {
+    notifyStart(node);
+    node.accept(this);
+    notifyEnd(node);
+  }
+
+  @override
+  visitNode(js.Node node) {
+    node.visitChildren(this);
+  }
+
+  visit(js.Node node, [BranchKind branch, value]) {
+    if (node != null) {
+      if (branch != null) {
+        notifyPushBranch(branch, value);
+        node.accept(this);
+        notifyPopBranch();
+      } else {
+        node.accept(this);
+      }
+    }
+  }
+
+  visitList(List<js.Node> nodeList) {
+    if (nodeList != null) {
+      for (js.Node node in nodeList) {
+        visit(node);
+      }
+    }
+  }
+
+  @override
+  visitFun(js.Fun node) {
+    bool activeBefore = active;
+    if (!active) {
+      active = node.sourceInformation != null;
+    }
+    visit(node.body);
+    leftToRightOffset = statementOffset =
+        getSyntaxOffset(node, kind: CodePositionKind.CLOSING);
+    Offset offset = getOffsetForNode(node, statementOffset);
+    notifyStep(node, offset, StepKind.FUN);
+    active = activeBefore;
+  }
+
+  @override
+  visitBlock(js.Block node) {
+    for (js.Statement statement in node.statements) {
+      visit(statement);
+    }
+  }
+
+  int getSyntaxOffset(js.Node node,
+                      {CodePositionKind kind: CodePositionKind.START}) {
+    CodePosition codePosition = codePositions[node];
+    if (codePosition != null) {
+      return codePosition.getPosition(kind);
+    }
+    return null;
+  }
+
+  visitSubexpression(js.Node parent,
+                     js.Expression child,
+                     int codeOffset,
+                     StepKind kind) {
+    var oldSteps = steps;
+    steps = [];
+    offsetPosition = codeOffset;
+    visit(child);
+    if (steps.isEmpty) {
+      notifyStep(parent,
+          getOffsetForNode(parent, offsetPosition),
+          kind);
+      // The [offsetPosition] should only be used by the first subexpression.
+      offsetPosition = null;
+    }
+    steps = oldSteps;
+  }
+
+  @override
+  visitExpressionStatement(js.ExpressionStatement node) {
+    statementOffset = getSyntaxOffset(node);
+    visitSubexpression(
+        node, node.expression, statementOffset,
+        StepKind.EXPRESSION_STATEMENT);
+    statementOffset = null;
+    leftToRightOffset = null;
+  }
+
+  @override
+  visitEmptyStatement(js.EmptyStatement node) {}
+
+  @override
+  visitCall(js.Call node) {
+    visit(node.target);
+    int oldPosition = offsetPosition;
+    offsetPosition = null;
+    visitList(node.arguments);
+    offsetPosition = oldPosition;
+    CallPosition callPosition =
+        CallPosition.getSemanticPositionForCall(node);
+    js.Node positionNode = callPosition.node;
+    int callOffset = getSyntaxOffset(
+        positionNode, kind: callPosition.codePositionKind);
+    if (offsetPosition == null) {
+      // Use the call offset if this is not the first subexpression.
+      offsetPosition = callOffset;
+    }
+    Offset offset = getOffsetForNode(positionNode, offsetPosition);
+    notifyStep(node, offset, StepKind.CALL);
+    steps.add(node);
+    offsetPosition = null;
+  }
+
+  @override
+  visitNew(js.New node) {
+    visit(node.target);
+    visitList(node.arguments);
+    if (offsetPosition == null) {
+      // Use the syntax offset if this is not the first subexpression.
+      offsetPosition = getSyntaxOffset(node);
+    }
+    notifyStep(
+        node, getOffsetForNode(node, offsetPosition), StepKind.NEW);
+    steps.add(node);
+    offsetPosition = null;
+  }
+
+  @override
+  visitAccess(js.PropertyAccess node) {
+    visit(node.receiver);
+    visit(node.selector);
+  }
+
+  @override
+  visitVariableUse(js.VariableUse node) {}
+
+  @override
+  visitLiteralBool(js.LiteralBool node) {}
+
+  @override
+  visitLiteralString(js.LiteralString node) {}
+
+  @override
+  visitLiteralNumber(js.LiteralNumber node) {}
+
+  @override
+  visitLiteralNull(js.LiteralNull node) {}
+
+  @override
+  visitName(js.Name node) {}
+
+  @override
+  visitVariableDeclarationList(js.VariableDeclarationList node) {
+    visitList(node.declarations);
+  }
+
+  @override
+  visitVariableDeclaration(js.VariableDeclaration node) {}
+
+  @override
+  visitVariableInitialization(js.VariableInitialization node) {
+    visit(node.leftHandSide);
+    visit(node.value);
+  }
+
+  @override
+  visitAssignment(js.Assignment node) {
+    visit(node.leftHandSide);
+    visit(node.value);
+  }
+
+  @override
+  visitIf(js.If node) {
+    statementOffset = getSyntaxOffset(node);
+    visitSubexpression(node, node.condition, statementOffset,
+        StepKind.IF_CONDITION);
+    statementOffset = null;
+    visit(node.then, BranchKind.CONDITION, true);
+    visit(node.otherwise, BranchKind.CONDITION, false);
+  }
+
+  @override
+  visitFor(js.For node) {
+    int offset = statementOffset = getSyntaxOffset(node);
+    statementOffset = offset;
+    leftToRightOffset = null;
+    if (node.init != null) {
+      visitSubexpression(node, node.init, getSyntaxOffset(node),
+          StepKind.FOR_INITIALIZER);
+    }
+
+    if (node.condition != null) {
+      visitSubexpression(node, node.condition, getSyntaxOffset(node.condition),
+          StepKind.FOR_CONDITION);
+    }
+
+    notifyPushBranch(BranchKind.LOOP);
+    visit(node.body);
+
+    statementOffset = offset;
+    if (node.update != null) {
+      visitSubexpression(node, node.update, getSyntaxOffset(node.update),
+          StepKind.FOR_UPDATE);
+    }
+
+    notifyPopBranch();
+  }
+
+  @override
+  visitWhile(js.While node) {
+    statementOffset = getSyntaxOffset(node);
+    if (node.condition != null) {
+      visitSubexpression(node, node.condition, getSyntaxOffset(node),
+          StepKind.WHILE_CONDITION);
+    }
+    statementOffset = null;
+    leftToRightOffset = null;
+
+    visit(node.body, BranchKind.LOOP);
+  }
+
+  @override
+  visitDo(js.Do node) {
+    statementOffset = getSyntaxOffset(node);
+    visit(node.body);
+    if (node.condition != null) {
+      visitSubexpression(node, node.condition, getSyntaxOffset(node.condition),
+          StepKind.DO_CONDITION);
+    }
+    statementOffset = null;
+    leftToRightOffset = null;
+  }
+
+  @override
+  visitBinary(js.Binary node) {
+    visit(node.left);
+    visit(node.right);
+  }
+
+  @override
+  visitThis(js.This node) {}
+
+  @override
+  visitReturn(js.Return node) {
+    statementOffset = getSyntaxOffset(node);
+    visit(node.value);
+    notifyStep(
+        node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.RETURN);
+    statementOffset = null;
+    leftToRightOffset = null;
+  }
+
+  @override
+  visitThrow(js.Throw node) {
+    statementOffset = getSyntaxOffset(node);
+    // Do not use [offsetPosition] for the subexpression.
+    offsetPosition = null;
+    visit(node.expression);
+    notifyStep(
+        node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.THROW);
+    statementOffset = null;
+    leftToRightOffset = null;
+  }
+
+  @override
+  visitContinue(js.Continue node) {
+    statementOffset = getSyntaxOffset(node);
+    notifyStep(
+        node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.CONTINUE);
+    statementOffset = null;
+    leftToRightOffset = null;
+  }
+
+  @override
+  visitBreak(js.Break node) {
+    statementOffset = getSyntaxOffset(node);
+    notifyStep(
+        node, getOffsetForNode(node, getSyntaxOffset(node)), StepKind.BREAK);
+    statementOffset = null;
+    leftToRightOffset = null;
+  }
+
+  @override
+  visitTry(js.Try node) {
+    visit(node.body);
+    visit(node.catchPart, BranchKind.CATCH);
+    visit(node.finallyPart, BranchKind.FINALLY);
+  }
+
+  @override
+  visitCatch(js.Catch node) {
+    visit(node.body);
+  }
+
+  @override
+  visitConditional(js.Conditional node) {
+    visit(node.condition);
+    visit(node.then, BranchKind.CONDITION, true);
+    visit(node.otherwise, BranchKind.CONDITION, false);
+  }
+
+  @override
+  visitPrefix(js.Prefix node) {
+    visit(node.argument);
+  }
+
+  @override
+  visitPostfix(js.Postfix node) {
+    visit(node.argument);
+  }
+
+  @override
+  visitObjectInitializer(js.ObjectInitializer node) {
+    visitList(node.properties);
+  }
+
+  @override
+  visitProperty(js.Property node) {
+    visit(node.name);
+    visit(node.value);
+  }
+
+  @override
+  visitRegExpLiteral(js.RegExpLiteral node) {}
+
+  @override
+  visitSwitch(js.Switch node) {
+    statementOffset = getSyntaxOffset(node);
+    visitSubexpression(node, node.key, getSyntaxOffset(node),
+        StepKind.SWITCH_EXPRESSION);
+    statementOffset = null;
+    leftToRightOffset = null;
+    for (int i = 0; i < node.cases.length; i++) {
+      visit(node.cases[i], BranchKind.CASE, i);
+    }
+  }
+
+  @override
+  visitCase(js.Case node) {
+    visit(node.expression);
+    visit(node.body);
+  }
+
+  @override
+  visitDefault(js.Default node) {
+    visit(node.body);
+  }
+
+  @override
+  visitArrayInitializer(js.ArrayInitializer node) {
+    visitList(node.elements);
+  }
+
+  @override
+  visitArrayHole(js.ArrayHole node) {}
+
+  @override
+  visitLabeledStatement(js.LabeledStatement node) {
+    statementOffset = getSyntaxOffset(node);
+    visit(node.body);
+    statementOffset = null;
+  }
+
+  Offset getOffsetForNode(js.Node node, int codeOffset) {
+    if (codeOffset == null) {
+      CodePosition codePosition = codePositions[node];
+      if (codePosition != null) {
+        codeOffset = codePosition.startPosition;
+      }
+    }
+    if (leftToRightOffset != null && leftToRightOffset < codeOffset) {
+      leftToRightOffset = codeOffset;
+    }
+    if (leftToRightOffset == null) {
+      leftToRightOffset = statementOffset;
+    }
+    return new Offset(statementOffset, leftToRightOffset, codeOffset);
+  }
+}
+
+
+class Coverage {
+  Set<js.Node> _nodesWithInfo = new Set<js.Node>();
+  int _nodesWithInfoCount = 0;
+  Set<js.Node> _nodesWithoutInfo = new Set<js.Node>();
+  int _nodesWithoutInfoCount = 0;
+  Map<Type, int> _nodesWithoutInfoCountByType = <Type, int>{};
+  Set<js.Node> _nodesWithoutOffset = new Set<js.Node>();
+  int _nodesWithoutOffsetCount = 0;
+
+  void registerNodeWithInfo(js.Node node) {
+    _nodesWithInfo.add(node);
+  }
+
+  void registerNodeWithoutInfo(js.Node node) {
+    _nodesWithoutInfo.add(node);
+  }
+
+  void registerNodesWithoutOffset(js.Node node) {
+    _nodesWithoutOffset.add(node);
+  }
+
+  void collapse() {
+    _nodesWithInfoCount += _nodesWithInfo.length;
+    _nodesWithInfo.clear();
+    _nodesWithoutOffsetCount += _nodesWithoutOffset.length;
+    _nodesWithoutOffset.clear();
+
+    _nodesWithoutInfoCount += _nodesWithoutInfo.length;
+    for (js.Node node in _nodesWithoutInfo) {
+      if (node is js.ExpressionStatement) {
+        _nodesWithoutInfoCountByType.putIfAbsent(
+            node.expression.runtimeType, () => 0);
+        _nodesWithoutInfoCountByType[node.expression.runtimeType]++;
+      } else {
+        _nodesWithoutInfoCountByType.putIfAbsent(
+            node.runtimeType, () => 0);
+        _nodesWithoutInfoCountByType[node.runtimeType]++;
+      }
+    }
+    _nodesWithoutInfo.clear();
+  }
+
+  String getCoverageReport() {
+    collapse();
+    StringBuffer sb = new StringBuffer();
+    int total = _nodesWithInfoCount + _nodesWithoutInfoCount;
+    if (total > 0) {
+      sb.write(_nodesWithInfoCount);
+      sb.write('/');
+      sb.write(total);
+      sb.write(' (');
+      sb.write((100.0 * _nodesWithInfoCount / total).toStringAsFixed(2));
+      sb.write('%) nodes with info.');
+    } else {
+      sb.write('No nodes.');
+    }
+    if (_nodesWithoutOffsetCount > 0) {
+      sb.write(' ');
+      sb.write(_nodesWithoutOffsetCount);
+      sb.write(' node');
+      if (_nodesWithoutOffsetCount > 1) {
+        sb.write('s');
+      }
+      sb.write(' without offset.');
+    }
+    if (_nodesWithoutInfoCount > 0) {
+      sb.write('\nNodes without info (');
+      sb.write(_nodesWithoutInfoCount);
+      sb.write(') by runtime type:');
+      List<Type> types = _nodesWithoutInfoCountByType.keys.toList();
+      types.sort((a, b) {
+        return -_nodesWithoutInfoCountByType[a].compareTo(
+            _nodesWithoutInfoCountByType[b]);
+      });
+
+      types.forEach((Type type) {
+        int count = _nodesWithoutInfoCountByType[type];
+        sb.write('\n ');
+        sb.write(count);
+        sb.write(' ');
+        sb.write(type);
+        sb.write(' node');
+        if (count > 1) {
+          sb.write('s');
+        }
+      });
+      sb.write('\n');
+    }
+    return sb.toString();
+  }
+
+  String toString() => getCoverageReport();
+}
+
+/// [TraceListener] that registers [onStep] callbacks with [coverage].
+class CoverageListener extends TraceListener with NodeToSourceInformationMixin {
+  final Coverage coverage;
+
+  CoverageListener(this.coverage);
+
+  @override
+  void onStep(js.Node node, Offset offset, StepKind kind) {
+    SourceInformation sourceInformation = computeSourceInformation(node);
+    if (sourceInformation != null) {
+      coverage.registerNodeWithInfo(node);
+    } else {
+      coverage.registerNodeWithoutInfo(node);
+    }
+  }
+
+  @override
+  void onEnd(js.Node node) {
+    coverage.collapse();
+  }
+}
+
+/// [CodePositionMap] that registers calls with [Coverage].
+class CodePositionCoverage implements CodePositionMap {
+  final CodePositionMap codePositions;
+  final Coverage coverage;
+
+  CodePositionCoverage(this.codePositions, this.coverage);
+
+  @override
+  CodePosition operator [](js.Node node) {
+    CodePosition codePosition = codePositions[node];
+    if (codePosition == null) {
+      coverage.registerNodesWithoutOffset(node);
+   }
+    return codePosition;
+  }
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
index 1855755..da46d43 100644
--- a/pkg/compiler/lib/src/io/source_information.dart
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -21,6 +21,8 @@
 /// Interface for passing source information, for instance for use in source
 /// maps, through the backend.
 abstract class SourceInformation extends JavaScriptNodeSourceInformation {
+  const SourceInformation();
+
   SourceSpan get sourceSpan;
 
   /// The source location associated with the start of the JS node.
@@ -47,6 +49,12 @@
   SourceInformationBuilder createBuilderForContext(AstElement element) {
     return const SourceInformationBuilder();
   }
+
+  /// Generate [SourceInformation] marker for non-preamble code.
+  SourceInformation buildSourceMappedMarker() => null;
+
+  /// Called when compilation has completed.
+  void onComplete() {}
 }
 
 /// Interface for generating [SourceInformation].
@@ -96,6 +104,10 @@
 
   /// Generate [SourceInformation] for the assignment in [node].
   SourceInformation buildAssignment(Node node) => null;
+
+  /// Generate [SourceInformation] for the variable declaration inserted as
+  /// first statement of a function.
+  SourceInformation buildVariableDeclaration() => null;
 }
 
 /// A location in a source file.
diff --git a/pkg/compiler/lib/src/io/start_end_information.dart b/pkg/compiler/lib/src/io/start_end_information.dart
index 988c77d..8cae566 100644
--- a/pkg/compiler/lib/src/io/start_end_information.dart
+++ b/pkg/compiler/lib/src/io/start_end_information.dart
@@ -116,7 +116,7 @@
 }
 
 class StartEndSourceInformationStrategy
-    implements JavaScriptSourceInformationStrategy {
+    extends JavaScriptSourceInformationStrategy {
   const StartEndSourceInformationStrategy();
 
   @override
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index 3a9fd2e..df510a8 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -20,12 +20,30 @@
 
 import 'js_source_mapping.dart';
 
-CodeBuffer prettyPrint(Node node,
-                       Compiler compiler,
-                       {DumpInfoTask monitor,
-                        bool allowVariableMinification: true,
-                        Renamer renamerForNames:
-                            JavaScriptPrintingOptions.identityRenamer}) {
+String prettyPrint(
+    Node node,
+    Compiler compiler,
+    {bool allowVariableMinification: true,
+     Renamer renamerForNames: JavaScriptPrintingOptions.identityRenamer}) {
+  // TODO(johnniwinther): Do we need all the options here?
+  JavaScriptPrintingOptions options = new JavaScriptPrintingOptions(
+      shouldCompressOutput: compiler.enableMinification,
+      minifyLocalVariables: allowVariableMinification,
+      preferSemicolonToNewlineInMinifiedOutput: USE_LAZY_EMITTER,
+      renamerForNames: renamerForNames);
+  SimpleJavaScriptPrintingContext context =
+      new SimpleJavaScriptPrintingContext();
+  Printer printer = new Printer(options, context);
+  printer.visit(node);
+  return context.getText();
+}
+
+CodeBuffer createCodeBuffer(
+    Node node,
+    Compiler compiler,
+    {DumpInfoTask monitor,
+     bool allowVariableMinification: true,
+     Renamer renamerForNames: JavaScriptPrintingOptions.identityRenamer}) {
   JavaScriptSourceInformationStrategy sourceInformationFactory =
       compiler.backend.sourceInformationStrategy;
   JavaScriptPrintingOptions options = new JavaScriptPrintingOptions(
@@ -35,14 +53,14 @@
       renamerForNames: renamerForNames);
   CodeBuffer outBuffer = new CodeBuffer();
   SourceInformationProcessor sourceInformationProcessor =
-      sourceInformationFactory.createProcessor(
-          new SourceLocationsMapper(outBuffer));
+        sourceInformationFactory.createProcessor(
+            new SourceLocationsMapper(outBuffer));
   Dart2JSJavaScriptPrintingContext context =
       new Dart2JSJavaScriptPrintingContext(
           compiler.reporter, monitor, outBuffer, sourceInformationProcessor);
   Printer printer = new Printer(options, context);
   printer.visit(node);
-  sourceInformationProcessor.process(node);
+  sourceInformationProcessor.process(node, outBuffer);
   return outBuffer;
 }
 
@@ -137,13 +155,13 @@
   /// A [js.Literal] that represents the string result of unparsing [ast].
   ///
   /// When its string [value] is requested, the node pretty-prints the given
-  /// [ast] and, if [protectForEval] is true, wraps the resulting
-  /// string in parenthesis. The result is also escaped.
+  /// [ast] and, if [protectForEval] is true, wraps the resulting string in
+  /// parenthesis. The result is also escaped.
   UnparsedNode(this.tree, this._compiler, this._protectForEval);
 
   LiteralString get _literal {
     if (_cachedLiteral == null) {
-      String text = prettyPrint(tree, _compiler).getText();
+      String text = prettyPrint(tree, _compiler);
       if (_protectForEval) {
         if (tree is Fun) text = '($text)';
         if (tree is LiteralExpression) {
@@ -164,6 +182,12 @@
   String get value => _literal.value;
 }
 
+/// True if the given template consists of just a placeholder. Such templates
+/// are sometimes used to manually promote the type of an expression.
+bool isIdentityTemplate(Template template) {
+  return template.ast is InterpolatedExpression;
+}
+
 /// Returns `true` if [template] will immediately give a TypeError if the first
 /// placeholder is `null` or `undefined`.
 bool isNullGuardOnFirstArgument(Template template) {
diff --git a/pkg/compiler/lib/src/js/js_debug.dart b/pkg/compiler/lib/src/js/js_debug.dart
index 43ec130..c8cbd0de 100644
--- a/pkg/compiler/lib/src/js/js_debug.dart
+++ b/pkg/compiler/lib/src/js/js_debug.dart
@@ -7,7 +7,12 @@
 library js.debug;
 
 import 'package:js_ast/js_ast.dart';
-import '../util/util.dart' show Indentation, Tagging;
+
+import '../io/code_output.dart' show
+    BufferedCodeOutput;
+import '../util/util.dart' show
+    Indentation,
+    Tagging;
 
 /// Unparse the JavaScript [node].
 String nodeToString(Node node) {
@@ -25,8 +30,8 @@
 class DebugPrinter extends BaseVisitor with Indentation, Tagging<Node> {
   StringBuffer sb = new StringBuffer();
 
-  void visitNodeWithChildren(Node node, String type) {
-    openNode(node, type);
+  void visitNodeWithChildren(Node node, String type, [Map params]) {
+    openNode(node, type, params);
     node.visitChildren(this);
     closeNode();
   }
@@ -42,6 +47,11 @@
   }
 
   @override
+  void visitBinary(Binary node) {
+    visitNodeWithChildren(node, '${node.runtimeType}', {'op': node.op});
+  }
+
+  @override
   void visitLiteralString(LiteralString node) {
     openAndCloseNode(node, '${node.runtimeType}', {'value': node.value});
   }
@@ -57,7 +67,8 @@
 }
 
 /// Simple printing context that doesn't throw on errors.
-class LenientPrintingContext extends SimpleJavaScriptPrintingContext {
+class LenientPrintingContext extends SimpleJavaScriptPrintingContext
+    implements BufferedCodeOutput {
   @override
   void error(String message) {
     buffer.write('>>$message<<');
diff --git a/pkg/compiler/lib/src/js/js_source_mapping.dart b/pkg/compiler/lib/src/js/js_source_mapping.dart
index 0378a58..cd72e35 100644
--- a/pkg/compiler/lib/src/js/js_source_mapping.dart
+++ b/pkg/compiler/lib/src/js/js_source_mapping.dart
@@ -5,7 +5,10 @@
 library js.source_mapping;
 
 import 'js.dart';
-import '../io/code_output.dart' show SourceLocations;
+import '../io/code_output.dart' show
+    BufferedCodeOutput,
+    CodeBuffer,
+    SourceLocations;
 import '../io/source_information.dart' show
     SourceLocation,
     SourceInformation,
@@ -64,5 +67,5 @@
 
   /// Process the source information and code positions for the [node] and all
   /// its children.
-  void process(Node node) {}
+  void process(Node node, BufferedCodeOutput code) {}
 }
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 05b00d1..14d1f6e 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -502,7 +502,7 @@
 
   bool enabledNoSuchMethod = false;
 
-  final SourceInformationStrategy sourceInformationStrategy;
+  SourceInformationStrategy sourceInformationStrategy;
 
   final BackendHelpers helpers;
   final BackendImpacts impacts;
@@ -520,7 +520,7 @@
         this.sourceInformationStrategy =
             generateSourceMap
                 ? (useNewSourceInfo
-                     ? const PositionSourceInformationStrategy()
+                     ? new PositionSourceInformationStrategy()
                      : const StartEndSourceInformationStrategy())
                 : const JavaScriptSourceInformationStrategy(),
         helpers = new BackendHelpers(compiler),
@@ -559,8 +559,18 @@
     return constantCompilerTask.jsConstantCompiler;
   }
 
-  FunctionElement resolveExternalFunction(FunctionElement element) {
-    if (isForeign(element) || isJsInterop(element)) return element;
+  MethodElement resolveExternalFunction(MethodElement element) {
+    if (isForeign(element)) {
+      return element;
+    }
+    if (isJsInterop(element))  {
+      if (element.memberName == const PublicName('[]') ||
+          element.memberName == const PublicName('[]=')) {
+        reporter.reportErrorMessage(element,
+            MessageKind.JS_INTEROP_INDEX_NOT_SUPPORTED);
+      }
+      return element;
+    }
     return patchResolverTask.measure(() {
       return patchResolverTask.resolveExternalFunction(element);
     });
@@ -940,14 +950,14 @@
 
   final Map<String, Set<ClassElement>> interceptedClassesCache =
       new Map<String, Set<ClassElement>>();
+  final Set<ClassElement> _noClasses = new Set<ClassElement>();
 
-  /**
-   * Returns a set of interceptor classes that contain a member named
-   * [name]. Returns [:null:] if there is no class.
-   */
+  /// Returns a set of interceptor classes that contain a member named [name]
+  ///
+  /// Returns an empty set if there is no class. Do not modify the returned set.
   Set<ClassElement> getInterceptedClassesOn(String name) {
     Set<Element> intercepted = interceptedElements[name];
-    if (intercepted == null) return null;
+    if (intercepted == null) return _noClasses;
     return interceptedClassesCache.putIfAbsent(name, () {
       // Populate the cache by running through all the elements and
       // determine if the given selector applies to them.
@@ -974,13 +984,12 @@
     Iterable<MixinApplicationElement> uses = classWorld.mixinUsesOf(mixin);
     Set<ClassElement> result = null;
     for (MixinApplicationElement use in uses) {
-      Iterable<ClassElement> subclasses = classWorld.strictSubclassesOf(use);
-      for (ClassElement subclass in subclasses) {
+      classWorld.forEachStrictSubclassOf(use, (ClassElement subclass) {
         if (isNativeOrExtendsNative(subclass)) {
           if (result == null) result = new Set<ClassElement>();
           result.add(subclass);
         }
-      }
+      });
     }
     return result;
   }
@@ -1251,6 +1260,10 @@
       addInterceptors(helpers.jsFixedArrayClass, enqueuer, registry);
       addInterceptors(helpers.jsExtendableArrayClass, enqueuer, registry);
       addInterceptors(helpers.jsUnmodifiableArrayClass, enqueuer, registry);
+      // Literal lists can be translated into calls to these functions:
+      enqueueInResolution(helpers.jsArrayTypedConstructor, registry);
+      enqueueInResolution(helpers.setRuntimeTypeInfo, registry);
+      enqueueInResolution(helpers.getTypeArgumentByIndex, registry);
     } else if (cls == coreClasses.intClass ||
                cls == helpers.jsIntClass) {
       addInterceptors(helpers.jsIntClass, enqueuer, registry);
@@ -1630,7 +1643,12 @@
       }
     }
 
-    generatedCode[element] = functionCompiler.compile(work);
+    jsAst.Fun function = functionCompiler.compile(work);
+    if (function.sourceInformation == null) {
+      function = function.withSourceInformation(
+          sourceInformationStrategy.buildSourceMappedMarker());
+    }
+    generatedCode[element] = function;
     WorldImpact worldImpact =
         impactTransformer.transformCodegenImpact(work.registry.worldImpact);
     compiler.dumpInfoTask.registerImpact(element, worldImpact);
@@ -1661,7 +1679,7 @@
    */
   String getGeneratedCode(Element element) {
     assert(invariant(element, element.isDeclaration));
-    return jsAst.prettyPrint(generatedCode[element], compiler).getText();
+    return jsAst.prettyPrint(generatedCode[element], compiler);
   }
 
   int assembleProgram() {
@@ -2191,7 +2209,7 @@
         });
         // 4) all overriding members of subclasses/subtypes (should be resolved)
         if (compiler.world.hasAnyStrictSubtype(cls)) {
-          for (ClassElement subcls in compiler.world.strictSubtypesOf(cls)) {
+          compiler.world.forEachStrictSubtypeOf(cls, (ClassElement subcls) {
             subcls.forEachClassMember((Member member) {
               if (memberNames.contains(member.name)) {
                 // TODO(20993): find out why this assertion fails.
@@ -2202,7 +2220,7 @@
                 }
               }
             });
-          }
+          });
         }
         // 5) all its closures
         List<LocalFunctionElement> closures = closureMap[cls];
@@ -2509,13 +2527,13 @@
       compiler.enabledInvokeOn = true;
     }
   }
-
+/*
   CodeBuffer codeOf(Element element) {
     return generatedCode.containsKey(element)
         ? jsAst.prettyPrint(generatedCode[element], compiler)
         : null;
   }
-
+*/
   FunctionElement helperForBadMain() => helpers.badMain;
 
   FunctionElement helperForMissingMain() => helpers.missingMain;
@@ -2559,6 +2577,7 @@
   @override
   bool enableCodegenWithErrorsIfSupported(Spannable node) {
     if (compiler.useCpsIr) {
+      // TODO(25747): Support code generation with compile-time errors.
       reporter.reportHintMessage(
           node,
           MessageKind.GENERIC,
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index f25e13b..29e6743 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -652,4 +652,4 @@
     }
     return _closure;
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index bc8ed93..4d0f497 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -91,7 +91,10 @@
   js.Fun buildFunction(tree_ir.FunctionDefinition function) {
     registerDefaultParameterValues(function.element);
     currentFunction = function.element;
-    visitStatement(function.body);
+    tree_ir.Statement statement = function.body;
+    while (statement != null) {
+      statement = visitStatement(statement);
+    }
 
     List<js.Parameter> parameters = new List<js.Parameter>();
     Set<tree_ir.Variable> parameterSet = new Set<tree_ir.Variable>();
@@ -121,6 +124,9 @@
       if (assign.op != null) break; // Compound assignment.
       js.VariableUse use = assign.leftHandSide;
 
+      // Do not touch non-local variables.
+      if (!usedVariableNames.contains(use.name)) break;
+
       // We cannot declare a variable more than once.
       if (!declaredVariables.add(use.name)) break;
 
@@ -144,6 +150,9 @@
       if (assign.op != null) break pullFromForLoop; // Compound assignment.
       js.VariableUse use = assign.leftHandSide;
 
+      // Do not touch non-local variables.
+      if (!usedVariableNames.contains(use.name)) break pullFromForLoop;
+
       // We cannot declare a variable more than once.
       if (!declaredVariables.add(use.name)) break pullFromForLoop;
 
@@ -218,9 +227,11 @@
 
   List<js.Expression> visitExpressionList(
       List<tree_ir.Expression> expressions) {
-    return new List<js.Expression>.generate(expressions.length,
-        (int index) => visitExpression(expressions[index]),
-        growable: false);
+    List<js.Expression> result = new List<js.Expression>(expressions.length);
+    for (int i = 0; i < expressions.length; ++i) {
+      result[i] = visitExpression(expressions[i]);
+    }
+    return result;
   }
 
   giveup(tree_ir.Node node,
@@ -364,26 +375,6 @@
   }
 
   @override
-  js.Expression visitLiteralMap(tree_ir.LiteralMap node) {
-    ConstructorElement constructor;
-    if (node.entries.isEmpty) {
-      constructor = glue.mapLiteralConstructorEmpty;
-    } else {
-      constructor = glue.mapLiteralConstructor;
-    }
-    List<js.Expression> entries =
-        new List<js.Expression>(2 * node.entries.length);
-    for (int i = 0; i < node.entries.length; i++) {
-      entries[2 * i] = visitExpression(node.entries[i].key);
-      entries[2 * i + 1] = visitExpression(node.entries[i].value);
-    }
-    List<js.Expression> args = entries.isEmpty
-         ? <js.Expression>[]
-         : <js.Expression>[new js.ArrayInitializer(entries)];
-    return buildStaticInvoke(constructor, args);
-  }
-
-  @override
   js.Expression visitLogicalOperator(tree_ir.LogicalOperator node) {
     return new js.Binary(
         node.operator,
@@ -405,13 +396,19 @@
   ///
   /// Even if the class is never instantiated, a JS constructor must be emitted
   /// so the 'instanceof' expression does not throw an exception at runtime.
-  ///
-  /// It does not help to ask the class world if the class is instantiated,
-  /// because it could still get tree-shaken if it is unused after optimization.
-  void registerInstanceofCheck(ClassElement class_) {
-    // TODO(asgerf): This is the only hook we have to ensure the JS constructor
-    //   gets emitted, but it is very imprecise. We should do better.
-    registry.registerInstantiatedClass(class_);
+  bool tryRegisterInstanceofCheck(ClassElement class_) {
+    if (glue.classWorld.isInstantiated(class_)) {
+      // Ensure the class remains instantiated during backend tree-shaking.
+      // TODO(asgerf): We could have a more precise hook to inform the emitter
+      // that the JS constructor function is needed, without the class being
+      // instantiated.
+      registry.registerInstantiatedClass(class_);
+      return true;
+    }
+    // Will throw if the JS constructor is not emitted, so do not allow the
+    // instanceof check.  This should only happen when certain optimization
+    // passes are disabled, as the type check itself is trivial.
+    return false;
   }
 
   @override
@@ -435,8 +432,8 @@
         // TODO(sra): Implement fast cast via calling 'boolTypeCast'.
       } else if (node.isTypeTest &&
                  node.typeArguments.isEmpty &&
-                 glue.mayGenerateInstanceofCheck(type)) {
-        registerInstanceofCheck(clazz);
+                 glue.mayGenerateInstanceofCheck(type) &&
+                 tryRegisterInstanceofCheck(clazz)) {
         return js.js('# instanceof #', [value, glue.constructorAccess(clazz)]);
       }
 
@@ -618,14 +615,15 @@
   }
 
   @override
-  void visitExpressionStatement(tree_ir.ExpressionStatement node) {
+  visitExpressionStatement(tree_ir.ExpressionStatement node) {
     js.Expression exp = visitExpression(node.expression);
     if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
       // Emit as 'return exp' to assist local analysis in the VM.
       accumulator.add(new js.Return(exp));
+      return null;
     } else {
       accumulator.add(new js.ExpressionStatement(exp));
-      visitStatement(node.next);
+      return node.next;
     }
   }
 
@@ -639,7 +637,7 @@
   }
 
   @override
-  void visitIf(tree_ir.If node) {
+  visitIf(tree_ir.If node) {
     js.Expression condition = visitExpression(node.condition);
     int usesBefore = fallthrough.useCount;
     // Unless the 'else' part ends the method. make sure to terminate any
@@ -651,21 +649,22 @@
     if (thenHasFallthrough) {
       js.Statement elseBody = buildBodyStatement(node.elseStatement);
       accumulator.add(new js.If(condition, thenBody, elseBody));
+      return null;
     } else {
       // The 'then' body cannot complete normally, so emit a short 'if'
       // and put the 'else' body after it.
       accumulator.add(new js.If.noElse(condition, thenBody));
-      visitStatement(node.elseStatement);
+      return node.elseStatement;
     }
   }
 
   @override
-  void visitLabeledStatement(tree_ir.LabeledStatement node) {
+  visitLabeledStatement(tree_ir.LabeledStatement node) {
     fallthrough.push(node.next);
     js.Statement body = buildBodyStatement(node.body);
     fallthrough.pop();
     accumulator.add(insertLabel(node.label, body));
-    visitStatement(node.next);
+    return node.next;
   }
 
   /// Creates a name for [label] if it does not already have one.
@@ -697,7 +696,9 @@
   js.Statement buildBodyStatement(tree_ir.Statement statement) {
     List<js.Statement> savedAccumulator = accumulator;
     accumulator = <js.Statement>[];
-    visitStatement(statement);
+    while (statement != null) {
+      statement = visitStatement(statement);
+    }
     js.Statement result = _bodyAsStatement();
     accumulator = savedAccumulator;
     return result;
@@ -706,7 +707,9 @@
   js.Block buildBodyBlock(tree_ir.Statement statement) {
     List<js.Statement> savedAccumulator = accumulator;
     accumulator = <js.Statement>[];
-    visitStatement(statement);
+    while (statement != null) {
+      statement = visitStatement(statement);
+    }
     js.Statement result = new js.Block(accumulator);
     accumulator = savedAccumulator;
     return result;
@@ -717,7 +720,7 @@
   }
 
   @override
-  void visitFor(tree_ir.For node) {
+  visitFor(tree_ir.For node) {
     js.Expression condition = visitExpression(node.condition);
     shortBreak.push(node.next);
     shortContinue.push(node);
@@ -744,12 +747,11 @@
       loopNode = new js.For(init, condition, update, body);
     }
     accumulator.add(insertLabel(node.label, loopNode));
-    visitStatement(node.next);
+    return node.next;
   }
 
   @override
   void visitWhileTrue(tree_ir.WhileTrue node) {
-    js.Expression condition = new js.LiteralBool(true);
     // A short break in the while will jump to the current fallthrough target.
     shortBreak.push(fallthrough.target);
     shortContinue.push(node);
@@ -764,7 +766,8 @@
       fallthrough.use();
     }
     shortBreak.pop();
-    accumulator.add(insertLabel(node.label, new js.While(condition, jsBody)));
+    accumulator.add(
+        insertLabel(node.label, new js.For(null, null, null, jsBody)));
   }
 
   bool isNull(tree_ir.Expression node) {
@@ -824,17 +827,14 @@
       registry.registerInstantiatedClosure(classElement.methodElement);
     }
     js.Expression instance = new js.New(
-        glue.constructorAccess(classElement),
-        visitExpressionList(node.arguments))
+            glue.constructorAccess(classElement),
+            visitExpressionList(node.arguments))
         .withSourceInformation(node.sourceInformation);
 
-    List<tree_ir.Expression> typeInformation = node.typeInformation;
-    assert(typeInformation.isEmpty ||
-        typeInformation.length == classElement.typeVariables.length);
-    if (typeInformation.isNotEmpty) {
+    tree_ir.Expression typeInformation = node.typeInformation;
+    if (typeInformation != null) {
       FunctionElement helper = glue.getAddRuntimeTypeInformation();
-      js.Expression typeArguments = new js.ArrayInitializer(
-          visitExpressionList(typeInformation));
+      js.Expression typeArguments = visitExpression(typeInformation);
       return buildStaticHelperInvocation(helper,
           <js.Expression>[instance, typeArguments],
           sourceInformation: node.sourceInformation);
@@ -921,8 +921,7 @@
     registry.registerStaticUse(
         new StaticUse.staticSet(node.element.declaration));
     js.Expression field = glue.staticFieldAccess(node.element);
-    js.Expression value = visitExpression(node.value);
-    return new js.Assignment(field, value);
+    return makeAssignment(field, node.value, compound: node.compound);
   }
 
   @override
@@ -987,7 +986,17 @@
   @override
   js.Expression visitTypeExpression(tree_ir.TypeExpression node) {
     List<js.Expression> arguments = visitExpressionList(node.arguments);
-    return glue.generateTypeRepresentation(node.dartType, arguments, registry);
+    switch (node.kind) {
+      case tree_ir.TypeExpressionKind.COMPLETE:
+        return glue.generateTypeRepresentation(
+            node.dartType, arguments, registry);
+      case tree_ir.TypeExpressionKind.INSTANCE:
+        // We expect only flat types for the INSTANCE representation.
+        assert(node.dartType ==
+               (node.dartType.element as ClassElement).thisType);
+        registry.registerInstantiatedClass(glue.listClass);
+        return new js.ArrayInitializer(arguments);
+    }
   }
 
   js.Node handleForeignCode(tree_ir.ForeignCode node) {
@@ -1015,14 +1024,14 @@
   }
 
   @override
-  void visitYield(tree_ir.Yield node) {
+  visitYield(tree_ir.Yield node) {
     js.Expression value = visitExpression(node.input);
     accumulator.add(new js.DartYield(value, node.hasStar));
-    visitStatement(node.next);
+    return node.next;
   }
 
   @override
-  void visitNullCheck(tree_ir.NullCheck node) {
+  visitReceiverCheck(tree_ir.ReceiverCheck node) {
     js.Expression value = visitExpression(node.value);
     // TODO(sra): Try to use the selector even when [useSelector] is false. The
     // reason we use 'toString' is that it is always defined so avoids a slow
@@ -1032,9 +1041,12 @@
     // hook for that selector. We don't know these things here, but the decision
     // could be deferred by creating a deferred property that was resolved after
     // codegen.
-    js.Expression access = node.selector != null && node.useSelector
+    js.Expression access = node.useSelector
         ? js.js('#.#', [value, glue.invocationName(node.selector)])
         : js.js('#.toString', [value]);
+    if (node.useInvoke) {
+      access = new js.Call(access, []);
+    }
     if (node.condition != null) {
       js.Expression condition = visitExpression(node.condition);
       js.Statement body = isNullReturn(node.next)
@@ -1044,7 +1056,7 @@
     } else {
       accumulator.add(new js.ExpressionStatement(access));
     }
-    visitStatement(node.next);
+    return node.next;
   }
 
   @override
@@ -1111,8 +1123,14 @@
         return js.js('typeof # !== "number"', args);
       case BuiltinOperator.IsFloor:
         return js.js('Math.floor(#) === #', args);
-      case BuiltinOperator.IsNumberAndFloor:
+      case BuiltinOperator.IsInteger:
         return js.js('typeof # === "number" && Math.floor(#) === #', args);
+      case BuiltinOperator.IsNotInteger:
+        return js.js('typeof # !== "number" || Math.floor(#) !== #', args);
+      case BuiltinOperator.IsUnsigned32BitInteger:
+        return js.js('# >>> 0 === #', args);
+      case BuiltinOperator.IsNotUnsigned32BitInteger:
+        return js.js('# >>> 0 !== #', args);
       case BuiltinOperator.IsFixedLengthJSArray:
         // TODO(sra): Remove boolify (i.e. !!).
         return js.js(r'!!#.fixed$length', args);
@@ -1193,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/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index b7d4c24..46ef1a5 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -228,8 +228,7 @@
     ClassWorld classWorld = _compiler.world;
     if (classWorld.isUsedAsMixin(cls)) return true;
 
-    Iterable<ClassElement> subclasses = _compiler.world.strictSubclassesOf(cls);
-    return subclasses.any((ClassElement subclass) {
+    return _compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) {
       return !_backend.rti.isTrivialSubstitution(subclass, cls);
     });
   }
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 034dd10..edc7c55 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -103,7 +103,7 @@
         }
 
         if (tracer != null) {
-          tracer.traceCompilation(element.name, null);
+          tracer.traceCompilation('$element', null);
         }
         cps.FunctionDefinition cpsFunction = compileToCpsIr(element);
         optimizeCpsBeforeInlining(cpsFunction);
@@ -131,6 +131,49 @@
     }
   }
 
+  String stringify(cps.FunctionDefinition node) {
+    return new SExpressionStringifier().withTypes().visit(node);
+  }
+
+  /// For debugging purposes, replace a call to [applyCpsPass] with a call
+  /// to [debugCpsPass] to check that this pass is idempotent.
+  ///
+  /// This runs [pass] followed by shrinking reductions, and then checks that
+  /// one more run of [pass] does not change the IR.  The intermediate shrinking
+  /// reductions pass is omitted if [pass] itself is shrinking reductions.
+  ///
+  /// If [targetName] is given, functions whose name contains that substring
+  /// will be dumped out if the idempotency test fails.
+  void debugCpsPass(cps_opt.Pass makePass(),
+                    cps.FunctionDefinition cpsFunction,
+                    [String targetName]) {
+    String original = stringify(cpsFunction);
+    cps_opt.Pass pass = makePass();
+    pass.rewrite(cpsFunction);
+    assert(checkCpsIntegrity(cpsFunction, pass.passName));
+    if (pass is! ShrinkingReducer) {
+      new ShrinkingReducer().rewrite(cpsFunction);
+    }
+    String before = stringify(cpsFunction);
+    makePass().rewrite(cpsFunction);
+    String after = stringify(cpsFunction);
+    if (before != after) {
+      print('SExpression changed for ${cpsFunction.element}');
+      if (targetName != null && '${cpsFunction.element}'.contains(targetName)) {
+        print(original);
+        print('\n-->\n');
+        print(before);
+        print('\n-->\n');
+        print(after);
+        compiler.outputProvider('original', 'dump')..add(original)..close();
+        compiler.outputProvider('before', 'dump')..add(before)..close();
+        compiler.outputProvider('after', 'dump')..add(after)..close();
+      }
+    }
+    traceGraph(pass.passName, cpsFunction);
+    dumpTypedIr(pass.passName, cpsFunction);
+  }
+
   void applyCpsPass(cps_opt.Pass pass, cps.FunctionDefinition cpsFunction) {
     cpsOptimizationTask.measureSubtask(pass.passName, () {
       pass.rewrite(cpsFunction);
@@ -141,8 +184,10 @@
   }
 
   cps.FunctionDefinition compileToCpsIr(AstElement element) {
-    cps.FunctionDefinition cpsFunction =
-        cpsBuilderTask.buildNode(element, typeSystem);
+    cps.FunctionDefinition cpsFunction = inliner.cache.getUnoptimized(element);
+    if (cpsFunction != null) return cpsFunction;
+
+    cpsFunction = cpsBuilderTask.buildNode(element, typeSystem);
     if (cpsFunction == null) {
       if (cpsBuilderTask.bailoutMessage == null) {
         giveUp('unable to build cps definition of $element');
@@ -157,6 +202,11 @@
     // insert fewer getInterceptor calls.
     applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
     applyCpsPass(new UnsugarVisitor(glue), cpsFunction);
+    applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
+    applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
+    applyCpsPass(new InsertRefinements(typeSystem), cpsFunction);
+
+    inliner.cache.putUnoptimized(element, cpsFunction);
     return cpsFunction;
   }
 
@@ -208,9 +258,6 @@
 
   void optimizeCpsBeforeInlining(cps.FunctionDefinition cpsFunction) {
     cpsOptimizationTask.measure(() {
-      applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
-      applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
-      applyCpsPass(new InsertRefinements(typeSystem), cpsFunction);
       applyCpsPass(new TypePropagator(this), cpsFunction);
       applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
       applyCpsPass(new ShrinkingReducer(), cpsFunction);
@@ -219,17 +266,26 @@
 
   void optimizeCpsAfterInlining(cps.FunctionDefinition cpsFunction) {
     cpsOptimizationTask.measure(() {
+      applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
+      applyCpsPass(new ShrinkingReducer(), cpsFunction);
       applyCpsPass(new RedundantRefinementEliminator(typeSystem), cpsFunction);
+      applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
+      applyCpsPass(new TypePropagator(this, recomputeAll: true), cpsFunction);
+      applyCpsPass(new ShrinkingReducer(), cpsFunction);
       applyCpsPass(new EagerlyLoadStatics(), cpsFunction);
       applyCpsPass(new GVN(compiler, typeSystem), cpsFunction);
+      applyCpsPass(new PathBasedOptimizer(backend, typeSystem), cpsFunction);
+      applyCpsPass(new ShrinkingReducer(), cpsFunction);
       applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
       applyCpsPass(new BoundsChecker(typeSystem, compiler.world), cpsFunction);
       applyCpsPass(new LoopInvariantBranchMotion(), cpsFunction);
       applyCpsPass(new ShrinkingReducer(), cpsFunction);
       applyCpsPass(new ScalarReplacer(compiler), cpsFunction);
+      applyCpsPass(new UseFieldInitializers(backend), cpsFunction);
       applyCpsPass(new MutableVariableEliminator(), cpsFunction);
       applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
       applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
+      applyCpsPass(new UpdateRefinements(typeSystem), cpsFunction);
       applyCpsPass(new ShrinkingReducer(), cpsFunction);
       applyCpsPass(new OptimizeInterceptors(backend, typeSystem), cpsFunction);
       applyCpsPass(new BackwardNullCheckRemover(typeSystem), cpsFunction);
@@ -267,7 +323,7 @@
 
     treeOptimizationTask.measure(() {
       applyTreePass(new StatementRewriter());
-      applyTreePass(new VariableMerger());
+      applyTreePass(new VariableMerger(minifying: compiler.enableMinification));
       applyTreePass(new LoopRewriter());
       applyTreePass(new LogicalRewriter());
       applyTreePass(new PullIntoInitializers());
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/js_backend/constant_system_javascript.dart b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
index 290d563..f6ebd07 100644
--- a/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_system_javascript.dart
@@ -274,8 +274,17 @@
         compiler.backend.typeImplementation.computeType(compiler.resolution));
   }
 
-  // Integer checks don't verify that the number is not -0.0.
-  bool isInt(ConstantValue constant) => constant.isInt || constant.isMinusZero;
+  // Integer checks report true for -0.0, INFINITY, and -INFINITY.  At
+  // runtime an 'X is int' check is implemented as:
+  //
+  // typeof(X) === "number" && Math.floor(X) === X
+  //
+  // We consistently match that runtime semantics at compile time as well.
+  bool isInt(ConstantValue constant) {
+    return constant.isInt || constant.isMinusZero ||
+        constant.isPositiveInfinity ||
+        constant.isNegativeInfinity;
+  }
   bool isDouble(ConstantValue constant)
       => constant.isDouble && !constant.isMinusZero;
   bool isString(ConstantValue constant) => constant.isString;
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 99d383c..4431a10 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -22,6 +22,7 @@
     CodegenWorkItem;
 import '../common/names.dart' show
     Identifiers,
+    Names,
     Selectors,
     Uris;
 import '../common/registry.dart' show
@@ -49,6 +50,8 @@
 import '../dart_types.dart';
 import '../deferred_load.dart' show
     DeferredLoadTask;
+import '../diagnostics/invariant.dart' show
+    DEBUG_MODE;
 import '../dump_info.dart' show
     DumpInfoTask;
 import '../elements/elements.dart';
diff --git a/pkg/compiler/lib/src/js_backend/namer_names.dart b/pkg/compiler/lib/src/js_backend/namer_names.dart
index 60e1597..31a1747 100644
--- a/pkg/compiler/lib/src/js_backend/namer_names.dart
+++ b/pkg/compiler/lib/src/js_backend/namer_names.dart
@@ -8,7 +8,12 @@
   int get _kind;
   _NamerName get _target => this;
 
-  toString() => throw new UnsupportedError("Cannot convert a name to a string");
+  String toString() {
+    if (DEBUG_MODE) {
+      return 'Name($key)';
+    }
+    throw new UnsupportedError("Cannot convert a name to a string");
+  }
 }
 
 enum _NamerNameKinds {
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index ee09ed3..4db2387 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -14,7 +14,7 @@
  *
  * The situation can be ameliorated with some heuristics for disregarding some
  * `noSuchMethod` implementations during type inference. We can partition
- * `noSuchMethod` implementations into 3 categories.
+ * `noSuchMethod` implementations into 4 categories.
  *
  * Implementations in category A are the default implementations
  * `Object.noSuchMethod` and `Interceptor.noSuchMethod`.
@@ -23,8 +23,13 @@
  *
  *     noSuchMethod(x) => throw 'not implemented'
  *
- * Implementations that do not fall into category A or B are in category C. They
- * are the only category of implementation that are considered during type
+ * Implementations in category C are not applicable, for example:
+ *
+ *     noSuchMethod() { /* missing parameter */ }
+ *     noSuchMethod(a, b) { /* too many parameters */ }
+ *
+ * Implementations that do not fall into category A, B or C are in category D.
+ * They are the only category of implementation that are considered during type
  * inference.
  *
  * Implementations that syntactically just forward to the super implementation,
@@ -42,11 +47,13 @@
   /// The implementations that fall into category B, described above.
   final Set<FunctionElement> throwingImpls = new Set<FunctionElement>();
   /// The implementations that fall into category C, described above.
+  final Set<FunctionElement> notApplicableImpls = new Set<FunctionElement>();
+  /// The implementations that fall into category D, described above.
   final Set<FunctionElement> otherImpls = new Set<FunctionElement>();
 
-  /// The implementations that fall into category C1
+  /// The implementations that fall into category D1
   final Set<FunctionElement> complexNoReturnImpls = new Set<FunctionElement>();
-  /// The implementations that fall into category C2
+  /// The implementations that fall into category D2
   final Set<FunctionElement> complexReturningImpls = new Set<FunctionElement>();
 
   /// The implementations that have not yet been categorized.
@@ -73,8 +80,8 @@
     _uncategorizedImpls.clear();
   }
 
-  /// Now that type inference is complete, split category C into two
-  /// subcategories: C1, those that have no return type, and C2, those
+  /// Now that type inference is complete, split category D into two
+  /// subcategories: D1, those that have no return type, and D2, those
   /// that have a return type.
   void onTypeInferenceComplete() {
     otherImpls.forEach(_subcategorizeOther);
@@ -104,7 +111,7 @@
 
   /// Returns [true] if the given element is a complex [noSuchMethod]
   /// implementation. An implementation is complex if it falls into
-  /// category C, as described above.
+  /// category D, as described above.
   bool isComplex(FunctionElement element) {
     assert(element.name == Identifiers.noSuchMethod_);
     return otherImpls.contains(element);
@@ -131,9 +138,12 @@
     if (otherImpls.contains(element)) {
       return NsmCategory.OTHER;
     }
+    if (notApplicableImpls.contains(element)) {
+      return NsmCategory.NOT_APPLICABLE;
+    }
     if (!Selectors.noSuchMethod_.signatureApplies(element)) {
-      otherImpls.add(element);
-      return NsmCategory.OTHER;
+      notApplicableImpls.add(element);
+      return NsmCategory.NOT_APPLICABLE;
     }
     if (_isDefaultNoSuchMethodImplementation(element)) {
       defaultImpls.add(element);
@@ -141,8 +151,8 @@
     } else if (_hasForwardingSyntax(element)) {
       // If the implementation is 'noSuchMethod(x) => super.noSuchMethod(x);'
       // then it is in the same category as the super call.
-      Element superCall = element.enclosingClass
-          .lookupSuperByName(Selectors.noSuchMethod_.memberName);
+      Element superCall =
+          element.enclosingClass.lookupSuperByName(Names.noSuchMethod_);
       NsmCategory category = _categorizeImpl(superCall);
       switch(category) {
         case NsmCategory.DEFAULT:
@@ -154,6 +164,12 @@
         case NsmCategory.OTHER:
           otherImpls.add(element);
           break;
+        case NsmCategory.NOT_APPLICABLE:
+          // If the super method is not applicable, the call is redirected to
+          // `Object.noSuchMethod`.
+          defaultImpls.add(element);
+          category = NsmCategory.DEFAULT;
+          break;
       }
       return category;
     } else if (_hasThrowingSyntax(element)) {
@@ -224,4 +240,9 @@
   }
 }
 
-enum NsmCategory { DEFAULT, THROWING, OTHER }
\ No newline at end of file
+enum NsmCategory {
+  DEFAULT,
+  THROWING,
+  NOT_APPLICABLE,
+  OTHER,
+}
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 849fae3..1501a93 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -236,8 +236,7 @@
       classesNeedingRti.add(cls);
 
       // TODO(ngeoffray): This should use subclasses, not subtypes.
-      Iterable<ClassElement> classes = compiler.world.strictSubtypesOf(cls);
-      classes.forEach((ClassElement sub) {
+      compiler.world.forEachStrictSubtypeOf(cls, (ClassElement sub) {
         potentiallyAddForRti(sub);
       });
 
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index fb34fae..f2c1ded 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -74,6 +74,7 @@
     TypeCheck,
     TypeChecks,
     TypeVariableHandler;
+import '../../js/js_debug.dart';
 import '../../universe/call_structure.dart' show
     CallStructure;
 import '../../universe/selector.dart' show
@@ -1609,9 +1610,8 @@
     outputBuffers[mainOutputUnit] = mainOutput;
 
 
-    mainOutput.addBuffer(jsAst.prettyPrint(program,
-                                           compiler,
-                                           monitor: compiler.dumpInfoTask));
+    mainOutput.addBuffer(jsAst.createCodeBuffer(
+        program, compiler, monitor: compiler.dumpInfoTask));
 
     if (compiler.deferredMapUri != null) {
       outputDeferredMap();
@@ -2055,9 +2055,8 @@
 
       outputBuffers[outputUnit] = output;
 
-      output.addBuffer(jsAst.prettyPrint(outputAsts[outputUnit],
-                                         compiler,
-                                         monitor: compiler.dumpInfoTask));
+      output.addBuffer(jsAst.createCodeBuffer(
+          outputAsts[outputUnit], compiler, monitor: compiler.dumpInfoTask));
 
       // Make a unique hash of the code (before the sourcemaps are added)
       // This will be used to retrieve the initializing function from the global
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index dbc6c9b..eb66c1a 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -22,6 +22,8 @@
     ClosureClassMap,
     ClosureFieldElement,
     CapturedVariable;
+import '../core_types.dart' show
+    CoreClasses;
 import '../dart_types.dart' show
     DartType,
     FunctionType,
@@ -34,6 +36,7 @@
 import '../elements/elements.dart' show
     ClassElement,
     ConstructorBodyElement,
+    ConstructorElement,
     Element,
     Elements,
     ElementKind,
diff --git a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
index 96838ac..a0b9b48 100644
--- a/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/lazy_emitter/model_emitter.dart
@@ -159,15 +159,16 @@
 
     program.finalizers.forEach((js.TokenFinalizer f) => f.finalizeTokens());
 
+    // TODO(johnnniwinther): Support source maps in this emitter.
     for (int i = 0; i < fragmentsCode.length; ++i) {
-      String code = js.prettyPrint(fragmentsCode[i], compiler).getText();
+      String code = js.createCodeBuffer(fragmentsCode[i], compiler).getText();
       totalSize += code.length;
       compiler.outputProvider(fragments[i+1].outputFileName, deferredExtension)
         ..add(code)
         ..close();
     }
 
-    String mainCode = js.prettyPrint(mainAst, compiler).getText();
+    String mainCode = js.createCodeBuffer(mainAst, compiler).getText();
     compiler.outputProvider(mainFragment.outputFileName, 'js')
         ..add(buildGeneratedBy(compiler))
         ..add(mainCode)
diff --git a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
index 43aa528..fdea7ff 100644
--- a/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/metadata_collector.dart
@@ -178,12 +178,42 @@
   }
 
   List<jsAst.DeferredNumber> reifyDefaultArguments(FunctionElement function) {
+    function = function.implementation;
     FunctionSignature signature = function.functionSignature;
     if (signature.optionalParameterCount == 0) return const [];
+
+    // Optional parameters of redirecting factory constructors take their
+    // defaults from the corresponding parameters of the redirection target.
+    Map<ParameterElement, ParameterElement> targetParameterMap;
+    if (function is ConstructorElement) {
+      // TODO(sra): dart2js generates a redirecting factory constructor body
+      // that has the signature of the redirecting constructor that calls the
+      // redirection target. This is wrong - it should have the signature of the
+      // target. This would make the reified default arguments trivial.
+
+      ConstructorElement constructor = function;
+      while (constructor.isRedirectingFactory &&
+             !constructor.isCyclicRedirection) {
+        // TODO(sra): Remove the loop once effectiveTarget forwards to patches.
+        constructor = constructor.effectiveTarget.implementation;
+      }
+
+      if (constructor != function) {
+        if (signature.hasOptionalParameters) {
+          targetParameterMap =
+              mapRedirectingFactoryConstructorOptionalParameters(
+                  signature, constructor.functionSignature);
+        }
+      }
+    }
+
     List<jsAst.DeferredNumber> defaultValues = <jsAst.DeferredNumber>[];
     for (ParameterElement element in signature.optionalParameters) {
-      ConstantValue constant =
-          _backend.constants.getConstantValueForVariable(element);
+      ParameterElement parameter =
+          (targetParameterMap == null) ? element : targetParameterMap[element];
+      ConstantValue constant = (parameter == null)
+          ? null
+          : _backend.constants.getConstantValueForVariable(parameter);
       jsAst.Expression expression = (constant == null)
           ? new jsAst.LiteralNull()
           : _emitter.constantReference(constant);
@@ -192,6 +222,40 @@
     return defaultValues;
   }
 
+  Map<ParameterElement, ParameterElement>
+  mapRedirectingFactoryConstructorOptionalParameters(
+      FunctionSignature source, FunctionSignature target) {
+    var map = <ParameterElement, ParameterElement>{};
+
+    if (source.optionalParametersAreNamed !=
+        target.optionalParametersAreNamed) {
+      // No legal optional arguments due to mismatch between named vs positional
+      // optional arguments.
+      return map;
+    }
+
+    if (source.optionalParametersAreNamed) {
+      for (ParameterElement element in source.optionalParameters) {
+        for (ParameterElement redirectedElement in target.optionalParameters) {
+          if (element.name == redirectedElement.name) {
+            map[element] = redirectedElement;
+            break;
+          }
+        }
+      }
+    } else {
+      int i = source.requiredParameterCount;
+      for (ParameterElement element in source.orderedOptionalParameters) {
+        if (i >= target.requiredParameterCount && i < target.parameterCount) {
+          map[element] =
+              target.orderedOptionalParameters[i - target.requiredParameterCount];
+        }
+        ++i;
+      }
+    }
+    return map;
+  }
+
   jsAst.Expression reifyMetadata(MetadataAnnotation annotation) {
     ConstantValue constant =
         _backend.constants.getConstantValueForMetadata(annotation);
@@ -229,9 +293,8 @@
 
   _MetadataEntry _addGlobalMetadata(jsAst.Node node) {
     String nameToKey(jsAst.Name name) => "${name.key}";
-    String printed = jsAst.prettyPrint(node, _compiler,
-                                       renamerForNames: nameToKey)
-                          .getText();
+    String printed = jsAst.prettyPrint(
+        node, _compiler, renamerForNames: nameToKey);
     return _globalMetadataMap.putIfAbsent(printed, () {
       _BoundMetadataEntry result = new _BoundMetadataEntry(node);
       if (_compiler.hasIncrementalSupport) {
@@ -366,4 +429,4 @@
     node.accept(this);
     return _foundUnboundToken;
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index 61c1b08..9c48f4d 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -35,6 +35,7 @@
 
   JavaScriptBackend get backend => compiler.backend;
   TypeTestRegistry get typeTestRegistry => emitterTask.typeTestRegistry;
+  CoreClasses get coreClasses => compiler.coreClasses;
 
   Set<ClassElement> get checkedClasses =>
       typeTestRegistry.checkedClasses;
@@ -181,7 +182,7 @@
     }
 
     if (superclass != null &&
-        superclass != compiler.coreClasses.objectClass &&
+        superclass != coreClasses.objectClass &&
         !haveSameTypeVariables(cls, superclass)) {
       // We cannot inherit the generated substitutions, because the type
       // variable layout for this class is different.  Instead we generate
@@ -217,7 +218,7 @@
 
     // A class that defines a `call` method implicitly implements
     // [Function] and needs checks for all typedefs that are used in is-checks.
-    if (checkedClasses.contains(compiler.coreClasses.functionClass) ||
+    if (checkedClasses.contains(coreClasses.functionClass) ||
         checkedFunctionTypes.isNotEmpty) {
       Element call = cls.lookupLocalMember(Identifiers.call);
       if (call == null) {
@@ -228,8 +229,8 @@
         FunctionElement callFunction = call;
         // A superclass might already implement the Function interface. In such
         // a case, we can avoid emiting the is test here.
-        if (!cls.superclass.implementsFunction(compiler)) {
-          _generateInterfacesIsTests(compiler.coreClasses.functionClass,
+        if (!cls.superclass.implementsFunction(coreClasses)) {
+          _generateInterfacesIsTests(coreClasses.functionClass,
                                     generateIsTest,
                                     generateSubstitution,
                                     generated);
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 9e81bca..11826c3 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -252,10 +252,9 @@
   }
 
   js.Statement buildDeferredInitializerGlobal() {
-    String global = deferredInitializersGlobal;
-    return js.js.statement(
-        "if (typeof($global) === 'undefined') var # = Object.create(null);",
-        new js.VariableDeclaration(global, allowRename: false));
+    return js.js.statement('self.#deferredInitializers = '
+        'self.#deferredInitializers || Object.create(null);',
+        {'deferredInitializers': deferredInitializersGlobal});
   }
 
   // Writes the given [fragment]'s [code] into a file.
@@ -281,7 +280,7 @@
         isSplit ? buildDeferredInitializerGlobal() : new js.Block.empty(),
         code]);
 
-    mainOutput.addBuffer(js.prettyPrint(program, compiler,
+    mainOutput.addBuffer(js.createCodeBuffer(program, compiler,
         monitor: compiler.dumpInfoTask));
 
     if (shouldGenerateSourceMap) {
@@ -335,7 +334,7 @@
         buildDeferredInitializerGlobal(),
         js.js.statement('$deferredInitializersGlobal.current = #', code)]);
 
-    output.addBuffer(js.prettyPrint(program, compiler,
+    output.addBuffer(js.createCodeBuffer(program, compiler,
         monitor: compiler.dumpInfoTask));
 
     // Make a unique hash of the code (before the sourcemaps are added)
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index 438dbe6..cd61a71 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -111,6 +111,9 @@
   static NativeBehavior get PURE => NativeBehavior._makePure();
   static NativeBehavior get PURE_ALLOCATION =>
       NativeBehavior._makePure(isAllocation: true);
+  static NativeBehavior get CHANGES_OTHER => NativeBehavior._makeChangesOther();
+  static NativeBehavior get DEPENDS_OTHER => NativeBehavior._makeDependsOther();
+
 
   String toString() {
     return 'NativeBehavior('
@@ -132,6 +135,18 @@
     return behavior;
   }
 
+  static NativeBehavior _makeChangesOther() {
+    // TODO(25544): Have a distinct effect instead of using static properties to
+    // model 'other' effects.
+    return _makePure()..sideEffects.setChangesStaticProperty();
+  }
+
+  static NativeBehavior _makeDependsOther() {
+    // TODO(25544): Have a distinct effect instead of using static properties to
+    // model 'other' effects.
+    return _makePure()..sideEffects.setDependsOnStaticPropertyStore();
+  }
+
   /// Processes the type specification string of a call to JS and stores the
   /// result in the [typesReturned] and [typesInstantiated]. It furthermore
   /// computes the side effects, and, if given, invokes [setSideEffects] with
diff --git a/pkg/compiler/lib/src/native/native.dart b/pkg/compiler/lib/src/native/native.dart
index ad88cbe..487832b 100644
--- a/pkg/compiler/lib/src/native/native.dart
+++ b/pkg/compiler/lib/src/native/native.dart
@@ -63,6 +63,8 @@
   String libraryName = library.canonicalUri.toString();
   if (library.entryCompilationUnit.script.name.contains(
           'sdk/tests/compiler/dart2js_native')
+      || library.entryCompilationUnit.script.name.contains(
+          'sdk/tests/compiler/dart2js_extra')
       || libraryName == 'dart:async'
       || libraryName == 'dart:html'
       || libraryName == 'dart:html_common'
diff --git a/pkg/compiler/lib/src/parser/node_listener.dart b/pkg/compiler/lib/src/parser/node_listener.dart
index 3a3e91b..b5f1db2 100644
--- a/pkg/compiler/lib/src/parser/node_listener.dart
+++ b/pkg/compiler/lib/src/parser/node_listener.dart
@@ -450,7 +450,7 @@
     pushNode(new Rethrow(throwToken, endToken));
     if (identical(throwToken.stringValue, 'throw')) {
       reporter.reportErrorMessage(
-          throwToken, MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP);
+          throwToken, MessageKind.MISSING_EXPRESSION_IN_THROW);
     }
   }
 
diff --git a/pkg/compiler/lib/src/parser/parser.dart b/pkg/compiler/lib/src/parser/parser.dart
index f2e0577..42e432b 100644
--- a/pkg/compiler/lib/src/parser/parser.dart
+++ b/pkg/compiler/lib/src/parser/parser.dart
@@ -780,10 +780,6 @@
         token = new SymbolToken(GT_INFO, token.charOffset);
         token.next = new SymbolToken(GT_INFO, token.charOffset + 1);
         token.next.next = next;
-      } else if (identical(token.stringValue, '>>>')) {
-        token = new SymbolToken(GT_INFO, token.charOffset);
-        token.next = new SymbolToken(GT_GT_INFO, token.charOffset + 1);
-        token.next.next = next;
       }
       endStuff(count, begin, token);
       return expect('>', token);
diff --git a/pkg/compiler/lib/src/resolution/class_members.dart b/pkg/compiler/lib/src/resolution/class_members.dart
index a23a490..36feaa4 100644
--- a/pkg/compiler/lib/src/resolution/class_members.dart
+++ b/pkg/compiler/lib/src/resolution/class_members.dart
@@ -6,7 +6,8 @@
 
 import '../common.dart';
 import '../common/names.dart' show
-    Identifiers;
+    Identifiers,
+    Names;
 import '../common/resolution.dart' show
     Resolution;
 import '../compiler.dart' show
@@ -76,9 +77,12 @@
   /// Compute all members of [cls] and checked that [cls] implements its
   /// interface unless it is abstract or declares a `noSuchMethod` method.
   void computeAllMembers() {
-    Map<Name, Member> declaredMembers = computeMembers(null, null);
-    if (!cls.isAbstract &&
-        !declaredMembers.containsKey(const PublicName('noSuchMethod'))) {
+    computeMembers(null, null);
+    if (!cls.isAbstract) {
+      Member member = classMembers[Names.noSuchMethod_];
+      if (member != null && !member.declarer.isObject) {
+        return;
+      }
       // Check for unimplemented members on concrete classes that neither have
       // a `@proxy` annotation nor declare a `noSuchMethod` method.
       checkInterfaceImplementation();
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index da82058..fb5a6f8 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -665,8 +665,7 @@
       if (identical(string, '!') ||
           identical(string, '&&') || identical(string, '||') ||
           identical(string, 'is') || identical(string, 'as') ||
-          identical(string, '?') || identical(string, '??') ||
-          identical(string, '>>>')) {
+          identical(string, '?') || identical(string, '??')) {
         return null;
       }
       String op = source;
@@ -3658,9 +3657,9 @@
   }
 
   ResolutionResult visitRethrow(Rethrow node) {
-    if (!inCatchBlock) {
+    if (!inCatchBlock && node.throwToken.stringValue == 'rethrow') {
       reporter.reportErrorMessage(
-          node, MessageKind.THROW_WITHOUT_EXPRESSION);
+          node, MessageKind.RETHROW_OUTSIDE_CATCH);
     }
     return const NoneResult();
   }
@@ -3674,7 +3673,7 @@
         // Specification 13.12.)
         reporter.reportErrorMessage(
             expression,
-            MessageKind.CANNOT_RETURN_FROM_CONSTRUCTOR);
+            MessageKind.RETURN_IN_GENERATIVE_CONSTRUCTOR);
       } else if (!node.isArrowBody && currentAsyncMarker.isYielding) {
         reporter.reportErrorMessage(
             node,
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index bcb686e..ca1d268 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -239,7 +239,7 @@
             tree.hasBody() &&
             !tree.isRedirectingFactory) {
           reporter.reportErrorMessage(
-              tree, MessageKind.CONST_CONSTRUCTOR_HAS_BODY);
+              tree, MessageKind.CONST_CONSTRUCTOR_OR_FACTORY_WITH_BODY);
         }
       }
 
diff --git a/pkg/compiler/lib/src/resolution/semantic_visitor.dart b/pkg/compiler/lib/src/resolution/semantic_visitor.dart
index cb391a3..e28d3e1 100644
--- a/pkg/compiler/lib/src/resolution/semantic_visitor.dart
+++ b/pkg/compiler/lib/src/resolution/semantic_visitor.dart
@@ -4336,6 +4336,21 @@
       Node rhs,
       A arg);
 
+  ///  Assignment of [rhs] to the unresolved super [element].
+  ///
+  /// For instance:
+  ///
+  ///     class B {}
+  ///     class C {
+  ///       m() => super.foo = 42;
+  ///     }
+  ///
+  R visitUnresolvedSuperSet(
+      Send node,
+      Element element,
+      Node rhs,
+      A arg);
+
   /// Invocation of the unresolved [element] with [arguments].
   ///
   /// For instance:
diff --git a/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart b/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
index 5e15a7d..75272f3 100644
--- a/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
+++ b/pkg/compiler/lib/src/resolution/semantic_visitor_mixins.dart
@@ -2650,6 +2650,15 @@
       A arg) {
     return bulkHandleSet(node, arg);
   }
+
+  @override
+  R visitUnresolvedSuperSet(
+      Send node,
+      Element element,
+      Node rhs,
+      A arg) {
+    return bulkHandleSet(node, arg);
+  }
 }
 
 /// Mixin that implements all `visitXIndexSet` methods of [SemanticSendVisitor]
@@ -3332,6 +3341,15 @@
   }
 
   @override
+  R visitUnresolvedSuperSet(
+      Send node,
+      Element element,
+      Node rhs,
+      A arg) {
+    return bulkHandleSuper(node, arg);
+  }
+
+  @override
   R visitUnresolvedSuperInvoke(
       Send node,
       Element function,
@@ -4498,6 +4516,16 @@
   }
 
   @override
+  R visitUnresolvedSuperSet(
+      Send node,
+      Element element,
+      Node rhs,
+      A arg) {
+    apply(rhs, arg);
+    return null;
+  }
+
+  @override
   R visitUnresolvedSuperInvoke(
       Send node,
       Element function,
diff --git a/pkg/compiler/lib/src/resolution/send_structure.dart b/pkg/compiler/lib/src/resolution/send_structure.dart
index 5daa7bd..5ff76ef 100644
--- a/pkg/compiler/lib/src/resolution/send_structure.dart
+++ b/pkg/compiler/lib/src/resolution/send_structure.dart
@@ -769,7 +769,11 @@
         // TODO(johnniwinther): Should this be a valid case?
         break;
       case AccessKind.UNRESOLVED_SUPER:
-        // TODO(johnniwinther): Handle this separately.
+        return visitor.visitUnresolvedSuperSet(
+            node,
+            semantics.element,
+            node.arguments.single,
+            arg);
       case AccessKind.UNRESOLVED:
         return visitor.visitUnresolvedSet(
             node,
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 07cf4e6..23153bf 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -12,10 +12,9 @@
 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';
 import '../dart_types.dart';
 import '../elements/elements.dart';
 import '../elements/modelx.dart' show
@@ -95,9 +94,6 @@
   String get fixedBackendName => _unsupported('fixedBackendName');
 
   @override
-  bool get hasFixedBackendName => _unsupported('hasFixedBackendName');
-
-  @override
   LibraryElement get implementationLibrary => library;
 
   @override
@@ -131,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
@@ -374,7 +361,6 @@
   List<ExportElement> _exports;
   ListedContainer _exportsMap;
   ListedContainer _importsMap;
-  Map<LibraryTag, LibraryElement> _libraryDependencies;
 
   LibraryElementZ(ObjectDecoder decoder)
       : super(decoder);
@@ -462,9 +448,6 @@
   }
 
   @override
-  bool get canUseNative => false;
-
-  @override
   Element findExported(String elementName) => _unsupported('findExported');
 
   void _ensureImports() {
@@ -853,7 +836,7 @@
   bool get hasLocalScopeMembers => _unsupported('hasLocalScopeMembers');
 
   @override
-  bool implementsFunction(Compiler compiler) {
+  bool implementsFunction(CoreClasses coreClasses) {
     return _unsupported('implementsFunction');
   }
 
@@ -892,9 +875,6 @@
   }
 
   @override
-  String get nativeTagInfo => _unsupported('nativeTagInfo');
-
-  @override
   void reverseBackendMembers() => _unsupported('reverseBackendMembers');
 
   @override
@@ -1572,4 +1552,4 @@
   Element lookupLocalMember(String memberName) {
     return _unsupported('lookupLocalMember');
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 540ba50..85fd583 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -1109,6 +1109,8 @@
     sourceElementStack.add(target);
     sourceInformationBuilder = sourceInformationFactory.createBuilderForContext(
             target);
+    graph.sourceInformation =
+        sourceInformationBuilder.buildVariableDeclaration();
   }
 
   BackendHelpers get helpers => backend.helpers;
@@ -4198,9 +4200,11 @@
       // If the isolate library is not used, we just generate code
       // to fetch the static state.
       String name = backend.namer.staticStateHolder;
-      push(new HForeignCode(js.js.parseForeignJS(name),
-                            backend.dynamicType,
-                            <HInstruction>[]));
+      push(new HForeignCode(
+          js.js.parseForeignJS(name),
+          backend.dynamicType,
+          <HInstruction>[],
+          nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
     } else {
       // Call a helper method from the isolate library. The isolate
       // library uses its own isolate structure, that encapsulates
@@ -4478,7 +4482,7 @@
         js.js.parseForeignJS("$isolateName = #"),
         backend.dynamicType,
         <HInstruction>[pop()],
-        nativeBehavior: native.NativeBehavior.PURE,
+        nativeBehavior: native.NativeBehavior.CHANGES_OTHER,
         effects: sideEffects));
   }
 
@@ -4488,7 +4492,8 @@
     }
     push(new HForeignCode(js.js.parseForeignJS(backend.namer.staticStateHolder),
                           backend.dynamicType,
-                          <HInstruction>[]));
+                          <HInstruction>[],
+                          nativeBehavior: native.NativeBehavior.DEPENDS_OTHER));
   }
 
   void handleForeignSend(ast.Send node, FunctionElement element) {
@@ -4548,7 +4553,10 @@
     String name = selector.name;
 
     ClassElement cls = currentNonClosureClass;
-    Element element = cls.lookupSuperMember(Identifiers.noSuchMethod_);
+    MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_);
+    if (!Selectors.noSuchMethod_.signatureApplies(element)) {
+      element = coreClasses.objectClass.lookupMember(Identifiers.noSuchMethod_);
+    }
     if (compiler.enabledInvokeOn && !element.enclosingClass.isObject) {
       // Register the call as dynamic if [noSuchMethod] on the super
       // class is _not_ the default implementation from [Object], in
@@ -4688,6 +4696,15 @@
   }
 
   @override
+  void visitUnresolvedSuperSet(
+      ast.Send node,
+      Element element,
+      ast.Node rhs,
+      _) {
+    handleSuperSendSet(node);
+  }
+
+  @override
   void visitSuperSetterGet(
       ast.Send node,
       MethodElement setter,
@@ -4837,8 +4854,7 @@
     ClassWorld classWorld = compiler.world;
     if (classWorld.isUsedAsMixin(cls)) return true;
 
-    Iterable<ClassElement> subclasses = compiler.world.strictSubclassesOf(cls);
-    return subclasses.any((ClassElement subclass) {
+    return compiler.world.anyStrictSubclassOf(cls, (ClassElement subclass) {
       return !rti.isTrivialSubstitution(subclass, cls);
     });
   }
@@ -6807,14 +6823,8 @@
       Element element,
       ast.Node rhs,
       _) {
-    if (node.isSuperCall) {
-      // TODO(johnniwinther): Remove this when final super field assignment is
-      // not an unresolved set.
-      handleSuperSendSet(node);
-    } else {
-      generateIsDeferredLoadedCheckOfSend(node);
-      generateNonInstanceSetter(node, element, visitAndPop(rhs));
-    }
+    generateIsDeferredLoadedCheckOfSend(node);
+    generateNonInstanceSetter(node, element, visitAndPop(rhs));
   }
 
   @override
@@ -7147,21 +7157,64 @@
     FunctionSignature targetSignature = targetConstructor.functionSignature;
     FunctionSignature redirectingSignature =
         redirectingConstructor.functionSignature;
-    redirectingSignature.forEachRequiredParameter((ParameterElement element) {
-      inputs.add(localsHandler.readLocal(element));
-    });
+
+    List<Element> targetRequireds = targetSignature.requiredParameters;
+    List<Element> redirectingRequireds
+        = redirectingSignature.requiredParameters;
+
     List<Element> targetOptionals =
         targetSignature.orderedOptionalParameters;
     List<Element> redirectingOptionals =
         redirectingSignature.orderedOptionalParameters;
-    int i = 0;
-    for (; i < redirectingOptionals.length; i++) {
-      ParameterElement parameter = redirectingOptionals[i];
+
+    // TODO(25579): This code can do the wrong thing redirecting constructor and
+    // the target do not correspond. It is correct if there is no
+    // warning. Ideally the redirecting constructor and the target would be the
+    // same function.
+
+    void loadLocal(ParameterElement parameter) {
       inputs.add(localsHandler.readLocal(parameter));
     }
-    for (; i < targetOptionals.length; i++) {
-      inputs.add(handleConstantForOptionalParameter(targetOptionals[i]));
+    void loadPosition(int position, ParameterElement optionalParameter) {
+      if (position < redirectingRequireds.length) {
+        loadLocal(redirectingRequireds[position]);
+      } else if (position < redirectingSignature.parameterCount &&
+                 !redirectingSignature.optionalParametersAreNamed) {
+        loadLocal(redirectingOptionals[position - redirectingRequireds.length]);
+      } else if (optionalParameter != null) {
+        inputs.add(handleConstantForOptionalParameter(optionalParameter));
+      } else {
+        // Wrong.
+        inputs.add(graph.addConstantNull(compiler));
+      }
     }
+
+    int position = 0;
+
+    for (ParameterElement targetParameter in targetRequireds) {
+      loadPosition(position++, null);
+    }
+
+    if (targetOptionals.isNotEmpty) {
+      if (targetSignature.optionalParametersAreNamed) {
+        for (ParameterElement parameter in targetOptionals) {
+          ParameterElement redirectingParameter =
+              redirectingOptionals.firstWhere(
+                  (p) => p.name == parameter.name,
+                  orElse: () => null);
+          if (redirectingParameter == null) {
+            inputs.add(handleConstantForOptionalParameter(parameter));
+          } else {
+            inputs.add(localsHandler.readLocal(redirectingParameter));
+          }
+        }
+      } else {
+        for (ParameterElement parameter in targetOptionals) {
+          loadPosition(position++, parameter);
+        }
+      }
+    }
+
     ClassElement targetClass = targetConstructor.enclosingClass;
     if (backend.classNeedsRti(targetClass)) {
       ClassElement cls = redirectingConstructor.enclosingClass;
@@ -7482,7 +7535,10 @@
     TypeMask mask = elements.getIteratorTypeMask(node);
 
     ClassWorld classWorld = compiler.world;
-    if (mask != null && mask.satisfies(helpers.jsIndexableClass, classWorld)) {
+    if (mask != null &&
+        mask.satisfies(helpers.jsIndexableClass, classWorld) &&
+        // String is indexable but not iterable.
+        !mask.satisfies(helpers.jsStringClass, classWorld)) {
       return buildSyncForInIndexable(node, mask);
     }
     buildSyncForInIterator(node);
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 688030a..fd2050c 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -247,7 +247,7 @@
     shouldGroupVarDeclarations = allocator.names.numberOfVariables > 1;
   }
 
-  void handleDelayedVariableDeclarations() {
+  void handleDelayedVariableDeclarations(SourceInformation sourceInformation) {
     // If we have only one variable declaration and the first statement is an
     // assignment to that variable then we can merge the two.  We count the
     // number of variables in the variable allocator to try to avoid this issue,
@@ -269,7 +269,8 @@
               js.VariableInitialization initialization =
                   new js.VariableInitialization(decl, assignment.value);
               currentContainer.statements[0] = new js.ExpressionStatement(
-                  new js.VariableDeclarationList([initialization]));
+                  new js.VariableDeclarationList([initialization]))
+                      .withSourceInformation(sourceInformation);
               return;
             }
           }
@@ -283,7 +284,8 @@
         declarations.add(new js.VariableInitialization(
             new js.VariableDeclaration(name), null));
       });
-      var declarationList = new js.VariableDeclarationList(declarations);
+      var declarationList = new js.VariableDeclarationList(declarations)
+          .withSourceInformation(sourceInformation);;
       insertStatementAtStart(new js.ExpressionStatement(declarationList));
     }
   }
@@ -293,7 +295,7 @@
     currentGraph = graph;
     subGraph = new SubGraph(graph.entry, graph.exit);
     visitBasicBlock(graph.entry);
-    handleDelayedVariableDeclarations();
+    handleDelayedVariableDeclarations(graph.sourceInformation);
   }
 
   void visitSubGraph(SubGraph newSubGraph) {
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 9cfb66b..8d5e08f 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -100,8 +100,7 @@
     // All intercepted classes extend `Interceptor`, so if the receiver can't be
     // a class extending `Interceptor` then it can be called directly.
     return new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, classWorld)
-        .intersection(receiver.instructionType, classWorld)
-        .isEmpty;
+        .isDisjoint(receiver.instructionType, classWorld);
   }
 
   HInstruction tryComputeConstantInterceptor(
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 0e1788b..c279da9 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -139,6 +139,7 @@
   bool isRecursiveMethod = false;
   bool calledInLoop = false;
   final List<HBasicBlock> blocks = <HBasicBlock>[];
+  SourceInformation sourceInformation;
 
   // We canonicalize all constants used within a graph so we do not
   // have to worry about them for global value numbering.
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index c98ceb1..a8d82ae 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -593,8 +593,7 @@
     // Intersection of int and double return conflicting, so
     // we don't optimize on numbers to preserve the runtime semantics.
     if (!(left.isNumberOrNull(compiler) && right.isNumberOrNull(compiler))) {
-      TypeMask intersection = leftType.intersection(rightType, compiler.world);
-      if (intersection.isEmpty && !intersection.isNullable) {
+      if (leftType.isDisjoint(rightType, compiler.world)) {
         return makeFalse();
       }
     }
@@ -737,8 +736,7 @@
           : new TypeMask.nonNullSubtype(element, classWorld);
       if (expressionMask.union(typeMask, classWorld) == typeMask) {
         return graph.addConstantBool(true, compiler);
-      } else if (expressionMask.intersection(typeMask,
-                                             compiler.world).isEmpty) {
+      } else if (expressionMask.isDisjoint(typeMask, compiler.world)) {
         return graph.addConstantBool(false, compiler);
       }
     }
@@ -2154,10 +2152,8 @@
     if (nonEscapingReceivers.contains(second)) return false;
     // Typed arrays of different types might have a shared buffer.
     if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true;
-    TypeMask intersection = first.instructionType.intersection(
+    return !first.instructionType.isDisjoint(
         second.instructionType, compiler.world);
-    if (intersection.isEmpty) return false;
-    return true;
   }
 
   bool isFinal(Element element) {
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index a940e71..7cd149e 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -682,6 +682,9 @@
     } else {
       constantNum = constant;
     }
+    if (constantNum.isPositiveInfinity || constantNum.isNegativeInfinity) {
+      return info.newUnboundRange();
+    }
     if (constantNum.isMinusZero) constantNum = new IntConstantValue(0);
     Value value = info.newIntValue(constantNum.primitiveValue);
     return info.newNormalizedRange(value, value);
diff --git a/pkg/compiler/lib/src/tokens/token.dart b/pkg/compiler/lib/src/tokens/token.dart
index 4c33648..1b05a5f 100644
--- a/pkg/compiler/lib/src/tokens/token.dart
+++ b/pkg/compiler/lib/src/tokens/token.dart
@@ -112,6 +112,9 @@
     }
   }
 
+  /// The character offset of the end of this token within the source text.
+  int get charEnd => charOffset + charCount;
+
   int get hashCode => computeHashCode(charOffset, info, value);
 }
 
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart
index 04d46f5..e95497b 100644
--- a/pkg/compiler/lib/src/tree/nodes.dart
+++ b/pkg/compiler/lib/src/tree/nodes.dart
@@ -147,6 +147,12 @@
 
   Token getBeginToken();
 
+  /// Returns the token that ends the 'prefix' of this node.
+  ///
+  /// For instance the end of the parameters in a [FunctionExpression] or the
+  /// last token before the start of a class body for a [ClassNode].
+  Token getPrefixEndToken() => getEndToken();
+
   Token getEndToken();
 
   Assert asAssert() => null;
@@ -263,6 +269,25 @@
 
   Token getBeginToken() => beginToken;
 
+  @override
+  Token getPrefixEndToken() {
+    Token token;
+    if (interfaces != null) {
+      token = interfaces.getEndToken();
+    }
+    if (token == null && superclass != null) {
+      token = superclass.getEndToken();
+    }
+    if (token == null && typeParameters != null) {
+      token == typeParameters.getEndToken();
+    }
+    if (token == null) {
+      token = name.getEndToken();
+    }
+    assert(invariant(beginToken, token != null));
+    return token;
+  }
+
   Token getEndToken() => endToken;
 }
 
@@ -738,6 +763,10 @@
   visitChildren(Visitor visitor) => function.accept(visitor);
 
   Token getBeginToken() => function.getBeginToken();
+
+  @override
+  Token getPrefixEndToken() => function.getPrefixEndToken();
+
   Token getEndToken() => function.getEndToken();
 }
 
@@ -826,6 +855,11 @@
     return firstBeginToken(name, parameters);
   }
 
+  @override
+  Token getPrefixEndToken() {
+    return parameters != null ? parameters.getEndToken() : name.getEndToken();
+  }
+
   Token getEndToken() {
     Token token = (body == null) ? null : body.getEndToken();
     token = (token == null) ? parameters.getEndToken() : token;
@@ -1300,7 +1334,10 @@
 
   Token getBeginToken() => typeName.getBeginToken();
 
-  Token getEndToken() => typeName.getEndToken();
+  Token getEndToken() {
+    if (typeArguments != null) return typeArguments.getEndToken();
+    return typeName.getEndToken();
+  }
 }
 
 class TypeVariable extends Node {
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
index b4f6dd8..dd44f1d 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
@@ -353,7 +353,8 @@
       case BuiltinOperator.IsNumber:
       case BuiltinOperator.IsNotNumber:
       case BuiltinOperator.IsFloor:
-      case BuiltinOperator.IsNumberAndFloor:
+      case BuiltinOperator.IsInteger:
+      case BuiltinOperator.IsNotInteger:
       case BuiltinOperator.Identical:
         return true;
       default:
@@ -373,6 +374,12 @@
       case BuiltinOperator.LooseNeq: return BuiltinOperator.LooseEq;
       case BuiltinOperator.IsNumber: return BuiltinOperator.IsNotNumber;
       case BuiltinOperator.IsNotNumber: return BuiltinOperator.IsNumber;
+      case BuiltinOperator.IsInteger: return BuiltinOperator.IsNotInteger;
+      case BuiltinOperator.IsNotInteger: return BuiltinOperator.IsInteger;
+      case BuiltinOperator.IsUnsigned32BitInteger:
+        return BuiltinOperator.IsNotUnsigned32BitInteger;
+      case BuiltinOperator.IsNotUnsigned32BitInteger:
+        return BuiltinOperator.IsUnsigned32BitInteger;
 
       // Because of NaN, these do not have a negated form.
       case BuiltinOperator.NumLt:
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
index 3b3a74a..8840c8e 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
@@ -168,7 +168,7 @@
     return node;
   }
 
-  Statement visitNullCheck(NullCheck node) {
+  Statement visitReceiverCheck(ReceiverCheck node) {
     if (node.condition != null) {
       node.condition = visitExpression(node.condition);
       // The value occurs in conditional context, so don't pull from that.
@@ -265,6 +265,12 @@
     return node;
   }
 
+  Expression visitAwait(Await node) {
+    super.visitAwait(node);
+    ++impureCounter;
+    return node;
+  }
+
   Expression visitConditional(Conditional node) {
     node.condition = visitExpression(node.condition);
     // Visit the branches to detect impure subexpressions, but do not pull
@@ -292,14 +298,6 @@
     return node;
   }
 
-  Expression visitLiteralMap(LiteralMap node) {
-    super.visitLiteralMap(node);
-    if (node.type != null) {
-      ++impureCounter; // Type casts can throw.
-    }
-    return node;
-  }
-
   Expression visitTypeOperator(TypeOperator node) {
     super.visitTypeOperator(node);
     if (!node.isTypeTest) {
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
index f23533c..3685137 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -372,6 +372,7 @@
            exp is CreateInvocationMirror ||
            exp is CreateInstance ||
            exp is CreateBox ||
+           exp is TypeExpression ||
            exp is GetStatic && exp.element.isFunction ||
            exp is Interceptor ||
            exp is ApplyBuiltinOperator ||
@@ -579,13 +580,11 @@
   }
 
   Expression visitLogicalOperator(LogicalOperator node) {
-    node.left = visitExpression(node.left);
-
     // Impure expressions may not propagate across the branch.
     inEmptyEnvironment(() {
       node.right = visitExpression(node.right);
     });
-
+    node.left = visitExpression(node.left);
     return node;
   }
 
@@ -739,31 +738,32 @@
     return node;
   }
 
-  Expression visitLiteralMap(LiteralMap node) {
-    // Process arguments right-to-left, the opposite of evaluation order.
-    for (LiteralMapEntry entry in node.entries.reversed) {
-      entry.value = visitExpression(entry.value);
-      entry.key = visitExpression(entry.key);
-    }
-    return node;
-  }
-
   Expression visitTypeOperator(TypeOperator node) {
     _rewriteList(node.typeArguments);
     node.value = visitExpression(node.value);
     return node;
   }
 
-  bool sameVariable(Expression e1, Expression e2) {
-    return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
-  }
-
   bool isCompoundableBuiltin(Expression e) {
     return e is ApplyBuiltinOperator &&
-           e.arguments.length == 2 &&
+           e.arguments.length >= 2 &&
            isCompoundableOperator(e.operator);
   }
 
+  /// Converts a compoundable operator application into the right-hand side for
+  /// use in a compound assignment, discarding the left-hand value.
+  ///
+  /// For example, for `x + y + z` it returns `y + z`.
+  Expression contractCompoundableBuiltin(ApplyBuiltinOperator e) {
+    assert(isCompoundableBuiltin(e));
+    if (e.arguments.length > 2) {
+      assert(e.operator == BuiltinOperator.StringConcatenate);
+      return new ApplyBuiltinOperator(e.operator, e.arguments.skip(1).toList());
+    } else {
+      return e.arguments[1];
+    }
+  }
+
   void destroyVariableUse(VariableUse node) {
     --node.variable.readCount;
   }
@@ -774,13 +774,12 @@
     if (isCompoundableBuiltin(node.value)) {
       ApplyBuiltinOperator rhs = node.value;
       Expression left = rhs.arguments[0];
-      Expression right = rhs.arguments[1];
       if (left is GetField &&
           left.field == node.field &&
-          sameVariable(left.object, node.object)) {
-        destroyVariableUse(left.object);
+          samePrimary(left.object, node.object)) {
+        destroyPrimaryExpression(left.object);
         node.compound = rhs.operator;
-        node.value = right;
+        node.value = contractCompoundableBuiltin(rhs);
       }
     }
     node.object = visitExpression(node.object);
@@ -800,6 +799,16 @@
   Expression visitSetStatic(SetStatic node) {
     allowRhsPropagation.add(true);
     node.value = visitExpression(node.value);
+    if (isCompoundableBuiltin(node.value)) {
+      ApplyBuiltinOperator rhs = node.value;
+      Expression left = rhs.arguments[0];
+      if (left is GetStatic &&
+          left.element == node.element &&
+          !left.useLazyGetter) {
+        node.compound = rhs.operator;
+        node.value = contractCompoundableBuiltin(rhs);
+      }
+    }
     allowRhsPropagation.removeLast();
     return node;
   }
@@ -814,6 +823,9 @@
   }
 
   Expression visitCreateInstance(CreateInstance node) {
+    if (node.typeInformation != null) {
+      node.typeInformation = visitExpression(node.typeInformation);
+    }
     _rewriteList(node.arguments);
     return node;
   }
@@ -859,14 +871,13 @@
     if (isCompoundableBuiltin(node.value)) {
       ApplyBuiltinOperator rhs = node.value;
       Expression left = rhs.arguments[0];
-      Expression right = rhs.arguments[1];
       if (left is GetIndex &&
-          sameVariable(left.object, node.object) &&
-          sameVariable(left.index, node.index)) {
-        destroyVariableUse(left.object);
-        destroyVariableUse(left.index);
+          samePrimary(left.object, node.object) &&
+          samePrimary(left.index, node.index)) {
+        destroyPrimaryExpression(left.object);
+        destroyPrimaryExpression(left.index);
         node.compound = rhs.operator;
-        node.value = right;
+        node.value = contractCompoundableBuiltin(rhs);
       }
     }
     node.index = visitExpression(node.index);
@@ -1244,13 +1255,13 @@
 
   @override
   Statement visitYield(Yield node) {
-    node.input = visitExpression(node.input);
     node.next = visitStatement(node.next);
+    node.input = visitExpression(node.input);
     return node;
   }
 
   @override
-  Statement visitNullCheck(NullCheck node) {
+  Statement visitReceiverCheck(ReceiverCheck node) {
     inEmptyEnvironment(() {
       node.next = visitStatement(node.next);
     });
@@ -1358,3 +1369,22 @@
     new VariableUseVisitor(callback).visitExpression(node);
   }
 }
+
+bool sameVariable(Expression e1, Expression e2) {
+  return e1 is VariableUse && e2 is VariableUse && e1.variable == e2.variable;
+}
+
+/// True if [e1] and [e2] are primary expressions (expressions without
+/// subexpressions) with the same value.
+bool samePrimary(Expression e1, Expression e2) {
+  return sameVariable(e1, e2) || (e1 is This && e2 is This);
+}
+
+/// Decrement the reference count for [e] if it is a variable use.
+void destroyPrimaryExpression(Expression e) {
+  if (e is VariableUse) {
+    --e.variable.readCount;
+  } else {
+    assert(e is This);
+  }
+}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
index fb31f02..bcc16ca 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
@@ -12,22 +12,19 @@
 /// This phase cleans up artifacts introduced by the translation through CPS,
 /// where each source variable is translated into several copies. The copies
 /// are merged again when they are not live simultaneously.
-class VariableMerger extends RecursiveVisitor implements Pass {
+class VariableMerger implements Pass {
   String get passName => 'Variable merger';
 
-  void rewrite(FunctionDefinition node) {
-    rewriteFunction(node);
-    visitStatement(node.body);
-  }
+  final bool minifying;
 
-  /// Rewrites the given function.
-  /// This is called for the outermost function and inner functions.
-  void rewriteFunction(FunctionDefinition node) {
-    BlockGraphBuilder builder = new BlockGraphBuilder();
-    builder.build(node);
+  VariableMerger({this.minifying: false});
+
+  void rewrite(FunctionDefinition node) {
+    BlockGraphBuilder builder = new BlockGraphBuilder()..build(node);
     _computeLiveness(builder.blocks);
-    Map<Variable, Variable> subst =
-        _computeRegisterAllocation(builder.blocks, node.parameters);
+    PriorityPairs priority = new PriorityPairs()..build(node);
+    Map<Variable, Variable> subst = _computeRegisterAllocation(
+        builder.blocks, node.parameters, priority, minifying: minifying);
     new SubstituteVariables(subst).apply(node);
   }
 }
@@ -248,6 +245,54 @@
   }
 }
 
+/// Collects prioritized variable pairs -- pairs that lead to significant code
+/// reduction if merged into one variable.
+///
+/// These arise from moving assigments `v1 = v2`, and compoundable assignments
+/// `v1 = v2 [+] E` where [+] is a compoundable operator.
+//
+// TODO(asgerf): We could have a more fine-grained priority level. All pairs
+//   are treated as equally important, but some pairs can eliminate more than
+//   one assignment.
+//   Also, some assignments are more important to remove than others, as they
+//   can block a later optimization, such rewriting a loop, or removing the
+//   'else' part of an 'if'.
+//
+class PriorityPairs extends RecursiveVisitor {
+  final Map<Variable, List<Variable>> _priority = <Variable, List<Variable>>{};
+
+  void build(FunctionDefinition node) {
+    visitStatement(node.body);
+  }
+
+  void _prioritize(Variable x, Variable y) {
+    _priority.putIfAbsent(x, () => new List<Variable>()).add(y);
+    _priority.putIfAbsent(y, () => new List<Variable>()).add(x);
+  }
+
+  visitAssign(Assign node) {
+    super.visitAssign(node);
+    Expression value = node.value;
+    if (value is VariableUse) {
+      _prioritize(node.variable, value.variable);
+    } else if (value is ApplyBuiltinOperator &&
+               isCompoundableOperator(value.operator) &&
+               value.arguments[0] is VariableUse) {
+      VariableUse use = value.arguments[0];
+      _prioritize(node.variable, use.variable);
+    }
+  }
+
+  /// Returns the other half of every priority pair containing [variable].
+  List<Variable> getPriorityPairsWith(Variable variable) {
+    return _priority[variable] ?? const <Variable>[];
+  }
+
+  bool hasPriorityPairs(Variable variable) {
+    return _priority.containsKey(variable);
+  }
+}
+
 /// Computes liveness information of the given control-flow graph.
 ///
 /// The results are stored in [Block.liveIn] and [Block.liveOut].
@@ -331,14 +376,6 @@
   }
 }
 
-/// For testing purposes, this flag can be passed to merge variables that
-/// originated from different source variables.
-///
-/// Correctness should not depend on the fact that we only merge variables
-/// originating from the same source variable. Setting this flag makes a bug
-/// more likely to provoke a test case failure.
-const bool NO_PRESERVE_VARS = const bool.fromEnvironment('NO_PRESERVE_VARS');
-
 /// Based on liveness information, computes a map of variable substitutions to
 /// merge variables.
 ///
@@ -348,23 +385,30 @@
 ///
 /// We then compute a graph coloring, where the color of a node denotes which
 /// variable it will be substituted by.
-///
-/// We never merge variables that originated from distinct source variables,
-/// so we build a separate register interference graph for each source variable.
 Map<Variable, Variable> _computeRegisterAllocation(List<Block> blocks,
-                                                   List<Variable> parameters) {
+                                                   List<Variable> parameters,
+                                                   PriorityPairs priority,
+                                                   {bool minifying}) {
   Map<Variable, Set<Variable>> interference = <Variable, Set<Variable>>{};
 
-  /// Group for the given variable. We attempt to merge variables in the same
-  /// group.
-  /// By default, variables are grouped based on their source variable name,
-  /// but this can be disabled for testing purposes.
-  String group(Variable variable) {
-    if (NO_PRESERVE_VARS) return '';
-    // Group variables based on the source variable's name, not its element,
-    // so if multiple locals are declared with the same name, they will
-    // map to the same (hoisted) variable in the output.
-    return variable.element == null ? '' : variable.element.name;
+  bool allowUnmotivatedMerge(Variable x, Variable y) {
+    if (minifying) return true;
+    // Do not allow merging temporaries with named variables if they are
+    // not connected by a phi.  That would leads to confusing mergings like:
+    //    var v0 = receiver.length;
+    //        ==>
+    //    receiver = receiver.length;
+    return x.element?.name == y.element?.name;
+  }
+
+  bool allowPhiMerge(Variable x, Variable y) {
+    if (minifying) return true;
+    // Temporaries may be merged with a named variable if this eliminates a phi.
+    // The presence of the phi implies that the two variables can contain the
+    // same value, so it is not that confusing that they get the same name.
+    return x.element == null ||
+           y.element == null ||
+           x.element.name == y.element.name;
   }
 
   Set<Variable> empty = new Set<Variable>();
@@ -372,12 +416,10 @@
   // At the assignment to a variable x, add an edge to every variable that is
   // live after the assignment (if it came from the same source variable).
   for (Block block in blocks) {
-    // Group the liveOut set by source variable.
-    Map<String, Set<Variable>> liveOut = <String, Set<Variable>>{};
+    // Track the live set while traversing the block.
+    Set<Variable> live = new Set<Variable>();
     for (Variable variable in block.liveOut) {
-      liveOut.putIfAbsent(
-          group(variable),
-          () => new Set<Variable>()).add(variable);
+      live.add(variable);
       interference.putIfAbsent(variable, () => new Set<Variable>());
     }
     // Get variables that are live at the catch block.
@@ -388,8 +430,6 @@
     for (VariableAccess access in block.accesses.reversed) {
       Variable variable = access.variable;
       interference.putIfAbsent(variable, () => new Set<Variable>());
-      Set<Variable> live =
-          liveOut.putIfAbsent(group(variable), () => new Set<Variable>());
       if (access.isRead) {
         live.add(variable);
       } else {
@@ -410,42 +450,89 @@
   List<Variable> variables = interference.keys.toList();
   variables.sort((x, y) => interference[y].length - interference[x].length);
 
-  Map<String, List<Variable>> registers = <String, List<Variable>>{};
+  List<Variable> registers = <Variable>[];
   Map<Variable, Variable> subst = <Variable, Variable>{};
 
-  // Parameters are special in that they must have a ParameterElement and
-  // cannot be merged with each other. Ensure that they are not substituted.
-  // Other variables can still be substituted by a parameter.
-  for (Variable parameter in parameters) {
-    if (parameter.isCaptured) continue;
-    subst[parameter] = parameter;
-    registers[group(parameter)] = <Variable>[parameter];
+  /// Called when [variable] has been assigned [target] as its register/color.
+  /// Will immediately try to satisfy its priority pairs by assigning the same
+  /// color the other half of each pair.
+  void searchPriorityPairs(Variable variable, Variable target) {
+    if (!priority.hasPriorityPairs(variable)) {
+      return; // Most variables (around 90%) do not have priority pairs.
+    }
+    List<Variable> worklist = <Variable>[variable];
+    while (worklist.isNotEmpty) {
+      Variable v1 = worklist.removeLast();
+      for (Variable v2 in priority.getPriorityPairsWith(v1)) {
+        // If v2 already has a color, we cannot change it.
+        if (subst.containsKey(v2)) continue;
+
+        // Do not merge differently named variables.
+        if (!allowPhiMerge(v1, v2)) continue;
+
+        // Ensure the graph coloring remains valid. If a neighbour of v2 already
+        // has the desired color, we cannot assign the same color to v2.
+        if (interference[v2].any((v3) => subst[v3] == target)) continue;
+
+        subst[v2] = target;
+        target.element ??= v2.element; // Preserve the name.
+        worklist.add(v2);
+      }
+    }
   }
 
+  void assignRegister(Variable variable, Variable registerRepresentative) {
+    subst[variable] = registerRepresentative;
+    // Ensure this register is never assigned to a variable with another name.
+    // This also ensures that named variables keep their name when merged
+    // with a temporary.
+    registerRepresentative.element ??= variable.element;
+    searchPriorityPairs(variable, registerRepresentative);
+  }
+
+  void assignNewRegister(Variable variable) {
+    registers.add(variable);
+    subst[variable] = variable;
+    searchPriorityPairs(variable, variable);
+  }
+
+  // Parameters cannot be merged with each other. Ensure that they are not
+  // substituted.  Other variables can still be substituted by a parameter.
+  for (Variable parameter in parameters) {
+    if (parameter.isCaptured) continue;
+    registers.add(parameter);
+    subst[parameter] = parameter;
+  }
+
+  // Try to merge parameters with locals to eliminate phis.
+  for (Variable parameter in parameters) {
+    searchPriorityPairs(parameter, parameter);
+  }
+
+  v1loop:
   for (Variable v1 in variables) {
-    // Parameters have already been assigned a substitute; skip those.
+    // Ignore if the variable has already been assigned a register.
     if (subst.containsKey(v1)) continue;
 
-    List<Variable> register = registers[group(v1)];
-
-    // Optimization: For the first variable in a group, allocate a new color
-    // without iterating over its interference edges.
-    if (register == null) {
-      registers[group(v1)] = <Variable>[v1];
-      subst[v1] = v1;
-      continue;
-    }
-
     // Optimization: If there are no interference edges for this variable,
-    // assign it the first color without copying the register list.
+    // find a color for it without copying the register list.
     Set<Variable> interferenceSet = interference[v1];
     if (interferenceSet.isEmpty) {
-      subst[v1] = register[0];
+      // Use the first register where naming constraints allow the merge.
+      for (Variable v2 in registers) {
+        if (allowUnmotivatedMerge(v1, v2)) {
+          assignRegister(v1, v2);
+          continue v1loop;
+        }
+      }
+      // No register allows merging with this one, create a new register.
+      assignNewRegister(v1);
       continue;
     }
 
     // Find an unused color.
-    Set<Variable> potential = new Set<Variable>.from(register);
+    Set<Variable> potential = new Set<Variable>.from(
+          registers.where((v2) => allowUnmotivatedMerge(v1, v2)));
     for (Variable v2 in interferenceSet) {
       Variable v2subst = subst[v2];
       if (v2subst != null) {
@@ -456,10 +543,9 @@
 
     if (potential.isEmpty) {
       // If no free color was found, add this variable as a new color.
-      register.add(v1);
-      subst[v1] = v1;
+      assignNewRegister(v1);
     } else {
-      subst[v1] = potential.first;
+      assignRegister(v1, potential.first);
     }
   }
 
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 b846c87..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),
-        translateArguments(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,46 +540,36 @@
   Expression visitLiteralList(cps_ir.LiteralList node) {
     return new LiteralList(
             node.dartType,
-            translateArguments(node.values));
-  }
-
-  Expression visitLiteralMap(cps_ir.LiteralMap node) {
-    return new LiteralMap(
-        node.dartType,
-        new List<LiteralMapEntry>.generate(node.entries.length, (int index) {
-          return new LiteralMapEntry(
-              getVariableUse(node.entries[index].key),
-              getVariableUse(node.entries[index].value));
-        })
-    );
+            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);
   }
 
   Expression visitTypeExpression(cps_ir.TypeExpression node) {
     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)));
   }
@@ -591,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);
   }
@@ -634,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
@@ -654,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,
@@ -683,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) {
@@ -709,12 +699,16 @@
     }
   }
 
-  visitNullCheck(cps_ir.NullCheck node) => (Statement next) {
-    return new NullCheck(
-        condition: getVariableUseOrNull(node.condition),
-        value: getVariableUse(node.value),
+  visitReceiverCheck(cps_ir.ReceiverCheck node) => (Statement next) {
+    // The CPS IR uses 'isNullCheck' because the semantics are important.
+    // 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.conditionRef),
+        value: getVariableUse(node.valueRef),
         selector: node.selector,
         useSelector: node.useSelector,
+        useInvoke: !node.isNullCheck,
         next: next,
         sourceInformation: node.sourceInformation);
   };
@@ -726,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/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index 19eeb05..ec2e34a 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -13,6 +13,8 @@
 
 import '../cps_ir/builtin_operator.dart';
 export '../cps_ir/builtin_operator.dart';
+import '../cps_ir/cps_ir_nodes.dart' show TypeExpressionKind;
+export '../cps_ir/cps_ir_nodes.dart' show TypeExpressionKind;
 
 // 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
@@ -114,7 +116,8 @@
     assert(host != null);
   }
 
-  String toString() => element == null ? 'Variable' : element.toString();
+  String toString() =>
+      element == null ? 'Variable.${hashCode}' : element.toString();
 }
 
 /// Read the value of a variable.
@@ -312,25 +315,6 @@
   }
 }
 
-class LiteralMapEntry {
-  Expression key;
-  Expression value;
-
-  LiteralMapEntry(this.key, this.value);
-}
-
-class LiteralMap extends Expression {
-  final InterfaceType type;
-  final List<LiteralMapEntry> entries;
-
-  LiteralMap(this.type, this.entries);
-
-  accept(ExpressionVisitor visitor) => visitor.visitLiteralMap(this);
-  accept1(ExpressionVisitor1 visitor, arg) {
-    return visitor.visitLiteralMap(this, arg);
-  }
-}
-
 /// Type test or type cast.
 ///
 /// Note that if this is a type test, then [type] cannot be `Object`, `dynamic`,
@@ -688,7 +672,7 @@
 class CreateInstance extends Expression {
   ClassElement classElement;
   List<Expression> arguments;
-  List<Expression> typeInformation;
+  Expression typeInformation;
   SourceInformation sourceInformation;
 
   CreateInstance(this.classElement, this.arguments,
@@ -760,8 +744,9 @@
   Element element;
   Expression value;
   SourceInformation sourceInformation;
+  BuiltinOperator compound;
 
-  SetStatic(this.element, this.value, this.sourceInformation);
+  SetStatic(this.element, this.value, this.sourceInformation, {this.compound});
 
   accept(ExpressionVisitor visitor) => visitor.visitSetStatic(this);
   accept1(ExpressionVisitor1 visitor, arg) => visitor.visitSetStatic(this, arg);
@@ -920,10 +905,11 @@
 /// are replaced by the values in [arguments].
 /// (See documentation on the TypeExpression CPS node for more details.)
 class TypeExpression extends Expression {
+  final TypeExpressionKind kind;
   final DartType dartType;
   final List<Expression> arguments;
 
-  TypeExpression(this.dartType, this.arguments);
+  TypeExpression(this.kind, this.dartType, this.arguments);
 
   accept(ExpressionVisitor visitor) {
     return visitor.visitTypeExpression(this);
@@ -964,23 +950,24 @@
   }
 }
 
-class NullCheck extends Statement {
+class ReceiverCheck extends Statement {
   Expression condition;
   Expression value;
   Selector selector;
   bool useSelector;
+  bool useInvoke;
   Statement next;
   SourceInformation sourceInformation;
 
-  NullCheck({this.condition, this.value, this.selector, this.useSelector,
-      this.next, this.sourceInformation});
+  ReceiverCheck({this.condition, this.value, this.selector, this.useSelector,
+      this.useInvoke, this.next, this.sourceInformation});
 
   accept(StatementVisitor visitor) {
-    return visitor.visitNullCheck(this);
+    return visitor.visitReceiverCheck(this);
   }
 
   accept1(StatementVisitor1 visitor, arg) {
-    return visitor.visitNullCheck(this, arg);
+    return visitor.visitReceiverCheck(this, arg);
   }
 }
 
@@ -999,7 +986,6 @@
   E visitLogicalOperator(LogicalOperator node);
   E visitNot(Not node);
   E visitLiteralList(LiteralList node);
-  E visitLiteralMap(LiteralMap node);
   E visitTypeOperator(TypeOperator node);
   E visitGetField(GetField node);
   E visitSetField(SetField node);
@@ -1037,7 +1023,6 @@
   E visitLogicalOperator(LogicalOperator node, A arg);
   E visitNot(Not node, A arg);
   E visitLiteralList(LiteralList node, A arg);
-  E visitLiteralMap(LiteralMap node, A arg);
   E visitTypeOperator(TypeOperator node, A arg);
   E visitGetField(GetField node, A arg);
   E visitSetField(SetField node, A arg);
@@ -1075,7 +1060,7 @@
   S visitUnreachable(Unreachable node);
   S visitForeignStatement(ForeignStatement node);
   S visitYield(Yield node);
-  S visitNullCheck(NullCheck node);
+  S visitReceiverCheck(ReceiverCheck node);
 }
 
 abstract class StatementVisitor1<S, A> {
@@ -1093,7 +1078,7 @@
   S visitUnreachable(Unreachable node, A arg);
   S visitForeignStatement(ForeignStatement node, A arg);
   S visitYield(Yield node, A arg);
-  S visitNullCheck(NullCheck node, A arg);
+  S visitReceiverCheck(ReceiverCheck node, A arg);
 }
 
 abstract class RecursiveVisitor implements StatementVisitor, ExpressionVisitor {
@@ -1156,13 +1141,6 @@
     node.values.forEach(visitExpression);
   }
 
-  visitLiteralMap(LiteralMap node) {
-    node.entries.forEach((LiteralMapEntry entry) {
-      visitExpression(entry.key);
-      visitExpression(entry.value);
-    });
-  }
-
   visitTypeOperator(TypeOperator node) {
     visitExpression(node.value);
     node.typeArguments.forEach(visitExpression);
@@ -1243,7 +1221,7 @@
 
   visitCreateInstance(CreateInstance node) {
     node.arguments.forEach(visitExpression);
-    node.typeInformation.forEach(visitExpression);
+    if (node.typeInformation != null) visitExpression(node.typeInformation);
   }
 
   visitReifyRuntimeType(ReifyRuntimeType node) {
@@ -1309,7 +1287,7 @@
     visitStatement(node.next);
   }
 
-  visitNullCheck(NullCheck node) {
+  visitReceiverCheck(ReceiverCheck node) {
     if (node.condition != null) visitExpression(node.condition);
     visitExpression(node.value);
     visitStatement(node.next);
@@ -1390,14 +1368,6 @@
     return node;
   }
 
-  visitLiteralMap(LiteralMap node) {
-    node.entries.forEach((LiteralMapEntry entry) {
-      entry.key = visitExpression(entry.key);
-      entry.value = visitExpression(entry.value);
-    });
-    return node;
-  }
-
   visitTypeOperator(TypeOperator node) {
     node.value = visitExpression(node.value);
     _replaceExpressions(node.typeArguments);
@@ -1492,7 +1462,9 @@
 
   visitCreateInstance(CreateInstance node) {
     _replaceExpressions(node.arguments);
-    _replaceExpressions(node.typeInformation);
+    if (node.typeInformation != null) {
+      node.typeInformation = visitExpression(node.typeInformation);
+    }
     return node;
   }
 
@@ -1575,7 +1547,7 @@
     return node;
   }
 
-  visitNullCheck(NullCheck node) {
+  visitReceiverCheck(ReceiverCheck node) {
     if (node.condition != null) {
       node.condition = visitExpression(node.condition);
     }
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
index 979647a..01aed83 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
@@ -179,7 +179,7 @@
     visitStatement(node.next);
   }
 
-  visitNullCheck(NullCheck node) {
+  visitReceiverCheck(ReceiverCheck node) {
     _addStatement(node);
     visitStatement(node.next);
   }
@@ -345,7 +345,7 @@
   }
 
   @override
-  visitNullCheck(NullCheck node) {
+  visitReceiverCheck(ReceiverCheck node) {
     printStatement(null, 'NullCheck ${expr(node.value)}');
   }
 }
@@ -414,16 +414,6 @@
     return "list [$values]";
   }
 
-  String visitLiteralMap(LiteralMap node) {
-    List<String> entries = new List<String>();
-    node.entries.forEach((LiteralMapEntry entry) {
-      String key = visitExpression(entry.key);
-      String value = visitExpression(entry.value);
-      entries.add("$key: $value");
-    });
-    return "map [${entries.join(', ')}]";
-  }
-
   String visitConstant(Constant node) {
     return "${node.value.toStructuredString()}";
   }
@@ -533,7 +523,9 @@
 
   @override
   String visitTypeExpression(TypeExpression node) {
-    return node.dartType.toString();
+    String kind = '${node.kind}'.split('.').last;
+    String args = node.arguments.map(visitExpression).join(', ');
+    return 'TypeExpression($kind, ${node.dartType}, $args)';
   }
 
   @override
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index 6512c5a..73e8ae4 100644
--- a/pkg/compiler/lib/src/types/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -53,7 +53,13 @@
 
   AbstractValue get interceptedTypes;
 
-  bool methodUsesReceiverArgument(FunctionElement function);
+  /// If true, [function] ignores its explicit receiver argument and will use
+  /// its `this` value instead.
+  bool methodIgnoresReceiverArgument(FunctionElement function);
+
+  /// If true, the explicit receiver argument can be ignored when invoking
+  /// [selector] on a value of [type].
+  bool targetIgnoresReceiverArgument(AbstractValue type, Selector selector);
 
   Element locateSingleElement(AbstractValue mask, Selector selector);
 
@@ -130,6 +136,8 @@
 
   bool isDefinitelyIntercepted(AbstractValue t, {bool allowNull});
 
+  bool isDefinitelySelfInterceptor(AbstractValue t, {bool allowNull: false});
+
   /// Given a class from the interceptor hierarchy, returns an [AbstractValue]
   /// matching all values with that interceptor (or a subtype thereof).
   AbstractValue getInterceptorSubtypes(ClassElement class_);
diff --git a/pkg/compiler/lib/src/types/constants.dart b/pkg/compiler/lib/src/types/constants.dart
index 1129465..e7ecab1 100644
--- a/pkg/compiler/lib/src/types/constants.dart
+++ b/pkg/compiler/lib/src/types/constants.dart
@@ -36,15 +36,15 @@
 
   @override
   TypeMask visitDouble(DoubleConstantValue constant, Compiler compiler) {
-    // We have to distinguish -0.0 from 0, but for all practical purposes
-    // -0.0 is an integer.
-    // TODO(17235): this kind of special casing should only happen in the
-    // backend.
-    if (constant.isMinusZero &&
-        compiler.backend.constantSystem.isInt(constant)) {
-      return compiler.typesTask.uint31Type;
+    // We have to recognize double constants that are 'is int'.
+    if (compiler.backend.constantSystem.isInt(constant)) {
+      if (constant.isMinusZero) {
+        return compiler.typesTask.uint31Type;
+      } else {
+        assert(constant.isPositiveInfinity || constant.isNegativeInfinity);
+        return compiler.typesTask.intType;
+      }
     }
-    assert(!compiler.backend.constantSystem.isInt(constant));
     return compiler.typesTask.doubleType;
   }
 
diff --git a/pkg/compiler/lib/src/types/flat_type_mask.dart b/pkg/compiler/lib/src/types/flat_type_mask.dart
index 6516d96..914e673 100644
--- a/pkg/compiler/lib/src/types/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/types/flat_type_mask.dart
@@ -358,6 +358,47 @@
     }
   }
 
+  bool isDisjoint(TypeMask other, ClassWorld classWorld) {
+    if (other is! FlatTypeMask) return other.isDisjoint(this, classWorld);
+    FlatTypeMask flatOther = other;
+
+    if (isNullable && flatOther.isNullable) return false;
+    if (isEmpty || flatOther.isEmpty) return true;
+    if (base == flatOther.base) return false;
+    if (isExact && flatOther.isExact) return true;
+
+    if (isExact) return !flatOther.contains(base, classWorld);
+    if (flatOther.isExact) return !contains(flatOther.base, classWorld);
+
+    // Normalization guarantees that isExact === !isSubclass && !isSubtype.
+    // Both are subclass or subtype masks, so if there is a subclass
+    // relationship, they are not disjoint.
+    if (classWorld.isSubclassOf(flatOther.base, base)) return false;
+    if (classWorld.isSubclassOf(base, flatOther.base)) return false;
+
+    // Two different base classes have no common subclass unless one is a
+    // subclass of the other (checked above).
+    if (isSubclass && flatOther.isSubclass) return true;
+
+    return _isDisjointHelper(this, flatOther, classWorld);
+  }
+
+  static bool _isDisjointHelper(
+      FlatTypeMask a, FlatTypeMask b, ClassWorld classWorld) {
+    if (!a.isSubclass && b.isSubclass) {
+      return _isDisjointHelper(b, a, classWorld);
+    }
+    assert(a.isSubclass || a.isSubtype);
+    assert(b.isSubtype);
+    var elements = a.isSubclass
+      ? classWorld.strictSubclassesOf(a.base)
+      : classWorld.strictSubtypesOf(a.base);
+    for (var element in elements) {
+      if (classWorld.isSubtypeOf(element, b.base)) return false;
+    }
+    return true;
+  }
+
   TypeMask intersectionSame(FlatTypeMask other, ClassWorld classWorld) {
     assert(base == other.base);
     // The two masks share the base type, so we must chose the most
@@ -685,16 +726,7 @@
     if (xSubset == null) return null;
     Iterable<ClassElement> ySubset = containedSubset(y, classWorld);
     if (ySubset == null) return null;
-    Iterable<ClassElement> smallSet, largeSet;
-    if (xSubset.length <= ySubset.length) {
-      smallSet = xSubset;
-      largeSet = ySubset;
-    } else {
-      smallSet = ySubset;
-      largeSet = xSubset;
-    }
-    var result = smallSet.where((ClassElement each) => largeSet.contains(each));
-    return result.toSet();
+    return xSubset.toSet().intersection(ySubset.toSet());
   }
 
   static Iterable<ClassElement> containedSubset(FlatTypeMask x,
diff --git a/pkg/compiler/lib/src/types/forwarding_type_mask.dart b/pkg/compiler/lib/src/types/forwarding_type_mask.dart
index ce29f50..a4400c6 100644
--- a/pkg/compiler/lib/src/types/forwarding_type_mask.dart
+++ b/pkg/compiler/lib/src/types/forwarding_type_mask.dart
@@ -84,6 +84,10 @@
     return forwardTo.union(other, classWorld);
   }
 
+  bool isDisjoint(TypeMask other, ClassWorld classWorld) {
+    return forwardTo.isDisjoint(other, classWorld);
+  }
+
   TypeMask intersection(TypeMask other, ClassWorld classWorld) {
     return forwardTo.intersection(other, classWorld);
   }
diff --git a/pkg/compiler/lib/src/types/type_mask.dart b/pkg/compiler/lib/src/types/type_mask.dart
index 3339738..736df0d 100644
--- a/pkg/compiler/lib/src/types/type_mask.dart
+++ b/pkg/compiler/lib/src/types/type_mask.dart
@@ -329,6 +329,10 @@
    */
   TypeMask union(TypeMask other, ClassWorld classWorld);
 
+
+  /// Returns whether the intersection of this and [other] is empty.
+  bool isDisjoint(TypeMask other, ClassWorld classWorld);
+
   /**
    * Returns a type mask representing the intersection of [this] and [other].
    */
diff --git a/pkg/compiler/lib/src/types/union_type_mask.dart b/pkg/compiler/lib/src/types/union_type_mask.dart
index 4a8397e..6166349 100644
--- a/pkg/compiler/lib/src/types/union_type_mask.dart
+++ b/pkg/compiler/lib/src/types/union_type_mask.dart
@@ -118,11 +118,11 @@
         // TODO(sigmund, johnniwinther): computing length here (and below) is
         // expensive. If we can't prevent `flatten` from being called a lot, it
         // might be worth caching results.
-        size = classWorld.strictSubclassesOf(candidate).length;
-        assert(size <= classWorld.strictSubtypesOf(candidate).length);
+        size = classWorld.strictSubclassCount(candidate);
+        assert(size <= classWorld.strictSubtypeCount(candidate));
       } else {
         kind = FlatTypeMask.SUBTYPE;
-        size = classWorld.strictSubtypesOf(candidate).length;
+        size = classWorld.strictSubtypeCount(candidate);
       }
       // Update the best candidate if the new one is better.
       if (bestElement == null || size < bestSize) {
@@ -152,12 +152,17 @@
   TypeMask intersection(var other, ClassWorld classWorld) {
     other = TypeMask.nonForwardingMask(other);
     if (!other.isUnion && disjointMasks.contains(other)) return other;
+    if (other.isUnion && this == other) return this;
 
     List<TypeMask> intersections = <TypeMask>[];
     for (TypeMask current in disjointMasks) {
       if (other.isUnion) {
-        for (FlatTypeMask flatOther in other.disjointMasks) {
-          intersections.add(current.intersection(flatOther, classWorld));
+        if (other.disjointMasks.contains(current)) {
+          intersections.add(current);
+        } else {
+          for (FlatTypeMask flatOther in other.disjointMasks) {
+            intersections.add(current.intersection(flatOther, classWorld));
+          }
         }
       } else {
         intersections.add(current.intersection(other, classWorld));
@@ -166,6 +171,13 @@
     return new TypeMask.unionOf(intersections, classWorld);
   }
 
+  bool isDisjoint(TypeMask other, ClassWorld classWorld) {
+    for (var current in disjointMasks) {
+      if (!current.isDisjoint(other, classWorld)) return false;
+    }
+    return true;
+  }
+
   TypeMask nullable() {
     if (isNullable) return this;
     List<FlatTypeMask> newList = new List<FlatTypeMask>.from(disjointMasks);
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index d895de2..3790a03 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -6,6 +6,7 @@
 
 import 'dart:collection' show
     IterableBase;
+import '../common.dart';
 import '../elements/elements.dart' show
     ClassElement;
 import '../util/enumset.dart' show
@@ -92,12 +93,14 @@
     return mask;
   }
 
+  final ClassHierarchyNode parentNode;
   final ClassElement cls;
   final EnumSet<Instantiation> _mask =
       new EnumSet<Instantiation>.fromValues(
           const <Instantiation>[Instantiation.UNINSTANTIATED]);
 
   ClassElement _leastUpperInstantiatedSubclass;
+  int _instantiatedSubclassCount = 0;
 
   /// `true` if [cls] has been directly instantiated.
   ///
@@ -111,14 +114,23 @@
 
   void set isDirectlyInstantiated(bool value) {
     if (value != isDirectlyInstantiated) {
+      ClassHierarchyNode parent = parentNode;
       if (value) {
         _mask.remove(Instantiation.UNINSTANTIATED);
         _mask.add(Instantiation.DIRECTLY_INSTANTIATED);
+        while (parent != null) {
+          parent._updateInstantiatedSubclassCount(1);
+          parent = parent.parentNode;
+        }
       } else {
         _mask.remove(Instantiation.DIRECTLY_INSTANTIATED);
         if (_mask.isEmpty) {
           _mask.add(Instantiation.UNINSTANTIATED);
         }
+        while (parent != null) {
+          parent._updateInstantiatedSubclassCount(-1);
+          parent = parent.parentNode;
+        }
       }
     }
   }
@@ -131,12 +143,18 @@
   ///   class C extends B {}
   ///   main() => [new B(), new C()];
   ///
-  bool get isIndirectlyInstantiated =>
-      _mask.contains(Instantiation.INDIRECTLY_INSTANTIATED);
+  bool get isIndirectlyInstantiated => _instantiatedSubclassCount > 0;
 
-  void set isIndirectlyInstantiated(bool value) {
-    if (value != isIndirectlyInstantiated) {
-      if (value) {
+  /// The number of strict subclasses that are directly or indirectly
+  /// instantiated.
+  int get instantiatedSubclassCount => _instantiatedSubclassCount;
+
+  void _updateInstantiatedSubclassCount(int change) {
+    bool before = isIndirectlyInstantiated;
+    _instantiatedSubclassCount += change;
+    bool after = isIndirectlyInstantiated;
+    if (before != after) {
+      if (after) {
         _mask.remove(Instantiation.UNINSTANTIATED);
         _mask.add(Instantiation.INDIRECTLY_INSTANTIATED);
       } else {
@@ -151,7 +169,11 @@
   /// The nodes for the direct subclasses of [cls].
   Link<ClassHierarchyNode> _directSubclasses = const Link<ClassHierarchyNode>();
 
-  ClassHierarchyNode(this.cls);
+  ClassHierarchyNode(this.parentNode, this.cls) {
+    if (parentNode != null) {
+      parentNode.addDirectSubclass(this);
+    }
+  }
 
   /// Adds [subclass] as a direct subclass of [cls].
   void addDirectSubclass(ClassHierarchyNode subclass) {
@@ -177,24 +199,6 @@
 
   /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
   ///
-  /// The directly instantiated, indirectly instantiated and uninstantiated
-  /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
-  /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
-  /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
-  Iterable<ClassElement> subclasses(
-      {bool includeDirectlyInstantiated: true,
-       bool includeIndirectlyInstantiated: true,
-       bool includeUninstantiated: true,
-       bool strict: false}) {
-    EnumSet<Instantiation> mask = createMask(
-        includeDirectlyInstantiated: includeDirectlyInstantiated,
-        includeIndirectlyInstantiated:includeIndirectlyInstantiated,
-        includeUninstantiated: includeUninstantiated);
-    return subclassesByMask(mask, strict: strict);
-  }
-
-  /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
-  ///
   /// Subclasses are included if their instantiation properties intersect with
   /// their corresponding [Instantiation] values in [mask]. If [strict] is
   /// `true`, [cls] itself is _not_ returned.
@@ -205,6 +209,65 @@
         this, mask, includeRoot: !strict);
   }
 
+  /// Applies [predicate] to each subclass of [cls] matching the criteria
+  /// specified by [mask] and [strict]. If [predicate] returns `true` on a
+  /// class, visitation is stopped immediately and the function returns `true`.
+  ///
+  /// [predicate] is applied to subclasses if their instantiation properties
+  /// intersect with their corresponding [Instantiation] values in [mask]. If
+  /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
+  bool anySubclass(
+      bool predicate(ClassElement cls),
+      EnumSet<Instantiation> mask,
+      {bool strict: false}) {
+
+    ForEach wrapper(ClassElement cls) {
+      return predicate(cls) ? ForEach.STOP : ForEach.CONTINUE;
+    }
+    return forEachSubclass(wrapper, mask, strict: strict) == ForEach.STOP;
+  }
+
+  /// Applies [f] to each subclass of [cls] matching the criteria specified by
+  /// [mask] and [strict].
+  ///
+  /// [f] is a applied to subclasses if their instantiation properties intersect
+  /// with their corresponding [Instantiation] values in [mask]. If [strict] is
+  /// `true`, [f] is _not_ called on [cls] itself.
+  ///
+  /// The visitation of subclasses can be cut short by the return value of [f].
+  /// If [ForEach.STOP] is returned, no further classes are visited and the
+  /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
+  /// subclasses of the last visited class are skipped, but visitation
+  /// continues. The return value of the function is either [ForEach.STOP], if
+  /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
+  /// the end.
+  ForEach forEachSubclass(
+      ForEachFunction f,
+      EnumSet<Instantiation> mask,
+      {bool strict: false}) {
+    ForEach forEach;
+    if (!strict && mask.intersects(_mask)) {
+      forEach = f(cls);
+    }
+    // Interpret `forEach == null` as `forEach == ForEach.CONTINUE`.
+    forEach ??= ForEach.CONTINUE;
+
+    if (forEach == ForEach.CONTINUE) {
+      if (mask.contains(Instantiation.UNINSTANTIATED) || isInstantiated) {
+        for (ClassHierarchyNode subclass in _directSubclasses) {
+          ForEach subForEach = subclass.forEachSubclass(f, mask);
+          if (subForEach == ForEach.STOP) {
+            return subForEach;
+          }
+        }
+      }
+    }
+    if (forEach == ForEach.STOP) {
+      return forEach;
+    }
+    return ForEach.CONTINUE;
+  }
+
   /// Returns the most specific subclass of [cls] (including [cls]) that is
   /// directly instantiated or a superclass of all directly instantiated
   /// subclasses. If [cls] is not instantiated, `null` is returned.
@@ -275,7 +338,8 @@
         if (instantiatedOnly && !child.isInstantiated) {
           continue;
         }
-        if (withRespectTo != null && !child.subclasses().any(isRelatedTo)) {
+        if (withRespectTo != null &&
+            !child.anySubclass(isRelatedTo, ClassHierarchyNode.ALL)) {
           continue;
         }
         if (needsComma) {
@@ -367,22 +431,31 @@
 
   ClassElement get cls => node.cls;
 
-  /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
-  ///
-  /// The directly instantiated, indirectly instantiated and uninstantiated
-  /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
-  /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
-  /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
-  Iterable<ClassElement> subclasses(
-      {bool includeDirectlyInstantiated: true,
-       bool includeIndirectlyInstantiated: true,
-       bool includeUninstantiated: true,
-       bool strict: false}) {
-    EnumSet<Instantiation> mask = ClassHierarchyNode.createMask(
-        includeDirectlyInstantiated: includeDirectlyInstantiated,
-        includeIndirectlyInstantiated:includeIndirectlyInstantiated,
-        includeUninstantiated: includeUninstantiated);
-    return subclassesByMask(mask, strict: strict);
+  /// Returns the number of directly instantiated subtypes of [cls].
+  int get instantiatedSubtypeCount {
+    int count = node.instantiatedSubclassCount;
+    if (_directSubtypes != null) {
+      for (ClassHierarchyNode subtypeNode in _directSubtypes) {
+        if (subtypeNode.isDirectlyInstantiated) {
+          count++;
+        }
+        count += subtypeNode.instantiatedSubclassCount;
+      }
+    }
+    return count;
+  }
+
+  /// Returns `true` if all instantiated subtypes of [cls] are subclasses of
+  /// [cls].
+  bool get hasOnlyInstantiatedSubclasses {
+    if (_directSubtypes != null) {
+      for (ClassHierarchyNode subtypeNode in _directSubtypes) {
+        if (subtypeNode.isInstantiated) {
+          return false;
+        }
+      }
+    }
+    return true;
   }
 
   /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
@@ -414,7 +487,6 @@
     return subtypesByMask(mask, strict: strict);
   }
 
-
   /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls].
   ///
   /// Subtypes are included if their instantiation properties intersect with
@@ -434,6 +506,91 @@
         includeRoot: !strict);
   }
 
+  /// Applies [predicate] to each subclass of [cls] matching the criteria
+  /// specified by [mask] and [strict]. If [predicate] returns `true` on a
+  /// class, visitation is stopped immediately and the function returns `true`.
+  ///
+  /// [predicate] is applied to subclasses if their instantiation properties
+  /// intersect with their corresponding [Instantiation] values in [mask]. If
+  /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
+  bool anySubclass(
+      bool predicate(ClassElement cls),
+      EnumSet<Instantiation> mask,
+      {bool strict: false}) {
+    return node.anySubclass(predicate, mask, strict: strict);
+  }
+
+  /// Applies [f] to each subclass of [cls] matching the criteria specified by
+  /// [mask] and [strict].
+  ///
+  /// [f] is a applied to subclasses if their instantiation properties intersect
+  /// with their corresponding [Instantiation] values in [mask]. If [strict] is
+  /// `true`, [f] is _not_ called on [cls] itself.
+  ///
+  /// The visitation of subclasses can be cut short by the return value of [f].
+  /// If [ForEach.STOP] is returned, no further classes are visited and the
+  /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
+  /// subclasses of the last visited class are skipped, but visitation
+  /// continues. The return value of the function is either [ForEach.STOP], if
+  /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
+  /// the end.
+  ForEach forEachSubclass(
+      ForEachFunction f,
+      EnumSet<Instantiation> mask,
+      {bool strict: false}) {
+    return node.forEachSubclass(f, mask, strict: strict);
+  }
+
+  /// Applies [predicate] to each subtype of [cls] matching the criteria
+  /// specified by [mask] and [strict]. If [predicate] returns `true` on a
+  /// class, visitation is stopped immediately and the function returns `true`.
+  ///
+  /// [predicate] is applied to subtypes if their instantiation properties
+  /// intersect with their corresponding [Instantiation] values in [mask]. If
+  /// [strict] is `true`, [predicate] is _not_ called on [cls] itself.
+  bool anySubtype(
+      bool predicate(ClassElement cls),
+      EnumSet<Instantiation> mask,
+      {bool strict: false}) {
+
+    ForEach wrapper(ClassElement cls) {
+      return predicate(cls) ? ForEach.STOP : ForEach.CONTINUE;
+    }
+    return forEachSubtype(wrapper, mask, strict: strict) == ForEach.STOP;
+  }
+
+  /// Applies [f] to each subtype of [cls] matching the criteria specified by
+  /// [mask] and [strict].
+  ///
+  /// [f] is a applied to subtypes if their instantiation properties intersect
+  /// with their corresponding [Instantiation] values in [mask]. If [strict] is
+  /// `true`, [f] is _not_ called on [cls] itself.
+  ///
+  /// The visitation of subtypes can be cut short by the return value of [f].
+  /// If [ForEach.STOP] is returned, no further classes are visited and the
+  /// function stops immediately. If [ForEach.SKIP_SUBCLASSES] is returned, the
+  /// subclasses of the last visited class are skipped, but visitation
+  /// continues. The return value of the function is either [ForEach.STOP], if
+  /// visitation was stopped, or [ForEach.CONTINUE] if visitation continued to
+  /// the end.
+  ForEach forEachSubtype(
+      ForEachFunction f,
+      EnumSet<Instantiation> mask,
+      {bool strict: false}) {
+    ForEach forEach = node.forEachSubclass(f, mask, strict: strict);
+    forEach ??= ForEach.CONTINUE;
+    if (forEach == ForEach.CONTINUE && _directSubtypes != null) {
+      for (ClassHierarchyNode subclass in _directSubtypes) {
+        ForEach subForEach = subclass.forEachSubclass(f, mask);
+        if (subForEach == ForEach.STOP) {
+          return subForEach;
+        }
+      }
+    }
+    assert(forEach != ForEach.SKIP_SUBCLASSES);
+    return forEach;
+  }
+
   /// Adds [subtype] as a subtype of [cls].
   void addSubtype(ClassHierarchyNode subtype) {
     if (node.contains(subtype.cls)) {
@@ -695,3 +852,20 @@
     return false;
   }
 }
+
+/// Enum values returned from the [ForEachFunction] provided to the `forEachX`
+/// functions of [ClassHierarchyNode] and [ClassSet]. The value is used to
+/// control the continued iteration.
+enum ForEach {
+  /// Iteration continues.
+  CONTINUE,
+  /// Iteration stops immediately.
+  STOP,
+  /// Iteration skips the subclasses of the current class.
+  SKIP_SUBCLASSES,
+}
+
+/// Visiting function used for the `forEachX` functions of [ClassHierarchyNode]
+/// and [ClassSet]. The return value controls the continued iteration. If `null`
+/// is returned, iteration continues to the end.
+typedef ForEach ForEachFunction(ClassElement cls);
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index 30b2081..da08fb6 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -93,6 +93,18 @@
   /// including [cls] itself.
   Iterable<ClassElement> strictSubclassesOf(ClassElement cls);
 
+  /// Returns the number of live classes that extend [cls] _not_
+  /// including [cls] itself.
+  int strictSubclassCount(ClassElement cls);
+
+  /// Applies [f] to each live class that extend [cls] _not_ including [cls]
+  /// itself.
+  void forEachStrictSubclassOf(ClassElement cls, ForEach f(ClassElement cls));
+
+  /// Returns `true` if [predicate] applies to any live class that extend [cls]
+  /// _not_ including [cls] itself.
+  bool anyStrictSubclassOf(ClassElement cls, bool predicate(ClassElement cls));
+
   /// Returns an iterable over the directly instantiated that implement [cls]
   /// possibly including [cls] itself, if it is live.
   Iterable<ClassElement> subtypesOf(ClassElement cls);
@@ -101,6 +113,18 @@
   /// including [cls] if it is live.
   Iterable<ClassElement> strictSubtypesOf(ClassElement cls);
 
+  /// Returns the number of live classes that implement [cls] _not_
+  /// including [cls] itself.
+  int strictSubtypeCount(ClassElement cls);
+
+  /// Applies [f] to each live class that implements [cls] _not_ including [cls]
+  /// itself.
+  void forEachStrictSubtypeOf(ClassElement cls, ForEach f(ClassElement cls));
+
+  /// Returns `true` if [predicate] applies to any live class that implements
+  /// [cls] _not_ including [cls] itself.
+  bool anyStrictSubtypeOf(ClassElement cls, bool predicate(ClassElement cls));
+
   /// Returns `true` if [a] and [b] have any known common subtypes.
   bool haveAnyCommonSubtypes(ClassElement a, ClassElement b);
 
@@ -248,6 +272,36 @@
         ClassHierarchyNode.DIRECTLY_INSTANTIATED, strict: true);
   }
 
+  /// Returns the number of live classes that extend [cls] _not_
+  /// including [cls] itself.
+  int strictSubclassCount(ClassElement cls) {
+    ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
+    if (subclasses == null) return 0;
+    return subclasses.instantiatedSubclassCount;
+  }
+
+  /// Applies [f] to each live class that extend [cls] _not_ including [cls]
+  /// itself.
+  void forEachStrictSubclassOf(ClassElement cls, ForEach f(ClassElement cls)) {
+    ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
+    if (subclasses == null) return;
+    subclasses.forEachSubclass(
+        f,
+        ClassHierarchyNode.DIRECTLY_INSTANTIATED,
+        strict: true);
+  }
+
+  /// Returns `true` if [predicate] applies to any live class that extend [cls]
+  /// _not_ including [cls] itself.
+  bool anyStrictSubclassOf(ClassElement cls, bool predicate(ClassElement cls)) {
+    ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration];
+    if (subclasses == null) return false;
+    return subclasses.anySubclass(
+        predicate,
+        ClassHierarchyNode.DIRECTLY_INSTANTIATED,
+        strict: true);
+  }
+
   /// Returns an iterable over the directly instantiated that implement [cls]
   /// possibly including [cls] itself, if it is live.
   Iterable<ClassElement> subtypesOf(ClassElement cls) {
@@ -272,6 +326,36 @@
     }
   }
 
+  /// Returns the number of live classes that implement [cls] _not_
+  /// including [cls] itself.
+  int strictSubtypeCount(ClassElement cls) {
+    ClassSet classSet = _classSets[cls.declaration];
+    if (classSet == null) return 0;
+    return classSet.instantiatedSubtypeCount;
+  }
+
+  /// Applies [f] to each live class that implements [cls] _not_ including [cls]
+  /// itself.
+  void forEachStrictSubtypeOf(ClassElement cls, ForEach f(ClassElement cls)) {
+    ClassSet classSet = _classSets[cls.declaration];
+    if (classSet == null) return;
+    classSet.forEachSubtype(
+        f,
+        ClassHierarchyNode.DIRECTLY_INSTANTIATED,
+        strict: true);
+  }
+
+  /// Returns `true` if [predicate] applies to any live class that extend [cls]
+  /// _not_ including [cls] itself.
+  bool anyStrictSubtypeOf(ClassElement cls, bool predicate(ClassElement cls)) {
+    ClassSet classSet = _classSets[cls.declaration];
+    if (classSet == null) return false;
+    return classSet.anySubtype(
+        predicate,
+        ClassHierarchyNode.DIRECTLY_INSTANTIATED,
+        strict: true);
+  }
+
   /// Returns `true` if [a] and [b] have any known common subtypes.
   bool haveAnyCommonSubtypes(ClassElement a, ClassElement b) {
     ClassSet classSetA = _classSets[a.declaration];
@@ -298,7 +382,7 @@
   /// Returns `true` if any directly instantiated class other than [cls]
   /// implements [cls].
   bool hasAnyStrictSubtype(ClassElement cls) {
-    return !strictSubtypesOf(cls).isEmpty;
+    return strictSubtypeCount(cls) > 0;
   }
 
   /// Returns `true` if all directly instantiated classes that implement [cls]
@@ -306,10 +390,12 @@
   bool hasOnlySubclasses(ClassElement cls) {
     // TODO(johnniwinther): move this to ClassSet?
     if (cls == objectClass) return true;
-    Iterable<ClassElement> subtypes = strictSubtypesOf(cls);
-    if (subtypes == null) return true;
-    Iterable<ClassElement> subclasses = strictSubclassesOf(cls);
-    return subclasses != null && (subclasses.length == subtypes.length);
+    ClassSet classSet = _classSets[cls.declaration];
+    if (classSet == null) {
+      // Vacuously true.
+      return true;
+    }
+    return classSet.hasOnlyInstantiatedSubclasses;
   }
 
   @override
@@ -501,11 +587,11 @@
   ClassHierarchyNode _ensureClassHierarchyNode(ClassElement cls) {
     cls = cls.declaration;
     return _classHierarchyNodes.putIfAbsent(cls, () {
-      ClassHierarchyNode node = new ClassHierarchyNode(cls);
+      ClassHierarchyNode parentNode;
       if (cls.superclass != null) {
-        _ensureClassHierarchyNode(cls.superclass).addDirectSubclass(node);
+        parentNode = _ensureClassHierarchyNode(cls.superclass);
       }
-      return node;
+      return new ClassHierarchyNode(parentNode, cls);
     });
   }
 
@@ -534,31 +620,28 @@
     });
   }
 
-  void _updateClassHierarchyNodeForClass(
-      ClassElement cls,
-      {bool directlyInstantiated: false,
-       bool indirectlyInstantiated: false}) {
-    ClassHierarchyNode node = getClassHierarchyNode(cls);
-    bool changed = false;
-    if (directlyInstantiated && !node.isDirectlyInstantiated) {
-      node.isDirectlyInstantiated = true;
-      changed = true;
-    }
-    if (indirectlyInstantiated && !node.isIndirectlyInstantiated) {
-      node.isIndirectlyInstantiated = true;
-      changed = true;
-    }
-    if (changed && cls.superclass != null) {
-      _updateClassHierarchyNodeForClass(
-          cls.superclass, indirectlyInstantiated: true);
-    }
+  void _updateSuperClassHierarchyNodeForClass(ClassHierarchyNode node) {
     // Ensure that classes implicitly implementing `Function` are in its
     // subtype set.
+    ClassElement cls = node.cls;
     if (cls != coreClasses.functionClass &&
-        cls.implementsFunction(compiler)) {
+        cls.implementsFunction(coreClasses)) {
       ClassSet subtypeSet = _ensureClassSet(coreClasses.functionClass);
       subtypeSet.addSubtype(node);
     }
+    if (!node.isInstantiated && node.parentNode != null) {
+      _updateSuperClassHierarchyNodeForClass(node.parentNode);
+    }
+  }
+
+  void _updateClassHierarchyNodeForClass(
+      ClassElement cls,
+      {bool directlyInstantiated: false}) {
+    ClassHierarchyNode node = getClassHierarchyNode(cls);
+    _updateSuperClassHierarchyNodeForClass(node);
+    if (directlyInstantiated) {
+      node.isDirectlyInstantiated = true;
+    }
   }
 
   void populate() {
diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml
index 3b7e3ea..922f69a 100644
--- a/pkg/compiler/pubspec.yaml
+++ b/pkg/compiler/pubspec.yaml
@@ -13,12 +13,9 @@
     path: ../../sdk/lib/_internal/js_runtime
   sdk_library_metadata:
     path: ../../sdk/lib/_internal/sdk_library_metadata
-  dart2js_info:
-    path: ../../../../dart2js_info
+  dart2js_info: ^0.2.4
   lookup_map:
     path: ../lookup_map
-  dart_messages:
-    path: ../dart_messages
 
 # Uncomment if running gclient, so you can depend directly on the downloaded
 # versions of dart2js's transitive dependencies:
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/dart_messages/bin/json_converter.dart b/pkg/dart_messages/bin/json_converter.dart
deleted file mode 100644
index 8d9b8ca..0000000
--- a/pkg/dart_messages/bin/json_converter.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:convert';
-import 'dart:io';
-
-import '../lib/shared_messages.dart' as shared_messages;
-
-/// Translates the shared messages in `../lib/shared_messages` to JSON and
-/// emits it into `../lib/shared_messages.json`.
-void main() {
-  var input = shared_messages.MESSAGES;
-  var outPath =
-      Platform.script.resolve('../lib/shared_messages.json').toFilePath();
-  print("Input: ${input.length} entries");
-  print("Output: $outPath");
-  new File(outPath).writeAsStringSync(JSON.encode(shared_messages.MESSAGES));
-  print("Done");
-}
diff --git a/pkg/dart_messages/bin/message_id.dart b/pkg/dart_messages/bin/message_id.dart
index 2d7ed53..7d59fbd 100644
--- a/pkg/dart_messages/bin/message_id.dart
+++ b/pkg/dart_messages/bin/message_id.dart
@@ -23,13 +23,13 @@
 /// Computes a random message ID that hasn't been used before.
 void main() {
   var usedIds =
-      shared_messages.MESSAGES.values.map((entry) => entry['id']).toSet();
+      shared_messages.MESSAGES.values.map((entry) => entry.id).toSet();
 
   print("${usedIds.length} existing ids");
 
   var newId;
   do {
     newId = computeId();
-  } while (!usedIds.contains(newId));
+  } while (usedIds.contains(newId));
   print("Available id: $newId");
 }
diff --git a/pkg/dart_messages/bin/publish.dart b/pkg/dart_messages/bin/publish.dart
new file mode 100644
index 0000000..d6e3f87
--- /dev/null
+++ b/pkg/dart_messages/bin/publish.dart
@@ -0,0 +1,233 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:convert';
+import 'dart:io' as io;
+
+import '../lib/shared_messages.dart';
+
+const String jsonPath = '../lib/generated/shared_messages.json';
+const String dart2jsPath =
+    '../../compiler/lib/src/diagnostics/generated/shared_messages.dart';
+const String analyzerPath =
+    '../../analyzer/lib/src/generated/generated/shared_messages.dart';
+
+final String dontEditWarning = """
+/*
+DON'T EDIT. GENERATED. DON'T EDIT.
+This file has been generated by 'publish.dart' in the dart_messages package.
+
+Messages are maintained in `lib/shared_messages.dart` of that same package.
+After any change to that file, run `bin/publish.dart` to generate a new version
+of the json, dart2js and analyzer representations.
+*/""";
+
+const String copyrightHeader = '''
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.''';
+
+void markAsReadonly(String path) {
+  // TODO(15078): mark as read-only. Currently not possible:
+  // http://dartbug.com/15078.
+}
+
+void emitJson() {
+  var input = MESSAGES;
+  var outPath = io.Platform.script.resolve(jsonPath).toFilePath();
+  print("Emitting JSON:");
+  print("  Input: ${input.length} entries");
+  print("  Output: $outPath");
+  new io.File(outPath).writeAsStringSync(messagesAsJson);
+  print("Emitting JSON done.");
+}
+
+/// Escapes the given string [str].
+///
+/// The parameter [str] may be `null` in which case the result is "null".
+String escapeString(String str) {
+  return JSON.encode(str);
+}
+
+/// Emits the messages in dart2js format.
+///
+/// The dart2js-format consists of two entities:
+///   1. the `MessageKind` enum, and
+///   2. the MessageKind-to-Template map `TEMPLATES`.
+///
+/// The template is an instance of MessageTemplate:
+///
+///     const MessageTemplate(
+///        this.kind,
+///        this.template,
+///        {this.howToFix,
+///         this.examples,
+///         this.options: const <String>[]});
+///
+/// A sample output thus looks as follows:
+///
+///     enum MessageKind {
+///       EXAMPLE_MESSAGE,
+///     }
+///
+///     const Map<MessageKind, MessageTemplate> {
+///       EXAMPLE_MESSAGE: const MessageTemplate(
+///         EXAMPLE_MESSAGE,
+///         "Don't use #foo with #bar",
+///         howToFix: "Just don't do it",
+///         options: const ['--some-flag']),
+///         examples: const ['''
+///     some example with bad code;'''],
+///     };
+void emitDart2js() {
+  var input = MESSAGES;
+  var outPath = io.Platform.script.resolve(dart2jsPath).toFilePath();
+  print("Emitting dart2js:");
+  print("  Input: ${input.length} entries");
+  print("  Output: $outPath");
+
+  StringBuffer out = new StringBuffer();
+  out.writeln(copyrightHeader);
+  out.writeln(dontEditWarning);
+  out.writeln("import '../messages.dart' show MessageKind, MessageTemplate;");
+  out.writeln();
+  out.writeln("const Map<MessageKind, MessageTemplate> TEMPLATES = "
+      "const <MessageKind, MessageTemplate>{ ");
+  input.forEach((name, message) {
+    if (!message.usedBy.contains(Platform.dart2js)) return;
+
+    out.writeln("  MessageKind.$name: const MessageTemplate(");
+    // TODO(floitsch): include id.
+    out.writeln("    MessageKind.$name,");
+    out.write("    ");
+    out.write(escapeString(message.template));
+    if (message.howToFix != null) {
+      out.write(",\n    howToFix: ${escapeString(message.howToFix)}");
+    }
+    if (message.options != null) {
+      out.write(",\n    options: const [");
+      out.write(message.options.map(escapeString).join(","));
+      out.writeln("]");
+    }
+    if (message.examples != null) {
+      out.writeln(",\n    examples: const [");
+
+      String escapeExampleContent(String content) {
+        if (content.contains("\n") || content.contains('"')) {
+          return 'r"""\n$content"""';
+        } else if (content.contains("\\")) {
+          return 'r"$content"';
+        }
+        return '"$content"';
+      }
+      for (var example in message.examples) {
+        if (example is String) {
+          out.write("      ");
+          out.write(escapeExampleContent(example));
+        } else if (example is Map) {
+          out.writeln("      const {");
+          example.forEach((String fileName, String content) {
+            out.writeln("      '$fileName': ");
+            out.write(escapeExampleContent(content));
+            out.writeln(",");
+          });
+          out.write("      }");
+        }
+        out.writeln(",");
+      }
+      out.writeln("    ]");
+    }
+    out.writeln("  ),  // Generated. Don't edit.");
+  });
+  out.writeln("};");
+
+  new io.File(outPath).writeAsStringSync(out.toString());
+  print("Emitting dart2js done.");
+}
+
+String convertToAnalyzerTemplate(String template, holeOrder) {
+  var holeMap;
+  if (holeOrder != null) {
+    holeMap = {};
+    for (int i = 0; i < holeOrder.length; i++) {
+      holeMap[holeOrder[i]] = i;
+    }
+  }
+  int seenHoles = 0;
+  return template.replaceAllMapped(new RegExp(r"#\w+|#{\w+}"), (Match match) {
+    if (holeMap != null) {
+      String matchedString = match[0];
+      String holeName = matchedString.startsWith("#{")
+          ? matchedString.substring(2, matchedString.length - 1)
+          : matchedString.substring(1);
+      int index = holeMap[holeName];
+      if (index == null) {
+        throw "Couldn't find hole-position for $holeName $holeMap";
+      }
+      return "{$index}";
+    } else {
+      return "{${seenHoles++}}";
+    }
+  });
+}
+
+/// Emits the messages in analyzer format.
+///
+/// Messages are encoded as instances of `ErrorCode` classes where the
+/// corresponding class is given by the `category` field of the Message.
+///
+/// All instances are stored as top-level const variables.
+///
+/// A sample output looks as follows:
+///
+///     const FooCategoryErrorCode EXAMPLE_MESSAGE = const FooCategoryErrorCode(
+///         "EXAMPLE_MESSAGE",
+///         "Don't use {0} with {1}",
+///         "Just don't do it");
+void emitAnalyzer() {
+  var input = MESSAGES;
+  var outPath = io.Platform.script.resolve(analyzerPath).toFilePath();
+  print("Emitting analyzer:");
+  print("  Input: ${input.length} entries");
+  print("  Output: $outPath");
+
+  StringBuffer out = new StringBuffer();
+  out.writeln(copyrightHeader);
+  out.writeln(dontEditWarning);
+  out.writeln("import 'package:analyzer/src/generated/error.dart';");
+  out.writeln("import 'package:analyzer/src/generated/parser.dart' "
+      "show ParserErrorCode;");
+  input.forEach((name, message) {
+    if (!message.usedBy.contains(Platform.analyzer)) return;
+
+    Category category = message.category;
+    String className = category.name + "Code";
+    out.writeln();
+    out.writeln("const $className $name = const $className(");
+    out.writeln("    '$name',");
+
+    String template = message.template;
+    List holeOrder = message.templateHoleOrder;
+    String analyzerTemplate = convertToAnalyzerTemplate(template, holeOrder);
+    out.write("    ");
+    out.write(escapeString(analyzerTemplate));
+    out.write(",\n    ");
+    out.write(escapeString(message.howToFix));
+    out.writeln(");  // Generated. Don't edit.");
+  });
+
+  new io.File(outPath).writeAsStringSync(out.toString());
+  print("Emitting analyzer done.");
+}
+
+/// Translates the shared messages in `../lib/shared_messages.dart` to JSON,
+/// dart2js, and analyzer formats.
+///
+/// Emits the json-output to [jsonPath], the dart2js-output to [dart2jsPath],
+/// and the analyzer-output to [analyzerPath].
+void main() {
+  emitJson();
+  emitDart2js();
+  emitAnalyzer();
+}
diff --git a/pkg/dart_messages/lib/generated/shared_messages.json b/pkg/dart_messages/lib/generated/shared_messages.json
new file mode 100644
index 0000000..a40bc3f
--- /dev/null
+++ b/pkg/dart_messages/lib/generated/shared_messages.json
@@ -0,0 +1,315 @@
+{
+  "exampleMessage": {
+    "id": "use an Id generated by bin/message_id.dart",
+    "subId": 0,
+    "category": "AnalysisOptionsError",
+    "template": "#use #named #arguments",
+    "templateHoleOrder": [
+      "arguments",
+      "named",
+      "use"
+    ],
+    "howToFix": "an explanation on how to fix things",
+    "options": null,
+    "usedBy": [],
+    "examples": [
+      "      Some multiline example;\n      That generates the bug.",
+      {
+        "fileA.dart": "        or a map from file to content.\n        again multiline",
+        "fileB.dart": "        with possibly multiple files.\n        muliline too"
+      }
+    ]
+  },
+  "CONST_CONSTRUCTOR_OR_FACTORY_WITH_BODY": {
+    "id": "LGJGHW",
+    "subId": 0,
+    "category": "ParserError",
+    "template": "Const constructor or factory can't have a body.",
+    "templateHoleOrder": null,
+    "howToFix": "Remove the 'const' keyword or the body.",
+    "options": null,
+    "usedBy": [
+      "Platform.dart2js"
+    ],
+    "examples": [
+      "         class C {\n           const C() {}\n         }\n\n         main() => new C();",
+      "         class C {\n           const factory C() {}\n         }\n\n         main() => new C();"
+    ]
+  },
+  "CONST_CONSTRUCTOR_WITH_BODY": {
+    "id": "LGJGHW",
+    "subId": 1,
+    "category": "ParserError",
+    "template": "Const constructor can't have a body.",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the 'const' keyword or the body.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "         class C {\n           const C() {}\n         }\n\n         main() => new C();"
+    ]
+  },
+  "CONST_FACTORY": {
+    "id": "LGJGHW",
+    "subId": 2,
+    "category": "ParserError",
+    "template": "Only redirecting factory constructors can be declared to be 'const'.",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the 'const' keyword or replacing the body with '=' followed by a valid target.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "         class C {\n           const factory C() {}\n         }\n\n         main() => new C();"
+    ]
+  },
+  "EXTRANEOUS_MODIFIER": {
+    "id": "GRKIQE",
+    "subId": 0,
+    "category": "ParserError",
+    "template": "Can't have modifier '#{modifier}' here.",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing '#{modifier}'.",
+    "options": null,
+    "usedBy": [
+      "Platform.dart2js"
+    ],
+    "examples": [
+      "var String foo; main(){}",
+      "var set foo; main(){}",
+      "var final foo; main(){}",
+      "var var foo; main(){}",
+      "var const foo; main(){}",
+      "var abstract foo; main(){}",
+      "var static foo; main(){}",
+      "var external foo; main(){}",
+      "get var foo; main(){}",
+      "set var foo; main(){}",
+      "final var foo; main(){}",
+      "var var foo; main(){}",
+      "const var foo; main(){}",
+      "abstract var foo; main(){}",
+      "static var foo; main(){}",
+      "external var foo; main(){}"
+    ]
+  },
+  "EXTRANEOUS_MODIFIER_REPLACE": {
+    "id": "GRKIQE",
+    "subId": 1,
+    "category": "ParserError",
+    "template": "Can't have modifier '#{modifier}' here.",
+    "templateHoleOrder": null,
+    "howToFix": "Try replacing modifier '#{modifier}' with 'var', 'final', or a type.",
+    "options": null,
+    "usedBy": [
+      "Platform.dart2js"
+    ],
+    "examples": [
+      "set foo; main(){}",
+      "abstract foo; main(){}",
+      "static foo; main(){}",
+      "external foo; main(){}"
+    ]
+  },
+  "CONST_CLASS": {
+    "id": "GRKIQE",
+    "subId": 2,
+    "category": "ParserError",
+    "template": "Classes can't be declared to be 'const'",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the 'const' keyword or moving to the class' constructor(s).",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "        const class C {}\n\n        main() => new C();\n        "
+    ]
+  },
+  "CONST_METHOD": {
+    "id": "GRKIQE",
+    "subId": 3,
+    "category": "ParserError",
+    "template": "Getters, setters and methods can't be declared to be 'const'",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the 'const' keyword.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "const int foo() => 499; main() {}",
+      "const int get foo => 499; main() {}",
+      "const set foo(v) => 499; main() {}",
+      "class A { const int foo() => 499; } main() { new A(); }",
+      "class A { const int get foo => 499; } main() { new A(); }",
+      "class A { const set foo(v) => 499; } main() { new A(); }"
+    ]
+  },
+  "CONST_ENUM": {
+    "id": "GRKIQE",
+    "subId": 4,
+    "category": "ParserError",
+    "template": "Enums can't be declared to be 'const'",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the 'const' keyword.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "const enum Foo { x } main() {}"
+    ]
+  },
+  "CONST_TYPEDEF": {
+    "id": "GRKIQE",
+    "subId": 5,
+    "category": "ParserError",
+    "template": "Type aliases can't be declared to be 'const'",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the 'const' keyword.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "const typedef void Foo(); main() {}"
+    ]
+  },
+  "CONST_AND_FINAL": {
+    "id": "GRKIQE",
+    "subId": 6,
+    "category": "ParserError",
+    "template": "Members can't be declared to be both 'const' and 'final'",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing either the 'const' or 'final' keyword.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "final const int x = 499; main() {}",
+      "const final int x = 499; main() {}",
+      "class A { static final const int x = 499; } main() {}",
+      "class A { static const final int x = 499; } main() {}"
+    ]
+  },
+  "CONST_AND_VAR": {
+    "id": "GRKIQE",
+    "subId": 7,
+    "category": "ParserError",
+    "template": "Members can't be declared to be both 'const' and 'var'",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing either the 'const' or 'var' keyword.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "var const x = 499; main() {}",
+      "const var x = 499; main() {}",
+      "class A { var const x = 499; } main() {}",
+      "class A { const var x = 499; } main() {}"
+    ]
+  },
+  "CLASS_IN_CLASS": {
+    "id": "DOTHQH",
+    "subId": 0,
+    "category": "ParserError",
+    "template": "Classes can't be declared inside other classes.",
+    "templateHoleOrder": null,
+    "howToFix": "Try moving the class to the top-level.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer"
+    ],
+    "examples": [
+      "class A { class B {} } main() { new A(); }"
+    ]
+  },
+  "CONSTRUCTOR_WITH_RETURN_TYPE": {
+    "id": "VOJBWY",
+    "subId": 0,
+    "category": "ParserError",
+    "template": "Constructors can't have a return type",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the return type.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer",
+      "Platform.dart2js"
+    ],
+    "examples": [
+      "class A { int A() {} } main() { new A(); }"
+    ]
+  },
+  "MISSING_EXPRESSION_IN_THROW": {
+    "id": "FTGGMJ",
+    "subId": 0,
+    "category": "ParserError",
+    "template": "Missing expression after 'throw'.",
+    "templateHoleOrder": null,
+    "howToFix": "Did you mean 'rethrow'?",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer",
+      "Platform.dart2js"
+    ],
+    "examples": [
+      "main() { throw; }",
+      "main() { try { throw 0; } catch(e) { throw; } }"
+    ]
+  },
+  "RETHROW_OUTSIDE_CATCH": {
+    "id": "MWETLC",
+    "subId": 0,
+    "category": "CompileTimeError",
+    "template": "Rethrow must be inside of catch clause",
+    "templateHoleOrder": null,
+    "howToFix": "Try moving the expression into a catch clause, or using a 'throw' expression.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer",
+      "Platform.dart2js"
+    ],
+    "examples": [
+      "main() { rethrow; }"
+    ]
+  },
+  "RETURN_IN_GENERATIVE_CONSTRUCTOR": {
+    "id": "UOTDQH",
+    "subId": 0,
+    "category": "CompileTimeError",
+    "template": "Constructors can't return values.",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the return statement or using a factory constructor.",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer",
+      "Platform.dart2js"
+    ],
+    "examples": [
+      "        class C {\n          C() {\n            return 1;\n          }\n        }\n\n        main() => new C();"
+    ]
+  },
+  "RETURN_IN_GENERATOR": {
+    "id": "JRUTUQ",
+    "subId": 0,
+    "category": "CompileTimeError",
+    "template": "Can't return a value from a generator function (using the '#{modifier}' modifier).",
+    "templateHoleOrder": null,
+    "howToFix": "Try removing the value, replacing 'return' with 'yield' or changing the method body modifier",
+    "options": null,
+    "usedBy": [
+      "Platform.analyzer",
+      "Platform.dart2js"
+    ],
+    "examples": [
+      "        foo() async* { return 0; }\n        main() => foo();\n        ",
+      "        foo() sync* { return 0; }\n        main() => foo();\n        "
+    ]
+  }
+}
\ No newline at end of file
diff --git a/pkg/dart_messages/lib/shared_messages.dart b/pkg/dart_messages/lib/shared_messages.dart
index bd51f58..ece8895 100644
--- a/pkg/dart_messages/lib/shared_messages.dart
+++ b/pkg/dart_messages/lib/shared_messages.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 // An update to this file must be followed by regenerating the corresponding
-// json file. Use `json_converter.dart` in the bin directory.
+// json, dart2js and analyzer file. Use `publish.dart` in the bin directory.
 //
 // Every message in this file must have an id. Use `message_id.dart` in the
 // bin directory to generate a fresh one.
@@ -58,5 +58,429 @@
 // 1. what is wrong, 2. why is it wrong, 3. how do I fix it. However, we
 // combine the first two in [template] and the last in [howToFix].
 
-final Map<String, Map> MESSAGES = {
+import 'dart:convert';
+
+/// Encodes the category of the message.
+///
+/// This is currently only used in the analyzer.
+// TODO(floitsch): encode severity and type in the category, so we can generate
+// the corresponding ErrorCode subclasses.
+class Category {
+  static final analysisOptionsError = new Category("AnalysisOptionsError");
+
+  static final analysisOptionsWarning = new Category("AnalysisOptionsWarning");
+
+  static final checkedModeCompileTimeError =
+      new Category("CheckedModeCompileTimeError");
+
+  static final parserError = new Category("ParserError");
+
+  static final compileTimeError = new Category("CompileTimeError");
+
+  final String name;
+
+  Category(this.name);
+}
+
+enum Platform { dart2js, analyzer, }
+const dart2js = Platform.dart2js;
+const analyzer = Platform.analyzer;
+
+class Message {
+  /// Generic id for this message.
+  ///
+  /// This id should be shared by all errors that fall into the same category.
+  /// In particular, we want errors of the same category to share the same
+  /// explanation page, and want to disable warnings of the same category
+  /// with just one line.
+  final String id;
+
+  /// The sub-id of the error.
+  ///
+  /// This id just needs to be unique within the same [id].
+  final int subId;
+
+  /// The error sub-id of which this message is a specialization.
+  ///
+  /// For example, "Const is not allowed on getters" may be a specialization of
+  /// "The 'const' keyword is not allowed here".
+  ///
+  /// Examples of the specialized message, should trigger for the more generic
+  /// message, when the platform doesn't support the more specialized message.
+  final int specializationOf;
+
+  final Category category;
+  final String template;
+  // The analyzer fills holes positionally (and not named). The following field
+  // overrides the order of the holes.
+  // For example the template "The argument #field in #cls is bad", could have
+  // the order `["cls", "field"]', which means that the analyzer would first
+  // provide the class `cls` and then only `field`.
+  // This list is generally `null`, but when it is provided it must contain all
+  // holes.
+  final List<String> templateHoleOrder;
+  final String howToFix;
+  final List<String> options;
+  final List examples;
+  final List<Platform> usedBy;
+
+  Message(
+      {this.id,
+      this.subId: 0,
+      this.specializationOf: -1,
+      this.category,
+      this.template,
+      this.templateHoleOrder,
+      this.howToFix,
+      this.options,
+      this.usedBy: const [],
+      this.examples});
+}
+
+String get messagesAsJson {
+  var jsonified = {};
+  MESSAGES.forEach((String name, Message message) {
+    jsonified[name] = {
+      'id': message.id,
+      'subId': message.subId,
+      'category': message.category.name,
+      'template': message.template,
+      'templateHoleOrder': message.templateHoleOrder,
+      'howToFix': message.howToFix,
+      'options': message.options,
+      'usedBy': message.usedBy.map((platform) => platform.toString()).toList(),
+      'examples': message.examples,
+    };
+  });
+  return new JsonEncoder.withIndent('  ').convert(jsonified);
+}
+
+final Map<String, Message> MESSAGES = {
+  'exampleMessage': new Message(
+      id: 'use an Id generated by bin/message_id.dart',
+      category: Category.analysisOptionsError,
+      template: "#use #named #arguments",
+      templateHoleOrder: ["arguments", "named", "use"],
+      howToFix: "an explanation on how to fix things",
+      examples: [
+        r'''
+      Some multiline example;
+      That generates the bug.''',
+        {
+          'fileA.dart': '''
+        or a map from file to content.
+        again multiline''',
+          'fileB.dart': '''
+        with possibly multiple files.
+        muliline too'''
+        }
+      ]),
+
+  // Const constructors (factory or not) may not have a body.
+  'CONST_CONSTRUCTOR_OR_FACTORY_WITH_BODY': new Message(
+      id: 'LGJGHW',
+      subId: 0,
+      category: Category.parserError,
+      template: "Const constructor or factory can't have a body.",
+      howToFix: "Remove the 'const' keyword or the body.",
+      usedBy: [
+        dart2js
+      ],
+      examples: const [
+        r"""
+         class C {
+           const C() {}
+         }
+
+         main() => new C();""",
+        r"""
+         class C {
+           const factory C() {}
+         }
+
+         main() => new C();"""
+      ]),
+  // Const constructors may not have a body.
+  'CONST_CONSTRUCTOR_WITH_BODY': new Message(
+      id: 'LGJGHW',
+      subId: 1,
+      specializationOf: 0,
+      category: Category.parserError,
+      template: "Const constructor can't have a body.",
+      howToFix: "Try removing the 'const' keyword or the body.",
+      usedBy: [
+        analyzer
+      ],
+      examples: const [
+        r"""
+         class C {
+           const C() {}
+         }
+
+         main() => new C();"""
+      ]),
+  // Const constructor factories may only redirect (and must not have a body).
+  'CONST_FACTORY': new Message(
+      id: 'LGJGHW',
+      subId: 2,
+      specializationOf: 0,
+      category: Category.parserError,
+      template: "Only redirecting factory constructors can be declared to "
+          "be 'const'.",
+      howToFix: "Try removing the 'const' keyword or replacing the body with "
+          "'=' followed by a valid target.",
+      usedBy: [
+        analyzer
+      ],
+      examples: const [
+        r"""
+         class C {
+           const factory C() {}
+         }
+
+         main() => new C();"""
+      ]),
+
+  'EXTRANEOUS_MODIFIER': new Message(
+      id: 'GRKIQE',
+      subId: 0,
+      category: Category.parserError,
+      template: "Can't have modifier '#{modifier}' here.",
+      howToFix: "Try removing '#{modifier}'.",
+      usedBy: [
+        dart2js
+      ],
+      examples: const [
+        "var String foo; main(){}",
+        // "var get foo; main(){}",
+        "var set foo; main(){}",
+        "var final foo; main(){}",
+        "var var foo; main(){}",
+        "var const foo; main(){}",
+        "var abstract foo; main(){}",
+        "var static foo; main(){}",
+        "var external foo; main(){}",
+        "get var foo; main(){}",
+        "set var foo; main(){}",
+        "final var foo; main(){}",
+        "var var foo; main(){}",
+        "const var foo; main(){}",
+        "abstract var foo; main(){}",
+        "static var foo; main(){}",
+        "external var foo; main(){}"
+      ]),
+
+  'EXTRANEOUS_MODIFIER_REPLACE': new Message(
+      id: 'GRKIQE',
+      subId: 1,
+      category: Category.parserError,
+      template: "Can't have modifier '#{modifier}' here.",
+      howToFix: "Try replacing modifier '#{modifier}' with 'var', 'final', "
+          "or a type.",
+      usedBy: [
+        dart2js
+      ],
+      examples: const [
+        // "get foo; main(){}",
+        "set foo; main(){}",
+        "abstract foo; main(){}",
+        "static foo; main(){}",
+        "external foo; main(){}"
+      ]),
+
+  'CONST_CLASS': new Message(
+      id: 'GRKIQE',
+      subId: 2,
+      // The specialization could also be 1, but the example below triggers 0.
+      specializationOf: 0,
+      category: Category.parserError,
+      template: "Classes can't be declared to be 'const'",
+      howToFix: "Try removing the 'const' keyword or moving to the class'"
+          " constructor(s).",
+      usedBy: [
+        analyzer
+      ],
+      examples: const [
+        r"""
+        const class C {}
+
+        main() => new C();
+        """
+      ]),
+
+  'CONST_METHOD': new Message(
+      id: 'GRKIQE',
+      subId: 3,
+      // The specialization could also be 1, but the example below triggers 0.
+      specializationOf: 0,
+      category: Category.parserError,
+      template: "Getters, setters and methods can't be declared to be 'const'",
+      howToFix: "Try removing the 'const' keyword.",
+      usedBy: [
+        analyzer
+      ],
+      examples: const [
+        "const int foo() => 499; main() {}",
+        "const int get foo => 499; main() {}",
+        "const set foo(v) => 499; main() {}",
+        "class A { const int foo() => 499; } main() { new A(); }",
+        "class A { const int get foo => 499; } main() { new A(); }",
+        "class A { const set foo(v) => 499; } main() { new A(); }",
+      ]),
+
+  'CONST_ENUM': new Message(
+      id: 'GRKIQE',
+      subId: 4,
+      // The specialization could also be 1, but the example below triggers 0.
+      specializationOf: 0,
+      category: Category.parserError,
+      template: "Enums can't be declared to be 'const'",
+      howToFix: "Try removing the 'const' keyword.",
+      usedBy: [analyzer],
+      examples: const ["const enum Foo { x } main() {}",]),
+
+  'CONST_TYPEDEF': new Message(
+      id: 'GRKIQE',
+      subId: 5,
+      // The specialization could also be 1, but the example below triggers 0.
+      specializationOf: 0,
+      category: Category.parserError,
+      template: "Type aliases can't be declared to be 'const'",
+      howToFix: "Try removing the 'const' keyword.",
+      usedBy: [analyzer],
+      examples: const ["const typedef void Foo(); main() {}",]),
+
+  'CONST_AND_FINAL': new Message(
+      id: 'GRKIQE',
+      subId: 6,
+      // The specialization could also be 1, but the example below triggers 0.
+      specializationOf: 0,
+      category: Category.parserError,
+      template: "Members can't be declared to be both 'const' and 'final'",
+      howToFix: "Try removing either the 'const' or 'final' keyword.",
+      usedBy: [
+        analyzer
+      ],
+      examples: const [
+        "final const int x = 499; main() {}",
+        "const final int x = 499; main() {}",
+        "class A { static final const int x = 499; } main() {}",
+        "class A { static const final int x = 499; } main() {}",
+      ]),
+
+  'CONST_AND_VAR': new Message(
+      id: 'GRKIQE',
+      subId: 7,
+      // The specialization could also be 1, but the example below triggers 0.
+      specializationOf: 0,
+      category: Category.parserError,
+      template: "Members can't be declared to be both 'const' and 'var'",
+      howToFix: "Try removing either the 'const' or 'var' keyword.",
+      usedBy: [
+        analyzer
+      ],
+      examples: const [
+        "var const x = 499; main() {}",
+        "const var x = 499; main() {}",
+        "class A { var const x = 499; } main() {}",
+        "class A { const var x = 499; } main() {}",
+      ]),
+
+  'CLASS_IN_CLASS': new Message(
+      // Dart2js currently reports this as an EXTRANEOUS_MODIFIER error.
+      // TODO(floitsch): make dart2js use this error instead.
+      id: 'DOTHQH',
+      category: Category.parserError,
+      template: "Classes can't be declared inside other classes.",
+      howToFix: "Try moving the class to the top-level.",
+      usedBy: [analyzer],
+      examples: const ["class A { class B {} } main() { new A(); }",]),
+
+  'CONSTRUCTOR_WITH_RETURN_TYPE': new Message(
+      id: 'VOJBWY',
+      category: Category.parserError,
+      template: "Constructors can't have a return type",
+      howToFix: "Try removing the return type.",
+      usedBy: [analyzer, dart2js],
+      examples: const ["class A { int A() {} } main() { new A(); }",]),
+
+  'MISSING_EXPRESSION_IN_THROW': new Message(
+      id: 'FTGGMJ',
+      subId: 0,
+      category: Category.parserError,
+      template: "Missing expression after 'throw'.",
+      howToFix: "Did you mean 'rethrow'?",
+      usedBy: [
+        analyzer,
+        dart2js
+      ],
+      examples: const [
+        'main() { throw; }',
+        'main() { try { throw 0; } catch(e) { throw; } }'
+      ]),
+
+  /**
+   * 12.8.1 Rethrow: It is a compile-time error if an expression of the form
+   * <i>rethrow;</i> is not enclosed within a on-catch clause.
+   */
+  'RETHROW_OUTSIDE_CATCH': new Message(
+      id: 'MWETLC',
+      category: Category.compileTimeError,
+      template: 'Rethrow must be inside of catch clause',
+      howToFix: "Try moving the expression into a catch clause, or "
+          "using a 'throw' expression.",
+      usedBy: [analyzer, dart2js],
+      examples: const ["main() { rethrow; }"]),
+
+  /**
+   * 13.12 Return: It is a compile-time error if a return statement of the form
+   * <i>return e;</i> appears in a generative constructor.
+   */
+  'RETURN_IN_GENERATIVE_CONSTRUCTOR': new Message(
+      id: 'UOTDQH',
+      category: Category.compileTimeError,
+      template: "Constructors can't return values.",
+      howToFix:
+          "Try removing the return statement or using a factory constructor.",
+      usedBy: [
+        analyzer,
+        dart2js
+      ],
+      examples: const [
+        """
+        class C {
+          C() {
+            return 1;
+          }
+        }
+
+        main() => new C();"""
+      ]),
+
+  /**
+   * 13.12 Return: It is a compile-time error if a return statement of the form
+   * <i>return e;</i> appears in a generator function.
+   */
+  'RETURN_IN_GENERATOR': new Message(
+      id: 'JRUTUQ',
+      subId: 0,
+      category: Category.compileTimeError,
+      template: "Can't return a value from a generator function "
+          "(using the '#{modifier}' modifier).",
+      howToFix: "Try removing the value, replacing 'return' with 'yield' or"
+          " changing the method body modifier",
+      usedBy: [
+        analyzer,
+        dart2js
+      ],
+      examples: const [
+        """
+        foo() async* { return 0; }
+        main() => foo();
+        """,
+        """
+        foo() sync* { return 0; }
+        main() => foo();
+        """
+      ]),
 };
diff --git a/pkg/dart_messages/lib/shared_messages.json b/pkg/dart_messages/lib/shared_messages.json
deleted file mode 100644
index 9e26dfe..0000000
--- a/pkg/dart_messages/lib/shared_messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
\ No newline at end of file
diff --git a/pkg/dart_messages/test/dart_messages_test.dart b/pkg/dart_messages/test/dart_messages_test.dart
index 3983773..b05bc3f 100644
--- a/pkg/dart_messages/test/dart_messages_test.dart
+++ b/pkg/dart_messages/test/dart_messages_test.dart
@@ -2,24 +2,23 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:convert';
-import 'dart:io';
+import 'dart:io' as io;
 
 import '../lib/shared_messages.dart';
 
 void testJsonIsUpdated() {
-  var packageRoot = Platform.packageRoot;
+  var packageRoot = io.Platform.packageRoot;
   if (packageRoot == null || packageRoot == "") {
     throw new UnsupportedError("This test requires a package root.");
   }
-  var jsonUri =
-      Uri.parse(packageRoot).resolve('dart_messages/shared_messages.json');
+  var jsonUri = Uri.parse(packageRoot).resolve(
+      'dart_messages/generated/shared_messages.json');
   var jsonPath = jsonUri.toFilePath();
-  var content = new File(jsonPath).readAsStringSync();
-  if (JSON.encode(MESSAGES) != content) {
+  var content = new io.File(jsonPath).readAsStringSync();
+  if (messagesAsJson != content) {
     print("The content of the Dart messages and the corresponding JSON file");
     print("is not the same.");
-    print("Please run bin/json_converter to update the JSON file.");
+    print("Please run bin/publish.dart to update the JSON file.");
     throw "Content is not the same";
   }
 }
@@ -27,7 +26,7 @@
 void testIdsAreUnique() {
   var usedIds = new Set();
   for (var entry in MESSAGES.values) {
-    var id = entry['id'];
+    var id = "${entry.id}-${entry.subId}";
     if (!usedIds.add(id)) {
       throw "Id appears twice: $id";
     }
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index b6d11aa..94371a0 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -81,6 +81,8 @@
 }
 
 class BaseVisitor<T> implements NodeVisitor<T> {
+  const BaseVisitor();
+
   T visitNode(Node node) {
     node.visitChildren(this);
     return null;
@@ -195,7 +197,9 @@
 
 /// This tag interface has no behaviour but must be implemented by any class
 /// that is to be stored on a [Node] as source information.
-abstract class JavaScriptNodeSourceInformation {}
+abstract class JavaScriptNodeSourceInformation {
+  const JavaScriptNodeSourceInformation();
+}
 
 abstract class Node {
   JavaScriptNodeSourceInformation get sourceInformation => _sourceInformation;
@@ -900,7 +904,7 @@
   }
   NamedFunction _clone() => new NamedFunction(name, function);
 
-  int get precedenceLevel => CALL;
+  int get precedenceLevel => LEFT_HAND_SIDE;
 }
 
 class Fun extends Expression {
@@ -919,7 +923,7 @@
 
   Fun _clone() => new Fun(params, body, asyncModifier: asyncModifier);
 
-  int get precedenceLevel => CALL;
+  int get precedenceLevel => LEFT_HAND_SIDE;
 }
 
 class AsyncModifier {
@@ -965,7 +969,7 @@
 
   PropertyAccess _clone() => new PropertyAccess(receiver, selector);
 
-  int get precedenceLevel => CALL;
+  int get precedenceLevel => LEFT_HAND_SIDE;
 }
 
 /// A [DeferredToken] is a placeholder for some [Expression] that is not known
@@ -1075,7 +1079,7 @@
   LiteralNumber(this.value);
 
   int get precedenceLevel => value.startsWith('-') ? UNARY : PRIMARY;
-  
+
   accept(NodeVisitor visitor) => visitor.visitLiteralNumber(this);
   LiteralNumber _clone() => new LiteralNumber(value);
 }
diff --git a/pkg/js_ast/lib/src/precedence.dart b/pkg/js_ast/lib/src/precedence.dart
index 6d66f1f..222f4a8 100644
--- a/pkg/js_ast/lib/src/precedence.dart
+++ b/pkg/js_ast/lib/src/precedence.dart
@@ -17,9 +17,6 @@
 const ADDITIVE = SHIFT + 1;
 const MULTIPLICATIVE = ADDITIVE + 1;
 const UNARY = MULTIPLICATIVE + 1;
-const LEFT_HAND_SIDE = UNARY + 1;
-// We merge new, call and member expressions.
-// This means that we have to emit parenthesis for 'new's. For example `new X;`
-// should be printed as `new X();`. This simplifies the requirements.
-const CALL = LEFT_HAND_SIDE;
-const PRIMARY = CALL + 1;
+const CALL = UNARY + 1;
+const LEFT_HAND_SIDE = CALL + 1;
+const PRIMARY = LEFT_HAND_SIDE + 1;
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index edd4189..564a467 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -678,7 +678,7 @@
 
   @override
   visitAssignment(Assignment assignment) {
-    visitNestedExpression(assignment.leftHandSide, LEFT_HAND_SIDE,
+    visitNestedExpression(assignment.leftHandSide, CALL,
                           newInForInit: inForInit,
                           newAtStatementBegin: atStatementBegin);
     if (assignment.value != null) {
@@ -719,7 +719,7 @@
   @override
   visitNew(New node) {
     out("new ");
-    visitNestedExpression(node.target, CALL,
+    visitNestedExpression(node.target, LEFT_HAND_SIDE,
                           newInForInit: inForInit, newAtStatementBegin: false);
     out("(");
     visitCommaSeparated(node.arguments, ASSIGNMENT,
@@ -729,7 +729,7 @@
 
   @override
   visitCall(Call call) {
-    visitNestedExpression(call.target, LEFT_HAND_SIDE,
+    visitNestedExpression(call.target, CALL,
                           newInForInit: inForInit,
                           newAtStatementBegin: atStatementBegin);
     out("(");
@@ -872,7 +872,7 @@
 
   @override
   void visitPostfix(Postfix postfix) {
-    visitNestedExpression(postfix.argument, LEFT_HAND_SIDE,
+    visitNestedExpression(postfix.argument, CALL,
                           newInForInit: inForInit,
                           newAtStatementBegin: atStatementBegin);
     out(postfix.op);
diff --git a/pkg/meta/CHANGELOG.md b/pkg/meta/CHANGELOG.md
new file mode 100644
index 0000000..fc3f06e
--- /dev/null
+++ b/pkg/meta/CHANGELOG.md
@@ -0,0 +1,7 @@
+## 0.9.0
+* 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/LICENSE b/pkg/meta/LICENSE
new file mode 100644
index 0000000..82e9b52
--- /dev/null
+++ b/pkg/meta/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2016, the Dart project authors. 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.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may 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 THE COPYRIGHT
+OWNER OR CONTRIBUTORS 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/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
new file mode 100644
index 0000000..c94fd80
--- /dev/null
+++ b/pkg/meta/lib/meta.dart
@@ -0,0 +1,107 @@
+// 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.
+
+/// Constants for use in metadata annotations such as `@protected`.
+///
+/// See also `@deprecated` and `@override` in the `dart:core` library.
+///
+/// Annotations provide semantic information that tools can use to provide a
+/// better user experience. For example, an IDE might not autocomplete the name
+/// of a function that's been marked `@deprecated`, or it might display the
+/// function's name differently.
+///
+/// For information on installing and importing this library, see the
+/// [meta package on pub.dartlang.org] (http://pub.dartlang.org/packages/meta).
+/// For examples of using annotations, see
+/// [Metadata](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#metadata)
+/// in the language tour.
+library meta;
+
+/// 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
+/// * 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/meta/pubspec.yaml b/pkg/meta/pubspec.yaml
new file mode 100644
index 0000000..4b20d9c
--- /dev/null
+++ b/pkg/meta/pubspec.yaml
@@ -0,0 +1,10 @@
+name: meta
+version: 0.9.0
+author: Dart Team <misc@dartlang.org>
+homepage: http://www.dartlang.org
+description: >
+ This library contains the definitions of annotations that provide additional
+ semantic information about the program being annotated. These annotations are
+ intended to be used by tools to provide a better user experience.
+environment:
+  sdk: '>=1.12.0 <2.0.0'
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 8f29f55..f0e031c 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -14,7 +14,7 @@
 # Analyzer2dart is not maintained anymore.
 analyzer2dart/test/*: Skip
 
-[ $compiler == none && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
+[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
 mutation_observer: Skip # Issue 21149
 unittest/*: Skip # Issue 21949
 lookup_map/*: SkipByDesign
@@ -26,6 +26,7 @@
 analysis_server/test/analysis/get_errors_test: Skip # runtime error, Issue 22180
 analysis_server/test/integration/analysis/analysis_options_test: RuntimeError # Issue 24796
 analyzer/test/generated/all_the_rest_test: Fail # Issue 21772
+analyzer_cli/test/driver_test: Fail # Issue 25471
 
 [ $compiler == dart2js ]
 analyzer_cli/test/*: SkipByDesign # Only meant to run on vm
@@ -44,13 +45,18 @@
 analysis_server/test/services/index/store/codec_test: Pass, Slow
 analysis_server/test/socket_server_test: Pass, Slow # Issue 19756, 21628
 analyzer/test/dart/element/element_test: Pass, Slow # Issue 24914
+analyzer/test/dart/ast/ast_test: Pass, Slow # Issue 19756, 21628
+analyzer/test/dart/ast/utilities_test: Pass, Slow # Issue 19756, 21628
+analyzer/test/dart/ast/visitor_test: Pass, Slow # Issue 19756, 21628
 analyzer/test/enum_test: Slow, Pass, Fail # Issue 21323
 analyzer/test/generated/all_the_rest_test: Pass, Slow # Issue 21628
 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: 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
@@ -65,10 +71,15 @@
 analyzer/test/generated/utilities_test: Pass, Slow # Issue 21628
 analyzer/test/src/context/cache_test: Pass, Slow # Issue 21628
 analyzer/test/src/context/context_test: Pass, Timeout # dartbug.com/23658
+analyzer/test/src/dart/ast/utilities_test: Pass, Slow # Issue 24914
 analyzer/test/src/dart/element/element_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/prelinker_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/resynthesize_strong_test: Pass, Slow
 analyzer/test/src/summary/resynthesize_test: Pass, Slow
 analyzer/test/src/summary/summary_sdk_test: Pass, Slow # Issue 24914
-analyzer/test/src/summary/summary_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/summarize_ast_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/summarize_elements_strong_test: Pass, Slow # Issue 24914
+analyzer/test/src/summary/summarize_elements_test: Pass, Slow # Issue 24914
 analyzer/test/src/task/dart_test: Pass, Slow # Issue 21628
 analyzer/test/src/task/dart_work_manager_test: Pass, Slow # Issue 21628
 analyzer/test/src/task/driver_test: Pass, Slow # Issue 21628
@@ -82,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
@@ -152,12 +165,13 @@
 observe/test/unique_message_test: SkipByDesign  # Uses dart:io.
 dart_messages/test/dart_messages_test: Skip  # Uses dart:io.
 
-[ $runtime == vm && ($arch == simarm64 || $arch == simarm || $arch == simarmv5te || $arch == simmips || $arch == armv5te) ]
+[ $runtime == vm && ($arch == simarm64 || $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simmips || $arch == armv6 || $arch == armv5te) ]
 # Timeout. These are not unit tests. They do not run efficiently on our
 # simulator or low-end devices.
 *: Skip
 
 [ $runtime == vm ]
+analyzer/test/file_system/physical_resource_provider_test: Pass, Fail # Issue 25472
 # Skip tests on the VM if the package depends on dart:html
 mutation_observer: Skip
 
@@ -203,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/pkg/typed_mock/README.md b/pkg/typed_mock/README.md
index 2414318..2b24907 100644
--- a/pkg/typed_mock/README.md
+++ b/pkg/typed_mock/README.md
@@ -2,6 +2,213 @@
 
 It is inspired by [Mockito](https://code.google.com/p/mockito/).
 
-The existing "mock" package suffers from using method names as strings,
-which makes it impossible to use code-completion, static validation,
-search and refactoring.
+Features of this package:
+- Code-completion, static validation, search and refactoring all work properly with mocks.
+- Much better error messages for unit testing.
+- Works with concrete and abstract classes.
+- Does not use mirrors.
+- No dependent packages.
+
+Other Mock libraries for Dart:
+- https://pub.dartlang.org/packages/mockito
+- https://pub.dartlang.org/packages/mock (deprecated)
+
+## Tutorial
+
+Let's take the simple case of making sure that a method is called. The first step is to create a mock of the object, as shown below. One nice feature of Dart is that all classes automatically define interfaces, so you don't need to separately define the interface.
+
+```dart
+import 'package:typed_mock/typed_mock.dart';
+
+class Dog {
+  String speak() => "Woof!";
+}
+
+class MockDog extends TypedMock implements Dog {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+```
+
+All of the magic happens because of the noSuchMethod() function. None of the functions for Animal are actually defined because we used `implements` instead of `extends`. Therefore, all calls to this object will end up in `noSuchMethod()`.
+
+#### Verify a function is called
+
+Here's the code to verify that the function is called:
+
+```dart
+
+void main() {
+  final dog = new MockDog();
+  verifyZeroInteractions(dog);
+  dog.speak();
+  verify(dog.speak()).once();
+  verifyNoMoreInteractions(dog);
+}
+```
+
+One of the interesting features of typed_mock is that it internally tracks all calls to each mock object, then tracks which calls have been matched with a verify() call and which not. Therefore, typed_mock is able to detect unexpected calls, even if those calls are made to methods that didn't exist when the test was written. This can be a good incentive to update your tests whenever you change a class.
+
+After creating the `MockAnimal` object, we call `verifyZeroInteractions()` to make sure that the object starts in a clean state. Next we call the `speak()` method, then prove that the speak function was actually called with `verify().once()`.
+
+There are several other functions for verifying calls that can be used instead of `once()`:
+- `atLeastOnce()` Ensure the function was called one or more times.
+- `times(n)` Ensure the function was called exactly `n` times.
+- `atLeast(n)` Ensure the function was called `n` or more times.
+- `atMost(n)` Ensure the function was called no more than `n` times.
+- `any()` Mark the function call as verified if it was called, but don't fail if it wasn't called.
+- `never()` Ensure the function was never called. It's often better to use `verifyNoMoreInteractions()` instead.
+
+#### Configure the mock to return a value
+
+Here's how to return a value from `speak()`:
+
+```dart
+void main() {
+  final dog = new MockDog();
+  when(dog.speak()).thenReturn("woof");
+  final s = dog.speak();
+  print("$s");
+  verify(dog.speak()).once();
+  verifyNoMoreInteractions(dog);
+}
+```
+
+What if `speak()` took the name of an animal as a parameter? When typed_mock tracks a function call, the call tracking is based on the function name and the parameters. For example:
+
+
+```dart
+import 'package:typed_mock/typed_mock.dart';
+
+abstract class Animal {
+  String speak();
+}
+
+class MockAnimal extends TypedMock implements Animal {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+void main() {
+  final animal = new MockAnimal();
+  when(animal.speak("dog")).thenReturn("woof");
+  final s = animal.speak();
+  print("$s");
+  verify(animal.speak("dog")).once();
+}
+```
+
+Note that you can reset the call and verify tracking using `resetInteractions()`. However, there is no way to reset the `when()` calls. Create a new mock instead.
+
+You can define different results based on the value of the parameter. Notice that the calls to `verify()` explicitly states the parameter value:
+
+```dart
+void main() {
+  final animal = new MockAnimal();
+  when(animal.speak("cat")).thenReturn("meow");
+  when(animal.speak("dog")).thenReturn("woof");
+  final s = animal.speak("cat"); // Prints: meow
+  verify(animal.speak("cat")).once();
+  verify(animal.speak("dog")).never();
+}
+```
+
+#### Match any value for a parameter
+
+Sometimes you don't care about the exact value of the parameter. That's when `anyString` is used, along with its siblings `anyInt`, `anyBool` and `anyObject`.
+
+The value `anyString` is a matcher that matches any String value. For example, here's how to use `anyString` in a call to `when()`:
+
+```dart
+void main() {
+  final animal = new MockAnimal();
+  when(animal.speak(anyString)).thenReturn("meow");
+  final s1 = animal.speak("cat");
+  final s2 = animal.speak("dog");
+  print("$s1 $s2"); // Prints: meow meow
+  verify(animal.speak(anyString)).times(2);
+}
+```
+
+You can also use `anyString` in `verify()` calls, even if the `when()` calls use exact values. For example:
+
+```dart
+void main() {
+  final animal = new MockAnimal();
+  when(animal.speak("cat")).thenReturn("meow");
+  when(animal.speak("dog")).thenReturn("woof");
+  var s
+  s = animal.speak("cat");
+  s = animal.speak("cat");
+  s = animal.speak("dog");
+  verify(animal.speak(anyString)).times(3);
+}
+```
+
+You can use `anyString` as the parameter for calculated values:
+```dart
+  when(animal.speak(anyString)).thenInvoke((String s) => 'The $s speaks!');
+```
+
+In addition to `thenReturn()` and `thenInvoke()`, typed_mock supports `thenReturnList()` and `thenThrow()`. See the link at the end of this document for examples.
+
+#### Mocking operator[] and operator[]=
+
+The typed_mock package is able to track set and get access with operators `[]=` and `[]`, respectively. There's nothing special about these operators - they are just functions with non-alphanumeric names that takes two or one parameters. As with other functions, typed_mock tracks both the index and the value as needed. Note the syntax to verify that a particular array element was assigned a particular value. The act of assigning true is tracked separately from the act of assigning false. The syntax is straightforward.
+
+```dart
+import 'package:typed_mock/typed_mock.dart';
+
+abstract class Tracker {
+  operator [](int index);
+  operator []=(int index, bool b);
+}
+
+class MockTracker extends TypedMock implements Tracker {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+void main() {
+  final tracker = new MockTracker();
+  tracker[2] = true;
+  when(tracker[3]).thenReturn(false);
+  when(tracker[4]).thenReturn(true);
+  bool x = tracker[3];
+  bool y = tracker[4];
+  print("$x $y");
+  verify(tracker[1] = true).never();
+  verify(tracker[2] = false).never();
+  verify(tracker[2] = true).once();
+  verify(tracker[3]).once();
+  verify(tracker[4]).once();
+  verify(tracker[5]).never();
+}
+```
+
+#### Passing mocks as closures
+
+Passing a mock as a function parameter may not behave as you expect because a hidden function is called in the mock to get the closure. The solution is to wrap the call in a separate closure. For example, the call to `verifyNoMoreInteractions()` fails because the reference to `dog.speak` caused a hidden function to be called in `MockDog`.
+
+```dart
+void doSomething(String myfunc()) {}
+
+void main() {
+  final dog = new MockDog();
+  doSomething(dog.speak);
+  verifyNoMoreInteractions(dog);
+}
+```
+
+The solution is as follows:
+
+```dart
+void doSomething(String myfunc()) {}
+
+void main() {
+  final dog = new MockDog();
+  doSomething(() => dog.speak());
+  verifyNoMoreInteractions(dog);
+}
+```
+
+## More Information
+
+For additional examples, see the [unit tests](https://github.com/dart-lang/sdk/blob/master/pkg/typed_mock/test/typed_mock_test.dart).
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 94de113..62b69fb 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -50,6 +50,69 @@
     defines += ["NDEBUG"]
   }
 
+  if (is_ios || is_mac) {
+    defines += ["DART_PRECOMPILER"]
+  }
+
+  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",
+    ]
+  }
+}
+
+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",
@@ -115,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 b6d6ac1..02ba3c4 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -10,9 +10,9 @@
 
 resources_sources_gypi =
     exec_script("../../tools/gypi_to_gn.py",
-                [rebase_path("resources_sources.gypi")],
+                [rebase_path("vmservice/vmservice_sources.gypi")],
                 "scope",
-                ["resources_sources.gypi"])
+                ["vmservice/vmservice_sources.gypi"])
 
 # Generate a resources.cc file for the service isolate without Observatory.
 action("gen_resources_cc") {
@@ -21,7 +21,11 @@
   inputs = [
     "../tools/create_resources.py",
   ]
-  sources = resources_sources_gypi.sources
+  # The path below is hard coded for the Mojo and Flutter trees. When moving
+  # the Dart runtime to gn, this path might need to be updated.
+  sources = rebase_path(resources_sources_gypi.sources,
+                        "",
+                        "//dart/runtime/bin/vmservice/")
   outputs = [ "$target_gen_dir/resources_gen.cc" ]
   args = [
     "--output",
@@ -72,17 +76,18 @@
 }
 
 
-iolib_sources_gypi =
+sdk_io_sources_gypi =
     exec_script("../../tools/gypi_to_gn.py",
-                [rebase_path("../../sdk/lib/io/iolib_sources.gypi")],
+                [rebase_path("../../sdk/lib/io/io_sources.gypi")],
                 "scope",
-                ["../../sdk/lib/io/iolib_sources.gypi"])
-iolib_sources = rebase_path(iolib_sources_gypi.sources, ".", "../../sdk/lib/io")
+                ["../../sdk/lib/io/io_sources.gypi"])
+sdk_io_sources =
+    rebase_path(sdk_io_sources_gypi.sources, ".", "../../sdk/lib/io")
 
 gen_library_src_path("generate_io_cc_file") {
   name = "io"
   kind = "source"
-  sources = ["../../sdk/lib/io/io.dart"] + iolib_sources
+  sources = ["../../sdk/lib/io/io.dart"] + sdk_io_sources
   output = "$target_gen_dir/io_gen.cc"
 }
 
@@ -233,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",
@@ -287,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/bin.gypi b/runtime/bin/bin.gypi
index 78c5a58..5d7b48e 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -62,7 +62,7 @@
         '../../sdk/lib/io/io.dart',
       ],
       'includes': [
-        '../../sdk/lib/io/iolib_sources.gypi',
+        '../../sdk/lib/io/io_sources.gypi',
       ],
       'actions': [
         {
@@ -366,6 +366,7 @@
       'defines': [
         'DART_SHARED_LIB',
         'DART_NO_SNAPSHOT',
+        'DART_PRECOMPILER',
       ],
     },
     {
@@ -515,7 +516,7 @@
       'type': 'none',
       'toolsets':['host'],
       'includes': [
-        'resources_sources.gypi',
+        'vmservice/vmservice_sources.gypi',
       ],
       'actions': [
         {
@@ -544,9 +545,12 @@
     {
       'target_name': 'generate_bootstrap_resources_cc_file',
       'type': 'none',
+      'dependencies': [
+        'bin/zlib.gyp:zlib_dart',
+      ],
       'toolsets':['host'],
       'includes': [
-        'resources_sources.gypi',
+        'vmservice/vmservice_sources.gypi',
       ],
       'actions': [
         {
@@ -574,6 +578,40 @@
       ]
     },
     {
+      # dart_product binary.
+      'target_name': 'dart_product',
+      'type': 'executable',
+      'dependencies': [
+        'libdart',
+        'libdart_builtin',
+        'libdart_io',
+      ],
+      'include_dirs': [
+        '..',
+        '../../third_party/', # Zlib
+      ],
+      'defines': [
+        'DART_PRODUCT_BINARY',
+      ],
+      'sources': [
+        'main.cc',
+        'builtin_common.cc',
+        'builtin_natives.cc',
+        'builtin_nolib.cc',
+        'builtin.h',
+        'io_natives.h',
+        'snapshot_empty.cc',
+        'observatory_assets_empty.cc',
+      ],
+      'conditions': [
+        ['OS=="win"', {
+          'link_settings': {
+            'libraries': [ '-lws2_32.lib', '-lRpcrt4.lib', '-lwinmm.lib' ],
+          },
+        }],
+      ],
+    },
+    {
       # dart binary with a snapshot of corelibs built in.
       'target_name': 'dart',
       'type': 'executable',
@@ -628,11 +666,69 @@
       },
     },
     {
-      # dart binary for running precompiled snapshots without the compiler.
-      'target_name': 'dart_precompiled',
+      # dart binary with a snapshot of corelibs built in and support for testing
+      # precompilation (aka --noopt)
+      'target_name': 'dart_noopt',
       'type': 'executable',
       'dependencies': [
-        'libdart_precompiled',
+        'libdart_noopt',
+        'libdart_builtin',
+        'libdart_io',
+        'build_observatory#host',
+        'generate_snapshot_file#host',
+        'generate_resources_cc_file#host',
+        'generate_observatory_assets_cc_file#host',
+      ],
+      'include_dirs': [
+        '..',
+        '../../third_party/', # Zlib
+      ],
+      'sources': [
+        'main.cc',
+        'builtin_common.cc',
+        'builtin_natives.cc',
+        'builtin_nolib.cc',
+        'builtin.h',
+        'io_natives.h',
+        'vmservice_impl.cc',
+        'vmservice_impl.h',
+        '<(snapshot_cc_file)',
+        '<(resources_cc_file)',
+        '<(observatory_assets_cc_file)',
+      ],
+      'defines': [
+        'DART_PRECOMPILER',
+      ],
+      'conditions': [
+        ['OS=="win"', {
+          'link_settings': {
+            'libraries': [ '-lws2_32.lib', '-lRpcrt4.lib', '-lwinmm.lib' ],
+          },
+          # Generate an import library on Windows, by exporting a function.
+          # Extensions use this import library to link to the API in dart.exe.
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'AdditionalOptions': [ '/EXPORT:Dart_True' ],
+            },
+          },
+        }],
+      ],
+      'configurations': {
+        'Dart_Linux_Base': {
+          # Have the linker add all symbols to the dynamic symbol table
+          # so that extensions can look them up dynamically in the binary.
+          'ldflags': [
+            '-rdynamic',
+          ],
+        },
+      },
+    },
+    {
+      # dart binary for running precompiled snapshots without the compiler.
+      'target_name': 'dart_precompiled_runtime',
+      'type': 'executable',
+      'dependencies': [
+        'libdart_precompiled_runtime',
         'libdart_builtin',
         'libdart_io',
         'build_observatory#host',
@@ -656,6 +752,9 @@
         '<(resources_cc_file)',
         '<(observatory_assets_cc_file)',
       ],
+      'defines': [
+        'DART_PRECOMPILED_RUNTIME',
+      ],
       'conditions': [
         ['OS=="win"', {
           'link_settings': {
@@ -760,6 +859,10 @@
         '<(observatory_assets_cc_file)',
         'snapshot_empty.cc',
       ],
+      'defines': [
+        'DART_NO_SNAPSHOT',
+        'DART_PRECOMPILER',
+      ],
       'conditions': [
         ['OS=="win"', {
           'link_settings': {
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index f162bcb..9a34b51 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -123,11 +123,18 @@
 
 // A class wrapping the load error message in an Error object.
 class _LoadError extends Error {
+  final _LoadRequest request;
   final String message;
-  final String uri;
-  _LoadError(this.uri, this.message);
+  _LoadError(this.request, this.message);
 
-  String toString() => 'Load Error for "$uri": $message';
+  String toString() {
+    var context = request._context;
+    if (context == null || context is! String) {
+      return 'Could not load "${request._uri}": $message';
+    } else {
+      return 'Could not import "${request._uri}" from "$context": $message';
+    }
+  }
 }
 
 // Class collecting all of the information about a particular load request.
@@ -372,13 +379,13 @@
       _finishLoadRequest(req);
     } else {
       assert(dataOrError is String);
-      var error = new _LoadError(req._uri, dataOrError.toString());
+      var error = new _LoadError(req, dataOrError.toString());
       _asyncLoadError(req, error, null);
     }
   } catch(e, s) {
     // Wrap inside a _LoadError unless we are already propagating a
     // previous _LoadError.
-    var error = (e is _LoadError) ? e : new _LoadError(req._uri, e.toString());
+    var error = (e is _LoadError) ? e : new _LoadError(req, e.toString());
     assert(req != null);
     _asyncLoadError(req, error, s);
   }
@@ -576,11 +583,12 @@
     if (_traceLoading) {
       _log("Exception when communicating with service isolate: $e");
     }
+    // Register a dummy load request so we can fail to load it.
+    var req = new _LoadRequest(tag, uri, resourceUri, context);
+
     // Wrap inside a _LoadError unless we are already propagating a previously
     // seen _LoadError.
-    var error = (e is _LoadError) ? e : new _LoadError(uri, e.toString());
-    // Register a dummy load request and fail to load it.
-    var req = new _LoadRequest(tag, uri, resourceUri, context);
+    var error = (e is _LoadError) ? e : new _LoadError(req, e.toString());
     _asyncLoadError(req, error, s);
   }
 }
@@ -597,11 +605,12 @@
       if (_traceLoading) {
         _log("Exception ($e) when resolving package URI: $resourceUri");
       }
+      // Register a dummy load request so we can fail to load it.
+      var req = new _LoadRequest(tag, uri, resourceUri, context);
+
       // Wrap inside a _LoadError unless we are already propagating a previously
       // seen _LoadError.
-      var error = (e is _LoadError) ? e : new _LoadError(uri, e.toString());
-      // Register a dummy load request and fail to load it.
-      var req = new _LoadRequest(tag, uri, resourceUri, context);
+      var error = (e is _LoadError) ? e : new _LoadError(req, e.toString());
       _asyncLoadError(req, error, s);
     }
     _loadData(tag, uri, resolvedUri, context);
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 8915011..f592f2c 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -16,7 +16,6 @@
 #include "bin/extensions.h"
 #include "bin/file.h"
 #include "bin/io_buffer.h"
-#include "bin/isolate_data.h"
 #include "bin/platform.h"
 #include "bin/socket.h"
 #include "bin/utils.h"
@@ -305,70 +304,69 @@
 }
 
 
-Dart_Handle DartUtils::SetWorkingDirectory(Dart_Handle builtin_lib) {
+Dart_Handle DartUtils::SetWorkingDirectory() {
+  IsolateData* isolate_data =
+      reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
+  Dart_Handle builtin_lib = isolate_data->builtin_lib();
   Dart_Handle directory = NewString(original_working_directory);
   return SingleArgDart_Invoke(builtin_lib, "_setWorkingDirectory", directory);
 }
 
 
-Dart_Handle DartUtils::ResolveUriInWorkingDirectory(Dart_Handle script_uri,
-                                                    Dart_Handle builtin_lib) {
+Dart_Handle DartUtils::ResolveUriInWorkingDirectory(Dart_Handle script_uri) {
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = script_uri;
-  return Dart_Invoke(builtin_lib,
+  return Dart_Invoke(DartUtils::BuiltinLib(),
                      NewString("_resolveInWorkingDirectory"),
                      kNumArgs,
                      dart_args);
 }
 
 
-Dart_Handle DartUtils::FilePathFromUri(Dart_Handle script_uri,
-                                       Dart_Handle builtin_lib) {
+Dart_Handle DartUtils::FilePathFromUri(Dart_Handle script_uri) {
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = script_uri;
-  return Dart_Invoke(builtin_lib,
+  return Dart_Invoke(DartUtils::BuiltinLib(),
                      NewString("_filePathFromUri"),
                      kNumArgs,
                      dart_args);
 }
 
 
-Dart_Handle DartUtils::ExtensionPathFromUri(Dart_Handle extension_uri,
-                                            Dart_Handle builtin_lib) {
+Dart_Handle DartUtils::ExtensionPathFromUri(Dart_Handle extension_uri) {
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = extension_uri;
-  return Dart_Invoke(builtin_lib,
+  return Dart_Invoke(DartUtils::BuiltinLib(),
                      NewString("_extensionPathFromUri"),
                      kNumArgs,
                      dart_args);
 }
 
 
-Dart_Handle DartUtils::ResolveUri(Dart_Handle library_url,
-                                  Dart_Handle url,
-                                  Dart_Handle builtin_lib) {
+Dart_Handle DartUtils::ResolveUri(Dart_Handle library_url, Dart_Handle url) {
   const int kNumArgs = 2;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = library_url;
   dart_args[1] = url;
-  return Dart_Invoke(
-      builtin_lib, NewString("_resolveUri"), kNumArgs, dart_args);
+  return Dart_Invoke(DartUtils::BuiltinLib(),
+                     NewString("_resolveUri"),
+                     kNumArgs,
+                     dart_args);
 }
 
 
 static Dart_Handle LoadDataAsync_Invoke(Dart_Handle tag,
                                         Dart_Handle url,
-                                        Dart_Handle library_url,
-                                        Dart_Handle builtin_lib) {
+                                        Dart_Handle library_url) {
   const int kNumArgs = 3;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = tag;
   dart_args[1] = url;
   dart_args[2] = library_url;
-  return Dart_Invoke(builtin_lib,
+  return Dart_Invoke(DartUtils::BuiltinLib(),
                      DartUtils::NewString("_loadDataAsync"),
                      kNumArgs,
                      dart_args);
@@ -407,10 +405,7 @@
       return url;
     }
     // Resolve the url within the context of the library's URL.
-    Dart_Handle builtin_lib =
-        Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-    RETURN_IF_ERROR(builtin_lib);
-    return ResolveUri(library_url, url, builtin_lib);
+    return ResolveUri(library_url, url);
   }
 
   // Handle 'import' of dart scheme URIs (i.e they start with 'dart:').
@@ -447,15 +442,12 @@
     }
   }
 
-  Dart_Handle builtin_lib =
-      Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-  RETURN_IF_ERROR(builtin_lib);
   if (DartUtils::IsDartExtensionSchemeURL(url_string)) {
     // Load a native code shared library to use in a native extension
     if (tag != Dart_kImportTag) {
       return NewError("Dart extensions must use import: '%s'", url_string);
     }
-    Dart_Handle path_parts = DartUtils::ExtensionPathFromUri(url, builtin_lib);
+    Dart_Handle path_parts = DartUtils::ExtensionPathFromUri(url);
     if (Dart_IsError(path_parts)) {
       return path_parts;
     }
@@ -474,10 +466,7 @@
 
   // Handle 'import' or 'part' requests for all other URIs. Call dart code to
   // read the source code asynchronously.
-  return LoadDataAsync_Invoke(Dart_NewInteger(tag),
-                              url,
-                              library_url,
-                              builtin_lib);
+  return LoadDataAsync_Invoke(Dart_NewInteger(tag), url, library_url);
 }
 
 
@@ -509,13 +498,12 @@
 }
 
 
-Dart_Handle DartUtils::LoadScript(const char* script_uri,
-                                  Dart_Handle builtin_lib) {
+Dart_Handle DartUtils::LoadScript(const char* script_uri) {
   Dart_Handle uri = Dart_NewStringFromCString(script_uri);
   IsolateData* isolate_data =
       reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
   Dart_TimelineAsyncBegin("LoadScript", &(isolate_data->load_async_id));
-  return LoadDataAsync_Invoke(Dart_Null(), uri, Dart_Null(), builtin_lib);
+  return LoadDataAsync_Invoke(Dart_Null(), uri, Dart_Null());
 }
 
 
@@ -656,9 +644,7 @@
 Dart_Handle DartUtils::PrepareBuiltinLibrary(Dart_Handle builtin_lib,
                                              Dart_Handle internal_lib,
                                              bool is_service_isolate,
-                                             bool trace_loading,
-                                             const char* package_root,
-                                             const char* packages_config) {
+                                             bool trace_loading) {
   // Setup the internal library's 'internalPrint' function.
   Dart_Handle print = Dart_Invoke(
       builtin_lib, NewString("_getPrintClosure"), 0, NULL);
@@ -678,41 +664,7 @@
       RETURN_IF_ERROR(result);
     }
     // Set current working directory.
-    result = SetWorkingDirectory(builtin_lib);
-    RETURN_IF_ERROR(result);
-    // Wait for the service isolate to initialize the load port.
-    Dart_Port load_port = Dart_ServiceWaitForLoadPort();
-    if (load_port == ILLEGAL_PORT) {
-      return Dart_NewUnhandledExceptionError(
-          NewDartUnsupportedError("Service did not return load port."));
-    }
-    result = Builtin::SetLoadPort(load_port);
-    RETURN_IF_ERROR(result);
-  }
-
-  // Set up package root if specified.
-  if (package_root != NULL) {
-    ASSERT(packages_config == NULL);
-    result = NewString(package_root);
-    RETURN_IF_ERROR(result);
-    const int kNumArgs = 1;
-    Dart_Handle dart_args[kNumArgs];
-    dart_args[0] = result;
-    result = Dart_Invoke(builtin_lib,
-                         NewString("_setPackageRoot"),
-                         kNumArgs,
-                         dart_args);
-    RETURN_IF_ERROR(result);
-  } else if (packages_config != NULL) {
-    result = NewString(packages_config);
-    RETURN_IF_ERROR(result);
-    const int kNumArgs = 1;
-    Dart_Handle dart_args[kNumArgs];
-    dart_args[0] = result;
-    result = Dart_Invoke(builtin_lib,
-                         NewString("_loadPackagesMap"),
-                         kNumArgs,
-                         dart_args);
+    result = SetWorkingDirectory();
     RETURN_IF_ERROR(result);
   }
   return Dart_True();
@@ -759,11 +711,50 @@
 }
 
 
-Dart_Handle DartUtils::PrepareForScriptLoading(const char* package_root,
-                                               const char* packages_config,
-                                               bool is_service_isolate,
-                                               bool trace_loading,
-                                               Dart_Handle builtin_lib) {
+Dart_Handle DartUtils::SetupServiceLoadPort() {
+  // Wait for the service isolate to initialize the load port.
+  Dart_Port load_port = Dart_ServiceWaitForLoadPort();
+  if (load_port == ILLEGAL_PORT) {
+    return Dart_NewUnhandledExceptionError(
+        NewDartUnsupportedError("Service did not return load port."));
+  }
+  return Builtin::SetLoadPort(load_port);
+}
+
+
+Dart_Handle DartUtils::SetupPackageRoot(const char* package_root,
+                                        const char* packages_config) {
+  // Set up package root if specified.
+  if (package_root != NULL) {
+    ASSERT(packages_config == NULL);
+    Dart_Handle result = NewString(package_root);
+    RETURN_IF_ERROR(result);
+    const int kNumArgs = 1;
+    Dart_Handle dart_args[kNumArgs];
+    dart_args[0] = result;
+    result = Dart_Invoke(DartUtils::BuiltinLib(),
+                         NewString("_setPackageRoot"),
+                         kNumArgs,
+                         dart_args);
+    RETURN_IF_ERROR(result);
+  } else if (packages_config != NULL) {
+    Dart_Handle result = NewString(packages_config);
+    RETURN_IF_ERROR(result);
+    const int kNumArgs = 1;
+    Dart_Handle dart_args[kNumArgs];
+    dart_args[0] = result;
+    result = Dart_Invoke(DartUtils::BuiltinLib(),
+                         NewString("_loadPackagesMap"),
+                         kNumArgs,
+                         dart_args);
+    RETURN_IF_ERROR(result);
+  }
+  return Dart_True();
+}
+
+
+Dart_Handle DartUtils::PrepareForScriptLoading(bool is_service_isolate,
+                                               bool trace_loading) {
   // First ensure all required libraries are available.
   Dart_Handle url = NewString(kCoreLibURL);
   RETURN_IF_ERROR(url);
@@ -781,9 +772,19 @@
   RETURN_IF_ERROR(url);
   Dart_Handle internal_lib = Dart_LookupLibrary(url);
   RETURN_IF_ERROR(internal_lib);
+  Dart_Handle builtin_lib =
+      Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
+  RETURN_IF_ERROR(builtin_lib);
   Dart_Handle io_lib = Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
   RETURN_IF_ERROR(io_lib);
 
+  // Setup the builtin library in a persistent handle attached the isolate
+  // specific data as we seem to lookup and use builtin lib a lot.
+  IsolateData* isolate_data =
+      reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
+  ASSERT(isolate_data != NULL);
+  isolate_data->set_builtin_lib(builtin_lib);
+
   // We need to ensure that all the scripts loaded so far are finalized
   // as we are about to invoke some Dart code below to setup closures.
   Dart_Handle result = Dart_FinalizeLoading(false);
@@ -792,9 +793,7 @@
   result = PrepareBuiltinLibrary(builtin_lib,
                                  internal_lib,
                                  is_service_isolate,
-                                 trace_loading,
-                                 package_root,
-                                 packages_config);
+                                 trace_loading);
   RETURN_IF_ERROR(result);
 
   RETURN_IF_ERROR(PrepareAsyncLibrary(async_lib, isolate_lib));
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 68ad7ed..1d18b5f9 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -11,6 +11,8 @@
 #include "platform/assert.h"
 #include "platform/globals.h"
 
+#include "bin/isolate_data.h"
+
 namespace dart {
 namespace bin {
 
@@ -27,7 +29,9 @@
  * API functions return any error handles passed in as arguments, unchanged.
  */
 static inline Dart_Handle ThrowIfError(Dart_Handle handle) {
-  if (Dart_IsError(handle)) Dart_PropagateError(handle);
+  if (Dart_IsError(handle)) {
+    Dart_PropagateError(handle);
+  }
   return handle;
 }
 
@@ -123,26 +127,12 @@
   static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
                                        Dart_Handle library,
                                        Dart_Handle url);
-  static Dart_Handle LoadScript(const char* script_uri,
-                                Dart_Handle builtin_lib);
-  static Dart_Handle PrepareBuiltinLibrary(Dart_Handle builtin_lib,
-                                           Dart_Handle internal_lib,
-                                           bool is_service_isolate,
-                                           bool trace_loading,
-                                           const char* package_root,
-                                           const char* packages_file);
-  static Dart_Handle PrepareCoreLibrary(Dart_Handle core_lib,
-                                 Dart_Handle builtin_lib,
-                                 bool is_service_isolate);
-  static Dart_Handle PrepareAsyncLibrary(Dart_Handle async_lib,
-                                  Dart_Handle isolate_lib);
-  static Dart_Handle PrepareIOLibrary(Dart_Handle io_lib);
-  static Dart_Handle PrepareIsolateLibrary(Dart_Handle isolate_lib);
-  static Dart_Handle PrepareForScriptLoading(const char* package_root,
-                                             const char* packages_file,
-                                             bool is_service_isolate,
-                                             bool trace_loading,
-                                             Dart_Handle builtin_lib);
+  static Dart_Handle LoadScript(const char* script_uri);
+  static Dart_Handle PrepareForScriptLoading(bool is_service_isolate,
+                                             bool trace_loading);
+  static Dart_Handle SetupServiceLoadPort();
+  static Dart_Handle SetupPackageRoot(const char* package_root,
+                                      const char* packages_file);
   static Dart_Handle SetupIOLibrary(const char* script_uri);
 
   static bool PostNull(Dart_Port port_id);
@@ -179,25 +169,20 @@
   static Dart_Handle NewError(const char* format, ...);
   static Dart_Handle NewInternalError(const char* message);
 
+  static Dart_Handle BuiltinLib() {
+    IsolateData* isolate_data =
+        reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
+    return isolate_data->builtin_lib();
+  }
+
   static bool SetOriginalWorkingDirectory();
 
   static const char* MapLibraryUrl(CommandLineOptions* url_mapping,
                                    const char* url_string);
 
-  static Dart_Handle SetWorkingDirectory(Dart_Handle builtin_lib);
-
-  static Dart_Handle ResolveUriInWorkingDirectory(Dart_Handle script_uri,
-                                                  Dart_Handle builtin_lib);
-
-  static Dart_Handle FilePathFromUri(Dart_Handle script_uri,
-                                     Dart_Handle builtin_lib);
-
-  static Dart_Handle ExtensionPathFromUri(Dart_Handle extension_uri,
-                                          Dart_Handle builtin_lib);
-
-  static Dart_Handle ResolveUri(Dart_Handle library_url,
-                                Dart_Handle url,
-                                Dart_Handle builtin_lib);
+  static Dart_Handle ResolveUriInWorkingDirectory(Dart_Handle script_uri);
+  static Dart_Handle FilePathFromUri(Dart_Handle script_uri);
+  static Dart_Handle ResolveUri(Dart_Handle library_url, Dart_Handle url);
 
   // Sniffs the specified text_buffer to see if it contains the magic number
   // representing a script snapshot. If the text_buffer is a script snapshot
@@ -230,6 +215,21 @@
   static const uint8_t magic_number[];
 
  private:
+  static Dart_Handle SetWorkingDirectory();
+  static Dart_Handle ExtensionPathFromUri(Dart_Handle extension_uri);
+
+  static Dart_Handle PrepareBuiltinLibrary(Dart_Handle builtin_lib,
+                                           Dart_Handle internal_lib,
+                                           bool is_service_isolate,
+                                           bool trace_loading);
+  static Dart_Handle PrepareCoreLibrary(Dart_Handle core_lib,
+                                 Dart_Handle builtin_lib,
+                                 bool is_service_isolate);
+  static Dart_Handle PrepareAsyncLibrary(Dart_Handle async_lib,
+                                  Dart_Handle isolate_lib);
+  static Dart_Handle PrepareIOLibrary(Dart_Handle io_lib);
+  static Dart_Handle PrepareIsolateLibrary(Dart_Handle isolate_lib);
+
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(DartUtils);
 };
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index fa48b0e..a28b01c 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -18,9 +18,7 @@
     Dart_SetReturnValue(args, DartUtils::NewString(current));
     free(current);
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -37,9 +35,7 @@
     if (Directory::SetCurrent(DartUtils::GetStringValue(path))) {
       Dart_SetReturnValue(args, Dart_True());
     } else {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     }
   }
 }
@@ -56,9 +52,7 @@
   } else if (result == Directory::DOES_NOT_EXIST) {
     Dart_SetReturnValue(args, Dart_NewInteger(kDoesNotExist));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -68,9 +62,7 @@
   if (Directory::Create(DartUtils::GetStringValue(path))) {
     Dart_SetReturnValue(args, Dart_True());
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -95,9 +87,7 @@
     Dart_SetReturnValue(args, DartUtils::NewString(result));
     free(result);
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -109,9 +99,7 @@
                         DartUtils::GetBooleanValue(recursive))) {
     Dart_SetReturnValue(args, Dart_True());
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -123,9 +111,7 @@
                         DartUtils::GetStringValue(newPath))) {
     Dart_SetReturnValue(args, Dart_True());
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
diff --git a/runtime/bin/extensions_android.cc b/runtime/bin/extensions_android.cc
index 0c79bff..e33c195 100644
--- a/runtime/bin/extensions_android.cc
+++ b/runtime/bin/extensions_android.cc
@@ -13,7 +13,8 @@
 namespace bin {
 
 const char* kPrecompiledLibraryName = "libprecompiled.so";
-const char* kPrecompiledSymbolName = "_kInstructionsSnapshot";
+const char* kPrecompiledInstructionsSymbolName = "_kInstructionsSnapshot";
+const char* kPrecompiledDataSymbolName = "_kDataSnapshot";
 
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
   return dlopen(library_file, RTLD_LAZY);
diff --git a/runtime/bin/extensions_linux.cc b/runtime/bin/extensions_linux.cc
index e172f0d..54a88a4 100644
--- a/runtime/bin/extensions_linux.cc
+++ b/runtime/bin/extensions_linux.cc
@@ -13,7 +13,8 @@
 namespace bin {
 
 const char* kPrecompiledLibraryName = "libprecompiled.so";
-const char* kPrecompiledSymbolName = "_kInstructionsSnapshot";
+const char* kPrecompiledInstructionsSymbolName = "_kInstructionsSnapshot";
+const char* kPrecompiledDataSymbolName = "_kDataSnapshot";
 
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
   return dlopen(library_file, RTLD_LAZY);
diff --git a/runtime/bin/extensions_macos.cc b/runtime/bin/extensions_macos.cc
index e248a47..0edb6b5 100644
--- a/runtime/bin/extensions_macos.cc
+++ b/runtime/bin/extensions_macos.cc
@@ -13,7 +13,8 @@
 namespace bin {
 
 const char* kPrecompiledLibraryName = "libprecompiled.dylib";
-const char* kPrecompiledSymbolName = "kInstructionsSnapshot";
+const char* kPrecompiledInstructionsSymbolName = "kInstructionsSnapshot";
+const char* kPrecompiledDataSymbolName = "kDataSnapshot";
 
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
   return dlopen(library_file, RTLD_LAZY);
diff --git a/runtime/bin/extensions_win.cc b/runtime/bin/extensions_win.cc
index d3b49f2..224bcdf 100644
--- a/runtime/bin/extensions_win.cc
+++ b/runtime/bin/extensions_win.cc
@@ -14,7 +14,8 @@
 namespace bin {
 
 const char* kPrecompiledLibraryName = "precompiled.dll";
-const char* kPrecompiledSymbolName = "_kInstructionsSnapshot";
+const char* kPrecompiledInstructionsSymbolName = "_kInstructionsSnapshot";
+const char* kPrecompiledDataSymbolName = "_kDataSnapshot";
 
 void* Extensions::LoadExtensionLibrary(const char* library_file) {
   SetLastError(0);
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index 1face6b..a1efe42 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -136,9 +136,7 @@
     Dart_SetReturnValue(args,
                         Dart_NewInteger(reinterpret_cast<intptr_t>(file)));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -176,9 +174,7 @@
   } else if (bytes_read == 0) {
     Dart_SetReturnValue(args, Dart_NewInteger(-1));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -193,15 +189,11 @@
     if (success) {
       Dart_SetReturnValue(args, Dart_NewInteger(1));
     } else {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     }
   } else {
     OSError os_error(-1, "Invalid argument", OSError::kUnknown);
-    Dart_Handle err = DartUtils::NewDartOSError(&os_error);
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -216,9 +208,7 @@
     Dart_Handle external_array = IOBuffer::Allocate(length, &buffer);
     int64_t bytes_read = file->Read(reinterpret_cast<void*>(buffer), length);
     if (bytes_read < 0) {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     } else {
       if (bytes_read < length) {
         const int kNumArgs = 3;
@@ -235,7 +225,6 @@
                         DartUtils::NewString("_makeUint8ListView"),
                         kNumArgs,
                         dart_args);
-        if (Dart_IsError(array_view)) Dart_PropagateError(array_view);
         Dart_SetReturnValue(args, array_view);
       } else {
         Dart_SetReturnValue(args, external_array);
@@ -243,9 +232,7 @@
     }
   } else {
     OSError os_error(-1, "Invalid argument", OSError::kUnknown);
-    Dart_Handle err = DartUtils::NewDartOSError(&os_error);
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -273,14 +260,12 @@
   if (bytes_read >= 0) {
     result = Dart_ListSetAsBytes(buffer_obj, start, buffer, bytes_read);
     if (Dart_IsError(result)) {
-      delete[] buffer;
-      Dart_PropagateError(result);
+      Dart_SetReturnValue(args, result);
+    } else {
+      Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
     }
-    Dart_SetReturnValue(args, Dart_NewInteger(bytes_read));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
   delete[] buffer;
 }
@@ -323,9 +308,7 @@
   if (Dart_IsError(result)) Dart_PropagateError(result);
 
   if (!success) {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   } else {
     Dart_SetReturnValue(args, Dart_Null());
   }
@@ -339,9 +322,7 @@
   if (return_value >= 0) {
     Dart_SetReturnValue(args, Dart_NewInteger(return_value));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -354,15 +335,11 @@
     if (file->SetPosition(position)) {
       Dart_SetReturnValue(args, Dart_True());
     } else {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     }
   } else {
     OSError os_error(-1, "Invalid argument", OSError::kUnknown);
-    Dart_Handle err = DartUtils::NewDartOSError(&os_error);
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -375,15 +352,11 @@
     if (file->Truncate(length)) {
       Dart_SetReturnValue(args, Dart_True());
     } else {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     }
   } else {
     OSError os_error(-1, "Invalid argument", OSError::kUnknown);
-    Dart_Handle err = DartUtils::NewDartOSError(&os_error);
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -395,9 +368,7 @@
   if (return_value >= 0) {
     Dart_SetReturnValue(args, Dart_NewInteger(return_value));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -409,9 +380,7 @@
   if (return_value >= 0) {
     Dart_SetReturnValue(args, Dart_NewInteger(return_value));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -423,9 +392,7 @@
   if (return_value >= 0) {
     Dart_SetReturnValue(args, Dart_NewInteger(return_value * kMSPerSecond));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -436,9 +403,7 @@
   if (file->Flush()) {
     Dart_SetReturnValue(args, Dart_True());
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -457,18 +422,13 @@
       if (file->Lock(static_cast<File::LockType>(lock), start, end)) {
         Dart_SetReturnValue(args, Dart_True());
       } else {
-        Dart_Handle err = DartUtils::NewDartOSError();
-        if (Dart_IsError(err)) Dart_PropagateError(err);
-        Dart_SetReturnValue(args, err);
+        Dart_SetReturnValue(args, DartUtils::NewDartOSError());
       }
       return;
     }
   }
-
   OSError os_error(-1, "Invalid argument", OSError::kUnknown);
-  Dart_Handle err = DartUtils::NewDartOSError(&os_error);
-  if (Dart_IsError(err)) Dart_PropagateError(err);
-  Dart_SetReturnValue(args, err);
+  Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
 }
 
 
@@ -479,9 +439,7 @@
   if (result) {
     Dart_SetReturnValue(args, Dart_NewBoolean(result));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -494,14 +452,11 @@
     const char* target =
         DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
     if (!File::CreateLink(name, target)) {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     }
   } else  {
     Dart_Handle err = DartUtils::NewDartArgumentError(
         "Non-string argument to Link.create");
-    if (Dart_IsError(err)) Dart_PropagateError(err);
     Dart_SetReturnValue(args, err);
   }
 }
@@ -513,9 +468,7 @@
         DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
     char* target = File::LinkTarget(name);
     if (target == NULL) {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     } else {
       Dart_SetReturnValue(args, DartUtils::NewString(target));
       free(target);
@@ -523,7 +476,6 @@
   } else {
     Dart_Handle err = DartUtils::NewDartArgumentError(
         "Non-string argument to Link.target");
-    if (Dart_IsError(err)) Dart_PropagateError(err);
     Dart_SetReturnValue(args, err);
   }
 }
@@ -536,9 +488,7 @@
   if (result) {
     Dart_SetReturnValue(args, Dart_NewBoolean(result));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -550,9 +500,7 @@
   if (result) {
     Dart_SetReturnValue(args, Dart_NewBoolean(result));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -566,9 +514,7 @@
   if (result) {
     Dart_SetReturnValue(args, Dart_NewBoolean(result));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -582,9 +528,7 @@
   if (result) {
     Dart_SetReturnValue(args, Dart_NewBoolean(result));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -598,9 +542,7 @@
   if (result) {
     Dart_SetReturnValue(args, Dart_NewBoolean(result));
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -613,9 +555,7 @@
     Dart_SetReturnValue(args, DartUtils::NewString(path));
     free(path);
   } else {
-    Dart_Handle err = DartUtils::NewDartOSError();
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError());
   }
 }
 
@@ -648,7 +588,6 @@
   } else  {
     Dart_Handle err = DartUtils::NewDartArgumentError(
         "Non-string argument to FileSystemEntity.type");
-    if (Dart_IsError(err)) Dart_PropagateError(err);
     Dart_SetReturnValue(args, err);
   }
 }
@@ -662,9 +601,7 @@
     int64_t stat_data[File::kStatSize];
     File::Stat(path, stat_data);
     if (stat_data[File::kType] == File::kDoesNotExist) {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     } else {
       Dart_Handle returned_data = Dart_NewTypedData(Dart_TypedData_kInt64,
                                                     File::kStatSize);
@@ -685,7 +622,6 @@
   } else {
     Dart_Handle err = DartUtils::NewDartArgumentError(
         "Non-string argument to FileSystemEntity.stat");
-    if (Dart_IsError(err)) Dart_PropagateError(err);
     Dart_SetReturnValue(args, err);
   }
 }
@@ -700,16 +636,13 @@
         DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
     File::Identical result = File::AreIdentical(path_1, path_2);
     if (result == File::kError) {
-      Dart_Handle err = DartUtils::NewDartOSError();
-      if (Dart_IsError(err)) Dart_PropagateError(err);
-      Dart_SetReturnValue(args, err);
+      Dart_SetReturnValue(args, DartUtils::NewDartOSError());
     } else {
       Dart_SetReturnValue(args, Dart_NewBoolean(result == File::kIdentical));
     }
   } else  {
     Dart_Handle err = DartUtils::NewDartArgumentError(
         "Non-string argument to FileSystemEntity.identical");
-    if (Dart_IsError(err)) Dart_PropagateError(err);
     Dart_SetReturnValue(args, err);
   }
 }
diff --git a/runtime/bin/file_system_watcher.cc b/runtime/bin/file_system_watcher.cc
index 164346c..5d8c0b8 100644
--- a/runtime/bin/file_system_watcher.cc
+++ b/runtime/bin/file_system_watcher.cc
@@ -24,9 +24,7 @@
     Dart_SetReturnValue(args, Dart_NewInteger(id));
   } else {
     OSError os_error;
-    Dart_Handle error = DartUtils::NewDartOSError(&os_error);
-    if (Dart_IsError(error)) Dart_PropagateError(error);
-    Dart_ThrowException(error);
+    Dart_ThrowException(DartUtils::NewDartOSError(&os_error));
   }
 }
 
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 0e12574..ea9f3d7 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -256,12 +256,8 @@
 
     // Run DartUtils::ResolveUriInWorkingDirectory in context of uri resolver
     // isolate.
-    Dart_Handle builtin_lib =
-        Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-    CHECK_RESULT(builtin_lib);
-
     Dart_Handle result = DartUtils::ResolveUriInWorkingDirectory(
-        DartUtils::NewString(script_uri), builtin_lib);
+        DartUtils::NewString(script_uri));
     if (Dart_IsError(result)) {
       failed = true;
       result_string = strdup(Dart_GetError(result));
@@ -285,12 +281,8 @@
     UriResolverIsolateScope scope;
 
     // Run DartUtils::FilePathFromUri in context of uri resolver isolate.
-    Dart_Handle builtin_lib =
-        Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-    CHECK_RESULT(builtin_lib);
-
     Dart_Handle result = DartUtils::FilePathFromUri(
-        DartUtils::NewString(script_uri), builtin_lib);
+        DartUtils::NewString(script_uri));
     if (Dart_IsError(result)) {
       failed = true;
       result_string = strdup(Dart_GetError(result));
@@ -314,14 +306,8 @@
     UriResolverIsolateScope scope;
 
     // Run DartUtils::ResolveUri in context of uri resolver isolate.
-    Dart_Handle builtin_lib =
-        Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-    CHECK_RESULT(builtin_lib);
-
     Dart_Handle result = DartUtils::ResolveUri(
-        DartUtils::NewString(library_uri),
-        DartUtils::NewString(uri),
-        builtin_lib);
+        DartUtils::NewString(library_uri), DartUtils::NewString(uri));
     if (Dart_IsError(result)) {
       failed = true;
       result_string = strdup(Dart_GetError(result));
@@ -449,7 +435,11 @@
   if (Dart_IsError(source)) {
     return source;
   }
-  return Dart_LoadScript(resolved_script_uri, source, 0, 0);
+  if (IsSnapshottingForPrecompilation()) {
+    return Dart_LoadScript(resolved_script_uri, source, 0, 0);
+  } else {
+    return Dart_LoadLibrary(resolved_script_uri, source, 0, 0);
+  }
 }
 
 
@@ -959,12 +949,15 @@
                                          Dart_IsolateFlags* flags,
                                          void* data,
                                          char** error) {
+  IsolateData* isolate_data = new IsolateData(script_uri,
+                                              package_root,
+                                              package_config);
   Dart_Isolate isolate = NULL;
   isolate = Dart_CreateIsolate(script_uri,
                                main,
                                NULL,
                                NULL,
-                               NULL,
+                               isolate_data,
                                error);
 
   if (isolate == NULL) {
@@ -1021,10 +1014,10 @@
   TimerUtils::InitOnce();
   EventHandler::Start();
 
+#if !defined(PRODUCT)
+  // Constant true in PRODUCT mode.
   vm_options.AddArgument("--load_deferred_eagerly");
-  // Workaround until issue 21620 is fixed.
-  // (https://github.com/dart-lang/sdk/issues/21620)
-  vm_options.AddArgument("--no-concurrent_sweep");
+#endif
 
   if (IsSnapshottingForPrecompilation()) {
     vm_options.AddArgument("--precompilation");
@@ -1042,6 +1035,7 @@
   char* error = Dart_Initialize(
       NULL,
       NULL,
+      NULL,
       CreateServiceIsolate,
       NULL,
       NULL,
@@ -1058,8 +1052,9 @@
     return 255;
   }
 
+  IsolateData* isolate_data = new IsolateData(NULL, NULL, NULL);
   Dart_Isolate isolate = Dart_CreateIsolate(
-      NULL, NULL, NULL, NULL, NULL, &error);
+      NULL, NULL, NULL, NULL, isolate_data, &error);
   if (isolate == NULL) {
     Log::PrintErr("Error: %s", error);
     free(error);
@@ -1081,24 +1076,21 @@
 
     SetupForUriResolution();
 
-    // Get handle to builtin library.
-    Dart_Handle builtin_lib =
-        Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-    CHECK_RESULT(builtin_lib);
-
-    // Ensure that we mark all libraries as loaded.
-    result = Dart_FinalizeLoading(false);
+    // Prepare builtin and its dependent libraries for use to resolve URIs.
+    // Set up various closures, e.g: printing, timers etc.
+    // Set up 'package root' for URI resolution.
+    result = DartUtils::PrepareForScriptLoading(false, false);
     CHECK_RESULT(result);
 
-    // Prepare for script loading by setting up the 'print' and 'timer'
-    // closures and setting up 'package root' for URI resolution.
-    result =
-        DartUtils::PrepareForScriptLoading(package_root,
-                                           NULL,
-                                           false,
-                                           false,
-                                           builtin_lib);
+    // Set up the load port provided by the service isolate so that we can
+    // load scripts.
+    result = DartUtils::SetupServiceLoadPort();
     CHECK_RESULT(result);
+
+    // Setup package root if specified.
+    result = DartUtils::SetupPackageRoot(package_root, NULL);
+    CHECK_RESULT(result);
+
     Dart_ExitScope();
     Dart_ExitIsolate();
 
@@ -1106,7 +1098,9 @@
 
     // Now we create an isolate into which we load all the code that needs to
     // be in the snapshot.
-    if (Dart_CreateIsolate(NULL, NULL, NULL, NULL, NULL, &error) == NULL) {
+    isolate_data = new IsolateData(NULL, NULL, NULL);
+    if (Dart_CreateIsolate(
+            NULL, NULL, NULL, NULL, isolate_data, &error) == NULL) {
       fprintf(stderr, "%s", error);
       free(error);
       exit(255);
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index ec70232..51b1d56 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -107,12 +107,12 @@
   V(SecureSocket_RegisterHandshakeCompleteCallback, 2)                         \
   V(SecureSocket_Renegotiate, 4)                                               \
   V(SecurityContext_Allocate, 1)                                               \
-  V(SecurityContext_UsePrivateKey, 3)                                          \
+  V(SecurityContext_UsePrivateKeyBytes, 3)                                     \
   V(SecurityContext_SetAlpnProtocols, 3)                                       \
-  V(SecurityContext_SetClientAuthorities, 2)                                   \
-  V(SecurityContext_SetTrustedCertificates, 3)                                 \
+  V(SecurityContext_SetClientAuthoritiesBytes, 3)                              \
+  V(SecurityContext_SetTrustedCertificatesBytes, 3)                            \
   V(SecurityContext_TrustBuiltinRoots, 1)                                      \
-  V(SecurityContext_UseCertificateChain, 2)                                    \
+  V(SecurityContext_UseCertificateChainBytes, 3)                               \
   V(ServerSocket_Accept, 2)                                                    \
   V(ServerSocket_CreateBindListen, 6)                                          \
   V(Socket_CreateConnect, 3)                                                   \
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index 29d2884..d3f411f 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -21,14 +21,15 @@
 // when the isolate shuts down.
 class IsolateData {
  public:
-  explicit IsolateData(const char* url,
-                       const char* package_root,
-                       const char* packages_file)
-      : script_url(strdup(url)),
+  IsolateData(const char* url,
+              const char* package_root,
+              const char* packages_file)
+      : script_url((url != NULL) ? strdup(url) : NULL),
         package_root(NULL),
         packages_file(NULL),
         udp_receive_buffer(NULL),
-        load_async_id(-1) {
+        load_async_id(-1),
+        builtin_lib_(NULL) {
     if (package_root != NULL) {
       ASSERT(packages_file == NULL);
       this->package_root = strdup(package_root);
@@ -36,14 +37,32 @@
       this->packages_file = strdup(packages_file);
     }
   }
-#if 0
+
   ~IsolateData() {
     free(script_url);
+    script_url = NULL;
     free(package_root);
+    package_root = NULL;
     free(packages_file);
+    packages_file = NULL;
     free(udp_receive_buffer);
+    udp_receive_buffer = NULL;
+    if (builtin_lib_ != NULL) {
+      Dart_DeletePersistentHandle(builtin_lib_);
+    }
   }
-#endif
+
+  Dart_Handle builtin_lib() const {
+    ASSERT(builtin_lib_ != NULL);
+    ASSERT(!Dart_IsError(builtin_lib_));
+    return builtin_lib_;
+  }
+  void set_builtin_lib(Dart_Handle lib) {
+    ASSERT(builtin_lib_ == NULL);
+    ASSERT(lib != NULL);
+    ASSERT(!Dart_IsError(lib));
+    builtin_lib_ = Dart_NewPersistentHandle(lib);
+  }
 
   char* script_url;
   char* package_root;
@@ -52,6 +71,8 @@
   int64_t load_async_id;
 
  private:
+  Dart_Handle builtin_lib_;
+
   DISALLOW_COPY_AND_ASSIGN(IsolateData);
 };
 
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 5e57327..bb21b9f 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -39,12 +39,22 @@
 // snapshot otherwise it is initialized to NULL.
 extern const uint8_t* isolate_snapshot_buffer;
 
-// Global state that stores a pointer to the application script snapshot.
+/**
+ * Global state used to control and store generation of application snapshots
+ * (script/full).
+ * A full application snapshot can be generated and run using the following
+ * commands
+ * - Generating a full application snapshot :
+ * dart_no_snapshot --full-snapshot-after-run=<filename> --package-root=<dirs>
+ *   <script_uri> [<script_options>]
+ * - Running the full application snapshot generated above :
+ * dart --run-full-snapshot=<filename> <script_uri> [<script_options>]
+ */
 static bool generate_script_snapshot = false;
-static bool generate_script_snapshot_after_run = false;
+static bool generate_full_snapshot_after_run = false;
+static bool run_full_snapshot = false;
 static const char* snapshot_filename = NULL;
 
-
 // Value of the --package-root flag.
 // (This pointer points into an argv buffer and does not need to be
 // free'd.)
@@ -58,17 +68,17 @@
 
 // Global flag that is used to indicate that we want to compile all the
 // dart functions and not run anything.
-static bool has_compile_all = false;
+static bool compile_all = false;
 
 
 // Global flag that is used to indicate that we want to compile all the
 // dart functions before running main and not compile anything thereafter.
-static bool has_gen_precompiled_snapshot = false;
+static bool gen_precompiled_snapshot = false;
 
 
 // Global flag that is used to indicate that we want to run from a precompiled
 // snapshot.
-static bool has_run_precompiled_snapshot = false;
+static bool run_precompiled_snapshot = false;
 
 
 // Value of the --gen/run_precompiled_snapshot flag.
@@ -80,19 +90,26 @@
 // Global flag that is used to indicate that we want to compile everything in
 // the same way as precompilation before main, then continue running in the
 // same process.
-static bool has_noopt = false;
+// Always set this with dart_noopt.
+#if defined(DART_PRECOMPILER) && !defined(DART_NO_SNAPSHOT)
+static const bool is_noopt = true;
+#else
+static const bool is_noopt = false;
+#endif
 
 
 extern const char* kPrecompiledLibraryName;
-extern const char* kPrecompiledSymbolName;
+extern const char* kPrecompiledInstructionsSymbolName;
+extern const char* kPrecompiledDataSymbolName;
 static const char* kPrecompiledVmIsolateName = "precompiled.vmisolate";
 static const char* kPrecompiledIsolateName = "precompiled.isolate";
 static const char* kPrecompiledInstructionsName = "precompiled.S";
-
+static const char* kVMIsolateSuffix = "vmisolate";
+static const char* kIsolateSuffix = "isolate";
 
 // Global flag that is used to indicate that we want to trace resolution of
 // URIs and the loading of libraries, parts and scripts.
-static bool has_trace_loading = false;
+static bool trace_loading = false;
 
 
 static const char* DEFAULT_VM_SERVICE_SERVER_IP = "127.0.0.1";
@@ -155,34 +172,34 @@
 }
 
 
-static bool has_version_option = false;
+static bool version_option = false;
 static bool ProcessVersionOption(const char* arg,
                                  CommandLineOptions* vm_options) {
   if (*arg != '\0') {
     return false;
   }
-  has_version_option = true;
+  version_option = true;
   return true;
 }
 
 
-static bool has_help_option = false;
+static bool help_option = false;
 static bool ProcessHelpOption(const char* arg, CommandLineOptions* vm_options) {
   if (*arg != '\0') {
     return false;
   }
-  has_help_option = true;
+  help_option = true;
   return true;
 }
 
 
-static bool has_verbose_option = false;
+static bool verbose_option = false;
 static bool ProcessVerboseOption(const char* arg,
                                  CommandLineOptions* vm_options) {
   if (*arg != '\0') {
     return false;
   }
-  has_verbose_option = true;
+  verbose_option = true;
   return true;
 }
 
@@ -302,7 +319,7 @@
   if (*arg != '\0') {
     return false;
   }
-  has_compile_all = true;
+  compile_all = true;
   return true;
 }
 
@@ -322,8 +339,11 @@
   } else {
     precompiled_snapshot_directory = arg;
   }
-  has_gen_precompiled_snapshot = true;
+  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;
 }
 
@@ -337,58 +357,70 @@
       (precompiled_snapshot_directory[0] == ':')) {
     precompiled_snapshot_directory = &precompiled_snapshot_directory[1];
   }
-  has_run_precompiled_snapshot = true;
+  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;
 }
 
 
-static bool ProcessNooptOption(
-    const char* arg,
-    CommandLineOptions* vm_options) {
-  ASSERT(arg != NULL);
-  if (*arg != '\0') {
+static bool ProcessSnapshotOptionHelper(const char* filename,
+                                        bool* snapshot_option) {
+  ASSERT((filename != NULL) && (strlen(filename) != 0));
+  snapshot_filename = filename;
+  *snapshot_option = true;
+  if (generate_script_snapshot && generate_full_snapshot_after_run) {
+    Log::PrintErr("--snapshot and --snapshot-after-run options"
+                  " cannot be specified at the same time\n");
+    *snapshot_option = false;
     return false;
   }
-  has_noopt = true;
-  vm_options->AddArgument("--precompilation");
   return true;
 }
 
 
-static bool ProcessScriptSnapshotOptionHelper(const char* filename,
-                                              bool* snapshot_option) {
-  *snapshot_option = false;
-  if ((filename != NULL) && (strlen(filename) != 0)) {
-    // Ensure that we are already running using a full snapshot.
-    if (isolate_snapshot_buffer == NULL) {
-      Log::PrintErr("Script snapshots cannot be generated in this version of"
-                    " dart\n");
-      return false;
-    }
-    snapshot_filename = filename;
-    *snapshot_option = true;
-    if (generate_script_snapshot && generate_script_snapshot_after_run) {
-      Log::PrintErr("--snapshot and --snapshot-after-run options"
-                    " cannot be specified at the same time\n");
-      return false;
-    }
-    return true;
-  }
-  return false;
-}
-
-
 static bool ProcessScriptSnapshotOption(const char* filename,
                                         CommandLineOptions* vm_options) {
-  return ProcessScriptSnapshotOptionHelper(filename, &generate_script_snapshot);
+  if ((filename == NULL) || (strlen(filename) == 0)) {
+    return false;
+  }
+  // Ensure that we are already running using a full snapshot.
+  if (isolate_snapshot_buffer == NULL) {
+    Log::PrintErr("Script snapshots cannot be generated in this version of"
+                  " Dart\n");
+    return false;
+  }
+  return ProcessSnapshotOptionHelper(filename, &generate_script_snapshot);
 }
 
 
-static bool ProcessScriptSnapshotAfterRunOption(
+static bool ProcessFullSnapshotAfterRunOption(
     const char* filename, CommandLineOptions* vm_options) {
-  return ProcessScriptSnapshotOptionHelper(filename,
-                                           &generate_script_snapshot_after_run);
+  if ((filename == NULL) || (strlen(filename) == 0)) {
+    return false;
+  }
+  // Ensure that we are running 'dart_no_snapshot'.
+  if (isolate_snapshot_buffer != NULL) {
+    Log::PrintErr("Full Application snapshots must be generated with"
+                  " dart_no_snapshot\n");
+    return false;
+  }
+  return ProcessSnapshotOptionHelper(filename,
+                                     &generate_full_snapshot_after_run);
+}
+
+
+static bool ProcessRunFullSnapshotOption(
+    const char* filename, CommandLineOptions* vm_options) {
+#ifndef DART_PRODUCT_BINARY
+  Log::PrintErr("Full Application snapshots can only be be run with"
+                " dart_product\n");
+  return false;
+#else
+  return ProcessSnapshotOptionHelper(filename, &run_full_snapshot);
+#endif  // defined(DART_PRODUCT_BINARY)
 }
 
 
@@ -425,6 +457,8 @@
   }
 
   vm_options->AddArgument("--pause-isolates-on-exit");
+  vm_options->AddArgument("--pause-isolates-on-unhandled-exceptions");
+  vm_options->AddArgument("--warn-on-pause-with-no-debugger");
   return true;
 }
 
@@ -434,7 +468,7 @@
   if (*arg != '\0') {
     return false;
   }
-  has_trace_loading = true;
+  trace_loading = true;
   return true;
 }
 
@@ -485,12 +519,12 @@
   { "--compile_all", ProcessCompileAllOption },
   { "--enable-vm-service", ProcessEnableVmServiceOption },
   { "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
-  { "--noopt", ProcessNooptOption },
   { "--observe", ProcessObserveOption },
   { "--run-precompiled-snapshot", ProcessRunPrecompiledSnapshotOption },
   { "--shutdown", ProcessShutdownOption },
   { "--snapshot=", ProcessScriptSnapshotOption },
-  { "--snapshot-after-run=", ProcessScriptSnapshotAfterRunOption },
+  { "--full-snapshot-after-run=", ProcessFullSnapshotAfterRunOption },
+  { "--run-full-snapshot=", ProcessRunFullSnapshotOption },
   { "--trace-loading", ProcessTraceLoadingOption },
   { NULL, NULL }
 };
@@ -607,23 +641,29 @@
                   "file is invalid.\n");
     return -1;
   }
-  if (has_noopt) {
-    if (has_gen_precompiled_snapshot) {
-      Log::PrintErr("Specifying --noopt and --gen_precompiled_snapshot"
+  if (is_noopt) {
+    if (gen_precompiled_snapshot) {
+      Log::PrintErr("Running dart_noopt with --gen_precompiled_snapshot"
                     " is invalid.\n");
       return -1;
     }
-    if (has_run_precompiled_snapshot) {
-      Log::PrintErr("Specifying --noopt and --run_precompiled_snapshot"
+    if (run_precompiled_snapshot) {
+      Log::PrintErr("Running dart_noopt with --run_precompiled_snapshot"
                     " is invalid.\n");
       return -1;
     }
   }
-  if (has_gen_precompiled_snapshot && has_run_precompiled_snapshot) {
-    Log::PrintErr("Specifying --gen_precompiled_snapshot and"
+  if (run_full_snapshot && run_precompiled_snapshot) {
+    Log::PrintErr("Specifying --run_full_snapshot and"
                   " --run_precompiled_snapshot is invalid.\n");
     return -1;
   }
+  if ((generate_full_snapshot_after_run || gen_precompiled_snapshot) &&
+      (run_full_snapshot || run_precompiled_snapshot)) {
+    Log::PrintErr("Specifying an option to generate a snapshot and"
+                  " run using a snapshot is invalid.\n");
+    return -1;
+  }
 
   return 0;
 }
@@ -709,6 +749,19 @@
                                                 char** error,
                                                 int* exit_code) {
   ASSERT(script_uri != NULL);
+#if defined(DART_PRODUCT_BINARY)
+  if (strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) {
+    // No service isolate support.
+    return NULL;
+  }
+#endif  // defined(DART_PRODUCT_BINARY)
+
+  if (run_full_snapshot &&
+      (strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0)) {
+    // We do not create a service isolate when running a full application
+    // snapshot.
+    return NULL;
+  }
   IsolateData* isolate_data = new IsolateData(script_uri,
                                               package_root,
                                               packages_config);
@@ -738,15 +791,18 @@
   Dart_Handle result = Dart_SetLibraryTagHandler(DartUtils::LibraryTagHandler);
   CHECK_RESULT(result);
 
+#if defined(DART_PRODUCT_BINARY)
+  ASSERT(!Dart_IsServiceIsolate(isolate));
+#else
   if (Dart_IsServiceIsolate(isolate)) {
     // If this is the service isolate, load embedder specific bits and return.
     if (!VmService::Setup(vm_service_server_ip,
                           vm_service_server_port,
-                          has_run_precompiled_snapshot)) {
+                          run_precompiled_snapshot)) {
       *error = strdup(VmService::GetErrorMessage());
       return NULL;
     }
-    if (has_compile_all) {
+    if (compile_all) {
       result = Dart_CompileAll();
       CHECK_RESULT(result);
     }
@@ -754,31 +810,31 @@
     Dart_ExitIsolate();
     return isolate;
   }
+#endif  // defined(DART_PRODUCT_BINARY)
 
-  // Load the specified application script into the newly created isolate.
+  // Prepare builtin and other core libraries for use to resolve URIs.
+  // Set up various closures, e.g: printing, timers etc.
+  // Set up 'package root' for URI resolution.
+  result = DartUtils::PrepareForScriptLoading(false, trace_loading);
+  CHECK_RESULT(result);
 
-  // Prepare builtin and its dependent libraries for use to resolve URIs.
-  // The builtin library is part of the core snapshot and would already be
-  // available here in the case of script snapshot loading.
-  Dart_Handle builtin_lib =
-      Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-  CHECK_RESULT(builtin_lib);
+  if (!run_full_snapshot) {
+    // Set up the load port provided by the service isolate so that we can
+    // load scripts.
+    result = DartUtils::SetupServiceLoadPort();
+    CHECK_RESULT(result);
+  }
 
-  // Prepare for script loading by setting up the 'print' and 'timer'
-  // closures and setting up 'package root' for URI resolution.
-  result = DartUtils::PrepareForScriptLoading(package_root,
-                                              packages_config,
-                                              false,
-                                              has_trace_loading,
-                                              builtin_lib);
+  // Setup package root if specified.
+  result = DartUtils::SetupPackageRoot(package_root, packages_config);
   CHECK_RESULT(result);
 
   result = Dart_SetEnvironmentCallback(EnvironmentCallback);
   CHECK_RESULT(result);
 
-  if (!has_run_precompiled_snapshot) {
-    // Load the script.
-    result = DartUtils::LoadScript(script_uri, builtin_lib);
+  if (!run_precompiled_snapshot && !run_full_snapshot) {
+    // Load the specified application script into the newly created isolate.
+    result = DartUtils::LoadScript(script_uri);
     CHECK_RESULT(result);
 
     // Run event-loop and wait for script loading to complete.
@@ -791,6 +847,9 @@
 
     result = DartUtils::SetupIOLibrary(script_uri);
     CHECK_RESULT(result);
+  } else if (run_full_snapshot) {
+    result = DartUtils::SetupIOLibrary(script_uri);
+    CHECK_RESULT(result);
   }
 
   // Make the isolate runnable so that it is ready to handle messages.
@@ -847,7 +906,7 @@
       "\n"
       "Executes the Dart script passed as <dart-script-file>.\n"
       "\n");
-  if (!has_verbose_option) {
+  if (!verbose_option) {
     Log::PrintErr(
 "Common options:\n"
 "--checked or -c\n"
@@ -860,9 +919,11 @@
 "--packages=<path>\n"
 "  Where to find a package spec file.\n"
 "--observe[=<port>[/<bind-address>]]\n"
-"  Enable the VM service and cause isolates to pause on exit (default port is\n"
-"  8181, default bind address is 127.0.0.1). With the default options,\n"
-"  Observatory will be available locally at http://127.0.0.1:8181/\n"
+"  The observe flag is used to run a program with a default set of options\n"
+"  for debugging under Observatory. With the default options, Observatory\n"
+"  will be available at http://127.0.0.1:8181/ (default port is 8181,\n"
+"  default bind address is 127.0.0.1).  Isolates will pause at exit and\n"
+"  when they throw unhandled exceptions.\n"
 "--version\n"
 "  Print the VM version.\n");
   } else {
@@ -878,9 +939,11 @@
 "--packages=<path>\n"
 "  Where to find a package spec file.\n"
 "--observe[=<port>[/<bind-address>]]\n"
-"  Enable the VM service and cause isolates to pause on exit (default port is\n"
-"  8181, default bind address is 127.0.0.1). With the default options,\n"
-"  Observatory will be available locally at http://127.0.0.1:8181/\n"
+"  The observe flag is used to run a program with a default set of options\n"
+"  for debugging under Observatory. With the default options, Observatory\n"
+"  will be available at http://127.0.0.1:8181/ (default port is 8181,\n"
+"  default bind address is 127.0.0.1).  Isolates will pause at exit and\n"
+"  when they throw unhandled exceptions.\n"
 "--version\n"
 "  Print the VM version.\n"
 "\n"
@@ -890,9 +953,9 @@
 "--trace-loading\n"
 "  enables tracing of library and script loading\n"
 "\n"
-"--enable-vm-service[:<port number>]\n"
+"--enable-vm-service[:<port>[/<bind-address>]]\n"
 "  enables the VM service and listens on specified port for connections\n"
-"  (default port number is 8181)\n"
+"  (default port number is 8181, default bind address is 127.0.0.1).\n"
 "\n"
 "The following options are only used for VM development and may\n"
 "be changed in any future version:\n");
@@ -1012,17 +1075,17 @@
 }
 
 
-static void WritePrecompiledSnapshotFile(const char* filename,
-                                         const uint8_t* buffer,
-                                         const intptr_t size) {
+static void WriteSnapshotFile(const char* snapshot_directory,
+                              const char* filename,
+                              bool write_magic_number,
+                              const uint8_t* buffer,
+                              const intptr_t size) {
   char* concat = NULL;
   const char* qualified_filename;
-  if (strlen(precompiled_snapshot_directory) > 0) {
-    intptr_t len = snprintf(NULL, 0, "%s/%s",
-                            precompiled_snapshot_directory, filename);
+  if ((snapshot_directory != NULL) && strlen(snapshot_directory) > 0) {
+    intptr_t len = snprintf(NULL, 0, "%s/%s", snapshot_directory, filename);
     concat = new char[len + 1];
-    snprintf(concat, len + 1, "%s/%s",
-             precompiled_snapshot_directory, filename);
+    snprintf(concat, len + 1, "%s/%s", snapshot_directory, filename);
     qualified_filename = concat;
   } else {
     qualified_filename = filename;
@@ -1030,6 +1093,12 @@
 
   File* file = File::Open(qualified_filename, File::kWriteTruncate);
   ASSERT(file != NULL);
+
+  if (write_magic_number) {
+    // Write the magic number to indicate file is a script snapshot.
+    DartUtils::WriteMagicNumber(file);
+  }
+
   if (!file->WriteFully(buffer, size)) {
     ErrorExit(kErrorExitCode,
               "Unable to open file %s for writing snapshot\n",
@@ -1042,16 +1111,15 @@
 }
 
 
-static void ReadPrecompiledSnapshotFile(const char* filename,
-                                        const uint8_t** buffer) {
+static void ReadSnapshotFile(const char* snapshot_directory,
+                             const char* filename,
+                             const uint8_t** buffer) {
   char* concat = NULL;
   const char* qualified_filename;
-  if (strlen(precompiled_snapshot_directory) > 0) {
-    intptr_t len = snprintf(NULL, 0, "%s/%s",
-                            precompiled_snapshot_directory, filename);
+  if ((snapshot_directory != NULL) && strlen(snapshot_directory) > 0) {
+    intptr_t len = snprintf(NULL, 0, "%s/%s", snapshot_directory, filename);
     concat = new char[len + 1];
-    snprintf(concat, len + 1, "%s/%s",
-             precompiled_snapshot_directory, filename);
+    snprintf(concat, len + 1, "%s/%s", snapshot_directory, filename);
     qualified_filename = concat;
   } else {
     qualified_filename = filename;
@@ -1059,15 +1127,19 @@
 
   void* file = DartUtils::OpenFile(qualified_filename, false);
   if (file == NULL) {
-    ErrorExit(kErrorExitCode,
-              "Error: Unable to open file %s for reading snapshot\n",
-              qualified_filename);
+    fprintf(stderr,
+            "Error: Unable to open file %s for reading snapshot\n",
+            qualified_filename);
+    fflush(stderr);
+    Platform::Exit(kErrorExitCode);
   }
   intptr_t len = -1;
   DartUtils::ReadFile(buffer, &len, file);
   if (*buffer == NULL || len == -1) {
-    ErrorExit(kErrorExitCode,
-              "Error: Unable to read snapshot file %s\n", qualified_filename);
+    fprintf(stderr,
+            "Error: Unable to read snapshot file %s\n", qualified_filename);
+    fflush(stderr);
+    Platform::Exit(kErrorExitCode);
   }
   DartUtils::CloseFile(file);
   if (concat != NULL) {
@@ -1100,22 +1172,54 @@
     ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
   }
 
-  // Open the snapshot file.
-  File* snapshot_file = File::Open(snapshot_filename, File::kWriteTruncate);
-  if (snapshot_file == NULL) {
-    ErrorExit(kErrorExitCode,
-              "Unable to open file %s for writing the snapshot\n",
-              snapshot_filename);
+  WriteSnapshotFile(NULL, snapshot_filename, true, buffer, size);
+}
+
+
+static void ComputeSnapshotFilenames(const char* filename,
+                                     char** vm_snapshot_fname,
+                                     char** isolate_snapshot_fname) {
+  intptr_t len = snprintf(NULL, 0, "%s.%s", filename, kVMIsolateSuffix);
+  *vm_snapshot_fname = new char[len + 1];
+  snprintf(*vm_snapshot_fname, len + 1, "%s.%s", filename, kVMIsolateSuffix);
+
+  len = snprintf(NULL, 0, "%s.%s", filename, kIsolateSuffix);
+  *isolate_snapshot_fname = new char[len + 1];
+  snprintf(*isolate_snapshot_fname, len + 1, "%s.%s", filename, kIsolateSuffix);
+}
+
+static void GenerateFullSnapshot() {
+  // Create a full snapshot of the script.
+  Dart_Handle result;
+  uint8_t* vm_isolate_buffer = NULL;
+  intptr_t vm_isolate_size = 0;
+  uint8_t* isolate_buffer = NULL;
+  intptr_t isolate_size = 0;
+  char* vm_snapshot_fname = NULL;
+  char* isolate_snapshot_fname = NULL;
+
+  result = Dart_CreateSnapshot(&vm_isolate_buffer,
+                               &vm_isolate_size,
+                               &isolate_buffer,
+                               &isolate_size);
+  if (Dart_IsError(result)) {
+    ErrorExit(kErrorExitCode, "%s\n", Dart_GetError(result));
   }
 
-  // Write the magic number to indicate file is a script snapshot.
-  DartUtils::WriteMagicNumber(snapshot_file);
-
-  // Now write the snapshot out to specified file.
-  bool bytes_written = snapshot_file->WriteFully(buffer, size);
-  ASSERT(bytes_written);
-  delete snapshot_file;
-  snapshot_file = NULL;
+  // Compute snapshot file names and write out the snapshot files.
+  ComputeSnapshotFilenames(snapshot_filename,
+                           &vm_snapshot_fname,
+                           &isolate_snapshot_fname);
+  WriteSnapshotFile(NULL,
+                    vm_snapshot_fname,
+                    false,
+                    vm_isolate_buffer,
+                    vm_isolate_size);
+  WriteSnapshotFile(NULL,
+                    isolate_snapshot_fname,
+                    false,
+                    isolate_buffer,
+                    isolate_size);
 }
 
 
@@ -1182,12 +1286,12 @@
     Dart_Handle root_lib = Dart_RootLibrary();
     // Import the root library into the builtin library so that we can easily
     // lookup the main entry point exported from the root library.
-    Dart_Handle builtin_lib =
-        Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-    ASSERT(!Dart_IsError(builtin_lib));
-    result = Dart_LibraryImportLibrary(builtin_lib, root_lib, Dart_Null());
-
-    if (has_gen_precompiled_snapshot) {
+    IsolateData* isolate_data =
+        reinterpret_cast<IsolateData*>(Dart_IsolateData(isolate));
+    result = Dart_LibraryImportLibrary(
+        isolate_data->builtin_lib(), root_lib, Dart_Null());
+#ifndef DART_PRODUCT_BINARY
+    if (is_noopt || gen_precompiled_snapshot) {
       // Load the embedder's portion of the VM service's Dart code so it will
       // be included in the precompiled snapshot.
       if (!VmService::LoadForGenPrecompiled()) {
@@ -1198,13 +1302,14 @@
         exit(kErrorExitCode);
       }
     }
+#endif  // !DART_PRODUCT_BINARY
 
-    if (has_compile_all) {
+    if (compile_all) {
       result = Dart_CompileAll();
       CHECK_RESULT(result);
     }
 
-    if (has_noopt || has_gen_precompiled_snapshot) {
+    if (is_noopt || gen_precompiled_snapshot) {
       Dart_QualifiedFunctionName standalone_entry_points[] = {
         { "dart:_builtin", "::", "_getMainClosure" },
         { "dart:_builtin", "::", "_getPrintClosure" },
@@ -1234,16 +1339,15 @@
         { "dart:io", "_SecureFilterImpl", "get:ENCRYPTED_SIZE" },
         { "dart:io", "_SecureFilterImpl", "get:SIZE" },
         { "dart:vmservice_io", "::", "main" },
-        { "dart:vmservice_io", "::", "boot" },
         { NULL, NULL, NULL }  // Must be terminated with NULL entries.
       };
 
-      const bool reset_fields = has_gen_precompiled_snapshot;
+      const bool reset_fields = gen_precompiled_snapshot;
       result = Dart_Precompile(standalone_entry_points, reset_fields);
       CHECK_RESULT(result);
     }
 
-    if (has_gen_precompiled_snapshot) {
+    if (gen_precompiled_snapshot) {
       uint8_t* vm_isolate_buffer = NULL;
       intptr_t vm_isolate_size = 0;
       uint8_t* isolate_buffer = NULL;
@@ -1257,15 +1361,21 @@
                                               &instructions_buffer,
                                               &instructions_size);
       CHECK_RESULT(result);
-      WritePrecompiledSnapshotFile(kPrecompiledVmIsolateName,
-                                   vm_isolate_buffer,
-                                   vm_isolate_size);
-      WritePrecompiledSnapshotFile(kPrecompiledIsolateName,
-                                   isolate_buffer,
-                                   isolate_size);
-      WritePrecompiledSnapshotFile(kPrecompiledInstructionsName,
-                                   instructions_buffer,
-                                   instructions_size);
+      WriteSnapshotFile(precompiled_snapshot_directory,
+                        kPrecompiledVmIsolateName,
+                        false,
+                        vm_isolate_buffer,
+                        vm_isolate_size);
+      WriteSnapshotFile(precompiled_snapshot_directory,
+                        kPrecompiledIsolateName,
+                        false,
+                        isolate_buffer,
+                        isolate_size);
+      WriteSnapshotFile(precompiled_snapshot_directory,
+                        kPrecompiledInstructionsName,
+                        false,
+                        instructions_buffer,
+                        instructions_size);
     } else {
       if (Dart_IsNull(root_lib)) {
         ErrorExit(kErrorExitCode,
@@ -1276,7 +1386,7 @@
       // The helper function _getMainClosure creates a closure for the main
       // entry point which is either explicitly or implictly exported from the
       // root library.
-      Dart_Handle main_closure = Dart_Invoke(builtin_lib,
+      Dart_Handle main_closure = Dart_Invoke(isolate_data->builtin_lib(),
           Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
       CHECK_RESULT(main_closure);
 
@@ -1296,12 +1406,14 @@
 
       // Keep handling messages until the last active receive port is closed.
       result = Dart_RunLoop();
-      CHECK_RESULT(result);
-
-      // Generate a script snapshot after execution if specified.
-      if (generate_script_snapshot_after_run) {
-        GenerateScriptSnapshot();
+      // Generate a full snapshot after execution if specified.
+      if (generate_full_snapshot_after_run) {
+        if (!Dart_IsCompilationError(result) &&
+            !Dart_IsVMRestartRequest(result)) {
+          GenerateFullSnapshot();
+        }
       }
+      CHECK_RESULT(result);
     }
   }
 
@@ -1424,10 +1536,10 @@
                      &dart_options,
                      &print_flags_seen,
                      &verbose_debug_seen) < 0) {
-    if (has_help_option) {
+    if (help_option) {
       PrintUsage();
       Platform::Exit(0);
-    } else if (has_version_option) {
+    } else if (version_option) {
       PrintVersion();
       Platform::Exit(0);
     } else if (print_flags_seen) {
@@ -1450,9 +1562,20 @@
     Platform::Exit(kErrorExitCode);
   }
 
-  if (generate_script_snapshot) {
+#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.
+  ASSERT(!gen_precompiled_snapshot && !run_precompiled_snapshot);
+  vm_options.AddArgument("--precompilation");
+#endif
 
   Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
 
@@ -1461,18 +1584,39 @@
   EventHandler::Start();
 
   const uint8_t* instructions_snapshot = NULL;
-  if (has_run_precompiled_snapshot) {
+  const uint8_t* data_snapshot = NULL;
+  if (run_precompiled_snapshot) {
     instructions_snapshot = reinterpret_cast<const uint8_t*>(
-        LoadLibrarySymbol(kPrecompiledLibraryName, kPrecompiledSymbolName));
-    ReadPrecompiledSnapshotFile(kPrecompiledVmIsolateName,
-                                &vm_isolate_snapshot_buffer);
-    ReadPrecompiledSnapshotFile(kPrecompiledIsolateName,
-                                &isolate_snapshot_buffer);
+        LoadLibrarySymbol(kPrecompiledLibraryName,
+                          kPrecompiledInstructionsSymbolName));
+    data_snapshot = reinterpret_cast<const uint8_t*>(
+        LoadLibrarySymbol(kPrecompiledLibraryName,
+                          kPrecompiledDataSymbolName));
+    ReadSnapshotFile(precompiled_snapshot_directory,
+                     kPrecompiledVmIsolateName,
+                     &vm_isolate_snapshot_buffer);
+    ReadSnapshotFile(precompiled_snapshot_directory,
+                     kPrecompiledIsolateName,
+                     &isolate_snapshot_buffer);
+
+  } else if (run_full_snapshot) {
+    char* vm_snapshot_fname;
+    char* isolate_snapshot_fname;
+
+    // Compute file names.
+    ComputeSnapshotFilenames(snapshot_filename,
+                             &vm_snapshot_fname,
+                             &isolate_snapshot_fname);
+
+    ReadSnapshotFile(NULL, vm_snapshot_fname, &vm_isolate_snapshot_buffer);
+    ReadSnapshotFile(NULL, isolate_snapshot_fname, &isolate_snapshot_buffer);
+    delete vm_snapshot_fname;
+    delete isolate_snapshot_fname;
   }
 
   // Initialize the Dart VM.
   char* error = Dart_Initialize(
-      vm_isolate_snapshot_buffer, instructions_snapshot,
+      vm_isolate_snapshot_buffer, instructions_snapshot, data_snapshot,
       CreateIsolateAndSetup, NULL, NULL, ShutdownIsolate,
       DartUtils::OpenFile,
       DartUtils::ReadFile,
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index f9d3457..b583049 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -188,6 +188,9 @@
         os_error_message != NULL ? os_error_message
                                  : "Cannot get error message");
     if (Dart_IsError(result)) {
+      delete[] string_args;
+      delete[] string_environment;
+      free(os_error_message);
       Dart_PropagateError(result);
     }
   }
@@ -230,7 +233,6 @@
   } else {
     Dart_Handle error = DartUtils::NewDartOSError();
     Process::Kill(pid, 9);
-    if (Dart_IsError(error)) Dart_PropagateError(error);
     Dart_ThrowException(error);
   }
 }
@@ -340,7 +342,6 @@
   result =
       Dart_NewStringFromUTF8(reinterpret_cast<const uint8_t*>(str), len);
   free(str);
-  if (Dart_IsError(result)) Dart_PropagateError(result);
   Dart_SetReturnValue(args, result);
 }
 
@@ -363,13 +364,11 @@
   }
   uint8_t* buffer = NULL;
   Dart_Handle external_array = IOBuffer::Allocate(system_len, &buffer);
-  if (Dart_IsError(external_array)) {
-    free(const_cast<char*>(system_string));
-    Dart_PropagateError(result);
+  if (!Dart_IsError(external_array)) {
+    memmove(buffer, system_string, system_len);
   }
-  memmove(buffer, system_string, system_len);
-  free(const_cast<char*>(system_string));
   Dart_SetReturnValue(args, external_array);
+  free(const_cast<char*>(system_string));
 }
 
 }  // namespace bin
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index 1917b46..60fb2b5 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -188,9 +188,9 @@
                bool runInShell,
                ProcessStartMode mode) : super() {
     if (!connectedResourceHandler) {
-      registerExtension('__getProcesses',
+      registerExtension('ext.dart.io.getProcesses',
                         _ProcessResourceInfo.getStartedProcesses);
-      registerExtension('__getProcessById',
+      registerExtension('ext.dart.io.getProcessById',
                         _ProcessResourceInfo.getProcessInfoMapById);
       connectedResourceHandler = true;
     }
diff --git a/runtime/bin/resources_sources.gypi b/runtime/bin/resources_sources.gypi
deleted file mode 100644
index 91e0255..0000000
--- a/runtime/bin/resources_sources.gypi
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# This file contains all sources for the Resources table.
-{
-  'sources': [
-# Standalone VM service sources.
-    'vmservice/loader.dart',
-    'vmservice/server.dart',
-    'vmservice/vmservice_io.dart',
-  ],
-}
-
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index bfb597b..ec9479a 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -106,7 +106,7 @@
                                                              dart_argv);
   ASSERT(set_vm_flags_success);
   const char* err_msg = Dart::InitOnce(dart::bin::vm_isolate_snapshot_buffer,
-                                       NULL,
+                                       NULL, NULL,
                                        NULL, NULL,
                                        dart::bin::DartUtils::OpenFile,
                                        dart::bin::DartUtils::ReadFile,
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index b1be87c..7d79dc6 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -12,6 +12,7 @@
 
 #include <openssl/bio.h>
 #include <openssl/err.h>
+#include <openssl/pkcs12.h>
 #include <openssl/safestack.h>
 #include <openssl/ssl.h>
 #include <openssl/tls1.h>
@@ -28,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 {
 
@@ -102,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();
 }
 
 
@@ -133,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();
 }
 
 
@@ -170,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);
+  }
 }
 
 
@@ -214,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;
 }
 
 
@@ -270,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);
 }
 
 
@@ -280,17 +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) {
-  if (certificate == NULL) return Dart_Null();
+  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));
@@ -299,14 +361,21 @@
       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;
 }
 
 
 int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) {
-  if (preverify_ok == 1) return 1;
+  if (preverify_ok == 1) {
+    return 1;
+  }
   Dart_Isolate isolate = Dart_CurrentIsolate();
   if (isolate == NULL) {
     FATAL("CertificateCallback called with no current isolate\n");
@@ -318,7 +387,14 @@
   SSLFilter* filter = static_cast<SSLFilter*>(
       SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index));
   Dart_Handle callback = filter->bad_certificate_callback();
-  if (Dart_IsNull(callback)) return 0;
+  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])) {
@@ -347,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);
+  }
 }
 
 
@@ -359,12 +439,12 @@
 }
 
 
-void CheckStatus(int status,
-                 const char* type,
-                 const char* message) {
+void CheckStatus(int status, const char* type, const char* message) {
   // TODO(24183): Take appropriate action on failed calls,
   // throw exception that includes all messages from the error stack.
-  if (status == 1) return;
+  if (status == 1) {
+    return;
+  }
   if (SSL_LOG_STATUS) {
     int error = ERR_get_error();
     Log::PrintErr("Failed: %s status %d", message, status);
@@ -376,68 +456,317 @@
 }
 
 
-void FUNCTION_NAME(SecurityContext_UsePrivateKey)(Dart_NativeArguments args) {
-  SSL_CTX* context = GetSecurityContext(args);
-  Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
-  const char* filename = NULL;
-  if (Dart_IsString(filename_object)) {
-    ThrowIfError(Dart_StringToCString(filename_object, &filename));
-  } else {
-    Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "File argument to SecurityContext.usePrivateKey is not a String"));
+// Where the argument to the constructor is the handle for an object
+// implementing List<int>, this class creates a scope in which a memory-backed
+// BIO is allocated. Leaving the scope cleans up the BIO and the buffer that
+// was used to create it.
+//
+// Do not make Dart_ API calls while in a ScopedMemBIO.
+// Do not call Dart_PropagateError while in a ScopedMemBIO.
+class ScopedMemBIO {
+ public:
+  explicit ScopedMemBIO(Dart_Handle object) {
+    if (!Dart_IsTypedData(object) && !Dart_IsList(object)) {
+      Dart_ThrowException(DartUtils::NewDartArgumentError(
+          "Argument is not a List<int>"));
+    }
+
+    uint8_t* bytes = NULL;
+    intptr_t bytes_len = 0;
+    bool is_typed_data = false;
+    if (Dart_IsTypedData(object)) {
+      is_typed_data = true;
+      Dart_TypedData_Type typ;
+      ThrowIfError(Dart_TypedDataAcquireData(
+          object,
+          &typ,
+          reinterpret_cast<void**>(&bytes),
+          &bytes_len));
+    } else {
+      ASSERT(Dart_IsList(object));
+      ThrowIfError(Dart_ListLength(object, &bytes_len));
+      bytes = Dart_ScopeAllocate(bytes_len);
+      ASSERT(bytes != NULL);
+      ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len));
+    }
+
+    object_ = object;
+    bytes_ = bytes;
+    bytes_len_ = bytes_len;
+    bio_ = BIO_new_mem_buf(bytes, bytes_len);
+    ASSERT(bio_ != NULL);
+    is_typed_data_ = is_typed_data;
   }
-  Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
+
+  ~ScopedMemBIO() {
+    ASSERT(bio_ != NULL);
+    if (is_typed_data_) {
+      BIO_free(bio_);
+      ThrowIfError(Dart_TypedDataReleaseData(object_));
+    } else {
+      BIO_free(bio_);
+    }
+  }
+
+  BIO* bio() {
+    ASSERT(bio_ != NULL);
+    return bio_;
+  }
+
+ private:
+  Dart_Handle object_;
+  uint8_t* bytes_;
+  intptr_t bytes_len_;
+  BIO* bio_;
+  bool is_typed_data_;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO);
+};
+
+
+template<typename T, void (*free_func)(T*)>
+class ScopedSSLType {
+ public:
+  explicit ScopedSSLType(T* obj) : obj_(obj) {}
+
+  ~ScopedSSLType() {
+    if (obj_ != NULL) {
+      free_func(obj_);
+    }
+  }
+
+  T* get() { return obj_; }
+  const T* get() const { return obj_; }
+
+  T* release() {
+    T* result = obj_;
+    obj_ = NULL;
+    return result;
+  }
+
+ private:
+  T* obj_;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ScopedSSLType);
+};
+
+template<typename T, typename E, void (*func)(E*)>
+class ScopedSSLStackType {
+ public:
+  explicit ScopedSSLStackType(T* obj) : obj_(obj) {}
+
+  ~ScopedSSLStackType() {
+    if (obj_ != NULL) {
+      sk_pop_free(reinterpret_cast<_STACK*>(obj_),
+                  reinterpret_cast<void (*)(void *)>(func));
+    }
+  }
+
+  T* get() { return obj_; }
+  const T* get() const { return obj_; }
+
+  T* release() {
+    T* result = obj_;
+    obj_ = NULL;
+    return result;
+  }
+
+ private:
+  T* obj_;
+
+  DISALLOW_ALLOCATION();
+  DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType);
+};
+
+typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12;
+typedef ScopedSSLType<X509, X509_free> ScopedX509;
+
+typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack;
+typedef ScopedSSLStackType<STACK_OF(X509_NAME), X509_NAME, X509_NAME_free>
+    ScopedX509NAMEStack;
+
+
+// We try reading data as PKCS12 only if reading as PEM was unsuccessful and
+// if there is no indication that the data is malformed PEM. We assume the data
+// is malformed PEM if it contains the start line, i.e. a line with ----- BEGIN.
+static bool TryPKCS12(bool pem_success) {
+  uint32_t last_error = ERR_peek_last_error();
+  return !pem_success &&
+      (ERR_GET_LIB(last_error) == ERR_LIB_PEM) &&
+      (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE);
+}
+
+
+static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) {
+  ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+  if (p12.get() == NULL) {
+    return NULL;
+  }
+
+  EVP_PKEY* key = NULL;
+  X509 *cert = NULL;
+  STACK_OF(X509) *ca_certs = NULL;
+  int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
+  if (status == 0) {
+    return NULL;
+  }
+
+  // We only care about the private key.
+  ScopedX509 delete_cert(cert);
+  ScopedX509Stack delete_ca_certs(ca_certs);
+  return key;
+}
+
+
+static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) {
+  EVP_PKEY *key = PEM_read_bio_PrivateKey(
+      bio, NULL, PasswordCallback, const_cast<char*>(password));
+  if (TryPKCS12(key != NULL)) {
+    // Reset the bio, and clear the error from trying to read as PEM.
+    ERR_clear_error();
+    BIO_reset(bio);
+
+    // Try to decode as PKCS12
+    key = GetPrivateKeyPKCS12(bio, password);
+  }
+  return key;
+}
+
+
+static const char* GetPasswordArgument(Dart_NativeArguments args,
+                                       intptr_t index) {
+  Dart_Handle password_object =
+      ThrowIfError(Dart_GetNativeArgument(args, index));
   const char* password = NULL;
   if (Dart_IsString(password_object)) {
     ThrowIfError(Dart_StringToCString(password_object, &password));
     if (strlen(password) > PEM_BUFSIZE - 1) {
       Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "SecurityContext.usePrivateKey password length is greater than"
-        " 1023 (PEM_BUFSIZE)"));
+        "Password length is greater than 1023 (PEM_BUFSIZE)"));
     }
   } else if (Dart_IsNull(password_object)) {
     password = "";
   } else {
     Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "SecurityContext.usePrivateKey password is not a String or null"));
+        "Password is not a String or null"));
   }
-
-  SSL_CTX_set_default_passwd_cb(context, PasswordCallback);
-  SSL_CTX_set_default_passwd_cb_userdata(context, const_cast<char*>(password));
-  int status = SSL_CTX_use_PrivateKey_file(context,
-                                           filename,
-                                           SSL_FILETYPE_PEM);
-  // TODO(24184): Handle different expected errors here - file missing,
-  // incorrect password, file not a PEM, and throw exceptions.
-  // CheckStatus should also throw an exception in uncaught cases.
-  CheckStatus(status, "TlsException", "Failure in usePrivateKey");
-  SSL_CTX_set_default_passwd_cb_userdata(context, NULL);
+  return password;
 }
 
 
-void FUNCTION_NAME(SecurityContext_SetTrustedCertificates)(
+void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
     Dart_NativeArguments args) {
   SSL_CTX* context = GetSecurityContext(args);
-  Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
-  const char* filename = NULL;
-  if (Dart_IsString(filename_object)) {
-    ThrowIfError(Dart_StringToCString(filename_object, &filename));
-  }
-  Dart_Handle directory_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
-  const char* directory = NULL;
-  if (Dart_IsString(directory_object)) {
-    ThrowIfError(Dart_StringToCString(directory_object, &directory));
-  } else if (Dart_IsNull(directory_object)) {
-    directory = NULL;
-  } else {
-    Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "Directory argument to SecurityContext.setTrustedCertificates is not "
-        "a String or null"));
+  const char* password = GetPasswordArgument(args, 2);
+
+  int status;
+  {
+    ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+    EVP_PKEY *key = GetPrivateKey(bio.bio(), password);
+    status = SSL_CTX_use_PrivateKey(context, key);
   }
 
-  int status = SSL_CTX_load_verify_locations(context, filename, directory);
-  CheckStatus(
-      status, "TlsException", "SSL_CTX_load_verify_locations");
+  // TODO(24184): Handle different expected errors here - file missing,
+  // incorrect password, file not a PEM, and throw exceptions.
+  // CheckStatus should also throw an exception in uncaught cases.
+  CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
+}
+
+
+static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context,
+                                             BIO* bio,
+                                             const char* password) {
+  ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+  if (p12.get() == NULL) {
+    return NULL;
+  }
+
+  EVP_PKEY* key = NULL;
+  X509 *cert = NULL;
+  STACK_OF(X509) *ca_certs = NULL;
+  int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
+  if (status == 0) {
+    return status;
+  }
+
+  ScopedX509Stack cert_stack(ca_certs);
+  X509_STORE* store = SSL_CTX_get_cert_store(context);
+  status = X509_STORE_add_cert(store, cert);
+  if (status == 0) {
+    X509_free(cert);
+    return status;
+  }
+
+  X509* ca;
+  while ((ca = sk_X509_shift(cert_stack.get())) != NULL) {
+    status = X509_STORE_add_cert(store, ca);
+    if (status == 0) {
+      X509_free(ca);
+      return status;
+    }
+  }
+
+  return status;
+}
+
+
+static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) {
+  X509_STORE* store = SSL_CTX_get_cert_store(context);
+
+  int status = 0;
+  X509* cert = NULL;
+  while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
+    status = X509_STORE_add_cert(store, cert);
+    if (status == 0) {
+      X509_free(cert);
+      return status;
+    }
+  }
+
+  // If bio does not contain PEM data, the first call to PEM_read_bio_X509 will
+  // return NULL, and the while-loop will exit while status is still 0.
+  uint32_t err = ERR_peek_last_error();
+  if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
+      (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
+    // If bio contains data that is trying to be PEM but is malformed, then
+    // this case will be triggered.
+    status = 0;
+  }
+
+  return status;
+}
+
+
+static int SetTrustedCertificatesBytes(SSL_CTX* context,
+                                       BIO* bio,
+                                       const char* password) {
+  int status = SetTrustedCertificatesBytesPEM(context, bio);
+  if (TryPKCS12(status != 0)) {
+    ERR_clear_error();
+    BIO_reset(bio);
+    status = SetTrustedCertificatesBytesPKCS12(context, bio, password);
+  } else if (status != 0) {
+    // The PEM file was successfully parsed.
+    ERR_clear_error();
+  }
+  return status;
+}
+
+
+void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
+    Dart_NativeArguments args) {
+  SSL_CTX* context = GetSecurityContext(args);
+  const char* password = GetPasswordArgument(args, 2);
+  int status;
+  {
+    ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+    status = SetTrustedCertificatesBytes(context, bio.bio(), password);
+  }
+  CheckStatus(status,
+              "TlsException",
+              "Failure in setTrustedCertificatesBytes");
 }
 
 
@@ -459,39 +788,245 @@
 }
 
 
-void FUNCTION_NAME(SecurityContext_UseCertificateChain)(
-    Dart_NativeArguments args) {
-  SSL_CTX* context = GetSecurityContext(args);
-  Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
-  const char* filename = NULL;
-  if (Dart_IsString(filename_object)) {
-    ThrowIfError(Dart_StringToCString(filename_object, &filename));
-  } else {
-    Dart_ThrowException(DartUtils::NewDartArgumentError(
-        "file argument in SecurityContext.useCertificateChain"
-        " is not a String"));
+static int UseChainBytesPKCS12(SSL_CTX* context,
+                               BIO* bio,
+                               const char* password) {
+  ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+  if (p12.get() == NULL) {
+    return NULL;
   }
-  int status = SSL_CTX_use_certificate_chain_file(context, filename);
-  CheckStatus(status,
-              "TlsException",
-              "Failure in useCertificateChain");
+
+  EVP_PKEY* key = NULL;
+  X509 *cert = NULL;
+  STACK_OF(X509) *ca_certs = NULL;
+  int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
+  if (status == 0) {
+    return status;
+  }
+
+  ScopedX509 x509(cert);
+  ScopedX509Stack certs(ca_certs);
+  status = SSL_CTX_use_certificate(context, x509.get());
+  if (ERR_peek_error() != 0) {
+    // Key/certificate mismatch doesn't imply status is 0.
+    status = 0;
+  }
+  if (status == 0) {
+    return status;
+  }
+
+  SSL_CTX_clear_chain_certs(context);
+
+  X509* ca;
+  while ((ca = sk_X509_shift(certs.get())) != NULL) {
+    status = SSL_CTX_add0_chain_cert(context, ca);
+    if (status == 0) {
+      X509_free(ca);
+      return status;
+    }
+  }
+
+  return status;
 }
 
 
-void FUNCTION_NAME(SecurityContext_SetClientAuthorities)(
+static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) {
+  int status = 0;
+  ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL));
+  if (x509.get() == NULL) {
+    return 0;
+  }
+
+  status = SSL_CTX_use_certificate(context, x509.get());
+  if (ERR_peek_error() != 0) {
+    // Key/certificate mismatch doesn't imply status is 0.
+    status = 0;
+  }
+  if (status == 0) {
+    return status;
+  }
+
+  SSL_CTX_clear_chain_certs(context);
+
+  X509* ca;
+  while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
+    status = SSL_CTX_add0_chain_cert(context, ca);
+    if (status == 0) {
+      X509_free(ca);
+      return status;
+    }
+    // Note that we must not free `ca` if it was successfully added to the
+    // chain. We must free the main certificate x509, though since its reference
+    // count is increased by SSL_CTX_use_certificate.
+  }
+
+  // If bio does not contain PEM data, the first call to PEM_read_bio_X509 will
+  // return NULL, and the while-loop will exit while status is still 0.
+  uint32_t err = ERR_peek_last_error();
+  if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
+      (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
+    // If bio contains data that is trying to be PEM but is malformed, then
+    // this case will be triggered.
+    status = 0;
+  }
+
+  return status;
+}
+
+
+static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) {
+  int status = UseChainBytesPEM(context, bio);
+  if (TryPKCS12(status != 0)) {
+    ERR_clear_error();
+    BIO_reset(bio);
+    status = UseChainBytesPKCS12(context, bio, password);
+  } else if (status != 0) {
+    // The PEM file was successfully read.
+    ERR_clear_error();
+  }
+  return status;
+}
+
+
+void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
     Dart_NativeArguments args) {
   SSL_CTX* context = GetSecurityContext(args);
-  Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
-  const char* filename = NULL;
-  if (Dart_IsString(filename_object)) {
-    ThrowIfError(Dart_StringToCString(filename_object, &filename));
-  } else {
-    Dart_ThrowException(DartUtils::NewDartArgumentError(
-         "file argument in SecurityContext.setClientAuthorities"
-         " is not a String"));
+  const char* password = GetPasswordArgument(args, 2);
+  int status;
+  {
+    ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+    status = UseChainBytes(context, bio.bio(), password);
   }
+  CheckStatus(status,
+              "TlsException",
+              "Failure in useCertificateChainBytes");
+}
+
+
+static STACK_OF(X509_NAME)* GetCertificateNamesPKCS12(BIO* bio,
+                                                      const char* password) {
+  ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
+  if (p12.get() == NULL) {
+    return NULL;
+  }
+
+  ScopedX509NAMEStack result(sk_X509_NAME_new_null());
+  if (result.get() == NULL) {
+    return NULL;
+  }
+
+  EVP_PKEY* key = NULL;
+  X509 *cert = NULL;
+  STACK_OF(X509) *ca_certs = NULL;
+  int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
+  if (status == 0) {
+    return NULL;
+  }
+
+  ScopedX509 x509(cert);
+  ScopedX509Stack certs(ca_certs);
+  X509_NAME* x509_name = X509_get_subject_name(x509.get());
+  if (x509_name == NULL) {
+    return NULL;
+  }
+
+  x509_name = X509_NAME_dup(x509_name);
+  if (x509_name == NULL) {
+    return NULL;
+  }
+
+  sk_X509_NAME_push(result.get(), x509_name);
+
+  while (true) {
+    ScopedX509 ca(sk_X509_shift(certs.get()));
+    if (ca.get() == NULL) {
+      break;
+    }
+
+    X509_NAME* x509_name = X509_get_subject_name(ca.get());
+    if (x509_name == NULL) {
+      return NULL;
+    }
+
+    x509_name = X509_NAME_dup(x509_name);
+    if (x509_name == NULL) {
+      return NULL;
+    }
+
+    sk_X509_NAME_push(result.get(), x509_name);
+  }
+
+  return result.release();
+}
+
+
+static STACK_OF(X509_NAME)* GetCertificateNamesPEM(BIO* bio) {
+  ScopedX509NAMEStack result(sk_X509_NAME_new_null());
+  if (result.get() == NULL) {
+    return NULL;
+  }
+
+  while (true) {
+    ScopedX509 x509(PEM_read_bio_X509(bio, NULL, NULL, NULL));
+    if (x509.get() == NULL) {
+      break;
+    }
+
+    X509_NAME* x509_name = X509_get_subject_name(x509.get());
+    if (x509_name == NULL) {
+      return NULL;
+    }
+
+    // Duplicate the name to put it on the stack.
+    x509_name = X509_NAME_dup(x509_name);
+    if (x509_name == NULL) {
+      return NULL;
+    }
+    sk_X509_NAME_push(result.get(), x509_name);
+  }
+
+  if (sk_X509_NAME_num(result.get()) == 0) {
+    // The data was not PEM.
+    return NULL;
+  }
+
+  uint32_t err = ERR_peek_last_error();
+  if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
+      (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
+    // The data was trying to be PEM, but was malformed.
+    return NULL;
+  }
+
+  return result.release();
+}
+
+
+static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio,
+                                                const char* password) {
+  STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio);
+  if (TryPKCS12(result != NULL)) {
+    ERR_clear_error();
+    BIO_reset(bio);
+    result = GetCertificateNamesPKCS12(bio, password);
+  } else if (result != NULL) {
+    // The PEM file was successfully parsed.
+    ERR_clear_error();
+  }
+  return result;
+}
+
+
+void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
+    Dart_NativeArguments args) {
+  SSL_CTX* context = GetSecurityContext(args);
+  const char* password = GetPasswordArgument(args, 2);
   STACK_OF(X509_NAME)* certificate_names;
-  certificate_names = SSL_load_client_CA_file(filename);
+
+  {
+    ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
+    certificate_names = GetCertificateNames(bio.bio(), password);
+  }
+
   if (certificate_names != NULL) {
     SSL_CTX_set_client_CA_list(context, certificate_names);
   } else {
@@ -692,7 +1227,7 @@
 }
 
 
-void SSLFilter::Init(Dart_Handle dart_this) {
+Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
   if (!library_initialized_) {
     InitializeLibrary();
   }
@@ -706,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");
   }
@@ -733,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;
 }
 
 
@@ -779,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);
 }
 
 
@@ -1022,7 +1594,7 @@
 }
 
 
-void SSLFilter::Destroy() {
+SSLFilter::~SSLFilter() {
   if (ssl_ != NULL) {
     SSL_free(ssl_);
     ssl_ = NULL;
@@ -1036,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 29adef4..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,
@@ -116,12 +118,11 @@
   bool in_handshake_;
   bool is_server_;
   char* hostname_;
-  X509_VERIFY_PARAM* certificate_checking_parameters_;
 
   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 8d0b6bc..455b132 100644
--- a/runtime/bin/secure_socket_patch.dart
+++ b/runtime/bin/secure_socket_patch.dart
@@ -137,14 +137,34 @@
   static final SecurityContext defaultContext =
       new _SecurityContext().._trustBuiltinRoots();
 
-  void usePrivateKey(String keyFile, {String password})
-      native "SecurityContext_UsePrivateKey";
-  void setTrustedCertificates({String file, String directory})
-      native "SecurityContext_SetTrustedCertificates";
-  void useCertificateChain(String file)
-      native "SecurityContext_UseCertificateChain";
-  void setClientAuthorities(String file)
-      native "SecurityContext_SetClientAuthorities";
+  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}) {
+    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 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}) {
+    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);
@@ -178,4 +198,4 @@
   }
   int _startValidity() native "X509_StartValidity";
   int _endValidity() native "X509_EndValidity";
-}
\ No newline at end of file
+}
diff --git a/runtime/bin/secure_socket_unsupported.cc b/runtime/bin/secure_socket_unsupported.cc
index 6bcc55e..91f4fc7 100644
--- a/runtime/bin/secure_socket_unsupported.cc
+++ b/runtime/bin/secure_socket_unsupported.cc
@@ -104,7 +104,8 @@
       "Secure Sockets unsupported on this platform"));
 }
 
-void FUNCTION_NAME(SecurityContext_UsePrivateKey)(Dart_NativeArguments args) {
+void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
+    Dart_NativeArguments args) {
   Dart_ThrowException(DartUtils::NewDartArgumentError(
       "Secure Sockets unsupported on this platform"));
 }
@@ -115,13 +116,13 @@
       "Secure Sockets unsupported on this platform"));
 }
 
-void FUNCTION_NAME(SecurityContext_SetClientAuthorities)(
+void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
     Dart_NativeArguments args) {
   Dart_ThrowException(DartUtils::NewDartArgumentError(
       "Secure Sockets unsupported on this platform"));
 }
 
-void FUNCTION_NAME(SecurityContext_SetTrustedCertificates)(
+void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
     Dart_NativeArguments args) {
   Dart_ThrowException(DartUtils::NewDartArgumentError(
       "Secure Sockets unsupported on this platform"));
@@ -133,7 +134,7 @@
       "Secure Sockets unsupported on this platform"));
 }
 
-void FUNCTION_NAME(SecurityContext_UseCertificateChain)(
+void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
     Dart_NativeArguments args) {
   Dart_ThrowException(DartUtils::NewDartArgumentError(
       "Secure Sockets unsupported on this platform"));
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index b0b6a34..87f39f6 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -293,9 +293,7 @@
     }
   } else {
     OSError os_error(-1, "Invalid argument", OSError::kUnknown);
-    Dart_Handle err = DartUtils::NewDartOSError(&os_error);
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
   }
 }
 
@@ -362,7 +360,6 @@
                   DartUtils::NewString("_makeDatagram"),
                   kNumArgs,
                   dart_args);
-  if (Dart_IsError(result)) Dart_PropagateError(result);
   Dart_SetReturnValue(args, result);
 }
 
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 7de16a9..1ec51b7 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -932,9 +932,9 @@
       eventPort = new RawReceivePort(multiplex);
     }
     if (!connectedResourceHandler) {
-      registerExtension('__getOpenSockets',
+      registerExtension('ext.dart.io.getOpenSockets',
                         _SocketResourceInfo.getOpenSockets);
-      registerExtension('__getSocketByID',
+      registerExtension('ext.dart.io.getSocketByID',
                         _SocketResourceInfo.getSocketInfoMapByID);
 
       connectedResourceHandler = true;
@@ -1243,9 +1243,11 @@
     native.isClosedWrite = true;
     if (fd != null) _getStdioHandle(native, fd);
     var result = new _RawSocket(native);
-    result._isMacOSTerminalInput =
-        Platform.isMacOS &&
-        _StdIOUtils._socketType(result._socket) == _STDIO_HANDLE_TYPE_TERMINAL;
+    if (fd != null) {
+      var socketType = _StdIOUtils._socketType(result._socket);
+      result._isMacOSTerminalInput =
+          Platform.isMacOS && socketType == _STDIO_HANDLE_TYPE_TERMINAL;
+    }
     return result;
   }
 
diff --git a/runtime/bin/stdio.cc b/runtime/bin/stdio.cc
index f0dc923..c866710 100644
--- a/runtime/bin/stdio.cc
+++ b/runtime/bin/stdio.cc
@@ -47,14 +47,13 @@
 void FUNCTION_NAME(Stdout_GetTerminalSize)(Dart_NativeArguments args) {
   if (!Dart_IsInteger(Dart_GetNativeArgument(args, 0))) {
     OSError os_error(-1, "Invalid argument", OSError::kUnknown);
-    Dart_Handle err = DartUtils::NewDartOSError(&os_error);
-    if (Dart_IsError(err)) Dart_PropagateError(err);
-    Dart_SetReturnValue(args, err);
+    Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
     return;
   }
   intptr_t fd = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
   if (fd != 1 && fd != 2) {
-    Dart_PropagateError(Dart_NewApiError("Terminal fd must be 1 or 2"));
+    Dart_SetReturnValue(args, Dart_NewApiError("Terminal fd must be 1 or 2"));
+    return;
   }
 
   int size[2];
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/bin/vmservice/loader.dart b/runtime/bin/vmservice/loader.dart
index 9b7355e..7bec4a1 100644
--- a/runtime/bin/vmservice/loader.dart
+++ b/runtime/bin/vmservice/loader.dart
@@ -57,8 +57,7 @@
     _sendResourceResponse(sp, id, data);
   },
   onError: (e) {
-    var err = "Error loading $uri:\n  $e";
-    _sendResourceResponse(sp, id, err);
+    _sendResourceResponse(sp, id, e.toString());
   });
 }
 
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index 69e9b2e..c8334da 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -157,7 +157,6 @@
             '${request.uri}\n$e\n');
       rethrow;
     }
-
   }
 
   Future startup() {
@@ -166,26 +165,29 @@
       return new Future.value(this);
     }
 
+    var address = new InternetAddress(_ip);
     // Startup HTTP server.
-    return HttpServer.bind(_ip, _port).then((s) {
+    return HttpServer.bind(address, _port).then((s) {
       _server = s;
-      _server.listen(_requestHandler);
+      _server.listen(_requestHandler, cancelOnError: true);
       var ip = _server.address.address.toString();
+      var port = _server.port.toString();
       if (_displayMessages) {
-        var port = _server.port.toString();
         print('Observatory listening on http://$ip:$port');
       }
       // Server is up and running.
       _notifyServerState(ip, _server.port);
+      onServerAddressChange('http://$ip:$port');
       return this;
     }).catchError((e, st) {
       print('Could not start Observatory HTTP server:\n$e\n$st\n');
       _notifyServerState("", 0);
+      onServerAddressChange(null);
       return this;
     });
   }
 
-  close(bool force) {
+  Future cleanup(bool force) {
     if (_server == null) {
       return new Future.value(null);
     }
@@ -204,17 +206,19 @@
     // Shutdown HTTP server and subscription.
     var ip = _server.address.address.toString();
     var port = _server.port.toString();
-    return close(forced).then((_) {
+    return cleanup(forced).then((_) {
       if (_displayMessages) {
         print('Observatory no longer listening on http://$ip:$port');
       }
       _server = null;
       _notifyServerState("", 0);
+      onServerAddressChange(null);
       return this;
     }).catchError((e, st) {
       _server = null;
       print('Could not shutdown Observatory HTTP server:\n$e\n$st\n');
       _notifyServerState("", 0);
+      onServerAddressChange(null);
       return this;
     });
   }
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 3816aa2..ba82441 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -21,45 +21,40 @@
 bool _autoStart;
 
 bool _isWindows = false;
-
 var _signalWatch;
 var _signalSubscription;
 
 // HTTP server.
 Server server;
 Future<Server> serverFuture;
-HashMap<String, Asset> _assets;
-HashMap<String, Asset> get assets {
-  if (_assets == null) {
-    try {
-      _assets = Asset.request();
-    } catch (e) {
-      print('Could not load Observatory assets: $e');
-    }
-  }
-  return _assets;
-}
 
-_onShutdown() {
+_lazyServerBoot() {
   if (server != null) {
-    server.close(true).catchError((e, st) {
-      print("Error in vm-service shutdown: $e\n$st\n");
-    });
+    return;
   }
-  if (_signalSubscription != null) {
-    _signalSubscription.cancel();
-    _signalSubscription = null;
-  }
-}
-
-_bootServer() {
   // Lazily create service.
   var service = new VMService();
-  service.onShutdown = _onShutdown;
   // Lazily create server.
   server = new Server(service, _ip, _port);
 }
 
+Future cleanupCallback() async {
+  // Cancel the sigquit subscription.
+  if (_signalSubscription != null) {
+    await _signalSubscription.cancel();
+    _signalSubscription = null;
+  }
+  if (server != null) {
+    try {
+      await server.cleanup(true);
+    } catch (e, st) {
+      print("Error in vm-service shutdown: $e\n$st\n");
+    }
+  }
+  // Call out to embedder's shutdown callback.
+  _shutdown();
+}
+
 _clearFuture(_) {
   serverFuture = null;
 }
@@ -69,9 +64,7 @@
     // Still waiting.
     return;
   }
-  if (server == null) {
-    _bootServer();
-  }
+  _lazyServerBoot();
   // Toggle HTTP server.
   if (server.running) {
     serverFuture = server.shutdown(true).then(_clearFuture);
@@ -81,6 +74,10 @@
 }
 
 _registerSignalHandler() {
+  if (_signalWatch == null) {
+    // Cannot register for signals.
+    return;
+  }
   if (_isWindows) {
     // Cannot register for signals on Windows.
     return;
@@ -88,28 +85,23 @@
   _signalSubscription = _signalWatch(ProcessSignal.SIGQUIT).listen(_onSignal);
 }
 
-const _shortDelay = const Duration(milliseconds: 10);
-
 main() {
+  // Set embedder hooks.
+  VMServiceEmbedderHooks.cleanup = cleanupCallback;
   if (_autoStart) {
-    _bootServer();
+    _lazyServerBoot();
     server.startup();
     // It's just here to push an event on the event loop so that we invoke the
     // scheduled microtasks.
     Timer.run(() {});
   }
-  // TODO(johnmccutchan, turnidge) Creating a VMService object here causes
-  // strange behavior from the legacy debug protocol and coverage tool.
-  // Enable this code, and remove the call to Isolate::KillIsolate() from
-  // service_isolate.cc when the strange behavior is solved.
-  // See: https://github.com/dart-lang/sdk/issues/23977
-  // else {
-  //   var service = new VMService();
-  //   service.onShutdown = _onShutdown;
-  // }
+  // TODO(johnmccutchan): Fixup service isolate shutdown in the general case.
+  // See ServiceIsolate::KillServiceIsolate and ServiceIsolate::Shutdown.
   scriptLoadPort.handler = _processLoadRequest;
   // Register signal handler after a small delay to avoid stalling main
   // isolate startup.
-  new Timer(_shortDelay, _registerSignalHandler);
+  new Timer(shortDelay, _registerSignalHandler);
   return scriptLoadPort;
 }
+
+_shutdown() native "VMServiceIO_Shutdown";
diff --git a/runtime/bin/vmservice/vmservice_sources.gypi b/runtime/bin/vmservice/vmservice_sources.gypi
new file mode 100644
index 0000000..a7d06cd
--- /dev/null
+++ b/runtime/bin/vmservice/vmservice_sources.gypi
@@ -0,0 +1,13 @@
+# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This file contains all Dart sources for the dart:io implementation of
+# the VM Service server.
+{
+  'sources': [
+    'loader.dart',
+    'server.dart',
+    'vmservice_io.dart',
+  ],
+}
diff --git a/runtime/bin/vmservice_dartium.cc b/runtime/bin/vmservice_dartium.cc
index cd2c87f..2a9fc8f 100644
--- a/runtime/bin/vmservice_dartium.cc
+++ b/runtime/bin/vmservice_dartium.cc
@@ -43,12 +43,15 @@
 Dart_Isolate VmServiceServer::CreateIsolate(const uint8_t* snapshot_buffer) {
   ASSERT(snapshot_buffer != NULL);
   // Create the isolate.
+  IsolateData* isolate_data = new IsolateData(DART_VM_SERVICE_ISOLATE_NAME,
+                                              NULL,
+                                              NULL);
   char* error = 0;
   Dart_Isolate isolate = Dart_CreateIsolate(DART_VM_SERVICE_ISOLATE_NAME,
                                             "main",
                                             snapshot_buffer,
                                             NULL,
-                                            NULL,
+                                            isolate_data,
                                             &error);
   if (!isolate) {
     fprintf(stderr, "Dart_CreateIsolate failed: %s\n", error);
@@ -59,18 +62,6 @@
   Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
   Builtin::SetNativeResolver(Builtin::kIOLibrary);
 
-  Dart_Handle builtin_lib =
-      Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-  CHECK_RESULT(builtin_lib);
-
-  Dart_Handle result;
-
-  // Prepare for script loading by setting up the 'print' and 'timer'
-  // closures and setting up 'package root' for URI resolution.
-  result = DartUtils::PrepareForScriptLoading(
-      NULL, NULL, true, false, builtin_lib);
-  CHECK_RESULT(result);
-
   ASSERT(Dart_IsServiceIsolate(isolate));
   if (!VmService::Setup(DEFAULT_VM_SERVICE_SERVER_IP,
                         DEFAULT_VM_SERVICE_SERVER_PORT,
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 0c0a63c..08fd57a 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -115,6 +115,11 @@
   Dart_ExitScope();
 }
 
+
+static void Shutdown(Dart_NativeArguments args) {
+  // NO-OP.
+}
+
 struct VmServiceIONativeEntry {
   const char* name;
   int num_arguments;
@@ -124,6 +129,7 @@
 
 static VmServiceIONativeEntry _VmServiceIONativeEntries[] = {
   {"VMServiceIO_NotifyServerState", 2, NotifyServerState},
+  {"VMServiceIO_Shutdown", 0, Shutdown },
 };
 
 
@@ -176,14 +182,10 @@
 
   Dart_Handle result;
 
-  Dart_Handle builtin_lib =
-      Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-  SHUTDOWN_ON_ERROR(builtin_lib);
-
-  // Prepare for script loading by setting up the 'print' and 'timer'
-  // closures and setting up 'package root' for URI resolution.
-  result = DartUtils::PrepareForScriptLoading(
-      NULL, NULL, true, false, builtin_lib);
+  // Prepare builtin and its dependent libraries for use to resolve URIs.
+  // Set up various closures, e.g: printing, timers etc.
+  // Set up 'package root' for URI resolution.
+  result = DartUtils::PrepareForScriptLoading(true, false);
   SHUTDOWN_ON_ERROR(result);
 
   if (running_precompiled) {
diff --git a/runtime/bin/zlib.gyp b/runtime/bin/zlib.gyp
index 6f2f913..98555f9f 100644
--- a/runtime/bin/zlib.gyp
+++ b/runtime/bin/zlib.gyp
@@ -20,7 +20,6 @@
     'zlib_path': '../../third_party/zlib',
   },
   # Added by Dart.  We do not indent, so diffs with the original are clearer.
-  'conditions': [[ 'dart_io_support==1', {
   'targets': [
     {
       'target_name': 'zlib_dart',  # Added by Dart (the _dart postfix)
@@ -72,5 +71,4 @@
       ],
     },
   ],
-  }]],
 }
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index 707686f..f976190 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -17,6 +17,8 @@
 
     'libdart_deps': ['libdart_lib_nosnapshot', 'libdart_lib',
                      'libdart_vm_nosnapshot', 'libdart_vm',
+                     'libdart_vm_noopt',
+                     'libdart_vm_precompiled_runtime',
                      'libdouble_conversion',],
   },
   'targets': [
@@ -55,11 +57,11 @@
       },
     },
     {
-      'target_name': 'libdart_precompiled',
+      'target_name': 'libdart_noopt',
       'type': 'static_library',
       'dependencies': [
         'libdart_lib',
-        'libdart_vm_precompiled',
+        'libdart_vm_noopt',
         'libdouble_conversion',
         'generate_version_cc_file#host',
       ],
@@ -81,7 +83,42 @@
       'defines': [
         # The only effect of DART_SHARED_LIB is to export the Dart API entries.
         'DART_SHARED_LIB',
-        'DART_PRECOMPILED',
+        'DART_PRECOMPILER',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          'include',
+        ],
+      },
+    },
+    {
+      'target_name': 'libdart_precompiled_runtime',
+      'type': 'static_library',
+      'dependencies': [
+        'libdart_lib_precompiled_runtime',
+        'libdart_vm_precompiled_runtime',
+        'libdouble_conversion',
+        'generate_version_cc_file#host',
+      ],
+      'include_dirs': [
+        '.',
+      ],
+      'sources': [
+        'include/dart_api.h',
+        'include/dart_mirrors_api.h',
+        'include/dart_native_api.h',
+        'include/dart_tools_api.h',
+        'vm/dart_api_impl.cc',
+        'vm/debugger_api_impl.cc',
+        'vm/mirrors_api_impl.cc',
+        'vm/native_api_impl.cc',
+        'vm/version.h',
+        '<(version_cc_file)',
+      ],
+      'defines': [
+        # The only effect of DART_SHARED_LIB is to export the Dart API entries.
+        'DART_SHARED_LIB',
+        'DART_PRECOMPILED_RUNTIME',
       ],
       'direct_dependent_settings': {
         'include_dirs': [
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 4249382..77d1289 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -144,19 +144,27 @@
  * by Dart_Error and exit the program.
  *
  * When an error is returned while in the body of a native function,
- * it can be propagated by calling Dart_PropagateError.  Errors should
- * be propagated unless there is a specific reason not to.  If an
- * error is not propagated then it is ignored.  For example, if an
- * unhandled exception error is ignored, that effectively "catches"
- * the unhandled exception.  Fatal errors must always be propagated.
+ * it can be propagated up the call stack by calling
+ * Dart_PropagateError, Dart_SetReturnValue, or Dart_ThrowException.
+ * Errors should be propagated unless there is a specific reason not
+ * to.  If an error is not propagated then it is ignored.  For
+ * example, if an unhandled exception error is ignored, that
+ * effectively "catches" the unhandled exception.  Fatal errors must
+ * always be propagated.
  *
- * Note that a call to Dart_PropagateError never returns.  Instead it
- * transfers control non-locally using a setjmp-like mechanism.  This
- * can be inconvenient if you have resources that you need to clean up
- * before propagating the error.  When an error is propagated, any
- * current scopes created by Dart_EnterScope will be exited.
+ * When an error is propagated, any current scopes created by
+ * Dart_EnterScope will be exited.
  *
- * To deal with this inconvenience, we often return error handles
+ * Using Dart_SetReturnValue to propagate an exception is somewhat
+ * more convenient than using Dart_PropagateError, and should be
+ * preferred for reasons discussed below.
+ *
+ * Dart_PropagateError and Dart_ThrowException do not return.  Instead
+ * they transfer control non-locally using a setjmp-like mechanism.
+ * This can be inconvenient if you have resources that you need to
+ * clean up before propagating the error.
+ *
+ * When relying on Dart_PropagateError, we often return error handles
  * rather than propagating them from helper functions.  Consider the
  * following contrived example:
  *
@@ -191,6 +199,38 @@
  * helper function returns the error handle to the caller, giving the
  * caller a chance to clean up before propagating the error handle.
  *
+ * When an error is propagated by calling Dart_SetReturnValue, the
+ * native function will be allowed to complete normally and then the
+ * exception will be propagated only once the native call
+ * returns. This can be convenient, as it allows the C code to clean
+ * up normally.
+ *
+ * The example can be written more simply using Dart_SetReturnValue to
+ * propagate the error.
+ *
+ * 1    Dart_Handle isLongStringHelper(Dart_Handle arg) {
+ * 2      intptr_t* length = 0;
+ * 3      result = Dart_StringLength(arg, &length);
+ * 4      if (Dart_IsError(result)) {
+ * 5        return result
+ * 6      }
+ * 7      return Dart_NewBoolean(length > 100);
+ * 8    }
+ * 9
+ * 10   void NativeFunction_isLongString(Dart_NativeArguments args) {
+ * 11     Dart_EnterScope();
+ * 12     AllocateMyResource();
+ * 13     Dart_Handle arg = Dart_GetNativeArgument(args, 0);
+ * 14     Dart_SetReturnValue(isLongStringHelper(arg));
+ * 15     FreeMyResource();
+ * 16     Dart_ExitScope();
+ * 17   }
+ *
+ * In this example, the call to Dart_SetReturnValue on line 14 will
+ * either return the normal return value or the error (potentially
+ * generated on line 3).  The call to FreeMyResource on line 15 will
+ * execute in either case.
+ *
  * --- Local and persistent handles ---
  *
  * Local handles are allocated within the current scope (see
@@ -757,6 +797,7 @@
 DART_EXPORT char* Dart_Initialize(
     const uint8_t* vm_isolate_snapshot,
     const uint8_t* instructions_snapshot,
+    const uint8_t* data_snapshot,
     Dart_IsolateCreateCallback create,
     Dart_IsolateInterruptCallback interrupt,
     Dart_IsolateUnhandledExceptionCallback unhandled_exception,
@@ -1038,6 +1079,94 @@
  * is impossible to mess up. */
 
 /**
+ * Query the current message notify callback for the isolate.
+ *
+ * \return The current message notify callback for the isolate.
+ */
+DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback();
+
+/**
+ * The VM's default message handler supports pausing an isolate before it
+ * processes the first message and right after the it processes the isolate's
+ * final message. This can be controlled for all isolates by two VM flags:
+ *
+ *   `--pause-isolates-on-start`
+ *   `--pause-isolates-on-exit`
+ *
+ * Additionally, Dart_SetShouldPauseOnStart and Dart_SetShouldPauseOnExit can be
+ * used to control this behaviour on a per-isolate basis.
+ *
+ * When an embedder is using a Dart_MessageNotifyCallback the embedder
+ * needs to cooperate with the VM so that the service protocol can report
+ * accurate information about isolates and so that tools such as debuggers
+ * work reliably.
+ *
+ * The following functions can be used to implement pausing on start and exit.
+ */
+
+/**
+ * If the VM flag `--pause-isolates-on-start` was passed this will be true.
+ *
+ * \return A boolean value indicating if pause on start was requested.
+ */
+DART_EXPORT bool Dart_ShouldPauseOnStart();
+
+/**
+ * Override the VM flag `--pause-isolates-on-start` for the current isolate.
+ *
+ * \param should_pause Should the isolate be paused on start?
+ *
+ * NOTE: This must be called before Dart_IsolateMakeRunnable.
+ */
+DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause);
+
+/**
+ * Is the current isolate paused on start?
+ *
+ * \return A boolean value indicating if the isolate is paused on start.
+ */
+DART_EXPORT bool Dart_IsPausedOnStart();
+
+/**
+ * Called when the embedder has paused the current isolate on start and when
+ * the embedder has resumed the isolate.
+ *
+ * \param paused Is the isolate paused on start?
+ */
+DART_EXPORT void Dart_SetPausedOnStart(bool paused);
+
+/**
+ * If the VM flag `--pause-isolates-on-exit` was passed this will be true.
+ *
+ * \return A boolean value indicating if pause on exit was requested.
+ */
+DART_EXPORT bool Dart_ShouldPauseOnExit();
+
+/**
+ * Override the VM flag `--pause-isolates-on-exit` for the current isolate.
+ *
+ * \param should_pause Should the isolate be paused on exit?
+ *
+ */
+DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause);
+
+/**
+ * Is the current isolate paused on exit?
+ *
+ * \return A boolean value indicating if the isolate is paused on exit.
+ */
+DART_EXPORT bool Dart_IsPausedOnExit();
+
+/**
+ * Called when the embedder has paused the current isolate on exit and when
+ * the embedder has resumed the isolate.
+ *
+ * \param paused Is the isolate paused on exit?
+ */
+DART_EXPORT void Dart_SetPausedOnExit(bool paused);
+
+
+/**
  * Handles the next pending message for the current isolate.
  *
  * May generate an unhandled exception error.
@@ -1047,6 +1176,15 @@
 DART_EXPORT Dart_Handle Dart_HandleMessage();
 
 /**
+ * Handles all pending messages for the current isolate.
+ *
+ * May generate an unhandled exception error.
+ *
+ * \return A valid handle if no error occurs during the operation.
+ */
+DART_EXPORT Dart_Handle Dart_HandleMessages();
+
+/**
  * Handles any pending messages for the vm service for the current
  * isolate.
  *
@@ -2143,6 +2281,10 @@
  * appropriate 'catch' block is found, executing 'finally' blocks,
  * etc.
  *
+ * If an error handle is passed into this function, the error is
+ * propagated immediately.  See Dart_PropagateError for a discussion
+ * of error propagation.
+ *
  * If successful, this function does not return. Note that this means
  * that the destructors of any stack-allocated C++ objects will not be
  * called. If there are no Dart frames on the stack, an error occurs.
@@ -2380,6 +2522,10 @@
 
 /**
  * Sets the return value for a native function.
+ *
+ * If retval is an Error handle, then error will be propagated once
+ * the native functions exits. See Dart_PropagateError for a
+ * discussion of how different types of errors are propagated.
  */
 DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args,
                                      Dart_Handle retval);
diff --git a/runtime/lib/async_patch.dart b/runtime/lib/async_patch.dart
index fdeb5c9..346e50d 100644
--- a/runtime/lib/async_patch.dart
+++ b/runtime/lib/async_patch.dart
@@ -86,7 +86,7 @@
     scheduleMicrotask(runBody);
   }
 
-  // Adds element to steam, returns true if the caller should terminate
+  // Adds element to stream, returns true if the caller should terminate
   // execution of the generator.
   //
   // TODO(hausner): Per spec, the generator should be suspended before
@@ -177,7 +177,12 @@
     }
     if (cancellationCompleter == null) {
       cancellationCompleter = new Completer();
-      scheduleGenerator();
+      // Only resume the generator if it is suspended at a yield.
+      // Cancellation does not affect an async generator that is
+      // suspended at an await.
+      if (isSuspendedAtYield) {
+        scheduleGenerator();
+      }
     }
     return cancellationCompleter.future;
   }
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 224d532..13f7513 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -40,9 +40,13 @@
 class _SyncIterator implements Iterator {
   bool isYieldEach;  // Set by generated code for the yield* statement.
   Iterator yieldEachIterator;
-  var current;  // Set by generated code for the yield and yield* statement.
+  var _current;  // Set by generated code for the yield and yield* statement.
   SyncGeneratorCallback moveNextFn;
 
+  get current => yieldEachIterator != null
+      ? yieldEachIterator.current
+      : _current;
+
   _SyncIterator(this.moveNextFn);
 
   bool moveNext() {
@@ -52,21 +56,22 @@
     while(true) {
       if (yieldEachIterator != null) {
         if (yieldEachIterator.moveNext()) {
-          current = yieldEachIterator.current;
           return true;
         }
         yieldEachIterator = null;
       }
       isYieldEach = false;
+      // moveNextFn() will update the values of isYieldEach and _current.
       if (!moveNextFn(this)) {
         moveNextFn = null;
-        current = null;
+        _current = null;
         return false;
       }
       if (isYieldEach) {
         // Spec mandates: it is a dynamic error if the class of [the object
         // returned by yield*] does not implement Iterable.
-        yieldEachIterator = (current as Iterable).iterator;
+        yieldEachIterator = (_current as Iterable).iterator;
+        _current = null;
         continue;
       }
       return true;
diff --git a/runtime/lib/core_sources.gypi b/runtime/lib/core_sources.gypi
index 73a4e04..bef056e 100644
--- a/runtime/lib/core_sources.gypi
+++ b/runtime/lib/core_sources.gypi
@@ -47,6 +47,7 @@
     'resource_patch.dart',
     'stacktrace.cc',
     'stacktrace.dart',
+    'stacktrace.h',
     'stopwatch.cc',
     'stopwatch_patch.dart',
     'string.cc',
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index ead1de1..e47e8ef 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -8,6 +8,7 @@
 
 #include "vm/debugger.h"
 #include "vm/exceptions.h"
+#include "vm/flags.h"
 #include "vm/native_entry.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
@@ -21,7 +22,7 @@
   GET_NON_NULL_NATIVE_ARGUMENT(Bool, when, arguments->NativeArgAt(0));
   GET_NATIVE_ARGUMENT(String, msg, arguments->NativeArgAt(1));
   Debugger* debugger = isolate->debugger();
-  if (!debugger) {
+  if (!FLAG_support_debugger || !debugger) {
     return when.raw();
   }
   if (when.value()) {
@@ -33,12 +34,17 @@
 
 DEFINE_NATIVE_ENTRY(Developer_inspect, 1) {
   GET_NATIVE_ARGUMENT(Instance, inspectee, arguments->NativeArgAt(0));
-  Service::SendInspectEvent(isolate, inspectee);
+  if (FLAG_support_service) {
+    Service::SendInspectEvent(isolate, inspectee);
+  }
   return inspectee.raw();
 }
 
 
 DEFINE_NATIVE_ENTRY(Developer_log, 8) {
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(String, message, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, timestamp, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, sequence, arguments->NativeArgAt(2));
@@ -61,6 +67,9 @@
 
 
 DEFINE_NATIVE_ENTRY(Developer_postEvent, 2) {
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(String, event_kind, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(String, event_data, arguments->NativeArgAt(1));
   Service::SendExtensionEvent(isolate, event_kind, event_data);
@@ -69,12 +78,18 @@
 
 
 DEFINE_NATIVE_ENTRY(Developer_lookupExtension, 1) {
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
   return isolate->LookupServiceExtensionHandler(name);
 }
 
 
 DEFINE_NATIVE_ENTRY(Developer_registerExtension, 2) {
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, handler, arguments->NativeArgAt(1));
   isolate->RegisterServiceExtensionHandler(name, handler);
diff --git a/runtime/lib/developer.dart b/runtime/lib/developer.dart
index af505ff..f7b45f0 100644
--- a/runtime/lib/developer.dart
+++ b/runtime/lib/developer.dart
@@ -67,7 +67,8 @@
               List<String> parameterKeys,
               List<String> parameterValues,
               SendPort replyPort,
-              Object id) {
+              Object id,
+              bool trace_service) {
   var parameters = {};
   for (var i = 0; i < parameterKeys.length; i++) {
     parameters[parameterKeys[i]] = parameterValues[i];
@@ -80,14 +81,14 @@
     response = new ServiceExtensionResponse.error(
         ServiceExtensionResponse.kExtensionError,
         errorDetails);
-    _postResponse(replyPort, id, response);
+    _postResponse(replyPort, id, response, trace_service);
     return;
   }
   if (response is! Future) {
     response = new ServiceExtensionResponse.error(
           ServiceExtensionResponse.kExtensionError,
           "Extension handler must return a Future");
-    _postResponse(replyPort, id, response);
+    _postResponse(replyPort, id, response, trace_service);
     return;
   }
   response.catchError((e, st) {
@@ -104,7 +105,7 @@
           ServiceExtensionResponse.kExtensionError,
           "Extension handler must complete to a ServiceExtensionResponse");
     }
-    _postResponse(replyPort, id, response);
+    _postResponse(replyPort, id, response, trace_service);
   }).catchError((e, st) {
     // We do not expect any errors to occur in the .then or .catchError blocks
     // but, suppress them just in case.
@@ -114,9 +115,13 @@
 // This code is only invoked by _runExtension.
 _postResponse(SendPort replyPort,
               Object id,
-              ServiceExtensionResponse response) {
+              ServiceExtensionResponse response,
+              bool trace_service) {
   assert(replyPort != null);
   if (id == null) {
+    if (trace_service) {
+      print("vm-service: posting no response for request");
+    }
     // No id -> no response.
     replyPort.send(null);
     return;
@@ -125,8 +130,14 @@
   StringBuffer sb = new StringBuffer();
   sb.write('{"jsonrpc":"2.0",');
   if (response._isError()) {
+    if (trace_service) {
+      print("vm-service: posting error response for request $id");
+    }
     sb.write('"error":');
   } else {
+    if (trace_service) {
+      print("vm-service: posting response for request $id");
+    }
     sb.write('"result":');
   }
   sb.write('${response._toString()},');
diff --git a/runtime/lib/errors.cc b/runtime/lib/errors.cc
index c7a2164..785950b 100644
--- a/runtime/lib/errors.cc
+++ b/runtime/lib/errors.cc
@@ -17,10 +17,10 @@
 DEFINE_NATIVE_ENTRY(AssertionError_throwNew, 2) {
   // No need to type check the arguments. This function can only be called
   // internally from the VM.
-  intptr_t assertion_start =
-      Smi::CheckedHandle(arguments->NativeArgAt(0)).Value();
-  intptr_t assertion_end =
-      Smi::CheckedHandle(arguments->NativeArgAt(1)).Value();
+  const TokenPosition assertion_start =
+      TokenPosition(Smi::CheckedHandle(arguments->NativeArgAt(0)).Value());
+  const TokenPosition assertion_end =
+      TokenPosition(Smi::CheckedHandle(arguments->NativeArgAt(1)).Value());
 
   const Array& args = Array::Handle(Array::New(4));
 
@@ -60,15 +60,16 @@
 DEFINE_NATIVE_ENTRY(TypeError_throwNew, 5) {
   // No need to type check the arguments. This function can only be called
   // internally from the VM.
-  intptr_t location = Smi::CheckedHandle(arguments->NativeArgAt(0)).Value();
+  const TokenPosition location =
+      TokenPosition(Smi::CheckedHandle(arguments->NativeArgAt(0)).Value());
   const Instance& src_value =
       Instance::CheckedHandle(arguments->NativeArgAt(1));
   const String& dst_type_name =
       String::CheckedHandle(arguments->NativeArgAt(2));
   const String& dst_name = String::CheckedHandle(arguments->NativeArgAt(3));
   const String& error_msg = String::CheckedHandle(arguments->NativeArgAt(4));
-  const String& src_type_name =
-      String::Handle(Type::Handle(src_value.GetType()).UserVisibleName());
+  const String& src_type_name = String::Handle(
+      AbstractType::Handle(src_value.GetType()).UserVisibleName());
   Exceptions::CreateAndThrowTypeError(location, src_type_name,
                                       dst_type_name, dst_name, error_msg);
   UNREACHABLE();
@@ -81,7 +82,7 @@
 // Return value: none, throws an exception.
 DEFINE_NATIVE_ENTRY(FallThroughError_throwNew, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_pos, arguments->NativeArgAt(0));
-  intptr_t fallthrough_pos = smi_pos.Value();
+  TokenPosition fallthrough_pos = TokenPosition(smi_pos.Value());
 
   const Array& args = Array::Handle(Array::New(2));
 
@@ -107,7 +108,7 @@
 DEFINE_NATIVE_ENTRY(AbstractClassInstantiationError_throwNew, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, smi_pos, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(String, class_name, arguments->NativeArgAt(1));
-  intptr_t error_pos = smi_pos.Value();
+  TokenPosition error_pos = TokenPosition(smi_pos.Value());
 
   const Array& args = Array::Handle(Array::New(3));
 
diff --git a/runtime/lib/errors_patch.dart b/runtime/lib/errors_patch.dart
index 59a61ec..0165ed9 100644
--- a/runtime/lib/errors_patch.dart
+++ b/runtime/lib/errors_patch.dart
@@ -362,18 +362,3 @@
     return msg_buf.toString();
   }
 }
-
-class _JavascriptIntegerOverflowError extends Error {
-  final Object _value;
-
-  _JavascriptIntegerOverflowError(this._value);
-  String toString() => "Javascript Integer Overflow: $_value";
-}
-
-class _JavascriptCompatibilityError extends Error {
-  final String _msg;
-
-  _JavascriptCompatibilityError(this._msg);
-  String toString() => "Javascript Compatibility Error: $_msg";
-}
-
diff --git a/runtime/lib/expando_patch.dart b/runtime/lib/expando_patch.dart
index 0c9427c..df0234d 100644
--- a/runtime/lib/expando_patch.dart
+++ b/runtime/lib/expando_patch.dart
@@ -131,7 +131,8 @@
          (object is bool) ||
          (object is num) ||
          (object is String)) {
-      throw new ArgumentError(object);
+      throw new ArgumentError.value(object,
+          "Expandos are not allowed on strings, numbers, booleans or null");
     }
   }
 
diff --git a/runtime/lib/function.cc b/runtime/lib/function.cc
index 607e29e..b7424f5 100644
--- a/runtime/lib/function.cc
+++ b/runtime/lib/function.cc
@@ -28,21 +28,21 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(FunctionImpl_equals, 2) {
-  const Instance& receiver = Instance::CheckedHandle(
+DEFINE_NATIVE_ENTRY(Closure_equals, 2) {
+  const Closure& receiver = Closure::CheckedHandle(
       zone, arguments->NativeArgAt(0));
-  ASSERT(receiver.IsClosure());
   GET_NATIVE_ARGUMENT(Instance, other, arguments->NativeArgAt(1));
   ASSERT(!other.IsNull());
   if (receiver.raw() == other.raw()) return Bool::True().raw();
   if (other.IsClosure()) {
-    const Function& func_a = Function::Handle(Closure::function(receiver));
-    const Function& func_b = Function::Handle(Closure::function(other));
+    const Function& func_a = Function::Handle(receiver.function());
+    const Function& func_b = Function::Handle(Closure::Cast(other).function());
     if (func_a.raw() == func_b.raw()) {
       ASSERT(!func_a.IsImplicitStaticClosureFunction());
       if (func_a.IsImplicitInstanceClosureFunction()) {
-        const Context& context_a = Context::Handle(Closure::context(receiver));
-        const Context& context_b = Context::Handle(Closure::context(other));
+        const Context& context_a = Context::Handle(receiver.context());
+        const Context& context_b = Context::Handle(
+            Closure::Cast(other).context());
         const Object& receiver_a = Object::Handle(context_a.At(0));
         const Object& receiver_b = Object::Handle(context_b.At(0));
         if (receiver_a.raw() == receiver_b.raw()) return Bool::True().raw();
@@ -53,48 +53,38 @@
 }
 
 
-DEFINE_NATIVE_ENTRY(FunctionImpl_hashCode, 1) {
-  const Instance& receiver = Instance::CheckedHandle(
+DEFINE_NATIVE_ENTRY(Closure_hashCode, 1) {
+  const Closure& receiver = Closure::CheckedHandle(
       zone, arguments->NativeArgAt(0));
-  if (receiver.IsClosure()) {
-    const Function& func = Function::Handle(Closure::function(receiver));
-    // Hash together name, class name and signature.
-    const Class& cls = Class::Handle(func.Owner());
-    intptr_t result = String::Handle(func.name()).Hash();
-    result += String::Handle(func.Signature()).Hash();
-    result += String::Handle(cls.Name()).Hash();
-    // Finalize hash value like for strings so that it fits into a smi.
-    result += result << 3;
-    result ^= result >> 11;
-    result += result << 15;
-    result &= ((static_cast<intptr_t>(1) << String::kHashBits) - 1);
-    return Smi::New(result);
-  }
-  UNREACHABLE();
-  return Object::null();
+  const Function& func = Function::Handle(receiver.function());
+  // Hash together name, class name and signature.
+  const Class& cls = Class::Handle(func.Owner());
+  intptr_t result = String::Handle(func.name()).Hash();
+  result += String::Handle(func.Signature()).Hash();
+  result += String::Handle(cls.Name()).Hash();
+  // Finalize hash value like for strings so that it fits into a smi.
+  result += result << 3;
+  result ^= result >> 11;
+  result += result << 15;
+  result &= ((static_cast<intptr_t>(1) << String::kHashBits) - 1);
+  return Smi::New(result);
 }
 
 
-DEFINE_NATIVE_ENTRY(FunctionImpl_clone, 1) {
-  const Instance& receiver = Instance::CheckedHandle(
+DEFINE_NATIVE_ENTRY(Closure_clone, 1) {
+  const Closure& receiver = Closure::CheckedHandle(
       zone, arguments->NativeArgAt(0));
-  ASSERT(receiver.IsClosure());
-  if (receiver.IsClosure()) {
-    const Function& func =
-        Function::Handle(zone, Closure::function(receiver));
-    const Context& ctx =
-        Context::Handle(zone, Closure::context(receiver));
-    Context& cloned_ctx =
-        Context::Handle(zone, Context::New(ctx.num_variables()));
-    cloned_ctx.set_parent(Context::Handle(zone, ctx.parent()));
-    Object& inst = Object::Handle(zone);
-    for (int i = 0; i < ctx.num_variables(); i++) {
-      inst = ctx.At(i);
-      cloned_ctx.SetAt(i, inst);
-    }
-    return Closure::New(func, cloned_ctx);
+  const Function& func = Function::Handle(zone, receiver.function());
+  const Context& ctx = Context::Handle(zone, receiver.context());
+  Context& cloned_ctx =
+      Context::Handle(zone, Context::New(ctx.num_variables()));
+  cloned_ctx.set_parent(Context::Handle(zone, ctx.parent()));
+  Object& inst = Object::Handle(zone);
+  for (int i = 0; i < ctx.num_variables(); i++) {
+    inst = ctx.At(i);
+    cloned_ctx.SetAt(i, inst);
   }
-  return Object::null();
+  return Closure::New(func, cloned_ctx);
 }
 
 
diff --git a/runtime/lib/function.dart b/runtime/lib/function.dart
index d91ce66..6c1d5cc 100644
--- a/runtime/lib/function.dart
+++ b/runtime/lib/function.dart
@@ -2,13 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-class _FunctionImpl implements Function {
+class _Closure implements Function {
 
-  bool operator ==(other) native "FunctionImpl_equals";
+  bool operator ==(other) native "Closure_equals";
 
-  int get hashCode native "FunctionImpl_hashCode";
+  int get hashCode native "Closure_hashCode";
 
-  _FunctionImpl get call => this;
+  _Closure get call => this;
 
-  _FunctionImpl _clone() native "FunctionImpl_clone";
+  _Closure _clone() native "Closure_clone";
+
+  // The type_arguments_, function_, and context_ fields are not declared here.
 }
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index 39b4522..016a454 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -113,13 +113,26 @@
   factory _GrowableList.withData(_List data)
     native "GrowableList_allocate";
 
-  int get length native "GrowableList_getLength";
-
   int get _capacity native "GrowableList_getCapacity";
 
+  int get length native "GrowableList_getLength";
+
   void set length(int new_length) {
-    if (new_length > _capacity) {
-      _grow(new_length);
+    int new_capacity = (new_length == 0) ? _kDefaultCapacity : new_length;
+    if (new_capacity > _capacity) {
+      _grow(new_capacity);
+      _setLength(new_length);
+      return;
+    }
+    // We are shrinking. Pick the method which has fewer writes.
+    // In the shrink-to-fit path, we write |new_capacity + new_length| words
+    // (null init + copy).
+    // In the non-shrink-to-fit path, we write |length - new_length| words
+    // (null overwrite).
+    final bool shouldShrinkToFit =
+        (new_capacity + new_length) < (length - new_length);
+    if (shouldShrinkToFit) {
+      _shrink(new_capacity, new_length);
     } else {
       for (int i = new_length; i < length; i++) {
         this[i] = null;
@@ -217,14 +230,22 @@
     throw IterableElementError.tooMany();;
   }
 
-  void _grow(int new_length) {
-    var new_data = new _List(new_length);
+  void _grow(int new_capacity) {
+    var new_data = new _List(new_capacity);
     for (int i = 0; i < length; i++) {
       new_data[i] = this[i];
     }
     _setData(new_data);
   }
 
+  void _shrink(int new_capacity, int new_length) {
+    var new_data = new _List(new_capacity);
+    for (int i = 0; i < new_length; i++) {
+      new_data[i] = this[i];
+    }
+    _setData(new_data);
+  }
+
   // Iterable interface.
 
   void forEach(f(T element)) {
diff --git a/runtime/lib/identical.cc b/runtime/lib/identical.cc
index 6440726..bbb47bd 100644
--- a/runtime/lib/identical.cc
+++ b/runtime/lib/identical.cc
@@ -5,49 +5,13 @@
 #include "vm/bootstrap_natives.h"
 
 #include "vm/object.h"
-#include "vm/report.h"
 
 namespace dart {
 
-DECLARE_FLAG(bool, warn_on_javascript_compatibility);
-
 DEFINE_NATIVE_ENTRY(Identical_comparison, 2) {
   GET_NATIVE_ARGUMENT(Instance, a, arguments->NativeArgAt(0));
   GET_NATIVE_ARGUMENT(Instance, b, arguments->NativeArgAt(1));
   const bool is_identical = a.IsIdenticalTo(b);
-  if (FLAG_warn_on_javascript_compatibility) {
-    if (!is_identical) {
-      if (a.IsString()) {
-        if (String::Cast(a).Equals(b)) {
-          Report::JSWarningFromNative(
-              true,  // Identical_comparison is static.
-              "strings that are equal are also identical");
-        }
-      } else if (a.IsInteger()) {
-        if (b.IsDouble()) {
-          const int64_t a_value = Integer::Cast(a).AsInt64Value();
-          const double b_value = Double::Cast(b).value();
-          if (a_value == floor(b_value)) {
-            Report::JSWarningFromNative(
-                true,  // Identical_comparison is static.
-                "integer value and integral double value that are equal "
-                "are also identical");
-          }
-        }
-      } else if (a.IsDouble()) {
-        if (b.IsInteger()) {
-          const double a_value = Double::Cast(a).value();
-          const int64_t b_value = Integer::Cast(b).AsInt64Value();
-          if (floor(a_value) == b_value) {
-            Report::JSWarningFromNative(
-                true,  // Identical_comparison is static.
-                "integral double value and integer value that are equal "
-                "are also identical");
-          }
-        }
-      }
-    }
-  }
   return Bool::Get(is_identical).raw();
 }
 
diff --git a/runtime/lib/immutable_map.dart b/runtime/lib/immutable_map.dart
index 2377c8c..b8d0d3c 100644
--- a/runtime/lib/immutable_map.dart
+++ b/runtime/lib/immutable_map.dart
@@ -11,8 +11,9 @@
 
 
   V operator [](Object key) {
-    // TODO(hausner): Since the keys are sorted, we could do a binary
-    // search. But is it worth it?
+    // To preserve the key-value order of the map literal, the keys are
+    // not sorted. Need to do linear search or implement an additional
+    // lookup table.
     for (int i = 0; i < _kvPairs.length - 1; i += 2) {
       if (key == _kvPairs[i]) {
         return _kvPairs[i+1];
diff --git a/runtime/lib/integers.cc b/runtime/lib/integers.cc
index 8deeee4..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()) {
@@ -251,17 +251,15 @@
 }
 
 
-// Passing true for 'silent' prevents throwing JavascriptIntegerOverflow.
 static RawInteger* ShiftOperationHelper(Token::Kind kind,
                                         const Integer& value,
-                                        const Smi& amount,
-                                        const bool silent = false) {
+                                        const Smi& amount) {
   if (amount.Value() < 0) {
     Exceptions::ThrowArgumentError(amount);
   }
   if (value.IsSmi()) {
     const Smi& smi_value = Smi::Cast(value);
-    return smi_value.ShiftOp(kind, amount, Heap::kNew, silent);
+    return smi_value.ShiftOp(kind, amount, Heap::kNew);
   }
   if (value.IsMint()) {
     const int64_t mint_value = value.AsInt64Value();
@@ -273,11 +271,11 @@
     if ((count + shift_count) < Mint::kBits) {
       switch (kind) {
         case Token::kSHL:
-          return Integer::New(mint_value << shift_count, Heap::kNew, silent);
+          return Integer::New(mint_value << shift_count, Heap::kNew);
         case Token::kSHR:
           shift_count =
               (-shift_count > Mint::kBits) ? Mint::kBits : -shift_count;
-          return Integer::New(mint_value >> shift_count, Heap::kNew, silent);
+          return Integer::New(mint_value >> shift_count, Heap::kNew);
         default:
           UNIMPLEMENTED();
       }
@@ -307,7 +305,7 @@
   }
   const Smi& smi_shift_count = Smi::Cast(shift_count);
   const Integer& shift_result = Integer::Handle(
-      ShiftOperationHelper(Token::kSHL, value, smi_shift_count, true));
+      ShiftOperationHelper(Token::kSHL, value, smi_shift_count));
   const Integer& result =
       Integer::Handle(shift_result.BitOp(Token::kBIT_AND, mask));
   return result.AsValidInteger();
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 773bac4..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(),
@@ -226,11 +226,11 @@
 
   if (closure.IsClosure()) {
     Function& func = Function::Handle();
-    func = Closure::function(closure);
+    func = Closure::Cast(closure).function();
     if (func.IsImplicitClosureFunction() && func.is_static()) {
 #if defined(DEBUG)
       Context& ctx = Context::Handle();
-      ctx = Closure::context(closure);
+      ctx = Closure::Cast(closure).context();
       ASSERT(ctx.num_variables() == 0);
 #endif
       // Get the parent function so that we get the right function name.
@@ -298,6 +298,7 @@
   Isolate* isolate = thread->isolate();
   Dart_LibraryTagHandler handler = isolate->library_tag_handler();
   if (handler != NULL) {
+    TransitionVMToNative transition(thread);
     Dart_EnterScope();
     Dart_Handle handle = handler(Dart_kCanonicalizeUrl,
                                  Api::NewHandle(thread, library.raw()),
@@ -390,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/math_patch.dart b/runtime/lib/math_patch.dart
index 667174c..4f0b852 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -116,6 +116,7 @@
   //   _state[_kSTATE_HI] = state >> 32;
   // This is a native to prevent 64-bit operations in Dart, which
   // fail with --throw_on_javascript_int_overflow.
+  // TODO(regis): Implement in Dart and remove Random_nextState in math.cc.
   void _nextState() native "Random_nextState";
 
   int nextInt(int max) {
@@ -160,6 +161,7 @@
 
   // This is a native to prevent 64-bit operations in Dart, which
   // fail with --throw_on_javascript_int_overflow.
+  // TODO(regis): Implement here in Dart and remove native in math.cc.
   static Uint32List _setupSeed(int seed) native "Random_setupSeed";
   // Get a seed from the VM's random number provider.
   static Uint32List _initialSeed() native "Random_initialSeed";
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 05453f8..aaa28e1 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -10,6 +10,7 @@
 #include "vm/compiler.h"
 #include "vm/dart_entry.h"
 #include "vm/exceptions.h"
+#include "vm/flags.h"
 #include "vm/object_store.h"
 #include "vm/parser.h"
 #include "vm/port.h"
@@ -18,7 +19,7 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, lazy_dispatchers);
+#ifndef PRODUCT
 
 #define PROPAGATE_IF_MALFORMED(type)                                           \
   if (type.IsMalformed()) {                                                    \
@@ -139,12 +140,18 @@
     // This covers the default constructor and forwarding constructors.
     has_extra_parameter_info = false;
   }
+  if (func.IsSignatureFunction() &&
+      (func.token_pos() == TokenPosition::kNoSource)) {
+    // Signature functions (except those describing typedefs) get canonicalized,
+    // hence do not have a token position, and therefore cannot be reparsed.
+    has_extra_parameter_info = false;
+  }
 
   Array& param_descriptor = Array::Handle();
   if (has_extra_parameter_info) {
     // Reparse the function for the following information:
     // * The default value of a parameter.
-    // * Whether a parameters has been deflared as final.
+    // * Whether a parameters has been declared as final.
     // * Any metadata associated with the parameter.
     const Object& result =
         Object::Handle(Parser::ParseFunctionParameters(func));
@@ -237,18 +244,21 @@
   args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
   args.SetAt(1, type);
   args.SetAt(2, String::Handle(cls.Name()));
-  args.SetAt(3, Bool::Get(cls.NumTypeParameters() != 0));
-  args.SetAt(4, cls.NumTypeParameters() == 0 ? Bool::False() : is_declaration);
+  args.SetAt(3, Bool::Get(cls.IsGeneric()));
+  args.SetAt(4, cls.IsGeneric() ? is_declaration : Bool::False());
   args.SetAt(5, owner_mirror);
   return CreateMirror(Symbols::_LocalTypedefMirror(), args);
 }
 
 
-static RawInstance* CreateFunctionTypeMirror(const Class& cls,
-                                             const AbstractType& type) {
-  const Array& args = Array::Handle(Array::New(2));
+static RawInstance* CreateFunctionTypeMirror(const AbstractType& type) {
+  ASSERT(type.IsFunctionType());
+  const Class& cls = Class::Handle(FunctionType::Cast(type).scope_class());
+  const Function& func = Function::Handle(FunctionType::Cast(type).signature());
+  const Array& args = Array::Handle(Array::New(3));
   args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
-  args.SetAt(1, type);
+  args.SetAt(1, MirrorReference::Handle(MirrorReference::New(func)));
+  args.SetAt(2, type);
   return CreateMirror(Symbols::_LocalFunctionTypeMirror(), args);
 }
 
@@ -260,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);
@@ -304,22 +314,6 @@
   return CreateMirror(Symbols::_LocalVariableMirror(), args);
 }
 
-static RawFunction* CallMethod(const Class& cls) {
-  if (cls.IsSignatureClass()) {
-    return cls.signature_function();
-  }
-
-  Class& lookup_cls = Class::Handle(cls.raw());
-  Function& call_function = Function::Handle();
-  do {
-    call_function = lookup_cls.LookupDynamicFunction(Symbols::Call());
-    if (!call_function.IsNull()) {
-      return call_function.raw();
-    }
-    lookup_cls = lookup_cls.SuperClass();
-  } while (!lookup_cls.IsNull());
-  return Function::null();
-}
 
 static RawInstance* CreateClassMirror(const Class& cls,
                                       const AbstractType& type,
@@ -335,14 +329,8 @@
   ASSERT(!type.IsNull());
   ASSERT(type.IsFinalized());
 
-  if (cls.IsSignatureClass()) {
-    if (cls.IsCanonicalSignatureClass()) {
-      // We represent function types as canonical signature classes.
-      return CreateFunctionTypeMirror(cls, type);
-    } else {
-      // We represent typedefs as non-canonical signature classes.
-      return CreateTypedefMirror(cls, type, is_declaration, owner_mirror);
-    }
+  if (cls.IsTypedefClass()) {
+    return CreateTypedefMirror(cls, type, is_declaration, owner_mirror);
   }
 
   const Error& error = Error::Handle(cls.EnsureIsFinalized(Thread::Current()));
@@ -554,6 +542,16 @@
   PROPAGATE_IF_MALFORMED(type);
   ASSERT(type.IsCanonical() || type.IsTypeParameter() || type.IsBoundedType());
 
+  if (type.IsFunctionType()) {
+    const Class& scope_class =
+        Class::Handle(FunctionType::Cast(type).scope_class());
+    if (scope_class.IsTypedefClass()) {
+      return CreateTypedefMirror(scope_class,
+                                 type, Bool::False(), Object::null_instance());
+    } else {
+      return CreateFunctionTypeMirror(type);
+    }
+  }
   if (type.HasResolvedTypeClass()) {
     const Class& cls = Class::Handle(type.type_class());
     // Handle void and dynamic types.
@@ -691,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);
@@ -785,8 +783,8 @@
   const TypeArguments& type_args =
       TypeArguments::Handle(instantiator.arguments());
   Error& bound_error = Error::Handle();
-  AbstractType& result =
-      AbstractType::Handle(type.InstantiateFrom(type_args, &bound_error));
+  AbstractType& result = AbstractType::Handle(
+      type.InstantiateFrom(type_args, &bound_error, NULL, NULL, Heap::kOld));
   if (!bound_error.IsNull()) {
     Exceptions::PropagateError(bound_error);
     UNREACHABLE();
@@ -828,12 +826,10 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   PROPAGATE_IF_MALFORMED(type);
   ASSERT(type.IsFinalized());
-  ASSERT(type.HasResolvedTypeClass());
+  ASSERT(type.IsFunctionType() || type.HasResolvedTypeClass());
   const Class& cls = Class::Handle(type.type_class());
   ASSERT(!cls.IsNull());
-  if (cls.IsDynamicClass() ||
-      cls.IsVoidClass() ||
-      (cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass())) {
+  if (cls.IsDynamicClass() || cls.IsVoidClass() || cls.IsTypedefClass()) {
     Exceptions::ThrowArgumentError(type);
     UNREACHABLE();
   }
@@ -887,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();
@@ -911,8 +907,9 @@
                                owner_mirror,
                                arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
-  const Class& cls = Class::Handle(ref.GetClassReferent());
-  const Function& func = Function::Handle(CallMethod(cls));
+  // TODO(rmacnak): Return get:call() method on class _Closure instead?
+  // This now returns the result of invoking that call getter.
+  const Function& func = Function::Handle(ref.GetFunctionReferent());
   ASSERT(!func.IsNull());
   return CreateMethodMirror(func, owner_mirror, AbstractType::Handle());
 }
@@ -921,8 +918,7 @@
 DEFINE_NATIVE_ENTRY(FunctionTypeMirror_parameters, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
-  const Class& cls = Class::Handle(ref.GetClassReferent());
-  const Function& func = Function::Handle(cls.signature_function());
+  const Function& func = Function::Handle(ref.GetFunctionReferent());
   return CreateParameterMirrorList(func, owner);
 }
 
@@ -932,8 +928,7 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType,
                                instantiator,
                                arguments->NativeArgAt(1));
-  const Class& cls = Class::Handle(ref.GetClassReferent());
-  const Function& func = Function::Handle(CallMethod(cls));
+  const Function& func = Function::Handle(ref.GetFunctionReferent());
   ASSERT(!func.IsNull());
   AbstractType& type = AbstractType::Handle(func.result_type());
   return InstantiateType(type, instantiator);
@@ -953,10 +948,6 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   PROPAGATE_IF_MALFORMED(type);
   ASSERT(type.IsFinalized());
-  if (!type.HasResolvedTypeClass()) {
-    Exceptions::ThrowArgumentError(type);
-    UNREACHABLE();
-  }
   const Class& cls = Class::Handle(type.type_class());
   const AbstractType& super_type = AbstractType::Handle(cls.super_type());
   ASSERT(super_type.IsNull() || super_type.IsFinalized());
@@ -968,10 +959,6 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   PROPAGATE_IF_MALFORMED(type);
   ASSERT(type.IsFinalized());
-  if (!type.HasResolvedTypeClass()) {
-    Exceptions::ThrowArgumentError(type);
-    UNREACHABLE();
-  }
   const Class& cls = Class::Handle(type.type_class());
   const AbstractType& super_type = AbstractType::Handle(cls.super_type());
   return InstantiateType(super_type, type);
@@ -982,10 +969,6 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   PROPAGATE_IF_MALFORMED(type);
   ASSERT(type.IsFinalized());
-  if (!type.HasResolvedTypeClass()) {
-    Exceptions::ThrowArgumentError(type);
-    UNREACHABLE();
-  }
   const Class& cls = Class::Handle(type.type_class());
   const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
@@ -999,10 +982,6 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   PROPAGATE_IF_MALFORMED(type);
   ASSERT(type.IsFinalized());
-  if (!type.HasResolvedTypeClass()) {
-    Exceptions::ThrowArgumentError(type);
-    UNREACHABLE();
-  }
   const Class& cls = Class::Handle(type.type_class());
   const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
@@ -1027,10 +1006,6 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   PROPAGATE_IF_MALFORMED(type);
   ASSERT(type.IsFinalized());
-  if (!type.HasResolvedTypeClass()) {
-    Exceptions::ThrowArgumentError(type);
-    UNREACHABLE();
-  }
   const Class& cls = Class::Handle(type.type_class());
   const AbstractType& mixin_type = AbstractType::Handle(cls.mixin());
   ASSERT(mixin_type.IsNull() || mixin_type.IsFinalized());
@@ -1045,10 +1020,6 @@
                                arguments->NativeArgAt(1));
   PROPAGATE_IF_MALFORMED(type);
   ASSERT(type.IsFinalized());
-  if (!type.HasResolvedTypeClass()) {
-    Exceptions::ThrowArgumentError(type);
-    UNREACHABLE();
-  }
   const Class& cls = Class::Handle(type.type_class());
   const AbstractType& mixin_type = AbstractType::Handle(cls.mixin());
   if (mixin_type.IsNull()) {
@@ -1166,13 +1137,11 @@
     entry = entries.GetNext();
     if (entry.IsClass()) {
       const Class& klass = Class::Cast(entry);
-      // We filter out function signature classes and dynamic.
+      // We filter out mixin application classes and dynamic.
       // TODO(12478): Should not need to filter out dynamic.
       // Note that the VM does not consider mixin application aliases to be
       // mixin applications.
-      if (!klass.IsCanonicalSignatureClass() &&
-          !klass.IsDynamicClass() &&
-          !klass.IsMixinApplication()) {
+      if (!klass.IsDynamicClass() && !klass.IsMixinApplication()) {
         type = klass.DeclarationType();
         member_mirror = CreateClassMirror(klass,
                                           type,
@@ -1307,9 +1276,8 @@
   // setters, assume the result is a closure and mark its function as invisible,
   // so it will not appear in stack traces. Whenever we support
   // ObjectMirror.evaluate this will need to be separated.
-  ASSERT(Instance::Cast(result).IsClosure());
-  const Function& func =
-      Function::Handle(Closure::function(Instance::Cast(result)));
+  ASSERT(result.IsClosure());
+  const Function& func = Function::Handle(Closure::Cast(result).function());
   func.set_is_visible(false);
   func.set_is_debuggable(false);
 
@@ -1317,10 +1285,9 @@
 }
 
 DEFINE_NATIVE_ENTRY(TypedefMirror_declaration, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
-  const Class& cls = Class::Handle(type.type_class());
-  // We represent typedefs as non-canonical signature classes.
-  ASSERT(cls.IsSignatureClass() && !cls.IsCanonicalSignatureClass());
+  GET_NON_NULL_NATIVE_ARGUMENT(FunctionType, type, arguments->NativeArgAt(0));
+  const Class& cls = Class::Handle(type.scope_class());
+  ASSERT(cls.IsTypedefClass());
   return CreateTypedefMirror(cls,
                              AbstractType::Handle(cls.DeclarationType()),
                              Bool::True(),  // is_declaration
@@ -1454,7 +1421,7 @@
 
 DEFINE_NATIVE_ENTRY(InstanceMirror_computeType, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
-  const Type& type = Type::Handle(instance.GetType());
+  const AbstractType& type = AbstractType::Handle(instance.GetType());
   // The static type of null is specified to be the bottom type, however, the
   // runtime type of null is the Null type, which we correctly return here.
   return type.Canonicalize();
@@ -1479,10 +1446,10 @@
     Type& instantiator = Type::Handle();
     if (closure.IsClosure()) {
       const TypeArguments& arguments =
-          TypeArguments::Handle(Closure::GetTypeArguments(closure));
+          TypeArguments::Handle(closure.GetTypeArguments());
       const Class& cls =
           Class::Handle(Isolate::Current()->object_store()->object_class());
-      instantiator = Type::New(cls, arguments, Scanner::kNoSourcePos);
+      instantiator = Type::New(cls, arguments, TokenPosition::kNoSource);
       instantiator.SetIsFinalized();
     }
     return CreateMethodMirror(function,
@@ -1708,8 +1675,8 @@
       // The type arguments of the redirection type are instantiated from the
       // type arguments of the type reflected by the class mirror.
       Error& bound_error = Error::Handle();
-      redirect_type ^= redirect_type.InstantiateFrom(type_arguments,
-                                                     &bound_error);
+      redirect_type ^= redirect_type.InstantiateFrom(
+          type_arguments, &bound_error, NULL, NULL, Heap::kOld);
       if (!bound_error.IsNull()) {
         Exceptions::PropagateError(bound_error);
         UNREACHABLE();
@@ -2003,7 +1970,7 @@
   }
 
   Script& script = Script::Handle();
-  intptr_t token_pos = Scanner::kNoSourcePos;
+  TokenPosition token_pos = TokenPosition::kNoSource;
 
   if (decl.IsFunction()) {
     const Function& func = Function::Cast(decl);
@@ -2015,8 +1982,7 @@
     token_pos = func.token_pos();
   } else if (decl.IsClass()) {
     const Class& cls = Class::Cast(decl);
-    const bool is_typedef = cls.IsSignatureClass() &&
-                            !cls.IsCanonicalSignatureClass();
+    const bool is_typedef = cls.IsTypedefClass();
     if (cls.is_synthesized_class() &&
         !is_typedef &&
         !cls.is_mixin_app_alias() &&
@@ -2027,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);
@@ -2052,13 +2018,13 @@
       return CreateSourceLocation(uri, 1, 1);
     }
     const TokenStream& stream = TokenStream::Handle(script.tokens());
-    TokenStream::Iterator tkit(stream, 0);
+    TokenStream::Iterator tkit(stream, TokenPosition::kMinSource);
     if (tkit.CurrentTokenKind() == Token::kSCRIPTTAG) tkit.Advance();
     token_pos = tkit.CurrentPosition();
   }
 
   ASSERT(!script.IsNull());
-  ASSERT(token_pos != Scanner::kNoSourcePos);
+  ASSERT(token_pos != TokenPosition::kNoSource);
 
   const String& uri = String::Handle(script.url());
   intptr_t from_line = 0;
@@ -2077,15 +2043,25 @@
 
 
 DEFINE_NATIVE_ENTRY(TypedefMirror_referent, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
-  const Class& cls = Class::Handle(type.type_class());
+  GET_NON_NULL_NATIVE_ARGUMENT(FunctionType, type, arguments->NativeArgAt(0));
+  const Class& cls = Class::Handle(type.scope_class());
+  ASSERT(cls.IsTypedefClass());
   const Function& sig_func = Function::Handle(cls.signature_function());
-  const Class& sig_cls = Class::Handle(sig_func.signature_class());
-
-  AbstractType& referent_type = AbstractType::Handle(sig_cls.DeclarationType());
-  referent_type = InstantiateType(referent_type, type);
-
-  return CreateFunctionTypeMirror(sig_cls, referent_type);
+  FunctionType& referent_type = FunctionType::Handle(sig_func.SignatureType());
+  // If the scope class of the function type is not generic, replace it with
+  // Closure class (Function::SignatureType() keeps it).
+  ASSERT(cls.raw() == referent_type.scope_class());
+  if (!cls.IsGeneric()) {
+    referent_type = FunctionType::New(
+        Class::Handle(Isolate::Current()->object_store()->closure_class()),
+        TypeArguments::Handle(referent_type.arguments()),
+        sig_func,
+        referent_type.token_pos());
+    referent_type ^= ClassFinalizer::FinalizeType(
+        cls, referent_type, ClassFinalizer::kCanonicalize);
+  }
+  referent_type ^= InstantiateType(referent_type, type);
+  return CreateFunctionTypeMirror(referent_type);
 }
 
 
@@ -2111,8 +2087,9 @@
 DEFINE_NATIVE_ENTRY(TypeMirror_subtypeTest, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, a, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, b, arguments->NativeArgAt(1));
-  return Bool::Get(a.IsSubtypeOf(b, NULL)).raw();
+  return Bool::Get(a.IsSubtypeOf(b, NULL, NULL, Heap::kNew)).raw();
 }
 
+#endif  // !PRODUCT
 
 }  // namespace dart
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index 0a839fb..78835a4 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -945,7 +945,8 @@
 
 class _LocalFunctionTypeMirror extends _LocalClassMirror
     implements FunctionTypeMirror {
-  _LocalFunctionTypeMirror(reflectee, reflectedType)
+  final _functionReflectee;
+  _LocalFunctionTypeMirror(reflectee, this._functionReflectee, reflectedType)
       : super(reflectee, reflectedType, null, null, false, false, false, false, false);
 
   bool get _isAnonymousMixinApplication => false;
@@ -962,7 +963,7 @@
   MethodMirror _callMethod;
   MethodMirror get callMethod {
     if (_callMethod == null) {
-      _callMethod = this._FunctionTypeMirror_call_method(_reflectee);
+      _callMethod = _FunctionTypeMirror_call_method(_functionReflectee);
     }
     return _callMethod;
   }
@@ -971,7 +972,7 @@
   TypeMirror get returnType {
     if (_returnType == null) {
       _returnType = reflectType(
-          _FunctionTypeMirror_return_type(_reflectee, _instantiator));
+          _FunctionTypeMirror_return_type(_functionReflectee, _instantiator));
     }
     return _returnType;
   }
@@ -979,7 +980,7 @@
   List<ParameterMirror> _parameters = null;
   List<ParameterMirror> get parameters {
     if (_parameters == null) {
-      _parameters = _FunctionTypeMirror_parameters(_reflectee);
+      _parameters = _FunctionTypeMirror_parameters(_functionReflectee);
       _parameters = new UnmodifiableListView(_parameters);
     }
     return _parameters;
@@ -990,16 +991,17 @@
   get typeVariables => emptyList;
   get typeArguments => emptyList;
   get metadata => emptyList;
+  get location => null;
 
   String toString() => "FunctionTypeMirror on '${_n(simpleName)}'";
 
-  MethodMirror _FunctionTypeMirror_call_method(reflectee)
+  MethodMirror _FunctionTypeMirror_call_method(functionReflectee)
       native "FunctionTypeMirror_call_method";
 
-  static Type _FunctionTypeMirror_return_type(reflectee, instantiator)
+  static Type _FunctionTypeMirror_return_type(functionReflectee, instantiator)
       native "FunctionTypeMirror_return_type";
 
-  List<ParameterMirror> _FunctionTypeMirror_parameters(reflectee)
+  List<ParameterMirror> _FunctionTypeMirror_parameters(functionReflectee)
       native "FunctionTypeMirror_parameters";
 }
 
@@ -1648,7 +1650,7 @@
       native "Mirrors_makeLocalTypeMirror";
 
   static Expando<ClassMirror> _declarationCache = new Expando("ClassMirror");
-  static Expando<TypeMirror> _instanitationCache = new Expando("TypeMirror");
+  static Expando<TypeMirror> _instantiationCache = new Expando("TypeMirror");
 
   static ClassMirror reflectClass(Type key) {
     var classMirror = _declarationCache[key];
@@ -1656,17 +1658,17 @@
       classMirror = makeLocalClassMirror(key);
       _declarationCache[key] = classMirror;
       if (!classMirror._isGeneric) {
-        _instanitationCache[key] = classMirror;
+        _instantiationCache[key] = classMirror;
       }
     }
     return classMirror;
   }
 
   static TypeMirror reflectType(Type key) {
-    var typeMirror = _instanitationCache[key];
+    var typeMirror = _instantiationCache[key];
     if (typeMirror == null) {
       typeMirror = makeLocalTypeMirror(key);
-      _instanitationCache[key] = typeMirror;
+      _instantiationCache[key] = typeMirror;
       if (typeMirror is ClassMirror && !typeMirror._isGeneric) {
         _declarationCache[key] = typeMirror;
       }
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 72fcc3e..09e4808 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -10,14 +10,12 @@
 #include "vm/heap.h"
 #include "vm/native_entry.h"
 #include "vm/object.h"
-#include "vm/report.h"
 #include "vm/stack_frame.h"
 #include "vm/symbols.h"
 
 namespace dart {
 
 DECLARE_FLAG(bool, trace_type_checks);
-DECLARE_FLAG(bool, warn_on_javascript_compatibility);
 
 // Helper function in stacktrace.cc.
 void _printCurrentStacktrace();
@@ -88,7 +86,7 @@
     // found.
     Function& function = Function::Handle();
     if (instance.IsClosure()) {
-      function = Closure::function(instance);
+      function = Closure::Cast(instance).function();
     } else {
       Class& instance_class = Class::Handle(instance.clazz());
       function = instance_class.LookupDynamicFunction(member_name);
@@ -121,40 +119,6 @@
 }
 
 
-static void WarnOnJSIntegralNumTypeTest(
-    const Instance& instance,
-    const TypeArguments& instantiator_type_arguments,
-    const AbstractType& type) {
-  const bool instance_is_int = instance.IsInteger();
-  const bool instance_is_double = instance.IsDouble();
-  if (!(instance_is_int || instance_is_double)) {
-    return;
-  }
-  AbstractType& instantiated_type = AbstractType::Handle(type.raw());
-  if (!type.IsInstantiated()) {
-    instantiated_type = type.InstantiateFrom(instantiator_type_arguments, NULL);
-  }
-  if (instance_is_double) {
-    if (instantiated_type.IsIntType()) {
-      const double value = Double::Cast(instance).value();
-      if (floor(value) == value) {
-        Report::JSWarningFromNative(
-            false,  // Object_instanceOf and Object_as are not static calls.
-            "integral value of type 'double' is also considered to be "
-            "of type 'int'");
-      }
-    }
-  } else {
-    ASSERT(instance_is_int);
-    if (instantiated_type.IsDoubleType()) {
-      Report::JSWarningFromNative(
-          false,  // Object_instanceOf and Object_as are not static calls.
-          "integer value is also considered to be of type 'double'");
-    }
-  }
-}
-
-
 DEFINE_NATIVE_ENTRY(Object_instanceOf, 4) {
   const Instance& instance =
       Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
@@ -166,12 +130,6 @@
   ASSERT(type.IsFinalized());
   ASSERT(!type.IsMalformed());
   ASSERT(!type.IsMalbounded());
-
-  // Check for javascript compatibility.
-  if (FLAG_warn_on_javascript_compatibility) {
-    WarnOnJSIntegralNumTypeTest(instance, instantiator_type_arguments, type);
-  }
-
   Error& bound_error = Error::Handle(zone, Error::null());
   const bool is_instance_of = instance.IsInstanceOf(type,
                                                     instantiator_type_arguments,
@@ -179,7 +137,8 @@
   if (FLAG_trace_type_checks) {
     const char* result_str = is_instance_of ? "true" : "false";
     OS::Print("Native Object.instanceOf: result %s\n", result_str);
-    const Type& instance_type = Type::Handle(instance.GetType());
+    const AbstractType& instance_type =
+        AbstractType::Handle(instance.GetType());
     OS::Print("  instance type: %s\n",
               String::Handle(instance_type.Name()).ToCString());
     OS::Print("  test type: %s\n", String::Handle(type.Name()).ToCString());
@@ -192,7 +151,7 @@
     DartFrameIterator iterator;
     StackFrame* caller_frame = iterator.NextFrame();
     ASSERT(caller_frame != NULL);
-    const intptr_t location = caller_frame->GetTokenPos();
+    const TokenPosition location = caller_frame->GetTokenPos();
     String& bound_error_message = String::Handle(
         zone, String::New(bound_error.ToErrorCString()));
     Exceptions::CreateAndThrowTypeError(
@@ -277,19 +236,14 @@
   if (instance.IsNull()) {
     return instance.raw();
   }
-
-  // Check for javascript compatibility.
-  if (FLAG_warn_on_javascript_compatibility) {
-    WarnOnJSIntegralNumTypeTest(instance, instantiator_type_arguments, type);
-  }
-
   const bool is_instance_of = instance.IsInstanceOf(type,
                                                     instantiator_type_arguments,
                                                     &bound_error);
   if (FLAG_trace_type_checks) {
     const char* result_str = is_instance_of ? "true" : "false";
     OS::Print("Object.as: result %s\n", result_str);
-    const Type& instance_type = Type::Handle(instance.GetType());
+    const AbstractType& instance_type =
+        AbstractType::Handle(instance.GetType());
     OS::Print("  instance type: %s\n",
               String::Handle(instance_type.Name()).ToCString());
     OS::Print("  cast type: %s\n", String::Handle(type.Name()).ToCString());
@@ -301,7 +255,7 @@
     DartFrameIterator iterator;
     StackFrame* caller_frame = iterator.NextFrame();
     ASSERT(caller_frame != NULL);
-    const intptr_t location = caller_frame->GetTokenPos();
+    const TokenPosition location = caller_frame->GetTokenPos();
     const AbstractType& instance_type =
         AbstractType::Handle(instance.GetType());
     const String& instance_type_name =
@@ -310,7 +264,8 @@
     if (!type.IsInstantiated()) {
       // Instantiate type before reporting the error.
       const AbstractType& instantiated_type = AbstractType::Handle(
-          type.InstantiateFrom(instantiator_type_arguments, NULL));
+          type.InstantiateFrom(instantiator_type_arguments, NULL,
+                               NULL, NULL, Heap::kNew));
       // Note that instantiated_type may be malformed.
       type_name = instantiated_type.UserVisibleName();
     } else {
@@ -325,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/stacktrace.cc b/runtime/lib/stacktrace.cc
index 7b79314..9d9a307 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+#include "lib/stacktrace.h"
 #include "vm/bootstrap_natives.h"
 #include "vm/exceptions.h"
 #include "vm/object_store.h"
@@ -36,7 +37,7 @@
 // Creates a Stacktrace object from the current stack.
 //
 // Skips the first skip_frames Dart frames.
-static const Stacktrace& GetCurrentStacktrace(int skip_frames) {
+const Stacktrace& GetCurrentStacktrace(int skip_frames) {
   const GrowableObjectArray& code_list =
       GrowableObjectArray::Handle(GrowableObjectArray::New());
   const GrowableObjectArray& pc_offset_list =
diff --git a/runtime/lib/stacktrace.h b/runtime/lib/stacktrace.h
new file mode 100644
index 0000000..c3b16e4
--- /dev/null
+++ b/runtime/lib/stacktrace.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef LIB_STACKTRACE_H_
+#define LIB_STACKTRACE_H_
+
+namespace dart {
+
+class Stacktrace;
+
+// Creates a Stacktrace object from the current stack.  Skips the
+// first skip_frames Dart frames.
+//
+// This function is exposed to provide stack trace printing in
+// assertion failures, etc.
+const Stacktrace& GetCurrentStacktrace(int skip_frames);
+
+}  // namespace dart
+
+#endif  // LIB_STACKTRACE_H_
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/lib/timeline.cc b/runtime/lib/timeline.cc
index 3d307da..ddc2f5a 100644
--- a/runtime/lib/timeline.cc
+++ b/runtime/lib/timeline.cc
@@ -16,13 +16,14 @@
 // Native implementations for the dart:developer library.
 
 DEFINE_NATIVE_ENTRY(Timeline_getIsolateNum, 0) {
-  return Integer::New(static_cast<int64_t>(isolate->main_port()),
-                      Heap::kOld,
-                      true);
+  return Integer::New(static_cast<int64_t>(isolate->main_port()), Heap::kOld);
 }
 
 
 DEFINE_NATIVE_ENTRY(Timeline_getNextAsyncId, 0) {
+  if (!FLAG_support_timeline) {
+    return Integer::New(0);
+  }
   TimelineEventRecorder* recorder = Timeline::recorder();
   if (recorder == NULL) {
     return Integer::New(0);
@@ -32,11 +33,14 @@
 
 
 DEFINE_NATIVE_ENTRY(Timeline_getTraceClock, 0) {
-  return Integer::New(OS::GetCurrentMonotonicMicros(), Heap::kNew, true);
+  return Integer::New(OS::GetCurrentMonotonicMicros(), Heap::kNew);
 }
 
 
 DEFINE_NATIVE_ENTRY(Timeline_reportTaskEvent, 6) {
+  if (!FLAG_support_timeline) {
+    return Object::null();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, id, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(String, phase, arguments->NativeArgAt(2));
@@ -100,6 +104,9 @@
 
 
 DEFINE_NATIVE_ENTRY(Timeline_reportCompleteEvent, 5) {
+  if (!FLAG_support_timeline) {
+    return Object::null();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, end, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(String, category, arguments->NativeArgAt(2));
@@ -143,6 +150,9 @@
 
 
 DEFINE_NATIVE_ENTRY(Timeline_reportInstantEvent, 4) {
+  if (!FLAG_support_timeline) {
+    return Object::null();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(String, category, arguments->NativeArgAt(1));
   GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(2));
diff --git a/runtime/lib/type_patch.dart b/runtime/lib/type_patch.dart
index 67d7db5..5d0f305 100644
--- a/runtime/lib/type_patch.dart
+++ b/runtime/lib/type_patch.dart
@@ -13,6 +13,10 @@
 class _Type extends _AbstractType {
 }
 
+// Equivalent of RawFunctionType.
+class _FunctionType extends _AbstractType {
+}
+
 // Equivalent of RawTypeRef.
 class _TypeRef extends _AbstractType {
 }
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
index 83a25e1..c18b8ec 100644
--- a/runtime/lib/vmservice.cc
+++ b/runtime/lib/vmservice.cc
@@ -6,6 +6,7 @@
 #include "vm/dart_api_impl.h"
 #include "vm/datastream.h"
 #include "vm/exceptions.h"
+#include "vm/flags.h"
 #include "vm/growable_array.h"
 #include "vm/message.h"
 #include "vm/native_entry.h"
@@ -24,6 +25,7 @@
 }
 
 
+#ifndef PRODUCT
 class RegisterRunningIsolatesVisitor : public IsolateVisitor {
  public:
   explicit RegisterRunningIsolatesVisitor(Thread* thread)
@@ -78,9 +80,12 @@
   Function& register_function_;
   Isolate* service_isolate_;
 };
-
+#endif  // !PRODUCT
 
 DEFINE_NATIVE_ENTRY(VMService_SendIsolateServiceMessage, 2) {
+  if (!FLAG_support_service) {
+    return Bool::Get(false).raw();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(SendPort, sp, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(1));
 
@@ -103,7 +108,9 @@
 
 DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
-  Service::HandleRootMessage(message);
+  if (FLAG_support_service) {
+    Service::HandleRootMessage(message);
+  }
   return Object::null();
 }
 
@@ -114,14 +121,17 @@
   }
   // Boot the dart:vmservice library.
   ServiceIsolate::BootVmServiceLibrary();
-
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
+#ifndef PRODUCT
   // Register running isolates with service.
   RegisterRunningIsolatesVisitor register_isolates(thread);
   if (FLAG_trace_service) {
     OS::Print("vm-service: Registering running isolates.\n");
   }
   Isolate::VisitIsolates(&register_isolates);
-
+#endif
   return Object::null();
 }
 
@@ -134,25 +144,48 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(VMService_OnServerAddressChange, 1) {
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
+  GET_NATIVE_ARGUMENT(String, address, arguments->NativeArgAt(0));
+  if (address.IsNull()) {
+    ServiceIsolate::SetServerAddress(NULL);
+  } else {
+    ServiceIsolate::SetServerAddress(address.ToCString());
+  }
+  return Object::null();
+}
+
+
 DEFINE_NATIVE_ENTRY(VMService_ListenStream, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
-  bool result = Service::ListenStream(stream_id.ToCString());
+  bool result = false;
+  if (FLAG_support_service) {
+    result = Service::ListenStream(stream_id.ToCString());
+  }
   return Bool::Get(result).raw();
 }
 
 
 DEFINE_NATIVE_ENTRY(VMService_CancelStream, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(String, stream_id, arguments->NativeArgAt(0));
-  Service::CancelStream(stream_id.ToCString());
+  if (FLAG_support_service) {
+    Service::CancelStream(stream_id.ToCString());
+  }
   return Object::null();
 }
 
 
 DEFINE_NATIVE_ENTRY(VMService_RequestAssets, 0) {
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
   return Service::RequestAssets();
 }
 
 
+#ifndef PRODUCT
 // TODO(25041): When reading, this class copies out the filenames and contents
 // into new buffers. It does this because the lifetime of |bytes| is uncertain.
 // If |bytes| is pinned in memory, then we could instead load up
@@ -340,8 +373,16 @@
 }
 
 
+#endif
+
+
 DEFINE_NATIVE_ENTRY(VMService_DecodeAssets, 1) {
+#ifndef PRODUCT
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
   GET_NON_NULL_NATIVE_ARGUMENT(TypedData, data, arguments->NativeArgAt(0));
+  TransitionVMToNative transition(thread);
   Api::Scope scope(thread);
 
   Dart_Handle data_handle = Api::NewHandle(thread, data.raw());
@@ -391,6 +432,9 @@
   }
 
   return result_list.raw();
+#else
+  return Object::null();
+#endif
 }
 
 }  // namespace dart
diff --git a/runtime/lib/vmservice_patch.dart b/runtime/lib/vmservice_patch.dart
index 3db7bca..f26b93d 100644
--- a/runtime/lib/vmservice_patch.dart
+++ b/runtime/lib/vmservice_patch.dart
@@ -27,6 +27,8 @@
     native "VMService_SendRootServiceMessage";
 patch void _onStart() native "VMService_OnStart";
 patch void _onExit() native "VMService_OnExit";
+patch void onServerAddressChange(String address)
+    native "VMService_OnServerAddressChange";
 patch bool _vmListenStream(String streamId) native "VMService_ListenStream";
 patch void _vmCancelStream(String streamId) native "VMService_CancelStream";
 patch Uint8List _requestAssets() native "VMService_RequestAssets";
diff --git a/runtime/observatory/BUILD.gn b/runtime/observatory/BUILD.gn
index a4a76ee..98cfe31 100644
--- a/runtime/observatory/BUILD.gn
+++ b/runtime/observatory/BUILD.gn
@@ -77,6 +77,8 @@
     "--silent=True",
     "--pub-executable",
     dart_host_pub_exe,
+    "--stamp",
+    rebase_path("$root_gen_dir/observatory_copy/dart/runtime/observatory/packages.stamp"),
     "--directory",
     rebase_path("$root_gen_dir/observatory_copy/dart/runtime/observatory/"),
     "--command",
@@ -84,7 +86,7 @@
   ]
 
   outputs = [
-    "$root_gen_dir/observatory_copy/dart/runtime/observatory/pubspec.lock",
+    "$root_gen_dir/observatory_copy/dart/runtime/observatory/packages.stamp",
   ]
 }
 
@@ -103,6 +105,7 @@
 
   inputs = [
     script,
+    "$root_gen_dir/observatory_copy/dart/runtime/observatory/packages.stamp",
   ]
   inputs += sources
 
@@ -118,7 +121,6 @@
   ]
 
   outputs = [
-    "$root_out_dir/observatory/build/web/index.html",
     "$root_out_dir/observatory/build/web/index.html.polymer.bootstrap.dart.js",
   ]
 }
@@ -132,7 +134,6 @@
 
   inputs = [
     script,
-    "$root_out_dir/observatory/build/web/index.html",
     "$root_out_dir/observatory/build/web/index.html.polymer.bootstrap.dart.js",
   ]
 
@@ -147,7 +148,6 @@
   ]
 
   outputs = [
-    "$root_out_dir/observatory/deployed/web/index.html",
     "$root_out_dir/observatory/deployed/web/index.html.polymer.bootstrap.dart.js",
   ]
 }
@@ -161,7 +161,6 @@
 
   inputs = [
     script,
-    "$root_out_dir/observatory/deployed/web/index.html",
     "$root_out_dir/observatory/deployed/web/index.html.polymer.bootstrap.dart.js",
   ]
 
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/object_graph.dart b/runtime/observatory/lib/object_graph.dart
index e70570e..8b491e8 100644
--- a/runtime/observatory/lib/object_graph.dart
+++ b/runtime/observatory/lib/object_graph.dart
@@ -8,8 +8,6 @@
 import 'dart:collection';
 import 'dart:typed_data';
 
-import 'package:logging/logging.dart';
-
 class _JenkinsSmiHash {
   static int combine(int hash, int value) {
     hash = 0x1fffffff & (hash + value);
@@ -499,7 +497,7 @@
         if (childId != null) {
           succs[edge] = childId;
           edge++;
-        } else { 
+        } else {
           // Reference into VM isolate's heap.
         }
         stream.readUnsigned();
@@ -519,7 +517,6 @@
 
   void _dfs() {
     var N = _N;
-    var E = _E;
     var firstSuccs = _firstSuccs;
     var succs = _succs;
 
@@ -531,7 +528,6 @@
     var parent = new Uint32List(N + 1);
     var dfsNumber = 0;
 
-    var dfsCount = 0;
     var stackTop = 0;
     var root = 1;
 
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 21305e1..b2216e4 100644
--- a/runtime/observatory/lib/src/app/page.dart
+++ b/runtime/observatory/lib/src/app/page.dart
@@ -122,6 +122,8 @@
       }
     }).catchError((e, stack) {
       Logger.root.severe('VMPage visit error: $e');
+      // Reroute to vm-connect.
+      app.locationManager.go(app.locationManager.makeLink('/vm-connect'));
     });
   }
 }
@@ -264,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/debugger/debugger_location.dart b/runtime/observatory/lib/src/debugger/debugger_location.dart
index caf5f57..7688712 100644
--- a/runtime/observatory/lib/src/debugger/debugger_location.dart
+++ b/runtime/observatory/lib/src/debugger/debugger_location.dart
@@ -401,13 +401,14 @@
         // Complete the line.
         var sharedPrefix = '${script.name}:';
         List completions = [];
-        for (var line in script.lines) {
-          if (line.possibleBpt) {
-            var currentLineStr = line.line.toString();
-            if (currentLineStr.startsWith(lineStr)) {
-              completions.add('${sharedPrefix}${currentLineStr} ');
-              completions.add('${sharedPrefix}${currentLineStr}:');
-            }
+        var report = await script.isolate.getSourceReport(
+            [Isolate.kPossibleBreakpointsReport], script);
+        Set<int> possibleBpts = getPossibleBreakpointLines(report, script);
+        for (var line in possibleBpts) {
+          var currentLineStr = line.toString();
+          if (currentLineStr.startsWith(lineStr)) {
+            completions.add('${sharedPrefix}${currentLineStr} ');
+            completions.add('${sharedPrefix}${currentLineStr}:');
           }
         }
         return completions;
@@ -416,9 +417,6 @@
         // Complete the column.
         int lineNum = int.parse(lineStr);
         var scriptLine = script.getLine(lineNum);
-        if (!scriptLine.possibleBpt) {
-          return [];
-        }
         var sharedPrefix = '${script.name}:${lineStr}:';
         List completions = [];
         int maxCol = scriptLine.text.trimRight().runes.length;
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index 8c67ebc..d50b092 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -88,10 +88,6 @@
     return Future.wait(loads);
   }
 
-  Future refreshCoverage() {
-    return cls.refreshCoverage();
-  }
-
   onSampleBufferChange(CpuProfile sampleBuffer) {
     stackTraceTreeConfigElement.show = sampleBuffer.sampleCount > 0;
     cpuProfileTreeElement.show = sampleBuffer.sampleCount > 0;
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index 6e59887..60e8ee0 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -24,7 +24,6 @@
       <library-nav-menu library="{{ cls.library }}"></library-nav-menu>
       <class-nav-menu cls="{{ cls }}" last="{{ true }}"></class-nav-menu>
       <nav-refresh callback="{{ refreshAllocationProfile }}" label="Refresh Allocation Profile"></nav-refresh>
-      <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
     </nav-bar>
 
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index cf78a26..6595447 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -8,6 +8,7 @@
 import 'dart:html';
 import 'dart:math';
 import 'observatory_element.dart';
+import 'nav_bar.dart';
 import 'package:observatory/app.dart';
 import 'package:observatory/cli.dart';
 import 'package:observatory/debugger.dart';
@@ -1067,28 +1068,6 @@
       'Syntax: info <subcommand>\n';
 }
 
-class RefreshCoverageCommand extends DebuggerCommand {
-  RefreshCoverageCommand(Debugger debugger) : super(debugger, 'coverage', []);
-
-  Future run(List<String> args) {
-    Set<Script> scripts = debugger.stackElement.activeScripts();
-    List pending = [];
-    for (var script in scripts) {
-      pending.add(script.refreshCoverage().then((_) {
-          debugger.console.print('Refreshed coverage for ${script.name}');
-        }));
-    }
-    return Future.wait(pending);
-  }
-
-  String helpShort = 'Refresh code coverage information for current frames';
-
-  String helpLong =
-      'Refresh code coverage information for current frames.\n'
-      '\n'
-      'Syntax: refresh coverage\n\n';
-}
-
 class RefreshStackCommand extends DebuggerCommand {
   RefreshStackCommand(Debugger debugger) : super(debugger, 'stack', []);
 
@@ -1106,7 +1085,6 @@
 
 class RefreshCommand extends DebuggerCommand {
   RefreshCommand(Debugger debugger) : super(debugger, 'refresh', [
-      new RefreshCoverageCommand(debugger),
       new RefreshStackCommand(debugger),
   ]);
 
@@ -1400,7 +1378,6 @@
       if ((breakOnException != iso.exceptionsPauseInfo) &&
           (iso.exceptionsPauseInfo != null)) {
         breakOnException = iso.exceptionsPauseInfo;
-        console.print("Now pausing for exceptions: $breakOnException");
       }
 
       _isolate.reload().then((response) {
@@ -1515,6 +1492,37 @@
     warnOutOfDate();
   }
 
+  void _reportIsolateError(Isolate isolate, String eventKind) {
+    if (isolate == null) {
+      return;
+    }
+    DartError error = isolate.error;
+    if (error == null) {
+      return;
+    }
+    console.newline();
+    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();
+    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) {
     if (event.kind == ServiceEvent.kPauseStart) {
       console.print(
@@ -1524,6 +1532,12 @@
       console.print(
           "Paused at isolate exit "
           "(type 'continue' or [F7] to exit the 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;
@@ -1640,8 +1654,11 @@
       case ServiceEvent.kPauseInterrupted:
       case ServiceEvent.kPauseException:
         if (event.owner == isolate) {
-          _refreshStack(event).then((_) {
+          _refreshStack(event).then((_) async {
             flushStdio();
+            if (isolate != null) {
+              await isolate.reload();
+            }
             _reportPause(event);
           });
         }
@@ -1810,7 +1827,7 @@
   Future smartNext() async {
     if (isolatePaused()) {
       var event = isolate.pauseEvent;
-      if (event.atAsyncJump) {
+      if (event.atAsyncSuspension) {
         return asyncNext();
       } else {
         return syncNext();
@@ -1823,10 +1840,10 @@
   Future asyncNext() async {
     if (isolatePaused()) {
       var event = isolate.pauseEvent;
-      if (event.asyncContinuation == null) {
+      if (!event.atAsyncSuspension) {
         console.print("No async continuation at this location");
       } else {
-        return isolate.asyncStepOver()[Isolate.kFirstResume];
+        return isolate.stepOverAsyncSuspension();
       }
     } else {
       console.print('The program is already running');
@@ -1896,6 +1913,7 @@
     var stackElement = $['stackElement'];
     debugger.stackElement = stackElement;
     stackElement.debugger = debugger;
+    stackElement.scroller = $['stackDiv'];
     debugger.console = $['console'];
     debugger.input = $['commandline'];
     debugger.input.debugger = debugger;
@@ -1952,7 +1970,8 @@
     var splitterDiv = $['splitterDiv'];
     var cmdDiv = $['commandDiv'];
 
-    int navbarHeight = navbarDiv.clientHeight;
+    // For now, force navbar height to 40px in the debugger.
+    int navbarHeight = NavBarElement.height;
     int splitterHeight = splitterDiv.clientHeight;
     int cmdHeight = cmdDiv.clientHeight;
 
@@ -1960,6 +1979,7 @@
     int fixedHeight = navbarHeight + splitterHeight + cmdHeight;
     int available = windowHeight - fixedHeight;
     int stackHeight = available ~/ 1.6;
+    navbarDiv.style.setProperty('height', '${navbarHeight}px');
     stackDiv.style.setProperty('height', '${stackHeight}px');
   }
 
@@ -1987,6 +2007,7 @@
 @CustomTag('debugger-stack')
 class DebuggerStackElement extends ObservatoryElement {
   @published Isolate isolate;
+  @published Element scroller;
   @observable bool hasStack = false;
   @observable bool hasMessages = false;
   @observable bool isSampled = false;
@@ -1996,6 +2017,7 @@
   _addFrame(List frameList, Frame frameInfo) {
     DebuggerFrameElement frameElement = new Element.tag('debugger-frame');
     frameElement.frame = frameInfo;
+    frameElement.scroller = scroller;
 
     if (frameInfo.index == currentFrame) {
       frameElement.setCurrent(true);
@@ -2122,15 +2144,6 @@
     }
   }
 
-  Set<Script> activeScripts() {
-    var s = new Set<Script>();
-    List frameElements = $['frameList'].children;
-    for (var frameElement in frameElements) {
-      s.add(frameElement.children[0].script);
-    }
-    return s;
-  }
-
   Future doPauseIsolate() {
     if (debugger != null) {
       return debugger.isolate.pause();
@@ -2153,6 +2166,7 @@
 @CustomTag('debugger-frame')
 class DebuggerFrameElement extends ObservatoryElement {
   @published Frame frame;
+  @published Element scroller;
 
   // Is this the current frame?
   bool _current = false;
@@ -2167,17 +2181,14 @@
       var frameOuter = $['frameOuter'];
       if (_current) {
         frameOuter.classes.add('current');
-        expanded = true;
-        frameOuter.classes.add('shadow');
+        _expand();
         scrollIntoView();
       } else {
         frameOuter.classes.remove('current');
         if (_pinned) {
-          expanded = true;
-          frameOuter.classes.add('shadow');
+          _expand();
         } else {
-          expanded = false;
-          frameOuter.classes.remove('shadow');
+          _unexpand();
         }
       }
       busy = false;
@@ -2190,7 +2201,6 @@
 
   DebuggerFrameElement.created() : super.created();
 
-
   String makeExpandKey(String key) {
     return '${frame.function.qualifiedName}/${key}';
   }
@@ -2206,11 +2216,87 @@
 
   Script get script => frame.location.script;
 
+  int _varsTop(varsDiv) {
+    const minTop = 5;
+    if (varsDiv == null) {
+      return minTop;
+    }
+    const navbarHeight = NavBarElement.height;
+    const bottomPad = 6;
+    var parent = varsDiv.parent.getBoundingClientRect();
+    var varsHeight = varsDiv.clientHeight;
+    var maxTop = parent.height - (varsHeight + bottomPad);
+    var adjustedTop = navbarHeight - parent.top;
+    return (max(minTop, min(maxTop, adjustedTop)));
+  }
+
+  void _onScroll(event) {
+    if (!expanded) {
+      return;
+    }
+    var varsDiv = shadowRoot.querySelector('#vars');
+    if (varsDiv == null) {
+      return;
+    }
+    var currentTop = varsDiv.style.top;
+    var newTop = _varsTop(varsDiv);
+    if (currentTop != newTop) {
+      varsDiv.style.top = '${newTop}px';
+    }
+  }
+
+  void _expand() {
+    var frameOuter = $['frameOuter'];
+    expanded = true;
+    frameOuter.classes.add('shadow');
+    _subscribeToScroll();
+  }
+
+  void _unexpand() {
+    var frameOuter = $['frameOuter'];
+    expanded = false;
+    _unsubscribeToScroll();
+    frameOuter.classes.remove('shadow');
+  }
+
+  StreamSubscription _scrollSubscription;
+  StreamSubscription _resizeSubscription;
+
+  void _subscribeToScroll() {
+    if (scroller != null) {
+      if (_scrollSubscription == null) {
+        _scrollSubscription = scroller.onScroll.listen(_onScroll);
+      }
+      if (_resizeSubscription == null) {
+        _resizeSubscription = window.onResize.listen(_onScroll);
+      }
+    }
+  }
+
+  void _unsubscribeToScroll() {
+    if (_scrollSubscription != null) {
+      _scrollSubscription.cancel();
+      _scrollSubscription = null;
+    }
+    if (_resizeSubscription != null) {
+      _resizeSubscription.cancel();
+      _resizeSubscription = null;
+    }
+  }
+
   @override
   void attached() {
     super.attached();
     int windowHeight = window.innerHeight;
     scriptHeight = '${windowHeight ~/ 1.6}px';
+    if (expanded) {
+      _subscribeToScroll();
+    }
+  }
+
+  void detached() {
+    _unsubscribeToScroll();
+    super.detached();
   }
 
   void toggleExpand(var a, var b, var c) {
@@ -2220,13 +2306,10 @@
     busy = true;
     frame.function.load().then((func) {
         _pinned = !_pinned;
-        var frameOuter = $['frameOuter'];
         if (_pinned) {
-          expanded = true;
-          frameOuter.classes.add('shadow');
+          _expand();
         } else {
-          expanded = false;
-          frameOuter.classes.remove('shadow');
+          _unexpand();
         }
         busy = false;
       });
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 981f260..20e2e4d 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -238,6 +238,12 @@
         flex-basis: 250px;
         overflow-x: hidden;
       }
+      #vars {
+        position: relative;
+        top: 5px;
+        padding-left:2em;
+        padding-bottom: 5px;
+      }
     </style>
     <div id="frameOuter" class="frameOuter">
       <a on-click="{{ toggleExpand }}">
@@ -263,11 +269,12 @@
                             location="{{ frame.function.location }}"
                             currentPos="{{ frame.location.tokenPos }}"
                             inDebuggerContext="{{ true }}"
+                            scroller="{{ scroller }}"
                             variables="{{ frame.variables }}">
               </source-inset>
             </div>
             <div class="flex-item-vars">
-              <div style="padding-left:2em;" class="memberList">
+              <div id="vars" class="memberList">
                 <template repeat="{{ v in properLocals }}">
                   {{ v['name']}}&nbsp;:&nbsp;
                   <any-service-ref ref="{{ v['value'] }}"
diff --git a/runtime/observatory/lib/src/elements/function_view.dart b/runtime/observatory/lib/src/elements/function_view.dart
index 5b0d8ec..58f206b 100644
--- a/runtime/observatory/lib/src/elements/function_view.dart
+++ b/runtime/observatory/lib/src/elements/function_view.dart
@@ -18,8 +18,4 @@
   Future refresh() {
     return function.reload();
   }
-
-  Future refreshCoverage() {
-    return function.refreshCoverage();
-  }
 }
diff --git a/runtime/observatory/lib/src/elements/function_view.html b/runtime/observatory/lib/src/elements/function_view.html
index 57e2c8c..a087382 100644
--- a/runtime/observatory/lib/src/elements/function_view.html
+++ b/runtime/observatory/lib/src/elements/function_view.html
@@ -21,7 +21,6 @@
         <class-nav-menu cls="{{ function.dartOwner }}"></class-nav-menu>
       </template>
       <nav-menu link="{{ makeLink('/inspect', function) }}" anchor="{{ function.name }}" last="{{ true }}"></nav-menu>
-      <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
     </nav-bar>
 
diff --git a/runtime/observatory/lib/src/elements/heap_profile.dart b/runtime/observatory/lib/src/elements/heap_profile.dart
index 731ff48..9e5b142 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.dart
+++ b/runtime/observatory/lib/src/elements/heap_profile.dart
@@ -156,7 +156,6 @@
   static const _FREE_INDEX = 1;
   static const _EXTERNAL_INDEX = 2;
 
-  static const _LABEL_INDEX = 0;
   static const _VALUE_INDEX = 1;
 
   void _initPieChartData(List rows) {
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/isolate_view.dart b/runtime/observatory/lib/src/elements/isolate_view.dart
index fe4fd95..40738a1 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.dart
+++ b/runtime/observatory/lib/src/elements/isolate_view.dart
@@ -33,8 +33,4 @@
       await isolate.topFrame.function.load();
     }
   }
-
-  Future refreshCoverage() {
-    return isolate.refreshCoverage();
-  }
 }
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index 915930fc..b090fdd 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -28,7 +28,6 @@
       <top-nav-menu></top-nav-menu>
       <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
       <isolate-nav-menu isolate="{{ isolate }}" last="{{ true }}"></isolate-nav-menu>
-      <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
     </nav-bar>
 
diff --git a/runtime/observatory/lib/src/elements/library_view.dart b/runtime/observatory/lib/src/elements/library_view.dart
index 6b43ae3..3c9a256 100644
--- a/runtime/observatory/lib/src/elements/library_view.dart
+++ b/runtime/observatory/lib/src/elements/library_view.dart
@@ -30,8 +30,4 @@
     library.variables.forEach((variable) => loads.add(variable.reload()));
     return Future.wait(loads);
   }
-
-  Future refreshCoverage() {
-    return library.refreshCoverage();
-  }
 }
diff --git a/runtime/observatory/lib/src/elements/library_view.html b/runtime/observatory/lib/src/elements/library_view.html
index d43fe3e..51d2da8 100644
--- a/runtime/observatory/lib/src/elements/library_view.html
+++ b/runtime/observatory/lib/src/elements/library_view.html
@@ -20,7 +20,6 @@
       <vm-nav-menu vm="{{ library.isolate.vm }}"></vm-nav-menu>
       <isolate-nav-menu isolate="{{ library.isolate }}"></isolate-nav-menu>
       <library-nav-menu library="{{ library }}" last="{{ true }}"></library-nav-menu>
-      <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
       <nav-refresh callback="{{ refresh }}"></nav-refresh>
     </nav-bar>
 
diff --git a/runtime/observatory/lib/src/elements/nav_bar.dart b/runtime/observatory/lib/src/elements/nav_bar.dart
index db77700..3999db87 100644
--- a/runtime/observatory/lib/src/elements/nav_bar.dart
+++ b/runtime/observatory/lib/src/elements/nav_bar.dart
@@ -17,6 +17,9 @@
   @published bool notifyOnPause = true;
   @published bool pad = true;
 
+  // Desired nav var height in pixels.
+  static const height = 40;
+
   NavBarElement.created() : super.created();
 }
 
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/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index 47bbff7..aa3c0a8 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -6,7 +6,9 @@
 
 import 'dart:async';
 import 'dart:html';
+import 'dart:math';
 import 'observatory_element.dart';
+import 'nav_bar.dart';
 import 'service_ref.dart';
 import 'package:observatory/service.dart';
 import 'package:observatory/utils.dart';
@@ -244,7 +246,7 @@
 
         for (var entry in callSite.entries) {
           var r = row();
-          r.append(cell(serviceRef(entry.receiverContainer)));
+          r.append(cell(serviceRef(entry.receiver)));
           r.append(cell(entry.count.toString()));
           r.append(cell(serviceRef(entry.target)));
           details.append(r);
@@ -374,16 +376,24 @@
   @published bool inDebuggerContext = false;
   @published ObservableList variables;
 
+  @published Element scroller;
+  RefreshButtonElement _refreshButton;
+
   int _currentLine;
   int _currentCol;
   int _startLine;
   int _endLine;
 
+  Map<int, List<ServiceMap>> _rangeMap = {};
+  Set _callSites = new Set<CallSite>();
+  Set _possibleBreakpointLines = new Set<int>();
+
   var annotations = [];
   var annotationsCursor;
 
   StreamSubscription _scriptChangeSubscription;
   Future<StreamSubscription> _debugSubscriptionFuture;
+  StreamSubscription _scrollSubscription;
 
   bool hasLoadedLibraryDeclarations = false;
 
@@ -402,11 +412,20 @@
     super.attached();
     _debugSubscriptionFuture =
         app.vm.listenEventStream(VM.kDebugStream, _onDebugEvent);
+    if (scroller != null) {
+      _scrollSubscription = scroller.onScroll.listen(_onScroll);
+    } else {
+      _scrollSubscription = window.onScroll.listen(_onScroll);
+    }
   }
 
   void detached() {
     cancelFutureSubscription(_debugSubscriptionFuture);
     _debugSubscriptionFuture = null;
+    if (_scrollSubscription != null) {
+      _scrollSubscription.cancel();
+      _scrollSubscription = null;
+    }
     if (_scriptChangeSubscription != null) {
       // Don't leak. If only Dart and Javascript exposed weak references...
       _scriptChangeSubscription.cancel();
@@ -415,6 +434,17 @@
     super.detached();
   }
 
+  void _onScroll(event) {
+    if (_refreshButton == null) {
+      return;
+    }
+    var currentTop = _refreshButton.style.top;
+    var newTop = _refreshButtonTop();
+    if (currentTop != newTop) {
+      _refreshButton.style.top = '${newTop}px';
+    }
+  }
+
   void _onDebugEvent(event) {
     if (script == null) {
       return;
@@ -486,11 +516,55 @@
     element.title = "Line did execute";
     return element;
   }
+  Element hitsCompiled(Element element) {
+    element.classes.add('hitsCompiled');
+    element.title = "Line in compiled function";
+    return element;
+  }
+  Element hitsNotCompiled(Element element) {
+    element.classes.add('hitsNotCompiled');
+    element.title = "Line in uncompiled function";
+    return element;
+  }
 
   Element container;
 
+  Future _refresh() async {
+    await update();
+  }
+
+  // Build _rangeMap and _callSites from a source report.
+  Future _refreshSourceReport() async {
+    var sourceReport = await script.isolate.getSourceReport(
+        [Isolate.kCallSitesReport, Isolate.kPossibleBreakpointsReport],
+        script, startPos, endPos);
+    _possibleBreakpointLines = getPossibleBreakpointLines(sourceReport, script);
+    _rangeMap.clear();
+    _callSites.clear();
+    for (var range in sourceReport['ranges']) {
+      int startLine = script.tokenToLine(range['startPos']);
+      int endLine = script.tokenToLine(range['endPos']);
+      for (var line = startLine; line <= endLine; line++) {
+        var rangeList = _rangeMap[line];
+        if (rangeList == null) {
+          _rangeMap[line] = [range];
+        } else {
+          rangeList.add(range);
+        }
+      }
+      if (range['compiled']) {
+        var rangeCallSites = range['callSites'];
+        if (rangeCallSites != null) {
+          for (var callSiteMap in rangeCallSites) {
+            _callSites.add(new CallSite.fromMap(callSiteMap, script));
+          }
+        }
+      }
+    }
+  }
+
   Task _updateTask;
-  void update() {
+  Future update() async {
     assert(_updateTask != null);
     if (script == null) {
       // We may have previously had a script.
@@ -500,13 +574,12 @@
       return;
     }
     if (!script.loaded) {
-      script.load().then((_) => update());
-      return;
+      await script.load();
     }
-
     if (_scriptChangeSubscription == null) {
       _scriptChangeSubscription = script.changes.listen((_) => update());
     }
+    await _refreshSourceReport();
 
     computeAnnotations();
 
@@ -803,7 +876,7 @@
   }
 
   void addCallSiteAnnotations() {
-    for (var callSite in script.callSites) {
+    for (var callSite in _callSites) {
       annotations.add(new CallSiteAnnotation(callSite));
     }
   }
@@ -828,10 +901,35 @@
     }
   }
 
+  int _refreshButtonTop() {
+    if (_refreshButton == null) {
+      return 5;
+    }
+    const padding = 5;
+    const navbarHeight = NavBarElement.height;
+    var rect = getBoundingClientRect();
+    var buttonHeight = _refreshButton.clientHeight;
+    return min(max(0, navbarHeight - rect.top) + padding,
+               rect.height - (buttonHeight + padding));
+  }
+
+  RefreshButtonElement _newRefreshButton() {
+    var button = new Element.tag('refresh-button');
+    button.style.position = 'absolute';
+    button.style.display = 'inline-block';
+    button.style.top = '${_refreshButtonTop()}px';
+    button.style.right = '5px';
+    button.callback = _refresh;
+    return button;
+  }
+
   Element linesTable() {
     var table = new DivElement();
     table.classes.add("sourceTable");
 
+    _refreshButton = _newRefreshButton();
+    table.append(_refreshButton);
+
     if (_startLine == null || _endLine == null) {
       return table;
     }
@@ -904,35 +1002,38 @@
 
   Element lineBreakpointElement(ScriptLine line) {
     var e = new DivElement();
-    var busy = false;
-    if (line == null || !line.possibleBpt) {
-      e.classes.add("emptyBreakpoint");
+    if (line == null || !_possibleBreakpointLines.contains(line.line)) {
       e.classes.add('noCopy');
+      e.classes.add("emptyBreakpoint");
       e.text = nbsp;
       return e;
     }
+
     e.text = 'B';
-    update() {
+    var busy = false;
+    void update() {
       e.classes.clear();
       e.classes.add('noCopy');
-
-      if (!line.possibleBpt) {
-        e.classes.add("emptyBreakpoint");
-        e.text = nbsp;
-      } else if (busy) {
+      if (busy) {
         e.classes.add("busyBreakpoint");
-      } else {
-        if (line.breakpoints != null) {
-          if (line.breakpointResolved) {
-            e.classes.add("resolvedBreakpoint");
-          } else {
-            e.classes.add("unresolvedBreakpoint");
+      } else if (line.breakpoints != null) {
+        bool resolved = false;
+        for (var bpt in line.breakpoints) {
+          if (bpt.resolved) {
+            resolved = true;
+            break;
           }
-        } else {
-          e.classes.add("possibleBreakpoint");
         }
+        if (resolved) {
+          e.classes.add("resolvedBreakpoint");
+        } else {
+          e.classes.add("unresolvedBreakpoint");
+        }
+      } else {
+        e.classes.add("possibleBreakpoint");
       }
     }
+
     line.changes.listen((_) => update());
     e.onClick.listen((event) {
       if (busy) {
@@ -973,17 +1074,51 @@
     var lineNumber = line == null ? "..." : line.line;
     var e = span("$nbsp${lineNumber.toString().padLeft(lineNumPad,nbsp)}$nbsp");
     e.classes.add('noCopy');
-
     if (lineNumber == _currentLine) {
       hitsCurrent(e);
-    } else if ((line == null) || (line.hits == null)) {
-      hitsUnknown(e);
-    } else if (line.hits == 0) {
-      hitsNotExecuted(e);
-    } else {
-      hitsExecuted(e);
+      return e;
     }
-
+    var ranges = _rangeMap[lineNumber];
+    if ((ranges == null) || ranges.isEmpty) {
+      // This line is not code.
+      hitsUnknown(e);
+      return e;
+    }
+    bool compiled = true;
+    bool hasCallInfo = false;
+    bool executed = false;
+    for (var range in ranges) {
+      if (range['compiled']) {
+        for (var callSite in range['callSites']) {
+          var callLine = line.script.tokenToLine(callSite['tokenPos']);
+          if (lineNumber == callLine) {
+            // The call site is on the current line.
+            hasCallInfo = true;
+            for (var cacheEntry in callSite['cacheEntries']) {
+              if (cacheEntry['count'] > 0) {
+                // If any call site on the line has been executed, we
+                // mark the line as executed.
+                executed = true;
+                break;
+              }
+            }
+          }
+        }
+      } else {
+        // If any range isn't compiled, show the line as not compiled.
+        // This is necessary so that nested functions appear to be uncompiled.
+        compiled = false;
+      }
+    }
+    if (executed) {
+      hitsExecuted(e);
+    } else if (hasCallInfo) {
+      hitsNotExecuted(e);
+    } else if (compiled) {
+      hitsCompiled(e);
+    } else {
+      hitsNotCompiled(e);
+    }
     return e;
   }
 
@@ -1036,6 +1171,26 @@
   }
 }
 
+@CustomTag('refresh-button')
+class RefreshButtonElement extends PolymerElement {
+  RefreshButtonElement.created() : super.created();
+
+  @published var callback = null;
+  bool busy = false;
+
+  Future buttonClick(var event, var b, var c) async {
+    if (busy) {
+      return;
+    }
+    busy = true;
+    if (callback != null) {
+      await callback();
+    }
+    busy = false;
+  }
+}
+
+
 @CustomTag('source-inset')
 class SourceInsetElement extends PolymerElement {
   SourceInsetElement.created() : super.created();
@@ -1045,4 +1200,5 @@
   @published int currentPos;
   @published bool inDebuggerContext = false;
   @published ObservableList variables;
+  @published Element scroller;
 }
diff --git a/runtime/observatory/lib/src/elements/script_inset.html b/runtime/observatory/lib/src/elements/script_inset.html
index a76ae42..92d2940 100644
--- a/runtime/observatory/lib/src/elements/script_inset.html
+++ b/runtime/observatory/lib/src/elements/script_inset.html
@@ -1,6 +1,19 @@
 <link rel="import" href="../../../../packages/polymer/polymer.html">
 <link rel="import" href="observatory_element.html">
 
+<polymer-element name="icon-refresh" noscript>
+  <template>
+    <style>
+      svg {
+        fill: currentColor
+      }
+    </style>
+    <svg width="24" height="24">
+      <path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
+    </svg>
+  </template>
+</polymer-element>
+
 <polymer-element name="script-inset" extends="observatory-element">
   <template>
     <style>
@@ -14,6 +27,7 @@
       .sourceInset {
       }
       .sourceTable {
+        position: relative;
         background-color: #f5f5f5;
         border: 1px solid #ccc;
         padding: 10px;
@@ -39,7 +53,7 @@
       .currentCol {
         background-color: #6cf;
       }
-      .hitsCurrent, .hitsNone, .hitsNotExecuted, .hitsExecuted {
+      .hitsCurrent, .hitsNone, .hitsNotExecuted, .hitsExecuted, .hitsCompiled, .hitsNotCompiled {
         display: table-cell;
         vertical-align: top;
         font: 400 14px consolas, courier, monospace;
@@ -58,6 +72,13 @@
       .hitsExecuted {
         background-color: #aea;
       }
+      .hitsCompiled {
+        background-color: #e0e0e0;
+      }
+      .hitsNotCompiled {
+        background-color: #f0c5c5;
+      }
+
       .noCopy {}
       .emptyBreakpoint, .possibleBreakpoint, .busyBreakpoint, .unresolvedBreakpoint, .resolvedBreakpoint  {
         display: table-cell;
@@ -99,12 +120,40 @@
   </template>
 </polymer-element>
 
+<polymer-element name="refresh-button">
+  <template>
+    <style>
+      .refreshButton {
+        color: rgba(0,0,0,.3);
+      }
+      .refreshButton:hover {
+        color: black;
+      }
+      .refreshButtonDisabled {
+        color: white;
+        cursor: wait;
+      }
+    </style>
+    <template if="{{ callback != null }}">
+      <template if="{{ busy }}">
+        <icon-refresh id="refreshIcon" class="refreshButtonDisabled">
+        </icon-refresh>
+      </template>
+      <template if="{{ !busy }}">
+        <a on-click="{{ buttonClick }}">
+          <icon-refresh id="refreshIcon" class="refreshButton"></icon-refresh>
+        </a>
+      </template>
+    </template>
+  </template>
+</polymer-element>
 
 <polymer-element name="source-inset">
 <template>
   <template if="{{ location != null }}">
     <script-inset script="{{ location.script }}"
                   startPos="{{ location.tokenPos }}"
+                  scroller="{{ scroller }}"
                   endPos="{{ location.endTokenPos }}"
                   height="{{ height }}"
                   currentPos="{{ currentPos }}"
diff --git a/runtime/observatory/lib/src/elements/script_view.dart b/runtime/observatory/lib/src/elements/script_view.dart
index ff07a80..c896b8d 100644
--- a/runtime/observatory/lib/src/elements/script_view.dart
+++ b/runtime/observatory/lib/src/elements/script_view.dart
@@ -20,8 +20,4 @@
   Future refresh() {
     return script.reload();
   }
-
-  Future refreshCoverage() {
-    return script.refreshCoverage();
-  }
 }
diff --git a/runtime/observatory/lib/src/elements/script_view.html b/runtime/observatory/lib/src/elements/script_view.html
index 1dc23b4..c65fa49 100644
--- a/runtime/observatory/lib/src/elements/script_view.html
+++ b/runtime/observatory/lib/src/elements/script_view.html
@@ -13,7 +13,6 @@
     <isolate-nav-menu isolate="{{ script.isolate }}"></isolate-nav-menu>
     <library-nav-menu library="{{ script.library }}"></library-nav-menu>
     <nav-menu link="{{ makeLink('/inspect', script) }}" anchor="{{ script.name }}" last="{{ true }}"></nav-menu>
-    <nav-refresh callback="{{ refreshCoverage }}" label="Refresh Coverage"></nav-refresh>
     <nav-refresh callback="{{ refresh }}"></nav-refresh>
   </nav-bar>
 
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index 04a7376..7a70c11 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -8,7 +8,6 @@
 import 'dart:convert';
 import 'dart:html';
 import 'observatory_element.dart';
-import 'package:observatory/app.dart';
 import 'package:observatory/service_html.dart';
 import 'package:polymer/polymer.dart';
 
@@ -57,17 +56,25 @@
   }
 
   Future recordOn() async {
-    return app.vm.invokeRpc('_setVMTimelineFlag', {
-      '_record': 'all',
+    return app.vm.invokeRpc('_setVMTimelineFlags', {
+      'recordedStreams': ['all'],
     });
   }
 
   Future recordOff() async {
-    return app.vm.invokeRpc('_setVMTimelineFlag', {
-      '_record': 'none',
+    return app.vm.invokeRpc('_setVMTimelineFlags', {
+      'recordedStreams': [],
     });
   }
 
+  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 f4ce72f..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;
     }
@@ -396,40 +403,6 @@
   }
 }
 
-abstract class Coverage {
-  // Following getters and functions will be provided by [ServiceObject].
-  String get id;
-  Isolate get isolate;
-
-  Future refreshCoverage() {
-    return refreshCallSiteData();
-  }
-
-  /// Default handler for coverage data.
-  void processCallSiteData(List coverageData) {
-    coverageData.forEach((scriptCoverage) {
-      assert(scriptCoverage['script'] != null);
-      scriptCoverage['script']._processCallSites(scriptCoverage['callSites']);
-    });
-  }
-
-  Future refreshCallSiteData() {
-    Map params = {};
-    if (this is! Isolate) {
-      params['targetId'] = id;
-    }
-    return isolate.invokeRpcNoUpgrade('_getCallSiteData', params).then(
-        (ObservableMap map) {
-          var coverage = new ServiceObject._fromMap(isolate, map);
-          assert(coverage.type == 'CodeCoverage');
-          var coverageList = coverage['coverage'];
-          assert(coverageList != null);
-          processCallSiteData(coverageList);
-          return this;
-        });
-  }
-}
-
 abstract class ServiceObjectOwner extends ServiceObject {
   /// Creates an empty [ServiceObjectOwner].
   ServiceObjectOwner._empty(ServiceObjectOwner owner) : super._empty(owner);
@@ -1136,7 +1109,7 @@
 }
 
 /// State for a running isolate.
-class Isolate extends ServiceObjectOwner with Coverage {
+class Isolate extends ServiceObjectOwner {
   static const kLoggingStream = '_Logging';
   static const kExtensionStream = 'Extension';
 
@@ -1171,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>();
@@ -1195,6 +1168,26 @@
     });
   }
 
+  static const kCallSitesReport = '_CallSites';
+  static const kPossibleBreakpointsReport = 'PossibleBreakpoints';
+
+  Future<ServiceMap> getSourceReport(List<String> report_kinds,
+                                     [Script script,
+                                      int startPos,
+                                      int endPos]) {
+    var params = { 'reports' : report_kinds };
+    if (script != null) {
+      params['scriptId'] = script.id;
+    }
+    if (startPos != null) {
+      params['tokenPos'] = startPos;
+    }
+    if (endPos != null) {
+      params['endTokenPos'] = endPos;
+    }
+    return invokeRpc('_getSourceReport', params);
+  }
+
   /// Fetches and builds the class hierarchy for this isolate. Returns the
   /// Object class object.
   Future<Class> getClassHierarchy() {
@@ -1207,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');
@@ -1389,7 +1386,7 @@
     }
     _loaded = true;
     loading = false;
-
+    runnable = map['runnable'] == true;
     _upgradeCollection(map, isolate);
     originNumber = int.parse(map['_originNumber'], onError:(_) => null);
     rootLibrary = map['rootLib'];
@@ -1537,34 +1534,15 @@
     }
   }
 
-  Future<ServiceObject> addBreakpoint(
-      Script script, int line, [int col]) async {
-    // TODO(turnidge): Pass line as an int instead of a string.
-    try {
-      Map params = {
-        'scriptId': script.id,
-        'line': line.toString(),
-      };
-      if (col != null) {
-        params['column'] = col.toString();
-      }
-      Breakpoint bpt = await invokeRpc('addBreakpoint', params);
-      if (bpt.resolved && script.loaded) {
-        SourceLocation loc = bpt.location;
-        if (script.tokenToLine(loc.tokenPos) != line) {
-          script.getLine(line).possibleBpt = false;
-        }
-      }
-      return bpt;
-    } on ServerRpcException catch(e) {
-      if (e.code == ServerRpcException.kCannotAddBreakpoint) {
-        // Unable to set a breakpoint at the desired line.
-        if (script.loaded) {
-          script.getLine(line).possibleBpt = false;
-        }
-      }
-      rethrow;
+  Future<ServiceObject> addBreakpoint(Script script, int line, [int col]) {
+    Map params = {
+      'scriptId': script.id,
+      'line': line,
+    };
+    if (col != null) {
+      params['column'] = col;
     }
+    return invokeRpc('addBreakpoint', params);
   }
 
   Future<ServiceObject> addBreakpointByScriptUri(
@@ -1610,69 +1588,12 @@
     return invokeRpc('resume', {'step': 'Over'});
   }
 
-  Future stepOut() {
-    return invokeRpc('resume', {'step': 'Out'});
+  Future stepOverAsyncSuspension() {
+    return invokeRpc('resume', {'step': 'OverAsyncSuspension'});
   }
 
-
-  static const int kFirstResume = 0;
-  static const int kSecondResume = 1;
-  /// result[kFirstResume] completes after the inital resume. The UI should
-  /// wait on this future because some other breakpoint may be hit before the
-  /// async continuation.
-  /// result[kSecondResume] completes after the second resume. Tests should
-  /// wait on this future to avoid confusing the pause event at the
-  /// state-machine switch with the pause event after the state-machine switch.
-  List<Future> asyncStepOver() {
-    Completer firstResume = new Completer();
-    Completer secondResume = new Completer();
-    var subscription;
-
-    handleError(error) {
-      if (subscription != null) {
-        subscription.cancel();
-        subscription = null;
-      }
-      firstResume.completeError(error);
-      secondResume.completeError(error);
-    }
-
-    if ((pauseEvent == null) ||
-        (pauseEvent.kind != ServiceEvent.kPauseBreakpoint) ||
-        (pauseEvent.asyncContinuation == null)) {
-      handleError(new Exception("No async continuation available"));
-    } else {
-      Instance continuation = pauseEvent.asyncContinuation;
-      assert(continuation.isClosure);
-      addBreakOnActivation(continuation).then((Breakpoint continuationBpt) {
-        vm.getEventStream(VM.kDebugStream).then((stream) {
-          var onResume = firstResume;
-          subscription = stream.listen((ServiceEvent event) {
-            if ((event.kind == ServiceEvent.kPauseBreakpoint) &&
-                (event.breakpoint == continuationBpt)) {
-              // We are stopped before state-machine dispatch; step-over to
-              // reach user code.
-              removeBreakpoint(continuationBpt).then((_) {
-                onResume = secondResume;
-                stepOver().catchError(handleError);
-              });
-            } else if (event.kind == ServiceEvent.kResume) {
-              if (onResume == secondResume) {
-                subscription.cancel();
-                subscription = null;
-              }
-              if (onResume != null) {
-                onResume.complete(this);
-                onResume = null;
-              }
-            }
-          });
-          resume().catchError(handleError);
-        }).catchError(handleError);
-      }).catchError(handleError);
-    }
-
-    return [firstResume.future, secondResume.future];
+  Future stepOut() {
+    return invokeRpc('resume', {'step': 'Out'});
   }
 
   Future setName(String newName) {
@@ -1924,8 +1845,7 @@
   @observable Frame topFrame;
   @observable String extensionRPC;
   @observable Instance exception;
-  @observable Instance asyncContinuation;
-  @observable bool atAsyncJump;
+  @observable bool atAsyncSuspension;
   @observable ServiceObject inspectee;
   @observable ByteData data;
   @observable int count;
@@ -1949,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']);
@@ -1974,12 +1895,7 @@
     if (map['exception'] != null) {
       exception = map['exception'];
     }
-    if (map['_asyncContinuation'] != null) {
-      asyncContinuation = map['_asyncContinuation'];
-      atAsyncJump = map['_atAsyncJump'];
-    } else {
-      atAsyncJump = false;
-    }
+    atAsyncSuspension = map['atAsyncSuspension'] != null;
     if (map['inspectee'] != null) {
       inspectee = map['inspectee'];
     }
@@ -2050,6 +1966,10 @@
   // The breakpoint has been assigned to a final source location.
   @observable bool resolved;
 
+  // The breakpoint was synthetically created as part of an
+  // 'OverAsyncContinuation' resume request.
+  @observable bool isSyntheticAsyncContinuation;
+
   void _update(ObservableMap map, bool mapIsRef) {
     _loaded = true;
     _upgradeCollection(map, owner);
@@ -2076,6 +1996,8 @@
       newScript._addBreakpoint(this);
     }
 
+    isSyntheticAsyncContinuation = map['isSyntheticAsyncContinuation'] != null;
+
     assert(resolved || location is UnresolvedSourceLocation);
   }
 
@@ -2091,7 +2013,11 @@
 
   String toString() {
     if (number != null) {
-      return 'Breakpoint ${number} at ${location})';
+      if (isSyntheticAsyncContinuation) {
+        return 'Synthetic Async Continuation Breakpoint ${number}';
+      } else {
+        return 'Breakpoint ${number} at ${location}';
+      }
     } else {
       return 'Uninitialized breakpoint';
     }
@@ -2116,7 +2042,7 @@
 }
 
 
-class Library extends HeapObject with Coverage {
+class Library extends HeapObject {
   @observable String uri;
   @reflectable final dependencies = new ObservableList<LibraryDependency>();
   @reflectable final scripts = new ObservableList<Script>();
@@ -2127,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) {
@@ -2214,7 +2144,7 @@
   bool get empty => accumulated.empty && current.empty;
 }
 
-class Class extends HeapObject with Coverage {
+class Class extends HeapObject {
   @observable Library library;
 
   @observable bool isAbstract;
@@ -2411,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?
@@ -2449,7 +2398,7 @@
     elements = map['elements'];
     associations = map['associations'];
     if (map['bytes'] != null) {
-      var bytes = BASE64.decode(map['bytes']);
+      Uint8List bytes = BASE64.decode(map['bytes']);
       switch (map['kind']) {
         case "Uint8ClampedList":
           typedElements = bytes.buffer.asUint8ClampedList(); break;
@@ -2593,7 +2542,7 @@
   static FunctionKind kUNKNOWN = new FunctionKind._internal('UNKNOWN');
 }
 
-class ServiceFunction extends HeapObject with Coverage {
+class ServiceFunction extends HeapObject {
   // owner is a Library, Class, or ServiceFunction.
   @observable ServiceObject dartOwner;
   @observable Library library;
@@ -2739,21 +2688,21 @@
   final Script script;
   final int line;
   final String text;
-  @observable int hits;
-  @observable bool possibleBpt = true;
-  @observable bool breakpointResolved = false;
   @observable Set<Breakpoint> breakpoints;
 
-  bool get isBlank {
-    // Compute isBlank on demand.
-    if (_isBlank == null) {
-      _isBlank = text.trim().isEmpty;
-    }
-    return _isBlank;
-  }
-  bool _isBlank;
+  ScriptLine(this.script, this.line, this.text);
 
-  bool get isTrivialLine => !possibleBpt;
+  bool get isBlank {
+    return text.isEmpty || text.trim().isEmpty;
+  }
+
+  bool _isTrivial = null;
+  bool get isTrivial {
+    if (_isTrivial == null) {
+      _isTrivial = _isTrivialLine(text);
+    }
+    return _isTrivial;
+  }
 
   static bool _isTrivialToken(String token) {
     if (token == 'else') {
@@ -2790,16 +2739,11 @@
     return true;
   }
 
-  ScriptLine(this.script, this.line, this.text) {
-    possibleBpt = !_isTrivialLine(text);
-  }
-
   void addBreakpoint(Breakpoint bpt) {
     if (breakpoints == null) {
       breakpoints = new Set<Breakpoint>();
     }
     breakpoints.add(bpt);
-    breakpointResolved = breakpointResolved || bpt.resolved;
   }
 
   void removeBreakpoint(Breakpoint bpt) {
@@ -2807,7 +2751,6 @@
     breakpoints.remove(bpt);
     if (breakpoints.isEmpty) {
       breakpoints = null;
-      breakpointResolved = false;
     }
   }
 }
@@ -2851,19 +2794,19 @@
 }
 
 class CallSiteEntry {
-  final /* Class | Library */ receiverContainer;
+  final /* Class | Library */ receiver;
   final int count;
   final ServiceFunction target;
 
-  CallSiteEntry(this.receiverContainer, this.count, this.target);
+  CallSiteEntry(this.receiver, this.count, this.target);
 
   factory CallSiteEntry.fromMap(Map entryMap) {
-    return new CallSiteEntry(entryMap['receiverContainer'],
+    return new CallSiteEntry(entryMap['receiver'],
                              entryMap['count'],
                              entryMap['target']);
   }
 
-  String toString() => "CallSiteEntry(${receiverContainer.name}, $count)";
+  String toString() => "CallSiteEntry(${receiver.name}, $count)";
 }
 
 /// The location of a local variable reference in a script.
@@ -2874,10 +2817,8 @@
   LocalVarLocation(this.line, this.column, this.endColumn);
 }
 
-class Script extends HeapObject with Coverage {
-  Set<CallSite> callSites = new Set<CallSite>();
+class Script extends HeapObject {
   final lines = new ObservableList<ScriptLine>();
-  final _hits = new Map<int, int>();
   @observable String uri;
   @observable String kind;
   @observable int firstTokenPos;
@@ -3022,36 +2963,6 @@
         _tokenToCol[tokenOffset] = colNumber;
       }
     }
-
-    for (var line in lines) {
-      // Remove possible breakpoints on lines with no tokens.
-      if (!lineSet.contains(line.line)) {
-        line.possibleBpt = false;
-      }
-    }
-  }
-
-  void _processCallSites(List newCallSiteMaps) {
-    var mergedCallSites = new Set<CallSite>();
-    for (var callSiteMap in newCallSiteMaps) {
-      var newSite = new CallSite.fromMap(callSiteMap, this);
-      mergedCallSites.add(newSite);
-
-      var line = newSite.line;
-      var hit = newSite.aggregateCount;
-      assert(line >= 1); // Lines start at 1.
-      var oldHits = _hits[line];
-      if (oldHits != null) {
-        hit += oldHits;
-      }
-      _hits[line] = hit;
-    }
-
-    mergedCallSites.addAll(callSites);
-    callSites = mergedCallSites;
-    _applyHitsToLines();
-    // Notify any Observers that this Script's state has changed.
-    notifyChange(null);
   }
 
   void _processSource(String source) {
@@ -3073,18 +2984,10 @@
       }
     }
 
-    _applyHitsToLines();
     // Notify any Observers that this Script's state has changed.
     notifyChange(null);
   }
 
-  void _applyHitsToLines() {
-    for (var line in lines) {
-      var hits = _hits[line.line];
-      line.hits = hits;
-    }
-  }
-
   void _addBreakpoint(Breakpoint bpt) {
     var line;
     if (bpt.location.tokenPos != null) {
@@ -3175,7 +3078,7 @@
 
     if (line == lastLine) {
       // Only one line.
-      if (!getLine(line).isTrivialLine) {
+      if (!getLine(line).isTrivial) {
         // TODO(johnmccutchan): end token pos -> column can lie for snapshotted
         // code. e.g.:
         // io_sink.dart source line 23 ends at column 39
@@ -3191,7 +3094,7 @@
     }
 
     // Scan first line.
-    if (!getLine(line).isTrivialLine) {
+    if (!getLine(line).isTrivial) {
       lineContents = getLine(line).text.substring(column);
       r.addAll(scanLineForLocalVariableLocations(pattern,
                                                   name,
@@ -3202,7 +3105,7 @@
 
     // Scan middle lines.
     while (line < (lastLine - 1)) {
-      if (getLine(line).isTrivialLine) {
+      if (getLine(line).isTrivial) {
         line++;
         continue;
       }
@@ -3216,7 +3119,7 @@
     }
 
     // Scan last line.
-    if (!getLine(line).isTrivialLine) {
+    if (!getLine(line).isTrivial) {
       // TODO(johnmccutchan): end token pos -> column can lie for snapshotted
       // code. e.g.:
       // io_sink.dart source line 23 ends at column 39
@@ -3713,7 +3616,7 @@
 
   @observable bool hasDisassembly = false;
 
-  void _processDisassembly(List<String> disassembly){
+  void _processDisassembly(List disassembly) {
     assert(disassembly != null);
     instructions.clear();
     instructionsByAddressOffset = new List(endAddress - startAddress);
@@ -4026,6 +3929,48 @@
 }
 
 
+// Helper function to extract possible breakpoint locations from a
+// SourceReport for some script.
+Set<int> getPossibleBreakpointLines(ServiceMap report, Script script) {
+  var result = new Set<int>();
+  int scriptIndex;
+  int numScripts = report['scripts'].length;
+  for (scriptIndex = 0; scriptIndex < numScripts; scriptIndex++) {
+    if (report['scripts'][scriptIndex].id == script.id) {
+      break;
+    }
+  }
+  if (scriptIndex == numScripts) {
+    return result;
+  }
+  var ranges = report['ranges'];
+  if (ranges != null) {
+    for (var range in ranges) {
+      if (range['scriptIndex'] != scriptIndex) {
+        continue;
+      }
+      if (range['compiled']) {
+        var possibleBpts = range['possibleBreakpoints'];
+        if (possibleBpts != null) {
+          for (var tokenPos in possibleBpts) {
+            result.add(script.tokenToLine(tokenPos));
+          }
+        }
+      } else {
+        int startLine = script.tokenToLine(range['startPos']);
+        int endLine = script.tokenToLine(range['endPos']);
+        for (int line = startLine; line <= endLine; line++) {
+          if (!script.getLine(line).isTrivial) {
+            result.add(line);
+          }
+        }
+      }
+    }
+  }
+  return result;
+}
+
+
 // Returns true if [map] is a service map. i.e. it has the following keys:
 // 'id' and a 'type'.
 bool _isServiceMap(ObservableMap m) {
diff --git a/runtime/observatory/observatory.gypi b/runtime/observatory/observatory.gypi
index 5d282ac..39a6db9d 100644
--- a/runtime/observatory/observatory.gypi
+++ b/runtime/observatory/observatory.gypi
@@ -25,13 +25,15 @@
             'pubspec.yaml',
           ],
           'outputs': [
-            'pubspec.lock'
+            '<(gen_source_dir)/observatory_packages.stamp'
           ],
           'action': [
             'python',
             '../tools/observatory_tool.py',
             '--sdk=True',
             '--package-root', '<(PRODUCT_DIR)/packages',
+            '--stamp',
+            '<(gen_source_dir)/observatory_packages.stamp',
             '--dart-executable',
             '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart_bootstrap<(EXECUTABLE_SUFFIX)',
             '--directory', 'observatory',
@@ -56,7 +58,7 @@
           'action_name': 'pub_build_observatory',
           'inputs': [
             '../../tools/observatory_tool.py',
-            'pubspec.lock',
+            '<(gen_source_dir)/observatory_packages.stamp',
             '<@(_sources)',
           ],
           'outputs': [
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/add_breakpoint_rpc_test.dart b/runtime/observatory/tests/service/add_breakpoint_rpc_test.dart
index a51a2b3..b735254 100644
--- a/runtime/observatory/tests/service/add_breakpoint_rpc_test.dart
+++ b/runtime/observatory/tests/service/add_breakpoint_rpc_test.dart
@@ -5,10 +5,14 @@
 
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 import 'deferred_library.dart' deferred as deferredLib;
 import 'dart:async';
 
+const int LINE_A = 24;
+const int LINE_B = 26;
+
 int value = 0;
 
 int incValue(int amount) {
@@ -17,9 +21,9 @@
 }
 
 Future testMain() async {
-  incValue(incValue(1));  // line 20
+  incValue(incValue(1));  // line A.
 
-  incValue(incValue(1));  // line 22
+  incValue(incValue(1));  // line B.
 
   await deferredLib.loadLibrary();
   deferredLib.deferredTest();
@@ -35,17 +39,17 @@
     var script = rootLib.scripts[0];
 
     // Future breakpoint.
-    var futureBpt1 = await isolate.addBreakpoint(script, 20);
+    var futureBpt1 = await isolate.addBreakpoint(script, LINE_A);
     expect(futureBpt1.number, equals(1));
     expect(futureBpt1.resolved, isFalse);
-    expect(await futureBpt1.location.getLine(), equals(20));
+    expect(await futureBpt1.location.getLine(), equals(LINE_A));
     expect(await futureBpt1.location.getColumn(), equals(null));
 
     // Future breakpoint with specific column.
-    var futureBpt2 = await isolate.addBreakpoint(script, 20, 3);
+    var futureBpt2 = await isolate.addBreakpoint(script, LINE_A, 3);
     expect(futureBpt2.number, equals(2));
     expect(futureBpt2.resolved, isFalse);
-    expect(await futureBpt2.location.getLine(), equals(20));
+    expect(await futureBpt2.location.getLine(), equals(LINE_A));
     expect(await futureBpt2.location.getColumn(), equals(3));
 
     var stream = await isolate.vm.getEventStream(VM.kDebugStream);
@@ -67,10 +71,10 @@
     // After resolution the breakpoints have assigned line & column.
     expect(resolvedCount, equals(2));
     expect(futureBpt1.resolved, isTrue);
-    expect(await futureBpt1.location.getLine(), equals(20));
+    expect(await futureBpt1.location.getLine(), equals(LINE_A));
     expect(await futureBpt1.location.getColumn(), equals(12));
     expect(futureBpt2.resolved, isTrue);
-    expect(await futureBpt2.location.getLine(), equals(20));
+    expect(await futureBpt2.location.getLine(), equals(LINE_A));
     expect(await futureBpt2.location.getColumn(), equals(3));
 
     // The first breakpoint hits before value is modified.
@@ -176,19 +180,19 @@
     var script = isolate.rootLibrary.scripts[0];
     // Try all columns, including some columns that are too big.
     for (int col = 1; col <= 50; col++) {
-      var bpt = await isolate.addBreakpoint(script, 20, col);
+      var bpt = await isolate.addBreakpoint(script, LINE_A, col);
       expect(bpt.resolved, isTrue);
       int resolvedLine = await bpt.location.getLine();
       int resolvedCol = await bpt.location.getColumn();
       print('20:${col} -> ${resolvedLine}:${resolvedCol}');
       if (col <= 10) {
-        expect(resolvedLine, equals(20));
+        expect(resolvedLine, equals(LINE_A));
         expect(resolvedCol, equals(3));
       } else if (col <= 19) {
-        expect(resolvedLine, equals(20));
+        expect(resolvedLine, equals(LINE_A));
         expect(resolvedCol, equals(12));
       } else {
-        expect(resolvedLine, equals(22));
+        expect(resolvedLine, equals(LINE_B));
         expect(resolvedCol, equals(12));
       }
       expect((await isolate.removeBreakpoint(bpt)).type, equals('Success'));
diff --git a/runtime/observatory/tests/service/async_continuation_test.dart b/runtime/observatory/tests/service/async_continuation_test.dart
deleted file mode 100644
index dfbad2d..0000000
--- a/runtime/observatory/tests/service/async_continuation_test.dart
+++ /dev/null
@@ -1,95 +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=--error_on_bad_type --error_on_bad_override --verbose-debug
-
-import 'dart:async';
-import 'dart:developer';
-import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
-import 'test_helper.dart';
-
-foo() {}
-
-doSync() {
-  foo();  // Line 15
-}
-
-doAsync() async {
-  foo();  // Line 19
-  await null;
-}
-
-doAsyncStar() async* {
-  foo();  // Line 24
-  yield null;
-}
-
-testeeDo() {
-  debugger();
-
-  doSync();
-
-  doAsync();
-
-  doAsyncStar().listen((_) => null);
-}
-
-test(Isolate isolate) async {
-  await isolate.rootLibrary.load();
-  var script = isolate.rootLibrary.scripts[0];
-
-  var bp1 = await isolate.addBreakpoint(script, 15);
-  expect(bp1, isNotNull);
-  expect(bp1 is Breakpoint, isTrue);
-
-  var bp2 = await isolate.addBreakpoint(script, 19);
-  expect(bp2, isNotNull);
-  expect(bp2 is Breakpoint, isTrue);
-
-  var bp3 = await isolate.addBreakpoint(script, 24);
-  expect(bp3, isNotNull);
-  expect(bp3 is Breakpoint, isTrue);
-
-  isolate.resume();
-
-  var bp1_hit = new Completer();
-  var bp2_hit = new Completer();
-  var bp3_hit = new Completer();
-
-  var stream = await isolate.vm.getEventStream(VM.kDebugStream);
-  stream.listen((ServiceEvent event) async {
-    print("Event: $event");
-    if (event.kind == ServiceEvent.kPauseBreakpoint) {
-      var bp = event.breakpoint;
-      print('Hit $bp');
-      if (bp == bp1) {
-        await stoppedAtLine(15)(isolate);
-        print(event.asyncContinuation);
-        expect(event.asyncContinuation, equals(null));
-        isolate.resume();
-        bp1_hit.complete(null);
-      }
-      if (bp == bp2) {
-        await stoppedAtLine(19)(isolate);
-        print(event.asyncContinuation);
-        expect(event.asyncContinuation.isClosure, isTrue);
-        isolate.resume();
-        bp2_hit.complete(null);
-      }
-      if (bp == bp3) {
-        await stoppedAtLine(24)(isolate);
-        print(event.asyncContinuation);
-        expect(event.asyncContinuation.isClosure, isTrue);
-        isolate.resume();
-        bp3_hit.complete(null);
-      }
-    }
-  });
-
-  await bp1_hit.future;
-  await bp2_hit.future;
-  await bp3_hit.future;
-}
-
-main(args) => runIsolateTests(args, [test], testeeConcurrent: testeeDo);
diff --git a/runtime/observatory/tests/service/async_next_test.dart b/runtime/observatory/tests/service/async_next_test.dart
index f3c64d9..4fefcca 100644
--- a/runtime/observatory/tests/service/async_next_test.dart
+++ b/runtime/observatory/tests/service/async_next_test.dart
@@ -4,16 +4,21 @@
 // VMOptions=--error_on_bad_type --error_on_bad_override  --verbose_debug
 
 import 'package:observatory/service_io.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 import 'dart:developer';
 
+const int LINE_A = 19;
+const int LINE_B = 20;
+const int LINE_C = 21;
+
 foo() async { }
 
 doAsync(stop) async {
   if (stop) debugger();
-  await foo(); // Line 14.
-  await foo(); // Line 15.
-  await foo(); // Line 16.
+  await foo(); // Line A.
+  await foo(); // Line B.
+  await foo(); // Line C.
   return null;
 }
 
@@ -26,18 +31,20 @@
 
 asyncNext(Isolate isolate) async {
   print('asyncNext');
-  return isolate.asyncStepOver()[Isolate.kSecondResume];
+  return asyncStepOver(isolate);
 }
 
 var tests = [
   hasStoppedAtBreakpoint,
-  stoppedAtLine(14),
+  stoppedAtLine(LINE_A),
+  stepOver, // foo()
   asyncNext,
   hasStoppedAtBreakpoint,
-  stoppedAtLine(15),
+  stoppedAtLine(LINE_B),
+  stepOver, // foo()
   asyncNext,
   hasStoppedAtBreakpoint,
-  stoppedAtLine(16),
+  stoppedAtLine(LINE_C),
   resumeIsolate,
 ];
 
diff --git a/runtime/observatory/tests/service/async_scope_test.dart b/runtime/observatory/tests/service/async_scope_test.dart
index a3f97cc..170a638 100644
--- a/runtime/observatory/tests/service/async_scope_test.dart
+++ b/runtime/observatory/tests/service/async_scope_test.dart
@@ -6,19 +6,23 @@
 import 'dart:developer';
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
+const int LINE_A = 19;
+const int LINE_B = 25;
+
 foo() {}
 
 doAsync(param1) async {
   var local1 = param1 + 1;
-  foo(); // Line 15
+  foo(); // Line A.
   await local1;
 }
 
 doAsyncStar(param2) async* {
   var local2 = param2 + 1;
-  foo(); // Line 21
+  foo(); // Line B.
   yield local2;
 }
 
@@ -53,17 +57,17 @@
 
 var tests = [
   hasStoppedAtBreakpoint, // debugger()
-  setBreakpointAtLine(15),
-  setBreakpointAtLine(21),
+  setBreakpointAtLine(LINE_A),
+  setBreakpointAtLine(LINE_B),
   resumeIsolate,
 
   hasStoppedAtBreakpoint,
-  stoppedAtLine(15),
+  stoppedAtLine(LINE_A),
   checkAsyncVarDescriptors,
   resumeIsolate,
 
   hasStoppedAtBreakpoint,
-  stoppedAtLine(21),
+  stoppedAtLine(LINE_B),
   checkAsyncStarVarDescriptors,
   resumeIsolate,
 ];
diff --git a/runtime/observatory/tests/service/break_on_function_test.dart b/runtime/observatory/tests/service/break_on_function_test.dart
index 1a0e0ee..e428b25 100644
--- a/runtime/observatory/tests/service/break_on_function_test.dart
+++ b/runtime/observatory/tests/service/break_on_function_test.dart
@@ -5,10 +5,13 @@
 
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 import 'dart:developer';
 
-testFunction(flag) {  // Line 11
+const int LINE_A = 14;
+
+testFunction(flag) {  // Line A.
   if (flag) {
     print("Yes");
   } else {
@@ -40,11 +43,11 @@
 resumeIsolate,
 
 hasStoppedAtBreakpoint,
-stoppedAtLine(11),
+stoppedAtLine(LINE_A),
 resumeIsolate,
 
 hasStoppedAtBreakpoint,
-stoppedAtLine(11),
+stoppedAtLine(LINE_A),
 resumeIsolate,
 
 ];
diff --git a/runtime/observatory/tests/service/caching_test.dart b/runtime/observatory/tests/service/caching_test.dart
index 8a72447..6194ba6 100644
--- a/runtime/observatory/tests/service/caching_test.dart
+++ b/runtime/observatory/tests/service/caching_test.dart
@@ -13,27 +13,14 @@
 import 'package:unittest/unittest.dart';
 import 'test_helper.dart';
 
-script() {
-  print("This executed");
-}
-
-hasSomeCoverageData(Script script) {
-  for (var line in script.lines) {
-    if (line.hits != null) return true;
-  }
-  return false;
-}
-
 var tests = [
 (Isolate isolate) async {
   Library lib = await isolate.rootLibrary.load();
   Script script = await lib.scripts.single.load();
-  expect(hasSomeCoverageData(script), isFalse);
-  Script script2 = await script.refreshCoverage();
+  Script script2 = await isolate.getObject(script.id);
   expect(identical(script, script2), isTrue);
-  expect(hasSomeCoverageData(script), isTrue);
 },
 
 ];
 
-main(args) => runIsolateTests(args, tests, testeeBefore: script);
+main(args) => runIsolateTests(args, tests);
diff --git a/runtime/observatory/tests/service/capture_stdio_test.dart b/runtime/observatory/tests/service/capture_stdio_test.dart
index 56a1451..279d055 100644
--- a/runtime/observatory/tests/service/capture_stdio_test.dart
+++ b/runtime/observatory/tests/service/capture_stdio_test.dart
@@ -8,6 +8,7 @@
 import 'dart:io';
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
 void test() {
diff --git a/runtime/observatory/tests/service/coverage_test.dart b/runtime/observatory/tests/service/coverage_test.dart
index 0255687..1266500 100644
--- a/runtime/observatory/tests/service/coverage_test.dart
+++ b/runtime/observatory/tests/service/coverage_test.dart
@@ -6,13 +6,18 @@
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
 import 'test_helper.dart';
+import 'service_test_common.dart';
 import 'dart:developer';
 
+const int LINE_A = 20;
+const int LINE_B = 38;
+const int LINE_C = 136;
+
 int globalVar = 100;
 
 class MyClass {
   static void myFunction(int value) {
-    if (value < 0) {
+    if (value < 0) {  // Line A.
       print("negative");
     } else {
       print("positive");
@@ -30,7 +35,7 @@
 }
 
 void testFunction() {
-  MyClass.otherFunction(-100);
+  MyClass.otherFunction(-100);  // Line B.
   MyClass.myFunction(10000);
 }
 
@@ -60,7 +65,10 @@
   expect(coverage['type'], equals('CodeCoverage'));
   expect(coverage['coverage'].length, equals(1));
   expect(coverage['coverage'][0]['hits'],
-         equals([15, 1, 16, 0, 18, 1, 20, 1]));
+         equals([LINE_A, 1,
+                 LINE_A + 1, 0,
+                 LINE_A + 3, 1,
+                 LINE_A + 5, 1]));
 
   // Class
   coverage = await isolate.invokeRpcNoUpgrade('_getCoverage',
@@ -68,8 +76,14 @@
   expect(coverage['type'], equals('CodeCoverage'));
   expect(coverage['coverage'].length, equals(1));
   expect(coverage['coverage'][0]['hits'],
-         equals([15, 1, 16, 0, 18, 1, 20, 1,
-                 24, 1, 25, 1, 27, 0]));
+         equals([LINE_A, 1,
+                 LINE_A + 1, 0,
+                 LINE_A + 3, 1,
+                 LINE_A + 5, 1,
+                 LINE_A + 9, 1,
+                 LINE_A + 10, 1,
+                 LINE_A + 12, 0,
+                 LINE_A - 2, 0]));
 
   // Library
   coverage = await isolate.invokeRpcNoUpgrade('_getCoverage',
@@ -77,10 +91,18 @@
   expect(coverage['type'], equals('CodeCoverage'));
   expect(coverage['coverage'].length, equals(4));
   expect(coverage['coverage'][0]['hits'],
-         equals([15, 1, 16, 0, 18, 1, 20, 1,
-                 24, 1, 25, 1, 27, 0]));
+         equals([LINE_A, 1,
+                 LINE_A + 1, 0,
+                 LINE_A + 3, 1,
+                 LINE_A + 5, 1,
+                 LINE_A + 9, 1,
+                 LINE_A + 10, 1,
+                 LINE_A + 12, 0,
+                 LINE_A - 2, 0]));
   expect(coverage['coverage'][1]['hits'],
-         equals([33, 1, 34, 1, 105, 2]));
+         equals([LINE_B, 1,
+                 LINE_B + 1, 1,
+                 LINE_C, 2]));
 
   // Script
   await cls.load();
@@ -89,17 +111,28 @@
   expect(coverage['type'], equals('CodeCoverage'));
   expect(coverage['coverage'].length, equals(4));
   expect(coverage['coverage'][0]['hits'],
-         equals([15, 1, 16, 0, 18, 1, 20, 1,
-                 24, 1, 25, 1, 27, 0]));
+         equals([LINE_A, 1,
+                 LINE_A + 1, 0,
+                 LINE_A + 3, 1,
+                 LINE_A + 5, 1,
+                 LINE_A + 9, 1,
+                 LINE_A + 10, 1,
+                 LINE_A + 12, 0,
+                 LINE_A - 2, 0]));
   expect(coverage['coverage'][1]['hits'],
-         equals([33, 1, 34, 1, 105, 2]));
+         equals([LINE_B, 1,
+                 LINE_B + 1, 1,
+                 LINE_C, 2]));
 
   // Isolate
   coverage = await isolate.invokeRpcNoUpgrade('_getCoverage', {});
+  print('Done processing _getCoverage for full isolate');
   expect(coverage['type'], equals('CodeCoverage'));
   expect(coverage['coverage'].length, greaterThan(100));
 },
 
 ];
 
-main(args) => runIsolateTests(args, tests, testeeConcurrent: testFunction);
+main(args) => runIsolateTests(args, tests,    // Line C.
+                              testeeConcurrent: testFunction,
+                              trace_service: true);
diff --git a/runtime/observatory/tests/service/debugger_location_test.dart b/runtime/observatory/tests/service/debugger_location_test.dart
index 7825ae6..53ed4fb 100644
--- a/runtime/observatory/tests/service/debugger_location_test.dart
+++ b/runtime/observatory/tests/service/debugger_location_test.dart
@@ -6,15 +6,20 @@
 import 'package:observatory/service_io.dart';
 import 'package:observatory/debugger.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 import 'dart:async';
 import 'dart:developer';
 
+const int LINE_A = 22;
+const int LINE_B = 112;
+const int LINE_C = 12;
+
 void testFunction() {
   int i = 0;
   while (i == 0) {
     debugger();
-    print('loop');
+    print('loop');  // Line A.
     print('loop');
   }
 }
@@ -59,7 +64,7 @@
   var debugger = await initDebugger(isolate);
   var loc = await DebuggerLocation.parse(debugger, '');
   expect(loc.valid, isTrue);
-  expect(loc.toString(), equals('debugger_location_test.dart:17:5'));
+  expect(loc.toString(), equals('debugger_location_test.dart:$LINE_A:5'));
 },
 
 // Parse line
@@ -236,24 +241,18 @@
       await DebuggerLocation.complete(debugger,
                                       'debugger_location_test.dart:11');
   expect(completions.toString(), equals(
-      '[debugger_location_test.dart:11 ,'
-      ' debugger_location_test.dart:11:,'
-      ' debugger_location_test.dart:110 ,'
-      ' debugger_location_test.dart:110:,'
-      ' debugger_location_test.dart:111 ,'
-      ' debugger_location_test.dart:111:,'
-      ' debugger_location_test.dart:112 ,'
-      ' debugger_location_test.dart:112:,'
-      ' debugger_location_test.dart:115 ,'
-      ' debugger_location_test.dart:115:,'
-      ' debugger_location_test.dart:116 ,'
-      ' debugger_location_test.dart:116:,'
-      ' debugger_location_test.dart:117 ,'
-      ' debugger_location_test.dart:117:,'
-      ' debugger_location_test.dart:118 ,'
-      ' debugger_location_test.dart:118:,'
-      ' debugger_location_test.dart:119 ,'
-      ' debugger_location_test.dart:119:]'));
+      '[debugger_location_test.dart:${LINE_B + 0} ,'
+      ' debugger_location_test.dart:${LINE_B + 0}:,'
+      ' debugger_location_test.dart:${LINE_B + 1} ,'
+      ' debugger_location_test.dart:${LINE_B + 1}:,'
+      ' debugger_location_test.dart:${LINE_B + 2} ,'
+      ' debugger_location_test.dart:${LINE_B + 2}:,'
+      ' debugger_location_test.dart:${LINE_B + 3} ,'
+      ' debugger_location_test.dart:${LINE_B + 3}:,'
+      ' debugger_location_test.dart:${LINE_B + 4} ,'
+      ' debugger_location_test.dart:${LINE_B + 4}:,'
+      ' debugger_location_test.dart:${LINE_B + 5} ,'
+      ' debugger_location_test.dart:${LINE_B + 5}:]'));
 },
 
 // Complete script:line:col
@@ -261,27 +260,27 @@
   var debugger = await initDebugger(isolate);
   var completions =
       await DebuggerLocation.complete(debugger,
-                                      'debugger_location_test.dart:11:2');
+                                      'debugger_location_test.dart:$LINE_C:2');
   expect(completions.toString(), equals(
-      '[debugger_location_test.dart:11:2 ,'
-      ' debugger_location_test.dart:11:20 ,'
-      ' debugger_location_test.dart:11:21 ,'
-      ' debugger_location_test.dart:11:22 ,'
-      ' debugger_location_test.dart:11:23 ,'
-      ' debugger_location_test.dart:11:24 ]'));
+      '[debugger_location_test.dart:$LINE_C:2 ,'
+      ' debugger_location_test.dart:$LINE_C:20 ,'
+      ' debugger_location_test.dart:$LINE_C:21 ,'
+      ' debugger_location_test.dart:$LINE_C:22 ,'
+      ' debugger_location_test.dart:$LINE_C:23 ,'
+      ' debugger_location_test.dart:$LINE_C:24 ]'));
 },
 
 // Complete without the script name.
 (Isolate isolate) async {
   var debugger = await initDebugger(isolate);
-  var completions = await DebuggerLocation.complete(debugger, '11:2');
+  var completions = await DebuggerLocation.complete(debugger, '$LINE_C:2');
   expect(completions.toString(), equals(
-      '[debugger_location_test.dart:11:2 ,'
-      ' debugger_location_test.dart:11:20 ,'
-      ' debugger_location_test.dart:11:21 ,'
-      ' debugger_location_test.dart:11:22 ,'
-      ' debugger_location_test.dart:11:23 ,'
-      ' debugger_location_test.dart:11:24 ]'));
+      '[debugger_location_test.dart:$LINE_C:2 ,'
+      ' debugger_location_test.dart:$LINE_C:20 ,'
+      ' debugger_location_test.dart:$LINE_C:21 ,'
+      ' debugger_location_test.dart:$LINE_C:22 ,'
+      ' debugger_location_test.dart:$LINE_C:23 ,'
+      ' debugger_location_test.dart:$LINE_C:24 ]'));
 },
 
 ];
diff --git a/runtime/observatory/tests/service/debugging_inlined_finally_test.dart b/runtime/observatory/tests/service/debugging_inlined_finally_test.dart
index 91ca4b2..7f867a2 100644
--- a/runtime/observatory/tests/service/debugging_inlined_finally_test.dart
+++ b/runtime/observatory/tests/service/debugging_inlined_finally_test.dart
@@ -5,9 +5,14 @@
 
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 import 'dart:developer';
 
+const int LINE_A = 24;
+const int LINE_B = 27;
+const int LINE_C = 30;
+
 testFunction() {
   debugger();
   var a;
@@ -16,13 +21,13 @@
     try {
       for (int i = 0; i < 10; i++) {
         var x = () => i + a + b;
-        return x;  // line 19
+        return x;  // LINE_A
       }
     } finally {
-      b = 10;  // line 22
+      b = 10;  // LINE_B
     }
   } finally {
-    a = 1;  // line 25
+    a = 1;  // LINE_C
   }
 }
 
@@ -44,32 +49,35 @@
 
   // Add 3 breakpoints.
   {
-    var result = await isolate.addBreakpoint(script, 19);
+    var result = await isolate.addBreakpoint(script, LINE_A);
     expect(result is Breakpoint, isTrue);
     Breakpoint bpt = result;
     expect(bpt.type, equals('Breakpoint'));
     expect(bpt.location.script.id, equals(script.id));
-    expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(19));
+    expect(bpt.location.script.tokenToLine(bpt.location.tokenPos),
+           equals(LINE_A));
     expect(isolate.breakpoints.length, equals(1));
   }
 
   {
-    var result = await isolate.addBreakpoint(script, 22);
+    var result = await isolate.addBreakpoint(script, LINE_B);
     expect(result is Breakpoint, isTrue);
     Breakpoint bpt = result;
     expect(bpt.type, equals('Breakpoint'));
     expect(bpt.location.script.id, equals(script.id));
-    expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(22));
+    expect(bpt.location.script.tokenToLine(bpt.location.tokenPos),
+           equals(LINE_B));
     expect(isolate.breakpoints.length, equals(2));
   }
 
   {
-    var result = await isolate.addBreakpoint(script, 25);
+    var result = await isolate.addBreakpoint(script, LINE_C);
     expect(result is Breakpoint, isTrue);
     Breakpoint bpt = result;
     expect(bpt.type, equals('Breakpoint'));
     expect(bpt.location.script.id, equals(script.id));
-    expect(bpt.location.script.tokenToLine(bpt.location.tokenPos), equals(25));
+    expect(bpt.location.script.tokenToLine(bpt.location.tokenPos),
+           equals(LINE_C));
     expect(isolate.breakpoints.length, equals(3));
   }
 
@@ -80,42 +88,45 @@
 
 hasStoppedAtBreakpoint,
 
-// We are at the breakpoint on line 19.
+// We are at the breakpoint on line LINE_A.
 (Isolate isolate) async {
   ServiceMap stack = await isolate.getStack();
   expect(stack.type, equals('Stack'));
   expect(stack['frames'].length, greaterThanOrEqualTo(1));
 
   Script script = stack['frames'][0].location.script;
-  expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(19));
+  expect(script.tokenToLine(stack['frames'][0].location.tokenPos),
+         equals(LINE_A));
 },
 
 resumeIsolate,
 
 hasStoppedAtBreakpoint,
 
-// We are at the breakpoint on line 22.
+// We are at the breakpoint on line LINE_B.
 (Isolate isolate) async {
   ServiceMap stack = await isolate.getStack();
   expect(stack.type, equals('Stack'));
   expect(stack['frames'].length, greaterThanOrEqualTo(1));
 
   Script script = stack['frames'][0].location.script;
-  expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(22));
+  expect(script.tokenToLine(stack['frames'][0].location.tokenPos),
+         equals(LINE_B));
 },
 
 resumeIsolate,
 
 hasStoppedAtBreakpoint,
 
-// We are at the breakpoint on line 25.
+// We are at the breakpoint on line LINE_C.
 (Isolate isolate) async {
   ServiceMap stack = await isolate.getStack();
   expect(stack.type, equals('Stack'));
   expect(stack['frames'].length, greaterThanOrEqualTo(1));
 
   Script script = stack['frames'][0].location.script;
-  expect(script.tokenToLine(stack['frames'][0].location.tokenPos), equals(25));
+  expect(script.tokenToLine(stack['frames'][0].location.tokenPos),
+         equals(LINE_C));
 },
 
 resumeIsolate,
diff --git a/runtime/observatory/tests/service/developer_extension_test.dart b/runtime/observatory/tests/service/developer_extension_test.dart
index e29686b..5c8e5cd 100644
--- a/runtime/observatory/tests/service/developer_extension_test.dart
+++ b/runtime/observatory/tests/service/developer_extension_test.dart
@@ -9,14 +9,14 @@
 import 'package:observatory/service_io.dart';
 import 'package:observatory/cpu_profile.dart';
 import 'package:unittest/unittest.dart';
-
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
 Future<ServiceExtensionResponse> Handler(String method,
                                          Map paremeters) {
   print('Invoked extension: $method');
   switch (method) {
-    case '__delay':
+    case 'ext..delay':
       Completer c = new Completer();
       new Timer(new Duration(seconds: 1), () {
         c.complete(new ServiceExtensionResponse.result(JSON.encode({
@@ -26,23 +26,23 @@
           })));
       });
       return c.future;
-    case '__error':
+    case 'ext..error':
       return new Future.value(
               new ServiceExtensionResponse.error(
-                  ServiceExtensionResponse.kExtensionErrorMin,
+                  ServiceExtensionResponse.extensionErrorMin,
                   'My error detail.'));
-    case '__exception':
+    case 'ext..exception':
       throw "I always throw!";
-    case '__success':
+    case 'ext..success':
       return new Future.value(
           new ServiceExtensionResponse.result(JSON.encode({
               'type': '_extensionType',
               'method': method,
               'parameters': paremeters,
           })));
-    case '__null':
+    case 'ext..null':
       return null;
-    case '__nullFuture':
+    case 'ext..nullFuture':
       return new Future.value(null);
   }
 }
@@ -54,25 +54,25 @@
 }
 
 void test() {
-  registerExtension('__delay', Handler);
+  registerExtension('ext..delay', Handler);
   debugger();
   postEvent('ALPHA', {
     'cat': 'dog'
   });
   debugger();
-  registerExtension('__error', Handler);
-  registerExtension('__exception', Handler);
-  registerExtension('__null', Handler);
-  registerExtension('__nullFuture', Handler);
-  registerExtension('__success', Handler);
+  registerExtension('ext..error', Handler);
+  registerExtension('ext..exception', Handler);
+  registerExtension('ext..null', Handler);
+  registerExtension('ext..nullFuture', Handler);
+  registerExtension('ext..success', Handler);
   bool exceptionThrown = false;
   try {
-    registerExtension('__delay', Handler);
+    registerExtension('ext..delay', Handler);
   } catch (e) {
     exceptionThrown = true;
   }
   expect(exceptionThrown, isTrue);
-  registerExtension('__languageError', LanguageErrorHandler);
+  registerExtension('ext..languageError', LanguageErrorHandler);
 }
 
 var tests = [
@@ -80,7 +80,7 @@
   (Isolate isolate) async {
     await isolate.load();
     expect(isolate.extensionRPCs.length, 1);
-    expect(isolate.extensionRPCs[0], equals('__delay'));
+    expect(isolate.extensionRPCs[0], equals('ext..delay'));
   },
   resumeIsolateAndAwaitEvent(Isolate.kExtensionStream, (ServiceEvent event) {
     expect(event.kind, equals(ServiceEvent.kExtension));
@@ -92,64 +92,63 @@
   resumeIsolateAndAwaitEvent(VM.kIsolateStream, (ServiceEvent event) {
     // Check that we received an event when '__error' was registered.
     expect(event.kind, equals(ServiceEvent.kServiceExtensionAdded));
-    expect(event.extensionRPC, equals('__error'));
+    expect(event.extensionRPC, equals('ext..error'));
   }),
   // Initial.
   (Isolate isolate) async {
     var result;
 
-    result = await isolate.invokeRpcNoUpgrade('__delay', {});
+    result = await isolate.invokeRpcNoUpgrade('ext..delay', {});
     expect(result['type'], equals('_delayedType'));
-    expect(result['method'], equals('__delay'));
+    expect(result['method'], equals('ext..delay'));
     expect(result['parameters']['isolateId'], isNotNull);
 
     try {
-      await isolate.invokeRpcNoUpgrade('__error', {});
+      await isolate.invokeRpcNoUpgrade('ext..error', {});
     } on ServerRpcException catch (e, st) {
-      expect(e.code, equals(ServiceExtensionResponse.kExtensionErrorMin));
+      expect(e.code, equals(ServiceExtensionResponse.extensionErrorMin));
       expect(e.message, equals('My error detail.'));
     }
 
     try {
-      await isolate.invokeRpcNoUpgrade('__exception', {});
+      await isolate.invokeRpcNoUpgrade('ext..exception', {});
     } on ServerRpcException catch (e, st) {
-      expect(e.code, equals(ServiceExtensionResponse.kExtensionError));
+      expect(e.code, equals(ServiceExtensionResponse.extensionError));
       expect(e.message.startsWith('I always throw!\n'), isTrue);
     }
 
     try {
-      await isolate.invokeRpcNoUpgrade('__null', {});
+      await isolate.invokeRpcNoUpgrade('ext..null', {});
     } on ServerRpcException catch (e, st) {
-      expect(e.code, equals(ServiceExtensionResponse.kExtensionError));
+      expect(e.code, equals(ServiceExtensionResponse.extensionError));
       expect(e.message, equals('Extension handler must return a Future'));
     }
 
     try {
-      await isolate.invokeRpcNoUpgrade('__nullFuture', {});
+      await isolate.invokeRpcNoUpgrade('ext..nullFuture', {});
     } on ServerRpcException catch (e, st) {
-      expect(e.code, equals(ServiceExtensionResponse.kExtensionError));
+      expect(e.code, equals(ServiceExtensionResponse.extensionError));
       expect(e.message, equals('Extension handler must complete to a '
                                'ServiceExtensionResponse'));
     }
 
-    result = await isolate.invokeRpcNoUpgrade('__success',
+    result = await isolate.invokeRpcNoUpgrade('ext..success',
                                               {'apple': 'banana'});
     expect(result['type'], equals('_extensionType'));
-    expect(result['method'], equals('__success'));
+    expect(result['method'], equals('ext..success'));
     expect(result['parameters']['isolateId'], isNotNull);
     expect(result['parameters']['apple'], equals('banana'));
 
 
     try {
-      result = await isolate.invokeRpcNoUpgrade('__languageError', {});
+      result = await isolate.invokeRpcNoUpgrade('ext..languageError', {});
     } on ServerRpcException catch (e, st) {
-      expect(e.code, equals(ServiceExtensionResponse.kExtensionError));
+      expect(e.code, equals(ServiceExtensionResponse.extensionError));
       expect(e.message, stringContainsInOrder([
-          'Error in extension `__languageError`:',
+          'Error in extension `ext..languageError`:',
           'developer_extension_test.dart',
           'semicolon expected']));
     }
-
   },
 ];
 
diff --git a/runtime/observatory/tests/service/eval_test.dart b/runtime/observatory/tests/service/eval_test.dart
index 99dfe8f..d41a70b 100644
--- a/runtime/observatory/tests/service/eval_test.dart
+++ b/runtime/observatory/tests/service/eval_test.dart
@@ -7,6 +7,7 @@
 import 'dart:developer';
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
 int globalVar = 100;
diff --git a/runtime/observatory/tests/service/evaluate_in_frame_rpc_test.dart b/runtime/observatory/tests/service/evaluate_in_frame_rpc_test.dart
index 053fd15..2c73fe6 100644
--- a/runtime/observatory/tests/service/evaluate_in_frame_rpc_test.dart
+++ b/runtime/observatory/tests/service/evaluate_in_frame_rpc_test.dart
@@ -3,10 +3,10 @@
 // BSD-style license that can be found in the LICENSE file.
 // VMOptions=--error_on_bad_type --error_on_bad_override
 
-import 'dart:async';
 import 'dart:developer';
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
 void method(int value, _) {
diff --git a/runtime/observatory/tests/service/file_service_test.dart b/runtime/observatory/tests/service/file_service_test.dart
index 22b5827..25500c6 100644
--- a/runtime/observatory/tests/service/file_service_test.dart
+++ b/runtime/observatory/tests/service/file_service_test.dart
@@ -64,20 +64,21 @@
     var result = JSON.encode({'type' : 'foobar'});
     return new Future.value(new ServiceExtensionResponse.result(result));
   }
-  registerExtension('__cleanup', cleanup);
-  registerExtension('__setup', setup);
+  registerExtension('ext.dart.io.cleanup', cleanup);
+  registerExtension('ext.dart.io.setup', setup);
 }
 
 var fileTests = [
   (Isolate isolate) async {
-    await isolate.invokeRpcNoUpgrade('__setup', {});
+    await isolate.invokeRpcNoUpgrade('ext.dart.io.setup', {});
     try {
-      var result = await isolate.invokeRpcNoUpgrade('__getOpenFiles', {});
+      var result =
+          await isolate.invokeRpcNoUpgrade('ext.dart.io.getOpenFiles', {});
       expect(result['type'], equals('_openfiles'));
 
       expect(result['data'].length, equals(2));
       var writing = await isolate.invokeRpcNoUpgrade(
-           '__getFileByID', { 'id' : result['data'][0]['id'] });
+           'ext.dart.io.getFileByID', { 'id' : result['data'][0]['id'] });
 
       expect(writing['totalRead'], equals(0));
       expect(writing['readCount'], equals(0));
@@ -87,7 +88,7 @@
       expect(writing['lastRead'], equals(0));
 
       var reading = await isolate.invokeRpcNoUpgrade(
-          '__getFileByID', { 'id' : result['data'][1]['id'] });
+          'ext.dart.io.getFileByID', { 'id' : result['data'][1]['id'] });
 
       expect(reading['totalRead'], equals(5));
       expect(reading['readCount'], equals(5));
@@ -97,7 +98,7 @@
       expect(reading['lastRead'], greaterThan(0));
 
     } finally {
-      await isolate.invokeRpcNoUpgrade('__cleanup', {});
+      await isolate.invokeRpcNoUpgrade('ext.dart.io.cleanup', {});
     }
   },
 ];
diff --git a/runtime/observatory/tests/service/get_allocation_samples_test.dart b/runtime/observatory/tests/service/get_allocation_samples_test.dart
index 698fce5..87615c9 100644
--- a/runtime/observatory/tests/service/get_allocation_samples_test.dart
+++ b/runtime/observatory/tests/service/get_allocation_samples_test.dart
@@ -7,7 +7,7 @@
 import 'package:observatory/service_io.dart';
 import 'package:observatory/cpu_profile.dart';
 import 'package:unittest/unittest.dart';
-
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
 class Foo {
@@ -67,7 +67,7 @@
     var tree = cpuProfile.loadCodeTree('exclusive');
     var node = tree.root;
     var expected =
-        ['Root', 'test', 'test', '_FunctionImpl.call', 'runIsolateTests'];
+        ['Root', 'test', 'test', '_Closure.call'];
     for (var i = 0; i < expected.length; i++) {
       expect(node.profileCode.code.name, equals(expected[i]));
       // Depth first traversal.
diff --git a/runtime/observatory/tests/service/get_object_rpc_test.dart b/runtime/observatory/tests/service/get_object_rpc_test.dart
index 6bfa71f..a98c535 100644
--- a/runtime/observatory/tests/service/get_object_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_object_rpc_test.dart
@@ -86,6 +86,99 @@
     expect(result['fields'], isEmpty);
   },
 
+  // A string
+  (Isolate isolate) async {
+    // Call eval to get a Dart list.
+    var evalResult = await eval(isolate, '"Chattanooga"');
+    var params = {
+      'objectId': evalResult['id'],
+    };
+    var result = await isolate.invokeRpcNoUpgrade('getObject', params);
+    expect(result['type'], equals('Instance'));
+    expect(result['kind'], equals('String'));
+    expect(result['_vmType'], equals('String'));
+    expect(result['id'], startsWith('objects/'));
+    expect(result['valueAsString'], equals('Chattanooga'));
+    expect(result['class']['type'], equals('@Class'));
+    expect(result['class']['name'], equals('_OneByteString'));
+    expect(result['size'], isPositive);
+    expect(result['fields'], isEmpty);
+    expect(result['length'], equals(11));
+    expect(result['offset'], isNull);
+    expect(result['count'], isNull);
+  },
+
+  // String prefix.
+  (Isolate isolate) async {
+    // Call eval to get a Dart list.
+    var evalResult = await eval(isolate, '"Chattanooga"');
+    var params = {
+      'objectId': evalResult['id'],
+      'count': 4,
+    };
+    var result = await isolate.invokeRpcNoUpgrade('getObject', params);
+    expect(result['type'], equals('Instance'));
+    expect(result['kind'], equals('String'));
+    expect(result['_vmType'], equals('String'));
+    expect(result['id'], startsWith('objects/'));
+    expect(result['valueAsString'], equals('Chat'));
+    expect(result['class']['type'], equals('@Class'));
+    expect(result['class']['name'], equals('_OneByteString'));
+    expect(result['size'], isPositive);
+    expect(result['fields'], isEmpty);
+    expect(result['length'], equals(11));
+    expect(result['offset'], isNull);
+    expect(result['count'], equals(4));
+  },
+
+  // String subrange.
+  (Isolate isolate) async {
+    // Call eval to get a Dart list.
+    var evalResult = await eval(isolate, '"Chattanooga"');
+    var params = {
+      'objectId': evalResult['id'],
+      'offset': 4,
+      'count': 6,
+    };
+    var result = await isolate.invokeRpcNoUpgrade('getObject', params);
+    expect(result['type'], equals('Instance'));
+    expect(result['kind'], equals('String'));
+    expect(result['_vmType'], equals('String'));
+    expect(result['id'], startsWith('objects/'));
+    expect(result['valueAsString'], equals('tanoog'));
+    expect(result['class']['type'], equals('@Class'));
+    expect(result['class']['name'], equals('_OneByteString'));
+    expect(result['size'], isPositive);
+    expect(result['fields'], isEmpty);
+    expect(result['length'], equals(11));
+    expect(result['offset'], equals(4));
+    expect(result['count'], equals(6));
+  },
+
+  // String with wacky offset.
+  (Isolate isolate) async {
+    // Call eval to get a Dart list.
+    var evalResult = await eval(isolate, '"Chattanooga"');
+    var params = {
+      'objectId': evalResult['id'],
+      'offset': 100,
+      'count': 2,
+    };
+    var result = await isolate.invokeRpcNoUpgrade('getObject', params);
+    expect(result['type'], equals('Instance'));
+    expect(result['kind'], equals('String'));
+    expect(result['_vmType'], equals('String'));
+    expect(result['id'], startsWith('objects/'));
+    expect(result['valueAsString'], equals(''));
+    expect(result['class']['type'], equals('@Class'));
+    expect(result['class']['name'], equals('_OneByteString'));
+    expect(result['size'], isPositive);
+    expect(result['fields'], isEmpty);
+    expect(result['length'], equals(11));
+    expect(result['offset'], equals(11));
+    expect(result['count'], equals(0));
+  },
+
   // A built-in List.
   (Isolate isolate) async {
     // Call eval to get a Dart list.
@@ -355,7 +448,7 @@
     expect(result['offset'], isNull);
     expect(result['count'], isNull);
     expect(result['bytes'], equals('AwIB'));
-    var bytes = BASE64.decode(result['bytes']);
+    Uint8List bytes = BASE64.decode(result['bytes']);
     expect(bytes.buffer.asUint8List().toString(), equals('[3, 2, 1]'));
   },
 
@@ -381,7 +474,7 @@
     expect(result['offset'], isNull);
     expect(result['count'], equals(2));
     expect(result['bytes'], equals('AwI='));
-    var bytes = BASE64.decode(result['bytes']);
+    Uint8List bytes = BASE64.decode(result['bytes']);
     expect(bytes.buffer.asUint8List().toString(), equals('[3, 2]'));
   },
 
@@ -408,7 +501,7 @@
     expect(result['offset'], equals(2));
     expect(result['count'], equals(1));
     expect(result['bytes'], equals('AQ=='));
-    var bytes = BASE64.decode(result['bytes']);
+    Uint8List bytes = BASE64.decode(result['bytes']);
     expect(bytes.buffer.asUint8List().toString(), equals('[1]'));
   },
 
@@ -458,7 +551,7 @@
     expect(result['offset'], isNull);
     expect(result['count'], isNull);
     expect(result['bytes'], equals('AwAAAAAAAAACAAAAAAAAAAEAAAAAAAAA'));
-    var bytes = BASE64.decode(result['bytes']);
+    Uint8List bytes = BASE64.decode(result['bytes']);
     expect(bytes.buffer.asUint64List().toString(), equals('[3, 2, 1]'));
   },
 
@@ -484,7 +577,7 @@
     expect(result['offset'], isNull);
     expect(result['count'], equals(2));
     expect(result['bytes'], equals('AwAAAAAAAAACAAAAAAAAAA=='));
-    var bytes = BASE64.decode(result['bytes']);
+    Uint8List bytes = BASE64.decode(result['bytes']);
     expect(bytes.buffer.asUint64List().toString(), equals('[3, 2]'));
   },
 
@@ -511,7 +604,7 @@
     expect(result['offset'], equals(2));
     expect(result['count'], equals(1));
     expect(result['bytes'], equals('AQAAAAAAAAA='));
-    var bytes = BASE64.decode(result['bytes']);
+    Uint8List bytes = BASE64.decode(result['bytes']);
     expect(bytes.buffer.asUint64List().toString(), equals('[1]'));
   },
 
diff --git a/runtime/observatory/tests/service/get_source_report_test.dart b/runtime/observatory/tests/service/get_source_report_test.dart
index 71345ee..006ef5b 100644
--- a/runtime/observatory/tests/service/get_source_report_test.dart
+++ b/runtime/observatory/tests/service/get_source_report_test.dart
@@ -6,6 +6,7 @@
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
 import 'test_helper.dart';
+import 'service_test_common.dart';
 import 'dart:developer';
 
 int globalVar = 100;
@@ -62,10 +63,10 @@
 
   var expectedRange = {
     'scriptIndex': 0,
-    'startPos': 33,
-    'endPos': 82,
+    'startPos': 38,
+    'endPos': 87,
     'compiled': true,
-    'coverage': {'hits': [48, 66, 76], 'misses': [54]}
+    'coverage': {'hits': [53, 71, 81], 'misses': [59]}
   };
 
   // Full script
@@ -110,7 +111,7 @@
   expect(coverage['scripts'].length, greaterThan(1));
 
   // Multiple reports (make sure enum list parameter parsing works).
-  params = { 'reports' : ['CallSites', 'Coverage'],
+  params = { 'reports' : ['_CallSites', 'Coverage', 'PossibleBreakpoints'],
              'scriptId' : func.location.script.id,
              'tokenPos' : func.location.tokenPos,
              'endTokenPos' : func.location.endTokenPos };
@@ -120,6 +121,7 @@
   var range = coverage['ranges'][0];
   expect(range.containsKey('callSites'), isTrue);
   expect(range.containsKey('coverage'), isTrue);
+  expect(range.containsKey('possibleBreakpoints'), isTrue);
 
   // missing scriptId with tokenPos.
   bool caughtException = false;
diff --git a/runtime/observatory/tests/service/get_stack_rpc_test.dart b/runtime/observatory/tests/service/get_stack_rpc_test.dart
index 7757819..7efc7e7 100644
--- a/runtime/observatory/tests/service/get_stack_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_stack_rpc_test.dart
@@ -5,13 +5,14 @@
 
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 import 'dart:async';
 import 'dart:isolate' as isolate;
 import 'dart:developer' as developer;
 
 int counter = 0;
-const stoppedAtLine = 23;
+const stoppedAtLine = 24;
 var port = new isolate.RawReceivePort(msgHandler);
 
 // This name is used in a test below.
diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart
index 3df8d67..d4c4913 100644
--- a/runtime/observatory/tests/service/get_version_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_version_rpc_test.dart
@@ -13,7 +13,7 @@
     var result = await vm.invokeRpcNoUpgrade('getVersion', {});
     expect(result['type'], equals('Version'));
     expect(result['major'], equals(3));
-    expect(result['minor'], equals(0));
+    expect(result['minor'], equals(3));
     expect(result['_privateMajor'], equals(0));
     expect(result['_privateMinor'], equals(0));
   },
diff --git a/runtime/observatory/tests/service/graph_test.dart b/runtime/observatory/tests/service/graph_test.dart
index 3cf8c46..fe31d16 100644
--- a/runtime/observatory/tests/service/graph_test.dart
+++ b/runtime/observatory/tests/service/graph_test.dart
@@ -71,9 +71,15 @@
                                       bVertex.shallowSize +
                                       rVertex.shallowSize));
 
-  const int fixedSizeListCid = 62;
+  Library corelib =
+      isolate.libraries.singleWhere((lib) => lib.uri == 'dart:core');
+  await corelib.load();
+  Class _List =
+      corelib.classes.singleWhere((cls) => cls.vmName.startsWith('_List'));
+  int kArrayCid = _List.vmCid;
+  // startsWith to ignore the private mangling
   List<ObjectVertex> lists = new List.from(graph.vertices.where(
-      (ObjectVertex obj) => obj.vmCid == fixedSizeListCid));
+      (ObjectVertex obj) => obj.vmCid == kArrayCid));
   expect(lists.length >= 2, isTrue);
   // Order by decreasing retained size.
   lists.sort((u, v) => v.retainedSize - u.retainedSize);
diff --git a/runtime/observatory/tests/service/isolate_lifecycle_test.dart b/runtime/observatory/tests/service/isolate_lifecycle_test.dart
index f88b123..992b100 100644
--- a/runtime/observatory/tests/service/isolate_lifecycle_test.dart
+++ b/runtime/observatory/tests/service/isolate_lifecycle_test.dart
@@ -9,7 +9,7 @@
 
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
-
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
 final spawnCount = 4;
@@ -131,7 +131,7 @@
   },
 
   (VM vm) async {
-    expect(numPaused(vm), spawnCount + 1 - resumeCount); 
+    expect(numPaused(vm), spawnCount + 1 - resumeCount);
   },
 ];
 
diff --git a/runtime/observatory/tests/service/issue_25465_test.dart b/runtime/observatory/tests/service/issue_25465_test.dart
new file mode 100644
index 0000000..21f91bd
--- /dev/null
+++ b/runtime/observatory/tests/service/issue_25465_test.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+import 'service_test_common.dart';
+import 'dart:async';
+
+const int LINE_A = 16;
+const int LINE_B = 17;
+
+testMain() {
+  var foo;      // line A
+  foo = 42;     // line B
+  print(foo);
+}
+
+var tests = [
+  hasPausedAtStart,
+
+  // Add breakpoints at line 11 and line 12.
+  (Isolate isolate) async {
+    var rootLib = isolate.rootLibrary;
+    await rootLib.load();
+    var script = rootLib.scripts[0];
+
+    var bpt1 = await isolate.addBreakpoint(script, LINE_A);
+    var bpt2 = await isolate.addBreakpoint(script, LINE_B);
+    expect(await bpt1.location.getLine(), equals(LINE_A));
+    expect(await bpt2.location.getLine(), equals(LINE_B));
+
+    var stream = await isolate.vm.getEventStream(VM.kDebugStream);
+    Completer completer = new Completer();
+    var subscription;
+    var breakCount = 0;
+    subscription = stream.listen((ServiceEvent event) async {
+      if (event.kind == ServiceEvent.kPauseBreakpoint) {
+        breakCount++;
+        print('break count is $breakCount');
+        if (breakCount == 1) {
+          // We are stopped at breakpoint 1.
+          expect(event.breakpoint.number, equals(bpt1.number));
+
+          // Remove both breakpoints
+          var result = await isolate.removeBreakpoint(bpt1);
+          expect(result.type, equals("Success"));
+
+          result = await isolate.removeBreakpoint(bpt2);
+          expect(result.type, equals("Success"));
+
+          isolate.stepOver();
+        } else {
+          // No breakpoint.
+          expect(event.breakpoint, isNull);
+
+          // We expect the next step to take us to line B.
+          var stack = await isolate.getStack();
+          expect(await stack['frames'][0].location.getLine(), equals(LINE_B));
+
+          subscription.cancel();
+          completer.complete(null);
+        }
+      }
+    });
+    isolate.resume();
+    await completer.future;
+  },
+];
+
+main(args) => runIsolateTests(args, tests,
+                              testeeConcurrent: testMain,
+                              pause_on_start: true);
diff --git a/runtime/observatory/tests/service/logging_test.dart b/runtime/observatory/tests/service/logging_test.dart
index cefa67b..777412f 100644
--- a/runtime/observatory/tests/service/logging_test.dart
+++ b/runtime/observatory/tests/service/logging_test.dart
@@ -6,7 +6,7 @@
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
 import 'package:logging/logging.dart';
-
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
 void init() {
@@ -40,6 +40,7 @@
     expect(event.logRecord['level'], equals(Level.FINE));
     expect(event.logRecord['time'], new isInstanceOf<DateTime>());
   }),
+  hasStoppedAtBreakpoint,
   resumeIsolateAndAwaitEvent(Isolate.kLoggingStream, (ServiceEvent event) {
     expect(event.kind, equals(ServiceEvent.kLogging));
     expect(event.logRecord['sequenceNumber'], equals(1));
diff --git a/runtime/observatory/tests/service/parameters_in_scope_at_entry_test.dart b/runtime/observatory/tests/service/parameters_in_scope_at_entry_test.dart
index 0e4209a..7f90eec 100644
--- a/runtime/observatory/tests/service/parameters_in_scope_at_entry_test.dart
+++ b/runtime/observatory/tests/service/parameters_in_scope_at_entry_test.dart
@@ -8,6 +8,11 @@
 import 'dart:developer';
 import 'package:unittest/unittest.dart';
 
+import 'service_test_common.dart';
+
+const int LINE_A = 29;
+const int LINE_B = 33;
+
 foo(param) {
   return param;
 }
@@ -21,16 +26,16 @@
 
 testMain() {
   debugger();
-  foo("in-scope");  // Line 24
+  foo("in-scope");  // Line A.
 
   var f = fooClosure();
   debugger();
-  f("in-scope");  // Line 28
+  f("in-scope");  // Line B.
 }
 
 var tests = [
   hasStoppedAtBreakpoint,
-  stoppedAtLine(24),
+  stoppedAtLine(LINE_A),
   (isolate) => isolate.stepInto(),
   hasStoppedAtBreakpoint,
   (isolate) async {
@@ -47,7 +52,7 @@
   resumeIsolate,
 
   hasStoppedAtBreakpoint,
-  stoppedAtLine(28),
+  stoppedAtLine(LINE_B),
   (isolate) => isolate.stepInto(),
   hasStoppedAtBreakpoint,
   (isolate) async {
diff --git a/runtime/observatory/tests/service/pause_on_unhandled_exceptions_test.dart b/runtime/observatory/tests/service/pause_on_unhandled_exceptions_test.dart
new file mode 100644
index 0000000..2e09acc
--- /dev/null
+++ b/runtime/observatory/tests/service/pause_on_unhandled_exceptions_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+import 'service_test_common.dart';
+
+doThrow() {
+  throw "TheException"; // Line 13.
+  return "end of doThrow";
+}
+
+var tests = [
+  hasStoppedWithUnhandledException,
+
+  (Isolate isolate) async {
+    print("We stoppped!");
+    var stack = await isolate.getStack();
+    expect(stack['frames'][0].function.name, equals('doThrow'));
+  }
+];
+
+main(args) => runIsolateTestsSynchronous(args,
+                                         tests,
+                                         pause_on_unhandled_exceptions: true,
+                                         testeeConcurrent: doThrow);
diff --git a/runtime/observatory/tests/service/process_service_test.dart b/runtime/observatory/tests/service/process_service_test.dart
index 956cc77..ee529c9 100644
--- a/runtime/observatory/tests/service/process_service_test.dart
+++ b/runtime/observatory/tests/service/process_service_test.dart
@@ -73,31 +73,32 @@
     return  process3.exitCode.then((int exit) => returnValue);
   }
 
-  registerExtension('__cleanup', cleanup);
-  registerExtension('__setup', setup);
-  registerExtension('__closeStdin', closeStdin);
+  registerExtension('ext.dart.io.cleanup', cleanup);
+  registerExtension('ext.dart.io.setup', setup);
+  registerExtension('ext.dart.io.closeStdin', closeStdin);
 
 }
 
 var processTests = [
   // Initial.
   (Isolate isolate) async {
-    var setup = await isolate.invokeRpcNoUpgrade('__setup', {});
+    var setup = await isolate.invokeRpcNoUpgrade('ext.dart.io.setup', {});
     try {
-      var all = await isolate.invokeRpcNoUpgrade('__getProcesses', {});
+      var all =
+          await isolate.invokeRpcNoUpgrade('ext.dart.io.getProcesses', {});
       expect(all['type'], equals('_startedprocesses'));
 
       expect(all['data'].length, equals(3));
 
       var first = await isolate.invokeRpcNoUpgrade(
-          '__getProcessById', { 'id' : all['data'][0]['id'] });
+          'ext.dart.io.getProcessById', { 'id' : all['data'][0]['id'] });
       expect(first['name'], io.Platform.executable);
       expect(first['pid'], equals(setup['pids'][0]));
       expect(first['arguments'].contains('foobar'), isFalse);
       expect(first['startedAt'], greaterThan(0));
 
       var second = await isolate.invokeRpcNoUpgrade(
-          '__getProcessById', { 'id' : all['data'][1]['id'] });
+          'ext.dart.io.getProcessById', { 'id' : all['data'][1]['id'] });
       expect(second['name'], io.Platform.executable);
       expect(second['pid'], equals(setup['pids'][1]));
       expect(second['arguments'].contains('foobar'), isTrue);
@@ -106,19 +107,19 @@
       expect(second['startedAt'], greaterThanOrEqualTo(first['startedAt']));
 
       var third = await isolate.invokeRpcNoUpgrade(
-          '__getProcessById', { 'id' : all['data'][2]['id'] });
+          'ext.dart.io.getProcessById', { 'id' : all['data'][2]['id'] });
       expect(third['name'], io.Platform.executable);
       expect(third['pid'], equals(setup['pids'][2]));
       expect(third['pid'] != first['pid'], isTrue);
       expect(third['pid'] != second['pid'], isTrue);
       expect(third['startedAt'], greaterThanOrEqualTo(second['startedAt']));
 
-      await isolate.invokeRpcNoUpgrade('__closeStdin', {});
-      all = await isolate.invokeRpcNoUpgrade('__getProcesses', {});
+      await isolate.invokeRpcNoUpgrade('ext.dart.io.closeStdin', {});
+      all = await isolate.invokeRpcNoUpgrade('ext.dart.io.getProcesses', {});
       expect(all['type'], equals('_startedprocesses'));
       expect(all['data'].length, equals(2));
     } finally {
-      await isolate.invokeRpcNoUpgrade('__cleanup', {});
+      await isolate.invokeRpcNoUpgrade('ext.dart.io.cleanup', {});
     }
   },
 ];
diff --git a/runtime/observatory/tests/service/reachable_size_test.dart b/runtime/observatory/tests/service/reachable_size_test.dart
index 5c346e3..ae6827e 100644
--- a/runtime/observatory/tests/service/reachable_size_test.dart
+++ b/runtime/observatory/tests/service/reachable_size_test.dart
@@ -6,6 +6,7 @@
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
 import 'test_helper.dart';
+import 'service_test_common.dart';
 
 class Pair {
   var x, y;
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index 7562cf4..0e3d8fd 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -22,4 +22,15 @@
 process_service_test: Pass, Fail # Issue 24344
 
 [ ($noopt || $compiler == precompiler) ]
-*: Skip # Issue 24651
\ No newline at end of file
+*: Skip # Issue 24651
+
+[ $runtime == vm ]
+coverage_test: Pass, Slow
+
+# Service protocol is not supported in product mode.
+[ $mode == product ]
+*: SkipByDesign
+
+# Service protocol is not supported when running a full application snapshot.
+[ ($runtime == dart_product) ]
+*: SkipByDesign
diff --git a/runtime/observatory/tests/service/service_test_common.dart b/runtime/observatory/tests/service/service_test_common.dart
new file mode 100644
index 0000000..7435ee5
--- /dev/null
+++ b/runtime/observatory/tests/service/service_test_common.dart
@@ -0,0 +1,236 @@
+// 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 service_test_common;
+
+import 'dart:async';
+import 'package:observatory/service_common.dart';
+import 'package:unittest/unittest.dart';
+
+typedef Future IsolateTest(Isolate isolate);
+typedef Future VMTest(VM vm);
+
+Future asyncStepOver(Isolate isolate) async {
+  final Completer pausedAtSyntheticBreakpoint = new Completer();
+  StreamSubscription subscription;
+
+  // Cancel the subscription.
+  cancelSubscription() {
+    if (subscription != null) {
+      subscription.cancel();
+      subscription = null;
+    }
+  }
+
+  // Complete futures with with error.
+  completeError(error) {
+    if (!pausedAtSyntheticBreakpoint.isCompleted) {
+      pausedAtSyntheticBreakpoint.completeError(error);
+    }
+  }
+
+  // Subscribe to the debugger event stream.
+  Stream stream;
+  try {
+    stream = await isolate.vm.getEventStream(VM.kDebugStream);
+  } catch (e) {
+    completeError(e);
+    return pausedAtSyntheticBreakpoint.future;
+  }
+
+  Breakpoint syntheticBreakpoint;
+
+  subscription = stream.listen((ServiceEvent event) async {
+    // Synthetic breakpoint add event. This is the first event we will
+    // receive.
+    bool isAdd = (event.kind == ServiceEvent.kBreakpointAdded) &&
+                 (event.breakpoint.isSyntheticAsyncContinuation) &&
+                 (event.owner == isolate);
+    // Resume after synthetic breakpoint added. This is the second event
+    // we will recieve.
+    bool isResume = (event.kind == ServiceEvent.kResume) &&
+                    (syntheticBreakpoint != null) &&
+                    (event.owner == isolate);
+    // Paused at synthetic breakpoint. This is the third event we will
+    // receive.
+    bool isPaused = (event.kind == ServiceEvent.kPauseBreakpoint) &&
+                    (syntheticBreakpoint != null) &&
+                    (event.breakpoint == syntheticBreakpoint);
+    if (isAdd) {
+      syntheticBreakpoint = event.breakpoint;
+    } else if (isResume) {
+    } else if (isPaused) {
+      pausedAtSyntheticBreakpoint.complete(isolate);
+      syntheticBreakpoint = null;
+      cancelSubscription();
+    }
+  });
+
+  // Issue the step OverAwait command.
+  try {
+    await isolate.stepOverAsyncSuspension();
+  } catch (e) {
+    // This can fail when another client issued the same resume command
+    // or another client has moved the isolate forward.
+    cancelSubscription();
+    completeError(e);
+  }
+
+  return pausedAtSyntheticBreakpoint.future;
+}
+
+
+Future<Isolate> hasPausedFor(Isolate isolate, String kind) {
+  // Set up a listener to wait for breakpoint events.
+  Completer completer = new Completer();
+  isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+    var subscription;
+    subscription = stream.listen((ServiceEvent event) {
+        if (event.kind == kind) {
+          print('Paused with $kind');
+          subscription.cancel();
+          if (completer != null) {
+            // Reload to update isolate.pauseEvent.
+            completer.complete(isolate.reload());
+            completer = null;
+          }
+        }
+    });
+
+    // Pause may have happened before we subscribed.
+    isolate.reload().then((_) {
+      if ((isolate.pauseEvent != null) &&
+         (isolate.pauseEvent.kind == kind)) {
+        // Already waiting at a breakpoint.
+        print('Paused with $kind');
+        subscription.cancel();
+        if (completer != null) {
+          completer.complete(isolate);
+          completer = null;
+        }
+      }
+    });
+  });
+
+  return completer.future;  // Will complete when breakpoint hit.
+}
+
+Future<Isolate> hasStoppedAtBreakpoint(Isolate isolate) {
+  return hasPausedFor(isolate, ServiceEvent.kPauseBreakpoint);
+}
+
+Future<Isolate> hasStoppedWithUnhandledException(Isolate isolate) {
+  return hasPausedFor(isolate, ServiceEvent.kPauseException);
+}
+
+Future<Isolate> hasPausedAtStart(Isolate isolate) {
+  return hasPausedFor(isolate, ServiceEvent.kPauseStart);
+}
+
+// Currying is your friend.
+IsolateTest setBreakpointAtLine(int line) {
+  return (Isolate isolate) async {
+    print("Setting breakpoint for line $line");
+    Library lib = await isolate.rootLibrary.load();
+    Script script = lib.scripts.single;
+
+    Breakpoint bpt = await isolate.addBreakpoint(script, line);
+    print("Breakpoint is $bpt");
+    expect(bpt, isNotNull);
+    expect(bpt is Breakpoint, isTrue);
+  };
+}
+
+IsolateTest stoppedAtLine(int line) {
+  return (Isolate isolate) async {
+    print("Checking we are at line $line");
+
+    ServiceMap stack = await isolate.getStack();
+    expect(stack.type, equals('Stack'));
+
+    List<Frame> frames = stack['frames'];
+    expect(frames.length, greaterThanOrEqualTo(1));
+
+    Frame top = frames[0];
+    Script script = await top.location.script.load();
+    int actualLine = script.tokenToLine(top.location.tokenPos);
+    if (actualLine != line) {
+      var sb = new StringBuffer();
+      sb.write("Expected to be at line $line but actually at line $actualLine");
+      sb.write("\nFull stack trace:\n");
+      for (Frame f in stack['frames']) {
+        sb.write(" $f [${await f.location.getLine()}]\n");
+      }
+      throw sb.toString();
+    }
+  };
+}
+
+
+Future<Isolate> resumeIsolate(Isolate isolate) {
+  Completer completer = new Completer();
+  isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+    var subscription;
+    subscription = stream.listen((ServiceEvent event) {
+      if (event.kind == ServiceEvent.kResume) {
+        subscription.cancel();
+        completer.complete();
+      }
+    });
+  });
+  isolate.resume();
+  return completer.future;
+}
+
+
+Future resumeAndAwaitEvent(Isolate isolate, stream, onEvent) async {
+  Completer completer = new Completer();
+  var sub;
+  sub = await isolate.vm.listenEventStream(
+    stream,
+    (ServiceEvent event) {
+      var r = onEvent(event);
+      if (r is! Future) {
+        r = new Future.value(r);
+      }
+      r.then((x) => sub.cancel().then((_) {
+        completer.complete();
+      }));
+    });
+  await isolate.resume();
+  return completer.future;
+}
+
+IsolateTest resumeIsolateAndAwaitEvent(stream, onEvent) {
+  return (Isolate isolate) async =>
+      resumeAndAwaitEvent(isolate, stream, onEvent);
+}
+
+
+Future<Isolate> stepOver(Isolate isolate) async {
+  await isolate.stepOver();
+  return hasStoppedAtBreakpoint(isolate);
+}
+
+Future<Class> getClassFromRootLib(Isolate isolate, String className) async {
+  Library rootLib = await isolate.rootLibrary.load();
+  for (var i = 0; i < rootLib.classes.length; i++) {
+    Class cls = rootLib.classes[i];
+    if (cls.name == className) {
+      return cls;
+    }
+  }
+  return null;
+}
+
+
+Future<Instance> rootLibraryFieldValue(Isolate isolate,
+                                       String fieldName) async {
+  Library rootLib = await isolate.rootLibrary.load();
+  Field field = rootLib.variables.singleWhere((v) => v.name == fieldName);
+  await field.load();
+  Instance value = field.staticValue;
+  await value.load();
+  return value;
+}
diff --git a/runtime/observatory/tests/service/smart_next_test.dart b/runtime/observatory/tests/service/smart_next_test.dart
index aeb819f..e0576a7 100644
--- a/runtime/observatory/tests/service/smart_next_test.dart
+++ b/runtime/observatory/tests/service/smart_next_test.dart
@@ -7,18 +7,21 @@
 import 'test_helper.dart';
 import 'dart:async';
 import 'dart:developer';
+import 'service_test_common.dart';
+
+const int LINE_A = 19;
 
 foo() async { }
 bar() { }
 
 doAsync(stop) async {
   if (stop) debugger();
-  await foo(); // Line 16.
-  bar();       // Line 17.
-  bar();       // Line 18.
-  await foo(); // Line 19.
-  await foo(); // Line 20.
-  bar();       // Line 21.
+  await foo(); // Line A.
+  bar();       // Line A + 1.
+  bar();       // Line A + 2.
+  await foo(); // Line A + 3.
+  await foo(); // Line A + 4.
+  bar();       // Line A + 5.
   return null;
 }
 
@@ -45,9 +48,9 @@
 }
 
 smartNext(Isolate isolate) async {
-  if (isolate.pauseEvent.atAsyncJump) {
+  if (isolate.pauseEvent.atAsyncSuspension) {
     print("next-async");
-    return isolate.asyncStepOver()[Isolate.kSecondResume];
+    return asyncStepOver(isolate);
   } else {
     print("next-sync");
     return stepOverAwaitingResume(isolate);
@@ -55,15 +58,15 @@
 }
 
 var tests = [
-             hasStoppedAtBreakpoint, stoppedAtLine(16), // foo()
-  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(16), // await
-  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(17), // bar()
-  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(18), // bar()
-  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(19), // foo()
-  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(19), // await
-  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(20), // foo()
-  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(20), // await
-  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(21), // bar()
+             hasStoppedAtBreakpoint, stoppedAtLine(LINE_A), // foo()
+  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(LINE_A), // await
+  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(LINE_A + 1), // bar()
+  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(LINE_A + 2), // bar()
+  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(LINE_A + 3), // foo()
+  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(LINE_A + 3), // await
+  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(LINE_A + 4), // foo()
+  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(LINE_A + 4), // await
+  smartNext, hasStoppedAtBreakpoint, stoppedAtLine(LINE_A + 5), // bar()
   resumeIsolate,
 ];
 
diff --git a/runtime/observatory/tests/service/step_into_async_no_await_test.dart b/runtime/observatory/tests/service/step_into_async_no_await_test.dart
index f9dddd5..fcae338 100644
--- a/runtime/observatory/tests/service/step_into_async_no_await_test.dart
+++ b/runtime/observatory/tests/service/step_into_async_no_await_test.dart
@@ -5,6 +5,9 @@
 
 import 'test_helper.dart';
 import 'dart:developer';
+import 'service_test_common.dart';
+
+const int LINE_A = 20;
 
 // :async_op will not be captured in this function because it never needs to
 // reschedule it.
@@ -14,12 +17,12 @@
 
 testMain() {
   debugger();
-  asyncWithoutAwait();  // Line 17
+  asyncWithoutAwait();  // Line A.
 }
 
 var tests = [
   hasStoppedAtBreakpoint,
-  stoppedAtLine(17),
+  stoppedAtLine(LINE_A),
   (isolate) => isolate.stepInto(),
   hasStoppedAtBreakpoint,
   (isolate) => isolate.getStack(),  // Should not crash.
diff --git a/runtime/observatory/tests/service/step_over_await_test.dart b/runtime/observatory/tests/service/step_over_await_test.dart
new file mode 100644
index 0000000..4f57a52
--- /dev/null
+++ b/runtime/observatory/tests/service/step_over_await_test.dart
@@ -0,0 +1,176 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override  --verbose_debug --trace_service
+
+import 'dart:async';
+import 'dart:developer';
+
+import 'test_helper.dart';
+import 'service_test_common.dart';
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+const int LINE_A = 24;
+const int LINE_B = 26;
+const int LINE_C = 28;
+const int LINE_D = 29;
+
+// This tests the low level synthetic breakpoint added / paused / removed
+// machinery triggered by the step OverAwait command.
+asyncWithoutAwait() async {
+  debugger();
+  print('a');  // LINE_A
+  await new Future.delayed(new Duration(seconds: 2));
+  print('b');  // LINE_B
+  debugger();  // LINE_C
+  debugger();  // LINE_D
+}
+
+testMain() {
+  asyncWithoutAwait();
+}
+
+Breakpoint syntheticBreakpoint;
+
+Future<Isolate> testLowLevelAwaitOver(
+    Isolate isolate) {
+  assert(isolate.pauseEvent.atAsyncSuspension);
+
+  int state = 0;
+  bool firstResume = true;
+  handleBreakpointAdded(ServiceEvent event) {
+    expect(syntheticBreakpoint, isNull);
+    expect(state, 0);
+    if (!event.breakpoint.isSyntheticAsyncContinuation) {
+      // Not a synthetic async breakpoint.
+      return;
+    }
+    if (event.owner != isolate) {
+      // Wrong isolate.
+      return;
+    }
+    syntheticBreakpoint = event.breakpoint;
+    print('!!!! Synthetic async breakpoint added ${syntheticBreakpoint}');
+    state = 1;
+  }
+
+  handleResume(ServiceEvent event) {
+    if (firstResume) {
+      expect(state, 1);
+      if (event.owner != isolate) {
+        // Wrong isolate.
+        return;
+      }
+      print('!!!! Got first resume.');
+      state = 2;
+      firstResume = false;
+    } else {
+      expect(state, 3);
+      if (event.owner != isolate) {
+        // Wrong isolate.
+        return;
+      }
+      print('!!!! Got second resume.');
+      state = 4;
+    }
+
+  }
+
+  handlePauseBreakpoint(ServiceEvent event) {
+    expect(syntheticBreakpoint, isNotNull);
+    expect(state, 2);
+    if (!event.breakpoint.isSyntheticAsyncContinuation) {
+      // Not a synthetic async breakpoint.
+      return;
+    }
+    if (event.owner != isolate) {
+      // Wrong isolate.
+      return;
+    }
+    expect(event.breakpoint, equals(syntheticBreakpoint));
+    print('!!!! Paused at synthetic async breakpoint ${syntheticBreakpoint}');
+    state = 3;
+  }
+
+  handleBreakpointRemoved(ServiceEvent event) {
+    expect(syntheticBreakpoint, isNotNull);
+    expect(state, 4);
+    if (!event.breakpoint.isSyntheticAsyncContinuation) {
+      // Not a synthetic async breakpoint.
+      return;
+    }
+    if (event.owner != isolate) {
+      // Wrong isolate.
+      return;
+    }
+    expect(event.breakpoint, equals(syntheticBreakpoint));
+    print('!!!! Synthetic async breakpoint removed ${syntheticBreakpoint}');
+    state = 5;
+    syntheticBreakpoint = null;
+  }
+
+  // Set up a listener to wait for debugger events.
+  Completer completer = new Completer();
+  isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
+    var subscription;
+    subscription = stream.listen((ServiceEvent event) async {
+      if (event.kind == ServiceEvent.kBreakpointAdded) {
+        handleBreakpointAdded(event);
+        expect(state, 1);
+      } else if (event.kind == ServiceEvent.kResume) {
+        if (firstResume) {
+          handleResume(event);
+          expect(state, 2);
+        } else {
+          handleResume(event);
+          expect(state, 4);
+        }
+      } else if (event.kind == ServiceEvent.kPauseBreakpoint) {
+        handlePauseBreakpoint(event);
+        expect(state, 3);
+        // Check that we are paused after the await statement.
+        await (stoppedAtLine(LINE_B)(isolate));
+        // Resume the isolate so that we trigger the breakpoint removal.
+        print('!!!! Triggering synthetic breakpoint removal.');
+        isolate.resume();
+      } else if (event.kind == ServiceEvent.kBreakpointRemoved) {
+        handleBreakpointRemoved(event);
+        expect(state, 5);
+        subscription.cancel();
+        if (completer != null) {
+          // Reload to update isolate.pauseEvent.
+          completer.complete(isolate.reload());
+          completer = null;
+        }
+      }
+    });
+  });
+
+  isolate.stepOverAsyncSuspension();
+
+  return completer.future;  // Will complete when breakpoint added.
+}
+
+
+var tests = [
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_A),
+  stepOver,
+  stepOver,
+  stepOver,
+  (Isolate isolate) async {
+    expect(isolate.pauseEvent.atAsyncSuspension, isTrue);
+    expect(syntheticBreakpoint, isNull);
+  },
+  testLowLevelAwaitOver,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_C),
+  resumeIsolate,
+  hasStoppedAtBreakpoint,
+  stoppedAtLine(LINE_D),
+  resumeIsolate,
+];
+
+main(args) => runIsolateTests(args, tests, testeeConcurrent: testMain);
diff --git a/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart b/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart
index 20a9b76..38e415b 100644
--- a/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart
+++ b/runtime/observatory/tests/service/tcp_socket_closing_service_test.dart
@@ -54,13 +54,14 @@
 var tests = [
   // Initial.
   (Isolate isolate) async {
-    var result = await isolate.invokeRpcNoUpgrade('__getOpenSockets', {});
+    var result =
+        await isolate.invokeRpcNoUpgrade('ext.dart.io.getOpenSockets', {});
     expect(result['type'], equals('_opensockets'));
     // We expect only one socket to be open, the server socket create at the
     // end of test.
     expect(result['data'].length, equals(1));
     var server = await isolate.invokeRpcNoUpgrade(
-        '__getSocketByID', { 'id' : result['data'][0]['id'] });
+        'ext.dart.io.getSocketByID', { 'id' : result['data'][0]['id'] });
     expect(server['listening'], isTrue);
     expect(server['lastRead'], equals(0));
     expect(server['totalRead'], equals(0));
diff --git a/runtime/observatory/tests/service/tcp_socket_service_test.dart b/runtime/observatory/tests/service/tcp_socket_service_test.dart
index c80cad5..646b5f6 100644
--- a/runtime/observatory/tests/service/tcp_socket_service_test.dart
+++ b/runtime/observatory/tests/service/tcp_socket_service_test.dart
@@ -30,7 +30,8 @@
 var tcpTests = [
   // Initial.
   (Isolate isolate) async {
-    var result = await isolate.invokeRpcNoUpgrade('__getOpenSockets', {});
+    var result =
+            await isolate.invokeRpcNoUpgrade('ext.dart.io.getOpenSockets', {});
     expect(result['type'], equals('_opensockets'));
     // We expect 3 sockets to be open (in this order):
     //   The server socket accepting connections, on port X
@@ -48,7 +49,7 @@
     expect(result['data'][2]['name'].startsWith('127.0.0.1:'), isTrue);
 
     var listening = await isolate.invokeRpcNoUpgrade(
-        '__getSocketByID', { 'id' : result['data'][0]['id'] });
+        'ext.dart.io.getSocketByID', { 'id' : result['data'][0]['id'] });
     expect(listening['id'], equals(result['data'][0]['id']));
     expect(listening['listening'], isTrue);
     expect(listening['socketType'], equals('TCP'));
@@ -64,11 +65,11 @@
     expect(listening['remotePort'], equals('NA'));
 
     var client = await isolate.invokeRpcNoUpgrade(
-        '__getSocketByID', { 'id' : result['data'][1]['id'] });
+        'ext.dart.io.getSocketByID', { 'id' : result['data'][1]['id'] });
     expect(client['id'], equals(result['data'][1]['id']));
 
     var server = await isolate.invokeRpcNoUpgrade(
-        '__getSocketByID', { 'id' : result['data'][2]['id'] });
+        'ext.dart.io.getSocketByID', { 'id' : result['data'][2]['id'] });
     expect(server['id'], equals(result['data'][2]['id']));
 
     // We expect the client to be connected on the port and
@@ -115,10 +116,10 @@
     }
 
     var secondClient = await isolate.invokeRpcNoUpgrade(
-        '__getSocketByID', { 'id' : result['data'][3]['id'] });
+        'ext.dart.io.getSocketByID', { 'id' : result['data'][3]['id'] });
     expect(secondClient['id'], equals(result['data'][3]['id']));
     var secondServer = await isolate.invokeRpcNoUpgrade(
-        '__getSocketByID', { 'id' : result['data'][4]['id'] });
+        'ext.dart.io.getSocketByID', { 'id' : result['data'][4]['id'] });
     expect(secondServer['id'], equals(result['data'][4]['id']));
 
     // We expect the client to be connected on the port and
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 58de4e6..91cb11e 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -8,32 +8,102 @@
 import 'dart:convert';
 import 'dart:io';
 import 'package:observatory/service_io.dart';
-import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
+
+/// Will be set to the http address of the VM's service protocol before
+/// any tests are invoked.
+String serviceHttpAddress;
+String serviceWebsocketAddress;
 
 bool _isWebSocketDisconnect(e) {
   return e is NetworkRpcException;
 }
 
-// This invocation should set up the state being tested.
-const String _TESTEE_MODE_FLAG = "--testee-mode";
+const String _TESTEE_ENV_KEY = 'SERVICE_TEST_TESTEE';
+const Map<String, String> _TESTEE_SPAWN_ENV = const {
+  _TESTEE_ENV_KEY: 'true'
+};
+bool _isTestee() {
+  return Platform.environment.containsKey(_TESTEE_ENV_KEY);
+}
 
-class _TestLauncher {
+class _SerivceTesteeRunner {
+  Future run({testeeBefore(): null,
+              testeeConcurrent(): null,
+              bool pause_on_start: false,
+              bool pause_on_exit: false}) async {
+    if (!pause_on_start) {
+      if (testeeBefore != null) {
+        var result = testeeBefore();
+        if (result is Future) {
+          await result;
+        }
+      }
+      print(''); // Print blank line to signal that testeeBefore has run.
+    }
+    if (testeeConcurrent != null) {
+      var result = testeeConcurrent();
+      if (result is Future) {
+        await result;
+      }
+    }
+    if (!pause_on_exit) {
+      // Wait around for the process to be killed.
+      stdin.first.then((_) => exit(0));
+    }
+  }
+
+  void runSync({void testeeBeforeSync(): null,
+                void testeeConcurrentSync(): null,
+                bool pause_on_start: false,
+                bool pause_on_exit: false}) {
+    if (!pause_on_start) {
+      if (testeeBeforeSync != null) {
+        testeeBeforeSync();
+      }
+      print(''); // Print blank line to signal that testeeBefore has run.
+    }
+    if (testeeConcurrentSync != null) {
+      testeeConcurrentSync();
+    }
+    if (!pause_on_exit) {
+      // Wait around for the process to be killed.
+      stdin.first.then((_) => exit(0));
+    }
+  }
+}
+
+class _ServiceTesteeLauncher {
   Process process;
   final List<String> args;
   bool killedByTester = false;
 
-  _TestLauncher() : args = ['--enable-vm-service:0',
-                            Platform.script.toFilePath(),
-                            _TESTEE_MODE_FLAG] {}
+  _ServiceTesteeLauncher() :
+      args = ['--enable-vm-service:0',
+              Platform.script.toFilePath()] {}
 
-  Future<int> launch(bool pause_on_start, bool pause_on_exit, bool trace_service) {
+  String get executablePath => Platform.executable;
+
+  // Spawn the testee process.
+  Future<Process> _spawnProcess(bool pause_on_start,
+                                bool pause_on_exit,
+                                bool pause_on_unhandled_exceptions,
+                                bool trace_service,
+                                bool trace_compiler) {
     assert(pause_on_start != null);
     assert(pause_on_exit != null);
     assert(trace_service != null);
+    // TODO(turnidge): I have temporarily turned on service tracing for
+    // all tests to help diagnose flaky tests.
+    trace_service = true;
     String dartExecutable = Platform.executable;
     var fullArgs = [];
     if (trace_service) {
       fullArgs.add('--trace-service');
+      fullArgs.add('--trace-service-verbose');
+    }
+    if (trace_compiler) {
+      fullArgs.add('--trace-compiler');
     }
     if (pause_on_start) {
       fullArgs.add('--pause-isolates-on-start');
@@ -41,11 +111,27 @@
     if (pause_on_exit) {
       fullArgs.add('--pause-isolates-on-exit');
     }
+    if (pause_on_unhandled_exceptions) {
+      fullArgs.add('--pause-isolates-on-unhandled-exceptions');
+    }
     fullArgs.addAll(Platform.executableArguments);
     fullArgs.addAll(args);
     print('** Launching $dartExecutable ${fullArgs.join(' ')}');
-    return Process.start(dartExecutable, fullArgs).then((p) {
+    return Process.start(dartExecutable,
+                         fullArgs,
+                         environment: _TESTEE_SPAWN_ENV);
+  }
 
+  Future<int> launch(bool pause_on_start,
+                     bool pause_on_exit,
+                     bool pause_on_unhandled_exceptions,
+                     bool trace_service,
+                     bool trace_compiler) {
+    return _spawnProcess(pause_on_start,
+                  pause_on_exit,
+                  pause_on_unhandled_exceptions,
+                  trace_service,
+                  trace_compiler).then((p) {
       Completer completer = new Completer();
       process = p;
       var portNumber;
@@ -92,60 +178,57 @@
   }
 }
 
-typedef Future IsolateTest(Isolate isolate);
-typedef Future VMTest(VM vm);
-
-/// Will be set to the http address of the VM's service protocol before
-/// any tests are invoked.
-String serviceHttpAddress;
-
-/// Runs [tests] in sequence, each of which should take an [Isolate] and
-/// return a [Future]. Code for setting up state can run before and/or
-/// concurrently with the tests. Uses [mainArgs] to determine whether
-/// to run tests or testee in this invokation of the script.
-void runIsolateTests(List<String> mainArgs,
-                     List<IsolateTest> tests,
-                     {void testeeBefore(),
-                      void testeeConcurrent(),
-                      bool pause_on_start: false,
-                      bool pause_on_exit: false,
-                      bool trace_service: false,
-                      bool verbose_vm: false}) {
-  assert(!pause_on_start || testeeBefore == null);
-  if (mainArgs.contains(_TESTEE_MODE_FLAG)) {
-    if (!pause_on_start) {
-      if (testeeBefore != null) {
-        testeeBefore();
-      }
-      print(''); // Print blank line to signal that we are ready.
-    }
-    if (testeeConcurrent != null) {
-      testeeConcurrent();
-    }
-    if (!pause_on_exit) {
-      // Wait around for the process to be killed.
-      stdin.first.then((_) => exit(0));
-    }
-  } else {
-    var process = new _TestLauncher();
-    process.launch(pause_on_start, pause_on_exit, trace_service).then((port) {
+class _ServiceTesterRunner {
+  void run({List<String> mainArgs,
+            List<VMTest> vmTests,
+            List<IsolateTest> isolateTests,
+            bool pause_on_start: false,
+            bool pause_on_exit: false,
+            bool trace_service: false,
+            bool trace_compiler: false,
+            bool verbose_vm: false,
+            bool pause_on_unhandled_exceptions: false}) {
+    var process = new _ServiceTesteeLauncher();
+    process.launch(pause_on_start, pause_on_exit,
+                   pause_on_unhandled_exceptions,
+                   trace_service, trace_compiler).then((port) async {
       if (mainArgs.contains("--gdb")) {
         port = 8181;
       }
-      String addr = 'ws://localhost:$port/ws';
+      serviceWebsocketAddress = 'ws://localhost:$port/ws';
       serviceHttpAddress = 'http://localhost:$port';
-      var testIndex = 1;
-      var totalTests = tests.length;
       var name = Platform.script.pathSegments.last;
       runZoned(() {
-        new WebSocketVM(new WebSocketVMTarget(addr)).load()
-            .then((VM vm) => vm.isolates.first.load())
-            .then((Isolate isolate) => Future.forEach(tests, (test) {
-              isolate.vm.verbose = verbose_vm;
-              print('Running $name [$testIndex/$totalTests]');
-              testIndex++;
-              return test(isolate);
-            })).then((_) => process.requestExit());
+        new WebSocketVM(new WebSocketVMTarget(serviceWebsocketAddress)).load()
+            .then((VM vm) async {
+
+              // Run vm tests.
+              if (vmTests != null) {
+                var testIndex = 1;
+                var totalTests = vmTests.length;
+                for (var test in vmTests) {
+                  vm.verbose = verbose_vm;
+                  print('Running $name [$testIndex/$totalTests]');
+                  testIndex++;
+                  await test(vm);
+                }
+              }
+
+              // Run isolate tests.
+              if (isolateTests != null) {
+                var isolate = await vm.isolates.first.load();
+                var testIndex = 1;
+                var totalTests = isolateTests.length;
+                for (var test in isolateTests) {
+                  vm.verbose = verbose_vm;
+                  print('Running $name [$testIndex/$totalTests]');
+                  testIndex++;
+                  await test(isolate);
+                }
+              }
+
+              await process.requestExit();
+            });
       }, onError: (e, st) {
         process.requestExit();
         if (!_isWebSocketDisconnect(e)) {
@@ -157,176 +240,75 @@
   }
 }
 
-
-Future<Isolate> hasStoppedAtBreakpoint(Isolate isolate) {
-  // Set up a listener to wait for breakpoint events.
-  Completer completer = new Completer();
-  isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
-    var subscription;
-    subscription = stream.listen((ServiceEvent event) {
-        if (event.kind == ServiceEvent.kPauseBreakpoint) {
-          print('Breakpoint reached');
-          subscription.cancel();
-          if (completer != null) {
-            // Reload to update isolate.pauseEvent.
-            completer.complete(isolate.reload());
-            completer = null;
-          }
-        }
-    });
-
-    // Pause may have happened before we subscribed.
-    isolate.reload().then((_) {
-      if ((isolate.pauseEvent != null) &&
-         (isolate.pauseEvent.kind == ServiceEvent.kPauseBreakpoint)) {
-        // Already waiting at a breakpoint.
-        print('Breakpoint reached');
-        subscription.cancel();
-        if (completer != null) {
-          completer.complete(isolate);
-          completer = null;
-        }
-      }
-    });
-  });
-
-  return completer.future;  // Will complete when breakpoint hit.
-}
-
-
-Future<Isolate> hasPausedAtStart(Isolate isolate) {
-  // Set up a listener to wait for breakpoint events.
-  Completer completer = new Completer();
-  isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
-    var subscription;
-    subscription = stream.listen((ServiceEvent event) {
-        if (event.kind == ServiceEvent.kPauseStart) {
-          print('Paused at isolate start');
-          subscription.cancel();
-          if (completer != null) {
-            // Reload to update isolate.pauseEvent.
-            completer.complete(isolate.reload());
-            completer = null;
-          }
-        }
-    });
-
-    // Pause may have happened before we subscribed.
-    isolate.reload().then((_) {
-      if ((isolate.pauseEvent != null) &&
-         (isolate.pauseEvent.kind == ServiceEvent.kPauseStart)) {
-        print('Paused at isolate start');
-        subscription.cancel();
-        if (completer != null) {
-          completer.complete(isolate);
-          completer = null;
-        }
-      }
-    });
-  });
-
-  return completer.future;
-}
-
-
-// Currying is your friend.
-IsolateTest setBreakpointAtLine(int line) {
-  return (Isolate isolate) async {
-    print("Setting breakpoint for line $line");
-    Library lib = await isolate.rootLibrary.load();
-    Script script = lib.scripts.single;
-
-    Breakpoint bpt = await isolate.addBreakpoint(script, line);
-    print("Breakpoint is $bpt");
-    expect(bpt, isNotNull);
-    expect(bpt is Breakpoint, isTrue);
-  };
-}
-
-IsolateTest stoppedAtLine(int line) {
-  return (Isolate isolate) async {
-    print("Checking we are at line $line");
-
-    ServiceMap stack = await isolate.getStack();
-    expect(stack.type, equals('Stack'));
-
-    List<Frame> frames = stack['frames'];
-    expect(frames.length, greaterThanOrEqualTo(1));
-
-    Frame top = frames[0];
-    Script script = await top.location.script.load();
-    if (script.tokenToLine(top.location.tokenPos) != line) {
-      var sb = new StringBuffer();
-      sb.write("Expected to be at line $line, but got stack trace:\n");
-      for (Frame f in stack['frames']) {
-        sb.write(" $f\n");
-      }
-      throw sb.toString();
-    }
-  };
-}
-
-
-Future<Isolate> resumeIsolate(Isolate isolate) {
-  Completer completer = new Completer();
-  isolate.vm.getEventStream(VM.kDebugStream).then((stream) {
-    var subscription;
-    subscription = stream.listen((ServiceEvent event) {
-      if (event.kind == ServiceEvent.kResume) {
-        subscription.cancel();
-        completer.complete();
-      }
-    });
-  });
-  isolate.resume();
-  return completer.future;
-}
-
-
-Future resumeAndAwaitEvent(Isolate isolate, stream, onEvent) async {
-  Completer completer = new Completer();
-  var sub;
-  sub = await isolate.vm.listenEventStream(
-    stream,
-    (ServiceEvent event) {
-      var r = onEvent(event);
-      if (r is! Future) {
-        r = new Future.value(r);
-      }
-      r.then((x) => sub.cancel().then((_) {
-        completer.complete();
-      }));
-    });
-  await isolate.resume();
-  return completer.future;
-}
-
-IsolateTest resumeIsolateAndAwaitEvent(stream, onEvent) {
-  return (Isolate isolate) async =>
-      resumeAndAwaitEvent(isolate, stream, onEvent);
-}
-
-
-Future<Class> getClassFromRootLib(Isolate isolate, String className) async {
-  Library rootLib = await isolate.rootLibrary.load();
-  for (var i = 0; i < rootLib.classes.length; i++) {
-    Class cls = rootLib.classes[i];
-    if (cls.name == className) {
-      return cls;
-    }
+/// Runs [tests] in sequence, each of which should take an [Isolate] and
+/// return a [Future]. Code for setting up state can run before and/or
+/// concurrently with the tests. Uses [mainArgs] to determine whether
+/// to run tests or testee in this invokation of the script.
+Future runIsolateTests(List<String> mainArgs,
+                       List<IsolateTest> tests,
+                       {testeeBefore(),
+                        testeeConcurrent(),
+                        bool pause_on_start: false,
+                        bool pause_on_exit: false,
+                        bool trace_service: false,
+                        bool trace_compiler: false,
+                        bool verbose_vm: false,
+                        bool pause_on_unhandled_exceptions: false}) async {
+  assert(!pause_on_start || testeeBefore == null);
+  if (_isTestee()) {
+    new _SerivceTesteeRunner().run(testeeBefore: testeeBefore,
+                                   testeeConcurrent: testeeConcurrent,
+                                   pause_on_start: pause_on_start,
+                                   pause_on_exit: pause_on_exit);
+  } else {
+    new _ServiceTesterRunner().run(
+        mainArgs: mainArgs,
+        isolateTests: tests,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit,
+        trace_service: trace_service,
+        trace_compiler: trace_compiler,
+        verbose_vm: verbose_vm,
+        pause_on_unhandled_exceptions: pause_on_unhandled_exceptions);
   }
-  return null;
 }
 
-
-Future<Instance> rootLibraryFieldValue(Isolate isolate,
-                                       String fieldName) async {
-  Library rootLib = await isolate.rootLibrary.load();
-  Field field = rootLib.variables.singleWhere((v) => v.name == fieldName);
-  await field.load();
-  Instance value = field.staticValue;
-  await value.load();
-  return value;
+/// Runs [tests] in sequence, each of which should take an [Isolate] and
+/// return a [Future]. Code for setting up state can run before and/or
+/// concurrently with the tests. Uses [mainArgs] to determine whether
+/// to run tests or testee in this invokation of the script.
+///
+/// This is a special version of this test harness specifically for the
+/// pause_on_unhandled_exceptions_test, which cannot properly function
+/// in an async context (because exceptions are *always* handled in async
+/// functions).
+void runIsolateTestsSynchronous(List<String> mainArgs,
+                                List<IsolateTest> tests,
+                                {void testeeBefore(),
+                                 void testeeConcurrent(),
+                                 bool pause_on_start: false,
+                                 bool pause_on_exit: false,
+                                 bool trace_service: false,
+                                 bool trace_compiler: false,
+                                 bool verbose_vm: false,
+                                 bool pause_on_unhandled_exceptions: false}) {
+  assert(!pause_on_start || testeeBefore == null);
+  if (_isTestee()) {
+    new _SerivceTesteeRunner().runSync(testeeBeforeSync: testeeBefore,
+                                       testeeConcurrentSync: testeeConcurrent,
+                                       pause_on_start: pause_on_start,
+                                       pause_on_exit: pause_on_exit);
+  } else {
+    new _ServiceTesterRunner().run(
+        mainArgs: mainArgs,
+        isolateTests: tests,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit,
+        trace_service: trace_service,
+        trace_compiler: trace_compiler,
+        verbose_vm: verbose_vm,
+        pause_on_unhandled_exceptions: pause_on_unhandled_exceptions);
+  }
 }
 
 
@@ -336,54 +318,28 @@
 /// to run tests or testee in this invokation of the script.
 Future runVMTests(List<String> mainArgs,
                   List<VMTest> tests,
-                  {Future testeeBefore(),
-                   Future testeeConcurrent(),
+                  {testeeBefore(),
+                   testeeConcurrent(),
                    bool pause_on_start: false,
                    bool pause_on_exit: false,
                    bool trace_service: false,
-                   bool verbose_vm: false}) async {
-  if (mainArgs.contains(_TESTEE_MODE_FLAG)) {
-    if (!pause_on_start) {
-      if (testeeBefore != null) {
-        await testeeBefore();
-      }
-      print(''); // Print blank line to signal that we are ready.
-    }
-    if (testeeConcurrent != null) {
-      await testeeConcurrent();
-    }
-    if (!pause_on_exit) {
-      // Wait around for the process to be killed.
-      stdin.first.then((_) => exit(0));
-    }
+                   bool trace_compiler: false,
+                   bool verbose_vm: false,
+                   bool pause_on_unhandled_exceptions: false}) async {
+  if (_isTestee()) {
+    new _SerivceTesteeRunner().run(testeeBefore: testeeBefore,
+                                   testeeConcurrent: testeeConcurrent,
+                                   pause_on_start: pause_on_start,
+                                   pause_on_exit: pause_on_exit);
   } else {
-    var process = new _TestLauncher();
-    process.launch(pause_on_start,
-                   pause_on_exit,
-                   trace_service).then((port) async {
-      if (mainArgs.contains("--gdb")) {
-        port = 8181;
-      }
-      String addr = 'ws://localhost:$port/ws';
-      serviceHttpAddress = 'http://localhost:$port';
-      var testIndex = 1;
-      var totalTests = tests.length;
-      var name = Platform.script.pathSegments.last;
-      runZoned(() {
-        new WebSocketVM(new WebSocketVMTarget(addr)).load()
-            .then((VM vm) => Future.forEach(tests, (test) {
-              vm.verbose = verbose_vm;
-              print('Running $name [$testIndex/$totalTests]');
-              testIndex++;
-              return test(vm);
-            })).then((_) => process.requestExit());
-      }, onError: (e, st) {
-        process.requestExit();
-        if (!_isWebSocketDisconnect(e)) {
-          print('Unexpected exception in service tests: $e $st');
-          throw e;
-        }
-      });
-    });
+    new _ServiceTesterRunner().run(
+        mainArgs: mainArgs,
+        vmTests: tests,
+        pause_on_start: pause_on_start,
+        pause_on_exit: pause_on_exit,
+        trace_service: trace_service,
+        trace_compiler: trace_compiler,
+        verbose_vm: verbose_vm,
+        pause_on_unhandled_exceptions: pause_on_unhandled_exceptions);
   }
 }
diff --git a/runtime/observatory/tests/service/udp_socket_service_test.dart b/runtime/observatory/tests/service/udp_socket_service_test.dart
index 49ff5e4..6a6a0e0 100644
--- a/runtime/observatory/tests/service/udp_socket_service_test.dart
+++ b/runtime/observatory/tests/service/udp_socket_service_test.dart
@@ -25,7 +25,8 @@
 var udpTests = [
   // Initial.
   (Isolate isolate) async {
-    var result = await isolate.invokeRpcNoUpgrade('__getOpenSockets', {});
+    var result =
+        await isolate.invokeRpcNoUpgrade('ext.dart.io.getOpenSockets', {});
     expect(result['type'], equals('_opensockets'));
     // We expect 2 sockets to be open (in this order):
     //   The server socket accepting connections, on port X
@@ -38,7 +39,7 @@
     expect(result['data'][1]['name'].startsWith('127.0.0.1:'), isTrue);
 
     var server = await isolate.invokeRpcNoUpgrade(
-        '__getSocketByID', { 'id' : result['data'][0]['id'] });
+        'ext.dart.io.getSocketByID', { 'id' : result['data'][0]['id'] });
     expect(server['id'], equals(result['data'][0]['id']));
     expect(server['remotePort'], equals('NA'));
     expect(server['remoteHost'], equals('NA'));
@@ -58,7 +59,7 @@
     expect(server['readCount'], greaterThanOrEqualTo(1));
 
     var client = await isolate.invokeRpcNoUpgrade(
-        '__getSocketByID', { 'id' : result['data'][1]['id'] });
+        'ext.dart.io.getSocketByID', { 'id' : result['data'][1]['id'] });
     expect(client['id'], equals(result['data'][1]['id']));
     expect(client['remotePort'], equals('NA'));
     expect(client['remoteHost'], equals('NA'));
diff --git a/runtime/observatory/tests/service/vm_restart_test.dart b/runtime/observatory/tests/service/vm_restart_test.dart
index 8f5da2e..605e7bf 100644
--- a/runtime/observatory/tests/service/vm_restart_test.dart
+++ b/runtime/observatory/tests/service/vm_restart_test.dart
@@ -7,6 +7,7 @@
 import 'dart:developer';
 import 'package:observatory/service_io.dart';
 import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
 import 'test_helper.dart';
 
 int count = 0;
@@ -69,7 +70,7 @@
         }
       }
     });
-    
+
     Completer restartCompleter = new Completer();
     var isolateStream = await isolate.vm.getEventStream(VM.kIsolateStream);
     var isolateSub;
@@ -101,5 +102,5 @@
   },
 ];
 
-  
+
 main(args) => runIsolateTests(args, tests, testeeConcurrent: test);
diff --git a/runtime/observatory/tests/service/vm_timeline_flags_test.dart b/runtime/observatory/tests/service/vm_timeline_flags_test.dart
new file mode 100644
index 0000000..6943874
--- /dev/null
+++ b/runtime/observatory/tests/service/vm_timeline_flags_test.dart
@@ -0,0 +1,114 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'dart:developer';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+primeDartTimeline() {
+  while (true) {
+    Timeline.startSync('apple');
+    Timeline.finishSync();
+    debugger();
+  }
+}
+
+bool isDart(Map event) => event['cat'] == 'Dart';
+bool isMetaData(Map event) => event['ph'] == 'M';
+bool isNotMetaData(Map event) => !isMetaData(event);
+bool isNotDartAndMetaData(Map event) => !isDart(event) && !isMetaData(event);
+
+List<Map> filterEvents(List<Map> events, filter) {
+  return events.where(filter).toList();
+}
+
+int dartEventCount;
+
+var tests = [
+  hasStoppedAtBreakpoint,
+  (Isolate isolate) async {
+    // Get the flags.
+    Map flags = await isolate.vm.invokeRpcNoUpgrade('_getVMTimelineFlags', {});
+    expect(flags['type'], 'TimelineFlags');
+    // Confirm that 'Dart' is available.
+    expect(flags['availableStreams'].contains('Dart'), isTrue);
+    // Confirm that nothing is being recorded.
+    expect(flags['recordedStreams'].length, equals(0));
+  },
+  (Isolate isolate) async {
+    // Get the timeline.
+    Map result = await isolate.vm.invokeRpcNoUpgrade('_getVMTimeline', {});
+    expect(result['type'], equals('_Timeline'));
+    expect(result['traceEvents'], new isInstanceOf<List>());
+    // Confirm that it as no non-meta data events.
+    expect(filterEvents(result['traceEvents'], isNotMetaData).length, 0);
+  },
+  (Isolate isolate) async {
+    // Enable the Dart category.
+    await isolate.vm.invokeRpcNoUpgrade('_setVMTimelineFlags', {
+      "recordedStreams": ["Dart"]
+    });
+  },
+  (Isolate isolate) async {
+    // Get the flags.
+    Map flags = await isolate.vm.invokeRpcNoUpgrade('_getVMTimelineFlags', {});
+    expect(flags['type'], 'TimelineFlags');
+    // Confirm that only Dart is being recorded.
+    expect(flags['recordedStreams'].length, equals(1));
+    expect(flags['recordedStreams'].contains('Dart'), isTrue);
+    print(flags);
+  },
+  resumeIsolate,
+  (Isolate isolate) async {
+    // Get the timeline.
+    Map result = await isolate.vm.invokeRpcNoUpgrade('_getVMTimeline', {});
+    expect(result['type'], equals('_Timeline'));
+    expect(result['traceEvents'], new isInstanceOf<List>());
+    print(result['traceEvents']);
+    // Confirm that Dart events are added.
+    expect(filterEvents(result['traceEvents'], isDart).length, greaterThan(0));
+    // Confirm that zero non-Dart events are added.
+    expect(
+        filterEvents(result['traceEvents'], isNotDartAndMetaData).length,
+        equals(0));
+  },
+  hasStoppedAtBreakpoint,
+  (Isolate isolate) async {
+    // Disable the Dart category.
+    await isolate.vm.invokeRpcNoUpgrade('_setVMTimelineFlags', {
+      "recordedStreams": []
+    });
+    // Grab the timeline and remember the number of Dart events.
+    Map result = await isolate.vm.invokeRpcNoUpgrade('_getVMTimeline', {});
+    expect(result['type'], equals('_Timeline'));
+    expect(result['traceEvents'], new isInstanceOf<List>());
+    dartEventCount = filterEvents(result['traceEvents'], isDart).length;
+  },
+  (Isolate isolate) async {
+    // Get the flags.
+    Map flags = await isolate.vm.invokeRpcNoUpgrade('_getVMTimelineFlags', {});
+    expect(flags['type'], 'TimelineFlags');
+    // Confirm that 'Dart' is not being recorded.
+    expect(flags['recordedStreams'].length, equals(0));
+  },
+  resumeIsolate,
+  (Isolate isolate) async {
+    // Grab the timeline and verify that we haven't added any new Dart events.
+    Map result = await isolate.vm.invokeRpcNoUpgrade('_getVMTimeline', {});
+    expect(result['type'], equals('_Timeline'));
+    expect(result['traceEvents'], new isInstanceOf<List>());
+    expect(filterEvents(result['traceEvents'], isDart).length, dartEventCount);
+    // Confirm that zero non-Dart events are added.
+    expect(
+        filterEvents(result['traceEvents'], isNotDartAndMetaData).length,
+        equals(0));
+  },
+];
+
+main(args) async => runIsolateTests(args,
+                                    tests,
+                                    testeeConcurrent: primeDartTimeline);
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/platform/globals.h b/runtime/platform/globals.h
index 8d3a155..d1c6ef6 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -57,7 +57,7 @@
 #include <inttypes.h>
 #include <stdint.h>
 #include <unistd.h>
-#endif
+#endif  // !defined(_WIN32)
 
 #include <float.h>
 #include <limits.h>
@@ -72,23 +72,30 @@
 #include "platform/c99_support_win.h"
 #include "platform/inttypes_support_win.h"
 #include "platform/floating_point_win.h"
-#endif
+#endif  // defined(_WIN32)
 
 #include "platform/math.h"
 
 #if !defined(_WIN32)
 #include "platform/floating_point.h"
-#endif
+#endif  // !defined(_WIN32)
 
 // Target OS detection.
 // for more information on predefined macros:
 //   - http://msdn.microsoft.com/en-us/library/b0084kay.aspx
 //   - with gcc, run: "echo | gcc -E -dM -"
 #if defined(__ANDROID__)
+
+// Check for Android first, to determine its difference from Linux.
 #define TARGET_OS_ANDROID 1
+
 #elif defined(__linux__) || defined(__FreeBSD__)
+
+// Generic Linux.
 #define TARGET_OS_LINUX 1
+
 #elif defined(__APPLE__)
+
 // Define the flavor of Mac OS we are running on.
 #include <TargetConditionals.h>
 // TODO(iposva): Rename TARGET_OS_MACOS to TARGET_OS_MAC to inherit
@@ -99,11 +106,33 @@
 #endif
 
 #elif defined(_WIN32)
+
+// Windows, both 32- and 64-bit, regardless of the check for _WIN32.
 #define TARGET_OS_WINDOWS 1
+
 #else
 #error Automatic target os detection failed.
 #endif
 
+
+// Setup product, release or debug build related macros.
+#if defined(PRODUCT) && defined(DEBUG)
+#error Both PRODUCT and DEBUG defined.
+#endif  // defined(PRODUCT) && defined(DEBUG)
+
+#if defined(PRODUCT)
+#define NOT_IN_PRODUCT(code)
+#define DEBUG_ONLY(code)
+#else  // defined(PRODUCT)
+#define NOT_IN_PRODUCT(code) code
+#if defined(DEBUG)
+#define DEBUG_ONLY(code) code
+#else  // defined(DEBUG)
+#define DEBUG_ONLY(code)
+#endif  // defined(DEBUG)
+#endif  // defined(PRODUCT)
+
+
 namespace dart {
 
 struct simd128_value_t {
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 9e4a384..508e0e7 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -204,16 +204,9 @@
 
   // dart2js represents integers as double precision floats, which can
   // represent anything in the range -2^53 ... 2^53.
-  static bool IsJavascriptInt64(int64_t value) {
+  static bool IsJavascriptInt(int64_t value) {
     return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
   }
-  static bool IsJavascriptInt(intptr_t value) {
-#if defined(ARCH_IS_64BIT)
-    return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
-#else
-    return true;
-#endif
-  }
 
   static char* StrError(int err, char* buffer, size_t bufsize);
 };
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index f5163a0..da20917 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -21,6 +21,8 @@
 # TODO(koda): Improve support for negative tests.
 cc/VerifyImplicit_Crash: Crash, Timeout  # Timeout: Issue #24596
 cc/VerifyExplicit_Crash: Crash, Timeout  # Timeout: Issue #24596
+# It can take some time for all the isolates to shutdown in a Debug build.
+dart/spawn_shutdown_test: Pass, Slow  # VM Shutdown test
 
 # The following section refers to the dart vm tests which live under
 # runtime/tests/vm/dart.
@@ -31,7 +33,7 @@
 cc/Dart2JSCompilerStats: Skip
 cc/CorelibCompilerStats: Skip
 
-[ $arch == simarm || $arch == simarmv5te || $arch == simarm64 || $arch == simmips ]
+[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simarm64 || $arch == simmips ]
 cc/Service_Profile: Skip
 
 [ $arch == arm ]
@@ -63,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
@@ -74,15 +76,26 @@
 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
 
-[ $runtime == dart_precompiled ]
-dart/inline_stack_frame_test: Fail  # Issue 24783 - inlined frames missing
-dart/data_uri_spawn_test: RuntimeError # Isolate.spawnUri
+[ $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 || $runtime == dart_precompiled ]
+dart/data_uri_spawn_test: SkipByDesign # Isolate.spawnUri
+
+[ $runtime == vm && $mode == product ]
+cc/IsolateSetCheckedMode: Fail,OK  # Expects exact type name.
+cc/LibraryGetClassNames: Fail,OK  # Expects exact type name.
+cc/StackTraceFormat: Fail,OK  # Expects exact type name.
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/third_party/double-conversion/src/bignum.cc b/runtime/third_party/double-conversion/src/bignum.cc
index 2743d67..8892de8 100644
--- a/runtime/third_party/double-conversion/src/bignum.cc
+++ b/runtime/third_party/double-conversion/src/bignum.cc
@@ -104,7 +104,7 @@
   const int kMaxUint64DecimalDigits = 19;
   Zero();
   int length = value.length();
-  int pos = 0;
+  unsigned int pos = 0;
   // Let's just say that each digit needs 4 bits.
   while (length >= kMaxUint64DecimalDigits) {
     uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
diff --git a/runtime/third_party/double-conversion/src/bignum.h b/runtime/third_party/double-conversion/src/bignum.h
index 5ec3544..c385f22 100644
--- a/runtime/third_party/double-conversion/src/bignum.h
+++ b/runtime/third_party/double-conversion/src/bignum.h
@@ -49,7 +49,6 @@
 
   void AssignPowerUInt16(uint16_t base, int exponent);
 
-  void AddUInt16(uint16_t operand);
   void AddUInt64(uint64_t operand);
   void AddBignum(const Bignum& other);
   // Precondition: this >= other.
diff --git a/runtime/third_party/double-conversion/src/cached-powers.cc b/runtime/third_party/double-conversion/src/cached-powers.cc
index d1359ff..2b43f06 100644
--- a/runtime/third_party/double-conversion/src/cached-powers.cc
+++ b/runtime/third_party/double-conversion/src/cached-powers.cc
@@ -131,7 +131,6 @@
   {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340},
 };
 
-static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers);
 static const int kCachedPowersOffset = 348;  // -1 * the first decimal_exponent.
 static const double kD_1_LOG2_10 = 0.30102999566398114;  //  1 / lg(10)
 // Difference between the decimal exponents in the table above.
@@ -149,7 +148,7 @@
   int foo = kCachedPowersOffset;
   int index =
       (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;
-  ASSERT(0 <= index && index < kCachedPowersLength);
+  ASSERT(0 <= index && index < static_cast<int>(ARRAY_SIZE(kCachedPowers)));
   CachedPower cached_power = kCachedPowers[index];
   ASSERT(min_exponent <= cached_power.binary_exponent);
   (void) max_exponent;  // Mark variable as used.
diff --git a/runtime/third_party/double-conversion/src/diy-fp.h b/runtime/third_party/double-conversion/src/diy-fp.h
index 9dcf8fb..2edf346 100644
--- a/runtime/third_party/double-conversion/src/diy-fp.h
+++ b/runtime/third_party/double-conversion/src/diy-fp.h
@@ -42,7 +42,7 @@
   static const int kSignificandSize = 64;
 
   DiyFp() : f_(0), e_(0) {}
-  DiyFp(uint64_t f, int e) : f_(f), e_(e) {}
+  DiyFp(uint64_t significand, int exponent) : f_(significand), e_(exponent) {}
 
   // this = this - other.
   // The exponents of both numbers must be the same and the significand of this
@@ -76,22 +76,22 @@
 
   void Normalize() {
     ASSERT(f_ != 0);
-    uint64_t f = f_;
-    int e = e_;
+    uint64_t significand = f_;
+    int exponent = e_;
 
     // This method is mainly called for normalizing boundaries. In general
     // boundaries need to be shifted by 10 bits. We thus optimize for this case.
     const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000);
-    while ((f & k10MSBits) == 0) {
-      f <<= 10;
-      e -= 10;
+    while ((significand & k10MSBits) == 0) {
+      significand <<= 10;
+      exponent -= 10;
     }
-    while ((f & kUint64MSB) == 0) {
-      f <<= 1;
-      e--;
+    while ((significand & kUint64MSB) == 0) {
+      significand <<= 1;
+      exponent--;
     }
-    f_ = f;
-    e_ = e;
+    f_ = significand;
+    e_ = exponent;
   }
 
   static DiyFp Normalize(const DiyFp& a) {
diff --git a/runtime/third_party/double-conversion/src/double-conversion.cc b/runtime/third_party/double-conversion/src/double-conversion.cc
index e379299..477f94e 100644
--- a/runtime/third_party/double-conversion/src/double-conversion.cc
+++ b/runtime/third_party/double-conversion/src/double-conversion.cc
@@ -118,7 +118,7 @@
     StringBuilder* result_builder) const {
   // Create a representation that is padded with zeros if needed.
   if (decimal_point <= 0) {
-      // "0.00000decimal_rep".
+      // "0.00000decimal_rep" or "0.000decimal_rep00".
     result_builder->AddCharacter('0');
     if (digits_after_point > 0) {
       result_builder->AddCharacter('.');
@@ -129,7 +129,7 @@
       result_builder->AddPadding('0', remaining_digits);
     }
   } else if (decimal_point >= length) {
-    // "decimal_rep0000.00000" or "decimal_rep.0000"
+    // "decimal_rep0000.00000" or "decimal_rep.0000".
     result_builder->AddSubstring(decimal_digits, length);
     result_builder->AddPadding('0', decimal_point - length);
     if (digits_after_point > 0) {
@@ -137,7 +137,7 @@
       result_builder->AddPadding('0', digits_after_point);
     }
   } else {
-    // "decima.l_rep000"
+    // "decima.l_rep000".
     ASSERT(digits_after_point > 0);
     result_builder->AddSubstring(decimal_digits, decimal_point);
     result_builder->AddCharacter('.');
@@ -416,8 +416,9 @@
 
 // Consumes the given substring from the iterator.
 // Returns false, if the substring does not match.
-static bool ConsumeSubString(const char** current,
-                             const char* end,
+template <class Iterator>
+static bool ConsumeSubString(Iterator* current,
+                             Iterator end,
                              const char* substring) {
   ASSERT(**current == *substring);
   for (substring++; *substring != '\0'; substring++) {
@@ -439,10 +440,36 @@
 const int kMaxSignificantDigits = 772;
 
 
+static const char kWhitespaceTable7[] = { 32, 13, 10, 9, 11, 12 };
+static const int kWhitespaceTable7Length = ARRAY_SIZE(kWhitespaceTable7);
+
+
+static const uc16 kWhitespaceTable16[] = {
+  160, 8232, 8233, 5760, 6158, 8192, 8193, 8194, 8195,
+  8196, 8197, 8198, 8199, 8200, 8201, 8202, 8239, 8287, 12288, 65279
+};
+static const int kWhitespaceTable16Length = ARRAY_SIZE(kWhitespaceTable16);
+
+
+static bool isWhitespace(int x) {
+  if (x < 128) {
+    for (int i = 0; i < kWhitespaceTable7Length; i++) {
+      if (kWhitespaceTable7[i] == x) return true;
+    }
+  } else {
+    for (int i = 0; i < kWhitespaceTable16Length; i++) {
+      if (kWhitespaceTable16[i] == x) return true;
+    }
+  }
+  return false;
+}
+
+
 // Returns true if a nonspace found and false if the end has reached.
-static inline bool AdvanceToNonspace(const char** current, const char* end) {
+template <class Iterator>
+static inline bool AdvanceToNonspace(Iterator* current, Iterator end) {
   while (*current != end) {
-    if (**current != ' ') return true;
+    if (!isWhitespace(**current)) return true;
     ++*current;
   }
   return false;
@@ -467,10 +494,17 @@
 // because it constant-propagated the radix and concluded that the last
 // condition was always true. By moving it into a separate function the
 // compiler wouldn't warn anymore.
+#if _MSC_VER
+#pragma optimize("",off)
 static bool IsDecimalDigitForRadix(int c, int radix) {
   return '0' <= c && c <= '9' && (c - '0') < radix;
 }
-
+#pragma optimize("",on)
+#else
+static bool inline IsDecimalDigitForRadix(int c, int radix) {
+	return '0' <= c && c <= '9' && (c - '0') < radix;
+}
+#endif
 // Returns true if 'c' is a character digit that is valid for the given radix.
 // The 'a_character' should be 'a' or 'A'.
 //
@@ -484,25 +518,27 @@
 
 
 // Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
-template <int radix_log_2>
-static double RadixStringToIeee(const char* current,
-                                const char* end,
+template <int radix_log_2, class Iterator>
+static double RadixStringToIeee(Iterator* current,
+                                Iterator end,
                                 bool sign,
                                 bool allow_trailing_junk,
                                 double junk_string_value,
                                 bool read_as_double,
-                                const char** trailing_pointer) {
-  ASSERT(current != end);
+                                bool* result_is_junk) {
+  ASSERT(*current != end);
 
   const int kDoubleSize = Double::kSignificandSize;
   const int kSingleSize = Single::kSignificandSize;
   const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize;
 
+  *result_is_junk = true;
+
   // Skip leading 0s.
-  while (*current == '0') {
-    ++current;
-    if (current == end) {
-      *trailing_pointer = end;
+  while (**current == '0') {
+    ++(*current);
+    if (*current == end) {
+      *result_is_junk = false;
       return SignedZero(sign);
     }
   }
@@ -513,14 +549,14 @@
 
   do {
     int digit;
-    if (IsDecimalDigitForRadix(*current, radix)) {
-      digit = static_cast<char>(*current) - '0';
-    } else if (IsCharacterDigitForRadix(*current, radix, 'a')) {
-      digit = static_cast<char>(*current) - 'a' + 10;
-    } else if (IsCharacterDigitForRadix(*current, radix, 'A')) {
-      digit = static_cast<char>(*current) - 'A' + 10;
+    if (IsDecimalDigitForRadix(**current, radix)) {
+      digit = static_cast<char>(**current) - '0';
+    } else if (IsCharacterDigitForRadix(**current, radix, 'a')) {
+      digit = static_cast<char>(**current) - 'a' + 10;
+    } else if (IsCharacterDigitForRadix(**current, radix, 'A')) {
+      digit = static_cast<char>(**current) - 'A' + 10;
     } else {
-      if (allow_trailing_junk || !AdvanceToNonspace(&current, end)) {
+      if (allow_trailing_junk || !AdvanceToNonspace(current, end)) {
         break;
       } else {
         return junk_string_value;
@@ -545,13 +581,13 @@
 
       bool zero_tail = true;
       for (;;) {
-        ++current;
-        if (current == end || !isDigit(*current, radix)) break;
-        zero_tail = zero_tail && *current == '0';
+        ++(*current);
+        if (*current == end || !isDigit(**current, radix)) break;
+        zero_tail = zero_tail && **current == '0';
         exponent += radix_log_2;
       }
 
-      if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+      if (!allow_trailing_junk && AdvanceToNonspace(current, end)) {
         return junk_string_value;
       }
 
@@ -573,14 +609,13 @@
       }
       break;
     }
-    ++current;
-  } while (current != end);
+    ++(*current);
+  } while (*current != end);
 
   ASSERT(number < ((int64_t)1 << kSignificandSize));
-  const double double_number = static_cast<double>(number);
-  ASSERT(static_cast<int64_t>(double_number) == number);
+  ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
 
-  *trailing_pointer = current;
+  *result_is_junk = false;
 
   if (exponent == 0) {
     if (sign) {
@@ -595,13 +630,14 @@
 }
 
 
+template <class Iterator>
 double StringToDoubleConverter::StringToIeee(
-    const char* input,
+    Iterator input,
     int length,
-    int* processed_characters_count,
-    bool read_as_double) const {
-  const char* current = input;
-  const char* end = input + length;
+    bool read_as_double,
+    int* processed_characters_count) const {
+  Iterator current = input;
+  Iterator end = input + length;
 
   *processed_characters_count = 0;
 
@@ -648,7 +684,7 @@
   if (*current == '+' || *current == '-') {
     sign = (*current == '-');
     ++current;
-    const char* next_non_space = current;
+    Iterator next_non_space = current;
     // Skip following spaces (if allowed).
     if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_;
     if (!allow_spaces_after_sign && (current != next_non_space)) {
@@ -712,17 +748,17 @@
         return junk_string_value_;  // "0x".
       }
 
-      const char* tail_pointer = NULL;
-      double result = RadixStringToIeee<4>(current,
+      bool result_is_junk;
+      double result = RadixStringToIeee<4>(&current,
                                            end,
                                            sign,
                                            allow_trailing_junk,
                                            junk_string_value_,
                                            read_as_double,
-                                           &tail_pointer);
-      if (tail_pointer != NULL) {
-        if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end);
-        *processed_characters_count = static_cast<int>(tail_pointer - input);
+                                           &result_is_junk);
+      if (!result_is_junk) {
+        if (allow_trailing_spaces) AdvanceToNonspace(&current, end);
+        *processed_characters_count = static_cast<int>(current - input);
       }
       return result;
     }
@@ -823,9 +859,9 @@
         return junk_string_value_;
       }
     }
-    char sign = '+';
+    char exponen_sign = '+';
     if (*current == '+' || *current == '-') {
-      sign = static_cast<char>(*current);
+      exponen_sign = static_cast<char>(*current);
       ++current;
       if (current == end) {
         if (allow_trailing_junk) {
@@ -859,7 +895,7 @@
       ++current;
     } while (current != end && *current >= '0' && *current <= '9');
 
-    exponent += (sign == '-' ? -num : num);
+    exponent += (exponen_sign == '-' ? -num : num);
   }
 
   if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
@@ -877,15 +913,16 @@
 
   if (octal) {
     double result;
-    const char* tail_pointer = NULL;
-    result = RadixStringToIeee<3>(buffer,
+    bool result_is_junk;
+    char* start = buffer;
+    result = RadixStringToIeee<3>(&start,
                                   buffer + buffer_pos,
                                   sign,
                                   allow_trailing_junk,
                                   junk_string_value_,
                                   read_as_double,
-                                  &tail_pointer);
-    ASSERT(tail_pointer != NULL);
+                                  &result_is_junk);
+    ASSERT(!result_is_junk);
     *processed_characters_count = static_cast<int>(current - input);
     return result;
   }
@@ -908,4 +945,38 @@
   return sign? -converted: converted;
 }
 
+
+double StringToDoubleConverter::StringToDouble(
+    const char* buffer,
+    int length,
+    int* processed_characters_count) const {
+  return StringToIeee(buffer, length, true, processed_characters_count);
+}
+
+
+double StringToDoubleConverter::StringToDouble(
+    const uc16* buffer,
+    int length,
+    int* processed_characters_count) const {
+  return StringToIeee(buffer, length, true, processed_characters_count);
+}
+
+
+float StringToDoubleConverter::StringToFloat(
+    const char* buffer,
+    int length,
+    int* processed_characters_count) const {
+  return static_cast<float>(StringToIeee(buffer, length, false,
+                                         processed_characters_count));
+}
+
+
+float StringToDoubleConverter::StringToFloat(
+    const uc16* buffer,
+    int length,
+    int* processed_characters_count) const {
+  return static_cast<float>(StringToIeee(buffer, length, false,
+                                         processed_characters_count));
+}
+
 }  // namespace double_conversion
diff --git a/runtime/third_party/double-conversion/src/double-conversion.h b/runtime/third_party/double-conversion/src/double-conversion.h
index 1c3387d..6bdfa8d 100644
--- a/runtime/third_party/double-conversion/src/double-conversion.h
+++ b/runtime/third_party/double-conversion/src/double-conversion.h
@@ -415,9 +415,10 @@
   //          junk, too.
   //  - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of
   //      a double literal.
-  //  - ALLOW_LEADING_SPACES: skip over leading spaces.
-  //  - ALLOW_TRAILING_SPACES: ignore trailing spaces.
-  //  - ALLOW_SPACES_AFTER_SIGN: ignore spaces after the sign.
+  //  - ALLOW_LEADING_SPACES: skip over leading whitespace, including spaces,
+  //                          new-lines, and tabs.
+  //  - ALLOW_TRAILING_SPACES: ignore trailing whitespace.
+  //  - ALLOW_SPACES_AFTER_SIGN: ignore whitespace after the sign.
   //       Ex: StringToDouble("-   123.2") -> -123.2.
   //           StringToDouble("+   123.2") -> 123.2
   //
@@ -502,19 +503,24 @@
   // in the 'processed_characters_count'. Trailing junk is never included.
   double StringToDouble(const char* buffer,
                         int length,
-                        int* processed_characters_count) const {
-    return StringToIeee(buffer, length, processed_characters_count, true);
-  }
+                        int* processed_characters_count) const;
+
+  // Same as StringToDouble above but for 16 bit characters.
+  double StringToDouble(const uc16* buffer,
+                        int length,
+                        int* processed_characters_count) const;
 
   // Same as StringToDouble but reads a float.
   // Note that this is not equivalent to static_cast<float>(StringToDouble(...))
   // due to potential double-rounding.
   float StringToFloat(const char* buffer,
                       int length,
-                      int* processed_characters_count) const {
-    return static_cast<float>(StringToIeee(buffer, length,
-                                           processed_characters_count, false));
-  }
+                      int* processed_characters_count) const;
+
+  // Same as StringToFloat above but for 16 bit characters.
+  float StringToFloat(const uc16* buffer,
+                      int length,
+                      int* processed_characters_count) const;
 
  private:
   const int flags_;
@@ -523,10 +529,11 @@
   const char* const infinity_symbol_;
   const char* const nan_symbol_;
 
-  double StringToIeee(const char* buffer,
+  template <class Iterator>
+  double StringToIeee(Iterator start_pointer,
                       int length,
-                      int* processed_characters_count,
-                      bool read_as_double) const;
+                      bool read_as_double,
+                      int* processed_characters_count) const;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
 };
diff --git a/runtime/third_party/double-conversion/src/utils.h b/runtime/third_party/double-conversion/src/utils.h
index dc7d209..51d5e61 100644
--- a/runtime/third_party/double-conversion/src/utils.h
+++ b/runtime/third_party/double-conversion/src/utils.h
@@ -34,16 +34,28 @@
 #include <assert.h>
 #ifndef ASSERT
 #define ASSERT(condition)         \
-  do {                            \
-    assert(condition);            \
-  } while (false && (condition))
+    assert(condition);
 #endif
 #ifndef UNIMPLEMENTED
 #define UNIMPLEMENTED() (abort())
 #endif
+#ifndef DOUBLE_CONVERSION_NO_RETURN
+#ifdef _MSC_VER
+#define DOUBLE_CONVERSION_NO_RETURN __declspec(noreturn)
+#else
+#define DOUBLE_CONVERSION_NO_RETURN __attribute__((noreturn))
+#endif
+#endif
 #ifndef UNREACHABLE
+#ifdef _MSC_VER
+void DOUBLE_CONVERSION_NO_RETURN abort_noreturn();
+inline void abort_noreturn() { abort(); }
+#define UNREACHABLE()   (abort_noreturn())
+#else
 #define UNREACHABLE()   (abort())
 #endif
+#endif
+
 
 // Double operations detection based on target architecture.
 // Linux uses a 80bit wide floating point stack on x86. This induces double
@@ -60,11 +72,14 @@
     defined(__hppa__) || defined(__ia64__) || \
     defined(__mips__) || \
     defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
+    defined(_POWER) || defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \
     defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
     defined(__SH4__) || defined(__alpha__) || \
     defined(_MIPS_ARCH_MIPS32R2) || \
-    defined(__AARCH64EL__)
+    defined(__AARCH64EL__) || defined(__aarch64__)
 #define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
+#elif defined(__mc68000__)
+#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
 #elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
 #if defined(_WIN32)
 // Windows uses a 64bit wide floating point stack.
@@ -100,6 +115,8 @@
 
 #endif
 
+typedef uint16_t uc16;
+
 // The following macro works on both 32 and 64-bit platforms.
 // Usage: instead of writing 0x1234567890123456
 //      write UINT64_2PART_C(0x12345678,90123456);
@@ -165,8 +182,8 @@
 class Vector {
  public:
   Vector() : start_(NULL), length_(0) {}
-  Vector(T* data, int length) : start_(data), length_(length) {
-    ASSERT(length == 0 || (length > 0 && data != NULL));
+  Vector(T* data, int len) : start_(data), length_(len) {
+    ASSERT(len == 0 || (len > 0 && data != NULL));
   }
 
   // Returns a vector using the same backing storage as this one,
@@ -208,8 +225,8 @@
 // buffer bounds on all operations in debug mode.
 class StringBuilder {
  public:
-  StringBuilder(char* buffer, int size)
-      : buffer_(buffer, size), position_(0) { }
+  StringBuilder(char* buffer, int buffer_size)
+      : buffer_(buffer, buffer_size), position_(0) { }
 
   ~StringBuilder() { if (!is_finalized()) Finalize(); }
 
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/tools/gyp/runtime-configurations.gypi b/runtime/tools/gyp/runtime-configurations.gypi
index 4f88987..e5fc998 100644
--- a/runtime/tools/gyp/runtime-configurations.gypi
+++ b/runtime/tools/gyp/runtime-configurations.gypi
@@ -31,22 +31,6 @@
         },
       },
 
-      'Dart_Debug': {
-        'abstract': 1,
-        'defines': [
-          'DEBUG',
-        ],
-        'xcode_settings': {
-          'GCC_OPTIMIZATION_LEVEL': '<(dart_debug_optimization_level)',
-        },
-      },
-
-      'Debug': {
-        'defines': [
-          'DEBUG',
-        ],
-      },
-
       'Dart_ia32_Base': {
         'abstract': 1,
         'xcode_settings': {
@@ -92,6 +76,20 @@
         },
       },
 
+      'Dart_simarmv6_Base': {
+        'abstract': 1,
+        'xcode_settings': {
+          'ARCHS': [ 'i386' ],
+        },
+      },
+
+      'Dart_simarmv5te_Base': {
+        'abstract': 1,
+        'xcode_settings': {
+          'ARCHS': [ 'i386' ],
+        },
+      },
+
       'Dart_simmips_Base': {
         'abstract': 1,
         'xcode_settings': {
@@ -99,12 +97,35 @@
         },
       },
 
+      'Dart_Debug': {
+        'abstract': 1,
+        'defines': [
+          'DEBUG',
+        ],
+        'xcode_settings': {
+          'GCC_OPTIMIZATION_LEVEL': '<(dart_debug_optimization_level)',
+        },
+      },
+
+      'Debug': {
+        'defines': [
+          'DEBUG',
+        ],
+      },
+
       'Dart_Release': {
         'abstract': 1,
         'xcode_settings': {
           'GCC_OPTIMIZATION_LEVEL': '3',
         },
       },
+
+      'Dart_Product' : {
+        'abstract': 1,
+        'xcode_settings': {
+          'GCC_OPTIMIZATION_LEVEL': '3',
+        }
+      },
     },
   },
 }
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
new file mode 100644
index 0000000..f813eb8
--- /dev/null
+++ b/runtime/vm/aot_optimizer.cc
@@ -0,0 +1,2816 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/aot_optimizer.h"
+
+#include "vm/bit_vector.h"
+#include "vm/branch_optimizer.h"
+#include "vm/cha.h"
+#include "vm/compiler.h"
+#include "vm/cpu.h"
+#include "vm/dart_entry.h"
+#include "vm/exceptions.h"
+#include "vm/flow_graph_builder.h"
+#include "vm/flow_graph_compiler.h"
+#include "vm/flow_graph_inliner.h"
+#include "vm/flow_graph_range_analysis.h"
+#include "vm/hash_map.h"
+#include "vm/il_printer.h"
+#include "vm/intermediate_language.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
+#include "vm/parser.h"
+#include "vm/precompiler.h"
+#include "vm/resolver.h"
+#include "vm/scopes.h"
+#include "vm/stack_frame.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+// Quick access to the current isolate and zone.
+#define I (isolate())
+#define Z (zone())
+
+static bool ShouldInlineSimd() {
+  return FlowGraphCompiler::SupportsUnboxedSimd128();
+}
+
+
+static bool CanUnboxDouble() {
+  return FlowGraphCompiler::SupportsUnboxedDoubles();
+}
+
+
+static bool CanConvertUnboxedMintToDouble() {
+  return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
+}
+
+
+// Optimize instance calls using ICData.
+void AotOptimizer::ApplyICData() {
+  VisitBlocks();
+}
+
+
+void AotOptimizer::PopulateWithICData() {
+  ASSERT(current_iterator_ == NULL);
+  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    ForwardInstructionIterator it(block_it.Current());
+    for (; !it.Done(); it.Advance()) {
+      Instruction* instr = it.Current();
+      if (instr->IsInstanceCall()) {
+        InstanceCallInstr* call = instr->AsInstanceCall();
+        if (!call->HasICData()) {
+          const Array& arguments_descriptor =
+              Array::Handle(zone(),
+                  ArgumentsDescriptor::New(call->ArgumentCount(),
+                                           call->argument_names()));
+          const ICData& ic_data = ICData::ZoneHandle(zone(), ICData::New(
+              function(), call->function_name(),
+              arguments_descriptor, call->deopt_id(),
+              call->checked_argument_count()));
+          call->set_ic_data(&ic_data);
+        }
+      }
+    }
+    current_iterator_ = NULL;
+  }
+}
+
+
+// Optimize instance calls using cid.  This is called after optimizer
+// converted instance calls to instructions. Any remaining
+// instance calls are either megamorphic calls, cannot be optimized or
+// 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 AotOptimizer::ApplyClassIds() {
+  ASSERT(current_iterator_ == NULL);
+  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    ForwardInstructionIterator it(block_it.Current());
+    current_iterator_ = &it;
+    for (; !it.Done(); it.Advance()) {
+      Instruction* instr = it.Current();
+      if (instr->IsInstanceCall()) {
+        InstanceCallInstr* call = instr->AsInstanceCall();
+        if (call->HasICData()) {
+          if (TryCreateICData(call)) {
+            VisitInstanceCall(call);
+          }
+        }
+      } else if (instr->IsPolymorphicInstanceCall()) {
+        SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall());
+      }
+    }
+    current_iterator_ = NULL;
+  }
+}
+
+
+// TODO(srdjan): Test/support other number types as well.
+static bool IsNumberCid(intptr_t cid) {
+  return (cid == kSmiCid) || (cid == kDoubleCid);
+}
+
+
+static void GetUniqueDynamicTarget(Isolate* isolate,
+                                   const String& fname,
+                                   Object* function) {
+  UniqueFunctionsSet functions_set(
+      isolate->object_store()->unique_dynamic_targets());
+  ASSERT(fname.IsSymbol());
+  *function = functions_set.GetOrNull(fname);
+  ASSERT(functions_set.Release().raw() ==
+      isolate->object_store()->unique_dynamic_targets());
+}
+
+
+bool AotOptimizer::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
+    // to megamorphic call.
+    return false;
+  }
+  GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
+  ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
+  for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
+    class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid());
+  }
+
+  const Token::Kind op_kind = call->token_kind();
+  if (Token::IsRelationalOperator(op_kind) ||
+      Token::IsEqualityOperator(op_kind) ||
+      Token::IsBinaryOperator(op_kind)) {
+    // Guess cid: if one of the inputs is a number assume that the other
+    // is a number of same type.
+    if (FLAG_guess_icdata_cid) {
+      const intptr_t cid_0 = class_ids[0];
+      const intptr_t cid_1 = class_ids[1];
+      if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) {
+        class_ids[0] = cid_1;
+      } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) {
+        class_ids[1] = cid_0;
+      }
+    }
+  }
+
+  bool all_cids_known = true;
+  for (intptr_t i = 0; i < class_ids.length(); i++) {
+    if (class_ids[i] == kDynamicCid) {
+      // Not all cid-s known.
+      all_cids_known = false;
+      break;
+    }
+  }
+
+  if (all_cids_known) {
+    const Class& receiver_class = Class::Handle(Z,
+        isolate()->class_table()->At(class_ids[0]));
+    if (!receiver_class.is_finalized()) {
+      // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can
+      // cause class finalization, since callee's receiver class may not be
+      // finalized yet.
+      return false;
+    }
+    const Array& args_desc_array = Array::Handle(Z,
+        ArgumentsDescriptor::New(call->ArgumentCount(),
+                                 call->argument_names()));
+    ArgumentsDescriptor args_desc(args_desc_array);
+    const Function& function = Function::Handle(Z,
+        Resolver::ResolveDynamicForReceiverClass(
+            receiver_class,
+            call->function_name(),
+            args_desc));
+    if (function.IsNull()) {
+      return false;
+    }
+
+    // Create new ICData, do not modify the one attached to the instruction
+    // since it is attached to the assembly instruction itself.
+    // TODO(srdjan): Prevent modification of ICData object that is
+    // referenced in assembly code.
+    const ICData& ic_data = ICData::ZoneHandle(Z,
+        ICData::NewFrom(*call->ic_data(), class_ids.length()));
+    if (class_ids.length() > 1) {
+      ic_data.AddCheck(class_ids, function);
+    } else {
+      ASSERT(class_ids.length() == 1);
+      ic_data.AddReceiverCheck(class_ids[0], function);
+    }
+    call->set_ic_data(&ic_data);
+    return true;
+  }
+
+  if (isolate()->object_store()->unique_dynamic_targets() != Array::null()) {
+    // Check if the target is unique.
+    Function& target_function = Function::Handle(Z);
+    GetUniqueDynamicTarget(isolate(), call->function_name(), &target_function);
+    // Calls with named arguments must be resolved/checked at runtime.
+    String& error_message = String::Handle(Z);
+    if (!target_function.IsNull() &&
+        !target_function.HasOptionalNamedParameters() &&
+        target_function.AreValidArgumentCounts(call->ArgumentCount(), 0,
+                                               &error_message)) {
+      const intptr_t cid = Class::Handle(Z, target_function.Owner()).id();
+      const ICData& ic_data = ICData::ZoneHandle(Z,
+          ICData::NewFrom(*call->ic_data(), 1));
+      ic_data.AddReceiverCheck(cid, target_function);
+      call->set_ic_data(&ic_data);
+      return true;
+    }
+  }
+
+  // Check if getter or setter in function's class and class is currently leaf.
+  if (FLAG_guess_icdata_cid &&
+      ((call->token_kind() == Token::kGET) ||
+          (call->token_kind() == Token::kSET))) {
+    const Class& owner_class = Class::Handle(Z, function().Owner());
+    if (!owner_class.is_abstract() &&
+        !CHA::HasSubclasses(owner_class) &&
+        !CHA::IsImplemented(owner_class)) {
+      const Array& args_desc_array = Array::Handle(Z,
+          ArgumentsDescriptor::New(call->ArgumentCount(),
+                                   call->argument_names()));
+      ArgumentsDescriptor args_desc(args_desc_array);
+      const Function& function = Function::Handle(Z,
+          Resolver::ResolveDynamicForReceiverClass(owner_class,
+                                                   call->function_name(),
+                                                   args_desc));
+      if (!function.IsNull()) {
+        const ICData& ic_data = ICData::ZoneHandle(Z,
+            ICData::NewFrom(*call->ic_data(), class_ids.length()));
+        ic_data.AddReceiverCheck(owner_class.id(), function);
+        call->set_ic_data(&ic_data);
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+
+const ICData& AotOptimizer::TrySpecializeICData(const ICData& ic_data,
+                                                intptr_t cid) {
+  ASSERT(ic_data.NumArgsTested() == 1);
+
+  if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
+    return ic_data;  // Nothing to do
+  }
+
+  const Function& function =
+      Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid));
+  // TODO(fschneider): Try looking up the function on the class if it is
+  // not found in the ICData.
+  if (!function.IsNull()) {
+    const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New(
+        Function::Handle(Z, ic_data.Owner()),
+        String::Handle(Z, ic_data.target_name()),
+        Object::empty_array(),  // Dummy argument descriptor.
+        ic_data.deopt_id(),
+        ic_data.NumArgsTested()));
+    new_ic_data.SetDeoptReasons(ic_data.DeoptReasons());
+    new_ic_data.AddReceiverCheck(cid, function);
+    return new_ic_data;
+  }
+
+  return ic_data;
+}
+
+
+void AotOptimizer::SpecializePolymorphicInstanceCall(
+    PolymorphicInstanceCallInstr* call) {
+  if (!FLAG_polymorphic_with_deopt) {
+    // Specialization adds receiver checks which can lead to deoptimization.
+    return;
+  }
+  if (!call->with_checks()) {
+    return;  // Already specialized.
+  }
+
+  const intptr_t receiver_cid =
+      call->PushArgumentAt(0)->value()->Type()->ToCid();
+  if (receiver_cid == kDynamicCid) {
+    return;  // No information about receiver was infered.
+  }
+
+  const ICData& ic_data = TrySpecializeICData(call->ic_data(), receiver_cid);
+  if (ic_data.raw() == call->ic_data().raw()) {
+    // No specialization.
+    return;
+  }
+
+  const bool with_checks = false;
+  PolymorphicInstanceCallInstr* specialized =
+      new(Z) PolymorphicInstanceCallInstr(call->instance_call(),
+                                          ic_data,
+                                          with_checks);
+  call->ReplaceWith(specialized, current_iterator());
+}
+
+
+static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
+  BinarySmiOpInstr* instr = d->AsBinarySmiOp();
+  if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
+    return instr;
+  }
+  return NULL;
+}
+
+
+static bool IsPositiveOrZeroSmiConst(Definition* d) {
+  ConstantInstr* const_instr = d->AsConstant();
+  if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
+    return Smi::Cast(const_instr->value()).Value() >= 0;
+  }
+  return false;
+}
+
+
+void AotOptimizer::OptimizeLeftShiftBitAndSmiOp(
+    Definition* bit_and_instr,
+    Definition* left_instr,
+    Definition* right_instr) {
+  ASSERT(bit_and_instr != NULL);
+  ASSERT((left_instr != NULL) && (right_instr != NULL));
+
+  // Check for pattern, smi_shift_left must be single-use.
+  bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
+  if (!is_positive_or_zero) {
+    is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
+  }
+  if (!is_positive_or_zero) return;
+
+  BinarySmiOpInstr* smi_shift_left = NULL;
+  if (bit_and_instr->InputAt(0)->IsSingleUse()) {
+    smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
+  }
+  if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
+    smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
+  }
+  if (smi_shift_left == NULL) return;
+
+  // Pattern recognized.
+  smi_shift_left->mark_truncating();
+  ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
+  if (bit_and_instr->IsBinaryMintOp()) {
+    // Replace Mint op with Smi op.
+    BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
+        Token::kBIT_AND,
+        new(Z) Value(left_instr),
+        new(Z) Value(right_instr),
+        Thread::kNoDeoptId);  // BIT_AND cannot deoptimize.
+    bit_and_instr->ReplaceWith(smi_op, current_iterator());
+  }
+}
+
+
+void AotOptimizer::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);
+  flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
+}
+
+
+// Dart:
+//  var x = d % 10;
+//  var y = d ~/ 10;
+//  var z = x + y;
+//
+// IL:
+//  v4 <- %(v2, v3)
+//  v5 <- ~/(v2, v3)
+//  v6 <- +(v4, v5)
+//
+// IL optimized:
+//  v4 <- DIVMOD(v2, v3);
+//  v5 <- LoadIndexed(v4, 0); // ~/ result
+//  v6 <- LoadIndexed(v4, 1); // % result
+//  v7 <- +(v5, v6)
+// Because of the environment it is important that merged instruction replaces
+// first original instruction encountered.
+void AotOptimizer::TryMergeTruncDivMod(
+    GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
+  if (merge_candidates->length() < 2) {
+    // Need at least a TRUNCDIV and a MOD.
+    return;
+  }
+  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
+    BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
+    if (curr_instr == NULL) {
+      // Instruction was merged already.
+      continue;
+    }
+    ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
+           (curr_instr->op_kind() == Token::kMOD));
+    // Check if there is kMOD/kTRUNDIV binop with same inputs.
+    const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
+        Token::kMOD : Token::kTRUNCDIV;
+    Definition* left_def = curr_instr->left()->definition();
+    Definition* right_def = curr_instr->right()->definition();
+    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
+      BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
+      // 'other_binop' can be NULL if it was already merged.
+      if ((other_binop != NULL) &&
+          (other_binop->op_kind() == other_kind) &&
+          (other_binop->left()->definition() == left_def) &&
+          (other_binop->right()->definition() == right_def)) {
+        (*merge_candidates)[k] = NULL;  // Clear it.
+        ASSERT(curr_instr->HasUses());
+        AppendExtractNthOutputForMerged(
+            curr_instr,
+            MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
+            kTagged, kSmiCid);
+        ASSERT(other_binop->HasUses());
+        AppendExtractNthOutputForMerged(
+            other_binop,
+            MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
+            kTagged, kSmiCid);
+
+        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
+        args->Add(new(Z) Value(curr_instr->left()->definition()));
+        args->Add(new(Z) Value(curr_instr->right()->definition()));
+
+        // Replace with TruncDivMod.
+        MergedMathInstr* div_mod = new(Z) MergedMathInstr(
+            args,
+            curr_instr->deopt_id(),
+            MergedMathInstr::kTruncDivMod);
+        curr_instr->ReplaceWith(div_mod, current_iterator());
+        other_binop->ReplaceUsesWith(div_mod);
+        other_binop->RemoveFromGraph();
+        // Only one merge possible. Because canonicalization happens later,
+        // more candidates are possible.
+        // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
+        break;
+      }
+    }
+  }
+}
+
+
+// Tries to merge MathUnary operations, in this case sinus and cosinus.
+void AotOptimizer::TryMergeMathUnary(
+    GrowableArray<MathUnaryInstr*>* merge_candidates) {
+  if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
+      !FLAG_merge_sin_cos) {
+    return;
+  }
+  if (merge_candidates->length() < 2) {
+    // Need at least a SIN and a COS.
+    return;
+  }
+  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
+    MathUnaryInstr* curr_instr = (*merge_candidates)[i];
+    if (curr_instr == NULL) {
+      // Instruction was merged already.
+      continue;
+    }
+    const intptr_t kind = curr_instr->kind();
+    ASSERT((kind == MathUnaryInstr::kSin) ||
+           (kind == MathUnaryInstr::kCos));
+    // Check if there is sin/cos binop with same inputs.
+    const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
+        MathUnaryInstr::kCos : MathUnaryInstr::kSin;
+    Definition* def = curr_instr->value()->definition();
+    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
+      MathUnaryInstr* other_op = (*merge_candidates)[k];
+      // 'other_op' can be NULL if it was already merged.
+      if ((other_op != NULL) && (other_op->kind() == other_kind) &&
+          (other_op->value()->definition() == def)) {
+        (*merge_candidates)[k] = NULL;  // Clear it.
+        ASSERT(curr_instr->HasUses());
+        AppendExtractNthOutputForMerged(curr_instr,
+                                        MergedMathInstr::OutputIndexOf(kind),
+                                        kUnboxedDouble, kDoubleCid);
+        ASSERT(other_op->HasUses());
+        AppendExtractNthOutputForMerged(
+            other_op,
+            MergedMathInstr::OutputIndexOf(other_kind),
+            kUnboxedDouble, kDoubleCid);
+        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
+        args->Add(new(Z) Value(curr_instr->value()->definition()));
+        // Replace with SinCos.
+        MergedMathInstr* sin_cos =
+            new(Z) MergedMathInstr(args,
+                                   curr_instr->DeoptimizationTarget(),
+                                   MergedMathInstr::kSinCos);
+        curr_instr->ReplaceWith(sin_cos, current_iterator());
+        other_op->ReplaceUsesWith(sin_cos);
+        other_op->RemoveFromGraph();
+        // Only one merge possible. Because canonicalization happens later,
+        // more candidates are possible.
+        // TODO(srdjan): Allow merging of sin/cos into sincos.
+        break;
+      }
+    }
+  }
+}
+
+
+// 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 AotOptimizer::TryOptimizePatterns() {
+  if (!FLAG_truncating_left_shift) return;
+  ASSERT(current_iterator_ == NULL);
+  GrowableArray<BinarySmiOpInstr*> div_mod_merge;
+  GrowableArray<MathUnaryInstr*> sin_cos_merge;
+  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    // Merging only per basic-block.
+    div_mod_merge.Clear();
+    sin_cos_merge.Clear();
+    ForwardInstructionIterator it(block_it.Current());
+    current_iterator_ = &it;
+    for (; !it.Done(); it.Advance()) {
+      if (it.Current()->IsBinarySmiOp()) {
+        BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
+        if (binop->op_kind() == Token::kBIT_AND) {
+          OptimizeLeftShiftBitAndSmiOp(binop,
+                                       binop->left()->definition(),
+                                       binop->right()->definition());
+        } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
+                   (binop->op_kind() == Token::kMOD)) {
+          if (binop->HasUses()) {
+            div_mod_merge.Add(binop);
+          }
+        }
+      } else if (it.Current()->IsBinaryMintOp()) {
+        BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
+        if (mintop->op_kind() == Token::kBIT_AND) {
+          OptimizeLeftShiftBitAndSmiOp(mintop,
+                                       mintop->left()->definition(),
+                                       mintop->right()->definition());
+        }
+      } else if (it.Current()->IsMathUnary()) {
+        MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
+        if ((math_unary->kind() == MathUnaryInstr::kSin) ||
+            (math_unary->kind() == MathUnaryInstr::kCos)) {
+          if (math_unary->HasUses()) {
+            sin_cos_merge.Add(math_unary);
+          }
+        }
+      }
+    }
+    TryMergeTruncDivMod(&div_mod_merge);
+    TryMergeMathUnary(&sin_cos_merge);
+    current_iterator_ = NULL;
+  }
+}
+
+
+static bool ClassIdIsOneOf(intptr_t class_id,
+                           const GrowableArray<intptr_t>& class_ids) {
+  for (intptr_t i = 0; i < class_ids.length(); i++) {
+    ASSERT(class_ids[i] != kIllegalCid);
+    if (class_ids[i] == class_id) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// Returns true if ICData tests two arguments and all ICData cids are in the
+// required sets 'receiver_class_ids' or 'argument_class_ids', respectively.
+static bool ICDataHasOnlyReceiverArgumentClassIds(
+    const ICData& ic_data,
+    const GrowableArray<intptr_t>& receiver_class_ids,
+    const GrowableArray<intptr_t>& argument_class_ids) {
+  if (ic_data.NumArgsTested() != 2) {
+    return false;
+  }
+  const intptr_t len = ic_data.NumberOfChecks();
+  GrowableArray<intptr_t> class_ids;
+  for (intptr_t i = 0; i < len; i++) {
+    if (ic_data.IsUsedAt(i)) {
+      ic_data.GetClassIdsAt(i, &class_ids);
+      ASSERT(class_ids.length() == 2);
+      if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
+          !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+
+static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
+                                              intptr_t receiver_class_id,
+                                              intptr_t argument_class_id) {
+  if (ic_data.NumArgsTested() != 2) {
+    return false;
+  }
+  const intptr_t len = ic_data.NumberOfChecks();
+  for (intptr_t i = 0; i < len; i++) {
+    if (ic_data.IsUsedAt(i)) {
+      GrowableArray<intptr_t> class_ids;
+      ic_data.GetClassIdsAt(i, &class_ids);
+      ASSERT(class_ids.length() == 2);
+      if ((class_ids[0] == receiver_class_id) &&
+          (class_ids[1] == argument_class_id)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+static bool HasOnlyOneSmi(const ICData& ic_data) {
+  return (ic_data.NumberOfUsedChecks() == 1)
+      && ic_data.HasReceiverClassId(kSmiCid);
+}
+
+
+static bool HasOnlySmiOrMint(const ICData& ic_data) {
+  if (ic_data.NumberOfUsedChecks() == 1) {
+    return ic_data.HasReceiverClassId(kSmiCid)
+        || ic_data.HasReceiverClassId(kMintCid);
+  }
+  return (ic_data.NumberOfUsedChecks() == 2)
+      && ic_data.HasReceiverClassId(kSmiCid)
+      && ic_data.HasReceiverClassId(kMintCid);
+}
+
+
+static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
+  if (ic_data.NumberOfUsedChecks() != 1) {
+    return false;
+  }
+  GrowableArray<intptr_t> first;
+  GrowableArray<intptr_t> second;
+  ic_data.GetUsedCidsForTwoArgs(&first, &second);
+  return (first[0] == cid) && (second[0] == cid);
+}
+
+// Returns false if the ICData contains anything other than the 4 combinations
+// of Mint and Smi for the receiver and argument classes.
+static bool HasTwoMintOrSmi(const ICData& ic_data) {
+  GrowableArray<intptr_t> first;
+  GrowableArray<intptr_t> second;
+  ic_data.GetUsedCidsForTwoArgs(&first, &second);
+  for (intptr_t i = 0; i < first.length(); i++) {
+    if ((first[i] != kSmiCid) && (first[i] != kMintCid)) {
+      return false;
+    }
+    if ((second[i] != kSmiCid) && (second[i] != kMintCid)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+// Returns false if the ICData contains anything other than the 4 combinations
+// of Double and Smi for the receiver and argument classes.
+static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
+  GrowableArray<intptr_t> class_ids(2);
+  class_ids.Add(kSmiCid);
+  class_ids.Add(kDoubleCid);
+  return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
+}
+
+
+static bool HasOnlyOneDouble(const ICData& ic_data) {
+  return (ic_data.NumberOfUsedChecks() == 1)
+      && ic_data.HasReceiverClassId(kDoubleCid);
+}
+
+
+static bool ShouldSpecializeForDouble(const ICData& ic_data) {
+  // Don't specialize for double if we can't unbox them.
+  if (!CanUnboxDouble()) {
+    return false;
+  }
+
+  // Unboxed double operation can't handle case of two smis.
+  if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+    return false;
+  }
+
+  // Check that it have seen only smis and doubles.
+  return HasTwoDoubleOrSmi(ic_data);
+}
+
+
+void AotOptimizer::ReplaceCall(Definition* call,
+                               Definition* replacement) {
+  // Remove the original push arguments.
+  for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+    PushArgumentInstr* push = call->PushArgumentAt(i);
+    push->ReplaceUsesWith(push->value()->definition());
+    push->RemoveFromGraph();
+  }
+  call->ReplaceWith(replacement, current_iterator());
+}
+
+
+void AotOptimizer::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),
+                                      deopt_id,
+                                      insert_before->token_pos()),
+                 deopt_environment,
+                 FlowGraph::kEffect);
+  }
+}
+
+
+Instruction* AotOptimizer::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),
+                                deopt_id,
+                                token_pos);
+  }
+  return new(Z) CheckClassInstr(
+      new(Z) Value(to_check), deopt_id, unary_checks, token_pos);
+}
+
+
+void AotOptimizer::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());
+  InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
+}
+
+
+void AotOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
+                call->deopt_id(),
+                call->env(),
+                call);
+}
+
+
+static bool ArgIsAlways(intptr_t cid,
+                        const ICData& ic_data,
+                        intptr_t arg_number) {
+  ASSERT(ic_data.NumArgsTested() > arg_number);
+  if (ic_data.NumberOfUsedChecks() == 0) {
+    return false;
+  }
+  const intptr_t num_checks = ic_data.NumberOfChecks();
+  for (intptr_t i = 0; i < num_checks; i++) {
+    if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
+  // Check for monomorphic IC data.
+  if (!call->HasICData()) return false;
+  const ICData& ic_data =
+      ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
+  if (ic_data.NumberOfChecks() != 1) {
+    return false;
+  }
+  return TryReplaceInstanceCallWithInline(call);
+}
+
+
+// Return true if d is a string of length one (a constant or result from
+// from string-from-char-code instruction.
+static bool IsLengthOneString(Definition* d) {
+  if (d->IsConstant()) {
+    const Object& obj = d->AsConstant()->value();
+    if (obj.IsString()) {
+      return String::Cast(obj).Length() == 1;
+    } else {
+      return false;
+    }
+  } else {
+    return d->IsStringFromCharCode();
+  }
+}
+
+
+// Returns true if the string comparison was converted into char-code
+// 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 AotOptimizer::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.
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  Value* left_val = NULL;
+  Definition* to_remove_left = NULL;
+  if (IsLengthOneString(right)) {
+    // Swap, since we know that both arguments are strings
+    Definition* temp = left;
+    left = right;
+    right = temp;
+  }
+  if (IsLengthOneString(left)) {
+    // Optimize if left is a string with length one (either constant or
+    // result of string-from-char-code.
+    if (left->IsConstant()) {
+      ConstantInstr* left_const = left->AsConstant();
+      const String& str = String::Cast(left_const->value());
+      ASSERT(str.Length() == 1);
+      ConstantInstr* char_code_left = flow_graph()->GetConstant(
+          Smi::ZoneHandle(Z, Smi::New(static_cast<intptr_t>(str.CharAt(0)))));
+      left_val = new(Z) Value(char_code_left);
+    } else if (left->IsStringFromCharCode()) {
+      // Use input of string-from-charcode as left value.
+      StringFromCharCodeInstr* instr = left->AsStringFromCharCode();
+      left_val = new(Z) Value(instr->char_code()->definition());
+      to_remove_left = instr;
+    } else {
+      // IsLengthOneString(left) should have been false.
+      UNREACHABLE();
+    }
+
+    Definition* to_remove_right = NULL;
+    Value* right_val = NULL;
+    if (right->IsStringFromCharCode()) {
+      // Skip string-from-char-code, and use its input as right value.
+      StringFromCharCodeInstr* right_instr = right->AsStringFromCharCode();
+      right_val = new(Z) Value(right_instr->char_code()->definition());
+      to_remove_right = right_instr;
+    } else {
+      const ICData& unary_checks_1 =
+          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
+      AddCheckClass(right,
+                    unary_checks_1,
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      // String-to-char-code instructions returns -1 (illegal charcode) if
+      // string is not of length one.
+      StringToCharCodeInstr* char_code_right =
+          new(Z) StringToCharCodeInstr(new(Z) Value(right), kOneByteStringCid);
+      InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue);
+      right_val = new(Z) Value(char_code_right);
+    }
+
+    // Comparing char-codes instead of strings.
+    EqualityCompareInstr* comp =
+        new(Z) EqualityCompareInstr(call->token_pos(),
+                                    op_kind,
+                                    left_val,
+                                    right_val,
+                                    kSmiCid,
+                                    call->deopt_id());
+    ReplaceCall(call, comp);
+
+    // Remove dead instructions.
+    if ((to_remove_left != NULL) &&
+        (to_remove_left->input_use_list() == NULL)) {
+      to_remove_left->ReplaceUsesWith(flow_graph()->constant_null());
+      to_remove_left->RemoveFromGraph();
+    }
+    if ((to_remove_right != NULL) &&
+        (to_remove_right->input_use_list() == NULL)) {
+      to_remove_right->ReplaceUsesWith(flow_graph()->constant_null());
+      to_remove_right->RemoveFromGraph();
+    }
+    return true;
+  }
+  return false;
+}
+
+
+static bool SmiFitsInDouble() { return kSmiBits < 53; }
+
+bool AotOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
+                                            Token::Kind op_kind) {
+  const ICData& ic_data = *call->ic_data();
+  ASSERT(ic_data.NumArgsTested() == 2);
+
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+
+  intptr_t cid = kIllegalCid;
+  if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
+    if (TryStringLengthOneEquality(call, op_kind)) {
+      return true;
+    } else {
+      return false;
+    }
+  } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(left),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(right),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    cid = kSmiCid;
+  } else if (HasTwoMintOrSmi(ic_data) &&
+             FlowGraphCompiler::SupportsUnboxedMints()) {
+    cid = kMintCid;
+  } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
+    // Use double comparison.
+    if (SmiFitsInDouble()) {
+      cid = kDoubleCid;
+    } else {
+      if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+        // We cannot use double comparison on two smis. Need polymorphic
+        // call.
+        return false;
+      } else {
+        InsertBefore(call,
+                     new(Z) CheckEitherNonSmiInstr(
+                         new(Z) Value(left),
+                         new(Z) Value(right),
+                         call->deopt_id()),
+                     call->env(),
+                     FlowGraph::kEffect);
+        cid = kDoubleCid;
+      }
+    }
+  } else {
+    // Check if ICDData contains checks with Smi/Null combinations. In that case
+    // we can still emit the optimized Smi equality operation but need to add
+    // checks for null or Smi.
+    GrowableArray<intptr_t> smi_or_null(2);
+    smi_or_null.Add(kSmiCid);
+    smi_or_null.Add(kNullCid);
+    if (ICDataHasOnlyReceiverArgumentClassIds(ic_data,
+                                              smi_or_null,
+                                              smi_or_null)) {
+      const ICData& unary_checks_0 =
+          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
+      AddCheckClass(left,
+                    unary_checks_0,
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+
+      const ICData& unary_checks_1 =
+          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
+      AddCheckClass(right,
+                    unary_checks_1,
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      cid = kSmiCid;
+    } else {
+      // Shortcut for equality with null.
+      ConstantInstr* right_const = right->AsConstant();
+      ConstantInstr* left_const = left->AsConstant();
+      if ((right_const != NULL && right_const->value().IsNull()) ||
+          (left_const != NULL && left_const->value().IsNull())) {
+        StrictCompareInstr* comp =
+            new(Z) StrictCompareInstr(call->token_pos(),
+                                      Token::kEQ_STRICT,
+                                      new(Z) Value(left),
+                                      new(Z) Value(right),
+                                      false);  // No number check.
+        ReplaceCall(call, comp);
+        return true;
+      }
+      return false;
+    }
+  }
+  ASSERT(cid != kIllegalCid);
+  EqualityCompareInstr* comp = new(Z) EqualityCompareInstr(call->token_pos(),
+                                                           op_kind,
+                                                           new(Z) Value(left),
+                                                           new(Z) Value(right),
+                                                           cid,
+                                                           call->deopt_id());
+  ReplaceCall(call, comp);
+  return true;
+}
+
+
+bool AotOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
+                                              Token::Kind op_kind) {
+  const ICData& ic_data = *call->ic_data();
+  ASSERT(ic_data.NumArgsTested() == 2);
+
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+
+  intptr_t cid = kIllegalCid;
+  if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(left),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(right),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    cid = kSmiCid;
+  } else if (HasTwoMintOrSmi(ic_data) &&
+             FlowGraphCompiler::SupportsUnboxedMints()) {
+    cid = kMintCid;
+  } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
+    // Use double comparison.
+    if (SmiFitsInDouble()) {
+      cid = kDoubleCid;
+    } else {
+      if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+        // We cannot use double comparison on two smis. Need polymorphic
+        // call.
+        return false;
+      } else {
+        InsertBefore(call,
+                     new(Z) CheckEitherNonSmiInstr(
+                         new(Z) Value(left),
+                         new(Z) Value(right),
+                         call->deopt_id()),
+                     call->env(),
+                     FlowGraph::kEffect);
+        cid = kDoubleCid;
+      }
+    }
+  } else {
+    return false;
+  }
+  ASSERT(cid != kIllegalCid);
+  RelationalOpInstr* comp = new(Z) RelationalOpInstr(call->token_pos(),
+                                                     op_kind,
+                                                     new(Z) Value(left),
+                                                     new(Z) Value(right),
+                                                     cid,
+                                                     call->deopt_id());
+  ReplaceCall(call, comp);
+  return true;
+}
+
+
+bool AotOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
+                                          Token::Kind op_kind) {
+  intptr_t operands_type = kIllegalCid;
+  ASSERT(call->HasICData());
+  const ICData& ic_data = *call->ic_data();
+  switch (op_kind) {
+    case Token::kADD:
+    case Token::kSUB:
+    case Token::kMUL:
+      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+        // Don't generate smi code if the IC data is marked because
+        // of an overflow.
+        operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
+            ? kMintCid
+            : kSmiCid;
+      } else if (HasTwoMintOrSmi(ic_data) &&
+                 FlowGraphCompiler::SupportsUnboxedMints()) {
+        // Don't generate mint code if the IC data is marked because of an
+        // overflow.
+        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) return false;
+        operands_type = kMintCid;
+      } else if (ShouldSpecializeForDouble(ic_data)) {
+        operands_type = kDoubleCid;
+      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
+        operands_type = kFloat32x4Cid;
+      } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+        ASSERT(op_kind != Token::kMUL);  // Int32x4 doesn't have a multiply op.
+        operands_type = kInt32x4Cid;
+      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
+        operands_type = kFloat64x2Cid;
+      } else {
+        return false;
+      }
+      break;
+    case Token::kDIV:
+      if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
+      if (ShouldSpecializeForDouble(ic_data) ||
+          HasOnlyTwoOf(ic_data, kSmiCid)) {
+        operands_type = kDoubleCid;
+      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
+        operands_type = kFloat32x4Cid;
+      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
+        operands_type = kFloat64x2Cid;
+      } else {
+        return false;
+      }
+      break;
+    case Token::kBIT_AND:
+    case Token::kBIT_OR:
+    case Token::kBIT_XOR:
+      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+        operands_type = kSmiCid;
+      } else if (HasTwoMintOrSmi(ic_data)) {
+        operands_type = kMintCid;
+      } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+        operands_type = kInt32x4Cid;
+      } else {
+        return false;
+      }
+      break;
+    case Token::kSHR:
+    case Token::kSHL:
+      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+        // Left shift may overflow from smi into mint or big ints.
+        // Don't generate smi code if the IC data is marked because
+        // of an overflow.
+        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
+          return false;
+        }
+        operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
+            ? kMintCid
+            : kSmiCid;
+      } else if (HasTwoMintOrSmi(ic_data) &&
+                 HasOnlyOneSmi(ICData::Handle(Z,
+                     ic_data.AsUnaryClassChecksForArgNr(1)))) {
+        // Don't generate mint code if the IC data is marked because of an
+        // overflow.
+        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
+          return false;
+        }
+        // Check for smi/mint << smi or smi/mint >> smi.
+        operands_type = kMintCid;
+      } else {
+        return false;
+      }
+      break;
+    case Token::kMOD:
+    case Token::kTRUNCDIV:
+      if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
+      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+        if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) {
+          return false;
+        }
+        operands_type = kSmiCid;
+      } else {
+        return false;
+      }
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  if (operands_type == kDoubleCid) {
+    if (!CanUnboxDouble()) {
+      return false;
+    }
+    // Check that either left or right are not a smi.  Result of a
+    // binary operation with two smis is a smi not a double, except '/' which
+    // returns a double for two smis.
+    if (op_kind != Token::kDIV) {
+      InsertBefore(call,
+                   new(Z) CheckEitherNonSmiInstr(
+                       new(Z) Value(left),
+                       new(Z) Value(right),
+                       call->deopt_id()),
+                   call->env(),
+                   FlowGraph::kEffect);
+    }
+
+    BinaryDoubleOpInstr* double_bin_op =
+        new(Z) BinaryDoubleOpInstr(op_kind,
+                                   new(Z) Value(left),
+                                   new(Z) Value(right),
+                                   call->deopt_id(), call->token_pos());
+    ReplaceCall(call, double_bin_op);
+  } else if (operands_type == kMintCid) {
+    if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
+    if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
+      ShiftMintOpInstr* shift_op =
+          new(Z) ShiftMintOpInstr(
+              op_kind, new(Z) Value(left), new(Z) Value(right),
+              call->deopt_id());
+      ReplaceCall(call, shift_op);
+    } else {
+      BinaryMintOpInstr* bin_op =
+          new(Z) BinaryMintOpInstr(
+              op_kind, new(Z) Value(left), new(Z) Value(right),
+              call->deopt_id());
+      ReplaceCall(call, bin_op);
+    }
+  } else if (operands_type == kFloat32x4Cid) {
+    return InlineFloat32x4BinaryOp(call, op_kind);
+  } else if (operands_type == kInt32x4Cid) {
+    return InlineInt32x4BinaryOp(call, op_kind);
+  } else if (operands_type == kFloat64x2Cid) {
+    return InlineFloat64x2BinaryOp(call, op_kind);
+  } else if (op_kind == Token::kMOD) {
+    ASSERT(operands_type == kSmiCid);
+    if (right->IsConstant()) {
+      const Object& obj = right->AsConstant()->value();
+      if (obj.IsSmi() && Utils::IsPowerOfTwo(Smi::Cast(obj).Value())) {
+        // Insert smi check and attach a copy of the original environment
+        // because the smi operation can still deoptimize.
+        InsertBefore(call,
+                     new(Z) CheckSmiInstr(new(Z) Value(left),
+                                          call->deopt_id(),
+                                          call->token_pos()),
+                     call->env(),
+                     FlowGraph::kEffect);
+        ConstantInstr* constant =
+            flow_graph()->GetConstant(Smi::Handle(Z,
+                Smi::New(Smi::Cast(obj).Value() - 1)));
+        BinarySmiOpInstr* bin_op =
+            new(Z) BinarySmiOpInstr(Token::kBIT_AND,
+                                    new(Z) Value(left),
+                                    new(Z) Value(constant),
+                                    call->deopt_id());
+        ReplaceCall(call, bin_op);
+        return true;
+      }
+    }
+    // Insert two smi checks and attach a copy of the original
+    // environment because the smi operation can still deoptimize.
+    AddCheckSmi(left, call->deopt_id(), call->env(), call);
+    AddCheckSmi(right, call->deopt_id(), call->env(), call);
+    BinarySmiOpInstr* bin_op =
+        new(Z) BinarySmiOpInstr(op_kind,
+                                new(Z) Value(left),
+                                new(Z) Value(right),
+                                call->deopt_id());
+    ReplaceCall(call, bin_op);
+  } else {
+    ASSERT(operands_type == kSmiCid);
+    // Insert two smi checks and attach a copy of the original
+    // environment because the smi operation can still deoptimize.
+    AddCheckSmi(left, call->deopt_id(), call->env(), call);
+    AddCheckSmi(right, call->deopt_id(), call->env(), call);
+    if (left->IsConstant() &&
+        ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) {
+      // Constant should be on the right side.
+      Definition* temp = left;
+      left = right;
+      right = temp;
+    }
+    BinarySmiOpInstr* bin_op =
+        new(Z) BinarySmiOpInstr(
+            op_kind,
+            new(Z) Value(left),
+            new(Z) Value(right),
+            call->deopt_id());
+    ReplaceCall(call, bin_op);
+  }
+  return true;
+}
+
+
+bool AotOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
+                                         Token::Kind op_kind) {
+  ASSERT(call->ArgumentCount() == 1);
+  Definition* input = call->ArgumentAt(0);
+  Definition* unary_op = NULL;
+  if (HasOnlyOneSmi(*call->ic_data())) {
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(input),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    unary_op = new(Z) UnarySmiOpInstr(
+        op_kind, new(Z) Value(input), call->deopt_id());
+  } else if ((op_kind == Token::kBIT_NOT) &&
+             HasOnlySmiOrMint(*call->ic_data()) &&
+             FlowGraphCompiler::SupportsUnboxedMints()) {
+    unary_op = new(Z) UnaryMintOpInstr(
+        op_kind, new(Z) Value(input), call->deopt_id());
+  } else if (HasOnlyOneDouble(*call->ic_data()) &&
+             (op_kind == Token::kNEGATE) &&
+             CanUnboxDouble()) {
+    AddReceiverCheck(call);
+    unary_op = new(Z) UnaryDoubleOpInstr(
+        Token::kNEGATE, new(Z) Value(input), call->deopt_id());
+  } else {
+    return false;
+  }
+  ASSERT(unary_op != NULL);
+  ReplaceCall(call, unary_op);
+  return true;
+}
+
+
+// Using field class
+RawField* AotOptimizer::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();
+    }
+    cls = cls.SuperClass();
+  }
+  return Field::null();
+}
+
+
+// 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 AotOptimizer::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
+    // may later add overriding methods.
+    return true;
+  }
+  Definition* callee_receiver = call->ArgumentAt(0);
+  ASSERT(callee_receiver != NULL);
+  const Function& function = flow_graph_->function();
+  if (function.IsDynamicFunction() &&
+      callee_receiver->IsParameter() &&
+      (callee_receiver->AsParameter()->index() == 0)) {
+    const String& name = (kind == RawFunction::kMethodExtractor)
+        ? String::Handle(Z, Field::NameFromGetter(call->function_name()))
+        : call->function_name();
+    const Class& cls = Class::Handle(Z, function.Owner());
+    if (!thread()->cha()->HasOverride(cls, name)) {
+      if (FLAG_trace_cha) {
+        THR_Print("  **(CHA) Instance call needs no check, "
+            "no overrides of '%s' '%s'\n",
+            name.ToCString(), cls.ToCString());
+      }
+      thread()->cha()->AddToLeafClasses(cls);
+      return false;
+    }
+  }
+  return true;
+}
+
+
+bool AotOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
+  ASSERT(call->HasICData());
+  const ICData& ic_data = *call->ic_data();
+  ASSERT(ic_data.HasOneTarget());
+  GrowableArray<intptr_t> class_ids;
+  ic_data.GetClassIdsAt(0, &class_ids);
+  ASSERT(class_ids.length() == 1);
+  // Inline implicit instance getter.
+  const String& field_name =
+      String::Handle(Z, Field::NameFromGetter(call->function_name()));
+  const Field& field =
+      Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
+  ASSERT(!field.IsNull());
+
+  if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) {
+    return false;
+  }
+  LoadFieldInstr* load = new(Z) LoadFieldInstr(
+      new(Z) Value(call->ArgumentAt(0)),
+      &field,
+      AbstractType::ZoneHandle(Z, field.type()),
+      call->token_pos());
+  load->set_is_immutable(field.is_final());
+
+  // Discard the environment from the original instruction because the load
+  // can't deoptimize.
+  call->RemoveEnvironment();
+  ReplaceCall(call, load);
+
+  if (load->result_cid() != kDynamicCid) {
+    // Reset value types if guarded_cid was used.
+    for (Value::Iterator it(load->input_use_list());
+         !it.Done();
+         it.Advance()) {
+      it.Current()->SetReachingType(NULL);
+    }
+  }
+  return true;
+}
+
+
+bool AotOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
+                                         MethodRecognizer::Kind getter) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  intptr_t mask = 0;
+  if ((getter == MethodRecognizer::kFloat32x4Shuffle) ||
+      (getter == MethodRecognizer::kFloat32x4ShuffleMix)) {
+    // Extract shuffle mask.
+    Definition* mask_definition = NULL;
+    if (getter == MethodRecognizer::kFloat32x4Shuffle) {
+      ASSERT(call->ArgumentCount() == 2);
+      mask_definition = call->ArgumentAt(1);
+    } else {
+      ASSERT(getter == MethodRecognizer::kFloat32x4ShuffleMix);
+      ASSERT(call->ArgumentCount() == 3);
+      mask_definition = call->ArgumentAt(2);
+    }
+    if (!mask_definition->IsConstant()) {
+      return false;
+    }
+    ASSERT(mask_definition->IsConstant());
+    ConstantInstr* constant_instruction = mask_definition->AsConstant();
+    const Object& constant_mask = constant_instruction->value();
+    if (!constant_mask.IsSmi()) {
+      return false;
+    }
+    ASSERT(constant_mask.IsSmi());
+    mask = Smi::Cast(constant_mask).Value();
+    if ((mask < 0) || (mask > 255)) {
+      // Not a valid mask.
+      return false;
+    }
+  }
+  if (getter == MethodRecognizer::kFloat32x4GetSignMask) {
+    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else if (getter == MethodRecognizer::kFloat32x4ShuffleMix) {
+    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        new(Z) Value(call->ArgumentAt(1)),
+        mask,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else {
+    ASSERT((getter == MethodRecognizer::kFloat32x4Shuffle)  ||
+           (getter == MethodRecognizer::kFloat32x4ShuffleX) ||
+           (getter == MethodRecognizer::kFloat32x4ShuffleY) ||
+           (getter == MethodRecognizer::kFloat32x4ShuffleZ) ||
+           (getter == MethodRecognizer::kFloat32x4ShuffleW));
+    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        mask,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  }
+  UNREACHABLE();
+  return false;
+}
+
+
+bool AotOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
+                                         MethodRecognizer::Kind getter) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  if ((getter == MethodRecognizer::kFloat64x2GetX) ||
+      (getter == MethodRecognizer::kFloat64x2GetY)) {
+    Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        0,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  }
+  UNREACHABLE();
+  return false;
+}
+
+
+bool AotOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
+                                       MethodRecognizer::Kind getter) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  intptr_t mask = 0;
+  if ((getter == MethodRecognizer::kInt32x4Shuffle) ||
+      (getter == MethodRecognizer::kInt32x4ShuffleMix)) {
+    // Extract shuffle mask.
+    Definition* mask_definition = NULL;
+    if (getter == MethodRecognizer::kInt32x4Shuffle) {
+      ASSERT(call->ArgumentCount() == 2);
+      mask_definition = call->ArgumentAt(1);
+    } else {
+      ASSERT(getter == MethodRecognizer::kInt32x4ShuffleMix);
+      ASSERT(call->ArgumentCount() == 3);
+      mask_definition = call->ArgumentAt(2);
+    }
+    if (!mask_definition->IsConstant()) {
+      return false;
+    }
+    ASSERT(mask_definition->IsConstant());
+    ConstantInstr* constant_instruction = mask_definition->AsConstant();
+    const Object& constant_mask = constant_instruction->value();
+    if (!constant_mask.IsSmi()) {
+      return false;
+    }
+    ASSERT(constant_mask.IsSmi());
+    mask = Smi::Cast(constant_mask).Value();
+    if ((mask < 0) || (mask > 255)) {
+      // Not a valid mask.
+      return false;
+    }
+  }
+  if (getter == MethodRecognizer::kInt32x4GetSignMask) {
+    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else if (getter == MethodRecognizer::kInt32x4ShuffleMix) {
+    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        new(Z) Value(call->ArgumentAt(1)),
+        mask,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else if (getter == MethodRecognizer::kInt32x4Shuffle) {
+    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        mask,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else {
+    Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  }
+}
+
+
+bool AotOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
+                                           Token::Kind op_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  // Type check left.
+  AddCheckClass(left,
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Type check right.
+  AddCheckClass(right,
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Replace call.
+  BinaryFloat32x4OpInstr* float32x4_bin_op =
+      new(Z) BinaryFloat32x4OpInstr(
+          op_kind, new(Z) Value(left), new(Z) Value(right),
+          call->deopt_id());
+  ReplaceCall(call, float32x4_bin_op);
+
+  return true;
+}
+
+
+bool AotOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
+                                         Token::Kind op_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  // Type check left.
+  AddCheckClass(left,
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Type check right.
+  AddCheckClass(right,
+                ICData::ZoneHandle(Z,
+                    call->ic_data()->AsUnaryClassChecksForArgNr(1)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Replace call.
+  BinaryInt32x4OpInstr* int32x4_bin_op =
+      new(Z) BinaryInt32x4OpInstr(
+          op_kind, new(Z) Value(left), new(Z) Value(right),
+          call->deopt_id());
+  ReplaceCall(call, int32x4_bin_op);
+  return true;
+}
+
+
+bool AotOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
+                                           Token::Kind op_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  // Type check left.
+  AddCheckClass(left,
+                ICData::ZoneHandle(
+                    call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Type check right.
+  AddCheckClass(right,
+                ICData::ZoneHandle(
+                    call->ic_data()->AsUnaryClassChecksForArgNr(1)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Replace call.
+  BinaryFloat64x2OpInstr* float64x2_bin_op =
+      new(Z) BinaryFloat64x2OpInstr(
+          op_kind, new(Z) Value(left), new(Z) Value(right),
+          call->deopt_id());
+  ReplaceCall(call, float64x2_bin_op);
+  return true;
+}
+
+
+// Only unique implicit instance getters can be currently handled.
+bool AotOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
+  ASSERT(call->HasICData());
+  const ICData& ic_data = *call->ic_data();
+  if (ic_data.NumberOfUsedChecks() == 0) {
+    // No type feedback collected.
+    return false;
+  }
+
+  if (!ic_data.HasOneTarget()) {
+    // Polymorphic sites are inlined like normal methods by conventional
+    // inlining in FlowGraphInliner.
+    return false;
+  }
+
+  const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0));
+  if (target.kind() != RawFunction::kImplicitGetter) {
+    // Non-implicit getters are inlined like normal methods by conventional
+    // inlining in FlowGraphInliner.
+    return false;
+  }
+  return InlineImplicitInstanceGetter(call);
+}
+
+
+bool AotOptimizer::TryReplaceInstanceCallWithInline(
+    InstanceCallInstr* call) {
+  Function& target = Function::Handle(Z);
+  GrowableArray<intptr_t> class_ids;
+  call->ic_data()->GetCheckAt(0, &class_ids, &target);
+  const intptr_t receiver_cid = class_ids[0];
+
+  TargetEntryInstr* entry;
+  Definition* last;
+  if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_,
+                                                   receiver_cid,
+                                                   target,
+                                                   call,
+                                                   call->ArgumentAt(0),
+                                                   call->token_pos(),
+                                                   *call->ic_data(),
+                                                   &entry, &last)) {
+    return false;
+  }
+
+  // Insert receiver class check.
+  AddReceiverCheck(call);
+  // Remove the original push arguments.
+  for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+    PushArgumentInstr* push = call->PushArgumentAt(i);
+    push->ReplaceUsesWith(push->value()->definition());
+    push->RemoveFromGraph();
+  }
+  // Replace all uses of this definition with the result.
+  call->ReplaceUsesWith(last);
+  // Finally insert the sequence other definition in place of this one in the
+  // graph.
+  call->previous()->LinkTo(entry->next());
+  entry->UnuseAllInputs();  // Entry block is not in the graph.
+  last->LinkTo(call);
+  // Remove through the iterator.
+  ASSERT(current_iterator()->Current() == call);
+  current_iterator()->RemoveCurrentFromGraph();
+  call->set_previous(NULL);
+  call->set_next(NULL);
+  return true;
+}
+
+
+void AotOptimizer::ReplaceWithMathCFunction(
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  AddReceiverCheck(call);
+  ZoneGrowableArray<Value*>* args =
+      new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
+  for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
+    args->Add(new(Z) Value(call->ArgumentAt(i)));
+  }
+  InvokeMathCFunctionInstr* invoke =
+      new(Z) InvokeMathCFunctionInstr(args,
+                                      call->deopt_id(),
+                                      recognized_kind,
+                                      call->token_pos());
+  ReplaceCall(call, invoke);
+}
+
+
+static bool IsSupportedByteArrayViewCid(intptr_t cid) {
+  switch (cid) {
+    case kTypedDataInt8ArrayCid:
+    case kTypedDataUint8ArrayCid:
+    case kExternalTypedDataUint8ArrayCid:
+    case kTypedDataUint8ClampedArrayCid:
+    case kExternalTypedDataUint8ClampedArrayCid:
+    case kTypedDataInt16ArrayCid:
+    case kTypedDataUint16ArrayCid:
+    case kTypedDataInt32ArrayCid:
+    case kTypedDataUint32ArrayCid:
+    case kTypedDataFloat32ArrayCid:
+    case kTypedDataFloat64ArrayCid:
+    case kTypedDataFloat32x4ArrayCid:
+    case kTypedDataInt32x4ArrayCid:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+// Inline only simple, frequently called core library methods.
+bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
+  ASSERT(call->HasICData());
+  const ICData& ic_data = *call->ic_data();
+  if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
+    // No type feedback collected or multiple targets found.
+    return false;
+  }
+
+  Function& target = Function::Handle(Z);
+  GrowableArray<intptr_t> class_ids;
+  ic_data.GetCheckAt(0, &class_ids, &target);
+  MethodRecognizer::Kind recognized_kind =
+      MethodRecognizer::RecognizeKind(target);
+
+  if ((recognized_kind == MethodRecognizer::kGrowableArraySetData) &&
+      (ic_data.NumberOfChecks() == 1) &&
+      (class_ids[0] == kGrowableObjectArrayCid)) {
+    // This is an internal method, no need to check argument types.
+    Definition* array = call->ArgumentAt(0);
+    Definition* value = call->ArgumentAt(1);
+    StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
+        GrowableObjectArray::data_offset(),
+        new(Z) Value(array),
+        new(Z) Value(value),
+        kEmitStoreBarrier,
+        call->token_pos());
+    ReplaceCall(call, store);
+    return true;
+  }
+
+  if ((recognized_kind == MethodRecognizer::kGrowableArraySetLength) &&
+      (ic_data.NumberOfChecks() == 1) &&
+      (class_ids[0] == kGrowableObjectArrayCid)) {
+    // This is an internal method, no need to check argument types nor
+    // range.
+    Definition* array = call->ArgumentAt(0);
+    Definition* value = call->ArgumentAt(1);
+    StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
+        GrowableObjectArray::length_offset(),
+        new(Z) Value(array),
+        new(Z) Value(value),
+        kNoStoreBarrier,
+        call->token_pos());
+    ReplaceCall(call, store);
+    return true;
+  }
+
+  if (((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) ||
+       (recognized_kind == MethodRecognizer::kStringBaseCharAt)) &&
+      (ic_data.NumberOfChecks() == 1) &&
+      ((class_ids[0] == kOneByteStringCid) ||
+       (class_ids[0] == kTwoByteStringCid))) {
+    return TryReplaceInstanceCallWithInline(call);
+  }
+
+  if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) {
+    if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
+      // This is an internal method, no need to check argument types nor
+      // range.
+      Definition* str = call->ArgumentAt(0);
+      Definition* index = call->ArgumentAt(1);
+      Definition* value = call->ArgumentAt(2);
+      StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr(
+          new(Z) Value(str),
+          new(Z) Value(index),
+          new(Z) Value(value),
+          kNoStoreBarrier,
+          1,  // Index scale
+          kOneByteStringCid,
+          call->deopt_id(),
+          call->token_pos());
+      ReplaceCall(call, store_op);
+      return true;
+    }
+    return false;
+  }
+
+  if (CanUnboxDouble() &&
+      (recognized_kind == MethodRecognizer::kIntegerToDouble) &&
+      (ic_data.NumberOfChecks() == 1)) {
+    if (class_ids[0] == kSmiCid) {
+      AddReceiverCheck(call);
+      ReplaceCall(call,
+                  new(Z) SmiToDoubleInstr(
+                      new(Z) Value(call->ArgumentAt(0)),
+                      call->token_pos()));
+      return true;
+    } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) {
+      AddReceiverCheck(call);
+      ReplaceCall(call,
+                  new(Z) MintToDoubleInstr(new(Z) Value(call->ArgumentAt(0)),
+                                           call->deopt_id()));
+      return true;
+    }
+  }
+
+  if (class_ids[0] == kDoubleCid) {
+    if (!CanUnboxDouble()) {
+      return false;
+    }
+    switch (recognized_kind) {
+      case MethodRecognizer::kDoubleToInteger: {
+        AddReceiverCheck(call);
+        ASSERT(call->HasICData());
+        const ICData& ic_data = *call->ic_data();
+        Definition* input = call->ArgumentAt(0);
+        Definition* d2i_instr = NULL;
+        if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) {
+          // Do not repeatedly deoptimize because result didn't fit into Smi.
+          d2i_instr =  new(Z) DoubleToIntegerInstr(
+              new(Z) Value(input), call);
+        } else {
+          // Optimistically assume result fits into Smi.
+          d2i_instr = new(Z) DoubleToSmiInstr(
+              new(Z) Value(input), call->deopt_id());
+        }
+        ReplaceCall(call, d2i_instr);
+        return true;
+      }
+      case MethodRecognizer::kDoubleMod:
+      case MethodRecognizer::kDoubleRound:
+        ReplaceWithMathCFunction(call, recognized_kind);
+        return true;
+      case MethodRecognizer::kDoubleTruncate:
+      case MethodRecognizer::kDoubleFloor:
+      case MethodRecognizer::kDoubleCeil:
+        if (!TargetCPUFeatures::double_truncate_round_supported()) {
+          ReplaceWithMathCFunction(call, recognized_kind);
+        } else {
+          AddReceiverCheck(call);
+          DoubleToDoubleInstr* d2d_instr =
+              new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)),
+                                         recognized_kind, call->deopt_id());
+          ReplaceCall(call, d2d_instr);
+        }
+        return true;
+      case MethodRecognizer::kDoubleAdd:
+      case MethodRecognizer::kDoubleSub:
+      case MethodRecognizer::kDoubleMul:
+      case MethodRecognizer::kDoubleDiv:
+        return TryReplaceInstanceCallWithInline(call);
+      default:
+        // Unsupported method.
+        return false;
+    }
+  }
+
+  if (IsSupportedByteArrayViewCid(class_ids[0]) &&
+      (ic_data.NumberOfChecks() == 1)) {
+    return TryReplaceInstanceCallWithInline(call);
+  }
+
+  if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
+    return TryInlineFloat32x4Method(call, recognized_kind);
+  }
+
+  if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
+    return TryInlineInt32x4Method(call, recognized_kind);
+  }
+
+  if ((class_ids[0] == kFloat64x2Cid) && (ic_data.NumberOfChecks() == 1)) {
+    return TryInlineFloat64x2Method(call, recognized_kind);
+  }
+
+  if (recognized_kind == MethodRecognizer::kIntegerLeftShiftWithMask32) {
+    ASSERT(call->ArgumentCount() == 3);
+    ASSERT(ic_data.NumArgsTested() == 2);
+    Definition* value = call->ArgumentAt(0);
+    Definition* count = call->ArgumentAt(1);
+    Definition* int32_mask = call->ArgumentAt(2);
+    if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+      if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
+        return false;
+      }
+      // We cannot overflow. The input value must be a Smi
+      AddCheckSmi(value, call->deopt_id(), call->env(), call);
+      AddCheckSmi(count, call->deopt_id(), call->env(), call);
+      ASSERT(int32_mask->IsConstant());
+      const Integer& mask_literal = Integer::Cast(
+          int32_mask->AsConstant()->value());
+      const int64_t mask_value = mask_literal.AsInt64Value();
+      ASSERT(mask_value >= 0);
+      if (mask_value > Smi::kMaxValue) {
+        // The result will not be Smi.
+        return false;
+      }
+      BinarySmiOpInstr* left_shift =
+          new(Z) BinarySmiOpInstr(Token::kSHL,
+                                  new(Z) Value(value),
+                                  new(Z) Value(count),
+                                  call->deopt_id());
+      left_shift->mark_truncating();
+      if ((kBitsPerWord == 32) && (mask_value == 0xffffffffLL)) {
+        // No BIT_AND operation needed.
+        ReplaceCall(call, left_shift);
+      } else {
+        InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
+        BinarySmiOpInstr* bit_and =
+            new(Z) BinarySmiOpInstr(Token::kBIT_AND,
+                                    new(Z) Value(left_shift),
+                                    new(Z) Value(int32_mask),
+                                    call->deopt_id());
+        ReplaceCall(call, bit_and);
+      }
+      return true;
+    }
+
+    if (HasTwoMintOrSmi(ic_data) &&
+        HasOnlyOneSmi(ICData::Handle(Z,
+                                     ic_data.AsUnaryClassChecksForArgNr(1)))) {
+      if (!FlowGraphCompiler::SupportsUnboxedMints() ||
+          ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
+        return false;
+      }
+      ShiftMintOpInstr* left_shift =
+          new(Z) ShiftMintOpInstr(Token::kSHL,
+                                  new(Z) Value(value),
+                                  new(Z) Value(count),
+                                  call->deopt_id());
+      InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
+      BinaryMintOpInstr* bit_and =
+          new(Z) BinaryMintOpInstr(Token::kBIT_AND,
+                                   new(Z) Value(left_shift),
+                                   new(Z) Value(int32_mask),
+                                   call->deopt_id());
+      ReplaceCall(call, bit_and);
+      return true;
+    }
+  }
+  return false;
+}
+
+
+bool AotOptimizer::TryInlineFloat32x4Constructor(
+    StaticCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  // Cannot handle unboxed instructions.
+  ASSERT(FLAG_precompiled_mode);
+  return false;
+}
+
+
+bool AotOptimizer::TryInlineFloat64x2Constructor(
+    StaticCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  // Cannot handle unboxed instructions.
+  ASSERT(FLAG_precompiled_mode);
+  return false;
+}
+
+
+bool AotOptimizer::TryInlineInt32x4Constructor(
+    StaticCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  // Cannot handle unboxed instructions.
+  ASSERT(FLAG_precompiled_mode);
+  return false;
+}
+
+
+bool AotOptimizer::TryInlineFloat32x4Method(
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  // Cannot handle unboxed instructions.
+  return false;
+}
+
+
+bool AotOptimizer::TryInlineFloat64x2Method(
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  // Cannot handle unboxed instructions.
+  return false;
+}
+
+
+bool AotOptimizer::TryInlineInt32x4Method(
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  // Cannot handle unboxed instructions.
+  return false;
+}
+
+
+// If type tests specified by 'ic_data' do not depend on type arguments,
+// return mapping cid->result in 'results' (i : cid; i + 1: result).
+// If all tests yield the same result, return it otherwise return Bool::null.
+// If no mapping is possible, 'results' is empty.
+// An instance-of test returning all same results can be converted to a class
+// check.
+RawBool* AotOptimizer::InstanceOfAsBool(
+    const ICData& ic_data,
+    const AbstractType& type,
+    ZoneGrowableArray<intptr_t>* results) const {
+  ASSERT(results->is_empty());
+  ASSERT(ic_data.NumArgsTested() == 1);  // Unary checks only.
+  if (type.IsFunctionType() || type.IsDartFunctionType() ||
+      !type.IsInstantiated() || type.IsMalformedOrMalbounded()) {
+    return Bool::null();
+  }
+  const Class& type_class = Class::Handle(Z, type.type_class());
+  const intptr_t num_type_args = type_class.NumTypeArguments();
+  if (num_type_args > 0) {
+    // Only raw types can be directly compared, thus disregarding type
+    // arguments.
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::Handle(Z, type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
+    if (!is_raw_type) {
+      // Unknown result.
+      return Bool::null();
+    }
+  }
+
+  const ClassTable& class_table = *isolate()->class_table();
+  Bool& prev = Bool::Handle(Z);
+  Class& cls = Class::Handle(Z);
+
+  bool results_differ = false;
+  for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
+    cls = class_table.At(ic_data.GetReceiverClassIdAt(i));
+    if (cls.NumTypeArguments() > 0) {
+      return Bool::null();
+    }
+    const bool is_subtype = cls.IsSubtypeOf(
+        TypeArguments::Handle(Z),
+        type_class,
+        TypeArguments::Handle(Z),
+        NULL,
+        NULL,
+        Heap::kOld);
+    results->Add(cls.id());
+    results->Add(is_subtype);
+    if (prev.IsNull()) {
+      prev = Bool::Get(is_subtype).raw();
+    } else {
+      if (is_subtype != prev.value()) {
+        results_differ = true;
+      }
+    }
+  }
+  return results_differ ?  Bool::null() : prev.raw();
+}
+
+
+// Returns true if checking against this type is a direct class id comparison.
+bool AotOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
+  ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
+  // Requires CHA.
+  if (!type.IsInstantiated()) return false;
+  // Function types have different type checking rules.
+  if (type.IsFunctionType()) return false;
+  const Class& type_class = Class::Handle(type.type_class());
+  // Could be an interface check?
+  if (CHA::IsImplemented(type_class)) return false;
+  // Check if there are subclasses.
+  if (CHA::HasSubclasses(type_class)) {
+    return false;
+  }
+
+  // Private classes cannot be subclassed by later loaded libs.
+  if (!type_class.IsPrivate()) {
+    if (FLAG_use_cha_deopt || isolate()->all_classes_finalized()) {
+      if (FLAG_trace_cha) {
+        THR_Print("  **(CHA) Typecheck as class equality since no "
+            "subclasses: %s\n",
+            type_class.ToCString());
+      }
+      if (FLAG_use_cha_deopt) {
+        thread()->cha()->AddToLeafClasses(type_class);
+      }
+    } else {
+      return false;
+    }
+  }
+  const intptr_t num_type_args = type_class.NumTypeArguments();
+  if (num_type_args > 0) {
+    // Only raw types can be directly compared, thus disregarding type
+    // arguments.
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::Handle(type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
+    return is_raw_type;
+  }
+  return true;
+}
+
+
+static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results,
+                                   intptr_t test_cid) {
+  for (intptr_t i = 0; i < results.length(); i += 2) {
+    if (results[i] == test_cid) return true;
+  }
+  return false;
+}
+
+
+static void TryAddTest(ZoneGrowableArray<intptr_t>* results,
+                       intptr_t test_cid,
+                       bool result) {
+  if (!CidTestResultsContains(*results, test_cid)) {
+    results->Add(test_cid);
+    results->Add(result);
+  }
+}
+
+
+// Tries to add cid tests to 'results' so that no deoptimization is
+// necessary.
+// TODO(srdjan): Do also for other than 'int' type.
+static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results,
+                                    const AbstractType& type) {
+  ASSERT(results->length() >= 2);  // At least on eentry.
+  const ClassTable& class_table = *Isolate::Current()->class_table();
+  if ((*results)[0] != kSmiCid) {
+    const Class& cls = Class::Handle(class_table.At(kSmiCid));
+    const Class& type_class = Class::Handle(type.type_class());
+    const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(),
+                                                type_class,
+                                                TypeArguments::Handle(),
+                                                NULL,
+                                                NULL,
+                                                Heap::kOld);
+    results->Add((*results)[results->length() - 2]);
+    results->Add((*results)[results->length() - 2]);
+    for (intptr_t i = results->length() - 3; i > 1; --i) {
+      (*results)[i] = (*results)[i - 2];
+    }
+    (*results)[0] = kSmiCid;
+    (*results)[1] = smi_is_subtype;
+  }
+
+  ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded());
+  ASSERT(results->length() >= 2);
+  if (type.IsIntType()) {
+    ASSERT((*results)[0] == kSmiCid);
+    TryAddTest(results, kMintCid, true);
+    TryAddTest(results, kBigintCid, true);
+    // Cannot deoptimize since all tests returning true have been added.
+    return false;
+  }
+
+  return true;  // May deoptimize since we have not identified all 'true' tests.
+}
+
+
+// TODO(srdjan): Use ICData to check if always true or false.
+void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
+  ASSERT(Token::IsTypeTestOperator(call->token_kind()));
+  Definition* left = call->ArgumentAt(0);
+  Definition* type_args = NULL;
+  AbstractType& type = AbstractType::ZoneHandle(Z);
+  bool negate = false;
+  if (call->ArgumentCount() == 2) {
+    type_args = flow_graph()->constant_null();
+    if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) {
+      type = Type::Number();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfInt()).raw()) {
+      type = Type::IntType();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfSmi()).raw()) {
+      type = Type::SmiType();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfDouble()).raw()) {
+      type = Type::Double();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfString()).raw()) {
+      type = Type::StringType();
+    } else {
+      UNIMPLEMENTED();
+    }
+    negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition()
+        ->AsConstant()->value()).value();
+  } else {
+    type_args = call->ArgumentAt(1);
+    type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw();
+    negate = Bool::Cast(call->ArgumentAt(3)->OriginalDefinition()
+        ->AsConstant()->value()).value();
+  }
+  const ICData& unary_checks =
+      ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
+  if ((unary_checks.NumberOfChecks() > 0) &&
+      (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
+    ZoneGrowableArray<intptr_t>* results =
+        new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
+    Bool& as_bool =
+        Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results));
+    if (as_bool.IsNull()) {
+      if (results->length() == unary_checks.NumberOfChecks() * 2) {
+        const bool can_deopt = TryExpandTestCidsResult(results, type);
+        TestCidsInstr* test_cids = new(Z) TestCidsInstr(
+            call->token_pos(),
+            negate ? Token::kISNOT : Token::kIS,
+            new(Z) Value(left),
+            *results,
+            can_deopt ? call->deopt_id() : Thread::kNoDeoptId);
+        // Remove type.
+        ReplaceCall(call, test_cids);
+        return;
+      }
+    } else {
+      // TODO(srdjan): Use TestCidsInstr also for this case.
+      // One result only.
+      AddReceiverCheck(call);
+      if (negate) {
+        as_bool = Bool::Get(!as_bool.value()).raw();
+      }
+      ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool);
+      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+        PushArgumentInstr* push = call->PushArgumentAt(i);
+        push->ReplaceUsesWith(push->value()->definition());
+        push->RemoveFromGraph();
+      }
+      call->ReplaceUsesWith(bool_const);
+      ASSERT(current_iterator()->Current() == call);
+      current_iterator()->RemoveCurrentFromGraph();
+      return;
+    }
+  }
+
+  if (TypeCheckAsClassEquality(type)) {
+    LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left));
+    InsertBefore(call,
+                 left_cid,
+                 NULL,
+                 FlowGraph::kValue);
+    const intptr_t type_cid = Class::Handle(Z, type.type_class()).id();
+    ConstantInstr* cid =
+        flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid)));
+
+    StrictCompareInstr* check_cid =
+        new(Z) StrictCompareInstr(
+            call->token_pos(),
+            negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
+            new(Z) Value(left_cid),
+            new(Z) Value(cid),
+            false);  // No number check.
+    ReplaceCall(call, check_cid);
+    return;
+  }
+
+  InstanceOfInstr* instance_of =
+      new(Z) InstanceOfInstr(call->token_pos(),
+                             new(Z) Value(left),
+                             new(Z) Value(type_args),
+                             type,
+                             negate,
+                             call->deopt_id());
+  ReplaceCall(call, instance_of);
+}
+
+
+// TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
+void AotOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
+  ASSERT(Token::IsTypeCastOperator(call->token_kind()));
+  Definition* left = call->ArgumentAt(0);
+  Definition* type_args = call->ArgumentAt(1);
+  const AbstractType& type =
+      AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
+  ASSERT(!type.IsMalformedOrMalbounded());
+  const ICData& unary_checks =
+      ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
+  if ((unary_checks.NumberOfChecks() > 0) &&
+      (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
+    ZoneGrowableArray<intptr_t>* results =
+        new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
+    const Bool& as_bool = Bool::ZoneHandle(Z,
+        InstanceOfAsBool(unary_checks, type, results));
+    if (as_bool.raw() == Bool::True().raw()) {
+      AddReceiverCheck(call);
+      // Remove the original push arguments.
+      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+        PushArgumentInstr* push = call->PushArgumentAt(i);
+        push->ReplaceUsesWith(push->value()->definition());
+        push->RemoveFromGraph();
+      }
+      // Remove call, replace it with 'left'.
+      call->ReplaceUsesWith(left);
+      ASSERT(current_iterator()->Current() == call);
+      current_iterator()->RemoveCurrentFromGraph();
+      return;
+    }
+  }
+  const String& dst_name = String::ZoneHandle(Z,
+      Symbols::New(Exceptions::kCastErrorDstName));
+  AssertAssignableInstr* assert_as =
+      new(Z) AssertAssignableInstr(call->token_pos(),
+                                   new(Z) Value(left),
+                                   new(Z) Value(type_args),
+                                   type,
+                                   dst_name,
+                                   call->deopt_id());
+  ReplaceCall(call, assert_as);
+}
+
+
+bool AotOptimizer::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 AotOptimizer::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)) {
+    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)) {
+    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 AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
+  ASSERT(FLAG_precompiled_mode);
+  InstanceCallNoopt(instr);
+}
+
+
+void AotOptimizer::VisitStaticCall(StaticCallInstr* call) {
+  if (!CanUnboxDouble()) {
+    return;
+  }
+  MethodRecognizer::Kind recognized_kind =
+      MethodRecognizer::RecognizeKind(call->function());
+  MathUnaryInstr::MathUnaryKind unary_kind;
+  switch (recognized_kind) {
+    case MethodRecognizer::kMathSqrt:
+      unary_kind = MathUnaryInstr::kSqrt;
+      break;
+    case MethodRecognizer::kMathSin:
+      unary_kind = MathUnaryInstr::kSin;
+      break;
+    case MethodRecognizer::kMathCos:
+      unary_kind = MathUnaryInstr::kCos;
+      break;
+    default:
+      unary_kind = MathUnaryInstr::kIllegal;
+      break;
+  }
+  if (unary_kind != MathUnaryInstr::kIllegal) {
+    ASSERT(FLAG_precompiled_mode);
+    // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
+    return;
+  }
+
+  switch (recognized_kind) {
+    case MethodRecognizer::kFloat32x4Zero:
+    case MethodRecognizer::kFloat32x4Splat:
+    case MethodRecognizer::kFloat32x4Constructor:
+    case MethodRecognizer::kFloat32x4FromFloat64x2:
+      TryInlineFloat32x4Constructor(call, recognized_kind);
+      break;
+    case MethodRecognizer::kFloat64x2Constructor:
+    case MethodRecognizer::kFloat64x2Zero:
+    case MethodRecognizer::kFloat64x2Splat:
+    case MethodRecognizer::kFloat64x2FromFloat32x4:
+      TryInlineFloat64x2Constructor(call, recognized_kind);
+      break;
+    case MethodRecognizer::kInt32x4BoolConstructor:
+    case MethodRecognizer::kInt32x4Constructor:
+      TryInlineInt32x4Constructor(call, recognized_kind);
+      break;
+    case MethodRecognizer::kObjectConstructor: {
+      // Remove the original push arguments.
+      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+        PushArgumentInstr* push = call->PushArgumentAt(i);
+        push->ReplaceUsesWith(push->value()->definition());
+        push->RemoveFromGraph();
+      }
+      // Manually replace call with global null constant. ReplaceCall can't
+      // be used for definitions that are already in the graph.
+      call->ReplaceUsesWith(flow_graph_->constant_null());
+      ASSERT(current_iterator()->Current() == call);
+      current_iterator()->RemoveCurrentFromGraph();
+      break;
+    }
+    case MethodRecognizer::kMathMin:
+    case MethodRecognizer::kMathMax: {
+      // We can handle only monomorphic min/max call sites with both arguments
+      // being either doubles or smis.
+      if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
+        const ICData& ic_data = *call->ic_data();
+        intptr_t result_cid = kIllegalCid;
+        if (ICDataHasReceiverArgumentClassIds(ic_data,
+                                              kDoubleCid, kDoubleCid)) {
+          result_cid = kDoubleCid;
+        } else if (ICDataHasReceiverArgumentClassIds(ic_data,
+                                                     kSmiCid, kSmiCid)) {
+          result_cid = kSmiCid;
+        }
+        if (result_cid != kIllegalCid) {
+          MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr(
+              recognized_kind,
+              new(Z) Value(call->ArgumentAt(0)),
+              new(Z) Value(call->ArgumentAt(1)),
+              call->deopt_id(),
+              result_cid);
+          const ICData& unary_checks =
+              ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks());
+          AddCheckClass(min_max->left()->definition(),
+                        unary_checks,
+                        call->deopt_id(),
+                        call->env(),
+                        call);
+          AddCheckClass(min_max->right()->definition(),
+                        unary_checks,
+                        call->deopt_id(),
+                        call->env(),
+                        call);
+          ReplaceCall(call, min_max);
+        }
+      }
+      break;
+    }
+    case MethodRecognizer::kMathDoublePow:
+    case MethodRecognizer::kMathTan:
+    case MethodRecognizer::kMathAsin:
+    case MethodRecognizer::kMathAcos:
+    case MethodRecognizer::kMathAtan:
+    case MethodRecognizer::kMathAtan2: {
+      ASSERT(FLAG_precompiled_mode);
+      // No UnboxDouble instructions allowed.
+      return;
+    }
+    case MethodRecognizer::kDoubleFromInteger: {
+      if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
+        const ICData& ic_data = *call->ic_data();
+        if (CanUnboxDouble()) {
+          if (ArgIsAlways(kSmiCid, ic_data, 1)) {
+            Definition* arg = call->ArgumentAt(1);
+            AddCheckSmi(arg, call->deopt_id(), call->env(), call);
+            ReplaceCall(call,
+                        new(Z) SmiToDoubleInstr(new(Z) Value(arg),
+                                                call->token_pos()));
+          } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
+                     CanConvertUnboxedMintToDouble()) {
+            Definition* arg = call->ArgumentAt(1);
+            ReplaceCall(call,
+                        new(Z) MintToDoubleInstr(new(Z) Value(arg),
+                                                 call->deopt_id()));
+          }
+        }
+      }
+      break;
+    }
+    default: {
+      if (call->function().IsFactory()) {
+        const Class& function_class =
+            Class::Handle(Z, call->function().Owner());
+        if ((function_class.library() == Library::CoreLibrary()) ||
+            (function_class.library() == Library::TypedDataLibrary())) {
+          intptr_t cid = FactoryRecognizer::ResultCid(call->function());
+          switch (cid) {
+            case kArrayCid: {
+              Value* type = new(Z) Value(call->ArgumentAt(0));
+              Value* num_elements = new(Z) Value(call->ArgumentAt(1));
+              if (num_elements->BindsToConstant() &&
+                  num_elements->BoundConstant().IsSmi()) {
+                intptr_t length =
+                    Smi::Cast(num_elements->BoundConstant()).Value();
+                if (length >= 0 && length <= Array::kMaxElements) {
+                  CreateArrayInstr* create_array =
+                      new(Z) CreateArrayInstr(
+                          call->token_pos(), type, num_elements);
+                  ReplaceCall(call, create_array);
+                }
+              }
+            }
+            default:
+              break;
+          }
+        }
+      }
+    }
+  }
+}
+
+
+void AotOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
+  // Replace generic allocation with a sequence of inlined allocation and
+  // explicit initalizing stores.
+  AllocateUninitializedContextInstr* replacement =
+      new AllocateUninitializedContextInstr(instr->token_pos(),
+                                            instr->num_context_variables());
+  instr->ReplaceWith(replacement, current_iterator());
+
+  StoreInstanceFieldInstr* store =
+      new(Z) StoreInstanceFieldInstr(Context::parent_offset(),
+                                     new Value(replacement),
+                                     new Value(flow_graph_->constant_null()),
+                                     kNoStoreBarrier,
+                                     instr->token_pos());
+  // Storing into uninitialized memory; remember to prevent dead store
+  // elimination and ensure proper GC barrier.
+  store->set_is_object_reference_initialization(true);
+  flow_graph_->InsertAfter(replacement, store, NULL, FlowGraph::kEffect);
+  Definition* cursor = store;
+  for (intptr_t i = 0; i < instr->num_context_variables(); ++i) {
+    store =
+        new(Z) StoreInstanceFieldInstr(Context::variable_offset(i),
+                                       new Value(replacement),
+                                       new Value(flow_graph_->constant_null()),
+                                       kNoStoreBarrier,
+                                       instr->token_pos());
+    // Storing into uninitialized memory; remember to prevent dead store
+    // elimination and ensure proper GC barrier.
+    store->set_is_object_reference_initialization(true);
+    flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect);
+    cursor = store;
+  }
+}
+
+
+void AotOptimizer::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())
+    instr->set_representation(kUnboxedMint);
+#endif
+}
+
+
+bool AotOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
+                                           const ICData& unary_ic_data) {
+  ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
+      (unary_ic_data.NumArgsTested() == 1));
+  if (I->type_checks()) {
+    // Checked mode setters are inlined like normal methods by conventional
+    // inlining.
+    return false;
+  }
+
+  ASSERT(instr->HasICData());
+  if (unary_ic_data.NumberOfChecks() == 0) {
+    // No type feedback collected.
+    return false;
+  }
+  if (!unary_ic_data.HasOneTarget()) {
+    // Polymorphic sites are inlined like normal method calls by conventional
+    // inlining.
+    return false;
+  }
+  Function& target = Function::Handle(Z);
+  intptr_t class_id;
+  unary_ic_data.GetOneClassCheckAt(0, &class_id, &target);
+  if (target.kind() != RawFunction::kImplicitSetter) {
+    // Non-implicit setter are inlined like normal method calls.
+    return false;
+  }
+  // Inline implicit instance setter.
+  const String& field_name =
+      String::Handle(Z, Field::NameFromSetter(instr->function_name()));
+  const Field& field =
+      Field::ZoneHandle(Z, GetField(class_id, field_name));
+  ASSERT(!field.IsNull());
+
+  if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) {
+    return false;
+  }
+
+  // Field guard was detached.
+  StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
+      field,
+      new(Z) Value(instr->ArgumentAt(0)),
+      new(Z) Value(instr->ArgumentAt(1)),
+      kEmitStoreBarrier,
+      instr->token_pos());
+
+  // No unboxed stores in precompiled code.
+  ASSERT(!store->IsUnboxedStore());
+
+  // Discard the environment from the original instruction because the store
+  // can't deoptimize.
+  instr->RemoveEnvironment();
+  ReplaceCall(instr, store);
+  return true;
+}
+
+
+}  // namespace dart
diff --git a/runtime/vm/aot_optimizer.h b/runtime/vm/aot_optimizer.h
new file mode 100644
index 0000000..3d1ed1b
--- /dev/null
+++ b/runtime/vm/aot_optimizer.h
@@ -0,0 +1,186 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_AOT_OPTIMIZER_H_
+#define VM_AOT_OPTIMIZER_H_
+
+#include "vm/intermediate_language.h"
+#include "vm/flow_graph.h"
+
+namespace dart {
+
+class CSEInstructionMap;
+template <typename T> class GrowableArray;
+class ParsedFunction;
+class RawBool;
+
+class AotOptimizer : public FlowGraphVisitor {
+ public:
+  AotOptimizer(
+      FlowGraph* flow_graph,
+      bool use_speculative_inlining,
+      GrowableArray<intptr_t>* inlining_black_list)
+      : FlowGraphVisitor(flow_graph->reverse_postorder()),
+        flow_graph_(flow_graph),
+        use_speculative_inlining_(use_speculative_inlining),
+        inlining_black_list_(inlining_black_list) {
+    ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
+  }
+  virtual ~AotOptimizer() {}
+
+  FlowGraph* flow_graph() const { return flow_graph_; }
+
+  // Add ICData to InstanceCalls, so that optimizations can be run on them.
+  // TODO(srdjan): StaticCals as well?
+  void PopulateWithICData();
+
+  // Use ICData to optimize, replace or eliminate instructions.
+  void ApplyICData();
+
+  // Use propagated class ids to optimize, replace or eliminate instructions.
+  void ApplyClassIds();
+
+  // 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.
+  // Merge instructions (only per basic-block).
+  void TryOptimizePatterns();
+
+  virtual void VisitStaticCall(StaticCallInstr* instr);
+  virtual void VisitInstanceCall(InstanceCallInstr* instr);
+  virtual void VisitAllocateContext(AllocateContextInstr* instr);
+  virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr* instr);
+
+  void InsertBefore(Instruction* next,
+                    Instruction* instr,
+                    Environment* env,
+                    FlowGraph::UseKind use_kind) {
+    flow_graph_->InsertBefore(next, instr, env, use_kind);
+  }
+
+ private:
+  // Attempt to build ICData for call using propagated class-ids.
+  bool TryCreateICData(InstanceCallInstr* call);
+  const ICData& TrySpecializeICData(const ICData& ic_data, intptr_t cid);
+
+  void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
+
+  bool TryReplaceWithIndexedOp(InstanceCallInstr* call);
+
+
+  bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind);
+  bool TryReplaceWithUnaryOp(InstanceCallInstr* call, Token::Kind op_kind);
+
+  bool TryReplaceWithEqualityOp(InstanceCallInstr* call, Token::Kind op_kind);
+  bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
+
+  bool TryInlineInstanceGetter(InstanceCallInstr* call);
+  bool TryInlineInstanceSetter(InstanceCallInstr* call,
+                               const ICData& unary_ic_data);
+
+  bool TryInlineInstanceMethod(InstanceCallInstr* call);
+  bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
+                                     MethodRecognizer::Kind recognized_kind);
+  bool TryInlineFloat64x2Constructor(StaticCallInstr* call,
+                                     MethodRecognizer::Kind recognized_kind);
+  bool TryInlineInt32x4Constructor(StaticCallInstr* call,
+                                    MethodRecognizer::Kind recognized_kind);
+  bool TryInlineFloat32x4Method(InstanceCallInstr* call,
+                                MethodRecognizer::Kind recognized_kind);
+  bool TryInlineFloat64x2Method(InstanceCallInstr* call,
+                                MethodRecognizer::Kind recognized_kind);
+  bool TryInlineInt32x4Method(InstanceCallInstr* call,
+                               MethodRecognizer::Kind recognized_kind);
+  void ReplaceWithInstanceOf(InstanceCallInstr* instr);
+  bool TypeCheckAsClassEquality(const AbstractType& type);
+  void ReplaceWithTypeCast(InstanceCallInstr* instr);
+
+  bool TryReplaceInstanceCallWithInline(InstanceCallInstr* call);
+
+  // Insert a check of 'to_check' determined by 'unary_checks'.  If the
+  // check fails it will deoptimize to 'deopt_id' using the deoptimization
+  // environment 'deopt_environment'.  The check is inserted immediately
+  // before 'insert_before'.
+  void AddCheckClass(Definition* to_check,
+                     const ICData& unary_checks,
+                     intptr_t deopt_id,
+                     Environment* deopt_environment,
+                     Instruction* insert_before);
+  Instruction* GetCheckClass(Definition* to_check,
+                             const ICData& unary_checks,
+                             intptr_t deopt_id,
+                             TokenPosition token_pos);
+
+  // Insert a Smi check if needed.
+  void AddCheckSmi(Definition* to_check,
+                   intptr_t deopt_id,
+                   Environment* deopt_environment,
+                   Instruction* insert_before);
+
+  // Add a class check for a call's first argument immediately before the
+  // call, using the call's IC data to determine the check, and the call's
+  // deopt ID and deoptimization environment if the check fails.
+  void AddReceiverCheck(InstanceCallInstr* call);
+
+  void ReplaceCall(Definition* call, Definition* replacement);
+
+
+  bool InstanceCallNeedsClassCheck(InstanceCallInstr* call,
+                                   RawFunction::Kind kind) const;
+
+  bool InlineFloat32x4Getter(InstanceCallInstr* call,
+                             MethodRecognizer::Kind getter);
+  bool InlineFloat64x2Getter(InstanceCallInstr* call,
+                             MethodRecognizer::Kind getter);
+  bool InlineInt32x4Getter(InstanceCallInstr* call,
+                            MethodRecognizer::Kind getter);
+  bool InlineFloat32x4BinaryOp(InstanceCallInstr* call,
+                               Token::Kind op_kind);
+  bool InlineInt32x4BinaryOp(InstanceCallInstr* call,
+                              Token::Kind op_kind);
+  bool InlineFloat64x2BinaryOp(InstanceCallInstr* call,
+                               Token::Kind op_kind);
+  bool InlineImplicitInstanceGetter(InstanceCallInstr* call);
+
+  RawBool* InstanceOfAsBool(const ICData& ic_data,
+                            const AbstractType& type,
+                            ZoneGrowableArray<intptr_t>* results) const;
+
+  void ReplaceWithMathCFunction(InstanceCallInstr* call,
+                                MethodRecognizer::Kind recognized_kind);
+
+  void OptimizeLeftShiftBitAndSmiOp(Definition* bit_and_instr,
+                                    Definition* left_instr,
+                                    Definition* right_instr);
+  void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
+  void TryMergeMathUnary(GrowableArray<MathUnaryInstr*>* merge_candidates);
+
+  void AppendExtractNthOutputForMerged(Definition* instr, intptr_t ix,
+                                       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(); }
+  Isolate* isolate() const { return flow_graph_->isolate(); }
+  Zone* zone() const { return flow_graph_->zone(); }
+
+  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(AotOptimizer);
+};
+
+
+}  // namespace dart
+
+#endif  // VM_AOT_OPTIMIZER_H_
diff --git a/runtime/vm/assembler.cc b/runtime/vm/assembler.cc
index f5358c1..318881c 100644
--- a/runtime/vm/assembler.cc
+++ b/runtime/vm/assembler.cc
@@ -13,9 +13,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, disassemble);
-DECLARE_FLAG(bool, disassemble_optimized);
-
 DEFINE_FLAG(bool, check_code_pointer, false,
             "Verify instructions offset in code object."
             "NOTE: This breaks the profiler.");
@@ -247,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) {
@@ -268,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.
@@ -285,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_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 12f470a..1e6e6ef 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -1798,10 +1798,20 @@
 
 ASSEMBLER_TEST_RUN(IntDiv_supported, test) {
   EXPECT(test != NULL);
+#if defined(USING_SIMULATOR)
+  bool orig = TargetCPUFeatures::integer_division_supported();
+  HostCPUFeatures::set_integer_division_supported(true);
   if (TargetCPUFeatures::can_divide()) {
     typedef int (*Tst)() DART_UNUSED;
     EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
   }
+  HostCPUFeatures::set_integer_division_supported(orig);
+#else
+  if (TargetCPUFeatures::can_divide()) {
+    typedef int (*Tst)() DART_UNUSED;
+    EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+  }
+#endif
 }
 
 
@@ -1829,10 +1839,20 @@
 
 ASSEMBLER_TEST_RUN(IntDiv_unsupported, test) {
   EXPECT(test != NULL);
+#if defined(USING_SIMULATOR)
+  bool orig = TargetCPUFeatures::integer_division_supported();
+  HostCPUFeatures::set_integer_division_supported(false);
   if (TargetCPUFeatures::can_divide()) {
     typedef int (*Tst)() DART_UNUSED;
     EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
   }
+  HostCPUFeatures::set_integer_division_supported(orig);
+#else
+  if (TargetCPUFeatures::can_divide()) {
+    typedef int (*Tst)() DART_UNUSED;
+    EXPECT_EQ(3, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
+  }
+#endif
 }
 
 
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 e075dd3..1654ac9 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -158,10 +158,11 @@
     kImmSize = 16,
   };
 
-  class LeftBits : public BitField<Register, kLeftPos, kLeftSize> {};
-  class RightBits : public BitField<Register, kRightPos, kRightSize> {};
-  class RelOpBits : public BitField<RelationOperator, kRelOpPos, kRelOpSize> {};
-  class ImmBits : public BitField<uint16_t, kImmPos, kImmSize> {};
+  class LeftBits : public BitField<uword, Register, kLeftPos, kLeftSize> {};
+  class RightBits : public BitField<uword, Register, kRightPos, kRightSize> {};
+  class RelOpBits :
+      public BitField<uword, RelationOperator, kRelOpPos, kRelOpSize> {};
+  class ImmBits : public BitField<uword, uint16_t, kImmPos, kImmSize> {};
 
   Register left() const { return LeftBits::decode(bits_); }
   Register right() const { return RightBits::decode(bits_); }
@@ -662,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());
@@ -790,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);
@@ -925,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 19542b3..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 {
@@ -91,7 +102,7 @@
 }
 
 
-LetNode::LetNode(intptr_t token_pos)
+LetNode::LetNode(TokenPosition token_pos)
   : AstNode(token_pos),
     vars_(1),
     initializers_(1),
@@ -101,8 +112,8 @@
 LocalVariable* LetNode::AddInitializer(AstNode* node) {
   initializers_.Add(node);
   char name[64];
-  OS::SNPrint(name, sizeof(name), ":lt%" Pd "_%" Pd "",
-      token_pos(), vars_.length());
+  OS::SNPrint(name, sizeof(name), ":lt%s_%" Pd "",
+      token_pos().ToCString(), vars_.length());
   LocalVariable* temp_var =
       new LocalVariable(token_pos(),
                         String::ZoneHandle(Symbols::New(name)),
@@ -121,6 +132,36 @@
   }
 }
 
+bool LetNode::IsPotentiallyConst() const {
+  for (intptr_t i = 0; i < num_temps(); i++) {
+    if (!initializers_[i]->IsPotentiallyConst()) {
+      return false;
+    }
+  }
+  for (intptr_t i = 0; i < nodes_.length(); i++) {
+    if (!nodes_[i]->IsPotentiallyConst()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+const Instance* LetNode::EvalConstExpr() const {
+  for (intptr_t i = 0; i < num_temps(); i++) {
+    if (initializers_[i]->EvalConstExpr() == NULL) {
+      return NULL;
+    }
+  }
+  const Instance* last = NULL;
+  for (intptr_t i = 0; i < nodes_.length(); i++) {
+    last = nodes_[i]->EvalConstExpr();
+    if (last == NULL) {
+      return NULL;
+    }
+  }
+  return last;
+}
+
 
 void ArrayNode::VisitChildren(AstNodeVisitor* visitor) const {
   for (intptr_t i = 0; i < this->length(); i++) {
@@ -329,6 +370,7 @@
     case Token::kBIT_AND:
     case Token::kSHL:
     case Token::kSHR:
+    case Token::kIFNULL:
       return this->left()->IsPotentiallyConst() &&
           this->right()->IsPotentiallyConst();
     default:
@@ -343,7 +385,8 @@
   if (left_val == NULL) {
     return NULL;
   }
-  if (!left_val->IsNumber() && !left_val->IsBool() && !left_val->IsString()) {
+  if (!left_val->IsNumber() && !left_val->IsBool() && !left_val->IsString() &&
+      kind_ != Token::kIFNULL) {
     return NULL;
   }
   const Instance* right_val = this->right()->EvalConstExpr();
@@ -388,6 +431,11 @@
         return left_val;
       }
       return NULL;
+    case Token::kIFNULL:
+      if (left_val->IsNull()) {
+        return right_val;
+      }
+      return left_val;
     default:
       UNREACHABLE();
       return NULL;
@@ -396,7 +444,7 @@
 }
 
 
-AstNode* UnaryOpNode::UnaryOpOrLiteral(intptr_t token_pos,
+AstNode* UnaryOpNode::UnaryOpOrLiteral(TokenPosition token_pos,
                                        Token::Kind kind,
                                        AstNode* operand) {
   AstNode* new_operand = operand->ApplyUnaryOp(kind);
@@ -538,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);
 }
 
 
@@ -626,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()),
@@ -661,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()),
@@ -717,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 01ae0cf..4ca2372 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -12,6 +12,7 @@
 #include "vm/object.h"
 #include "vm/native_entry.h"
 #include "vm/token.h"
+#include "vm/token_position.h"
 
 namespace dart {
 
@@ -91,19 +92,20 @@
 
 #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; }
 
 
 class AstNode : public ZoneAllocated {
  public:
-  explicit AstNode(intptr_t token_pos)
+  explicit AstNode(TokenPosition token_pos)
       : token_pos_(token_pos) {
-    ASSERT(Scanner::ValidSourcePosition(token_pos_));
+    ASSERT(!token_pos_.IsClassifying() ||
+           (token_pos_ == TokenPosition::kMethodExtractor));
   }
   virtual ~AstNode() { }
 
-  intptr_t token_pos() const { return token_pos_; }
+  TokenPosition token_pos() const { return token_pos_; }
 
 #define AST_TYPE_CHECK(BaseName)                                               \
   bool Is##BaseName##Node() { return As##BaseName##Node() != NULL; }           \
@@ -114,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,
@@ -148,18 +150,22 @@
   // 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;
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   DISALLOW_COPY_AND_ASSIGN(AstNode);
 };
 
 
 class AwaitNode : public AstNode {
  public:
-  AwaitNode(intptr_t token_pos,
+  AwaitNode(TokenPosition token_pos,
             AstNode* expr,
             LocalVariable* saved_try_ctx,
             LocalVariable* async_saved_try_ctx,
@@ -214,7 +220,7 @@
  public:
   AwaitMarkerNode(LocalScope* async_scope,
                   LocalScope* await_scope,
-                  intptr_t token_pos)
+                  TokenPosition token_pos)
     : AstNode(token_pos),
       async_scope_(async_scope),
       await_scope_(await_scope) {
@@ -240,7 +246,7 @@
 
 class SequenceNode : public AstNode {
  public:
-  SequenceNode(intptr_t token_pos, LocalScope* scope)
+  SequenceNode(TokenPosition token_pos, LocalScope* scope)
     : AstNode(token_pos),
       scope_(scope),
       nodes_(4),
@@ -275,7 +281,7 @@
 
 class CloneContextNode : public AstNode {
  public:
-  explicit CloneContextNode(intptr_t token_pos)
+  explicit CloneContextNode(TokenPosition token_pos)
     : AstNode(token_pos) {
   }
 
@@ -290,7 +296,7 @@
 
 class ArgumentListNode : public AstNode {
  public:
-  explicit ArgumentListNode(intptr_t token_pos)
+  explicit ArgumentListNode(TokenPosition token_pos)
      : AstNode(token_pos),
        nodes_(4),
        names_(Array::ZoneHandle()) {
@@ -322,11 +328,14 @@
 
 class LetNode : public AstNode {
  public:
-  explicit LetNode(intptr_t token_pos);
+  explicit LetNode(TokenPosition token_pos);
 
   LocalVariable* TempAt(intptr_t i) const { return vars_[i]; }
   AstNode* InitializerAt(intptr_t i) const { return initializers_[i]; }
 
+  virtual bool IsPotentiallyConst() const;
+  virtual const Instance* EvalConstExpr() const;
+
   LocalVariable* AddInitializer(AstNode* node);
 
   const GrowableArray<AstNode*>& nodes() const { return nodes_; }
@@ -352,13 +361,13 @@
 
 class ArrayNode : public AstNode {
  public:
-  ArrayNode(intptr_t token_pos, const AbstractType& type)
+  ArrayNode(TokenPosition token_pos, const AbstractType& type)
       : AstNode(token_pos),
         type_(type),
         elements_() {
     CheckFields();
   }
-  ArrayNode(intptr_t token_pos,
+  ArrayNode(TokenPosition token_pos,
             const AbstractType& type,
             const GrowableArray<AstNode*>& elements)
       : AstNode(token_pos),
@@ -403,7 +412,7 @@
 
 class StringInterpolateNode : public AstNode {
  public:
-  StringInterpolateNode(intptr_t token_pos, ArrayNode* value)
+  StringInterpolateNode(TokenPosition token_pos, ArrayNode* value)
       : AstNode(token_pos), value_(value) { }
 
   virtual void VisitChildren(AstNodeVisitor* visitor) const {
@@ -425,7 +434,7 @@
 
 class LiteralNode : public AstNode {
  public:
-  LiteralNode(intptr_t token_pos, const Instance& literal)
+  LiteralNode(TokenPosition token_pos, const Instance& literal)
       : AstNode(token_pos), literal_(literal) {
     ASSERT(literal_.IsNotTemporaryScopedHandle());
     ASSERT(literal_.IsSmi() || literal_.IsOld());
@@ -461,7 +470,7 @@
 
 class TypeNode : public AstNode {
  public:
-  TypeNode(intptr_t token_pos, const AbstractType& type)
+  TypeNode(TokenPosition token_pos, const AbstractType& type)
       : AstNode(token_pos), type_(type) {
     ASSERT(type_.IsZoneHandle());
     ASSERT(!type_.IsNull());
@@ -496,7 +505,7 @@
 
 class AssignableNode : public AstNode {
  public:
-  AssignableNode(intptr_t token_pos,
+  AssignableNode(TokenPosition token_pos,
                  AstNode* expr,
                  const AbstractType& type,
                  const String& dst_name)
@@ -529,7 +538,7 @@
 
 class ClosureNode : public AstNode {
  public:
-  ClosureNode(intptr_t token_pos,
+  ClosureNode(TokenPosition token_pos,
               const Function& function,
               AstNode* receiver,  // Non-null for implicit instance closures.
               LocalScope* scope)  // Null for implicit closures.
@@ -581,7 +590,7 @@
 // field access nodes.
 class PrimaryNode : public AstNode {
  public:
-  PrimaryNode(intptr_t token_pos, const Object& primary)
+  PrimaryNode(TokenPosition token_pos, const Object& primary)
       : AstNode(token_pos),
         primary_(primary),
         is_deferred_reference_(false) {
@@ -627,13 +636,13 @@
   };
 
   // Return from a void function returns the null object.
-  explicit ReturnNode(intptr_t token_pos)
+  explicit ReturnNode(TokenPosition token_pos)
       : AstNode(token_pos),
         value_(new LiteralNode(token_pos, Instance::ZoneHandle())),
         inlined_finally_list_(),
         return_type_(kRegular) { }
   // Return from a non-void function.
-  ReturnNode(intptr_t token_pos,
+  ReturnNode(TokenPosition token_pos,
              AstNode* value)
       : AstNode(token_pos),
         value_(value),
@@ -680,7 +689,7 @@
 
 class ComparisonNode : public AstNode {
  public:
-  ComparisonNode(intptr_t token_pos,
+  ComparisonNode(TokenPosition token_pos,
                  Token::Kind kind,
                  AstNode* left,
                  AstNode* right)
@@ -718,7 +727,7 @@
 
 class BinaryOpNode : public AstNode {
  public:
-  BinaryOpNode(intptr_t token_pos,
+  BinaryOpNode(TokenPosition token_pos,
                Token::Kind kind,
                AstNode* left,
                AstNode* right)
@@ -762,7 +771,7 @@
 
 class BinaryOpWithMask32Node : public BinaryOpNode {
  public:
-  BinaryOpWithMask32Node(intptr_t token_pos,
+  BinaryOpWithMask32Node(TokenPosition token_pos,
                          Token::Kind kind_value,
                          AstNode* left,
                          AstNode* right,
@@ -793,10 +802,10 @@
 class UnaryOpNode : public AstNode {
  public:
   // Returns optimized version, e.g., for ('-' '1') ('-1') literal is returned.
-  static AstNode* UnaryOpOrLiteral(intptr_t token_pos,
+  static AstNode* UnaryOpOrLiteral(TokenPosition token_pos,
                                    Token::Kind kind,
                                    AstNode* operand);
-  UnaryOpNode(intptr_t token_pos,
+  UnaryOpNode(TokenPosition token_pos,
               Token::Kind kind,
               AstNode* operand)
       : AstNode(token_pos), kind_(kind), operand_(operand) {
@@ -829,7 +838,7 @@
 
 class ConditionalExprNode : public AstNode {
  public:
-  ConditionalExprNode(intptr_t token_pos,
+  ConditionalExprNode(TokenPosition token_pos,
                       AstNode* condition,
                       AstNode* true_expr,
                       AstNode* false_expr)
@@ -877,7 +886,7 @@
 
 class IfNode : public AstNode {
  public:
-  IfNode(intptr_t token_pos,
+  IfNode(TokenPosition token_pos,
          AstNode* condition,
          SequenceNode* true_branch,
          SequenceNode* false_branch)
@@ -913,7 +922,7 @@
 
 class CaseNode : public AstNode {
  public:
-  CaseNode(intptr_t token_pos,
+  CaseNode(TokenPosition token_pos,
            SourceLabel* label,
            SequenceNode* case_expressions,
            bool contains_default,
@@ -957,7 +966,7 @@
 
 class SwitchNode : public AstNode {
  public:
-  SwitchNode(intptr_t token_pos,
+  SwitchNode(TokenPosition token_pos,
              SourceLabel* label,
              SequenceNode* body)
     : AstNode(token_pos),
@@ -986,7 +995,7 @@
 
 class WhileNode : public AstNode {
  public:
-  WhileNode(intptr_t token_pos,
+  WhileNode(TokenPosition token_pos,
             SourceLabel* label,
             AstNode* condition,
             SequenceNode* condition_preamble,
@@ -1028,7 +1037,7 @@
 
 class DoWhileNode : public AstNode {
  public:
-  DoWhileNode(intptr_t token_pos,
+  DoWhileNode(TokenPosition token_pos,
               SourceLabel* label,
               AstNode* condition,
               SequenceNode* body)
@@ -1064,7 +1073,7 @@
 // The condition can be NULL.
 class ForNode : public AstNode {
  public:
-  ForNode(intptr_t token_pos,
+  ForNode(TokenPosition token_pos,
           SourceLabel* label,
           SequenceNode* initializer,
           AstNode* condition,
@@ -1120,7 +1129,7 @@
 
 class JumpNode : public AstNode {
  public:
-  JumpNode(intptr_t token_pos,
+  JumpNode(TokenPosition token_pos,
            Token::Kind kind,
            SourceLabel* label)
     : AstNode(token_pos),
@@ -1161,7 +1170,7 @@
 
 class StopNode : public AstNode {
  public:
-  StopNode(intptr_t token_pos, const char* message)
+  StopNode(TokenPosition token_pos, const char* message)
       : AstNode(token_pos),
         message_(message) {
     ASSERT(message != NULL);
@@ -1182,7 +1191,7 @@
 
 class LoadLocalNode : public AstNode {
  public:
-  LoadLocalNode(intptr_t token_pos, const LocalVariable* local)
+  LoadLocalNode(TokenPosition token_pos, const LocalVariable* local)
       : AstNode(token_pos), local_(*local) {
     ASSERT(local != NULL);
   }
@@ -1206,7 +1215,9 @@
 
 class StoreLocalNode : public AstNode {
  public:
-  StoreLocalNode(intptr_t token_pos, const LocalVariable* local, AstNode* value)
+  StoreLocalNode(TokenPosition token_pos,
+                 const LocalVariable* local,
+                 AstNode* value)
       : AstNode(token_pos),  local_(*local), value_(value) {
     ASSERT(local != NULL);
     ASSERT(value_ != NULL);
@@ -1231,10 +1242,11 @@
 
 class LoadInstanceFieldNode : public AstNode {
  public:
-  LoadInstanceFieldNode(intptr_t token_pos,
+  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());
   }
@@ -1258,13 +1270,13 @@
 
 class StoreInstanceFieldNode : public AstNode {
  public:
-  StoreInstanceFieldNode(intptr_t token_pos,
+  StoreInstanceFieldNode(TokenPosition token_pos,
                          AstNode* instance,
                          const Field& field,
                          AstNode* value)
       : AstNode(token_pos),
         instance_(instance),
-        field_(field),
+        field_(*MayCloneField(field)),
         value_(value) {
     ASSERT(instance_ != NULL);
     ASSERT(field_.IsZoneHandle());
@@ -1293,8 +1305,10 @@
 
 class LoadStaticFieldNode : public AstNode {
  public:
-  LoadStaticFieldNode(intptr_t token_pos, const Field& field)
-      : AstNode(token_pos), field_(field), is_deferred_reference_(false) {
+  LoadStaticFieldNode(TokenPosition token_pos, const Field& field)
+      : AstNode(token_pos),
+        field_(*MayCloneField(field)),
+        is_deferred_reference_(false) {
     ASSERT(field_.IsZoneHandle());
   }
 
@@ -1329,8 +1343,12 @@
 
 class StoreStaticFieldNode : public AstNode {
  public:
-  StoreStaticFieldNode(intptr_t token_pos, const Field& field, AstNode* value)
-      : AstNode(token_pos), field_(field), value_(value) {
+  StoreStaticFieldNode(TokenPosition token_pos,
+                       const Field& field,
+                       AstNode* value)
+      : AstNode(token_pos),
+        field_(*MayCloneField(field)),
+        value_(value) {
     ASSERT(field_.IsZoneHandle());
     ASSERT(value_ != NULL);
   }
@@ -1354,7 +1372,7 @@
 
 class LoadIndexedNode : public AstNode {
  public:
-  LoadIndexedNode(intptr_t token_pos,
+  LoadIndexedNode(TokenPosition token_pos,
                   AstNode* array,
                   AstNode* index,
                   const Class& super_class)
@@ -1391,7 +1409,7 @@
 
 class StoreIndexedNode : public AstNode {
  public:
-  StoreIndexedNode(intptr_t token_pos,
+  StoreIndexedNode(TokenPosition token_pos,
                    AstNode* array,
                    AstNode* index,
                    AstNode* value,
@@ -1432,7 +1450,7 @@
 
 class InstanceCallNode : public AstNode {
  public:
-  InstanceCallNode(intptr_t token_pos,
+  InstanceCallNode(TokenPosition token_pos,
                    AstNode* receiver,
                    const String& function_name,
                    ArgumentListNode* arguments,
@@ -1472,7 +1490,7 @@
 
 class InstanceGetterNode : public AstNode {
  public:
-  InstanceGetterNode(intptr_t token_pos,
+  InstanceGetterNode(TokenPosition token_pos,
                      AstNode* receiver,
                      const String& field_name,
                      bool is_conditional = false)
@@ -1511,7 +1529,7 @@
 
 class InstanceSetterNode : public AstNode {
  public:
-  InstanceSetterNode(intptr_t token_pos,
+  InstanceSetterNode(TokenPosition token_pos,
                      AstNode* receiver,
                      const String& field_name,
                      AstNode* value,
@@ -1551,8 +1569,9 @@
 
 class InitStaticFieldNode : public AstNode {
  public:
-  InitStaticFieldNode(intptr_t token_pos, const Field& field)
-      : AstNode(token_pos), field_(field) {
+  InitStaticFieldNode(TokenPosition token_pos, const Field& field)
+      : AstNode(token_pos),
+        field_(*MayCloneField(field)) {
     ASSERT(field_.IsZoneHandle());
   }
 
@@ -1571,7 +1590,7 @@
 
 class StaticGetterNode : public AstNode {
  public:
-  StaticGetterNode(intptr_t token_pos,
+  StaticGetterNode(TokenPosition token_pos,
                    AstNode* receiver,
                    const Class& cls,
                    const String& field_name)
@@ -1628,7 +1647,7 @@
 class StaticSetterNode : public AstNode {
  public:
   // Static setter with resolved setter function.
-  StaticSetterNode(intptr_t token_pos,
+  StaticSetterNode(TokenPosition token_pos,
                    AstNode* receiver,
                    const String& field_name,
                    const Function& function,
@@ -1646,7 +1665,7 @@
   }
 
   // For unresolved setters.
-  StaticSetterNode(intptr_t token_pos,
+  StaticSetterNode(TokenPosition token_pos,
                    AstNode* receiver,
                    const Class& cls,
                    const String& field_name,
@@ -1690,7 +1709,7 @@
 
 class StaticCallNode : public AstNode {
  public:
-  StaticCallNode(intptr_t token_pos,
+  StaticCallNode(TokenPosition token_pos,
                  const Function& function,
                  ArgumentListNode* arguments)
       : AstNode(token_pos),
@@ -1721,7 +1740,7 @@
 
 class ClosureCallNode : public AstNode {
  public:
-  ClosureCallNode(intptr_t token_pos,
+  ClosureCallNode(TokenPosition token_pos,
                   AstNode* closure,
                   ArgumentListNode* arguments)
       : AstNode(token_pos),
@@ -1777,7 +1796,7 @@
 // instantiator_class.
 class ConstructorCallNode : public AstNode {
  public:
-  ConstructorCallNode(intptr_t token_pos,
+  ConstructorCallNode(TokenPosition token_pos,
                       const TypeArguments& type_arguments,
                       const Function& constructor,
                       ArgumentListNode* arguments)
@@ -1814,7 +1833,7 @@
 // The body of a Dart function marked as 'native' consists of this node.
 class NativeBodyNode : public AstNode {
  public:
-  NativeBodyNode(intptr_t token_pos,
+  NativeBodyNode(TokenPosition token_pos,
                  const Function& function,
                  const String& native_c_function_name,
                  LocalScope* scope,
@@ -1855,7 +1874,7 @@
  public:
   static const intptr_t kInvalidTryIndex = -1;
 
-  CatchClauseNode(intptr_t token_pos,
+  CatchClauseNode(TokenPosition token_pos,
                   SequenceNode* catch_block,
                   const Array& handler_types,
                   const LocalVariable* context_var,
@@ -1918,7 +1937,7 @@
 
 class TryCatchNode : public AstNode {
  public:
-  TryCatchNode(intptr_t token_pos,
+  TryCatchNode(TokenPosition token_pos,
                SequenceNode* try_block,
                const LocalVariable* context_var,
                CatchClauseNode* catch_block,
@@ -1971,7 +1990,7 @@
 
 class ThrowNode : public AstNode {
  public:
-  ThrowNode(intptr_t token_pos, AstNode* exception, AstNode* stacktrace)
+  ThrowNode(TokenPosition token_pos, AstNode* exception, AstNode* stacktrace)
       : AstNode(token_pos), exception_(exception), stacktrace_(stacktrace) {
     ASSERT(exception_ != NULL);
   }
@@ -1998,7 +2017,7 @@
 
 class InlinedFinallyNode : public AstNode {
  public:
-  InlinedFinallyNode(intptr_t token_pos,
+  InlinedFinallyNode(TokenPosition token_pos,
                      SequenceNode* finally_block,
                      const LocalVariable* context_var,
                      intptr_t try_index)
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 7cc69d4..e438827 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -10,6 +10,8 @@
 #include "vm/os.h"
 #include "vm/parser.h"
 
+#if !defined(PRODUCT)
+
 namespace dart {
 
 AstPrinter::AstPrinter() : indent_(0) { }
@@ -19,7 +21,7 @@
 
 
 void AstPrinter::VisitGenericAstNode(AstNode* node) {
-  THR_Print("(%s ", node->PrettyName());
+  THR_Print("(%s ", node->Name());
   node->VisitChildren(this);
   THR_Print(")");
 }
@@ -28,11 +30,11 @@
 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(" (%" Pd "-%" Pd ") loop %d",
-              scope->begin_token_pos(),
-              scope->end_token_pos(),
+    THR_Print(" (%s-%s) loop %d",
+              scope->begin_token_pos().ToCString(),
+              scope->end_token_pos().ToCString(),
               scope->loop_level());
     if (scope->HasContextLevel()) {
       THR_Print(" context %d captures %d",
@@ -81,7 +83,7 @@
       kind = "";
       UNREACHABLE();
   }
-  THR_Print("(%s %s", node->PrettyName(), kind);
+  THR_Print("(%s %s", node->Name(), kind);
   node->VisitChildren(this);
   THR_Print(")");
 }
@@ -90,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());
@@ -119,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(),
@@ -135,7 +137,7 @@
 
 
 void AstPrinter::VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node) {
-  VisitGenericFieldNode(node, node->field());
+  VisitGenericFieldNode(node, Field::ZoneHandle(node->field().Original()));
 }
 
 
@@ -166,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());
 }
 
@@ -182,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);
@@ -191,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(")");
 }
@@ -199,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());
 }
@@ -207,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("\")");
@@ -235,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(")");
 }
@@ -252,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);
   }
@@ -278,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 ");
@@ -299,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());
@@ -308,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(")");
@@ -317,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(")");
 }
@@ -325,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);
 }
 
 
@@ -337,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());
 }
 
@@ -370,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());
 }
@@ -379,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);
@@ -388,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(")");
 }
@@ -403,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()));
 }
@@ -415,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) {
@@ -433,7 +432,7 @@
 
 
 void AstPrinter::VisitStopNode(StopNode* node) {
-  THR_Print("(%s %s)", node->PrettyName(), node->message());
+  THR_Print("(%s %s)", node->Name(), node->message());
 }
 
 
@@ -478,9 +477,9 @@
   } else if (var->owner()->function_level() != 0) {
     THR_Print(" lev %d", var->owner()->function_level());
   }
-  THR_Print(" valid %" Pd "-%" Pd ")\n",
-            var->token_pos(),
-            scope->end_token_pos());
+  THR_Print(" valid %s-%s)\n",
+            var->token_pos().ToCString(),
+            scope->end_token_pos().ToCString());
 }
 
 
@@ -551,9 +550,9 @@
         THR_Print(" ctx %d", param->owner()->context_level());
       }
     }
-    THR_Print(" valid %" Pd "-%" Pd ")\n",
-              param->token_pos(),
-              scope->end_token_pos());
+    THR_Print(" valid %s-%s)\n",
+              param->token_pos().ToCString(),
+              scope->end_token_pos().ToCString());
     pos++;
   }
   // Visit remaining non-parameter variables and children scopes.
@@ -575,3 +574,5 @@
 }
 
 }  // namespace dart
+
+#endif  // !defined(PRODUCT)
diff --git a/runtime/vm/ast_printer_test.cc b/runtime/vm/ast_printer_test.cc
index 872d5bb..588d702 100644
--- a/runtime/vm/ast_printer_test.cc
+++ b/runtime/vm/ast_printer_test.cc
@@ -12,8 +12,10 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 TEST_CASE(AstPrinter) {
-  const intptr_t kPos = Scanner::kNoSourcePos;
+  const TokenPosition kPos = TokenPosition::kNoSource;
   LocalVariable* v =
       new LocalVariable(kPos,
                         String::ZoneHandle(Symbols::New("wurscht")),
@@ -36,4 +38,6 @@
   AstPrinter::PrintNode(new UnaryOpNode(kPos, Token::kNEGATE, ll));
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/ast_test.cc b/runtime/vm/ast_test.cc
index 83fea1b..88096e9 100644
--- a/runtime/vm/ast_test.cc
+++ b/runtime/vm/ast_test.cc
@@ -13,10 +13,10 @@
 namespace dart {
 
 TEST_CASE(Ast) {
-  LocalVariable* v = new LocalVariable(Scanner::kNoSourcePos,
+  LocalVariable* v = new LocalVariable(TokenPosition::kNoSource,
                                        String::ZoneHandle(Symbols::New("v")),
                                        Type::ZoneHandle(Type::DynamicType()));
-  AstNode* ll = new LoadLocalNode(Scanner::kNoSourcePos, v);
+  AstNode* ll = new LoadLocalNode(TokenPosition::kNoSource, v);
   EXPECT(ll->IsLoadLocalNode());
   EXPECT(!ll->IsLiteralNode());
   LoadLocalNode* lln = ll->AsLoadLocalNode();
@@ -24,7 +24,7 @@
   v->set_index(1);
   EXPECT_EQ(1, v->index());
 
-  LocalVariable* p = new LocalVariable(Scanner::kNoSourcePos,
+  LocalVariable* p = new LocalVariable(TokenPosition::kNoSource,
                                        String::ZoneHandle(Symbols::New("p")),
                                        Type::ZoneHandle(Type::DynamicType()));
   EXPECT(!p->HasIndex());
@@ -32,28 +32,31 @@
   EXPECT(p->HasIndex());
   EXPECT_EQ(-1, p->index());
 
-  ReturnNode* r = new ReturnNode(Scanner::kNoSourcePos, lln);
+  ReturnNode* r = new ReturnNode(TokenPosition::kNoSource, lln);
   EXPECT_EQ(lln, r->value());
 
-  LiteralNode* l =
-      new LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(3)));
+  LiteralNode* l = new LiteralNode(TokenPosition::kNoSource,
+                                   Smi::ZoneHandle(Smi::New(3)));
   EXPECT(l->literal().IsSmi());
   EXPECT_EQ(Smi::New(3), l->literal().raw());
 
   BinaryOpNode* b =
-      new BinaryOpNode(Scanner::kNoSourcePos, Token::kADD, l, lln);
+      new BinaryOpNode(TokenPosition::kNoSource, Token::kADD, l, lln);
   EXPECT_EQ(Token::kADD, b->kind());
   EXPECT_EQ(l, b->left());
   EXPECT_EQ(lln, b->right());
 
   UnaryOpNode* u =
-      new UnaryOpNode(Scanner::kNoSourcePos, Token::kNEGATE, b);
+      new UnaryOpNode(TokenPosition::kNoSource, Token::kNEGATE, b);
   EXPECT_EQ(Token::kNEGATE, u->kind());
   EXPECT_EQ(b, u->operand());
 
-  SequenceNode* sequence_node = new SequenceNode(1, new LocalScope(NULL, 0, 0));
-  LiteralNode* literal_node = new LiteralNode(2,  Smi::ZoneHandle(Smi::New(3)));
-  ReturnNode* return_node = new ReturnNode(3, literal_node);
+  SequenceNode* sequence_node =
+      new SequenceNode(TokenPosition(1), new LocalScope(NULL, 0, 0));
+  LiteralNode* literal_node =
+      new LiteralNode(TokenPosition(2),  Smi::ZoneHandle(Smi::New(3)));
+  ReturnNode* return_node =
+      new ReturnNode(TokenPosition(3), literal_node);
   sequence_node->Add(return_node);
   GrowableArray<AstNode*> nodes;
   sequence_node->CollectAllNodes(&nodes);
diff --git a/runtime/vm/ast_transformer.cc b/runtime/vm/ast_transformer.cc
index 32ec3f9..4b05867 100644
--- a/runtime/vm/ast_transformer.cc
+++ b/runtime/vm/ast_transformer.cc
@@ -13,6 +13,9 @@
 // Quick access to the current zone.
 #define Z (thread()->zone())
 
+// Quick synthetic token position.
+#define ST(token_pos) ((token_pos).ToSynthetic())
+
 // Nodes that are unreachable from already parsed expressions.
 #define FOR_EACH_UNREACHABLE_NODE(V)                                           \
   V(AwaitMarker)                                                               \
@@ -71,7 +74,7 @@
   if (await_tmp == NULL) {
     // We need a new temp variable; add it to the function's top scope.
     await_tmp = new (Z) LocalVariable(
-        Scanner::kNoSourcePos, symbol, Object::dynamic_type());
+        TokenPosition::kNoSource, symbol, Object::dynamic_type());
     async_temp_scope_->AddVariable(await_tmp);
     // After adding it to the top scope, we can look it up from the preamble.
     // The following call includes an ASSERT check.
@@ -89,9 +92,12 @@
 }
 
 
-LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(AstNode* node) {
+LocalVariable* AwaitTransformer::AddToPreambleNewTempVar(
+    AstNode* node,
+    TokenPosition token_pos) {
   LocalVariable* tmp_var = EnsureCurrentTempVar();
-  preamble_->Add(new(Z) StoreLocalNode(Scanner::kNoSourcePos, tmp_var, node));
+  ASSERT(token_pos.IsSynthetic() || token_pos.IsNoSource());
+  preamble_->Add(new(Z) StoreLocalNode(token_pos, tmp_var, node));
   NextTempVar();
   return tmp_var;
 }
@@ -119,7 +125,7 @@
   //   :saved_try_ctx_var = :await_saved_try_ctx_var_y;
   //   :await_temp_var_(X+1) = :result_param;
 
-  const intptr_t token_pos = node->token_pos();
+  const TokenPosition token_pos = ST(node->token_pos());
   LocalVariable* async_op = GetVariableInScope(
       preamble_->scope(), Symbols::AsyncOperation());
   LocalVariable* async_then_callback = GetVariableInScope(
@@ -134,7 +140,8 @@
       preamble_->scope(), Symbols::AsyncOperationStackTraceParam());
 
   AstNode* transformed_expr = Transform(node->expr());
-  LocalVariable* await_temp = AddToPreambleNewTempVar(transformed_expr);
+  LocalVariable* await_temp = AddToPreambleNewTempVar(transformed_expr,
+                                                      ST(node->token_pos()));
 
   AwaitMarkerNode* await_marker =
       new (Z) AwaitMarkerNode(async_temp_scope_, node->scope(), token_pos);
@@ -146,23 +153,23 @@
   const Function& async_await_helper = Function::ZoneHandle(
       Z, async_lib.LookupFunctionAllowPrivate(Symbols::AsyncAwaitHelper()));
   ASSERT(!async_await_helper.IsNull());
-  ArgumentListNode* async_await_helper_args = new (Z) ArgumentListNode(
-      Scanner::kNoSourcePos);
+  ArgumentListNode* async_await_helper_args =
+      new (Z) ArgumentListNode(token_pos);
   async_await_helper_args->Add(
-      new(Z) LoadLocalNode(Scanner::kNoSourcePos, await_temp));
+      new(Z) LoadLocalNode(token_pos, await_temp));
   async_await_helper_args->Add(
-      new(Z) LoadLocalNode(Scanner::kNoSourcePos, async_then_callback));
+      new(Z) LoadLocalNode(token_pos, async_then_callback));
   async_await_helper_args->Add(
-      new(Z) LoadLocalNode(Scanner::kNoSourcePos, async_catch_error_callback));
+      new(Z) LoadLocalNode(token_pos, async_catch_error_callback));
   StaticCallNode* await_helper_call = new (Z) StaticCallNode(
       node->token_pos(),
       async_await_helper,
       async_await_helper_args);
 
   preamble_->Add(new(Z) StoreLocalNode(
-      Scanner::kNoSourcePos, result_param, await_helper_call));
+      token_pos, result_param, await_helper_call));
 
-  ReturnNode* continuation_return = new(Z) ReturnNode(Scanner::kNoSourcePos);
+  ReturnNode* continuation_return = new(Z) ReturnNode(token_pos);
   continuation_return->set_return_type(ReturnNode::kContinuationTarget);
   preamble_->Add(continuation_return);
 
@@ -171,15 +178,15 @@
   // saved try context of the outer try block.
   if (node->saved_try_ctx() != NULL) {
     preamble_->Add(new (Z) StoreLocalNode(
-        Scanner::kNoSourcePos,
+        token_pos,
         node->saved_try_ctx(),
-        new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+        new (Z) LoadLocalNode(token_pos,
                               node->async_saved_try_ctx())));
     if (node->outer_saved_try_ctx() != NULL) {
       preamble_->Add(new (Z) StoreLocalNode(
-          Scanner::kNoSourcePos,
+          token_pos,
           node->outer_saved_try_ctx(),
-          new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+          new (Z) LoadLocalNode(token_pos,
                                 node->outer_async_saved_try_ctx())));
     }
   } else {
@@ -188,34 +195,33 @@
 
   // Load the async_op variable. It is unused, but the observatory uses it
   // to determine if a breakpoint is inside an asynchronous function.
-  LoadLocalNode* load_async_op = new (Z) LoadLocalNode(
-      Scanner::kNoSourcePos, async_op);
+  LoadLocalNode* load_async_op = new (Z) LoadLocalNode(token_pos, async_op);
   preamble_->Add(load_async_op);
 
   LoadLocalNode* load_error_param = new (Z) LoadLocalNode(
-      Scanner::kNoSourcePos, error_param);
+      token_pos, error_param);
   LoadLocalNode* load_stack_trace_param = new (Z) LoadLocalNode(
-      Scanner::kNoSourcePos, stack_trace_param);
+      token_pos, stack_trace_param);
   SequenceNode* error_ne_null_branch = new (Z) SequenceNode(
-      Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
+      token_pos, ChainNewScope(preamble_->scope()));
   error_ne_null_branch->Add(new (Z) ThrowNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       load_error_param,
       load_stack_trace_param));
   preamble_->Add(new (Z) IfNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       new (Z) ComparisonNode(
-          Scanner::kNoSourcePos,
+          token_pos,
           Token::kNE,
           load_error_param,
-          new (Z) LiteralNode(Scanner::kNoSourcePos,
+          new (Z) LiteralNode(token_pos,
                               Object::null_instance())),
           error_ne_null_branch,
           NULL));
 
   LocalVariable* result = AddToPreambleNewTempVar(new(Z) LoadLocalNode(
-      Scanner::kNoSourcePos, result_param));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+      token_pos, result_param), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(token_pos, result);
 }
 
 
@@ -242,18 +248,18 @@
   const Token::Kind compare_logical_op = (logical_op == Token::kAND) ?
       Token::kEQ : Token::kNE;
   SequenceNode* eval = new (Z) SequenceNode(
-      Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
+      ST(new_left->token_pos()), ChainNewScope(preamble_->scope()));
   SequenceNode* saved_preamble = preamble_;
   preamble_ = eval;
   result = Transform(right);
   preamble_ = saved_preamble;
   IfNode* right_body = new(Z) IfNode(
-      Scanner::kNoSourcePos,
+      ST(new_left->token_pos()),
       new(Z) ComparisonNode(
-          Scanner::kNoSourcePos,
+          ST(new_left->token_pos()),
           compare_logical_op,
           new_left,
-          new(Z) LiteralNode(Scanner::kNoSourcePos, Bool::True())),
+          new(Z) LiteralNode(ST(new_left->token_pos()), Bool::True())),
       eval,
       NULL);
   preamble_->Add(right_body);
@@ -280,8 +286,8 @@
       new(Z) BinaryOpNode(node->token_pos(),
                           node->kind(),
                           new_left,
-                          new_right));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                          new_right), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -295,8 +301,8 @@
                                     node->kind(),
                                     new_left,
                                     new_right,
-                                    node->mask32()));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                                    node->mask32()), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -307,16 +313,17 @@
       new(Z) ComparisonNode(node->token_pos(),
                             node->kind(),
                             new_left,
-                            new_right));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                            new_right), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
 void AwaitTransformer::VisitUnaryOpNode(UnaryOpNode* node) {
   AstNode* new_operand = Transform(node->operand());
   LocalVariable* result = AddToPreambleNewTempVar(
-      new(Z) UnaryOpNode(node->token_pos(), node->kind(), new_operand));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+      new(Z) UnaryOpNode(node->token_pos(), node->kind(), new_operand),
+      ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -325,26 +332,26 @@
 void AwaitTransformer::VisitConditionalExprNode(ConditionalExprNode* node) {
   AstNode* new_condition = Transform(node->condition());
   SequenceNode* new_true = new (Z) SequenceNode(
-      Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
+      ST(node->true_expr()->token_pos()), ChainNewScope(preamble_->scope()));
   SequenceNode* saved_preamble = preamble_;
   preamble_ = new_true;
   AstNode* new_true_result = Transform(node->true_expr());
   SequenceNode* new_false = new (Z) SequenceNode(
-      Scanner::kNoSourcePos, ChainNewScope(preamble_->scope()));
+      ST(node->false_expr()->token_pos()), ChainNewScope(preamble_->scope()));
   preamble_ = new_false;
   AstNode* new_false_result = Transform(node->false_expr());
   preamble_ = saved_preamble;
-  IfNode* new_if = new(Z) IfNode(Scanner::kNoSourcePos,
+  IfNode* new_if = new(Z) IfNode(ST(node->token_pos()),
                                  new_condition,
                                  new_true,
                                  new_false);
   preamble_->Add(new_if);
   LocalVariable* result = AddToPreambleNewTempVar(
-      new(Z) ConditionalExprNode(Scanner::kNoSourcePos,
+      new(Z) ConditionalExprNode(ST(node->token_pos()),
                                  new_condition,
                                  new_true_result,
-                                 new_false_result));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                                 new_false_result), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -371,8 +378,8 @@
   ArrayNode* new_value = Transform(node->value())->AsArrayNode();
   LocalVariable* result = AddToPreambleNewTempVar(
       new(Z) StringInterpolateNode(node->token_pos(),
-                                   new_value));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                                   new_value), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -385,8 +392,8 @@
       new(Z) ClosureNode(node->token_pos(),
                          node->function(),
                          new_receiver,
-                         node->scope()));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                         node->scope()), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -399,8 +406,8 @@
                               new_receiver,
                               node->function_name(),
                               new_args,
-                              node->is_conditional()));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                              node->is_conditional()), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -410,8 +417,8 @@
   LocalVariable* result = AddToPreambleNewTempVar(
       new(Z) StaticCallNode(node->token_pos(),
                             node->function(),
-                            new_args));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                            new_args), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -422,8 +429,8 @@
       new(Z) ConstructorCallNode(node->token_pos(),
                                  node->type_arguments(),
                                  node->constructor(),
-                                 new_args));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                                 new_args), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -433,8 +440,8 @@
       new(Z) InstanceGetterNode(node->token_pos(),
                                 new_receiver,
                                 node->field_name(),
-                                node->is_conditional()));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                                node->is_conditional()), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -449,8 +456,8 @@
                                 new_receiver,
                                 node->field_name(),
                                 new_value,
-                                node->is_conditional()));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                                node->is_conditional()), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -465,8 +472,9 @@
                               node->cls(),
                               node->field_name());
   new_getter->set_owner(node->owner());
-  LocalVariable* result = AddToPreambleNewTempVar(new_getter);
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+  LocalVariable* result =
+      AddToPreambleNewTempVar(new_getter, ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -489,8 +497,9 @@
                                 node->function(),
                                 new_value);
 
-  LocalVariable* result = AddToPreambleNewTempVar(new_setter);
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+  LocalVariable* result =
+      AddToPreambleNewTempVar(new_setter, ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -512,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);
 }
 
 
@@ -525,8 +535,8 @@
       new(Z) LoadIndexedNode(node->token_pos(),
                              new_array,
                              new_index,
-                             node->super_class()));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                             node->super_class()), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -539,8 +549,8 @@
                               new_array,
                               new_index,
                               new_value,
-                              node->super_class()));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                              node->super_class()), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -550,8 +560,8 @@
       new(Z) AssignableNode(node->token_pos(),
                             new_expr,
                             node->type(),
-                            node->dst_name()));
-  result_ = new(Z) LoadLocalNode(Scanner::kNoSourcePos, result);
+                            node->dst_name()), ST(node->token_pos()));
+  result_ = new(Z) LoadLocalNode(ST(node->token_pos()), result);
 }
 
 
@@ -565,8 +575,8 @@
     async_temp_scope_->AddVariable(node->TempAt(i));
     AstNode* new_init_val = Transform(node->InitializerAt(i));
     preamble_->Add(new(Z) StoreLocalNode(node->token_pos(),
-                   node->TempAt(i),
-                   new_init_val));
+                                         node->TempAt(i),
+                                         new_init_val));
   }
 
   // Add all expressions but the last to the preamble. We must do
diff --git a/runtime/vm/ast_transformer.h b/runtime/vm/ast_transformer.h
index e9f6791..5930f41 100644
--- a/runtime/vm/ast_transformer.h
+++ b/runtime/vm/ast_transformer.h
@@ -51,7 +51,8 @@
 
  private:
   LocalVariable* EnsureCurrentTempVar();
-  LocalVariable* AddToPreambleNewTempVar(AstNode* node);
+  LocalVariable* AddToPreambleNewTempVar(AstNode* node,
+                                         TokenPosition token_pos);
   ArgumentListNode* TransformArguments(ArgumentListNode* node);
   AstNode* LazyTransform(const Token::Kind kind,
                          AstNode* new_left,
diff --git a/runtime/vm/atomic.h b/runtime/vm/atomic.h
index 809548a..bd489d0 100644
--- a/runtime/vm/atomic.h
+++ b/runtime/vm/atomic.h
@@ -18,16 +18,28 @@
   // Returns the original value at p.
   //
   // NOTE: Not to be used for any atomic operations involving memory locations
-  // that are accessed by generated code
+  // that are accessed by generated code.
   static uintptr_t FetchAndIncrement(uintptr_t* p);
 
+  // Atomically increment the value at p by 'value'.
+  //
+  // NOTE: Not to be used for any atomic operations involving memory locations
+  // that are accessed by generated code.
+  static void IncrementBy(intptr_t* p, intptr_t value);
+
   // Atomically fetch the value at p and decrement the value at p.
   // Returns the original value at p.
   //
   // NOTE: Not to be used for any atomic operations involving memory locations
-  // that are accessed by generated code
+  // that are accessed by generated code.
   static uintptr_t FetchAndDecrement(uintptr_t* p);
 
+  // Atomically decrement the value at p by 'value'.
+  //
+  // NOTE: Not to be used for any atomic operations involving memory locations
+  // that are accessed by generated code.
+  static void DecrementBy(intptr_t* p, intptr_t value);
+
   // Atomically compare *ptr to old_value, and if equal, store new_value.
   // Returns the original value at ptr.
   //
diff --git a/runtime/vm/atomic_android.h b/runtime/vm/atomic_android.h
index 8d01ae7..c3727af 100644
--- a/runtime/vm/atomic_android.h
+++ b/runtime/vm/atomic_android.h
@@ -21,11 +21,21 @@
 }
 
 
+inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_add(p, value);
+}
+
+
 inline uintptr_t AtomicOperations::FetchAndDecrement(uintptr_t* p) {
   return __sync_fetch_and_sub(p, 1);
 }
 
 
+inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_sub(p, value);
+}
+
+
 #if !defined(USING_SIMULATOR)
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
diff --git a/runtime/vm/atomic_linux.h b/runtime/vm/atomic_linux.h
index 1150857..15f0396 100644
--- a/runtime/vm/atomic_linux.h
+++ b/runtime/vm/atomic_linux.h
@@ -21,11 +21,21 @@
 }
 
 
+inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_add(p, value);
+}
+
+
 inline uintptr_t AtomicOperations::FetchAndDecrement(uintptr_t* p) {
   return __sync_fetch_and_sub(p, 1);
 }
 
 
+inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_sub(p, value);
+}
+
+
 #if !defined(USING_SIMULATOR)
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
diff --git a/runtime/vm/atomic_macos.h b/runtime/vm/atomic_macos.h
index 31d219b..fd5af87 100644
--- a/runtime/vm/atomic_macos.h
+++ b/runtime/vm/atomic_macos.h
@@ -21,11 +21,21 @@
 }
 
 
+inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_add(p, value);
+}
+
+
 inline uintptr_t AtomicOperations::FetchAndDecrement(uintptr_t* p) {
   return __sync_fetch_and_sub(p, 1);
 }
 
 
+inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
+  __sync_fetch_and_sub(p, value);
+}
+
+
 #if !defined(USING_SIMULATOR)
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
diff --git a/runtime/vm/atomic_test.cc b/runtime/vm/atomic_test.cc
index 2e327a5..6973d8b 100644
--- a/runtime/vm/atomic_test.cc
+++ b/runtime/vm/atomic_test.cc
@@ -26,6 +26,20 @@
 }
 
 
+UNIT_TEST_CASE(IncrementBy) {
+  intptr_t v = 42;
+  AtomicOperations::IncrementBy(&v, 100);
+  EXPECT_EQ(static_cast<intptr_t>(142), v);
+}
+
+
+UNIT_TEST_CASE(DecrementBy) {
+  intptr_t v = 42;
+  AtomicOperations::DecrementBy(&v, 41);
+  EXPECT_EQ(static_cast<intptr_t>(1), v);
+}
+
+
 UNIT_TEST_CASE(LoadRelaxed) {
   uword v = 42;
   EXPECT_EQ(static_cast<uword>(42), AtomicOperations::LoadRelaxed(&v));
diff --git a/runtime/vm/atomic_win.h b/runtime/vm/atomic_win.h
index 8e07cd3..1563035 100644
--- a/runtime/vm/atomic_win.h
+++ b/runtime/vm/atomic_win.h
@@ -28,6 +28,19 @@
 }
 
 
+inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
+#if defined(HOST_ARCH_X64)
+  InterlockedExchangeAdd64(reinterpret_cast<LONGLONG*>(p),
+                           static_cast<LONGLONG>(value));
+#elif defined(HOST_ARCH_IA32)
+  InterlockedExchangeAdd(reinterpret_cast<LONG*>(p),
+                         static_cast<LONG>(value));
+#else
+#error Unsupported host architecture.
+#endif
+}
+
+
 inline uintptr_t AtomicOperations::FetchAndDecrement(uintptr_t* p) {
 #if defined(HOST_ARCH_X64)
   return static_cast<uintptr_t>(
@@ -41,6 +54,19 @@
 }
 
 
+inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
+#if defined(HOST_ARCH_X64)
+  InterlockedExchangeAdd64(reinterpret_cast<LONGLONG*>(p),
+                           static_cast<LONGLONG>(-value));
+#elif defined(HOST_ARCH_IA32)
+  InterlockedExchangeAdd(reinterpret_cast<LONG*>(p),
+                         static_cast<LONG>(-value));
+#else
+#error Unsupported host architecture.
+#endif
+}
+
+
 #if !defined(USING_SIMULATOR)
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index dc2fcdf..1c59f8d 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -6,6 +6,7 @@
 
 #include "bin/builtin.h"
 #include "bin/file.h"
+#include "bin/isolate_data.h"
 
 #include "platform/assert.h"
 #include "platform/globals.h"
@@ -23,6 +24,73 @@
 Benchmark* Benchmark::tail_ = NULL;
 const char* Benchmark::executable_ = NULL;
 
+
+//
+// Measure compile of all dart2js(compiler) functions.
+//
+static char* ComputeDart2JSPath(const char* arg) {
+  char buffer[2048];
+  char* dart2js_path = strdup(File::GetCanonicalPath(arg));
+  const char* compiler_path =
+      "%s%spkg%scompiler%slib%scompiler.dart";
+  const char* path_separator = File::PathSeparator();
+  ASSERT(path_separator != NULL && strlen(path_separator) == 1);
+  char* ptr = strrchr(dart2js_path, *path_separator);
+  while (ptr != NULL) {
+    *ptr = '\0';
+    OS::SNPrint(buffer, 2048, compiler_path,
+                dart2js_path,
+                path_separator,
+                path_separator,
+                path_separator,
+                path_separator,
+                path_separator);
+    if (File::Exists(buffer)) {
+      break;
+    }
+    ptr = strrchr(dart2js_path, *path_separator);
+  }
+  if (ptr == NULL) {
+    free(dart2js_path);
+    dart2js_path = NULL;
+  }
+  return dart2js_path;
+}
+
+
+static void func(Dart_NativeArguments args) {
+}
+
+
+static Dart_NativeFunction NativeResolver(Dart_Handle name,
+                                          int arg_count,
+                                          bool* auto_setup_scope) {
+  ASSERT(auto_setup_scope != NULL);
+  *auto_setup_scope = false;
+  return &func;
+}
+
+
+static void SetupDart2JSPackagePath() {
+  bool worked = bin::DartUtils::SetOriginalWorkingDirectory();
+  EXPECT(worked);
+
+  Dart_Handle result = bin::DartUtils::PrepareForScriptLoading(false, false);
+  DART_CHECK_VALID(result);
+
+  // Setup package root.
+  char buffer[2048];
+  char* executable_path =
+      strdup(File::GetCanonicalPath(Benchmark::Executable()));
+  const char* packages_path = "%s%s..%spackages";
+  const char* path_separator = File::PathSeparator();
+  OS::SNPrint(buffer, 2048, packages_path,
+              executable_path, path_separator, path_separator);
+  result = bin::DartUtils::SetupPackageRoot(buffer, NULL);
+  DART_CHECK_VALID(result);
+}
+
+
 void Benchmark::RunAll(const char* executable) {
   SetExecutable(executable);
   Benchmark* benchmark = first_;
@@ -33,12 +101,23 @@
 }
 
 
+Dart_Isolate Benchmark::CreateIsolate(const uint8_t* buffer) {
+  bin::IsolateData* isolate_data = new bin::IsolateData(NULL, NULL, NULL);
+  char* err = NULL;
+  isolate_ = Dart_CreateIsolate(NULL, NULL, buffer, NULL, isolate_data, &err);
+  EXPECT(isolate_ != NULL);
+  free(err);
+  return isolate_;
+}
+
+
 //
 // Measure compile of all functions in dart core lib classes.
 //
 BENCHMARK(CorelibCompileAll) {
   bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
   bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
+  TransitionNativeToVM transition(thread);
   Timer timer(true, "Compile all of Core lib benchmark");
   timer.Start();
   const Error& error = Error::Handle(Library::CompileAll());
@@ -52,9 +131,13 @@
 }
 
 
+#ifndef PRODUCT
+
+
 BENCHMARK(CorelibCompilerStats) {
   bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
   bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
+  TransitionNativeToVM transition(thread);
   CompilerStats* stats = thread->isolate()->compiler_stats();
   ASSERT(stats != NULL);
   stats->EnableBenchmark();
@@ -71,6 +154,52 @@
 }
 
 
+BENCHMARK(Dart2JSCompilerStats) {
+  bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
+  bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
+  SetupDart2JSPackagePath();
+  char* dart_root = ComputeDart2JSPath(Benchmark::Executable());
+  char* script = NULL;
+  if (dart_root != NULL) {
+    HANDLESCOPE(thread);
+    script = OS::SCreate(NULL,
+        "import '%s/pkg/compiler/lib/compiler.dart';", dart_root);
+    Dart_Handle lib = TestCase::LoadTestScript(
+        script,
+        reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
+    EXPECT_VALID(lib);
+  } else {
+    Dart_Handle lib = TestCase::LoadTestScript(
+        "import 'pkg/compiler/lib/compiler.dart';",
+        reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
+    EXPECT_VALID(lib);
+  }
+  CompilerStats* stats = thread->isolate()->compiler_stats();
+  ASSERT(stats != NULL);
+  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();
+  benchmark->set_score(elapsed_time);
+  free(dart_root);
+  free(script);
+}
+
+
+#endif  // !PRODUCT
+
+
 //
 // Measure creation of core isolate from a snapshot.
 //
@@ -78,7 +207,7 @@
   const int kNumIterations = 1000;
   Timer timer(true, "CorelibIsolateStartup");
   Isolate* isolate = thread->isolate();
-  Thread::ExitIsolate();
+  Dart_ExitIsolate();
   for (int i = 0; i < kNumIterations; i++) {
     timer.Start();
     TestCase::CreateTestIsolate();
@@ -86,7 +215,7 @@
     Dart_ShutdownIsolate();
   }
   benchmark->set_score(timer.TotalElapsedTime() / kNumIterations);
-  Thread::EnterIsolate(isolate);
+  Dart_EnterIsolate(reinterpret_cast<Dart_Isolate>(isolate));
 }
 
 
@@ -142,7 +271,7 @@
                                          int argument_count,
                                          bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   const char* cstr = NULL;
   Dart_Handle result = Dart_StringToCString(name, &cstr);
   EXPECT_VALID(result);
@@ -239,131 +368,6 @@
 }
 
 
-//
-// Measure compile of all dart2js(compiler) functions.
-//
-static char* ComputeDart2JSPath(const char* arg) {
-  char buffer[2048];
-  char* dart2js_path = strdup(File::GetCanonicalPath(arg));
-  const char* compiler_path =
-      "%s%spkg%scompiler%slib%scompiler.dart";
-  const char* path_separator = File::PathSeparator();
-  ASSERT(path_separator != NULL && strlen(path_separator) == 1);
-  char* ptr = strrchr(dart2js_path, *path_separator);
-  while (ptr != NULL) {
-    *ptr = '\0';
-    OS::SNPrint(buffer, 2048, compiler_path,
-                dart2js_path,
-                path_separator,
-                path_separator,
-                path_separator,
-                path_separator,
-                path_separator);
-    if (File::Exists(buffer)) {
-      break;
-    }
-    ptr = strrchr(dart2js_path, *path_separator);
-  }
-  if (ptr == NULL) {
-    free(dart2js_path);
-    dart2js_path = NULL;
-  }
-  return dart2js_path;
-}
-
-
-static void func(Dart_NativeArguments args) {
-}
-
-
-// Emulates DartUtils::PrepareForScriptLoading.
-static Dart_Handle PreparePackageRoot(const char* package_root,
-                                      Dart_Handle builtin_lib) {
-  // First ensure all required libraries are available.
-  Dart_Handle url = NewString(bin::DartUtils::kCoreLibURL);
-  DART_CHECK_VALID(url);
-  Dart_Handle core_lib = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(core_lib);
-  url = NewString(bin::DartUtils::kAsyncLibURL);
-  DART_CHECK_VALID(url);
-  Dart_Handle async_lib = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(async_lib);
-  url = NewString(bin::DartUtils::kIsolateLibURL);
-  DART_CHECK_VALID(url);
-  Dart_Handle isolate_lib = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(isolate_lib);
-  url = NewString(bin::DartUtils::kInternalLibURL);
-  DART_CHECK_VALID(url);
-  Dart_Handle internal_lib = Dart_LookupLibrary(url);
-  DART_CHECK_VALID(internal_lib);
-  Dart_Handle io_lib =
-      bin::Builtin::LoadAndCheckLibrary(bin::Builtin::kIOLibrary);
-  DART_CHECK_VALID(io_lib);
-
-  // We need to ensure that all the scripts loaded so far are finalized
-  // as we are about to invoke some Dart code below to setup closures.
-  Dart_Handle result = Dart_FinalizeLoading(false);
-  DART_CHECK_VALID(result);
-
-  // Necessary parts from PrepareBuiltinLibrary.
-  // Setup the internal library's 'internalPrint' function.
-  result = Dart_Invoke(builtin_lib, NewString("_getPrintClosure"), 0, NULL);
-  DART_CHECK_VALID(result);
-  result = Dart_SetField(internal_lib, NewString("_printClosure"), result);
-  DART_CHECK_VALID(result);
-#if defined(TARGET_OS_WINDOWS)
-    result = Dart_SetField(builtin_lib, NewString("_isWindows"), Dart_True());
-    DART_CHECK_VALID(result);
-#endif  // defined(TARGET_OS_WINDOWS)
-  // Set current working directory.
-  result = bin::DartUtils::SetWorkingDirectory(builtin_lib);
-  DART_CHECK_VALID(result);
-  // Set the package root for builtin.dart.
-  result = NewString(package_root);
-  DART_CHECK_VALID(result);
-  const int kNumArgs = 1;
-  Dart_Handle dart_args[kNumArgs];
-  dart_args[0] = result;
-  result = Dart_Invoke(builtin_lib,
-                       NewString("_setPackageRoot"),
-                       kNumArgs,
-                       dart_args);
-  DART_CHECK_VALID(result);
-
-  bin::DartUtils::PrepareAsyncLibrary(async_lib, isolate_lib);
-  bin::DartUtils::PrepareCoreLibrary(core_lib, builtin_lib, false);
-  bin::DartUtils::PrepareIsolateLibrary(isolate_lib);
-  bin::DartUtils::PrepareIOLibrary(io_lib);
-  return Dart_True();
-}
-
-
-static Dart_NativeFunction NativeResolver(Dart_Handle name,
-                                          int arg_count,
-                                          bool* auto_setup_scope) {
-  ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
-  return &func;
-}
-
-static void SetupDart2JSPackagePath() {
-  Dart_Handle builtin_lib =
-      bin::Builtin::LoadAndCheckLibrary(bin::Builtin::kBuiltinLibrary);
-  DART_CHECK_VALID(builtin_lib);
-
-  bool worked = bin::DartUtils::SetOriginalWorkingDirectory();
-  EXPECT(worked);
-  char buffer[2048];
-  char* executable_path =
-      strdup(File::GetCanonicalPath(Benchmark::Executable()));
-  const char* packages_path = "%s%s..%spackages";
-  const char* path_separator = File::PathSeparator();
-  OS::SNPrint(buffer, 2048, packages_path,
-              executable_path, path_separator, path_separator);
-  Dart_Handle result = PreparePackageRoot(buffer, builtin_lib);
-  DART_CHECK_VALID(result);
-}
-
 BENCHMARK(Dart2JSCompileAll) {
   bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
   bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
@@ -386,42 +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();
-  EXPECT_VALID(result);
-  timer.Stop();
-  int64_t elapsed_time = timer.TotalElapsedTime();
-  benchmark->set_score(elapsed_time);
-  free(dart_root);
-  free(script);
-}
-
-
-BENCHMARK(Dart2JSCompilerStats) {
-  bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
-  bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
-  SetupDart2JSPackagePath();
-  char* dart_root = ComputeDart2JSPath(Benchmark::Executable());
-  char* script = NULL;
-  if (dart_root != NULL) {
-    HANDLESCOPE(thread);
-    script = OS::SCreate(NULL,
-        "import '%s/pkg/compiler/lib/compiler.dart';", dart_root);
-    Dart_Handle lib = TestCase::LoadTestScript(
-        script,
-        reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
-    EXPECT_VALID(lib);
-  } else {
-    Dart_Handle lib = TestCase::LoadTestScript(
-        "import 'pkg/compiler/lib/compiler.dart';",
-        reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
-    EXPECT_VALID(lib);
-  }
-  CompilerStats* stats = thread->isolate()->compiler_stats();
-  ASSERT(stats != NULL);
-  stats->EnableBenchmark();
-  Timer timer(true, "Compile all of dart2js benchmark");
-  timer.Start();
-  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();
@@ -693,6 +669,7 @@
 
 
 BENCHMARK(SimpleMessage) {
+  TransitionNativeToVM transition(thread);
   const Array& array_object = Array::Handle(Array::New(2));
   array_object.SetAt(0, Integer::Handle(Smi::New(42)));
   array_object.SetAt(1, Object::Handle());
diff --git a/runtime/vm/benchmark_test.h b/runtime/vm/benchmark_test.h
index 615965c..357fde6b 100644
--- a/runtime/vm/benchmark_test.h
+++ b/runtime/vm/benchmark_test.h
@@ -81,13 +81,7 @@
   int64_t score() const { return score_; }
   Isolate* isolate() const { return reinterpret_cast<Isolate*>(isolate_); }
 
-  Dart_Isolate CreateIsolate(const uint8_t* buffer) {
-    char* err = NULL;
-    isolate_ = Dart_CreateIsolate(NULL, NULL, buffer, NULL, NULL, &err);
-    EXPECT(isolate_ != NULL);
-    free(err);
-    return isolate_;
-  }
+  Dart_Isolate CreateIsolate(const uint8_t* buffer);
 
   void Run() { (*run_)(this); }
   void RunBenchmark();
diff --git a/runtime/vm/bitfield.h b/runtime/vm/bitfield.h
index 6108065..42a121a 100644
--- a/runtime/vm/bitfield.h
+++ b/runtime/vm/bitfield.h
@@ -9,26 +9,26 @@
 
 static const uword kUwordOne = 1U;
 
-// BitField is a template for encoding and decoding a bit field inside
-// an unsigned machine word.
-template<typename T, int position, int size>
+// BitField is a template for encoding and decoding a value of type T
+// inside a storage of type S.
+template<typename S, typename T, int position, int size>
 class BitField {
  public:
   static const intptr_t kNextBit = position + size;
 
   // Tells whether the provided value fits into the bit field.
   static bool is_valid(T value) {
-    return (static_cast<uword>(value) & ~((kUwordOne << size) - 1)) == 0;
+    return (static_cast<S>(value) & ~((kUwordOne << size) - 1)) == 0;
   }
 
-  // Returns a uword mask of the bit field.
-  static uword mask() {
+  // Returns a S mask of the bit field.
+  static S mask() {
     return (kUwordOne << size) - 1;
   }
 
-  // Returns a uword mask of the bit field which can be applied directly to
+  // Returns a S mask of the bit field which can be applied directly to
   // to the raw unshifted bits.
-  static uword mask_in_place() {
+  static S mask_in_place() {
     return ((kUwordOne << size) - 1) << position;
   }
 
@@ -43,23 +43,24 @@
     return size;
   }
 
-  // Returns a uword with the bit field value encoded.
-  static uword encode(T value) {
+  // Returns an S with the bit field value encoded.
+  static S encode(T value) {
+    COMPILE_ASSERT((sizeof(S) * kBitsPerByte) >= (position + size));
     ASSERT(is_valid(value));
-    return static_cast<uword>(value) << position;
+    return static_cast<S>(value) << position;
   }
 
   // Extracts the bit field from the value.
-  static T decode(uword value) {
+  static T decode(S value) {
     return static_cast<T>((value >> position) & ((kUwordOne << size) - 1));
   }
 
-  // Returns a uword with the bit field value encoded based on the
+  // Returns an S with the bit field value encoded based on the
   // original value. Only the bits corresponding to this bit field
   // will be changed.
-  static uword update(T value, uword original) {
+  static S update(T value, S original) {
     ASSERT(is_valid(value));
-    return (static_cast<uword>(value) << position) |
+    return (static_cast<S>(value) << position) |
         (~mask_in_place() & original);
   }
 };
diff --git a/runtime/vm/bitfield_test.cc b/runtime/vm/bitfield_test.cc
index 7728b29..a9d41c9 100644
--- a/runtime/vm/bitfield_test.cc
+++ b/runtime/vm/bitfield_test.cc
@@ -10,7 +10,7 @@
 namespace dart {
 
 UNIT_TEST_CASE(BitFields) {
-  class TestBitFields : public BitField<int32_t, 1, 8> {};
+  class TestBitFields : public BitField<uword, int32_t, 1, 8> {};
   EXPECT(TestBitFields::is_valid(16));
   EXPECT(!TestBitFields::is_valid(256));
   EXPECT_EQ(0x00ffU, TestBitFields::mask());
diff --git a/runtime/vm/block_scheduler.cc b/runtime/vm/block_scheduler.cc
index a84a5d9..5b3d78d 100644
--- a/runtime/vm/block_scheduler.cc
+++ b/runtime/vm/block_scheduler.cc
@@ -6,12 +6,11 @@
 
 #include "vm/allocation.h"
 #include "vm/code_patcher.h"
+#include "vm/compiler.h"
 #include "vm/flow_graph.h"
 
 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.
@@ -60,6 +59,11 @@
 
   const Array& ic_data_array = Array::Handle(flow_graph()->zone(),
       flow_graph()->parsed_function().function().ic_data_array());
+  if (Compiler::IsBackgroundCompilation() && ic_data_array.IsNull()) {
+    // Deferred loading cleared ic_data_array.
+    Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
+  }
+  ASSERT(!ic_data_array.IsNull());
   Array& edge_counters = Array::Handle();
   edge_counters ^= ic_data_array.At(0);
 
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 7596920..8cb5d77 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -209,6 +209,9 @@
                                               Dart_Handle uri) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
+  // This handler calls into the VM directly and does not use the Dart
+  // API so we transition back to VM.
+  TransitionNativeToVM transition(thread);
   if (!Dart_IsLibrary(library)) {
     return Api::NewError("not a library");
   }
@@ -292,6 +295,11 @@
   for (intptr_t i = 0;
        bootstrap_libraries[i].index_ != ObjectStore::kNone;
        ++i) {
+#ifdef PRODUCT
+    if (bootstrap_libraries[i].index_ == ObjectStore::kMirrors) {
+      continue;
+    }
+#endif  // !PRODUCT
     uri = Symbols::New(bootstrap_libraries[i].uri_);
     lib = Library::LookupLibrary(uri);
     if (lib.IsNull()) {
@@ -307,6 +315,11 @@
   for (intptr_t i = 0;
        bootstrap_libraries[i].index_ != ObjectStore::kNone;
        ++i) {
+#ifdef PRODUCT
+    if (bootstrap_libraries[i].index_ == ObjectStore::kMirrors) {
+      continue;
+    }
+#endif  // PRODUCT
     uri = Symbols::New(bootstrap_libraries[i].uri_);
     lib = Library::LookupLibrary(uri);
     ASSERT(!lib.IsNull());
@@ -339,13 +352,11 @@
     SetupNativeResolver();
     ClassFinalizer::ProcessPendingClasses();
 
-    Class& cls = Class::Handle(zone);
-    // Eagerly compile the function implementation class as it is the super
-    // class of signature classes. This allows us to just finalize signature
-    // classes without going through the hoops of trying to compile them.
-    const Type& type =
-        Type::Handle(zone, isolate->object_store()->function_impl_type());
-    cls = type.type_class();
+    // Eagerly compile the _Closure class as it is the class of all closure
+    // instances. This allows us to just finalize function types
+    // without going through the hoops of trying to compile their scope class.
+    const Class& cls =
+        Class::Handle(zone, isolate->object_store()->closure_class());
     Compiler::CompileClass(cls);
   }
 
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index d0bef86..7e1ea34 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -28,6 +28,9 @@
   int argument_count_;
 } BootStrapEntries[] = {
   BOOTSTRAP_NATIVE_LIST(REGISTER_NATIVE_ENTRY)
+#ifndef PRODUCT
+  MIRRORS_BOOTSTRAP_NATIVE_LIST(REGISTER_NATIVE_ENTRY)
+#endif  // !PRODUCT
 };
 
 
@@ -116,10 +119,11 @@
   library.set_native_entry_resolver(resolver);
   library.set_native_entry_symbol_resolver(symbol_resolver);
 
+NOT_IN_PRODUCT(
   library = Library::MirrorsLibrary();
   ASSERT(!library.IsNull());
   library.set_native_entry_resolver(resolver);
-  library.set_native_entry_symbol_resolver(symbol_resolver);
+  library.set_native_entry_symbol_resolver(symbol_resolver));
 
   library = Library::ProfilerLibrary();
   ASSERT(!library.IsNull());
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 8803755..02b1e3c 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -28,9 +28,9 @@
   V(Object_instanceOfString, 2)                                                \
   V(Object_as, 3)                                                              \
   V(Function_apply, 2)                                                         \
-  V(FunctionImpl_equals, 2)                                                    \
-  V(FunctionImpl_hashCode, 1)                                                  \
-  V(FunctionImpl_clone, 1)                                                     \
+  V(Closure_equals, 2)                                                         \
+  V(Closure_hashCode, 1)                                                       \
+  V(Closure_clone, 1)                                                          \
   V(AbstractType_toString, 1)                                                  \
   V(Identical_comparison, 2)                                                   \
   V(Integer_bitAndFromInteger, 2)                                              \
@@ -316,6 +316,55 @@
   V(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0)                         \
   V(Isolate_getCurrentRootUriStr, 0)                                           \
   V(Isolate_sendOOB, 2)                                                        \
+  V(GrowableList_allocate, 2)                                                  \
+  V(GrowableList_getIndexed, 2)                                                \
+  V(GrowableList_setIndexed, 3)                                                \
+  V(GrowableList_getLength, 1)                                                 \
+  V(GrowableList_getCapacity, 1)                                               \
+  V(GrowableList_setLength, 2)                                                 \
+  V(GrowableList_setData, 2)                                                   \
+  V(Internal_makeListFixedLength, 1)                                           \
+  V(Internal_makeFixedListUnmodifiable, 1)                                     \
+  V(Internal_inquireIs64Bit, 0)                                                \
+  V(LinkedHashMap_allocate, 1)                                                 \
+  V(LinkedHashMap_getIndex, 1)                                                 \
+  V(LinkedHashMap_setIndex, 2)                                                 \
+  V(LinkedHashMap_getData, 1)                                                  \
+  V(LinkedHashMap_setData, 2)                                                  \
+  V(LinkedHashMap_getHashMask, 1)                                              \
+  V(LinkedHashMap_setHashMask, 2)                                              \
+  V(LinkedHashMap_getUsedData, 1)                                              \
+  V(LinkedHashMap_setUsedData, 2)                                              \
+  V(LinkedHashMap_getDeletedKeys, 1)                                           \
+  V(LinkedHashMap_setDeletedKeys, 2)                                           \
+  V(WeakProperty_new, 2)                                                       \
+  V(WeakProperty_getKey, 1)                                                    \
+  V(WeakProperty_getValue, 1)                                                  \
+  V(WeakProperty_setValue, 2)                                                  \
+  V(Uri_isWindowsPlatform, 0)                                                  \
+  V(LibraryPrefix_load, 1)                                                     \
+  V(LibraryPrefix_invalidateDependentCode, 1)                                  \
+  V(LibraryPrefix_loadError, 1)                                                \
+  V(LibraryPrefix_isLoaded, 1)                                                 \
+  V(UserTag_new, 2)                                                            \
+  V(UserTag_label, 1)                                                          \
+  V(UserTag_defaultTag, 0)                                                     \
+  V(UserTag_makeCurrent, 1)                                                    \
+  V(Profiler_getCurrentTag, 0)                                                 \
+  V(ClassID_getID, 1)                                                          \
+  V(Num_toString, 1)                                                           \
+  V(VMService_SendIsolateServiceMessage, 2)                                    \
+  V(VMService_SendRootServiceMessage, 1)                                       \
+  V(VMService_OnStart, 0)                                                      \
+  V(VMService_OnExit, 0)                                                       \
+  V(VMService_OnServerAddressChange, 1)                                        \
+  V(VMService_ListenStream, 1)                                                 \
+  V(VMService_CancelStream, 1)                                                 \
+  V(VMService_RequestAssets, 0)                                                \
+  V(VMService_DecodeAssets, 1)                                                 \
+
+// List of bootstrap native entry points used in the dart:mirror library.
+#define MIRRORS_BOOTSTRAP_NATIVE_LIST(V)                                       \
   V(Mirrors_evalInLibraryWithPrivateKey, 2)                                    \
   V(Mirrors_makeLocalClassMirror, 1)                                           \
   V(Mirrors_makeLocalTypeMirror, 1)                                            \
@@ -365,51 +414,6 @@
   V(TypedefMirror_referent, 1)                                                 \
   V(TypedefMirror_declaration, 1)                                              \
   V(VariableMirror_type, 2)                                                    \
-  V(GrowableList_allocate, 2)                                                  \
-  V(GrowableList_getIndexed, 2)                                                \
-  V(GrowableList_setIndexed, 3)                                                \
-  V(GrowableList_getLength, 1)                                                 \
-  V(GrowableList_getCapacity, 1)                                               \
-  V(GrowableList_setLength, 2)                                                 \
-  V(GrowableList_setData, 2)                                                   \
-  V(Internal_makeListFixedLength, 1)                                           \
-  V(Internal_makeFixedListUnmodifiable, 1)                                     \
-  V(Internal_inquireIs64Bit, 0)                                                \
-  V(LinkedHashMap_allocate, 1)                                                 \
-  V(LinkedHashMap_getIndex, 1)                                                 \
-  V(LinkedHashMap_setIndex, 2)                                                 \
-  V(LinkedHashMap_getData, 1)                                                  \
-  V(LinkedHashMap_setData, 2)                                                  \
-  V(LinkedHashMap_getHashMask, 1)                                              \
-  V(LinkedHashMap_setHashMask, 2)                                              \
-  V(LinkedHashMap_getUsedData, 1)                                              \
-  V(LinkedHashMap_setUsedData, 2)                                              \
-  V(LinkedHashMap_getDeletedKeys, 1)                                           \
-  V(LinkedHashMap_setDeletedKeys, 2)                                           \
-  V(WeakProperty_new, 2)                                                       \
-  V(WeakProperty_getKey, 1)                                                    \
-  V(WeakProperty_getValue, 1)                                                  \
-  V(WeakProperty_setValue, 2)                                                  \
-  V(Uri_isWindowsPlatform, 0)                                                  \
-  V(LibraryPrefix_load, 1)                                                     \
-  V(LibraryPrefix_invalidateDependentCode, 1)                                  \
-  V(LibraryPrefix_loadError, 1)                                                \
-  V(LibraryPrefix_isLoaded, 1)                                                 \
-  V(UserTag_new, 2)                                                            \
-  V(UserTag_label, 1)                                                          \
-  V(UserTag_defaultTag, 0)                                                     \
-  V(UserTag_makeCurrent, 1)                                                    \
-  V(Profiler_getCurrentTag, 0)                                                 \
-  V(ClassID_getID, 1)                                                          \
-  V(Num_toString, 1)                                                           \
-  V(VMService_SendIsolateServiceMessage, 2)                                    \
-  V(VMService_SendRootServiceMessage, 1)                                       \
-  V(VMService_OnStart, 0)                                                      \
-  V(VMService_OnExit, 0)                                                       \
-  V(VMService_ListenStream, 1)                                                 \
-  V(VMService_CancelStream, 1)                                                 \
-  V(VMService_RequestAssets, 0)                                                \
-  V(VMService_DecodeAssets, 1)                                                 \
 
 class BootstrapNatives : public AllStatic {
  public:
@@ -423,6 +427,9 @@
   static void DN_##name(Dart_NativeArguments args);
 
   BOOTSTRAP_NATIVE_LIST(DECLARE_BOOTSTRAP_NATIVE)
+#ifndef PRODUCT
+  MIRRORS_BOOTSTRAP_NATIVE_LIST(DECLARE_BOOTSTRAP_NATIVE)
+#endif
 
 #undef DECLARE_BOOTSTRAP_NATIVE
 };
diff --git a/runtime/vm/branch_optimizer.cc b/runtime/vm/branch_optimizer.cc
new file mode 100644
index 0000000..b34baf7
--- /dev/null
+++ b/runtime/vm/branch_optimizer.cc
@@ -0,0 +1,355 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/branch_optimizer.h"
+
+#include "vm/flow_graph.h"
+#include "vm/intermediate_language.h"
+
+namespace dart {
+
+// Returns true if the given phi has a single input use and
+// is used in the environments either at the corresponding block entry or
+// at the same instruction where input use is.
+static bool PhiHasSingleUse(PhiInstr* phi, Value* use) {
+  if ((use->next_use() != NULL) || (phi->input_use_list() != use)) {
+    return false;
+  }
+
+  BlockEntryInstr* block = phi->block();
+  for (Value* env_use = phi->env_use_list();
+       env_use != NULL;
+       env_use = env_use->next_use()) {
+    if ((env_use->instruction() != block) &&
+        (env_use->instruction() != use->instruction())) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+bool BranchSimplifier::Match(JoinEntryInstr* block) {
+  // Match the pattern of a branch on a comparison whose left operand is a
+  // phi from the same block, and whose right operand is a constant.
+  //
+  //   Branch(Comparison(kind, Phi, Constant))
+  //
+  // These are the branches produced by inlining in a test context.  Also,
+  // the phi has no other uses so they can simply be eliminated.  The block
+  // has no other phis and no instructions intervening between the phi and
+  // branch so the block can simply be eliminated.
+  BranchInstr* branch = block->last_instruction()->AsBranch();
+  ASSERT(branch != NULL);
+  ComparisonInstr* comparison = branch->comparison();
+  Value* left = comparison->left();
+  PhiInstr* phi = left->definition()->AsPhi();
+  Value* right = comparison->right();
+  ConstantInstr* constant =
+      (right == NULL) ? NULL : right->definition()->AsConstant();
+  return (phi != NULL) &&
+      (constant != NULL) &&
+      (phi->GetBlock() == block) &&
+      PhiHasSingleUse(phi, left) &&
+      (block->next() == branch) &&
+      (block->phis()->length() == 1);
+}
+
+
+JoinEntryInstr* BranchSimplifier::ToJoinEntry(Zone* zone,
+                                              TargetEntryInstr* target) {
+  // Convert a target block into a join block.  Branches will be duplicated
+  // so the former true and false targets become joins of the control flows
+  // from all the duplicated branches.
+  JoinEntryInstr* join =
+      new(zone) JoinEntryInstr(target->block_id(), target->try_index());
+  join->InheritDeoptTarget(zone, target);
+  join->LinkTo(target->next());
+  join->set_last_instruction(target->last_instruction());
+  target->UnuseAllInputs();
+  return join;
+}
+
+
+BranchInstr* BranchSimplifier::CloneBranch(Zone* zone,
+                                           BranchInstr* branch,
+                                           Value* new_left,
+                                           Value* new_right) {
+  ComparisonInstr* comparison = branch->comparison();
+  ComparisonInstr* new_comparison =
+      comparison->CopyWithNewOperands(new_left, new_right);
+  BranchInstr* new_branch = new(zone) BranchInstr(new_comparison);
+  new_branch->set_is_checked(branch->is_checked());
+  return new_branch;
+}
+
+
+void BranchSimplifier::Simplify(FlowGraph* flow_graph) {
+  // Optimize some branches that test the value of a phi.  When it is safe
+  // to do so, push the branch to each of the predecessor blocks.  This is
+  // an optimization when (a) it can avoid materializing a boolean object at
+  // the phi only to test its value, and (b) it can expose opportunities for
+  // constant propagation and unreachable code elimination.  This
+  // optimization is intended to run after inlining which creates
+  // opportunities for optimization (a) and before constant folding which
+  // can perform optimization (b).
+
+  // Begin with a worklist of join blocks ending in branches.  They are
+  // candidates for the pattern below.
+  Zone* zone = flow_graph->zone();
+  const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder();
+  GrowableArray<BlockEntryInstr*> worklist(postorder.length());
+  for (BlockIterator it(postorder); !it.Done(); it.Advance()) {
+    BlockEntryInstr* block = it.Current();
+    if (block->IsJoinEntry() && block->last_instruction()->IsBranch()) {
+      worklist.Add(block);
+    }
+  }
+
+  // Rewrite until no more instance of the pattern exists.
+  bool changed = false;
+  while (!worklist.is_empty()) {
+    // All blocks in the worklist are join blocks (ending with a branch).
+    JoinEntryInstr* block = worklist.RemoveLast()->AsJoinEntry();
+    ASSERT(block != NULL);
+
+    if (Match(block)) {
+      changed = true;
+
+      // The branch will be copied and pushed to all the join's
+      // predecessors.  Convert the true and false target blocks into join
+      // blocks to join the control flows from all of the true
+      // (respectively, false) targets of the copied branches.
+      //
+      // The converted join block will have no phis, so it cannot be another
+      // instance of the pattern.  There is thus no need to add it to the
+      // worklist.
+      BranchInstr* branch = block->last_instruction()->AsBranch();
+      ASSERT(branch != NULL);
+      JoinEntryInstr* join_true =
+          ToJoinEntry(zone, branch->true_successor());
+      JoinEntryInstr* join_false =
+          ToJoinEntry(zone, branch->false_successor());
+
+      ComparisonInstr* comparison = branch->comparison();
+      PhiInstr* phi = comparison->left()->definition()->AsPhi();
+      ConstantInstr* constant = comparison->right()->definition()->AsConstant();
+      ASSERT(constant != NULL);
+      // Copy the constant and branch and push it to all the predecessors.
+      for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) {
+        GotoInstr* old_goto =
+            block->PredecessorAt(i)->last_instruction()->AsGoto();
+        ASSERT(old_goto != NULL);
+
+        // Replace the goto in each predecessor with a rewritten branch,
+        // rewritten to use the corresponding phi input instead of the phi.
+        Value* new_left = phi->InputAt(i)->Copy(zone);
+        Value* new_right = new(zone) Value(constant);
+        BranchInstr* new_branch =
+            CloneBranch(zone, branch, new_left, new_right);
+        if (branch->env() == NULL) {
+          new_branch->InheritDeoptTarget(zone, old_goto);
+        } else {
+          // Take the environment from the branch if it has one.
+          new_branch->InheritDeoptTarget(zone, branch);
+          // InheritDeoptTarget gave the new branch's comparison the same
+          // deopt id that it gave the new branch.  The id should be the
+          // deopt id of the original comparison.
+          new_branch->comparison()->SetDeoptId(*comparison);
+          // The phi can be used in the branch's environment.  Rename such
+          // uses.
+          for (Environment::DeepIterator it(new_branch->env());
+               !it.Done();
+               it.Advance()) {
+            Value* use = it.CurrentValue();
+            if (use->definition() == phi) {
+              Definition* replacement = phi->InputAt(i)->definition();
+              use->RemoveFromUseList();
+              use->set_definition(replacement);
+              replacement->AddEnvUse(use);
+            }
+          }
+        }
+
+        new_branch->InsertBefore(old_goto);
+        new_branch->set_next(NULL);  // Detaching the goto from the graph.
+        old_goto->UnuseAllInputs();
+
+        // Update the predecessor block.  We may have created another
+        // instance of the pattern so add it to the worklist if necessary.
+        BlockEntryInstr* branch_block = new_branch->GetBlock();
+        branch_block->set_last_instruction(new_branch);
+        if (branch_block->IsJoinEntry()) worklist.Add(branch_block);
+
+        // Connect the branch to the true and false joins, via empty target
+        // blocks.
+        TargetEntryInstr* true_target =
+            new(zone) TargetEntryInstr(flow_graph->max_block_id() + 1,
+                                          block->try_index());
+        true_target->InheritDeoptTarget(zone, join_true);
+        TargetEntryInstr* false_target =
+            new(zone) TargetEntryInstr(flow_graph->max_block_id() + 2,
+                                          block->try_index());
+        false_target->InheritDeoptTarget(zone, join_false);
+        flow_graph->set_max_block_id(flow_graph->max_block_id() + 2);
+        *new_branch->true_successor_address() = true_target;
+        *new_branch->false_successor_address() = false_target;
+        GotoInstr* goto_true = new(zone) GotoInstr(join_true);
+        goto_true->InheritDeoptTarget(zone, join_true);
+        true_target->LinkTo(goto_true);
+        true_target->set_last_instruction(goto_true);
+        GotoInstr* goto_false = new(zone) GotoInstr(join_false);
+        goto_false->InheritDeoptTarget(zone, join_false);
+        false_target->LinkTo(goto_false);
+        false_target->set_last_instruction(goto_false);
+      }
+      // When all predecessors have been rewritten, the original block is
+      // unreachable from the graph.
+      phi->UnuseAllInputs();
+      branch->UnuseAllInputs();
+      block->UnuseAllInputs();
+      ASSERT(!phi->HasUses());
+    }
+  }
+
+  if (changed) {
+    // We may have changed the block order and the dominator tree.
+    flow_graph->DiscoverBlocks();
+    GrowableArray<BitVector*> dominance_frontier;
+    flow_graph->ComputeDominators(&dominance_frontier);
+  }
+}
+
+
+static bool IsTrivialBlock(BlockEntryInstr* block, Definition* defn) {
+  return (block->IsTargetEntry() && (block->PredecessorCount() == 1)) &&
+    ((block->next() == block->last_instruction()) ||
+     ((block->next() == defn) && (defn->next() == block->last_instruction())));
+}
+
+
+static void EliminateTrivialBlock(BlockEntryInstr* block,
+                                  Definition* instr,
+                                  IfThenElseInstr* before) {
+  block->UnuseAllInputs();
+  block->last_instruction()->UnuseAllInputs();
+
+  if ((block->next() == instr) &&
+      (instr->next() == block->last_instruction())) {
+    before->previous()->LinkTo(instr);
+    instr->LinkTo(before);
+  }
+}
+
+
+void IfConverter::Simplify(FlowGraph* flow_graph) {
+  Zone* zone = flow_graph->zone();
+  bool changed = false;
+
+  const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder();
+  for (BlockIterator it(postorder); !it.Done(); it.Advance()) {
+    BlockEntryInstr* block = it.Current();
+    JoinEntryInstr* join = block->AsJoinEntry();
+
+    // Detect diamond control flow pattern which materializes a value depending
+    // on the result of the comparison:
+    //
+    // B_pred:
+    //   ...
+    //   Branch if COMP goto (B_pred1, B_pred2)
+    // B_pred1: -- trivial block that contains at most one definition
+    //   v1 = Constant(...)
+    //   goto B_block
+    // B_pred2: -- trivial block that contains at most one definition
+    //   v2 = Constant(...)
+    //   goto B_block
+    // B_block:
+    //   v3 = phi(v1, v2) -- single phi
+    //
+    // and replace it with
+    //
+    // Ba:
+    //   v3 = IfThenElse(COMP ? v1 : v2)
+    //
+    if ((join != NULL) &&
+        (join->phis() != NULL) &&
+        (join->phis()->length() == 1) &&
+        (block->PredecessorCount() == 2)) {
+      BlockEntryInstr* pred1 = block->PredecessorAt(0);
+      BlockEntryInstr* pred2 = block->PredecessorAt(1);
+
+      PhiInstr* phi = (*join->phis())[0];
+      Value* v1 = phi->InputAt(0);
+      Value* v2 = phi->InputAt(1);
+
+      if (IsTrivialBlock(pred1, v1->definition()) &&
+          IsTrivialBlock(pred2, v2->definition()) &&
+          (pred1->PredecessorAt(0) == pred2->PredecessorAt(0))) {
+        BlockEntryInstr* pred = pred1->PredecessorAt(0);
+        BranchInstr* branch = pred->last_instruction()->AsBranch();
+        ComparisonInstr* comparison = branch->comparison();
+
+        // Check if the platform supports efficient branchless IfThenElseInstr
+        // for the given combination of comparison and values flowing from
+        // false and true paths.
+        if (IfThenElseInstr::Supports(comparison, v1, v2)) {
+          Value* if_true = (pred1 == branch->true_successor()) ? v1 : v2;
+          Value* if_false = (pred2 == branch->true_successor()) ? v1 : v2;
+
+          ComparisonInstr* new_comparison =
+              comparison->CopyWithNewOperands(
+                  comparison->left()->Copy(zone),
+                  comparison->right()->Copy(zone));
+          IfThenElseInstr* if_then_else = new(zone) IfThenElseInstr(
+              new_comparison,
+              if_true->Copy(zone),
+              if_false->Copy(zone));
+          flow_graph->InsertBefore(branch,
+                                   if_then_else,
+                                   NULL,
+                                   FlowGraph::kValue);
+
+          phi->ReplaceUsesWith(if_then_else);
+
+          // Connect IfThenElseInstr to the first instruction in the merge block
+          // effectively eliminating diamond control flow.
+          // Current block as well as pred1 and pred2 blocks are no longer in
+          // the graph at this point.
+          if_then_else->LinkTo(join->next());
+          pred->set_last_instruction(join->last_instruction());
+
+          // Resulting block must inherit block id from the eliminated current
+          // block to guarantee that ordering of phi operands in its successor
+          // stays consistent.
+          pred->set_block_id(block->block_id());
+
+          // If v1 and v2 were defined inside eliminated blocks pred1/pred2
+          // move them out to the place before inserted IfThenElse instruction.
+          EliminateTrivialBlock(pred1, v1->definition(), if_then_else);
+          EliminateTrivialBlock(pred2, v2->definition(), if_then_else);
+
+          // Update use lists to reflect changes in the graph.
+          phi->UnuseAllInputs();
+          branch->UnuseAllInputs();
+          block->UnuseAllInputs();
+
+          // The graph has changed. Recompute dominators and block orders after
+          // this pass is finished.
+          changed = true;
+        }
+      }
+    }
+  }
+
+  if (changed) {
+    // We may have changed the block order and the dominator tree.
+    flow_graph->DiscoverBlocks();
+    GrowableArray<BitVector*> dominance_frontier;
+    flow_graph->ComputeDominators(&dominance_frontier);
+  }
+}
+
+
+}  // namespace dart
diff --git a/runtime/vm/branch_optimizer.h b/runtime/vm/branch_optimizer.h
new file mode 100644
index 0000000..2e2b135
--- /dev/null
+++ b/runtime/vm/branch_optimizer.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_BRANCH_OPTIMIZER_H_
+#define VM_BRANCH_OPTIMIZER_H_
+
+#include "vm/allocation.h"
+
+namespace dart {
+
+class FlowGraph;
+class JoinEntryInstr;
+class Zone;
+class TargetEntryInstr;
+class Value;
+class BranchInstr;
+
+// Rewrite branches to eliminate materialization of boolean values after
+// inlining, and to expose other optimizations (e.g., constant folding of
+// branches, unreachable code elimination).
+class BranchSimplifier : public AllStatic {
+ public:
+  static void Simplify(FlowGraph* flow_graph);
+
+  // Replace a target entry instruction with a join entry instruction.  Does
+  // not update the original target's predecessors to point to the new block
+  // and does not replace the target in already computed block order lists.
+  static JoinEntryInstr* ToJoinEntry(Zone* zone,
+                                     TargetEntryInstr* target);
+
+ private:
+  // Match an instance of the pattern to rewrite.  See the implementation
+  // for the patterns that are handled by this pass.
+  static bool Match(JoinEntryInstr* block);
+
+  // Duplicate a branch while replacing its comparison's left and right
+  // inputs.
+  static BranchInstr* CloneBranch(Zone* zone,
+                                  BranchInstr* branch,
+                                  Value* new_left,
+                                  Value* new_right);
+};
+
+
+// Rewrite diamond control flow patterns that materialize values to use more
+// efficient branchless code patterns if such are supported on the current
+// platform.
+class IfConverter : public AllStatic {
+ public:
+  static void Simplify(FlowGraph* flow_graph);
+};
+
+}  // namespace dart
+
+#endif  // VM_BRANCH_OPTIMIZER_H_
diff --git a/runtime/vm/cha.cc b/runtime/vm/cha.cc
index 667d598..ed5255e 100644
--- a/runtime/vm/cha.cc
+++ b/runtime/vm/cha.cc
@@ -49,8 +49,8 @@
 
 
 bool CHA::IsImplemented(const Class& cls) {
-  // Signature classes have different type checking rules.
-  ASSERT(!cls.IsSignatureClass());
+  // Function type aliases have different type checking rules.
+  ASSERT(!cls.IsTypedefClass());
   // Can't track dependencies for classes on the VM heap since those are
   // read-only.
   // TODO(fschneider): Enable tracking of CHA dependent code for VM heap
diff --git a/runtime/vm/cha_test.cc b/runtime/vm/cha_test.cc
index a7c998d..7712324 100644
--- a/runtime/vm/cha_test.cc
+++ b/runtime/vm/cha_test.cc
@@ -98,10 +98,9 @@
   EXPECT(ContainsCid(cha.leaf_classes(), class_c.id()));
   EXPECT(ContainsCid(cha.leaf_classes(), class_d.id()));
 
-  const Class& function_impl_class =
-      Class::Handle(Type::Handle(Isolate::Current()->object_store()->
-          function_impl_type()).type_class());
-  EXPECT(cha.HasSubclasses(function_impl_class.id()));
+  const Class& closure_class =
+      Class::Handle(Isolate::Current()->object_store()->closure_class());
+  EXPECT(!cha.HasSubclasses(closure_class.id()));
 }
 
 }  // namespace dart
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 8ef3511..d1e9f5b 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -11,15 +11,14 @@
 #include "vm/longjump.h"
 #include "vm/log.h"
 #include "vm/object_store.h"
-#include "vm/report.h"
 #include "vm/symbols.h"
 
 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.");
-DECLARE_FLAG(bool, use_cha_deopt);
 
 
 bool ClassFinalizer::AllClassesFinalized() {
@@ -123,8 +122,7 @@
   ASSERT(isolate != NULL);
   HANDLESCOPE(thread);
   ObjectStore* object_store = isolate->object_store();
-  const Error& error =
-      Error::Handle(thread->zone(), object_store->sticky_error());
+  const Error& error = Error::Handle(thread->zone(), thread->sticky_error());
   if (!error.IsNull()) {
     return false;
   }
@@ -242,7 +240,7 @@
   // by Object::Init().
   if (!ProcessPendingClasses()) {
     // TODO(srdjan): Exit like a real VM instead.
-    const Error& err = Error::Handle(object_store->sticky_error());
+    const Error& err = Error::Handle(Thread::Current()->sticky_error());
     OS::PrintErr("Could not verify bootstrap classes : %s\n",
                  err.ToErrorCString());
     OS::Exit(255);
@@ -392,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)) {
@@ -440,7 +438,8 @@
     if (!target_type.IsInstantiated()) {
       const TypeArguments& type_args = TypeArguments::Handle(type.arguments());
       Error& bound_error = Error::Handle();
-      target_type ^= target_type.InstantiateFrom(type_args, &bound_error);
+      target_type ^= target_type.InstantiateFrom(
+          type_args, &bound_error, NULL, NULL, Heap::kOld);
       if (bound_error.IsNull()) {
         target_type ^= FinalizeType(cls, target_type, kCanonicalize);
       } else {
@@ -457,10 +456,10 @@
 }
 
 
-void ClassFinalizer::ResolveTypeClass(const Class& cls,
-                                      const AbstractType& type) {
-  if (type.IsFinalized() || type.HasResolvedTypeClass()) {
-    return;
+RawAbstractType* ClassFinalizer::ResolveTypeClass(const Class& cls,
+                                                  const Type& type) {
+  if (type.IsFinalized()) {
+    return type.raw();
   }
   if (FLAG_trace_type_finalization) {
     THR_Print("Resolve type class of '%s'\n",
@@ -473,55 +472,83 @@
   // that the type parameter appeared in a static scope. Leaving the type as
   // unresolved is the correct thing to do.
 
-  // Lookup the type class.
-  const UnresolvedClass& unresolved_class =
-      UnresolvedClass::Handle(type.unresolved_class());
-  const Class& type_class =
-      Class::Handle(ResolveClass(cls, unresolved_class));
-
-  // Replace unresolved class with resolved type class.
-  const Type& parameterized_type = Type::Cast(type);
-  if (type_class.IsNull()) {
-    // The type class could not be resolved. The type is malformed.
-    FinalizeMalformedType(
-        Error::Handle(),  // No previous error.
-        Script::Handle(cls.script()),
-        parameterized_type,
-        "cannot resolve class '%s' from '%s'",
-        String::Handle(unresolved_class.Name()).ToCString(),
-        String::Handle(cls.Name()).ToCString());
-    return;
+  // Lookup the type class if necessary.
+  Class& type_class = Class::Handle();
+  if (type.HasResolvedTypeClass()) {
+    type_class = type.type_class();
+  } else {
+    const UnresolvedClass& unresolved_class =
+        UnresolvedClass::Handle(type.unresolved_class());
+    type_class = ResolveClass(cls, unresolved_class);
+    if (type_class.IsNull()) {
+      // The type class could not be resolved. The type is malformed.
+      FinalizeMalformedType(
+          Error::Handle(),  // No previous error.
+          Script::Handle(cls.script()),
+          type,
+          "cannot resolve class '%s' from '%s'",
+          String::Handle(unresolved_class.Name()).ToCString(),
+          String::Handle(cls.Name()).ToCString());
+      return type.raw();
+    }
   }
-  parameterized_type.set_type_class(type_class);
+  // Promote the Type to a FunctionType in case its type class is a typedef.
+  if (type_class.IsTypedefClass()) {
+    return FunctionType::New(type_class,
+                             TypeArguments::Handle(type.arguments()),
+                             Function::Handle(type_class.signature_function()),
+                             type.token_pos());
+  }
+  // Replace unresolved class with resolved type class.
+  type.set_type_class(type_class);
+  return type.raw();
 }
 
 
-void ClassFinalizer::ResolveType(const Class& cls, const AbstractType& type) {
+RawAbstractType* ClassFinalizer::ResolveType(const Class& cls,
+                                             const AbstractType& type) {
   if (type.IsResolved()) {
-    return;
+    return type.raw();
   }
-  ASSERT(type.IsType());
   if (FLAG_trace_type_finalization) {
     THR_Print("Resolve type '%s'\n", String::Handle(type.Name()).ToCString());
   }
-  ResolveTypeClass(cls, type);
-  if (type.IsMalformed()) {
-    ASSERT(type.IsResolved());
-    return;
+  AbstractType& resolved_type = AbstractType::Handle();
+  if (type.IsType()) {
+    resolved_type = ResolveTypeClass(cls, Type::Cast(type));
+    if (resolved_type.IsMalformed()) {
+      ASSERT(resolved_type.IsResolved());
+      return resolved_type.raw();
+    }
+  } else {
+    ASSERT(type.IsFunctionType());
+    const Function& signature =
+        Function::Handle(FunctionType::Cast(type).signature());
+    const Class& scope_class =
+        Class::Handle(FunctionType::Cast(type).scope_class());
+    if (scope_class.IsTypedefClass()) {
+      ResolveSignature(scope_class, signature);
+    } else {
+      ResolveSignature(cls, signature);
+    }
+    resolved_type = type.raw();
   }
   // Mark type as resolved before resolving its type arguments in order to avoid
   // repeating resolution of recursive types.
-  Type::Cast(type).set_is_resolved();
+  resolved_type.SetIsResolved();
   // Resolve type arguments, if any.
-  const TypeArguments& arguments = TypeArguments::Handle(type.arguments());
+  const TypeArguments& arguments =
+      TypeArguments::Handle(resolved_type.arguments());
   if (!arguments.IsNull()) {
     const intptr_t num_arguments = arguments.Length();
     AbstractType& type_argument = AbstractType::Handle();
     for (intptr_t i = 0; i < num_arguments; i++) {
       type_argument = arguments.TypeAt(i);
-      ResolveType(cls, type_argument);
+      type_argument = ResolveType(cls, type_argument);
+      arguments.SetTypeAt(i, type_argument);
     }
   }
+  return resolved_type.raw();
 }
 
 
@@ -564,7 +591,7 @@
 // A non-contractive type can be detected by looking at the queue of types
 // pending finalization that are mutually recursive with the checked type.
 void ClassFinalizer::CheckRecursiveType(const Class& cls,
-                                        const Type& type,
+                                        const AbstractType& type,
                                         PendingTypes* pending_types) {
   Zone* zone = Thread::Current()->zone();
   if (FLAG_trace_type_finalization) {
@@ -596,13 +623,14 @@
   TypeArguments& pending_arguments = TypeArguments::Handle(zone);
   const intptr_t num_pending_types = pending_types->length();
   for (intptr_t i = num_pending_types - 1; i >= 0; i--) {
-    const Type& pending_type = Type::Cast(pending_types->At(i));
+    const AbstractType& pending_type = pending_types->At(i);
     if (FLAG_trace_type_finalization) {
       THR_Print("  Comparing with pending type '%s': %s\n",
                 String::Handle(pending_type.Name()).ToCString(),
                 pending_type.ToCString());
     }
     if ((pending_type.raw() != type.raw()) &&
+        pending_type.IsType() &&
         (pending_type.type_class() == type_cls.raw())) {
       pending_arguments = pending_type.arguments();
       if (!pending_arguments.IsSubvectorEquivalent(arguments,
@@ -620,6 +648,137 @@
 }
 
 
+// Expand the type arguments of the given type and finalize its full type
+// argument vector. Return the number of type arguments (0 for a raw type).
+intptr_t ClassFinalizer::ExpandAndFinalizeTypeArguments(
+    const Class& cls,
+    const AbstractType& type,
+    PendingTypes* pending_types) {
+  Zone* Z = Thread::Current()->zone();
+  // The type class does not need to be finalized in order to finalize the type,
+  // however, it must at least be resolved (this was done as part of resolving
+  // the type itself, a precondition to calling FinalizeType).
+  // Also, the interfaces of the type class must be resolved and the type
+  // parameters of the type class must be finalized.
+  Class& type_class = Class::Handle(Z, type.type_class());
+  if (!type_class.is_type_finalized()) {
+    FinalizeTypeParameters(type_class, pending_types);
+    ResolveUpperBounds(type_class);
+  }
+
+  // The finalized type argument vector needs num_type_arguments types.
+  const intptr_t num_type_arguments = type_class.NumTypeArguments();
+  // 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.
+  // However, type parameter bounds are checked below, even for a raw type.
+  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()->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'",
+                  type_class_name.ToCString());
+    }
+    // Make the type raw and continue without reporting any error.
+    // A static warning should have been reported.
+    arguments = TypeArguments::null();
+    type.set_arguments(arguments);
+  }
+
+  // Mark the type as being finalized in order to detect self reference and
+  // postpone bound checking until after all types in the graph of
+  // mutually recursive types are finalized.
+  type.SetIsBeingFinalized();
+  pending_types->Add(type);
+
+  // The full type argument vector consists of the type arguments of the
+  // 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 (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)) {
+      full_arguments = TypeArguments::New(num_type_arguments);
+      // Copy the parsed type arguments at the correct offset in the full type
+      // argument vector.
+      const intptr_t offset = num_type_arguments - num_type_parameters;
+      AbstractType& type_arg =
+          AbstractType::Handle(Z, Type::DynamicType());
+      // Leave the temporary type arguments at indices [0..offset[ as null.
+      for (intptr_t i = 0; i < num_type_parameters; i++) {
+        // If no type parameters were provided, a raw type is desired, so we
+        // create a vector of dynamic.
+        if (!arguments.IsNull()) {
+          type_arg = arguments.TypeAt(i);
+          // The parsed type_arg may or may not be finalized.
+        }
+        full_arguments.SetTypeAt(offset + i, type_arg);
+      }
+      // Replace the compile-time argument vector (of length zero or
+      // num_type_parameters) of this type being finalized with the still
+      // unfinalized run-time argument vector (of length num_type_arguments).
+      // This type being finalized may be recursively reached via bounds
+      // checking or type arguments of its super type.
+      type.set_arguments(full_arguments);
+      // Finalize the current type arguments of the type, which are still the
+      // parsed type arguments.
+      if (!arguments.IsNull()) {
+        for (intptr_t i = 0; i < num_type_parameters; i++) {
+          type_arg = full_arguments.TypeAt(offset + i);
+          ASSERT(!type_arg.IsBeingFinalized());
+          type_arg = FinalizeType(cls, type_arg, kFinalize, pending_types);
+          if (type_arg.IsMalformed()) {
+            // Malformed type arguments are mapped to dynamic.
+            type_arg = Type::DynamicType();
+          }
+          full_arguments.SetTypeAt(offset + i, type_arg);
+        }
+      }
+      if (offset > 0) {
+        TrailPtr instantiation_trail = new Trail(Z, 4);
+        Error& bound_error = Error::Handle(Z);
+        FinalizeTypeArguments(type_class, full_arguments, offset,
+                              &bound_error, pending_types, instantiation_trail);
+      }
+      if (full_arguments.IsRaw(0, num_type_arguments)) {
+        // The parameterized_type is raw. Set its argument vector to null, which
+        // is more efficient in type tests.
+        full_arguments = TypeArguments::null();
+      }
+      type.set_arguments(full_arguments);
+    } else {
+      ASSERT(full_arguments.IsNull());  // Use null vector for raw type.
+    }
+  }
+
+  // Self referencing types may get finalized indirectly.
+  if (!type.IsFinalized()) {
+    ASSERT(full_arguments.IsNull() ||
+           !full_arguments.IsRaw(0, num_type_arguments));
+    if (FLAG_trace_type_finalization) {
+      THR_Print("Marking type '%s' as finalized for class '%s'\n",
+                String::Handle(Z, type.Name()).ToCString(),
+                String::Handle(Z, cls.Name()).ToCString());
+    }
+    // Mark the type as finalized.
+    type.SetIsFinalized();
+    // Do not yet remove the type from the pending_types array.
+  }
+  return full_arguments.IsNull() ? 0 : full_arguments.Length();
+}
+
+
 // Finalize the type argument vector 'arguments' of the type defined by the
 // class 'cls' parameterized with the type arguments 'cls_args'.
 // The vector 'cls_args' is already initialized as a subvector at the correct
@@ -659,7 +818,7 @@
     intptr_t num_uninitialized_arguments,
     Error* bound_error,
     PendingTypes* pending_types,
-    TrailPtr trail) {
+    TrailPtr instantiation_trail) {
   ASSERT(arguments.Length() >= cls.NumTypeArguments());
   if (!cls.is_type_finalized()) {
     FinalizeTypeParameters(cls, pending_types);
@@ -687,8 +846,8 @@
         super_type_arg = super_type_args.TypeAt(i);
         if (!super_type_arg.IsTypeRef()) {
           if (super_type_arg.IsBeingFinalized()) {
-            ASSERT(super_type_arg.IsType());
-            CheckRecursiveType(cls, Type::Cast(super_type_arg), pending_types);
+            ASSERT(super_type_arg.IsType() || super_type_arg.IsFunctionType());
+            CheckRecursiveType(cls, super_type_arg, pending_types);
             if (FLAG_trace_type_finalization) {
               THR_Print("Creating TypeRef '%s': '%s'\n",
                         String::Handle(super_type_arg.Name()).ToCString(),
@@ -719,7 +878,7 @@
           }
           Error& error = Error::Handle();
           super_type_arg = super_type_arg.InstantiateFrom(
-              arguments, &error, trail, Heap::kOld);
+              arguments, &error, instantiation_trail, NULL, Heap::kOld);
           if (!error.IsNull()) {
             // InstantiateFrom does not report an error if the type is still
             // uninstantiated. Instead, it will return a new BoundedType so
@@ -737,7 +896,7 @@
             if (super_type_arg.IsTypeRef()) {
               super_type_arg = TypeRef::Cast(super_type_arg).type();
             }
-            Type::Cast(super_type_arg).set_is_being_finalized();
+            Type::Cast(super_type_arg).SetIsBeingFinalized();
             pending_types->Add(super_type_arg);
             const Class& cls = Class::Handle(super_type_arg.type_class());
             FinalizeTypeArguments(
@@ -746,7 +905,7 @@
                 cls.NumTypeArguments() - cls.NumTypeParameters(),
                 bound_error,
                 pending_types,
-                trail);
+                instantiation_trail);
             Type::Cast(super_type_arg).SetIsFinalized();
           }
         }
@@ -754,7 +913,7 @@
       arguments.SetTypeAt(i, super_type_arg);
     }
     FinalizeTypeArguments(super_class, arguments, super_offset,
-                          bound_error, pending_types, trail);
+                          bound_error, pending_types, instantiation_trail);
   }
 }
 
@@ -769,7 +928,7 @@
                                              Error* bound_error) {
   if (!cls.is_type_finalized()) {
     FinalizeTypeParameters(cls);
-    FinalizeUpperBounds(cls);
+    FinalizeUpperBounds(cls, kFinalize);  // No canonicalization yet.
   }
   // Note that when finalizing a type, we need to verify the bounds in both
   // production mode and checked mode, because the finalized type may be written
@@ -821,8 +980,8 @@
       if (declared_bound.IsInstantiated()) {
         instantiated_bound = declared_bound.raw();
       } else {
-        instantiated_bound =
-            declared_bound.InstantiateFrom(arguments, &error, NULL, Heap::kOld);
+        instantiated_bound = declared_bound.InstantiateFrom(
+            arguments, &error, NULL, NULL, Heap::kOld);
       }
       if (!instantiated_bound.IsFinalized()) {
         // The bound refers to type parameters, creating a cycle; postpone
@@ -844,14 +1003,16 @@
         if (type_arg.IsTypeParameter()) {
           const Class& type_arg_cls = Class::Handle(
               TypeParameter::Cast(type_arg).parameterized_class());
-          const AbstractType& bound = AbstractType::Handle(
+          AbstractType& bound = AbstractType::Handle(
               TypeParameter::Cast(type_arg).bound());
-          ResolveType(type_arg_cls, bound);
+          bound = ResolveType(type_arg_cls, bound);
+          TypeParameter::Cast(type_arg).set_bound(bound);
         }
         // This may be called only if type needs to be finalized, therefore
         // seems OK to allocate finalized types in old space.
         if (!type_param.CheckBound(type_arg, instantiated_bound,
-                &error, Heap::kOld) && error.IsNull()) {
+                                   &error, NULL, Heap::kOld) &&
+            error.IsNull()) {
           // The bound cannot be checked at compile time; postpone to run time.
           type_arg = BoundedType::New(type_arg, instantiated_bound, type_param);
           arguments.SetTypeAt(offset + i, type_arg);
@@ -870,41 +1031,49 @@
 }
 
 
-void ClassFinalizer::CheckTypeBounds(const Class& cls, const Type& type) {
+void ClassFinalizer::CheckTypeBounds(const Class& cls,
+                                     const AbstractType& type) {
+  Zone* Z = Thread::Current()->zone();
+  ASSERT(type.IsType() || type.IsFunctionType());
   ASSERT(type.IsFinalized());
-  TypeArguments& arguments = TypeArguments::Handle(type.arguments());
+  ASSERT(!type.IsCanonical());
+  TypeArguments& arguments = TypeArguments::Handle(Z, type.arguments());
   if (arguments.IsNull()) {
     return;
   }
-  Class& owner_class = Class::Handle();
-  Class& type_class = Class::Handle(type.type_class());
-  if (type_class.IsSignatureClass()) {
-    const Function& signature_fun =
-        Function::Handle(type_class.signature_function());
-    ASSERT(!signature_fun.is_static());
-    owner_class = signature_fun.Owner();
-  } else {
-    owner_class = type_class.raw();
+  if (FLAG_trace_type_finalization) {
+    THR_Print("Checking bounds of type '%s' for class '%s'\n",
+              String::Handle(Z, type.Name()).ToCString(),
+              String::Handle(Z, cls.Name()).ToCString());
   }
-  Error& bound_error = Error::Handle();
-  CheckTypeArgumentBounds(owner_class, arguments, &bound_error);
-  type.set_arguments(arguments);
-  // If a bound error occurred, mark the type as malbounded.
-  // The bound error will be ignored in production mode.
-  if (!bound_error.IsNull()) {
-    // No compile-time error during finalization.
-    const String& type_name = String::Handle(type.UserVisibleName());
-    FinalizeMalboundedType(bound_error,
-                           Script::Handle(cls.script()),
-                           type,
-                           "type '%s' has an out of bound type argument",
-                           type_name.ToCString());
-    if (FLAG_trace_type_finalization) {
-      THR_Print("Marking type '%s' as malbounded: %s\n",
-                String::Handle(type.Name()).ToCString(),
-                bound_error.ToCString());
+  const Class& type_class = Class::Handle(Z, type.type_class());
+  Error& bound_error = Error::Handle(Z);
+  CheckTypeArgumentBounds(type_class, arguments, &bound_error);
+  // CheckTypeArgumentBounds may have indirectly canonicalized this type.
+  if (!type.IsCanonical()) {
+    type.set_arguments(arguments);
+    // If a bound error occurred, mark the type as malbounded.
+    // The bound error will be ignored in production mode.
+    if (!bound_error.IsNull()) {
+      // No compile-time error during finalization.
+      const String& type_name = String::Handle(Z, type.UserVisibleName());
+      FinalizeMalboundedType(bound_error,
+                             Script::Handle(Z, cls.script()),
+                             type,
+                             "type '%s' has an out of bound type argument",
+                             type_name.ToCString());
+      if (FLAG_trace_type_finalization) {
+        THR_Print("Marking type '%s' as malbounded: %s\n",
+                  String::Handle(Z, type.Name()).ToCString(),
+                  bound_error.ToCString());
+      }
     }
   }
+  if (FLAG_trace_type_finalization) {
+    THR_Print("Done checking bounds of type '%s': %s\n",
+              String::Handle(Z, type.Name()).ToCString(),
+              type.ToCString());
+  }
 }
 
 
@@ -919,7 +1088,11 @@
   if (type.IsFinalized()) {
     // Ensure type is canonical if canonicalization is requested, unless type is
     // malformed.
-    if ((finalization >= kCanonicalize) && !type.IsMalformed()) {
+    if ((finalization >= kCanonicalize) &&
+        !type.IsMalformed() &&
+        !type.IsCanonical() &&
+        (type.IsType() || type.IsFunctionType())) {
+      CheckTypeBounds(cls, type);
       return type.Canonicalize();
     }
     return type.raw();
@@ -936,22 +1109,23 @@
   // encountered here.
   ASSERT(!type.IsBeingFinalized());
 
+  Zone* Z = Thread::Current()->zone();
+  const AbstractType& resolved_type =
+      AbstractType::Handle(Z, ResolveType(cls, type));
   // A malformed type gets mapped to a finalized type.
-  ResolveType(cls, type);
-  if (type.IsMalformed()) {
-    ASSERT(type.IsFinalized());
-    return type.raw();
+  if (resolved_type.IsMalformed()) {
+    ASSERT(resolved_type.IsFinalized());
+    return resolved_type.raw();
   }
 
-  Zone* Z = Thread::Current()->zone();
   if (FLAG_trace_type_finalization) {
     THR_Print("Finalizing type '%s' for class '%s'\n",
-              String::Handle(Z, type.Name()).ToCString(),
-              cls.ToCString());
+              String::Handle(Z, resolved_type.Name()).ToCString(),
+              String::Handle(Z, cls.Name()).ToCString());
   }
 
-  if (type.IsTypeParameter()) {
-    const TypeParameter& type_parameter = TypeParameter::Cast(type);
+  if (resolved_type.IsTypeParameter()) {
+    const TypeParameter& type_parameter = TypeParameter::Cast(resolved_type);
     const Class& parameterized_class =
         Class::Handle(Z, type_parameter.parameterized_class());
     ASSERT(!parameterized_class.IsNull());
@@ -966,7 +1140,7 @@
     // belongs to a mixin application class.
     if (!type_parameter.IsFinalized()) {
       type_parameter.set_index(type_parameter.index() + offset);
-      type_parameter.set_is_finalized();
+      type_parameter.SetIsFinalized();
     } else {
       ASSERT(cls.IsMixinApplication());
     }
@@ -981,8 +1155,8 @@
     return type_parameter.raw();
   }
 
-  // At this point, we can only have a parameterized_type.
-  const Type& parameterized_type = Type::Cast(type);
+  // At this point, we can only have a Type or a FunctionType.
+  ASSERT(resolved_type.IsType() || resolved_type.IsFunctionType());
 
   // This type is the root type of the type graph if no pending types queue is
   // allocated yet.
@@ -991,197 +1165,98 @@
     pending_types = new PendingTypes(Z, 4);
   }
 
-  // The type class does not need to be finalized in order to finalize the type,
-  // however, it must at least be resolved (this was done as part of resolving
-  // the type itself, a precondition to calling FinalizeType).
-  // Also, the interfaces of the type class must be resolved and the type
-  // parameters of the type class must be finalized.
-  Class& type_class = Class::Handle(Z, parameterized_type.type_class());
-  if (!type_class.is_type_finalized()) {
-    FinalizeTypeParameters(type_class, pending_types);
-    ResolveUpperBounds(type_class);
-  }
-
-  // The finalized type argument vector needs num_type_arguments types.
-  const intptr_t num_type_arguments = type_class.NumTypeArguments();
-  // The type class has num_type_parameters type parameters.
-  const intptr_t num_type_parameters = type_class.NumTypeParameters();
-
-  // 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.
-  // However, type parameter bounds are checked below, even for a raw type.
-  TypeArguments& arguments =
-      TypeArguments::Handle(Z, parameterized_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()) {
-      const String& type_class_name =
-          String::Handle(Z, type_class.Name());
-      ReportError(cls, parameterized_type.token_pos(),
-                  "wrong number of type arguments for class '%s'",
-                  type_class_name.ToCString());
-    }
-    // Make the type raw and continue without reporting any error.
-    // A static warning should have been reported.
-    arguments = TypeArguments::null();
-    parameterized_type.set_arguments(arguments);
-  }
-
-  // Mark the type as being finalized in order to detect self reference and
-  // postpone bound checking until after all types in the graph of
-  // mutually recursive types are finalized.
-  parameterized_type.set_is_being_finalized();
-  pending_types->Add(parameterized_type);
-
-  // The full type argument vector consists of the type arguments of the
-  // 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);
-  Error& bound_error = Error::Handle(Z);
-  if (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)) {
-      full_arguments = TypeArguments::New(num_type_arguments);
-      // Copy the parsed type arguments at the correct offset in the full type
-      // argument vector.
-      const intptr_t offset = num_type_arguments - num_type_parameters;
-      AbstractType& type_arg =
-          AbstractType::Handle(Z, Type::DynamicType());
-      // Leave the temporary type arguments at indices [0..offset[ as null.
-      for (intptr_t i = 0; i < num_type_parameters; i++) {
-        // If no type parameters were provided, a raw type is desired, so we
-        // create a vector of dynamic.
-        if (!arguments.IsNull()) {
-          type_arg = arguments.TypeAt(i);
-          // The parsed type_arg may or may not be finalized.
-        }
-        full_arguments.SetTypeAt(offset + i, type_arg);
-      }
-      // Replace the compile-time argument vector (of length zero or
-      // num_type_parameters) of this type being finalized with the still
-      // unfinalized run-time argument vector (of length num_type_arguments).
-      // This type being finalized may be recursively reached via bounds
-      // checking or type arguments of its super type.
-      parameterized_type.set_arguments(full_arguments);
-      // Finalize the current type arguments of the type, which are still the
-      // parsed type arguments.
-      if (!arguments.IsNull()) {
-        for (intptr_t i = 0; i < num_type_parameters; i++) {
-          type_arg = full_arguments.TypeAt(offset + i);
-          ASSERT(!type_arg.IsBeingFinalized());
-          type_arg = FinalizeType(cls, type_arg, kFinalize, pending_types);
-          if (type_arg.IsMalformed()) {
-            // Malformed type arguments are mapped to dynamic.
-            type_arg = Type::DynamicType();
-          }
-          full_arguments.SetTypeAt(offset + i, type_arg);
-        }
-      }
-      // If the type class is a signature class, the full argument vector
-      // must include the argument vector of the super type.
-      // If the signature class is a function type alias, it is also the owner
-      // of its signature function and no super type is involved.
-      // If the signature class is canonical (not an alias), the owner of its
-      // signature function may either be an alias or the enclosing class of a
-      // local function, in which case the super type of the enclosing class is
-      // also considered when filling up the argument vector.
-      Class& owner_class = Class::Handle(Z);
-      if (type_class.IsSignatureClass()) {
-        const Function& signature_fun =
-            Function::Handle(Z, type_class.signature_function());
-        ASSERT(!signature_fun.is_static());
-        owner_class = signature_fun.Owner();
-      } else {
-        owner_class = type_class.raw();
-      }
-      if (offset > 0) {
-        TrailPtr trail = new Trail(Z, 4);
-        FinalizeTypeArguments(owner_class, full_arguments, offset,
-                              &bound_error, pending_types, trail);
-      }
-      if (full_arguments.IsRaw(0, num_type_arguments)) {
-        // The parameterized_type is raw. Set its argument vector to null, which
-        // is more efficient in type tests.
-        full_arguments = TypeArguments::null();
-      }
-      parameterized_type.set_arguments(full_arguments);
-    } else {
-      ASSERT(full_arguments.IsNull());  // Use null vector for raw type.
-    }
-  }
-
-  // Self referencing types may get finalized indirectly.
-  if (!parameterized_type.IsFinalized()) {
-    ASSERT(full_arguments.IsNull() ||
-           !full_arguments.IsRaw(0, num_type_arguments));
-    // Mark the type as finalized.
-    parameterized_type.SetIsFinalized();
-    // Do not yet remove the type from the pending_types array.
-  }
+  const intptr_t num_expanded_type_arguments =
+      ExpandAndFinalizeTypeArguments(cls, resolved_type, pending_types);
 
   // If we are done finalizing a graph of mutually recursive types, check their
   // bounds.
   if (is_root_type) {
     for (intptr_t i = pending_types->length() - 1; i >= 0; i--) {
-      CheckTypeBounds(cls, Type::Cast(pending_types->At(i)));
-      if (FLAG_trace_type_finalization && type.IsRecursive()) {
-        THR_Print("Done finalizing recursive type '%s': %s\n",
-                  String::Handle(Z, type.Name()).ToCString(),
-                  type.ToCString());
+      const AbstractType& type = pending_types->At(i);
+      if (!type.IsMalformed() && !type.IsCanonical()) {
+        CheckTypeBounds(cls, type);
       }
     }
   }
 
-  // If the type class is a signature class, we are currently finalizing a
-  // signature type, i.e. finalizing the result type and parameter types of the
-  // signature function of this signature type.
+  // If the type is a FunctionType, we also need to finalize the types in its
+  // signature, i.e. finalize the result type and parameter types of the
+  // signature function of this function type.
   // We do this after marking this type as finalized in order to allow a
   // function type to refer to itself via its parameter types and result type.
-  if (type_class.IsSignatureClass()) {
-    // The class may be created while parsing a function body, after all
-    // pending classes have already been finalized.
-    FinalizeTypesInClass(type_class);
+  // Note that we do not instantiate these types according to the type
+  // arguments. This will happen on demand when executing a type test.
+  if (resolved_type.IsFunctionType()) {
+    const Function& signature =
+        Function::Handle(Z, FunctionType::Cast(resolved_type).signature());
+    const Class& scope_class =
+        Class::Handle(Z, FunctionType::Cast(resolved_type).scope_class());
+    if (scope_class.IsTypedefClass()) {
+      FinalizeSignature(scope_class, signature);
+    } else {
+      FinalizeSignature(cls, signature);
+    }
   }
 
   if (FLAG_trace_type_finalization) {
     THR_Print("Done finalizing type '%s' with %" Pd " type args: %s\n",
-              String::Handle(Z, parameterized_type.Name()).ToCString(),
-              parameterized_type.arguments() == TypeArguments::null() ?
-                  0 : num_type_arguments,
-              parameterized_type.ToCString());
+              String::Handle(Z, resolved_type.Name()).ToCString(),
+              num_expanded_type_arguments,
+              resolved_type.ToCString());
   }
 
   if (finalization >= kCanonicalize) {
-    if (FLAG_trace_type_finalization && parameterized_type.IsRecursive()) {
-      AbstractType& type = Type::Handle(Z);
-      type = parameterized_type.Canonicalize();
-      THR_Print("Done canonicalizing recursive type '%s': %s\n",
-                String::Handle(Z, type.Name()).ToCString(),
-                type.ToCString());
-      return type.raw();
+    if (FLAG_trace_type_finalization) {
+      THR_Print("Canonicalizing type '%s'\n",
+                String::Handle(Z, resolved_type.Name()).ToCString());
+      AbstractType& canonical_type =
+          AbstractType::Handle(Z, resolved_type.Canonicalize());
+      THR_Print("Done canonicalizing type '%s'\n",
+                String::Handle(Z, canonical_type.Name()).ToCString());
+      return canonical_type.raw();
     }
-    return parameterized_type.Canonicalize();
+    return resolved_type.Canonicalize();
   } else {
-    return parameterized_type.raw();
+    return resolved_type.raw();
   }
 }
 
 
-void ClassFinalizer::ResolveAndFinalizeSignature(const Class& cls,
-                                                 const Function& function) {
+void ClassFinalizer::ResolveSignature(const Class& cls,
+                                      const Function& function) {
   // Resolve result type.
   AbstractType& type = AbstractType::Handle(function.result_type());
   // It is not a compile time error if this name does not resolve to a class or
   // interface.
+  AbstractType& resolved_type = AbstractType::Handle(ResolveType(cls, type));
+  if (resolved_type.raw() != type.raw()) {
+    function.set_result_type(resolved_type);
+  }
+  // Resolve formal parameter types.
+  const intptr_t num_parameters = function.NumParameters();
+  for (intptr_t i = 0; i < num_parameters; i++) {
+    type = function.ParameterTypeAt(i);
+    resolved_type = ResolveType(cls, type);
+    if (resolved_type.raw() != type.raw()) {
+      function.SetParameterTypeAt(i, resolved_type);
+    }
+  }
+}
+
+
+void ClassFinalizer::FinalizeSignature(const Class& cls,
+                                       const Function& function) {
+  // Finalize result type.
+  AbstractType& type = AbstractType::Handle(function.result_type());
+  // It is not a compile time error if this name does not resolve to a class or
+  // interface.
   AbstractType& finalized_type =
       AbstractType::Handle(FinalizeType(cls, type, kCanonicalize));
   // The result type may be malformed or malbounded.
-  if (type.raw() != finalized_type.raw()) {
+  if (finalized_type.raw() != type.raw()) {
     function.set_result_type(finalized_type);
   }
-  // Resolve formal parameter types.
+  // Finalize formal parameter types.
   const intptr_t num_parameters = function.NumParameters();
   for (intptr_t i = 0; i < num_parameters; i++) {
     type = function.ParameterTypeAt(i);
@@ -1255,13 +1330,15 @@
   for (intptr_t i = 0; i < num_type_params; i++) {
     type_param ^= type_params.TypeAt(i);
     bound = type_param.bound();
-    ResolveType(cls, bound);
+    bound = ResolveType(cls, bound);
+    type_param.set_bound(bound);
   }
 }
 
 
 // Finalize the upper bounds of the type parameters of class cls.
-void ClassFinalizer::FinalizeUpperBounds(const Class& cls) {
+void ClassFinalizer::FinalizeUpperBounds(const Class& cls,
+                                         FinalizationKind finalization) {
   const intptr_t num_type_params = cls.NumTypeParameters();
   TypeParameter& type_param = TypeParameter::Handle();
   AbstractType& bound = AbstractType::Handle();
@@ -1277,7 +1354,7 @@
       // A bound involved in F-bounded quantification may form a cycle.
       continue;
     }
-    bound = FinalizeType(cls, bound, kCanonicalize);
+    bound = FinalizeType(cls, bound, finalization);
     type_param.set_bound(bound);
   }
 }
@@ -1385,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(
@@ -1445,10 +1522,10 @@
   Error& error = Error::Handle(Z);
   for (intptr_t i = 0; i < num_functions; i++) {
     function ^= array.At(i);
-    ResolveAndFinalizeSignature(cls, function);
+    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++) {
@@ -1718,8 +1795,8 @@
                   FinalizeType(mixin_app_class, param_bound, kCanonicalize);
               param.set_bound(param_bound);  // In case part of recursive type.
             }
-            param_bound = param_bound.InstantiateFrom(instantiator,
-                                                      &bound_error);
+            param_bound = param_bound.InstantiateFrom(
+                instantiator, &bound_error, NULL, NULL, Heap::kOld);
             // The instantiator contains only TypeParameter objects and no
             // BoundedType objects, so no bound error may occur.
             ASSERT(!param_bound.IsBoundedType());
@@ -1915,10 +1992,15 @@
   const intptr_t num_super_type_params = super_class.NumTypeParameters();
   AbstractType& type = AbstractType::Handle(zone);
   // The instantiator is mapping finalized type parameters of mixin_class to
-  // unfinalized type parameters of mixin_app_class.
-  ASSERT(aliased_mixin_type.IsFinalized());
+  // unfinalized type parameters of mixin_app_class. Therefore, the type
+  // arguments of mixin_class_super_type must be finalized, since they get
+  // instantiated by this instantiator. Finalizing the types in mixin_class
+  // will finalize mixin_class_super_type.
+  // The aliased_mixin_type does not need to be finalized, but only resolved.
+  ASSERT(aliased_mixin_type.IsResolved());
   const Class& aliased_mixin_type_class = Class::Handle(zone,
       aliased_mixin_type.type_class());
+  FinalizeTypesInClass(mixin_class);
   const intptr_t num_aliased_mixin_type_params =
       aliased_mixin_type_class.NumTypeParameters();
   ASSERT(inserted_class.NumTypeParameters() ==
@@ -1947,19 +2029,21 @@
         // the BoundedType in another BoundedType.
         if (type.IsBoundedType()) {
           bounded_type = BoundedType::Cast(type).type();
-          bounded_type = bounded_type.InstantiateFrom(instantiator,
-                                                      &bound_error);
+          bounded_type = bounded_type.InstantiateFrom(
+              instantiator, &bound_error, NULL, NULL, Heap::kOld);
           // The instantiator contains only TypeParameter objects and no
           // BoundedType objects, so no bound error may occur.
           ASSERT(bound_error.IsNull());
           upper_bound = BoundedType::Cast(type).bound();
-          upper_bound = upper_bound.InstantiateFrom(instantiator, &bound_error);
+          upper_bound = upper_bound.InstantiateFrom(
+              instantiator, &bound_error, NULL, NULL, Heap::kOld);
           ASSERT(bound_error.IsNull());
           type_parameter = BoundedType::Cast(type).type_parameter();
           // The type parameter that declared the bound does not change.
           type = BoundedType::New(bounded_type, upper_bound, type_parameter);
         } else {
-          type = type.InstantiateFrom(instantiator, &bound_error);
+          type = type.InstantiateFrom(
+              instantiator, &bound_error, NULL, NULL, Heap::kOld);
           ASSERT(bound_error.IsNull());
         }
       }
@@ -2022,10 +2106,10 @@
   const Class& mixin_class = Class::Handle(mixin_type.type_class());
 
   if (FLAG_trace_class_finalization) {
-    THR_Print("Applying mixin type '%s' to %s at pos %" Pd "\n",
+    THR_Print("Applying mixin type '%s' to %s at pos %s\n",
               String::Handle(mixin_type.Name()).ToCString(),
               mixin_app_class.ToCString(),
-              mixin_app_class.token_pos());
+              mixin_app_class.token_pos().ToCString());
   }
 
   // Check for illegal self references.
@@ -2152,10 +2236,10 @@
   // A default constructor will be created for the mixin app alias class.
 
   if (FLAG_trace_class_finalization) {
-    THR_Print("Applying mixin members of %s to %s at pos %" Pd "\n",
+    THR_Print("Applying mixin members of %s to %s at pos %s\n",
               mixin_cls.ToCString(),
               cls.ToCString(),
-              cls.token_pos());
+              cls.token_pos().ToCString());
   }
 
   const GrowableObjectArray& cloned_funcs =
@@ -2175,9 +2259,18 @@
     if (func.IsGenerativeConstructor()) {
       // A mixin class must not have explicit constructors.
       if (!func.IsImplicitConstructor()) {
-        ReportError(cls, cls.token_pos(),
-                    "mixin class '%s' must not have constructors\n",
-                    String::Handle(zone, mixin_cls.Name()).ToCString());
+        const Script& script = Script::Handle(cls.script());
+        const Error& error = Error::Handle(
+            LanguageError::NewFormatted(Error::Handle(),
+                script, func.token_pos(), Report::AtLocation,
+                Report::kError, Heap::kNew,
+                "constructor '%s' is illegal in mixin class %s",
+                String::Handle(func.UserVisibleName()).ToCString(),
+                String::Handle(zone, mixin_cls.Name()).ToCString()));
+
+        ReportErrors(error, cls, cls.token_pos(),
+                     "mixin class '%s' must not have constructors",
+                     String::Handle(zone, mixin_cls.Name()).ToCString());
       }
       continue;  // Skip the implicit constructor.
     }
@@ -2245,7 +2338,9 @@
   // Only resolving rather than finalizing the upper bounds here would result in
   // instantiated type parameters of the super type to temporarily have
   // unfinalized bounds. It is more efficient to finalize them early.
-  FinalizeUpperBounds(cls);
+  // Finalize bounds even if running in production mode, so that a snapshot
+  // contains them.
+  FinalizeUpperBounds(cls, kCanonicalizeWellFormed);
   // Finalize super type.
   AbstractType& super_type = AbstractType::Handle(cls.super_type());
   if (!super_type.IsNull()) {
@@ -2265,10 +2360,13 @@
     mixin_type ^= FinalizeType(cls, mixin_type, kCanonicalizeWellFormed);
     cls.set_mixin(mixin_type);
   }
-  if (cls.IsSignatureClass()) {
+  if (cls.IsTypedefClass()) {
+    const Function& signature = Function::Handle(cls.signature_function());
+    FunctionType& type = FunctionType::Handle(signature.SignatureType());
+
     // Check for illegal self references.
     GrowableArray<intptr_t> visited_aliases;
-    if (!IsAliasCycleFree(cls, &visited_aliases)) {
+    if (!IsTypedefCycleFree(cls, type, &visited_aliases)) {
       const String& name = String::Handle(cls.Name());
       ReportError(cls, cls.token_pos(),
                   "typedef '%s' illegally refers to itself",
@@ -2276,26 +2374,22 @@
     }
     cls.set_is_type_finalized();
 
-    // The type parameters of signature classes may have bounds.
-    FinalizeUpperBounds(cls);
-
     // Resolve and finalize the result and parameter types of the signature
-    // function of this signature class.
-    const Function& sig_function = Function::Handle(cls.signature_function());
-    ResolveAndFinalizeSignature(cls, sig_function);
+    // function of this typedef class.
+    FinalizeSignature(cls, signature);  // Does not modify signature type.
+    ASSERT(signature.SignatureType() == type.raw());
 
-    // Resolve and finalize the signature type of this signature class.
-    const Type& sig_type = Type::Handle(cls.SignatureType());
-    FinalizeType(cls, sig_type, kCanonicalizeWellFormed);
+    // Resolve and finalize the signature type of this typedef.
+    type ^= FinalizeType(cls, type, kCanonicalizeWellFormed);
+    signature.SetSignatureType(type);
 
-    // Add this class to the subclasses of the superclass (_FunctionImpl).
-    if (!super_type.IsNull()) {
-      ASSERT(!super_type.IsObjectType());
-      ASSERT(!super_class.IsNull());
-      super_class.AddDirectSubclass(cls);
-    }
+    // Closure instances do not refer to this typedef as their class, so there
+    // is no need to add this typedef class to the subclasses of _Closure.
+    ASSERT(super_type.IsNull() || super_type.IsObjectType());
+
     return;
   }
+
   // Finalize interface types (but not necessarily interface classes).
   Array& interface_types = Array::Handle(cls.interfaces());
   AbstractType& interface_type = AbstractType::Handle();
@@ -2332,9 +2426,6 @@
   // Mark as type finalized before resolving type parameter upper bounds
   // in order to break cycles.
   cls.set_is_type_finalized();
-  // Finalize bounds even if running in production mode, so that a snapshot
-  // contains them.
-  FinalizeUpperBounds(cls);
   // Add this class to the direct subclasses of the superclass, unless the
   // superclass is Object.
   if (!super_type.IsNull() && !super_type.IsObjectType()) {
@@ -2401,9 +2492,9 @@
     cls.SetFunctions(functions);
   }
   // Every class should have at least a constructor, unless it is a top level
-  // class or a signature class.
+  // class or a typedef class.
   ASSERT(cls.IsTopLevel() ||
-         cls.IsSignatureClass() ||
+         cls.IsTypedefClass() ||
          (Array::Handle(cls.functions()).Length() > 0));
   // Resolve and finalize all member types.
   ResolveAndFinalizeMemberTypes(cls);
@@ -2494,82 +2585,80 @@
 }
 
 
-// Helper function called by IsAliasCycleFree.
-bool ClassFinalizer::IsTypeCycleFree(
-    const Class& cls,
-    const AbstractType& type,
-    GrowableArray<intptr_t>* visited) {
+// Returns false if a function type alias illegally refers to itself.
+bool ClassFinalizer::IsTypedefCycleFree(const Class& cls,
+                                        const AbstractType& type,
+                                        GrowableArray<intptr_t>* visited) {
   ASSERT(visited != NULL);
-  ResolveType(cls, type);
-  if (type.IsType() && !type.IsMalformed()) {
-    const Class& type_class = Class::Handle(type.type_class());
-    if (!type_class.is_type_finalized() &&
-        type_class.IsSignatureClass() &&
-        !IsAliasCycleFree(type_class, visited)) {
-      return false;
-    }
-    const TypeArguments& type_args = TypeArguments::Handle(type.arguments());
-    if (!type_args.IsNull()) {
-      AbstractType& type_arg = AbstractType::Handle();
-      for (intptr_t i = 0; i < type_args.Length(); i++) {
-        type_arg = type_args.TypeAt(i);
-        if (!IsTypeCycleFree(cls, type_arg, visited)) {
+  AbstractType& resolved_type = AbstractType::Handle(ResolveType(cls, type));
+  bool checking_typedef = false;
+  if ((resolved_type.IsType() || resolved_type.IsFunctionType()) &&
+      !resolved_type.IsMalformed()) {
+    AbstractType& other_type = AbstractType::Handle();
+    if (resolved_type.IsFunctionType()) {
+      const Class& scope_class = Class::Handle(resolved_type.type_class());
+      const Function& signature_function =
+          Function::Handle(FunctionType::Cast(resolved_type).signature());
+      // The signature function of this function type may be a local signature
+      // function used in a formal parameter type of the typedef signature, but
+      // not the typedef signature function itself, thus not qualifying as an
+      // illegal self reference.
+      if (!scope_class.is_type_finalized() &&
+          scope_class.IsTypedefClass() &&
+          (scope_class.signature_function() == signature_function.raw())) {
+        checking_typedef = true;
+        const intptr_t scope_class_id = scope_class.id();
+        ASSERT(visited != NULL);
+        for (intptr_t i = 0; i < visited->length(); i++) {
+          if ((*visited)[i] == scope_class_id) {
+            // We have already visited alias 'scope_class'. We found a cycle.
+            return false;
+          }
+        }
+        visited->Add(scope_class_id);
+      }
+      // Check the bounds of this function type.
+      const intptr_t num_type_params = scope_class.NumTypeParameters();
+      TypeParameter& type_param = TypeParameter::Handle();
+      const TypeArguments& type_params =
+          TypeArguments::Handle(scope_class.type_parameters());
+      ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
+             (type_params.Length() == num_type_params));
+      for (intptr_t i = 0; i < num_type_params; i++) {
+        type_param ^= type_params.TypeAt(i);
+        other_type = type_param.bound();
+        if (!IsTypedefCycleFree(cls, other_type, visited)) {
+          return false;
+        }
+      }
+      // Check the result type of the signature of this function type.
+      other_type = signature_function.result_type();
+      if (!IsTypedefCycleFree(cls, other_type, visited)) {
+        return false;
+      }
+      // Check the parameter types of the signature of this function type.
+      const intptr_t num_parameters = signature_function.NumParameters();
+      for (intptr_t i = 0; i < num_parameters; i++) {
+        other_type = signature_function.ParameterTypeAt(i);
+        if (!IsTypedefCycleFree(cls, other_type, visited)) {
           return false;
         }
       }
     }
-  }
-  return true;
-}
-
-
-// Returns false if the function type alias illegally refers to itself.
-bool ClassFinalizer::IsAliasCycleFree(const Class& cls,
-                                      GrowableArray<intptr_t>* visited) {
-  ASSERT(cls.IsSignatureClass());
-  ASSERT(!cls.is_type_finalized());
-  ASSERT(visited != NULL);
-  const intptr_t cls_index = cls.id();
-  for (intptr_t i = 0; i < visited->length(); i++) {
-    if ((*visited)[i] == cls_index) {
-      // We have already visited alias 'cls'. We found a cycle.
-      return false;
+    const TypeArguments& type_args =
+        TypeArguments::Handle(resolved_type.arguments());
+    if (!type_args.IsNull()) {
+      for (intptr_t i = 0; i < type_args.Length(); i++) {
+        other_type = type_args.TypeAt(i);
+        if (!IsTypedefCycleFree(cls, other_type, visited)) {
+          return false;
+        }
+      }
+    }
+    if (checking_typedef) {
+      visited->RemoveLast();
     }
   }
-
-  // Visit the bounds, result type, and parameter types of this signature type.
-  visited->Add(cls.id());
-  AbstractType& type = AbstractType::Handle();
-
-  // Check the bounds of this signature type.
-  const intptr_t num_type_params = cls.NumTypeParameters();
-  TypeParameter& type_param = TypeParameter::Handle();
-  const TypeArguments& type_params =
-      TypeArguments::Handle(cls.type_parameters());
-  ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
-         (type_params.Length() == num_type_params));
-  for (intptr_t i = 0; i < num_type_params; i++) {
-    type_param ^= type_params.TypeAt(i);
-    type = type_param.bound();
-    if (!IsTypeCycleFree(cls, type, visited)) {
-      return false;
-    }
-  }
-  // Check the result type of the function of this signature type.
-  const Function& function = Function::Handle(cls.signature_function());
-  type = function.result_type();
-  if (!IsTypeCycleFree(cls, type, visited)) {
-    return false;
-  }
-  // Check the formal parameter types of the function of this signature type.
-  const intptr_t num_parameters = function.NumParameters();
-  for (intptr_t i = 0; i < num_parameters; i++) {
-    type = function.ParameterTypeAt(i);
-    if (!IsTypeCycleFree(cls, type, visited)) {
-      return false;
-    }
-  }
-  visited->RemoveLast();
   return true;
 }
 
@@ -2627,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'",
@@ -2657,8 +2746,16 @@
       GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
   AbstractType& mixin_super_type =
       AbstractType::Handle(zone, mixin_app_type.super_type());
-  ResolveType(cls, mixin_super_type);
+  mixin_super_type = ResolveType(cls, mixin_super_type);
   ASSERT(mixin_super_type.HasResolvedTypeClass());  // Even if malformed.
+  if (mixin_super_type.IsMalformedOrMalbounded()) {
+    ReportError(Error::Handle(zone, mixin_super_type.error()));
+  }
+  if (mixin_super_type.IsDynamicType()) {
+    ReportError(cls, cls.token_pos(),
+                "class '%s' may not extend 'dynamic'",
+                String::Handle(zone, cls.Name()).ToCString());
+  }
   // The super type may have a BoundedType as type argument, but cannot be
   // a BoundedType itself.
   CollectTypeArguments(cls, Type::Cast(mixin_super_type), type_args);
@@ -2673,7 +2770,7 @@
   for (intptr_t i = 0; i < depth; i++) {
     mixin_type = mixin_app_type.MixinTypeAt(i);
     ASSERT(!mixin_type.IsNull());
-    ResolveType(cls, mixin_type);
+    mixin_type = ResolveType(cls, mixin_type);
     ASSERT(mixin_type.HasResolvedTypeClass());  // Even if malformed.
     ASSERT(mixin_type.IsType());
     const intptr_t num_super_type_args = type_args.Length();
@@ -2834,7 +2931,7 @@
   Class& interface_class = Class::Handle(zone);
 
   // Resolve super type. Failures lead to a longjmp.
-  ResolveType(cls, super_type);
+  super_type = ResolveType(cls, super_type);
   if (super_type.IsMalformedOrMalbounded()) {
     ReportError(Error::Handle(zone, super_type.error()));
   }
@@ -2844,7 +2941,7 @@
                 String::Handle(zone, cls.Name()).ToCString());
   }
   interface_class = super_type.type_class();
-  if (interface_class.IsSignatureClass()) {
+  if (interface_class.IsTypedefClass()) {
     ReportError(cls, cls.token_pos(),
                 "class '%s' may not extend function type alias '%s'",
                 String::Handle(zone, cls.Name()).ToCString(),
@@ -2914,7 +3011,7 @@
   // Resolve interfaces. Failures lead to a longjmp.
   for (intptr_t i = 0; i < super_interfaces.Length(); i++) {
     interface ^= super_interfaces.At(i);
-    ResolveType(cls, interface);
+    interface = ResolveType(cls, interface);
     ASSERT(!interface.IsTypeParameter());  // Should be detected by parser.
     // A malbounded interface is only reported when involved in a type test.
     if (interface.IsMalformed()) {
@@ -2925,7 +3022,7 @@
                   "'dynamic' may not be used as interface");
     }
     interface_class = interface.type_class();
-    if (interface_class.IsSignatureClass()) {
+    if (interface_class.IsTypedefClass()) {
       const String& interface_name = String::Handle(zone,
                                                     interface_class.Name());
       ReportError(cls, cls.token_pos(),
@@ -3048,10 +3145,10 @@
                                        va_list args) {
   LanguageError& error = LanguageError::Handle(
       LanguageError::NewFormattedV(
-          prev_error, script, type.token_pos(),
+          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);
@@ -3061,7 +3158,7 @@
   type.set_arguments(Object::null_type_arguments());
   if (!type.IsFinalized()) {
     type.SetIsFinalized();
-    // Do not canonicalize malformed types, since they may not be resolved.
+    // Do not canonicalize malformed types, since they contain an error field.
   } else {
     // The only case where the malformed type was already finalized is when its
     // type arguments are not within bounds. In that case, we have a prev_error.
@@ -3072,7 +3169,7 @@
 
 RawType* ClassFinalizer::NewFinalizedMalformedType(const Error& prev_error,
                                                    const Script& script,
-                                                   intptr_t type_pos,
+                                                   TokenPosition type_pos,
                                                    const char* format, ...) {
   va_list args;
   va_start(args, format);
@@ -3103,17 +3200,17 @@
 
 void ClassFinalizer::FinalizeMalboundedType(const Error& prev_error,
                                             const Script& script,
-                                            const Type& type,
+                                            const AbstractType& type,
                                             const char* format, ...) {
   va_list args;
   va_start(args, format);
   LanguageError& error = LanguageError::Handle(
       LanguageError::NewFormattedV(
-          prev_error, script, type.token_pos(),
+          prev_error, script, type.token_pos(), Report::AtLocation,
           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);
@@ -3132,7 +3229,7 @@
 
 void ClassFinalizer::ReportErrors(const Error& prev_error,
                                   const Class& cls,
-                                  intptr_t token_pos,
+                                  TokenPosition token_pos,
                                   const char* format, ...) {
   va_list args;
   va_start(args, format);
@@ -3144,12 +3241,13 @@
 
 
 void ClassFinalizer::ReportError(const Class& cls,
-                                 intptr_t token_pos,
+                                 TokenPosition token_pos,
                                  const char* format, ...) {
   va_list args;
   va_start(args, format);
   const Script& script = Script::Handle(cls.script());
-  Report::MessageV(Report::kError, script, token_pos, format, args);
+  Report::MessageV(Report::kError,
+                   script, token_pos, Report::AtLocation, format, args);
   va_end(args);
   UNREACHABLE();
 }
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index 3aa7c2c..e630df0 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -42,7 +42,7 @@
   // string and its arguments.
   static RawType* NewFinalizedMalformedType(const Error& prev_error,
                                             const Script& script,
-                                            intptr_t type_pos,
+                                            TokenPosition type_pos,
                                             const char* format, ...)
        PRINTF_ATTRIBUTE(4, 5);
 
@@ -60,7 +60,7 @@
   // string and its arguments.
   static void FinalizeMalboundedType(const Error& prev_error,
                                      const Script& script,
-                                     const Type& type,
+                                     const AbstractType& type,
                                      const char* format, ...)
        PRINTF_ATTRIBUTE(4, 5);
 
@@ -89,7 +89,8 @@
 #endif  // defined(DART_NO_SNAPSHOT).
 
   // Resolve the class of the type, but not the type's type arguments.
-  static void ResolveTypeClass(const Class& cls, const AbstractType& type);
+  // May promote the type from Type to FunctionType.
+  static RawAbstractType* ResolveTypeClass(const Class& cls, const Type& type);
 
   // Resolve the type and target of the redirecting factory.
   static void ResolveRedirectingFactory(const Class& cls,
@@ -102,17 +103,16 @@
  private:
   static void AllocateEnumValues(const Class& enum_cls);
   static bool IsSuperCycleFree(const Class& cls);
-  static bool IsTypeCycleFree(const Class& cls,
-                              const AbstractType& type,
-                              GrowableArray<intptr_t>* visited);
-  static bool IsAliasCycleFree(const Class& cls,
-                               GrowableArray<intptr_t>* visited);
+  static bool IsTypedefCycleFree(const Class& cls,
+                                 const AbstractType& type,
+                                 GrowableArray<intptr_t>* visited);
   static bool IsMixinCycleFree(const Class& cls,
                                GrowableArray<intptr_t>* visited);
   static void CheckForLegalConstClass(const Class& cls);
   static RawClass* ResolveClass(const Class& cls,
                                 const UnresolvedClass& unresolved_class);
-  static void ResolveType(const Class& cls, const AbstractType& type);
+  static RawAbstractType* ResolveType(const Class& cls,
+                                      const AbstractType& type);
   static void ResolveRedirectingFactoryTarget(
       const Class& cls,
       const Function& factory,
@@ -134,6 +134,9 @@
                                             GrowableArray<intptr_t>* visited);
   static void FinalizeTypeParameters(const Class& cls,
                                      PendingTypes* pending_types = NULL);
+  static intptr_t ExpandAndFinalizeTypeArguments(const Class& cls,
+                                                 const AbstractType& type,
+                                                 PendingTypes* pending_types);
   static void FinalizeTypeArguments(const Class& cls,
                                     const TypeArguments& arguments,
                                     intptr_t num_uninitialized_arguments,
@@ -141,16 +144,17 @@
                                     PendingTypes* pending_types,
                                     TrailPtr trail);
   static void CheckRecursiveType(const Class& cls,
-                                 const Type& type,
+                                 const AbstractType& type,
                                  PendingTypes* pending_types);
-  static void CheckTypeBounds(const Class& cls, const Type& type);
+  static void CheckTypeBounds(const Class& cls, const AbstractType& type);
   static void CheckTypeArgumentBounds(const Class& cls,
                                       const TypeArguments& arguments,
                                       Error* bound_error);
   static void ResolveUpperBounds(const Class& cls);
-  static void FinalizeUpperBounds(const Class& cls);
-  static void ResolveAndFinalizeSignature(const Class& cls,
-                                          const Function& function);
+  static void FinalizeUpperBounds(const Class& cls,
+                                  FinalizationKind finalization);
+  static void ResolveSignature(const Class& cls, const Function& function);
+  static void FinalizeSignature(const Class& cls, const Function& function);
   static void ResolveAndFinalizeMemberTypes(const Class& cls);
   static void PrintClassInformation(const Class& cls);
   static void CollectInterfaces(
@@ -163,11 +167,11 @@
                                 va_list args);
   static void ReportError(const Error& error);
   static void ReportError(const Class& cls,
-                          intptr_t token_pos,
+                          TokenPosition token_pos,
                           const char* format, ...) PRINTF_ATTRIBUTE(3, 4);
   static void ReportErrors(const Error& prev_error,
                            const Class& cls,
-                           intptr_t token_pos,
+                           TokenPosition token_pos,
                            const char* format, ...) PRINTF_ATTRIBUTE(4, 5);
 
   // Verify implicit offsets recorded in the VM for direct access to fields of
diff --git a/runtime/vm/class_finalizer_test.cc b/runtime/vm/class_finalizer_test.cc
index 828ecac..f1c492e 100644
--- a/runtime/vm/class_finalizer_test.cc
+++ b/runtime/vm/class_finalizer_test.cc
@@ -13,8 +13,8 @@
 static RawClass* CreateTestClass(const char* name) {
   const String& class_name = String::Handle(Symbols::New(name));
   const Script& script = Script::Handle();
-  const Class& cls =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& cls = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   cls.set_interfaces(Object::empty_array());
   cls.SetFunctions(Object::empty_array());
   cls.SetFields(Object::empty_array());
@@ -96,12 +96,12 @@
   const UnresolvedClass& unresolved = UnresolvedClass::Handle(
       UnresolvedClass::New(LibraryPrefix::Handle(),
                            superclass_name,
-                           Scanner::kNoSourcePos));
+                           TokenPosition::kNoSource));
   const TypeArguments& type_arguments = TypeArguments::Handle();
   rhb.set_super_type(Type::Handle(
       Type::New(Object::Handle(unresolved.raw()),
                 type_arguments,
-                Scanner::kNoSourcePos)));
+                TokenPosition::kNoSource)));
   EXPECT(ClassFinalizer::ProcessPendingClasses());
 }
 
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 52786ee..7129cf8 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -144,6 +144,7 @@
 
 
 void ClassTable::RegisterAt(intptr_t index, const Class& cls) {
+  ASSERT(Thread::Current()->IsMutatorThread());
   ASSERT(index != kIllegalCid);
   ASSERT(index >= kNumPredefinedCids);
   if (index >= capacity_) {
@@ -179,6 +180,13 @@
 }
 
 
+#if defined(DEBUG)
+void ClassTable::Unregister(intptr_t index) {
+  table_[index] = 0;
+}
+#endif
+
+
 void ClassTable::VisitObjectPointers(ObjectPointerVisitor* visitor) {
   ASSERT(visitor != NULL);
   visitor->VisitPointers(reinterpret_cast<RawObject**>(&table_[0]), top_);
@@ -224,6 +232,9 @@
 
 
 void ClassTable::PrintToJSONObject(JSONObject* object) {
+  if (!FLAG_support_service) {
+    return;
+  }
   Class& cls = Class::Handle();
   object->AddProperty("type", "ClassList");
   {
@@ -317,6 +328,9 @@
 
 void ClassHeapStats::PrintToJSONObject(const Class& cls,
                                        JSONObject* obj) const {
+  if (!FLAG_support_service) {
+    return;
+  }
   obj->AddProperty("type", "ClassHeapStats");
   obj->AddProperty("class", cls);
   {
@@ -472,6 +486,9 @@
 
 
 void ClassTable::AllocationProfilePrintJSON(JSONStream* stream) {
+  if (!FLAG_support_service) {
+    return;
+  }
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
   Heap* heap = isolate->heap();
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index aaabdf4..97e475a 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -132,7 +132,8 @@
     kTraceAllocationBit = 0,
   };
 
-  class TraceAllocationBit : public BitField<bool, kTraceAllocationBit, 1> {};
+  class TraceAllocationBit :
+      public BitField<intptr_t, bool, kTraceAllocationBit, 1> {};
 
   // Recent old at start of last new GC (used to compute promoted_*).
   intptr_t old_pre_new_gc_count_;
@@ -170,6 +171,10 @@
 
   void RegisterAt(intptr_t index, const Class& cls);
 
+#if defined(DEBUG)
+  void Unregister(intptr_t index);
+#endif
+
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
   void Validate();
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index adc7853..dad76d9 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -9,31 +9,58 @@
 void DescriptorList::AddDescriptor(RawPcDescriptors::Kind kind,
                                    intptr_t pc_offset,
                                    intptr_t deopt_id,
-                                   intptr_t token_pos,
+                                   TokenPosition token_pos,
                                    intptr_t try_index) {
   ASSERT((kind == RawPcDescriptors::kRuntimeCall) ||
          (kind == RawPcDescriptors::kOther) ||
          (deopt_id != Thread::kNoDeoptId));
 
-  intptr_t merged_kind_try =
-      RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
+  // When precompiling, we only use pc descriptors for exceptions.
+  if (!FLAG_precompiled_mode || try_index != -1) {
+    intptr_t merged_kind_try =
+        RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
 
-  PcDescriptors::EncodeInteger(&encoded_data_, merged_kind_try);
-  PcDescriptors::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
-  PcDescriptors::EncodeInteger(&encoded_data_, deopt_id - prev_deopt_id);
-  PcDescriptors::EncodeInteger(&encoded_data_, token_pos - prev_token_pos);
+    PcDescriptors::EncodeInteger(&encoded_data_, merged_kind_try);
+    PcDescriptors::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
+    PcDescriptors::EncodeInteger(&encoded_data_, deopt_id - prev_deopt_id);
+    PcDescriptors::EncodeInteger(&encoded_data_,
+                                 token_pos.value() - prev_token_pos);
 
-  prev_pc_offset = pc_offset;
-  prev_deopt_id = deopt_id;
-  prev_token_pos = token_pos;
+    prev_pc_offset = pc_offset;
+    prev_deopt_id = deopt_id;
+    prev_token_pos = token_pos.value();
+  }
 }
 
 
 RawPcDescriptors* DescriptorList::FinalizePcDescriptors(uword entry_point) {
+  if (encoded_data_.length() == 0) {
+    return Object::empty_descriptors().raw();
+  }
   return PcDescriptors::New(&encoded_data_);
 }
 
 
+
+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);
+
+  prev_pc_offset = pc_offset;
+  prev_token_pos = token_pos.value();
+}
+
+
+RawCodeSourceMap* CodeSourceMapBuilder::Finalize() {
+  return CodeSourceMap::New(&encoded_data_);
+}
+
+
 void StackmapTableBuilder::AddEntry(intptr_t pc_offset,
                                     BitmapBuilder* bitmap,
                                     intptr_t register_bit_count) {
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index e24e186..c5eeda7 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -26,7 +26,7 @@
   void AddDescriptor(RawPcDescriptors::Kind kind,
                      intptr_t pc_offset,
                      intptr_t deopt_id,
-                     intptr_t token_pos,
+                     TokenPosition token_pos,
                      intptr_t try_index);
 
   RawPcDescriptors* FinalizePcDescriptors(uword entry_point);
@@ -42,6 +42,29 @@
 };
 
 
+class CodeSourceMapBuilder : public ZoneAllocated {
+ public:
+  explicit CodeSourceMapBuilder(intptr_t initial_capacity = 64)
+    : encoded_data_(initial_capacity),
+      prev_pc_offset(0),
+      prev_token_pos(0) {}
+
+  ~CodeSourceMapBuilder() { }
+
+  void AddEntry(intptr_t pc_offset, TokenPosition token_pos);
+
+  RawCodeSourceMap* Finalize();
+
+ private:
+  GrowableArray<uint8_t> encoded_data_;
+
+  intptr_t prev_pc_offset;
+  intptr_t prev_token_pos;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeSourceMapBuilder);
+};
+
+
 class StackmapTableBuilder : public ZoneAllocated {
  public:
   StackmapTableBuilder()
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 2586a97..5f8bb1d 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -18,7 +18,7 @@
 
 namespace dart {
 
-static const intptr_t kPos = Scanner::kNoSourcePos;
+static const TokenPosition kPos = TokenPosition::kNoSource;
 
 
 CODEGEN_TEST_GENERATE(StackmapCodegen, test) {
@@ -178,7 +178,10 @@
   EXPECT_EQ(10, value);
   EXPECT_VALID(Dart_IntegerToInt64(k, &value));
   EXPECT_EQ(20, value);
-  Isolate::Current()->heap()->CollectAllGarbage();
+  {
+    TransitionNativeToVM transition(Thread::Current());
+    Isolate::Current()->heap()->CollectAllGarbage();
+  }
 }
 
 
@@ -211,6 +214,8 @@
       "}\n";
   // First setup the script and compile the script.
   TestCase::LoadTestScript(kScriptChars, native_resolver);
+  TransitionNativeToVM transition(thread);
+
   EXPECT(ClassFinalizer::ProcessPendingClasses());
   const String& name = String::Handle(String::New(TestCase::url()));
   const Library& lib = Library::Handle(Library::LookupLibrary(name));
@@ -248,7 +253,8 @@
   const PcDescriptors& descriptors =
       PcDescriptors::Handle(code.pc_descriptors());
   int call_count = 0;
-  PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kUnoptStaticCall);
+  PcDescriptors::Iterator iter(descriptors,
+                               RawPcDescriptors::kUnoptStaticCall);
   while (iter.MoveNext()) {
     stackmap_table_builder->AddEntry(iter.PcOffset(), stack_bitmap, 0);
     ++call_count;
@@ -268,4 +274,100 @@
   EXPECT(!result.IsError());
 }
 
+
+TEST_CASE(DescriptorList_TokenPositions) {
+  DescriptorList* descriptors = new DescriptorList(64);
+  ASSERT(descriptors != NULL);
+  const intptr_t token_positions[] = {
+    kMinInt32,
+    5,
+    13,
+    13,
+    13,
+    13,
+    31,
+    23,
+    23,
+    23,
+    33,
+    33,
+    5,
+    5,
+    TokenPosition::kMinSourcePos,
+    TokenPosition::kMaxSourcePos,
+  };
+  const intptr_t num_token_positions =
+      sizeof(token_positions) / sizeof(token_positions[0]);
+
+  for (intptr_t i = 0; i < num_token_positions; i++) {
+    descriptors->AddDescriptor(RawPcDescriptors::kRuntimeCall, 0, 0,
+                               TokenPosition(token_positions[i]), 0);
+  }
+
+  const PcDescriptors& finalized_descriptors =
+      PcDescriptors::Handle(descriptors->FinalizePcDescriptors(0));
+
+  ASSERT(!finalized_descriptors.IsNull());
+  PcDescriptors::Iterator it(finalized_descriptors,
+                             RawPcDescriptors::kRuntimeCall);
+
+  intptr_t i = 0;
+  while (it.MoveNext()) {
+    if (token_positions[i] != it.TokenPos().value()) {
+      OS::Print("[%" Pd "]: Expected: %" Pd " != %" Pd "\n",
+                i, token_positions[i], it.TokenPos().value());
+    }
+    EXPECT(token_positions[i] == it.TokenPos().value());
+    i++;
+  }
+}
+
+
+TEST_CASE(CodeSourceMap_TokenPositions) {
+  const intptr_t token_positions[] = {
+    kMinInt32,
+    5,
+    13,
+    13,
+    13,
+    13,
+    31,
+    23,
+    23,
+    23,
+    33,
+    33,
+    5,
+    5,
+    TokenPosition::kMinSourcePos,
+    TokenPosition::kMaxSourcePos,
+  };
+  const intptr_t num_token_positions =
+      sizeof(token_positions) / sizeof(token_positions[0]);
+
+  CodeSourceMapBuilder* builder = new CodeSourceMapBuilder();
+  ASSERT(builder != NULL);
+
+  for (intptr_t i = 0; i < num_token_positions; i++) {
+    builder->AddEntry(i, TokenPosition(token_positions[i]));
+  }
+
+  const CodeSourceMap& code_Source_map =
+      CodeSourceMap::Handle(builder->Finalize());
+
+  ASSERT(!code_Source_map.IsNull());
+  CodeSourceMap::Iterator it(code_Source_map);
+
+  uintptr_t i = 0;
+  while (it.MoveNext()) {
+    EXPECT(it.PcOffset() == i);
+    if (token_positions[i] != it.TokenPos().value()) {
+      OS::Print("[%" Pd "]: Expected: %" Pd " != %" Pd "\n",
+                i, token_positions[i], it.TokenPos().value());
+    }
+    EXPECT(token_positions[i] == it.TokenPos().value());
+    i++;
+  }
+}
+
 }  // namespace dart
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index d7c92d7..758c2e0 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -13,11 +13,11 @@
 #include "vm/debugger.h"
 #include "vm/deopt_instructions.h"
 #include "vm/exceptions.h"
+#include "vm/flags.h"
 #include "vm/object_store.h"
 #include "vm/message.h"
 #include "vm/message_handler.h"
 #include "vm/parser.h"
-#include "vm/report.h"
 #include "vm/resolver.h"
 #include "vm/runtime_entry.h"
 #include "vm/stack_frame.h"
@@ -27,15 +27,8 @@
 
 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");
@@ -61,21 +54,16 @@
 DECLARE_FLAG(bool, enable_inlining_annotations);
 DECLARE_FLAG(bool, trace_compiler);
 DECLARE_FLAG(bool, trace_optimizing_compiler);
-DECLARE_FLAG(bool, warn_on_javascript_compatibility);
 DECLARE_FLAG(int, max_polymorphic_checks);
 
-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");
-DEFINE_FLAG(bool, lazy_dispatchers, true, "Lazily generate dispatchers");
 
 #ifdef DEBUG
 DEFINE_FLAG(charp, gc_at_instance_allocation, NULL,
@@ -147,7 +135,7 @@
 
 
 // Helper returning the token position of the Dart caller.
-static intptr_t GetCallerLocation() {
+static TokenPosition GetCallerLocation() {
   DartFrameIterator iterator;
   StackFrame* caller_frame = iterator.NextFrame();
   ASSERT(caller_frame != NULL);
@@ -204,10 +192,11 @@
   ASSERT(!type.IsNull() && !type.IsInstantiated());
   ASSERT(instantiator.IsNull() || instantiator.IsInstantiated());
   Error& bound_error = Error::Handle();
-  type = type.InstantiateFrom(instantiator, &bound_error);
+  type =
+      type.InstantiateFrom(instantiator, &bound_error, NULL, NULL, Heap::kOld);
   if (!bound_error.IsNull()) {
     // Throw a dynamic type error.
-    const intptr_t location = GetCallerLocation();
+    const TokenPosition location = GetCallerLocation();
     String& bound_error_message =  String::Handle(
         String::New(bound_error.ToErrorCString()));
     Exceptions::CreateAndThrowTypeError(
@@ -239,14 +228,14 @@
   // 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,
                                                       &bound_error);
     if (!bound_error.IsNull()) {
       // Throw a dynamic type error.
-      const intptr_t location = GetCallerLocation();
+      const TokenPosition location = GetCallerLocation();
       String& bound_error_message =  String::Handle(
           String::New(bound_error.ToErrorCString()));
       Exceptions::CreateAndThrowTypeError(
@@ -300,7 +289,7 @@
   StackFrame* caller_frame = iterator.NextFrame();
   ASSERT(caller_frame != NULL);
 
-  const Type& instance_type = Type::Handle(instance.GetType());
+  const AbstractType& instance_type = AbstractType::Handle(instance.GetType());
   ASSERT(instance_type.IsInstantiated());
   if (type.IsInstantiated()) {
     OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n",
@@ -315,7 +304,8 @@
     // Instantiate type before printing.
     Error& bound_error = Error::Handle();
     const AbstractType& instantiated_type = AbstractType::Handle(
-        type.InstantiateFrom(instantiator_type_arguments, &bound_error));
+        type.InstantiateFrom(instantiator_type_arguments, &bound_error,
+                             NULL, NULL, Heap::kOld));
     OS::PrintErr("%s: '%s' %s '%s' instantiated from '%s' (pc: %#" Px ").\n",
                  message,
                  String::Handle(instance_type.Name()).ToCString(),
@@ -334,10 +324,10 @@
 
 
 // This updates the type test cache, an array containing 4-value elements
-// (instance class, instance type arguments, instantiator type arguments and
-// test_result). It can be applied to classes with type arguments in which
-// case it contains just the result of the class subtype test, not including
-// the evaluation of type arguments.
+// (instance class (or function if the instance is a closure), instance type
+// arguments, instantiator type arguments and test_result). It can be applied to
+// classes with type arguments in which case it contains just the result of the
+// class subtype test, not including the evaluation of type arguments.
 // This operation is currently very slow (lookup of code is not efficient yet).
 static void UpdateTypeTestCache(
     const Instance& instance,
@@ -360,11 +350,16 @@
     }
     return;
   }
-  TypeArguments& instance_type_arguments =
-      TypeArguments::Handle();
   const Class& instance_class = Class::Handle(instance.clazz());
-
-  if (instance_class.NumTypeArguments() > 0) {
+  Object& instance_class_id_or_function = Object::Handle();
+  if (instance_class.IsClosureClass()) {
+    instance_class_id_or_function = Closure::Cast(instance).function();
+  } else {
+    instance_class_id_or_function = Smi::New(instance_class.id());
+  }
+  TypeArguments& instance_type_arguments = TypeArguments::Handle();
+  if (instance_class.IsClosureClass() ||
+      (instance_class.NumTypeArguments() > 0)) {
     instance_type_arguments = instance.GetTypeArguments();
   }
 
@@ -377,20 +372,19 @@
          instance_type_arguments.IsCanonical());
   ASSERT(instantiator_type_arguments.IsNull() ||
          instantiator_type_arguments.IsCanonical());
-  intptr_t last_instance_class_id = -1;
-  TypeArguments& last_instance_type_arguments =
-      TypeArguments::Handle();
-  TypeArguments& last_instantiator_type_arguments =
-      TypeArguments::Handle();
+  Object& last_instance_class_id_or_function = Object::Handle();
+  TypeArguments& last_instance_type_arguments = TypeArguments::Handle();
+  TypeArguments& last_instantiator_type_arguments = TypeArguments::Handle();
   Bool& last_result = Bool::Handle();
   for (intptr_t i = 0; i < len; ++i) {
     new_cache.GetCheck(
         i,
-        &last_instance_class_id,
+        &last_instance_class_id_or_function,
         &last_instance_type_arguments,
         &last_instantiator_type_arguments,
         &last_result);
-    if ((last_instance_class_id == instance_class.id()) &&
+    if ((last_instance_class_id_or_function.raw() ==
+         instance_class_id_or_function.raw()) &&
         (last_instance_type_arguments.raw() == instance_type_arguments.raw()) &&
         (last_instantiator_type_arguments.raw() ==
          instantiator_type_arguments.raw())) {
@@ -402,7 +396,7 @@
     }
   }
 #endif
-  new_cache.AddCheck(instance_class.id(),
+  new_cache.AddCheck(instance_class_id_or_function,
                      instance_type_arguments,
                      instantiator_type_arguments,
                      result);
@@ -411,17 +405,18 @@
     if (!test_type.IsInstantiated()) {
       Error& bound_error = Error::Handle();
       test_type = type.InstantiateFrom(instantiator_type_arguments,
-                                       &bound_error);
+                                       &bound_error,
+                                       NULL, NULL, Heap::kNew);
       ASSERT(bound_error.IsNull());  // Malbounded types are not optimized.
     }
     OS::PrintErr("  Updated test cache %p ix: %" Pd " with "
-        "(cid: %" Pd ", type-args: %p, instantiator: %p, result: %s)\n"
+        "(cid-or-fun: %p, type-args: %p, instantiator: %p, result: %s)\n"
         "    instance  [class: (%p '%s' cid: %" Pd "),    type-args: %p %s]\n"
         "    test-type [class: (%p '%s' cid: %" Pd "), in-type-args: %p %s]\n",
         new_cache.raw(),
         len,
 
-        instance_class.id(),
+        instance_class_id_or_function.raw(),
         instance_type_arguments.raw(),
         instantiator_type_arguments.raw(),
         result.ToCString(),
@@ -471,7 +466,7 @@
   }
   if (!result.value() && !bound_error.IsNull()) {
     // Throw a dynamic type error only if the instanceof test fails.
-    const intptr_t location = GetCallerLocation();
+    const TokenPosition location = GetCallerLocation();
     String& bound_error_message =  String::Handle(
         String::New(bound_error.ToErrorCString()));
     Exceptions::CreateAndThrowTypeError(
@@ -495,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));
@@ -518,42 +512,24 @@
   }
   if (!is_instance_of) {
     // Throw a dynamic type error.
-    const intptr_t location = GetCallerLocation();
+    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));
-      // 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);
@@ -571,7 +547,7 @@
 // Arg0: bad object.
 // Return value: none, throws TypeError or AssertionError.
 DEFINE_RUNTIME_ENTRY(NonBoolTypeError, 1) {
-  const intptr_t location = GetCallerLocation();
+  const TokenPosition location = GetCallerLocation();
   const Instance& src_instance = Instance::CheckedHandle(arguments.ArgAt(0));
 
   if (src_instance.IsNull()) {
@@ -608,7 +584,7 @@
 // Arg2: type of destination being assigned to.
 // Return value: none, throws an exception.
 DEFINE_RUNTIME_ENTRY(BadTypeError, 3) {
-  const intptr_t location = GetCallerLocation();
+  const TokenPosition location = GetCallerLocation();
   const Instance& src_value = Instance::CheckedHandle(arguments.ArgAt(0));
   const String& dst_name = String::CheckedHandle(arguments.ArgAt(1));
   const AbstractType& dst_type =
@@ -700,6 +676,10 @@
 // Gets called from debug stub when code reaches a breakpoint
 // set on a runtime stub call.
 DEFINE_RUNTIME_ENTRY(BreakpointRuntimeHandler, 0) {
+  if (!FLAG_support_debugger) {
+    UNREACHABLE();
+    return;
+  }
   DartFrameIterator iterator;
   StackFrame* caller_frame = iterator.NextFrame();
   ASSERT(caller_frame != NULL);
@@ -715,6 +695,10 @@
 
 
 DEFINE_RUNTIME_ENTRY(SingleStepHandler, 0) {
+  if (!FLAG_support_debugger) {
+    UNREACHABLE();
+    return;
+  }
   const Error& error =
       Error::Handle(isolate->debugger()->DebuggerStepCallback());
   if (!error.IsNull()) {
@@ -745,15 +729,8 @@
   if (getter.IsNull() || getter.IsMethodExtractor()) {
     return false;
   }
-  const Class& cache_class = Class::Handle(receiver_class.IsSignatureClass()
-      ? receiver_class.SuperClass()
-      : receiver_class.raw());
-  ASSERT(
-      !receiver_class.IsSignatureClass() ||
-      (receiver_class.SuperClass() == Type::Handle(
-       Isolate::Current()->object_store()->function_impl_type()).type_class()));
   const Function& target_function =
-      Function::Handle(cache_class.GetInvocationDispatcher(
+      Function::Handle(receiver_class.GetInvocationDispatcher(
           target_name,
           arguments_descriptor,
           RawFunction::kInvokeFieldDispatcher,
@@ -877,18 +854,6 @@
   const ICData& ic_data = ICData::CheckedHandle(arguments.ArgAt(1));
   GrowableArray<const Instance*> args(1);
   args.Add(&receiver);
-  if (FLAG_warn_on_javascript_compatibility) {
-    if (receiver.IsDouble() &&
-        String::Handle(ic_data.target_name()).Equals(Symbols::toString())) {
-      const double value = Double::Cast(receiver).value();
-      if (floor(value) == value) {
-        Report::JSWarningFromIC(ic_data,
-                                "string representation of an integral value "
-                                "of type 'double' has no decimal mark and "
-                                "no fractional part");
-      }
-    }
-  }
   const Function& result =
       Function::Handle(InlineCacheMissHandler(args, ic_data));
   arguments.SetReturn(result);
@@ -1223,15 +1188,14 @@
 // Arg1: arguments descriptor array.
 // Arg2: arguments array.
 DEFINE_RUNTIME_ENTRY(InvokeClosureNoSuchMethod, 3) {
-  const Instance& receiver = Instance::CheckedHandle(arguments.ArgAt(0));
+  const Closure& receiver = Closure::CheckedHandle(arguments.ArgAt(0));
   const Array& orig_arguments_desc = Array::CheckedHandle(arguments.ArgAt(1));
   const Array& orig_arguments = Array::CheckedHandle(arguments.ArgAt(2));
 
   // For closure the function name is always 'call'. Replace it with the
   // name of the closurized function so that exception contains more
   // relevant information.
-  ASSERT(receiver.IsClosure());
-  const Function& function = Function::Handle(Closure::function(receiver));
+  const Function& function = Function::Handle(receiver.function());
   const String& original_function_name =
       String::Handle(function.QualifiedUserVisibleName());
   const Object& result = Object::Handle(
@@ -1245,13 +1209,15 @@
 
 
 static bool CanOptimizeFunction(const Function& function, Thread* thread) {
-  Isolate* isolate = thread->isolate();
-  if (isolate->debugger()->IsStepping() ||
-      isolate->debugger()->HasBreakpoint(function, thread->zone())) {
-    // We cannot set breakpoints and single step in optimized code,
-    // so do not optimize the function.
-    function.set_usage_counter(0);
-    return false;
+  if (FLAG_support_debugger) {
+    Isolate* isolate = thread->isolate();
+    if (isolate->debugger()->IsStepping() ||
+        isolate->debugger()->HasBreakpoint(function, thread->zone())) {
+      // We cannot set breakpoints and single step in optimized code,
+      // so do not optimize the function.
+      function.set_usage_counter(0);
+      return false;
+    }
   }
   if (function.deoptimization_counter() >=
       FLAG_max_deoptimization_counter_threshold) {
@@ -1374,17 +1340,17 @@
     // TODO(turnidge): Consider using DeoptimizeAt instead.
     DeoptimizeFunctionsOnStack();
   }
-  if (do_stacktrace) {
+  if (FLAG_support_debugger && do_stacktrace) {
     String& var_name = String::Handle();
     Instance& var_value = Instance::Handle();
     DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
     intptr_t num_frames = stack->Length();
     for (intptr_t i = 0; i < num_frames; i++) {
       ActivationFrame* frame = stack->FrameAt(i);
-      // Variable locations and number are unknown when 'always_optimize'.
+      // Variable locations and number are unknown when precompiling.
       const int num_vars =
-         Compiler::always_optimize() ? 0 : frame->NumLocalVariables();
-      intptr_t unused;
+         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);
       }
@@ -1475,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());
@@ -1482,6 +1449,19 @@
 
   if (CanOptimizeFunction(function, thread)) {
     if (FLAG_background_compilation) {
+      Field& field = Field::Handle(zone, isolate->GetDeoptimizingBoxedField());
+      while (!field.IsNull()) {
+        if (FLAG_trace_optimization || FLAG_trace_field_guards) {
+          THR_Print("Lazy disabling unboxing of %s\n", field.ToCString());
+        }
+        field.set_is_unboxing_candidate(false);
+        field.DeoptimizeDependentCode();
+        // Get next field.
+        field = isolate->GetDeoptimizingBoxedField();
+      }
+    }
+    // TODO(srdjan): Fix background compilation of regular expressions.
+    if (FLAG_background_compilation) {
       if (FLAG_enable_inlining_annotations) {
         FATAL("Cannot enable inlining annotations and background compilation");
       }
@@ -1516,6 +1496,9 @@
     ASSERT(!optimized_code.IsNull());
   }
   arguments.SetReturn(Code::Handle(zone, function.CurrentCode()));
+#else
+  UNREACHABLE();
+#endif  // !DART_PRECOMPILED_RUNTIME
 }
 
 
@@ -1539,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));
@@ -1550,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());
@@ -1560,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);
 }
@@ -1573,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);
@@ -1608,6 +1587,9 @@
         alloc_stub.EntryPoint());
   }
   arguments.SetReturn(alloc_stub);
+#else
+  UNREACHABLE();
+#endif
 }
 
 
@@ -1680,7 +1662,7 @@
   }
 }
 
-
+#if !defined(DART_PRECOMPILED_RUNTIME)
 static void CopySavedRegisters(uword saved_registers_address,
                                fpu_register_t** fpu_registers,
                                intptr_t** cpu_registers) {
@@ -1705,6 +1687,7 @@
   }
   *cpu_registers = cpu_registers_copy;
 }
+#endif
 
 
 // Copies saved registers and caller's frame into temporary buffers.
@@ -1716,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);
@@ -1762,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
 
@@ -1769,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);
@@ -1803,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
 
@@ -1813,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);
@@ -1821,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/code_generator_test.cc b/runtime/vm/code_generator_test.cc
index bea6025..e3c33a5 100644
--- a/runtime/vm/code_generator_test.cc
+++ b/runtime/vm/code_generator_test.cc
@@ -20,7 +20,7 @@
 
 namespace dart {
 
-static const intptr_t kPos = 0;
+static const TokenPosition kPos = TokenPosition::kMinSource;
 
 
 CODEGEN_TEST_GENERATE(SimpleReturnCodegen, test) {
diff --git a/runtime/vm/code_observers.cc b/runtime/vm/code_observers.cc
index 331a4be..ec47c8f 100644
--- a/runtime/vm/code_observers.cc
+++ b/runtime/vm/code_observers.cc
@@ -10,6 +10,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 Mutex* CodeObservers::mutex_ = NULL;
 intptr_t CodeObservers::observers_length_ = 0;
 CodeObserver** CodeObservers::observers_ = NULL;
@@ -66,4 +68,6 @@
 }
 
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/code_observers.h b/runtime/vm/code_observers.h
index 2e857f7..1ce8135 100644
--- a/runtime/vm/code_observers.h
+++ b/runtime/vm/code_observers.h
@@ -10,6 +10,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 class Mutex;
 
 // Object observing code creation events. Used by external profilers and
@@ -65,6 +67,7 @@
   static CodeObserver** observers_;
 };
 
+#endif  // !PRODUCT
 
 }  // namespace dart
 
diff --git a/runtime/vm/code_patcher_arm64_test.cc b/runtime/vm/code_patcher_arm64_test.cc
index bb7008a..32d8ada 100644
--- a/runtime/vm/code_patcher_arm64_test.cc
+++ b/runtime/vm/code_patcher_arm64_test.cc
@@ -23,12 +23,13 @@
 ASSEMBLER_TEST_GENERATE(IcDataAccess, assembler) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index f9a3f42..06b9f8c 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -23,12 +23,13 @@
 ASSEMBLER_TEST_GENERATE(IcDataAccess, assembler) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index a9c62f4..26fe49f 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -23,12 +23,13 @@
 ASSEMBLER_TEST_GENERATE(IcDataAccess, assembler) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_mips_test.cc b/runtime/vm/code_patcher_mips_test.cc
index 78e698b..e99a987 100644
--- a/runtime/vm/code_patcher_mips_test.cc
+++ b/runtime/vm/code_patcher_mips_test.cc
@@ -23,12 +23,13 @@
 ASSEMBLER_TEST_GENERATE(IcDataAccess, assembler) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index ca98231..13d2978 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -23,12 +23,13 @@
 ASSEMBLER_TEST_GENERATE(IcDataAccess, assembler) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::Handle(Symbols::New("callerFunction"));
   const Function& function = Function::Handle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const Array& args_descriptor =
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 70d1ac6..dd2ddee 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -8,6 +8,7 @@
 
 #include "vm/ast_printer.h"
 #include "vm/block_scheduler.h"
+#include "vm/branch_optimizer.h"
 #include "vm/cha.h"
 #include "vm/code_generator.h"
 #include "vm/code_patcher.h"
@@ -15,6 +16,7 @@
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
 #include "vm/deopt_instructions.h"
+#include "vm/disassembler.h"
 #include "vm/exceptions.h"
 #include "vm/flags.h"
 #include "vm/flow_graph.h"
@@ -22,17 +24,19 @@
 #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"
 #include "vm/os.h"
 #include "vm/parser.h"
+#include "vm/precompiler.h"
+#include "vm/redundancy_elimination.h"
 #include "vm/regexp_parser.h"
 #include "vm/regexp_assembler.h"
-#include "vm/scanner.h"
 #include "vm/symbols.h"
 #include "vm/tags.h"
 #include "vm/thread_registry.h"
@@ -48,8 +52,6 @@
     "Do conditional constant propagation/unreachable code elimination.");
 DEFINE_FLAG(int, max_deoptimization_counter_threshold, 16,
     "How many times we allow deoptimization before we disallow optimization.");
-DEFINE_FLAG(bool, disassemble, false, "Disassemble dart code.");
-DEFINE_FLAG(bool, disassemble_optimized, false, "Disassemble optimized code.");
 DEFINE_FLAG(bool, loop_invariant_code_motion, true,
     "Do loop invariant code motion.");
 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph.");
@@ -57,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.");
@@ -66,107 +69,73 @@
 DEFINE_FLAG(bool, use_inlining, true, "Enable call-site inlining");
 DEFINE_FLAG(bool, verify_compiler, false,
     "Enable compiler verification assertions");
-DEFINE_FLAG(int, max_speculative_inlining_attempts, 1,
-    "Max number of attempts with speculative inlining (precompilation only)");
 
-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_inlining_intervals);
 DECLARE_FLAG(bool, trace_irregexp);
 
 
-bool Compiler::always_optimize_ = false;
-bool Compiler::allow_recompilation_ = true;
+#ifndef DART_PRECOMPILED_RUNTIME
 
-#ifndef DART_PRECOMPILED
-
-// TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove
-// separate helpers functions & `optimizing` args.
-class CompilationPipeline : public ZoneAllocated {
- public:
-  static CompilationPipeline* New(Zone* zone, const Function& function);
-
-  virtual void ParseFunction(ParsedFunction* parsed_function) = 0;
-  virtual FlowGraph* BuildFlowGraph(
-      Zone* zone,
-      ParsedFunction* parsed_function,
-      const ZoneGrowableArray<const ICData*>& ic_data_array,
-      intptr_t osr_id) = 0;
-  virtual void FinalizeCompilation() = 0;
-  virtual ~CompilationPipeline() { }
-};
+void DartCompilationPipeline::ParseFunction(ParsedFunction* parsed_function) {
+  Parser::ParseFunction(parsed_function);
+  parsed_function->AllocateVariables();
+}
 
 
-class DartCompilationPipeline : public CompilationPipeline {
- public:
-  virtual void ParseFunction(ParsedFunction* parsed_function) {
-    Parser::ParseFunction(parsed_function);
-    parsed_function->AllocateVariables();
-  }
+FlowGraph* DartCompilationPipeline::BuildFlowGraph(
+    Zone* zone,
+    ParsedFunction* parsed_function,
+    const ZoneGrowableArray<const ICData*>& ic_data_array,
+    intptr_t osr_id) {
+  // Build the flow graph.
+  FlowGraphBuilder builder(*parsed_function,
+                           ic_data_array,
+                           NULL,  // NULL = not inlining.
+                           osr_id);
 
-  virtual FlowGraph* BuildFlowGraph(
-      Zone* zone,
-      ParsedFunction* parsed_function,
-      const ZoneGrowableArray<const ICData*>& ic_data_array,
-      intptr_t osr_id) {
-    // Build the flow graph.
-    FlowGraphBuilder builder(*parsed_function,
-                             ic_data_array,
-                             NULL,  // NULL = not inlining.
-                             osr_id);
-
-    return builder.BuildGraph();
-  }
-
-  virtual void FinalizeCompilation() { }
-};
+  return builder.BuildGraph();
+}
 
 
-class IrregexpCompilationPipeline : public CompilationPipeline {
- public:
-  IrregexpCompilationPipeline() : backtrack_goto_(NULL) { }
+void DartCompilationPipeline::FinalizeCompilation() { }
 
-  virtual void ParseFunction(ParsedFunction* parsed_function) {
-    RegExpParser::ParseFunction(parsed_function);
-    // Variables are allocated after compilation.
-  }
 
-  virtual FlowGraph* BuildFlowGraph(
-      Zone* zone,
-      ParsedFunction* parsed_function,
-      const ZoneGrowableArray<const ICData*>& ic_data_array,
-      intptr_t osr_id) {
-    // Compile to the dart IR.
-    RegExpEngine::CompilationResult result =
-        RegExpEngine::CompileIR(parsed_function->regexp_compile_data(),
-                                parsed_function,
-                                ic_data_array);
-    backtrack_goto_ = result.backtrack_goto;
+void IrregexpCompilationPipeline::ParseFunction(
+    ParsedFunction* parsed_function) {
+  RegExpParser::ParseFunction(parsed_function);
+  // Variables are allocated after compilation.
+}
 
-    // Allocate variables now that we know the number of locals.
-    parsed_function->AllocateIrregexpVariables(result.num_stack_locals);
+FlowGraph* IrregexpCompilationPipeline::BuildFlowGraph(
+    Zone* zone,
+    ParsedFunction* parsed_function,
+    const ZoneGrowableArray<const ICData*>& ic_data_array,
+    intptr_t osr_id) {
+  // Compile to the dart IR.
+  RegExpEngine::CompilationResult result =
+      RegExpEngine::CompileIR(parsed_function->regexp_compile_data(),
+                              parsed_function,
+                              ic_data_array);
+  backtrack_goto_ = result.backtrack_goto;
 
-    // Build the flow graph.
-    FlowGraphBuilder builder(*parsed_function,
-                             ic_data_array,
-                             NULL,  // NULL = not inlining.
-                             osr_id);
+  // Allocate variables now that we know the number of locals.
+  parsed_function->AllocateIrregexpVariables(result.num_stack_locals);
 
-    return new(zone) FlowGraph(*parsed_function,
-                               result.graph_entry,
-                               result.num_blocks);
-  }
+  // Build the flow graph.
+  FlowGraphBuilder builder(*parsed_function,
+                           ic_data_array,
+                           NULL,  // NULL = not inlining.
+                           osr_id);
 
-  virtual void FinalizeCompilation() {
-    backtrack_goto_->ComputeOffsetTable();
-  }
+  return new(zone) FlowGraph(*parsed_function,
+                             result.graph_entry,
+                             result.num_blocks);
+}
 
- private:
-  IndirectGotoInstr* backtrack_goto_;
-};
-
+void IrregexpCompilationPipeline::FinalizeCompilation() {
+  backtrack_goto_->ComputeOffsetTable();
+}
 
 CompilationPipeline* CompilationPipeline::New(Zone* zone,
                                               const Function& function) {
@@ -213,11 +182,10 @@
     return Error::null();
   } else {
     Thread* const thread = Thread::Current();
-    Isolate* const isolate = thread->isolate();
     StackZone zone(thread);
     Error& error = Error::Handle();
-    error = isolate->object_store()->sticky_error();
-    isolate->object_store()->clear_sticky_error();
+    error = thread->sticky_error();
+    thread->clear_sticky_error();
     return error.raw();
   }
   UNREACHABLE();
@@ -282,14 +250,13 @@
   if (cls.is_marked_for_parsing()) {
     return Error::null();
   }
-  // If the class is a signature class there is no need to try and
+  // If the class is a typedef class there is no need to try and
   // compile it. Just finalize it directly.
-  if (cls.IsSignatureClass()) {
+  if (cls.IsTypedefClass()) {
 #if defined(DEBUG)
-    const Type& type = Type::Handle(
-        Isolate::Current()->object_store()->function_impl_type());
-    const Class& type_cls = Class::Handle(type.type_class());
-    ASSERT(type_cls.is_finalized());
+    const Class& closure_cls = Class::Handle(
+        Isolate::Current()->object_store()->closure_class());
+    ASSERT(closure_cls.is_finalized());
 #endif
     LongJumpScope jump;
     if (setjmp(*jump.Set()) == 0) {
@@ -297,20 +264,16 @@
       return Error::null();
     } else {
       Thread* thread = Thread::Current();
-      Isolate* isolate = thread->isolate();
       Error& error = Error::Handle(thread->zone());
-      error = isolate->object_store()->sticky_error();
-      isolate->object_store()->clear_sticky_error();
+      error = thread->sticky_error();
+      thread->clear_sticky_error();
       return error.raw();
     }
   }
 
   Thread* const thread = Thread::Current();
-  Isolate* const isolate = thread->isolate();
   StackZone zone(thread);
-  // We remember all the classes that are being compiled in these lists. This
-  // also allows us to reset the marked_for_parsing state in case we see an
-  // error.
+NOT_IN_PRODUCT(
   VMTagScope tagScope(thread, VMTag::kCompileClassTagId);
   TimelineDurationScope tds(thread,
                             thread->isolate()->GetCompilerStream(),
@@ -319,7 +282,11 @@
     tds.SetNumArguments(1);
     tds.CopyArgument(0, "class", cls.ToCString());
   }
+)  // !PRODUCT
 
+  // We remember all the classes that are being compiled in these lists. This
+  // also allows us to reset the marked_for_parsing state in case we see an
+  // error.
   GrowableHandlePtrArray<const Class> parse_list(thread->zone(), 4);
   GrowableHandlePtrArray<const Class> patch_list(thread->zone(), 4);
 
@@ -390,8 +357,8 @@
       }
     }
     Error& error = Error::Handle(zone.GetZone());
-    error = isolate->object_store()->sticky_error();
-    isolate->object_store()->clear_sticky_error();
+    error = thread->sticky_error();
+    thread->clear_sticky_error();
     return error.raw();
   }
   UNREACHABLE();
@@ -451,6 +418,7 @@
     Assembler* assembler,
     FlowGraphCompiler* graph_compiler,
     FlowGraph* flow_graph) {
+  ASSERT(!FLAG_precompiled_mode);
   const Function& function = parsed_function()->function();
   Zone* const zone = thread()->zone();
 
@@ -490,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);
 
@@ -498,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()) {
@@ -519,7 +505,7 @@
           }
         }
       }
-      if (!flow_graph->guarded_fields()->is_empty()) {
+      if (!flow_graph->parsed_function().guarded_fields()->is_empty()) {
         if (field_invalidation_gen_at_start() !=
             isolate()->field_invalidation_gen()) {
           code_is_valid = false;
@@ -551,33 +537,19 @@
     // Register code with the classes it depends on because of CHA and
     // fields it depends on because of store guards, unless we cannot
     // deopt.
-    if (Compiler::allow_recompilation()) {
-      // Deoptimize field dependent code first, before registering
-      // this yet uninstalled code as dependent on a field.
-      // TODO(srdjan): Debugging dart2js crashes;
-      // FlowGraphOptimizer::VisitStoreInstanceField populates
-      // deoptimize_dependent_code() list, currently disabled.
-      for (intptr_t i = 0;
-           i < flow_graph->deoptimize_dependent_code().length();
-           i++) {
-        const Field* field = flow_graph->deoptimize_dependent_code()[i];
-        field->DeoptimizeDependentCode();
-      }
-      for (intptr_t i = 0;
-           i < thread()->cha()->leaf_classes().length();
-           ++i) {
-        thread()->cha()->leaf_classes()[i]->RegisterCHACode(code);
-      }
-      for (intptr_t i = 0;
-           i < flow_graph->guarded_fields()->length();
-           i++) {
-        const Field* field = (*flow_graph->guarded_fields())[i];
-        field->RegisterDependentCode(code);
-      }
+    for (intptr_t i = 0;
+         i < thread()->cha()->leaf_classes().length();
+         ++i) {
+      thread()->cha()->leaf_classes()[i]->RegisterCHACode(code);
+    }
+    const ZoneGrowableArray<const Field*>& guarded_fields =
+        *flow_graph->parsed_function().guarded_fields();
+    for (intptr_t i = 0; i < guarded_fields.length(); i++) {
+      const Field* field = guarded_fields[i];
+      field->RegisterDependentCode(code);
     }
   } else {  // not optimized.
-    if (!Compiler::always_optimize() &&
-        (function.ic_data_array() == Array::null())) {
+    if (function.ic_data_array() == Array::null()) {
       function.SaveICDataMap(
           graph_compiler->deopt_id_to_ic_data(),
           Array::Handle(zone, graph_compiler->edge_counters_array()));
@@ -600,13 +572,15 @@
 // If optimized_result_code is not NULL then it is caller's responsibility
 // to install code.
 bool CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
+  ASSERT(!FLAG_precompiled_mode);
   const Function& function = parsed_function()->function();
   if (optimized() && !function.IsOptimizable()) {
     return false;
   }
   bool is_compiled = false;
   Zone* const zone = thread()->zone();
-  TimelineStream* compiler_timeline = isolate()->GetCompilerStream();
+  NOT_IN_PRODUCT(
+      TimelineStream* compiler_timeline = isolate()->GetCompilerStream());
   CSTAT_TIMER_SCOPE(thread(), codegen_timer);
   HANDLESCOPE(thread());
 
@@ -616,12 +590,10 @@
   // longjmp from the ARM or MIPS assemblers. In all other paths through this
   // while loop, done is set to true. use_far_branches is always false on ia32
   // and x64.
-  bool done = false;
+  volatile bool done = false;
   // volatile because the variable may be clobbered by a longjmp.
   volatile bool use_far_branches = false;
-  volatile bool use_speculative_inlining =
-      FLAG_max_speculative_inlining_attempts > 0;
-  GrowableArray<intptr_t> inlining_black_list;
+  const bool use_speculative_inlining = false;
 
   while (!done) {
     const intptr_t prev_deopt_id = thread()->deopt_id();
@@ -644,14 +616,22 @@
         if (optimized()) {
           // Extract type feedback before the graph is built, as the graph
           // builder uses it to attach it to nodes.
-          ASSERT(function.deoptimization_counter() <
-                 FLAG_max_deoptimization_counter_threshold);
+
+          // In background compilation the deoptimization counter may have
+          // already reached the limit.
+          ASSERT(Compiler::IsBackgroundCompilation() ||
+                 (function.deoptimization_counter() <
+                     FLAG_max_deoptimization_counter_threshold));
 
           // 'Freeze' ICData in background compilation so that it does not
           // change while compiling.
-          const bool clone_descriptors = Compiler::IsBackgroundCompilation();
-          function.RestoreICDataMap(ic_data_array, clone_descriptors);
+          const bool clone_ic_data = Compiler::IsBackgroundCompilation();
+          function.RestoreICDataMap(ic_data_array, clone_ic_data);
 
+          if (Compiler::IsBackgroundCompilation() &&
+              (function.ic_data_array() == Array::null())) {
+            Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
+          }
           if (FLAG_print_ic_data_map) {
             for (intptr_t i = 0; i < ic_data_array->length(); i++) {
               if ((*ic_data_array)[i] != NULL) {
@@ -662,9 +642,9 @@
           }
         }
 
-        TimelineDurationScope tds(thread(),
-                                  compiler_timeline,
-                                  "BuildFlowGraph");
+        NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+                                                 compiler_timeline,
+                                                 "BuildFlowGraph");)
         flow_graph = pipeline->BuildFlowGraph(zone,
                                               parsed_function(),
                                               *ic_data_array,
@@ -688,16 +668,15 @@
       const bool reorder_blocks =
           FlowGraph::ShouldReorderBlocks(function, optimized());
       if (reorder_blocks) {
-        TimelineDurationScope tds(thread(),
-                                  compiler_timeline,
-                                  "BlockScheduler::AssignEdgeWeights");
+        NOT_IN_PRODUCT(TimelineDurationScope tds(
+            thread(), compiler_timeline, "BlockScheduler::AssignEdgeWeights"));
         block_scheduler.AssignEdgeWeights();
       }
 
       if (optimized()) {
-        TimelineDurationScope tds(thread(),
-                                  compiler_timeline,
-                                  "ComputeSSA");
+        NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+                                                 compiler_timeline,
+                                                 "ComputeSSA"));
         CSTAT_TIMER_SCOPE(thread(), ssa_timer);
         // Transform to SSA (virtual register 0 and no inlining arguments).
         flow_graph->ComputeSSA(0, NULL);
@@ -710,32 +689,25 @@
       // 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
       // have non-generic type feedback attached to them that can
       // potentially affect optimizations.
       if (optimized()) {
-        TimelineDurationScope tds(thread(),
-                                  compiler_timeline,
-                                  "OptimizationPasses");
+        NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+                                                 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,
-                                     &inlining_black_list);
-        if (Compiler::always_optimize()) {
-          optimizer.PopulateWithICData();
+        JitOptimizer optimizer(flow_graph);
 
-          optimizer.ApplyClassIds();
-          DEBUG_ASSERT(flow_graph->VerifyUseLists());
-
-          FlowGraphTypePropagator::Propagate(flow_graph);
-          DEBUG_ASSERT(flow_graph->VerifyUseLists());
-        }
         optimizer.ApplyICData();
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
@@ -748,9 +720,9 @@
 
         // Inlining (mutates the flow graph)
         if (FLAG_use_inlining) {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "Inlining");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "Inlining"));
           CSTAT_TIMER_SCOPE(thread(), graphinliner_timer);
           // Propagate types to create more inlining opportunities.
           FlowGraphTypePropagator::Propagate(flow_graph);
@@ -762,9 +734,10 @@
 
           FlowGraphInliner inliner(flow_graph,
                                    &inline_id_to_function,
+                                   &inline_id_to_token_pos,
                                    &caller_inline_id,
                                    use_speculative_inlining,
-                                   &inlining_black_list);
+                                   NULL);
           inliner.Inline();
           // Use lists are maintained and validated by the inliner.
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -775,9 +748,9 @@
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "ApplyClassIds");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "ApplyClassIds"));
           // Use propagated class-ids to optimize further.
           optimizer.ApplyClassIds();
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -789,17 +762,17 @@
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         // Do optimizations that depend on the propagated type information.
-        if (optimizer.Canonicalize()) {
+        if (flow_graph->Canonicalize()) {
           // Invoke Canonicalize twice in order to fully canonicalize patterns
           // like "if (a & const == 0) { }".
-          optimizer.Canonicalize();
+          flow_graph->Canonicalize();
         }
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "BranchSimplifier");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "BranchSimplifier"));
           BranchSimplifier::Simplify(flow_graph);
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
@@ -808,13 +781,13 @@
         }
 
         if (FLAG_constant_propagation) {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "ConstantPropagation");
-          ConstantPropagator::Optimize(flow_graph);
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "ConstantPropagation");
+          ConstantPropagator::Optimize(flow_graph));
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
           // A canonicalization pass to remove e.g. smi checks on smi constants.
-          optimizer.Canonicalize();
+          flow_graph->Canonicalize();
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
           // Canonicalization introduced more opportunities for constant
           // propagation.
@@ -837,24 +810,23 @@
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "SelectRepresentations");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "SelectRepresentations"));
           // Where beneficial convert Smi operations into Int32 operations.
           // Only meanigful for 32bit platforms right now.
-          optimizer.WidenSmiToInt32();
+          flow_graph->WidenSmiToInt32();
 
           // Unbox doubles. Performed after constant propagation to minimize
           // interference from phis merging double values and tagged
           // values coming from dead paths.
-          optimizer.SelectRepresentations();
+          flow_graph->SelectRepresentations();
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
         }
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "CommonSubexpressionElinination");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(
+              thread(), compiler_timeline, "CommonSubexpressionElinination"));
           if (FLAG_common_subexpression_elimination ||
               FLAG_loop_invariant_code_motion) {
             flow_graph->ComputeBlockEffects();
@@ -863,12 +835,12 @@
           if (FLAG_common_subexpression_elimination) {
             if (DominatorBasedCSE::Optimize(flow_graph)) {
               DEBUG_ASSERT(flow_graph->VerifyUseLists());
-              optimizer.Canonicalize();
+              flow_graph->Canonicalize();
               // Do another round of CSE to take secondary effects into account:
               // e.g. when eliminating dependent loads (a.x[0] + a.x[0])
               // TODO(fschneider): Change to a one-pass optimization pass.
               if (DominatorBasedCSE::Optimize(flow_graph)) {
-                optimizer.Canonicalize();
+                flow_graph->Canonicalize();
               }
               DEBUG_ASSERT(flow_graph->VerifyUseLists());
             }
@@ -892,16 +864,16 @@
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "DeadStoreElimination");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "DeadStoreElimination"));
           DeadStoreElimination::Optimize(flow_graph);
         }
 
         if (FLAG_range_analysis) {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "RangeAnalysis");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "RangeAnalysis"));
           // Propagate types after store-load-forwarding. Some phis may have
           // become smi phis that can be processed by range analysis.
           FlowGraphTypePropagator::Propagate(flow_graph);
@@ -910,14 +882,15 @@
           // We have to perform range analysis after LICM because it
           // optimistically moves CheckSmi through phis into loop preheaders
           // making some phis smi.
-          optimizer.InferIntRanges();
+          RangeAnalysis range_analysis(flow_graph);
+          range_analysis.Analyze();
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
         }
 
         if (FLAG_constant_propagation) {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "ConstantPropagator::OptimizeBranches");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(
+              thread(), compiler_timeline,
+              "ConstantPropagator::OptimizeBranches"));
           // Constant propagation can use information from range analysis to
           // find unreachable branch targets and eliminate branches that have
           // the same true- and false-target.
@@ -931,9 +904,8 @@
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "TryCatchAnalyzer::Optimize");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(
+              thread(), compiler_timeline, "TryCatchAnalyzer::Optimize"));
           // Optimize try-blocks.
           TryCatchAnalyzer::Optimize(flow_graph);
         }
@@ -941,18 +913,18 @@
         // Detach environments from the instructions that can't deoptimize.
         // Do it before we attempt to perform allocation sinking to minimize
         // amount of materializations it has to perform.
-        optimizer.EliminateEnvironments();
+        flow_graph->EliminateEnvironments();
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "EliminateDeadPhis");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "EliminateDeadPhis"));
           DeadCodeElimination::EliminateDeadPhis(flow_graph);
           DEBUG_ASSERT(flow_graph->VerifyUseLists());
         }
 
-        if (optimizer.Canonicalize()) {
-          optimizer.Canonicalize();
+        if (flow_graph->Canonicalize()) {
+          flow_graph->Canonicalize();
         }
 
         // Attempt to sink allocations of temporary non-escaping objects to
@@ -960,9 +932,8 @@
         AllocationSinking* sinking = NULL;
         if (FLAG_allocation_sinking &&
             (flow_graph->graph_entry()->SuccessorCount()  == 1)) {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "AllocationSinking::Optimize");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(
+              thread(), compiler_timeline, "AllocationSinking::Optimize"));
           // TODO(fschneider): Support allocation sinking with try-catch.
           sinking = new AllocationSinking(flow_graph);
           sinking->Optimize();
@@ -976,29 +947,28 @@
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "SelectRepresentations");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "SelectRepresentations"));
           // Ensure that all phis inserted by optimization passes have
           // consistent representations.
-          optimizer.SelectRepresentations();
+          flow_graph->SelectRepresentations();
         }
 
-        if (optimizer.Canonicalize()) {
+        if (flow_graph->Canonicalize()) {
           // To fully remove redundant boxing (e.g. BoxDouble used only in
           // environments and UnboxDouble instructions) instruction we
           // first need to replace all their uses and then fold them away.
           // For now we just repeat Canonicalize twice to do that.
           // TODO(vegorov): implement a separate representation folding pass.
-          optimizer.Canonicalize();
+          flow_graph->Canonicalize();
         }
         DEBUG_ASSERT(flow_graph->VerifyUseLists());
 
         if (sinking != NULL) {
-          TimelineDurationScope tds2(
-              thread(),
-              compiler_timeline,
-              "AllocationSinking::DetachMaterializations");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(
+              thread(), compiler_timeline,
+              "AllocationSinking::DetachMaterializations"));
           // Remove all MaterializeObject instructions inserted by allocation
           // sinking from the flow graph and let them float on the side
           // referenced only from environments. Register allocator will consider
@@ -1011,18 +981,17 @@
         FlowGraphInliner::CollectGraphInfo(flow_graph, true);
 
         {
-          TimelineDurationScope tds2(thread(),
-                                     compiler_timeline,
-                                     "AllocateRegisters");
+          NOT_IN_PRODUCT(TimelineDurationScope tds2(thread(),
+                                                    compiler_timeline,
+                                                    "AllocateRegisters"));
           // Perform register allocation on the SSA graph.
           FlowGraphAllocator allocator(*flow_graph);
           allocator.AllocateRegisters();
         }
 
         if (reorder_blocks) {
-          TimelineDurationScope tds(thread(),
-                                    compiler_timeline,
-                                    "BlockScheduler::ReorderBlocks");
+          NOT_IN_PRODUCT(TimelineDurationScope tds(
+              thread(), compiler_timeline, "BlockScheduler::ReorderBlocks"));
           block_scheduler.ReorderBlocks();
         }
 
@@ -1036,19 +1005,20 @@
       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);
-        TimelineDurationScope tds(thread(),
-                                  compiler_timeline,
-                                  "CompileGraph");
+        NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+                                                 compiler_timeline,
+                                                 "CompileGraph"));
         graph_compiler.CompileGraph();
         pipeline->FinalizeCompilation();
       }
       {
-        TimelineDurationScope tds(thread(),
-                                  compiler_timeline,
-                                  "FinalizeCompilation");
+        NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
+                                                 compiler_timeline,
+                                                 "FinalizeCompilation"));
         if (thread()->IsMutatorThread()) {
           FinalizeCompilation(&assembler, &graph_compiler, flow_graph);
         } else {
@@ -1059,14 +1029,13 @@
           // instruction object, since the creation of instruction object
           // changes code page access permissions (makes them temporary not
           // executable).
-          isolate()->thread_registry()->SafepointThreads();
           {
+            SafepointOperationScope safepoint_scope(thread());
             // Do not Garbage collect during this stage and instead allow the
             // heap to grow.
             NoHeapGrowthControlScope no_growth_control;
             FinalizeCompilation(&assembler, &graph_compiler, flow_graph);
           }
-          isolate()->thread_registry()->ResumeAllThreads();
           if (isolate()->heap()->NeedsGarbageCollection()) {
             isolate()->heap()->CollectAllGarbage();
           }
@@ -1079,8 +1048,7 @@
       done = true;
     } else {
       // We bailed out or we encountered an error.
-      const Error& error = Error::Handle(
-          isolate()->object_store()->sticky_error());
+      const Error& error = Error::Handle(thread()->sticky_error());
 
       if (error.raw() == Object::branch_offset_error().raw()) {
         // Compilation failed due to an out of range branch offset in the
@@ -1089,25 +1057,8 @@
         ASSERT(!use_far_branches);
         use_far_branches = true;
       } else if (error.raw() == Object::speculative_inlining_error().raw()) {
-        // The return value of setjmp is the deopt id of the check instruction
-        // that caused the bailout.
-        done = false;
-#if defined(DEBUG)
-        ASSERT(Compiler::always_optimize());
-        ASSERT(use_speculative_inlining);
-        for (intptr_t i = 0; i < inlining_black_list.length(); ++i) {
-          ASSERT(inlining_black_list[i] != val);
-        }
-#endif
-        inlining_black_list.Add(val);
-        const intptr_t max_attempts = FLAG_max_speculative_inlining_attempts;
-        if (inlining_black_list.length() >= max_attempts) {
-          use_speculative_inlining = false;
-          if (FLAG_trace_compiler || FLAG_trace_optimizing_compiler) {
-            THR_Print("Disabled speculative inlining after %" Pd " attempts.\n",
-                      inlining_black_list.length());
-          }
-        }
+        // Can only happen with precompilation.
+        UNREACHABLE();
       } else {
         // If the error isn't due to an out of range branch offset, we don't
         // try again (done = true), and indicate that we did not finish
@@ -1121,7 +1072,7 @@
       // Clear the error if it was not a real error, but just a bailout.
       if (error.IsLanguageError() &&
           (LanguageError::Cast(error).kind() == Report::kBailout)) {
-        isolate()->object_store()->clear_sticky_error();
+        thread()->clear_sticky_error();
       }
       is_compiled = false;
     }
@@ -1132,147 +1083,7 @@
 }
 
 
-static void DisassembleCode(const Function& function, bool optimized) {
-  const char* function_fullname = function.ToFullyQualifiedCString();
-  THR_Print("Code for %sfunction '%s' {\n",
-            optimized ? "optimized " : "",
-            function_fullname);
-  const Code& code = Code::Handle(function.CurrentCode());
-  code.Disassemble();
-  THR_Print("}\n");
-
-  THR_Print("Pointer offsets for function: {\n");
-  // Pointer offsets are stored in descending order.
-  Object& obj = Object::Handle();
-  for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) {
-    const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint();
-    obj = *reinterpret_cast<RawObject**>(addr);
-    THR_Print(" %d : %#" Px " '%s'\n",
-              code.GetPointerOffsetAt(i), addr, obj.ToCString());
-  }
-  THR_Print("}\n");
-
-  THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
-  PcDescriptors::PrintHeaderString();
-  const PcDescriptors& descriptors =
-      PcDescriptors::Handle(code.pc_descriptors());
-  THR_Print("%s}\n", descriptors.ToCString());
-
-  uword start = Instructions::Handle(code.instructions()).EntryPoint();
-  const Array& deopt_table = Array::Handle(code.deopt_info_array());
-  intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
-  if (deopt_table_length > 0) {
-    THR_Print("DeoptInfo: {\n");
-    Smi& offset = Smi::Handle();
-    TypedData& info = TypedData::Handle();
-    Smi& reason_and_flags = Smi::Handle();
-    for (intptr_t i = 0; i < deopt_table_length; ++i) {
-      DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags);
-      const intptr_t reason =
-          DeoptTable::ReasonField::decode(reason_and_flags.Value());
-      ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons));
-      THR_Print("%4" Pd ": 0x%" Px "  %s  (%s)\n",
-                i,
-                start + offset.Value(),
-                DeoptInfo::ToCString(deopt_table, info),
-                DeoptReasonToCString(
-                    static_cast<ICData::DeoptReasonId>(reason)));
-    }
-    THR_Print("}\n");
-  }
-
-  const ObjectPool& object_pool = ObjectPool::Handle(code.GetObjectPool());
-  object_pool.DebugPrint();
-
-  THR_Print("Stackmaps for function '%s' {\n", function_fullname);
-  if (code.stackmaps() != Array::null()) {
-    const Array& stackmap_table = Array::Handle(code.stackmaps());
-    Stackmap& map = Stackmap::Handle();
-    for (intptr_t i = 0; i < stackmap_table.Length(); ++i) {
-      map ^= stackmap_table.At(i);
-      THR_Print("%s\n", map.ToCString());
-    }
-  }
-  THR_Print("}\n");
-
-  THR_Print("Variable Descriptors for function '%s' {\n",
-            function_fullname);
-  const LocalVarDescriptors& var_descriptors =
-      LocalVarDescriptors::Handle(code.GetLocalVarDescriptors());
-  intptr_t var_desc_length =
-      var_descriptors.IsNull() ? 0 : var_descriptors.Length();
-  String& var_name = String::Handle();
-  for (intptr_t i = 0; i < var_desc_length; i++) {
-    var_name = var_descriptors.GetName(i);
-    RawLocalVarDescriptors::VarInfo var_info;
-    var_descriptors.GetInfo(i, &var_info);
-    const int8_t kind = var_info.kind();
-    if (kind == RawLocalVarDescriptors::kSavedCurrentContext) {
-      THR_Print("  saved current CTX reg offset %d\n", var_info.index());
-    } else {
-      if (kind == RawLocalVarDescriptors::kContextLevel) {
-        THR_Print("  context level %d scope %d", var_info.index(),
-            var_info.scope_id);
-      } else if (kind == RawLocalVarDescriptors::kStackVar) {
-        THR_Print("  stack var '%s' offset %d",
-          var_name.ToCString(), var_info.index());
-      } else {
-        ASSERT(kind == RawLocalVarDescriptors::kContextVar);
-        THR_Print("  context var '%s' level %d offset %d",
-            var_name.ToCString(), var_info.scope_id, var_info.index());
-      }
-      THR_Print(" (valid %d-%d)\n", var_info.begin_pos, var_info.end_pos);
-    }
-  }
-  THR_Print("}\n");
-
-  THR_Print("Exception Handlers for function '%s' {\n", function_fullname);
-  const ExceptionHandlers& handlers =
-        ExceptionHandlers::Handle(code.exception_handlers());
-  THR_Print("%s}\n", handlers.ToCString());
-
-  {
-    THR_Print("Static call target functions {\n");
-    const Array& table = Array::Handle(code.static_calls_target_table());
-    Smi& offset = Smi::Handle();
-    Function& function = Function::Handle();
-    Code& code = Code::Handle();
-    for (intptr_t i = 0; i < table.Length();
-        i += Code::kSCallTableEntryLength) {
-      offset ^= table.At(i + Code::kSCallTableOffsetEntry);
-      function ^= table.At(i + Code::kSCallTableFunctionEntry);
-      code ^= table.At(i + Code::kSCallTableCodeEntry);
-      if (function.IsNull()) {
-        Class& cls = Class::Handle();
-        cls ^= code.owner();
-        if (cls.IsNull()) {
-          const String& code_name = String::Handle(code.Name());
-          THR_Print("  0x%" Px ": %s, %p\n",
-              start + offset.Value(),
-              code_name.ToCString(),
-              code.raw());
-        } else {
-          THR_Print("  0x%" Px ": allocation stub for %s, %p\n",
-              start + offset.Value(),
-              cls.ToCString(),
-              code.raw());
-        }
-      } else {
-        THR_Print("  0x%" Px ": %s, %p\n",
-            start + offset.Value(),
-            function.ToFullyQualifiedCString(),
-            code.raw());
-      }
-    }
-    THR_Print("}\n");
-  }
-  if (optimized && FLAG_trace_inlining_intervals) {
-    code.DumpInlinedIntervals();
-  }
-}
-
-
-#if defined(DEBUG)
+DEBUG_ONLY(
 // Verifies that the inliner is always in the list of inlined functions.
 // If this fails run with --trace-inlining-intervals to get more information.
 static void CheckInliningIntervals(const Function& function) {
@@ -1290,18 +1101,13 @@
            function.raw());
   }
 }
-#endif
-
+)
 
 static RawError* CompileFunctionHelper(CompilationPipeline* pipeline,
                                        const Function& function,
                                        bool optimized,
                                        intptr_t osr_id) {
-  // Check that we optimize if 'Compiler::always_optimize()' is set to true,
-  // except if the function is marked as not optimizable.
-  ASSERT(!function.IsOptimizable() ||
-         !Compiler::always_optimize() || optimized);
-  ASSERT(Compiler::allow_recompilation() || !function.HasCode());
+  ASSERT(!FLAG_precompiled_mode);
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
     Thread* const thread = Thread::Current();
@@ -1317,12 +1123,15 @@
     ParsedFunction* parsed_function = new(zone) ParsedFunction(
         thread, Function::ZoneHandle(zone, function.raw()));
     if (trace_compiler) {
-      THR_Print("Compiling %s%sfunction: '%s' @ token %" Pd ", size %" Pd "\n",
+      const intptr_t token_size = function.end_token_pos().Pos() -
+                                  function.token_pos().Pos();
+      THR_Print("Compiling %s%sfunction %s: '%s' @ token %s, size %" Pd "\n",
                 (osr_id == Compiler::kNoOSRDeoptId ? "" : "osr "),
                 (optimized ? "optimized " : ""),
+                (Compiler::IsBackgroundCompilation() ? "(background)" : ""),
                 function.ToFullyQualifiedCString(),
-                function.token_pos(),
-                (function.end_token_pos() - function.token_pos()));
+                function.token_pos().ToCString(),
+                token_size);
     }
     INC_STAT(thread, num_functions_compiled, 1);
     if (optimized) {
@@ -1342,7 +1151,6 @@
     const bool success = helper.Compile(pipeline);
     if (!success) {
       if (optimized) {
-        ASSERT(!Compiler::always_optimize());  // Optimized is the only code.
         // Optimizer bailed out. Disable optimizations and never try again.
         if (trace_compiler) {
           THR_Print("--> disabling optimizations for '%s'\n",
@@ -1357,8 +1165,10 @@
         // Encountered error.
         Error& error = Error::Handle();
         // We got an error during compilation.
-        error = isolate->object_store()->sticky_error();
-        isolate->object_store()->clear_sticky_error();
+        error = thread->sticky_error();
+        thread->clear_sticky_error();
+        ASSERT(error.IsLanguageError() &&
+               LanguageError::Cast(error).kind() != Report::kBailout);
         return error.raw();
       }
     }
@@ -1373,33 +1183,32 @@
                 per_compile_timer.TotalElapsedTime());
     }
 
-    isolate->debugger()->NotifyCompilation(function);
+    if (FLAG_support_debugger) {
+      isolate->debugger()->NotifyCompilation(function);
+    }
 
     if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) {
-      DisassembleCode(function, optimized);
+      Disassembler::DisassembleCode(function, optimized);
     } else if (FLAG_disassemble_optimized &&
                optimized &&
                FlowGraphPrinter::ShouldPrint(function)) {
       // TODO(fschneider): Print unoptimized code along with the optimized code.
       THR_Print("*** BEGIN CODE\n");
-      DisassembleCode(function, true);
+      Disassembler::DisassembleCode(function, true);
       THR_Print("*** END CODE\n");
     }
-#if defined(DEBUG)
-    CheckInliningIntervals(function);
-#endif
+    DEBUG_ONLY(CheckInliningIntervals(function));
     return Error::null();
   } else {
     Thread* const thread = Thread::Current();
-    Isolate* const isolate = thread->isolate();
     StackZone stack_zone(thread);
     Error& error = Error::Handle();
     // We got an error during compilation.
-    error = isolate->object_store()->sticky_error();
-    isolate->object_store()->clear_sticky_error();
+    error = thread->sticky_error();
+    thread->clear_sticky_error();
     // Unoptimized compilation or precompilation may encounter compile-time
     // errors, but regular optimized compilation should not.
-    ASSERT(!optimized || Compiler::always_optimize());
+    ASSERT(!optimized);
     // Do not attempt to optimize functions that can cause errors.
     function.set_is_optimizable(false);
     return error.raw();
@@ -1411,26 +1220,28 @@
 
 RawError* Compiler::CompileFunction(Thread* thread,
                                     const Function& function) {
+#ifdef DART_PRECOMPILER
+  if (FLAG_precompiled_mode) {
+    return Precompiler::CompileFunction(thread, function);
+  }
+#endif
   Isolate* isolate = thread->isolate();
   VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
   TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function);
 
   if (!isolate->compilation_allowed()) {
-    FATAL3("Precompilation missed function %s (%" Pd ", %s)\n",
+    FATAL3("Precompilation missed function %s (%s, %s)\n",
            function.ToLibNamePrefixedQualifiedCString(),
-           function.token_pos(),
+           function.token_pos().ToCString(),
            Function::KindToCString(function.kind()));
   }
 
   CompilationPipeline* pipeline =
       CompilationPipeline::New(thread->zone(), function);
 
-  const bool optimized =
-      Compiler::always_optimize() && function.IsOptimizable();
-
   return CompileFunctionHelper(pipeline,
                                function,
-                               optimized,
+                               /* optimized = */ false,
                                kNoOSRDeoptId);
 }
 
@@ -1498,15 +1309,15 @@
     CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
     helper.Compile(&pipeline);
     if (FLAG_disassemble) {
-      DisassembleCode(parsed_function->function(), false);
+      Disassembler::DisassembleCode(parsed_function->function(), false);
     }
     return Error::null();
   } else {
-    Isolate* const isolate = Isolate::Current();
     Error& error = Error::Handle();
+    Thread* thread = Thread::Current();
     // We got an error during compilation.
-    error = isolate->object_store()->sticky_error();
-    isolate->object_store()->clear_sticky_error();
+    error = thread->sticky_error();
+    thread->clear_sticky_error();
     return error.raw();
   }
   UNREACHABLE();
@@ -1565,67 +1376,42 @@
 }
 
 
-void Compiler::CompileStaticInitializer(const Field& field) {
-  ASSERT(field.is_static());
-  if (field.HasPrecompiledInitializer()) {
-    // TODO(rmacnak): Investigate why this happens for _enum_names.
-    OS::Print("Warning: Ignoring repeated request for initializer for %s\n",
-              field.ToCString());
-    return;
-  }
-  Thread* thread = Thread::Current();
-  StackZone zone(thread);
-
-  ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
-
-  parsed_function->AllocateVariables();
-  // Non-optimized code generator.
-  DartCompilationPipeline pipeline;
-  CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
-  helper.Compile(&pipeline);
-  const Function& initializer = parsed_function->function();
-  field.SetPrecompiledInitializer(initializer);
-}
-
-
 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
+#ifdef DART_PRECOMPILER
+  if (FLAG_precompiled_mode) {
+    return Precompiler::EvaluateStaticInitializer(field);
+  }
+#endif
   ASSERT(field.is_static());
   // The VM sets the field's value to transiton_sentinel prior to
   // evaluating the initializer value.
   ASSERT(field.StaticValue() == Object::transition_sentinel().raw());
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
-    // Under precompilation, the initializer may have already been compiled, in
-    // which case use it. Under lazy compilation or early in precompilation, the
-    // initializer has not yet been created, so create it now, but don't bother
-    // remembering it because it won't be used again.
-    Function& initializer = Function::Handle();
-    if (!field.HasPrecompiledInitializer()) {
-      Thread* const thread = Thread::Current();
-      StackZone zone(thread);
-      ParsedFunction* parsed_function =
-          Parser::ParseStaticFieldInitializer(field);
+    // Under lazy compilation initializer has not yet been created, so create
+    // it now, but don't bother remembering it because it won't be used again.
+    ASSERT(!field.HasPrecompiledInitializer());
+    Thread* const thread = Thread::Current();
+    StackZone zone(thread);
+    ParsedFunction* parsed_function =
+        Parser::ParseStaticFieldInitializer(field);
 
-      parsed_function->AllocateVariables();
-      // Non-optimized code generator.
-      DartCompilationPipeline pipeline;
-      CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
-      helper.Compile(&pipeline);
-      initializer = parsed_function->function().raw();
-      Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
-          Object::empty_var_descriptors());
-    } else {
-      initializer ^= field.PrecompiledInitializer();
-    }
+    parsed_function->AllocateVariables();
+    // Non-optimized code generator.
+    DartCompilationPipeline pipeline;
+    CompileParsedFunctionHelper helper(parsed_function, false, kNoOSRDeoptId);
+    helper.Compile(&pipeline);
+    const Function& initializer =
+        Function::Handle(parsed_function->function().raw());
+    Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
+        Object::empty_var_descriptors());
     // Invoke the function to evaluate the expression.
     return DartEntry::InvokeFunction(initializer, Object::empty_array());
   } else {
     Thread* const thread = Thread::Current();
-    Isolate* const isolate = thread->isolate();
     StackZone zone(thread);
-    const Error& error =
-        Error::Handle(thread->zone(), isolate->object_store()->sticky_error());
-    isolate->object_store()->clear_sticky_error();
+    const Error& error = Error::Handle(thread->zone(), thread->sticky_error());
+    thread->clear_sticky_error();
     return error.raw();
   }
   UNREACHABLE();
@@ -1635,12 +1421,23 @@
 
 
 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
+#ifdef DART_PRECOMPILER
+  if (FLAG_precompiled_mode) {
+    return Precompiler::ExecuteOnce(fragment);
+  }
+#endif
   LongJumpScope jump;
   if (setjmp(*jump.Set()) == 0) {
     Thread* const thread = Thread::Current();
+
+    // Don't allow message interrupts while executing constant
+    // expressions.  They can cause bogus recursive compilation.
+    NoOOBMessageScope no_msg_scope(thread);
     if (FLAG_trace_compiler) {
       THR_Print("compiling expression: ");
-      AstPrinter::PrintNode(fragment);
+      if (FLAG_support_ast_printer) {
+        AstPrinter::PrintNode(fragment);
+      }
     }
 
     // Create a dummy function object for the code generator.
@@ -1687,10 +1484,8 @@
     return result.raw();
   } else {
     Thread* const thread = Thread::Current();
-    Isolate* const isolate = thread->isolate();
-    const Object& result =
-      PassiveObject::Handle(isolate->object_store()->sticky_error());
-    isolate->object_store()->clear_sticky_error();
+    const Object& result = PassiveObject::Handle(thread->sticky_error());
+    thread->clear_sticky_error();
     return result.raw();
   }
   UNREACHABLE();
@@ -1698,6 +1493,16 @@
 }
 
 
+void Compiler::AbortBackgroundCompilation(intptr_t deopt_id) {
+  if (FLAG_trace_compiler) {
+    THR_Print("ABORT background compilation.");
+  }
+  ASSERT(Compiler::IsBackgroundCompilation());
+  Thread::Current()->long_jump_base()->Jump(
+      deopt_id, Object::background_compilation_error());
+}
+
+
 // C-heap allocated background compilation queue element.
 class QueueElement {
  public:
@@ -1899,9 +1704,7 @@
   {
     MonitorLocker ml_done(done_monitor);
     while (!(*task_done)) {
-      // In case that the compiler is waiting for safepoint.
-      Isolate::Current()->thread_registry()->CheckSafepoint();
-      ml_done.Wait(1);
+      ml_done.WaitWithSafepointCheck(Thread::Current());
     }
   }
   delete task_done;
@@ -1941,11 +1744,22 @@
 }
 
 
-#else  // DART_PRECOMPILED
+#else  // DART_PRECOMPILED_RUNTIME
+
+
+CompilationPipeline* CompilationPipeline::New(Zone* zone,
+                                              const Function& function) {
+  UNREACHABLE();
+  return NULL;
+}
 
 
 DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
-  UNREACHABLE();
+  const Function& function = Function::CheckedHandle(arguments.ArgAt(0));
+  FATAL3("Precompilation missed function %s (%" Pd ", %s)\n",
+         function.ToLibNamePrefixedQualifiedCString(),
+         function.token_pos().value(),
+         Function::KindToCString(function.kind()));
 }
 
 
@@ -2007,11 +1821,6 @@
 }
 
 
-void Compiler::CompileStaticInitializer(const Field& field) {
-  UNREACHABLE();
-}
-
-
 RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
   ASSERT(field.HasPrecompiledInitializer());
   const Function& initializer =
@@ -2020,13 +1829,17 @@
 }
 
 
-
 RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
   UNREACHABLE();
   return Object::null();
 }
 
 
+void Compiler::AbortBackgroundCompilation(intptr_t deopt_id) {
+  UNREACHABLE();
+}
+
+
 void BackgroundCompiler::CompileOptimized(const Function& function) {
   UNREACHABLE();
 }
@@ -2046,6 +1859,6 @@
   UNREACHABLE();
 }
 
-#endif  // DART_PRECOMPILED
+#endif  // DART_PRECOMPILED_RUNTIME
 
 }  // namespace dart
diff --git a/runtime/vm/compiler.h b/runtime/vm/compiler.h
index 130567d..01822ac 100644
--- a/runtime/vm/compiler.h
+++ b/runtime/vm/compiler.h
@@ -17,7 +17,9 @@
 class Class;
 class Code;
 class CompilationWorkQueue;
+class FlowGraph;
 class Function;
+class IndirectGotoInstr;
 class Library;
 class ParsedFunction;
 class QueueElement;
@@ -26,6 +28,54 @@
 class SequenceNode;
 
 
+class CompilationPipeline : public ZoneAllocated {
+ public:
+  static CompilationPipeline* New(Zone* zone, const Function& function);
+
+  virtual void ParseFunction(ParsedFunction* parsed_function) = 0;
+  virtual FlowGraph* BuildFlowGraph(
+      Zone* zone,
+      ParsedFunction* parsed_function,
+      const ZoneGrowableArray<const ICData*>& ic_data_array,
+      intptr_t osr_id) = 0;
+  virtual void FinalizeCompilation() = 0;
+  virtual ~CompilationPipeline() { }
+};
+
+
+class DartCompilationPipeline : public CompilationPipeline {
+ public:
+  virtual void ParseFunction(ParsedFunction* parsed_function);
+
+  virtual FlowGraph* BuildFlowGraph(
+      Zone* zone,
+      ParsedFunction* parsed_function,
+      const ZoneGrowableArray<const ICData*>& ic_data_array,
+      intptr_t osr_id);
+
+  virtual void FinalizeCompilation();
+};
+
+
+class IrregexpCompilationPipeline : public CompilationPipeline {
+ public:
+  IrregexpCompilationPipeline() : backtrack_goto_(NULL) { }
+
+  virtual void ParseFunction(ParsedFunction* parsed_function);
+
+  virtual FlowGraph* BuildFlowGraph(
+      Zone* zone,
+      ParsedFunction* parsed_function,
+      const ZoneGrowableArray<const ICData*>& ic_data_array,
+      intptr_t osr_id);
+
+  virtual void FinalizeCompilation();
+
+ private:
+  IndirectGotoInstr* backtrack_goto_;
+};
+
+
 class Compiler : public AllStatic {
  public:
   static const intptr_t kNoOSRDeoptId = Thread::kNoDeoptId;
@@ -82,7 +132,6 @@
   // The return value is either a RawInstance on success or a RawError
   // on compilation failure.
   static RawObject* EvaluateStaticInitializer(const Field& field);
-  static void CompileStaticInitializer(const Field& field);
 
   // Generates local var descriptors and sets it in 'code'. Do not call if the
   // local var descriptor already exists.
@@ -93,22 +142,11 @@
   // Returns Error::null() if there is no compilation error.
   static RawError* CompileAllFunctions(const Class& cls);
 
-  // The following global flags are changed by --noopt handler;
-  // the flags are changed when generating best unoptimized code (no runtime
-  // feedback, no deoptimization).
-
-  // Default: false.
-  static bool always_optimize() { return always_optimize_; }
-  static void set_always_optimize(bool value) { always_optimize_ = value; }
-
-  static bool allow_recompilation() { return allow_recompilation_; }
-  static void set_allow_recompilation(bool value) {
-    allow_recompilation_ = value;
-  }
-
- private:
-  static bool always_optimize_;
-  static bool allow_recompilation_;
+  // Notify the compiler that background (optimized) compilation has failed
+  // because the mutator thread changed the state (e.g., deoptimization,
+  // deferred loading). The background compilation may retry to compile
+  // the same function later.
+  static void AbortBackgroundCompilation(intptr_t deopt_id);
 };
 
 
diff --git a/runtime/vm/compiler_stats.cc b/runtime/vm/compiler_stats.cc
index d5b20f4..7905ed8 100644
--- a/runtime/vm/compiler_stats.cc
+++ b/runtime/vm/compiler_stats.cc
@@ -33,7 +33,7 @@
     obj_ = raw_obj;
     if (obj_.GetClassId() == TokenStream::kClassId) {
       TokenStream::Iterator tkit(TokenStream::Cast(obj_),
-                                 0,
+                                 TokenPosition::kMinSource,
                                  TokenStream::Iterator::kNoNewlines);
       Token::Kind kind = tkit.CurrentTokenKind();
       while (kind != Token::kEOS) {
@@ -89,6 +89,8 @@
 }
 
 
+#ifndef PRODUCT
+
 // This function is used as a callback in the log object to which the
 // compiler stats are printed. It will be called only once, to print
 // the accumulated text when all of the compiler stats values are
@@ -286,4 +288,6 @@
   return stats_text;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/compiler_stats.h b/runtime/vm/compiler_stats.h
index 296b2a4..9b9e67b 100644
--- a/runtime/vm/compiler_stats.h
+++ b/runtime/vm/compiler_stats.h
@@ -72,20 +72,22 @@
 };
 
 #define INC_STAT(thread, counter, incr)                                        \
-  if (FLAG_compiler_stats) {                                                   \
+  if (FLAG_support_compiler_stats && FLAG_compiler_stats) {                    \
     MutexLocker ml((thread)->isolate()->mutex());                              \
     (thread)->isolate()->compiler_stats()->counter += (incr);                  \
   }
 
 #define STAT_VALUE(thread, counter)                                            \
-  ((FLAG_compiler_stats != false) ?                                            \
+  ((FLAG_support_compiler_stats && FLAG_compiler_stats) ?                      \
       (thread)->isolate()->compiler_stats()->counter : 0)
 
 #define CSTAT_TIMER_SCOPE(thr, t)                                              \
-  TimerScope timer(FLAG_compiler_stats,                                        \
-      FLAG_compiler_stats ? &((thr)->isolate()->compiler_stats()->t) : NULL,   \
+  TimerScope timer(FLAG_support_compiler_stats && FLAG_compiler_stats,         \
+      (FLAG_support_compiler_stats && FLAG_compiler_stats) ?                   \
+      &((thr)->isolate()->compiler_stats()->t) : NULL,                         \
       thr);
 
+
 }  // namespace dart
 
 #endif  // VM_COMPILER_STATS_H_
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index cab1593..8dd7c2f 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -8,16 +8,14 @@
 #include "vm/compiler.h"
 #include "vm/dart_api_impl.h"
 #include "vm/object.h"
+#include "vm/safepoint.h"
 #include "vm/symbols.h"
 #include "vm/thread_pool.h"
-#include "vm/thread_registry.h"
 #include "vm/unit_test.h"
 
 namespace dart {
 
-DECLARE_FLAG(bool, background_compilation);
-
-TEST_CASE(CompileScript) {
+VM_TEST_CASE(CompileScript) {
   const char* kScriptChars =
       "class A {\n"
       "  static foo() { return 42; }\n"
@@ -32,7 +30,7 @@
 }
 
 
-TEST_CASE(CompileFunction) {
+VM_TEST_CASE(CompileFunction) {
   const char* kScriptChars =
             "class A {\n"
             "  static foo() { return 42; }\n"
@@ -73,7 +71,7 @@
 }
 
 
-TEST_CASE(CompileFunctionOnHelperThread) {
+VM_TEST_CASE(CompileFunctionOnHelperThread) {
   // Create a simple function and compile it without optimization.
   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);
@@ -106,8 +107,7 @@
   Monitor* m = new Monitor();
   MonitorLocker ml(m);
   while (!func.HasOptimizedCode()) {
-    Isolate::Current()->thread_registry()->CheckSafepoint();
-    ml.Wait(1);
+    ml.WaitWithSafepointCheck(thread, 1);
   }
   BackgroundCompiler::Stop(isolate->background_compiler());
 }
@@ -123,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);
@@ -167,6 +166,7 @@
       Dart_Invoke(lib, Dart_NewStringFromCString("makeObj"), 0,  NULL);
   EXPECT(!Dart_IsNull(obj_handle));
   EXPECT(!Dart_IsError(obj_handle));
+  TransitionNativeToVM transition(thread);
   const Object& obj = Object::Handle(Api::UnwrapHandle(obj_handle));
   EXPECT(!obj.IsNull());
   EXPECT(obj.IsInstance());
@@ -184,7 +184,7 @@
 }
 
 
-TEST_CASE(EvalExpressionWithLazyCompile) {
+VM_TEST_CASE(EvalExpressionWithLazyCompile) {
   Library& lib = Library::Handle(Library::CoreLibrary());
 
   const String& expression = String::Handle(String::New(
@@ -199,7 +199,7 @@
 }
 
 
-TEST_CASE(EvalExpressionExhaustCIDs) {
+VM_TEST_CASE(EvalExpressionExhaustCIDs) {
   Library& lib = Library::Handle(Library::CoreLibrary());
 
   const String& expression = String::Handle(String::New("3 + 4"));
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/coverage.cc b/runtime/vm/coverage.cc
index 42dff5e..2e85c3d 100644
--- a/runtime/vm/coverage.cc
+++ b/runtime/vm/coverage.cc
@@ -41,10 +41,13 @@
     (*map)[i] = -1;
   }
 #endif
-  TokenStream::Iterator tkit(tkns, 0, TokenStream::Iterator::kAllTokens);
+  TokenStream::Iterator tkit(tkns,
+                             TokenPosition::kMinSource,
+                             TokenStream::Iterator::kAllTokens);
   intptr_t cur_line = script.line_offset() + 1;
   while (tkit.CurrentTokenKind() != Token::kEOS) {
-    (*map)[tkit.CurrentPosition()] = cur_line;
+    const intptr_t position = tkit.CurrentPosition().Pos();
+    (*map)[position] = cur_line;
     if (tkit.CurrentTokenKind() == Token::kNEWLINE) {
       cur_line++;
     }
@@ -57,6 +60,9 @@
                                  const JSONArray& hits_or_sites,
                                  const GrowableArray<intptr_t>& pos_to_line,
                                  bool as_call_sites) {
+  if (!FLAG_support_coverage) {
+    return;
+  }
   // If the function should not be compiled for coverage analysis, then just
   // skip this method.
   // TODO(iposva): Maybe we should skip synthesized methods in general too.
@@ -83,12 +89,12 @@
   // Print the hit counts for all IC datas.
   ZoneGrowableArray<const ICData*>* ic_data_array =
       new(zone) ZoneGrowableArray<const ICData*>();
-  function.RestoreICDataMap(ic_data_array, false /* clone descriptors */);
+  function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
   const PcDescriptors& descriptors = PcDescriptors::Handle(
       zone, code.pc_descriptors());
 
-  const intptr_t begin_pos = function.token_pos();
-  const intptr_t end_pos = function.end_token_pos();
+  const TokenPosition begin_pos = function.token_pos();
+  const TokenPosition end_pos = function.end_token_pos();
   intptr_t last_line = -1;
   intptr_t last_count = 0;
   // Only IC based calls have counting.
@@ -98,16 +104,18 @@
     HANDLESCOPE(thread);
     const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
     if (!ic_data->IsNull()) {
-      const intptr_t token_pos = iter.TokenPos();
+      const TokenPosition token_pos = iter.TokenPos();
       // Filter out descriptors that do not map to tokens in the source code.
       if ((token_pos < begin_pos) || (token_pos > end_pos)) {
         continue;
       }
       if (as_call_sites) {
         bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall;
-        ic_data->PrintToJSONArray(hits_or_sites, token_pos, is_static_call);
+        ic_data->PrintToJSONArray(hits_or_sites,
+                                  token_pos,
+                                  is_static_call);
       } else {
-        intptr_t line = pos_to_line[token_pos];
+        intptr_t line = pos_to_line[token_pos.Pos()];
 #if defined(DEBUG)
         const Script& script = Script::Handle(zone, function.script());
         intptr_t test_line = -1;
@@ -141,6 +149,9 @@
                               const JSONArray& jsarr,
                               CoverageFilter* filter,
                               bool as_call_sites) {
+  if (!FLAG_support_coverage) {
+    return;
+  }
   Thread* thread = Thread::Current();
   if (cls.EnsureIsFinalized(thread) != Error::null()) {
     // Only classes that have been finalized do have a meaningful list of
@@ -235,6 +246,9 @@
 
 
 void CodeCoverage::Write(Thread* thread) {
+  if (!FLAG_support_coverage) {
+    return;
+  }
   if (FLAG_coverage_dir == NULL) {
     return;
   }
@@ -267,6 +281,9 @@
                              JSONStream* stream,
                              CoverageFilter* filter,
                              bool as_call_sites) {
+  if (!FLAG_support_coverage) {
+    return;
+  }
   CoverageFilterAll default_filter;
   if (filter == NULL) {
     filter = &default_filter;
diff --git a/runtime/vm/coverage_test.cc b/runtime/vm/coverage_test.cc
index 1a2b0eb..025c6ed 100644
--- a/runtime/vm/coverage_test.cc
+++ b/runtime/vm/coverage_test.cc
@@ -8,7 +8,10 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 static RawObject* ExecuteScript(const char* script) {
+  TransitionVMToNative transition(Thread::Current());
   Dart_Handle h_lib = TestCase::LoadTestScript(script, NULL);
   EXPECT_VALID(h_lib);
   Library& lib = Library::Handle();
@@ -34,7 +37,7 @@
 };
 
 
-TEST_CASE(Coverage_Empty) {
+VM_TEST_CASE(Coverage_Empty) {
   const char* kScript =
       "main() {\n"
       "}";
@@ -56,7 +59,7 @@
 }
 
 
-TEST_CASE(Coverage_MainWithClass) {
+VM_TEST_CASE(Coverage_MainWithClass) {
   const char* kScript =
       "class Foo {\n"
       "  var x;\n"
@@ -100,7 +103,7 @@
 }
 
 
-TEST_CASE(Coverage_FilterFunction) {
+VM_TEST_CASE(Coverage_FilterFunction) {
   const char* kScript =
       "class Foo {\n"
       "  var x;\n"
@@ -136,4 +139,6 @@
   EXPECT_SUBSTRING(buf, js.ToCString());
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index 491468a..edaea94 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -56,12 +56,16 @@
 
 namespace dart {
 
-// TODO(zra): Add a target for ARMv6.
 #if defined(TARGET_ARCH_ARM_5TE)
 DEFINE_FLAG(bool, use_vfp, false, "Use vfp instructions if supported");
 DEFINE_FLAG(bool, use_neon, false, "Use neon instructions if supported");
 DEFINE_FLAG(bool, use_integer_division, false,
             "Use integer division instruction if supported");
+#elif defined(TARGET_ARCH_ARM_6)
+DEFINE_FLAG(bool, use_vfp, true, "Use vfp instructions if supported");
+DEFINE_FLAG(bool, use_neon, false, "Use neon instructions if supported");
+DEFINE_FLAG(bool, use_integer_division, false,
+            "Use integer division instruction if supported");
 #else
 DEFINE_FLAG(bool, use_vfp, true, "Use vfp instructions if supported");
 DEFINE_FLAG(bool, use_neon, true, "Use neon instructions if supported");
@@ -242,6 +246,8 @@
 
 #if defined(TARGET_ARCH_ARM_5TE)
   arm_version_ = ARMv5TE;
+#elif defined(TARGET_ARCH_ARM_6)
+  arm_version_ = ARMv6;
 #else
   arm_version_ = ARMv7;
 #endif
diff --git a/runtime/vm/cpuid.h b/runtime/vm/cpuid.h
index b9d193a..b33812e 100644
--- a/runtime/vm/cpuid.h
+++ b/runtime/vm/cpuid.h
@@ -26,14 +26,14 @@
   static const char* field(CpuInfoIndices idx) { return NULL; }
 #endif
 
-  static bool sse2() { return sse2_; }
-  static bool sse41() { return sse41_; }
-
+ private:
   // Caller must free the result of id_string and brand_string.
   static const char* id_string();
   static const char* brand_string();
 
- private:
+  static bool sse2() { return sse2_; }
+  static bool sse41() { return sse41_; }
+
   static bool sse2_;
   static bool sse41_;
   static const char* id_string_;
diff --git a/runtime/vm/cpuinfo.h b/runtime/vm/cpuinfo.h
index 3ccf2d4..95b6ec3 100644
--- a/runtime/vm/cpuinfo.h
+++ b/runtime/vm/cpuinfo.h
@@ -45,27 +45,24 @@
 
   // Returns true if the cpuinfo field contains the string.
   static bool FieldContains(CpuInfoIndices idx, const char* search_string);
-  static bool FieldContainsByString(
-      const char* field, const char* search_string);
 
   // Returns true if the cpuinfo field [field] exists and is non-empty.
   static bool HasField(const char* field);
 
-  // Returns the field. Caller is responsible for freeing the result.
-  static const char* ExtractField(CpuInfoIndices idx);
-  static const char* ExtractFieldByString(const char* field);
-
   // Returns the field describing the CPU model. Caller is responsible for
   // freeing the result.
   static const char* GetCpuModel() {
     if (HasField(FieldName(kCpuInfoHardware))) {
       return ExtractField(kCpuInfoHardware);
     } else {
-      return "";
+      return strdup("Unknown");
     }
   }
 
  private:
+  // Returns the field. Caller is responsible for freeing the result.
+  static const char* ExtractField(CpuInfoIndices idx);
+
   // The method to use to acquire info about the CPU.
   static CpuInfoMethod method_;
 
diff --git a/runtime/vm/cpuinfo_android.cc b/runtime/vm/cpuinfo_android.cc
index e4e4826..1e4229c 100644
--- a/runtime/vm/cpuinfo_android.cc
+++ b/runtime/vm/cpuinfo_android.cc
@@ -52,25 +52,12 @@
 }
 
 
-bool CpuInfo::FieldContainsByString(const char* field,
-                                    const char* search_string) {
-  ASSERT(method_ != kCpuInfoDefault);
-  return ProcCpuInfo::FieldContains(field, search_string);
-}
-
-
 const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
   ASSERT(method_ != kCpuInfoDefault);
   return ProcCpuInfo::ExtractField(FieldName(idx));
 }
 
 
-const char* CpuInfo::ExtractFieldByString(const char* field) {
-  ASSERT(method_ != kCpuInfoDefault);
-  return ProcCpuInfo::ExtractField(field);
-}
-
-
 bool CpuInfo::HasField(const char* field) {
   ASSERT(method_ != kCpuInfoDefault);
   return ProcCpuInfo::HasField(field);
diff --git a/runtime/vm/cpuinfo_linux.cc b/runtime/vm/cpuinfo_linux.cc
index 0341530..8d76233 100644
--- a/runtime/vm/cpuinfo_linux.cc
+++ b/runtime/vm/cpuinfo_linux.cc
@@ -28,14 +28,20 @@
   fields_[kCpuInfoFeatures] = "flags";
   method_ = kCpuInfoCpuId;
   CpuId::InitOnce();
-#elif defined(HOST_ARCH_ARM) || defined(HOST_ARCH_ARM64)
-  // TODO(zra): Verify that these field names are correct for arm64.
+#elif defined(HOST_ARCH_ARM)
   fields_[kCpuInfoProcessor] = "Processor";
   fields_[kCpuInfoModel] = "model name";
   fields_[kCpuInfoHardware] = "Hardware";
   fields_[kCpuInfoFeatures] = "Features";
   method_ = kCpuInfoSystem;
   ProcCpuInfo::InitOnce();
+#elif defined(HOST_ARCH_ARM64)
+  fields_[kCpuInfoProcessor] = "Processor";
+  fields_[kCpuInfoModel] = "CPU implementer";
+  fields_[kCpuInfoHardware] = "CPU implementer";
+  fields_[kCpuInfoFeatures] = "Features";
+  method_ = kCpuInfoSystem;
+  ProcCpuInfo::InitOnce();
 #elif defined(HOST_ARCH_MIPS)
   fields_[kCpuInfoProcessor] = "system type";
   fields_[kCpuInfoModel] = "cpu model";
@@ -61,7 +67,10 @@
 
 bool CpuInfo::FieldContains(CpuInfoIndices idx, const char* search_string) {
   if (method_ == kCpuInfoCpuId) {
-    return strstr(CpuId::field(idx), search_string);
+    const char* field = CpuId::field(idx);
+    bool contains = (strstr(field, search_string) != NULL);
+    free(const_cast<char*>(field));
+    return contains;
   } else {
     ASSERT(method_ == kCpuInfoSystem);
     return ProcCpuInfo::FieldContains(FieldName(idx), search_string);
@@ -69,23 +78,6 @@
 }
 
 
-bool CpuInfo::FieldContainsByString(const char* field,
-                                    const char* search_string) {
-  if (method_ == kCpuInfoCpuId) {
-    for (int i = 0; i < kCpuInfoMax; i++) {
-      if (strcmp(field, fields_[i]) == 0) {
-        return FieldContains(static_cast<CpuInfoIndices>(i), search_string);
-      }
-    }
-    UNIMPLEMENTED();
-    return false;
-  } else {
-    ASSERT(method_ == kCpuInfoSystem);
-    return ProcCpuInfo::FieldContains(field, search_string);
-  }
-}
-
-
 const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
   if (method_ == kCpuInfoCpuId) {
     return CpuId::field(idx);
@@ -96,22 +88,6 @@
 }
 
 
-const char* CpuInfo::ExtractFieldByString(const char* field) {
-  if (method_ == kCpuInfoCpuId) {
-    for (int i = 0; i < kCpuInfoMax; i++) {
-      if (strcmp(field, fields_[i]) == 0) {
-        return ExtractField(static_cast<CpuInfoIndices>(i));
-      }
-    }
-    UNIMPLEMENTED();
-    return NULL;
-  } else {
-    ASSERT(method_ == kCpuInfoSystem);
-    return ProcCpuInfo::ExtractField(field);
-  }
-}
-
-
 bool CpuInfo::HasField(const char* field) {
   if (method_ == kCpuInfoCpuId) {
     return (strcmp(field, fields_[kCpuInfoProcessor]) == 0) ||
diff --git a/runtime/vm/cpuinfo_macos.cc b/runtime/vm/cpuinfo_macos.cc
index 6352391..eef06d9 100644
--- a/runtime/vm/cpuinfo_macos.cc
+++ b/runtime/vm/cpuinfo_macos.cc
@@ -31,10 +31,10 @@
 void CpuInfo::Cleanup() {}
 
 
-bool CpuInfo::FieldContainsByString(const char* field,
-                                    const char* search_string) {
+bool CpuInfo::FieldContains(CpuInfoIndices idx, const char* search_string) {
   ASSERT(method_ != kCpuInfoDefault);
   ASSERT(search_string != NULL);
+  const char* field = FieldName(idx);
   char dest[1024];
   size_t dest_len = 1024;
 
@@ -48,14 +48,9 @@
 }
 
 
-bool CpuInfo::FieldContains(CpuInfoIndices idx, const char* search_string) {
+const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
   ASSERT(method_ != kCpuInfoDefault);
-  return FieldContainsByString(FieldName(idx), search_string);
-}
-
-
-const char* CpuInfo::ExtractFieldByString(const char* field) {
-  ASSERT(method_ != kCpuInfoDefault);
+  const char* field = FieldName(idx);
   ASSERT(field != NULL);
   size_t result_len;
 
@@ -65,7 +60,7 @@
     return 0;
   }
 
-  char* result = new char[result_len];
+  char* result = reinterpret_cast<char*>(malloc(result_len));
   if (sysctlbyname(field, result, &result_len, NULL, 0) != 0) {
     UNREACHABLE();
     return 0;
@@ -75,12 +70,6 @@
 }
 
 
-const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
-  ASSERT(method_ != kCpuInfoDefault);
-  return ExtractFieldByString(FieldName(idx));
-}
-
-
 bool CpuInfo::HasField(const char* field) {
   ASSERT(method_ != kCpuInfoDefault);
   ASSERT(field != NULL);
diff --git a/runtime/vm/cpuinfo_test.cc b/runtime/vm/cpuinfo_test.cc
index 860c407..0b6113b 100644
--- a/runtime/vm/cpuinfo_test.cc
+++ b/runtime/vm/cpuinfo_test.cc
@@ -12,6 +12,8 @@
 UNIT_TEST_CASE(GetCpuModelTest) {
   const char* cpumodel = CpuInfo::GetCpuModel();
   EXPECT_NE(strlen(cpumodel), 0UL);
+  // caller is responsible for deleting the returned cpumodel string.
+  free(const_cast<char*>(cpumodel));
 }
 
 }  // namespace dart
diff --git a/runtime/vm/cpuinfo_win.cc b/runtime/vm/cpuinfo_win.cc
index b648566..1570af7 100644
--- a/runtime/vm/cpuinfo_win.cc
+++ b/runtime/vm/cpuinfo_win.cc
@@ -43,37 +43,12 @@
 }
 
 
-bool CpuInfo::FieldContainsByString(const char* field,
-                                    const char* search_string) {
-  ASSERT(method_ != kCpuInfoDefault);
-  for (int i = 0; i < kCpuInfoMax; i++) {
-    if (strcmp(field, fields_[i]) == 0) {
-      return FieldContains(static_cast<CpuInfoIndices>(i), search_string);
-    }
-  }
-  UNIMPLEMENTED();
-  return false;
-}
-
-
 const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
   ASSERT(method_ != kCpuInfoDefault);
   return CpuId::field(idx);
 }
 
 
-const char* CpuInfo::ExtractFieldByString(const char* field) {
-  ASSERT(method_ != kCpuInfoDefault);
-  for (int i = 0; i < kCpuInfoMax; i++) {
-    if (strcmp(field, fields_[i]) == 0) {
-      return ExtractField(static_cast<CpuInfoIndices>(i));
-    }
-  }
-  UNIMPLEMENTED();
-  return NULL;
-}
-
-
 bool CpuInfo::HasField(const char* field) {
   ASSERT(method_ != kCpuInfoDefault);
   return (strcmp(field, fields_[kCpuInfoProcessor]) == 0) ||
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index b78ea60..d720f70 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -16,6 +16,8 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, trace_shutdown);
+
 static void native_echo(Dart_NativeArguments args);
 static void CustomIsolateImpl_start(Dart_NativeArguments args);
 static Dart_NativeFunction NativeLookup(Dart_Handle name,
@@ -210,6 +212,7 @@
     OS::Print("<< Shutting down isolate(%p)\n", isolate());
     event_queue->RemoveEventsForIsolate(isolate());
     Dart_SetMessageNotifyCallback(NULL);
+    Dart_ExitScope();
     Dart_ShutdownIsolate();
   } else {
     Dart_ExitScope();
@@ -230,7 +233,7 @@
                                         int argc,
                                         bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   const char* name_str = NULL;
   EXPECT(Dart_IsString(name));
   EXPECT_VALID(Dart_StringToCString(name, &name_str));
@@ -315,6 +318,8 @@
 
 
 UNIT_TEST_CASE(CustomIsolates) {
+  bool saved_flag = FLAG_trace_shutdown;
+  FLAG_trace_shutdown = true;
   FLAG_verify_handles = true;
   FLAG_verify_on_transition = true;
   event_queue = new EventQueue();
@@ -354,6 +359,7 @@
 
   delete event_queue;
   event_queue = NULL;
+  FLAG_trace_shutdown = saved_flag;
 }
 
 }  // namespace dart
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index a9ddae5..bef0ebb 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -14,6 +14,7 @@
 #include "vm/handles.h"
 #include "vm/heap.h"
 #include "vm/isolate.h"
+#include "vm/message_handler.h"
 #include "vm/metrics.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
@@ -36,15 +37,20 @@
 DECLARE_FLAG(bool, print_class_table);
 DECLARE_FLAG(bool, trace_isolates);
 DECLARE_FLAG(bool, trace_time_all);
+DECLARE_FLAG(bool, pause_isolates_on_start);
+DECLARE_FLAG(bool, pause_isolates_on_exit);
 DEFINE_FLAG(bool, keep_code, false,
             "Keep deoptimized code for profiling.");
 DEFINE_FLAG(bool, shutdown, true, "Do a clean shutdown of the VM");
+DEFINE_FLAG(bool, trace_shutdown, false, "Trace VM shutdown on stderr");
 
 Isolate* Dart::vm_isolate_ = NULL;
+int64_t Dart::start_time_ = 0;
 ThreadPool* Dart::thread_pool_ = NULL;
 DebugInfo* Dart::pprof_symbol_generator_ = NULL;
 ReadOnlyHandles* Dart::predefined_handles_ = NULL;
 const uint8_t* Dart::instructions_snapshot_buffer_ = NULL;
+const uint8_t* Dart::data_snapshot_buffer_ = NULL;
 
 // Structure for managing read-only global handles allocation used for
 // creating global read-only handles that are pre created and initialized
@@ -72,6 +78,7 @@
 
 const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
                            const uint8_t* instructions_snapshot,
+                           const uint8_t* data_snapshot,
                            Dart_IsolateCreateCallback create,
                            Dart_IsolateShutdownCallback shutdown,
                            Dart_FileOpenCallback file_open,
@@ -89,16 +96,20 @@
   OS::InitOnce();
   VirtualMemory::InitOnce();
   OSThread::InitOnce();
-  Timeline::InitOnce();
-  TimelineDurationScope tds(Timeline::GetVMStream(),
-                            "Dart::InitOnce");
+  if (FLAG_support_timeline) {
+    Timeline::InitOnce();
+  }
+  NOT_IN_PRODUCT(TimelineDurationScope tds(Timeline::GetVMStream(),
+                                           "Dart::InitOnce"));
   Isolate::InitOnce();
   PortMap::InitOnce();
   FreeListElement::InitOnce();
   Api::InitOnce();
-  CodeObservers::InitOnce();
-  ThreadInterrupter::InitOnce();
-  Profiler::InitOnce();
+  NOT_IN_PRODUCT(CodeObservers::InitOnce());
+  if (FLAG_profiler) {
+    ThreadInterrupter::InitOnce();
+    Profiler::InitOnce();
+  }
   SemiSpace::InitOnce();
   Metric::InitOnce();
   StoreBuffer::InitOnce();
@@ -120,10 +131,10 @@
     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);
     // Verify assumptions about executing in the VM isolate.
     ASSERT(vm_isolate_ == Isolate::Current());
@@ -146,6 +157,8 @@
     if (vm_isolate_snapshot != NULL) {
       if (instructions_snapshot != NULL) {
         vm_isolate_->SetupInstructionsSnapshotPage(instructions_snapshot);
+        ASSERT(data_snapshot != NULL);
+        vm_isolate_->SetupDataSnapshotPage(data_snapshot);
       }
       const Snapshot* snapshot = Snapshot::SetupFromBuffer(vm_isolate_snapshot);
       if (snapshot == NULL) {
@@ -155,6 +168,7 @@
       VmIsolateSnapshotReader reader(snapshot->content(),
                                      snapshot->length(),
                                      instructions_snapshot,
+                                     data_snapshot,
                                      T);
       const Error& error = Error::Handle(reader.ReadVmIsolateSnapshot());
       if (!error.IsNull()) {
@@ -197,7 +211,10 @@
   Isolate::SetCreateCallback(create);
   Isolate::SetShutdownCallback(shutdown);
 
-  Service::SetGetServiceAssetsCallback(get_service_assets);
+  if (FLAG_support_service) {
+    Service::SetGetServiceAssetsCallback(get_service_assets);
+  }
+
   ServiceIsolate::Run();
 
   return NULL;
@@ -222,12 +239,28 @@
     return "VM already terminated.";
   }
 
-  // Shut down profiling.
-  Profiler::Shutdown();
+  if (FLAG_trace_shutdown) {
+    OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Starting shutdown\n",
+                 timestamp());
+  }
+
+  if (FLAG_profiler) {
+    // Shut down profiling.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down profiling\n",
+                   timestamp());
+    }
+    Profiler::Shutdown();
+  }
+
 
   {
     // Set the VM isolate as current isolate when shutting down
     // Metrics so that we can use a StackZone.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Entering vm isolate\n",
+                   timestamp());
+    }
     bool result = Thread::EnterIsolate(vm_isolate_);
     ASSERT(result);
     Metric::Cleanup();
@@ -236,19 +269,39 @@
 
   if (FLAG_shutdown) {
     // Disable the creation of new isolates.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling isolate creation\n",
+                   timestamp());
+    }
     Isolate::DisableIsolateCreation();
 
     // Send the OOB Kill message to all remaining application isolates.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Killing all app isolates\n",
+                   timestamp());
+    }
     Isolate::KillAllIsolates(Isolate::kInternalKillMsg);
 
     // Shutdown the service isolate.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down service isolate\n",
+                   timestamp());
+    }
     ServiceIsolate::Shutdown();
 
     // Wait for all application isolates and the service isolate to shutdown
     // before shutting down the thread pool.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Waiting for isolate shutdown\n",
+                   timestamp());
+    }
     WaitForIsolateShutdown();
 
     // Shutdown the thread pool. On return, all thread pool threads have exited.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting thread pool\n",
+                   timestamp());
+    }
     delete thread_pool_;
     thread_pool_ = NULL;
 
@@ -258,9 +311,17 @@
     // This must come after deletion of the thread pool to avoid a race in which
     // a thread spawned by the thread pool does not exit through the thread
     // pool, messing up its bookkeeping.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling OS Thread creation\n",
+                   timestamp());
+    }
     OSThread::DisableOSThreadCreation();
 
     // Set the VM isolate as current isolate.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Cleaning up vm isolate\n",
+                   timestamp());
+    }
     bool result = Thread::EnterIsolate(vm_isolate_);
     ASSERT(result);
 
@@ -277,16 +338,41 @@
     OSThread* os_thread = OSThread::Current();
     OSThread::SetCurrent(NULL);
     delete os_thread;
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleted os_thread\n",
+                   timestamp());
+    }
   } else {
     // Shutdown the service isolate.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down service isolate\n",
+                   timestamp());
+    }
     ServiceIsolate::Shutdown();
 
     // Disable thread creation.
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling OS Thread creation\n",
+                   timestamp());
+    }
     OSThread::DisableOSThreadCreation();
   }
 
-  CodeObservers::DeleteAll();
-  Timeline::Shutdown();
+  if (FLAG_trace_shutdown) {
+    OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting code observers\n",
+                 timestamp());
+  }
+  NOT_IN_PRODUCT(CodeObservers::DeleteAll());
+  if (FLAG_support_timeline) {
+    if (FLAG_trace_shutdown) {
+      OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down timeline\n",
+                   timestamp());
+    }
+    Timeline::Shutdown();
+  }
+  if (FLAG_trace_shutdown) {
+    OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done\n", timestamp());
+  }
 
   return NULL;
 }
@@ -304,15 +390,17 @@
   // Initialize the new isolate.
   Thread* T = Thread::Current();
   Isolate* I = T->isolate();
-  TimelineDurationScope tds(T, I->GetIsolateStream(), "InitializeIsolate");
-  tds.SetNumArguments(1);
-  tds.CopyArgument(0, "isolateName", I->name());
-
+  NOT_IN_PRODUCT(
+    TimelineDurationScope tds(T, I->GetIsolateStream(), "InitializeIsolate");
+    tds.SetNumArguments(1);
+    tds.CopyArgument(0, "isolateName", I->name());
+  )
   ASSERT(I != NULL);
   StackZone zone(T);
   HandleScope handle_scope(T);
   {
-    TimelineDurationScope tds(T, I->GetIsolateStream(), "ObjectStore::Init");
+    NOT_IN_PRODUCT(TimelineDurationScope tds(T,
+        I->GetIsolateStream(), "ObjectStore::Init"));
     ObjectStore::Init(I);
   }
 
@@ -322,8 +410,8 @@
   }
   if (snapshot_buffer != NULL) {
     // Read the snapshot and setup the initial state.
-    TimelineDurationScope tds(
-        T, I->GetIsolateStream(), "IsolateSnapshotReader");
+    NOT_IN_PRODUCT(TimelineDurationScope tds(T,
+        I->GetIsolateStream(), "IsolateSnapshotReader"));
     // TODO(turnidge): Remove once length is not part of the snapshot.
     const Snapshot* snapshot = Snapshot::SetupFromBuffer(snapshot_buffer);
     if (snapshot == NULL) {
@@ -338,6 +426,7 @@
     IsolateSnapshotReader reader(snapshot->content(),
                                  snapshot->length(),
                                  Dart::instructions_snapshot_buffer(),
+                                 Dart::data_snapshot_buffer(),
                                  T);
     const Error& error = Error::Handle(reader.ReadFullSnapshot());
     if (!error.IsNull()) {
@@ -356,27 +445,30 @@
   }
 
   Object::VerifyBuiltinVtables();
-#if defined(DEBUG)
-  I->heap()->Verify(kForbidMarked);
-#endif
+  DEBUG_ONLY(I->heap()->Verify(kForbidMarked));
 
   {
-    TimelineDurationScope tds(T, I->GetIsolateStream(), "StubCode::Init");
+    NOT_IN_PRODUCT(TimelineDurationScope tds(T,
+        I->GetIsolateStream(), "StubCode::Init"));
     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);
 
   if (snapshot_buffer == NULL) {
-    if (!I->object_store()->PreallocateObjects()) {
-      return I->object_store()->sticky_error();
+    const Error& error = Error::Handle(I->object_store()->PreallocateObjects());
+    if (!error.IsNull()) {
+      return error.raw();
     }
   }
 
@@ -388,10 +480,16 @@
   }
 
   ServiceIsolate::MaybeMakeServiceIsolate(I);
-
+  if (!ServiceIsolate::IsServiceIsolate(I)) {
+    I->message_handler()->set_should_pause_on_start(
+        FLAG_pause_isolates_on_start);
+    I->message_handler()->set_should_pause_on_exit(
+        FLAG_pause_isolates_on_exit);
+  }
   ServiceIsolate::SendIsolateStartupMessage();
-  I->debugger()->NotifyIsolateCreated();
-
+  if (FLAG_support_debugger) {
+    I->debugger()->NotifyIsolateCreated();
+  }
   // Create tag table.
   I->set_tag_table(GrowableObjectArray::Handle(GrowableObjectArray::New()));
   // Set up default UserTag.
@@ -436,6 +534,12 @@
 }
 
 
+int64_t Dart::timestamp() {
+  return ((OS::GetCurrentTimeMicros() - Dart::start_time_) /
+          kMillisecondsPerSecond);
+}
+
+
 uword Dart::AllocateReadOnlyHandle() {
   ASSERT(Isolate::Current() == Dart::vm_isolate());
   ASSERT(predefined_handles_ != NULL);
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index 412eef2..aa43e12 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -23,6 +23,7 @@
   static const char* InitOnce(
       const uint8_t* vm_isolate_snapshot,
       const uint8_t* instructions_snapshot,
+      const uint8_t* data_snapshot,
       Dart_IsolateCreateCallback create,
       Dart_IsolateShutdownCallback shutdown,
       Dart_FileOpenCallback file_open,
@@ -43,6 +44,10 @@
   static Isolate* vm_isolate() { return vm_isolate_; }
   static ThreadPool* thread_pool() { return thread_pool_; }
 
+  // Returns a timestamp for use in debugging output in milliseconds
+  // since start time.
+  static int64_t timestamp();
+
   static void set_pprof_symbol_generator(DebugInfo* value) {
     pprof_symbol_generator_ = value;
   }
@@ -64,14 +69,23 @@
     return instructions_snapshot_buffer_ != NULL;
   }
 
+  static const uint8_t* data_snapshot_buffer() {
+    return data_snapshot_buffer_;
+  }
+  static void set_data_snapshot_buffer(const uint8_t* buffer) {
+    data_snapshot_buffer_ = buffer;
+  }
+
  private:
   static void WaitForIsolateShutdown();
 
   static Isolate* vm_isolate_;
+  static int64_t start_time_;
   static ThreadPool* thread_pool_;
   static DebugInfo* pprof_symbol_generator_;
   static ReadOnlyHandles* predefined_handles_;
   static const uint8_t* instructions_snapshot_buffer_;
+  static const uint8_t* data_snapshot_buffer_;
 };
 
 }  // namespace dart
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 796aaca..4c6fd00 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -7,6 +7,7 @@
 #include "include/dart_native_api.h"
 
 #include "platform/assert.h"
+#include "lib/stacktrace.h"
 #include "vm/class_finalizer.h"
 #include "vm/compiler.h"
 #include "vm/dart.h"
@@ -15,7 +16,6 @@
 #include "vm/dart_api_state.h"
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
-#include "vm/debuginfo.h"
 #include "vm/exceptions.h"
 #include "vm/flags.h"
 #include "vm/growable_array.h"
@@ -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)
@@ -77,7 +75,7 @@
   }
 }
 
-#if 0
+#ifndef PRODUCT
 #define API_TIMELINE_DURATION                                                  \
   TimelineDurationScope tds(Thread::Current(),                                 \
                             Timeline::GetVMApiStream(),                        \
@@ -88,9 +86,9 @@
                              Timeline::GetVMApiStream(),                       \
                              CURRENT_FUNC)
 #else
-#define API_TIMELINE_DURATION ASSERT(true)
-#define API_TIMELINE_BEGIN_END ASSERT(true)
-#endif
+#define API_TIMELINE_DURATION do { } while (false)
+#define API_TIMELINE_BEGIN_END do { } while (false)
+#endif  // !PRODUCT
 
 #if defined(DEBUG)
 // An object visitor which will iterate over all the function objects in the
@@ -111,7 +109,7 @@
       // Verify that the result type of a function is canonical or a
       // TypeParameter.
       typeHandle_ ^= funcHandle_.result_type();
-      ASSERT(typeHandle_.IsNull() ||
+      ASSERT(typeHandle_.IsMalformed() ||
              !typeHandle_.IsResolved() ||
              typeHandle_.IsTypeParameter() ||
              typeHandle_.IsCanonical());
@@ -120,8 +118,9 @@
       const intptr_t num_parameters = funcHandle_.NumParameters();
       for (intptr_t i = 0; i < num_parameters; i++) {
         typeHandle_ = funcHandle_.ParameterTypeAt(i);
-        ASSERT(typeHandle_.IsTypeParameter() ||
+        ASSERT(typeHandle_.IsMalformed() ||
                !typeHandle_.IsResolved() ||
+               typeHandle_.IsTypeParameter() ||
                typeHandle_.IsCanonical());
       }
     }
@@ -147,7 +146,9 @@
     if (obj_class.IsSubtypeOf(Object::null_type_arguments(),
                               list_class,
                               Object::null_type_arguments(),
-                              &malformed_type_error)) {
+                              &malformed_type_error,
+                              NULL,
+                              Heap::kNew)) {
       ASSERT(malformed_type_error.IsNull());  // Type is a raw List.
       return instance.raw();
     }
@@ -167,7 +168,9 @@
     if (obj_class.IsSubtypeOf(Object::null_type_arguments(),
                               map_class,
                               Object::null_type_arguments(),
-                              &malformed_type_error)) {
+                              &malformed_type_error,
+                              NULL,
+                              Heap::kNew)) {
       ASSERT(malformed_type_error.IsNull());  // Type is a raw Map.
       return instance.raw();
     }
@@ -357,6 +360,26 @@
 }
 
 
+static const char* GetErrorString(Thread* thread, const Object& obj) {
+  // This function requires an API scope to be present.
+  if (obj.IsError()) {
+    ASSERT(thread->api_top_scope() != NULL);
+    const Error& error = Error::Cast(obj);
+    const char* str = error.ToErrorCString();
+    intptr_t len = strlen(str) + 1;
+    char* str_copy = Api::TopScope(thread)->zone()->Alloc<char>(len);
+    strncpy(str_copy, str, len);
+    // Strip a possible trailing '\n'.
+    if ((len > 1) && (str_copy[len - 2] == '\n')) {
+      str_copy[len - 2] = '\0';
+    }
+    return str_copy;
+  } else {
+    return "";
+  }
+}
+
+
 Dart_Handle Api::InitNewHandle(Thread* thread, RawObject* raw) {
   LocalHandles* local_handles = Api::TopScope(thread)->local_handles();
   ASSERT(local_handles != NULL);
@@ -440,8 +463,8 @@
   if (ClassFinalizer::ProcessPendingClasses()) {
     return Api::Success();
   }
-  ASSERT(isolate->object_store()->sticky_error() != Object::null());
-  return Api::NewHandle(thread, isolate->object_store()->sticky_error());
+  ASSERT(thread->sticky_error() != Object::null());
+  return Api::NewHandle(thread, thread->sticky_error());
 }
 
 
@@ -451,7 +474,9 @@
 
 
 Dart_Handle Api::NewError(const char* format, ...) {
-  DARTSCOPE(Thread::Current());
+  Thread* T = Thread::Current();
+  CHECK_API_SCOPE(T);
+  HANDLESCOPE(T);
   CHECK_CALLBACK_STATE(T);
 
   va_list args;
@@ -713,7 +738,7 @@
 // --- Handles ---
 
 DART_EXPORT bool Dart_IsError(Dart_Handle handle) {
-  return RawObject::IsErrorClassId(Api::ClassId(handle));
+  return Api::IsError(handle);
 }
 
 
@@ -748,20 +773,7 @@
   API_TIMELINE_DURATION;
   DARTSCOPE(Thread::Current());
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
-  if (obj.IsError()) {
-    const Error& error = Error::Cast(obj);
-    const char* str = error.ToErrorCString();
-    intptr_t len = strlen(str) + 1;
-    char* str_copy = Api::TopScope(T)->zone()->Alloc<char>(len);
-    strncpy(str_copy, str, len);
-    // Strip a possible trailing '\n'.
-    if ((len > 1) && (str_copy[len - 2] == '\n')) {
-      str_copy[len - 2] = '\0';
-    }
-    return str_copy;
-  } else {
-    return "";
-  }
+  return GetErrorString(T, obj);
 }
 
 
@@ -818,7 +830,8 @@
   Instance& obj = Instance::Handle(Z);
   intptr_t class_id = Api::ClassId(exception);
   if ((class_id == kApiErrorCid) || (class_id == kLanguageErrorCid)) {
-    obj = String::New(::Dart_GetError(exception));
+    const Object& excp = Object::Handle(Z, Api::UnwrapHandle(exception));
+    obj = String::New(GetErrorString(T, excp));
   } else {
     obj = Api::UnwrapInstanceHandle(Z, exception).raw();
     if (obj.IsNull()) {
@@ -848,6 +861,7 @@
     return Api::NewError("No Dart frames on stack, cannot propagate error.");
   }
 
+  TransitionNativeToVM transition(thread);
   // Unwind all the API scopes till the exit frame before propagating.
   const Error* error;
   {
@@ -1033,6 +1047,7 @@
   if (callback == NULL) {
     return NULL;
   }
+  TransitionNativeToVM transition(thread);
   return AllocateFinalizableHandle(thread,
                                    object,
                                    peer,
@@ -1119,6 +1134,7 @@
 DART_EXPORT char* Dart_Initialize(
     const uint8_t* vm_isolate_snapshot,
     const uint8_t* instructions_snapshot,
+    const uint8_t* data_snapshot,
     Dart_IsolateCreateCallback create,
     Dart_IsolateInterruptCallback interrupt,
     Dart_IsolateUnhandledExceptionCallback unhandled,
@@ -1129,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) {
@@ -1142,6 +1158,7 @@
   }
   const char* err_msg = Dart::InitOnce(vm_isolate_snapshot,
                                        instructions_snapshot,
+                                       data_snapshot,
                                        create, shutdown,
                                        file_open, file_read, file_write,
                                        file_close, entropy_source,
@@ -1223,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);
@@ -1244,13 +1260,19 @@
     const Error& error_obj =
         Error::Handle(Z, Dart::InitializeIsolate(snapshot, callback_data));
     if (error_obj.IsNull()) {
-  #if defined(DART_NO_SNAPSHOT)
+  #if defined(DART_NO_SNAPSHOT) && !defined(PRODUCT)
       if (FLAG_check_function_fingerprints) {
         Library::CheckFunctionFingerprints();
       }
-  #endif  // defined(DART_NO_SNAPSHOT).
+  #endif  // defined(DART_NO_SNAPSHOT) && !defined(PRODUCT).
       // We exit the API scope entered above.
       Dart_ExitScope();
+      // A Thread structure has been associated to the thread, we do the
+      // safepoint transition explicity here instead of using the
+      // TransitionXXX scope objects as the reverse transition happens
+      // outside this scope in Dart_ShutdownIsolate/Dart_ExitIsolate.
+      T->set_execution_state(Thread::kThreadInNative);
+      T->EnterSafepoint();
       return Api::CastIsolate(I);
     }
     *error = strdup(error_obj.ToErrorCString());
@@ -1272,6 +1294,12 @@
     HandleScope handle_scope(T);
     Dart::RunShutdownCallback();
   }
+  // The Thread structure is disassociated from the isolate, we do the
+  // safepoint transition explicity here instead of using the TransitionXXX
+  // scope objects as the original transition happened outside this scope in
+  // Dart_EnterIsolate/Dart_CreateIsolate.
+  T->ExitSafepoint();
+  T->set_execution_state(Thread::kThreadInVM);
   Dart::ShutdownIsolate();
 }
 
@@ -1315,6 +1343,13 @@
   if (!Thread::EnterIsolate(iso)) {
     FATAL("Unable to Enter Isolate as Dart VM is shutting down");
   }
+  // A Thread structure has been associated to the thread, we do the
+  // safepoint transition explicity here instead of using the
+  // TransitionXXX scope objects as the reverse transition happens
+  // outside this scope in Dart_ExitIsolate/Dart_ShutdownIsolate.
+  Thread* T = Thread::Current();
+  T->set_execution_state(Thread::kThreadInNative);
+  T->EnterSafepoint();
 }
 
 
@@ -1336,8 +1371,80 @@
 }
 
 
+DART_EXPORT bool Dart_ShouldPauseOnStart() {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  return isolate->message_handler()->should_pause_on_start();
+}
+
+
+DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause) {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  if (isolate->is_runnable()) {
+    FATAL1("%s expects the current isolate to not be runnable yet.",
+           CURRENT_FUNC);
+  }
+  return isolate->message_handler()->set_should_pause_on_start(should_pause);
+}
+
+
+DART_EXPORT bool Dart_IsPausedOnStart() {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  return isolate->message_handler()->is_paused_on_start();
+}
+
+
+DART_EXPORT void Dart_SetPausedOnStart(bool paused) {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  if (isolate->message_handler()->is_paused_on_start() != paused) {
+    isolate->message_handler()->PausedOnStart(paused);
+  }
+}
+
+
+DART_EXPORT bool Dart_ShouldPauseOnExit() {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  return isolate->message_handler()->should_pause_on_exit();
+}
+
+
+DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause) {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  return isolate->message_handler()->set_should_pause_on_exit(should_pause);
+}
+
+
+DART_EXPORT bool Dart_IsPausedOnExit() {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  return isolate->message_handler()->is_paused_on_exit();
+}
+
+
+DART_EXPORT void Dart_SetPausedOnExit(bool paused) {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  if (isolate->message_handler()->is_paused_on_exit() != paused) {
+    isolate->message_handler()->PausedOnExit(paused);
+  }
+}
+
+
 DART_EXPORT void Dart_ExitIsolate() {
-  CHECK_ISOLATE(Isolate::Current());
+  Thread* T = Thread::Current();
+  CHECK_ISOLATE(T->isolate());
+  // The Thread structure is disassociated from the isolate, we do the
+  // safepoint transition explicity here instead of using the TransitionXXX
+  // scope objects as the original transition happened outside this scope in
+  // Dart_EnterIsolate/Dart_CreateIsolate.
+  ASSERT(T->execution_state() == Thread::kThreadInNative);
+  T->ExitSafepoint();
+  T->set_execution_state(Thread::kThreadInVM);
   Thread::ExitIsolate();
 }
 
@@ -1379,8 +1486,6 @@
   I->heap()->IterateObjects(&check_canonical);
 #endif  // #if defined(DEBUG).
 
-  // Since this is only a snapshot the root library should not be set.
-  I->object_store()->set_root_library(Library::Handle(Z));
   FullSnapshotWriter writer(vm_isolate_snapshot_buffer,
                             isolate_snapshot_buffer,
                             NULL, /* instructions_snapshot_buffer */
@@ -1477,6 +1582,13 @@
 }
 
 
+DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback() {
+  Isolate* isolate = Isolate::Current();
+  CHECK_ISOLATE(isolate);
+  return isolate->message_notify_callback();
+}
+
+
 struct RunLoopData {
   Monitor* monitor;
   bool done;
@@ -1498,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.
-    Thread::ExitIsolate();
+    Monitor monitor;
+    MonitorLocker ml(&monitor);
     RunLoopData data;
     data.monitor = &monitor;
     data.done = false;
@@ -1513,13 +1625,11 @@
     while (!data.done) {
       ml.Wait();
     }
-    if (!Thread::EnterIsolate(I)) {
-      FATAL("Inconsistent state, VM shutting down while in run loop.");
-    }
   }
-  if (I->object_store()->sticky_error() != Object::null()) {
-    Dart_Handle error = Api::NewHandle(T, I->object_store()->sticky_error());
-    I->object_store()->clear_sticky_error();
+  ::Dart_EnterIsolate(Api::CastIsolate(I));
+  if (T->sticky_error() != Object::null()) {
+    Dart_Handle error = Api::NewHandle(T, T->sticky_error());
+    T->clear_sticky_error();
     return error;
   }
   if (FLAG_print_class_table) {
@@ -1536,9 +1646,26 @@
   CHECK_API_SCOPE(T);
   CHECK_CALLBACK_STATE(T);
   API_TIMELINE_BEGIN_END;
+  TransitionNativeToVM transition(T);
   if (I->message_handler()->HandleNextMessage() != MessageHandler::kOK) {
-    Dart_Handle error = Api::NewHandle(T, I->object_store()->sticky_error());
-    I->object_store()->clear_sticky_error();
+    Dart_Handle error = Api::NewHandle(T, T->sticky_error());
+    T->clear_sticky_error();
+    return error;
+  }
+  return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_HandleMessages() {
+  Thread* T = Thread::Current();
+  Isolate* I = T->isolate();
+  CHECK_API_SCOPE(T);
+  CHECK_CALLBACK_STATE(T);
+  API_TIMELINE_BEGIN_END;
+  TransitionNativeToVM transition(T);
+  if (I->message_handler()->HandleAllMessages() != MessageHandler::kOK) {
+    Dart_Handle error = Api::NewHandle(T, T->sticky_error());
+    T->clear_sticky_error();
     return error;
   }
   return Api::Success();
@@ -1551,6 +1678,7 @@
   CHECK_API_SCOPE(T);
   CHECK_CALLBACK_STATE(T);
   API_TIMELINE_DURATION;
+  TransitionNativeToVM transition(T);
   ASSERT(I->GetAndClearResumeRequest() == false);
   MessageHandler::MessageStatus status =
       I->message_handler()->HandleOOBMessages();
@@ -1858,14 +1986,7 @@
 
 
 DART_EXPORT bool Dart_IsClosure(Dart_Handle object) {
-  // We can't use a fast class index check here because there are many
-  // different signature classes for closures.
-  Thread* thread = Thread::Current();
-  CHECK_ISOLATE(thread->isolate());
-  ReusableObjectHandleScope reused_obj_handle(thread);
-  const Instance& closure_obj =
-      Api::UnwrapInstanceHandle(reused_obj_handle, object);
-  return (!closure_obj.IsNull() && closure_obj.IsClosure());
+  return Api::ClassId(object) == kClosureCid;
 }
 
 
@@ -1896,7 +2017,9 @@
     bool is_future = obj_class.IsSubtypeOf(Object::null_type_arguments(),
                                            future_class,
                                            Object::null_type_arguments(),
-                                           &malformed_type_error);
+                                           &malformed_type_error,
+                                           NULL,
+                                           Heap::kNew);
     ASSERT(malformed_type_error.IsNull());  // Type is a raw Future.
     return is_future;
   }
@@ -1917,7 +2040,8 @@
   if (!obj.IsInstance()) {
     RETURN_TYPE_ERROR(Z, instance, Instance);
   }
-  const Type& type = Type::Handle(Instance::Cast(obj).GetType());
+  const AbstractType& type =
+      AbstractType::Handle(Instance::Cast(obj).GetType());
   return Api::NewHandle(T, type.Canonicalize());
 }
 
@@ -3677,7 +3801,8 @@
       // type arguments of the type argument.
       Error& bound_error = Error::Handle();
       redirect_type ^= redirect_type.InstantiateFrom(type_arguments,
-                                                     &bound_error);
+                                                     &bound_error,
+                                                     NULL, NULL, Heap::kNew);
       if (!bound_error.IsNull()) {
         return Api::NewHandle(T, bound_error.raw());
       }
@@ -3888,7 +4013,7 @@
 
   // Construct name of the constructor to invoke.
   const String& constructor_name = Api::UnwrapStringHandle(Z, name);
-  const Type& type_obj = Type::Handle(Z, instance.GetType());
+  const AbstractType& type_obj = AbstractType::Handle(Z, instance.GetType());
   const Class& cls = Class::Handle(Z, type_obj.type_class());
   const String& class_name = String::Handle(Z, cls.Name());
   const Array& strings = Array::Handle(Z, Array::New(3));
@@ -4193,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);
@@ -4381,6 +4506,10 @@
   Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
   CHECK_CALLBACK_STATE(thread);
+  if (Api::IsError(exception)) {
+    ::Dart_PropagateError(exception);
+  }
+
   {
     const Instance& excp = Api::UnwrapInstanceHandle(zone, exception);
     if (excp.IsNull()) {
@@ -4393,6 +4522,7 @@
     return Api::NewError("No Dart frames on stack, cannot throw exception");
   }
 
+  TransitionNativeToVM transition(thread);
   // Unwind all the API scopes till the exit frame before throwing an
   // exception.
   const Instance* saved_exception;
@@ -4431,6 +4561,7 @@
     return Api::NewError("No Dart frames on stack, cannot throw exception");
   }
 
+  TransitionNativeToVM transition(thread);
   // Unwind all the API scopes till the exit frame before throwing an
   // exception.
   const Instance* saved_exception;
@@ -4802,10 +4933,17 @@
                                      Dart_Handle retval) {
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
   ASSERT(arguments->thread()->isolate() == Isolate::Current());
-  if ((retval != Api::Null()) && (!Api::IsInstance(retval))) {
+  if ((retval != Api::Null()) &&
+      !Api::IsInstance(retval) &&
+      !Api::IsError(retval)) {
+    // Print the current stack trace to make the problematic caller
+    // easier to find.
+    const Stacktrace& stacktrace = GetCurrentStacktrace(0);
+    OS::PrintErr("=== Current Trace:\n%s===\n", stacktrace.ToCString());
+
     const Object& ret_obj = Object::Handle(Api::UnwrapHandle(retval));
-    FATAL1("Return value check failed: saw '%s' expected a dart Instance.",
-           ret_obj.ToCString());
+    FATAL1("Return value check failed: saw '%s' expected a dart Instance or "
+           "an Error.", ret_obj.ToCString());
   }
   ASSERT(retval != 0);
   Api::SetReturnValue(arguments, retval);
@@ -4826,12 +4964,51 @@
 
 
 // --- 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();
-  Scope api_scope(thread);
   Dart_EnvironmentCallback callback = isolate->environment_callback();
   String& result = String::Handle(thread->zone());
   if (callback != NULL) {
+    TransitionVMToNative transition(thread);
+    Scope api_scope(thread);
     Dart_Handle response = callback(Api::NewHandle(thread, name.raw()));
     if (::Dart_IsString(response)) {
       result ^= Api::UnwrapHandle(response);
@@ -4846,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();
 }
 
@@ -4996,6 +5164,10 @@
   NoHeapGrowthControlScope no_growth_control;
 
   const Snapshot* snapshot = Snapshot::SetupFromBuffer(buffer);
+  if (snapshot == NULL) {
+    return Api::NewError("%s expects parameter 'buffer' to be a script type"
+                         " snapshot with a valid length.", CURRENT_FUNC);
+  }
   if (!snapshot->IsScriptSnapshot()) {
     return Api::NewError("%s expects parameter 'buffer' to be a script type"
                          " snapshot.", CURRENT_FUNC);
@@ -5135,7 +5307,7 @@
 
   // Construct the type object, canonicalize it and return.
   Type& instantiated_type = Type::Handle(
-      Type::New(cls, type_args_obj, Scanner::kNoSourcePos));
+      Type::New(cls, type_args_obj, TokenPosition::kNoSource));
   instantiated_type ^= ClassFinalizer::FinalizeType(
       cls, instantiated_type, ClassFinalizer::kCanonicalize);
   return Api::NewHandle(T, instantiated_type.raw());
@@ -5400,14 +5572,18 @@
   // the new code, the debugger convert them to unresolved source breakpoints.
   // The code that completes the futures (invoked below) may call into the
   // newly loaded code and trigger one of these breakpoints.
-  I->debugger()->NotifyDoneLoading();
+  if (FLAG_support_debugger) {
+    I->debugger()->NotifyDoneLoading();
+  }
 
-  // Notify mirrors that MirrorSystem.libraries needs to be recomputed.
-  const Library& libmirrors = Library::Handle(Z, Library::MirrorsLibrary());
-  const Field& dirty_bit = Field::Handle(Z,
-      libmirrors.LookupLocalField(String::Handle(String::New("dirty"))));
-  ASSERT(!dirty_bit.IsNull() && dirty_bit.is_static());
-  dirty_bit.SetStaticValue(Bool::True());
+  if (FLAG_enable_mirrors) {
+    // Notify mirrors that MirrorSystem.libraries needs to be recomputed.
+    const Library& libmirrors = Library::Handle(Z, Library::MirrorsLibrary());
+    const Field& dirty_bit = Field::Handle(Z,
+        libmirrors.LookupLocalField(String::Handle(String::New("dirty"))));
+    ASSERT(!dirty_bit.IsNull() && dirty_bit.is_static());
+    dirty_bit.SetStaticValue(Bool::True());
+  }
 
   if (complete_futures) {
     const Library& corelib = Library::Handle(Z, Library::CoreLibrary());
@@ -5506,7 +5682,9 @@
     const char* name,
     Dart_ServiceRequestCallback callback,
     void* user_data) {
-  Service::RegisterIsolateEmbedderCallback(name, callback, user_data);
+  if (FLAG_support_service) {
+    Service::RegisterIsolateEmbedderCallback(name, callback, user_data);
+  }
 }
 
 
@@ -5514,13 +5692,18 @@
     const char* name,
     Dart_ServiceRequestCallback callback,
     void* user_data) {
-  Service::RegisterRootEmbedderCallback(name, callback, user_data);
+  if (FLAG_support_service) {
+    Service::RegisterRootEmbedderCallback(name, callback, user_data);
+  }
 }
 
 
 DART_EXPORT Dart_Handle Dart_SetServiceStreamCallbacks(
     Dart_ServiceStreamListenCallback listen_callback,
     Dart_ServiceStreamCancelCallback cancel_callback) {
+  if (!FLAG_support_service) {
+    return Api::Success();
+  }
   if (listen_callback != NULL) {
     if (Service::stream_listen_callback() != NULL) {
       return Api::NewError(
@@ -5558,6 +5741,9 @@
                                                   const char* event_kind,
                                                   const uint8_t* bytes,
                                                   intptr_t bytes_length) {
+#if defined(PRODUCT)
+  return Api::Success();
+#else  // defined(PRODUCT)
   DARTSCOPE(Thread::Current());
   Isolate* I = T->isolate();
   if (stream_id == NULL) {
@@ -5576,6 +5762,7 @@
   Service::SendEmbedderEvent(I, stream_id, event_kind,
                              bytes, bytes_length);
   return Api::Success();
+#endif  // defined(PRODUCT)
 }
 
 
@@ -5585,6 +5772,9 @@
 
 
 DART_EXPORT void Dart_TimelineSetRecordedStreams(int64_t stream_mask) {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE(isolate);
   isolate->GetAPIStream()->set_enabled(
@@ -5606,6 +5796,9 @@
 
 DART_EXPORT void Dart_GlobalTimelineSetRecordedStreams(int64_t stream_mask) {
   // Per isolate overrides.
+  if (!FLAG_support_timeline) {
+    return;
+  }
   const bool api_enabled = (stream_mask & DART_TIMELINE_STREAM_API) != 0;
   const bool compiler_enabled =
       (stream_mask & DART_TIMELINE_STREAM_COMPILER) != 0;
@@ -5733,6 +5926,9 @@
 
 DART_EXPORT bool Dart_TimelineGetTrace(Dart_StreamConsumer consumer,
                                        void* user_data) {
+  if (!FLAG_support_timeline) {
+    return false;
+  }
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE(isolate);
   if (consumer == NULL) {
@@ -5755,6 +5951,9 @@
 
 DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer,
                                              void* user_data) {
+  if (!FLAG_support_timeline) {
+    return false;
+  }
   // To support various embedders, it must be possible to call this function
   // from a thread for which we have not entered an Isolate and set up a Thread
   // TLS object. Therefore, a Zone may not be available, a StackZone cannot be
@@ -5778,6 +5977,9 @@
 DART_EXPORT Dart_Handle Dart_TimelineDuration(const char* label,
                                               int64_t start_micros,
                                               int64_t end_micros) {
+  if (!FLAG_support_timeline) {
+    return Api::Success();
+  }
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE(isolate);
   if (label == NULL) {
@@ -5799,6 +6001,9 @@
 
 
 DART_EXPORT Dart_Handle Dart_TimelineInstant(const char* label) {
+  if (!FLAG_support_timeline) {
+    return Api::Success();
+  }
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE(isolate);
   if (label == NULL) {
@@ -5817,6 +6022,9 @@
 
 DART_EXPORT Dart_Handle Dart_TimelineAsyncBegin(const char* label,
                                                 int64_t* async_id) {
+  if (!FLAG_support_timeline) {
+    return Api::Success();
+  }
   Isolate* isolate = Isolate::Current();
   CHECK_ISOLATE(isolate);
   if (label == NULL) {
@@ -5842,6 +6050,9 @@
 
 DART_EXPORT Dart_Handle Dart_TimelineAsyncInstant(const char* label,
                                                   int64_t async_id) {
+  if (!FLAG_support_timeline) {
+    return Api::Success();
+  }
   if (async_id < 0) {
     return Api::Success();
   }
@@ -5863,6 +6074,9 @@
 
 DART_EXPORT Dart_Handle Dart_TimelineAsyncEnd(const char* label,
                                               int64_t async_id) {
+  if (!FLAG_support_timeline) {
+    return Api::Success();
+  }
   if (async_id < 0) {
     return Api::Success();
   }
@@ -5882,7 +6096,9 @@
 }
 
 
-#if defined(DART_PRECOMPILED)
+// The precompiler is included in dart_no_snapshot and dart_noopt, and
+// excluded from dart and dart_precompiled_runtime.
+#if !defined(DART_PRECOMPILER)
 
 DART_EXPORT Dart_Handle Dart_Precompile(
     Dart_QualifiedFunctionName entry_points[],
@@ -5903,14 +6119,14 @@
   return 0;
 }
 
-#else  // DART_PRECOMPILED
+#else  // DART_PRECOMPILER
 
 DART_EXPORT Dart_Handle Dart_Precompile(
     Dart_QualifiedFunctionName entry_points[],
     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);
@@ -5977,7 +6193,7 @@
 
   return Api::Success();
 }
-#endif  // DART_PRECOMPILED
+#endif  // DART_PRECOMPILER
 
 
 DART_EXPORT bool Dart_IsRunningPrecompiledCode() {
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 6172e1a..67c0257 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -8,6 +8,7 @@
 #include "vm/allocation.h"
 #include "vm/native_arguments.h"
 #include "vm/object.h"
+#include "vm/safepoint.h"
 
 namespace dart {
 
@@ -51,11 +52,12 @@
       FATAL1("%s expects to find a current scope. Did you forget to call "     \
            "Dart_EnterScope?", CURRENT_FUNC);                                  \
     }                                                                          \
-  } while (0)
+  } while (0);                                                                 \
 
 #define DARTSCOPE(thread)                                                      \
   Thread* T = (thread);                                                        \
   CHECK_API_SCOPE(T);                                                          \
+  TransitionNativeToVM trainsition(T);                                         \
   HANDLESCOPE(T);
 
 
@@ -160,6 +162,11 @@
     return (ClassId(handle) >= kInstanceCid);
   }
 
+  // Returns true if the handle holds an Error.
+  static bool IsError(Dart_Handle handle) {
+    return RawObject::IsErrorClassId(ClassId(handle));
+  }
+
   // Returns the value of a Smi.
   static intptr_t SmiValue(Dart_Handle handle) {
     // TODO(turnidge): Assumes RawObject* is at offset zero.  Fix.
@@ -253,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 a2cf1d3..91043ed 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -19,10 +19,11 @@
 
 namespace dart {
 
-DECLARE_FLAG(int, optimization_counter_threshold);
 DECLARE_FLAG(bool, verify_acquired_data);
 DECLARE_FLAG(bool, ignore_patch_signature_mismatch);
 
+#ifndef PRODUCT
+
 TEST_CASE(ErrorHandleBasics) {
   const char* kScriptChars =
       "void testMain() {\n"
@@ -374,7 +375,7 @@
 static Dart_NativeFunction CurrentStackTraceNativeLookup(
     Dart_Handle name, int argument_count, bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   return reinterpret_cast<Dart_NativeFunction>(&CurrentStackTraceNative);
 }
 
@@ -396,6 +397,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 TEST_CASE(ErrorHandleTypes) {
   const String& compile_message = String::Handle(String::New("CompileError"));
   const String& fatal_message = String::Handle(String::New("FatalError"));
@@ -500,22 +504,36 @@
 }
 
 
+// Should we propagate the error via Dart_SetReturnValue?
+static bool use_set_return = false;
+
+// Should we propagate the error via Dart_ThrowException?
+static bool use_throw_exception = false;
+
+
 void PropagateErrorNative(Dart_NativeArguments args) {
-  Dart_EnterScope();
   Dart_Handle closure = Dart_GetNativeArgument(args, 0);
   EXPECT(Dart_IsClosure(closure));
   Dart_Handle result = Dart_InvokeClosure(closure, 0, NULL);
   EXPECT(Dart_IsError(result));
-  result = Dart_PropagateError(result);
-  EXPECT_VALID(result);  // We do not expect to reach here.
-  UNREACHABLE();
+  if (use_set_return) {
+    Dart_SetReturnValue(args, result);
+  } else if (use_throw_exception) {
+    result = Dart_ThrowException(result);
+    EXPECT_VALID(result);  // We do not expect to reach here.
+    UNREACHABLE();
+  } else {
+    result = Dart_PropagateError(result);
+    EXPECT_VALID(result);  // We do not expect to reach here.
+    UNREACHABLE();
+  }
 }
 
 
 static Dart_NativeFunction PropagateError_native_lookup(
     Dart_Handle name, int argument_count, bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   return reinterpret_cast<Dart_NativeFunction>(&PropagateErrorNative);
 }
 
@@ -543,6 +561,38 @@
       kScriptChars, &PropagateError_native_lookup);
   Dart_Handle result;
 
+  // Use Dart_PropagateError to propagate the error.
+  use_throw_exception = false;
+  use_set_return = false;
+
+  result = Dart_Invoke(lib, NewString("Func1"), 0, NULL);
+  EXPECT(Dart_IsError(result));
+  EXPECT(!Dart_ErrorHasException(result));
+  EXPECT_SUBSTRING("semicolon expected", Dart_GetError(result));
+
+  result = Dart_Invoke(lib, NewString("Func2"), 0, NULL);
+  EXPECT(Dart_IsError(result));
+  EXPECT(Dart_ErrorHasException(result));
+  EXPECT_SUBSTRING("myException", Dart_GetError(result));
+
+  // Use Dart_SetReturnValue to propagate the error.
+  use_throw_exception = false;
+  use_set_return = true;
+
+  result = Dart_Invoke(lib, NewString("Func1"), 0, NULL);
+  EXPECT(Dart_IsError(result));
+  EXPECT(!Dart_ErrorHasException(result));
+  EXPECT_SUBSTRING("semicolon expected", Dart_GetError(result));
+
+  result = Dart_Invoke(lib, NewString("Func2"), 0, NULL);
+  EXPECT(Dart_IsError(result));
+  EXPECT(Dart_ErrorHasException(result));
+  EXPECT_SUBSTRING("myException", Dart_GetError(result));
+
+  // Use Dart_ThrowException to propagate the error.
+  use_throw_exception = true;
+  use_set_return = false;
+
   result = Dart_Invoke(lib, NewString("Func1"), 0, NULL);
   EXPECT(Dart_IsError(result));
   EXPECT(!Dart_ErrorHasException(result));
@@ -615,7 +665,8 @@
 
   // Non-instance objects.
   {
-    DARTSCOPE(thread);
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     Dart_Handle lib1 = Dart_LookupLibrary(dart_core);
     Dart_Handle lib2 = Dart_LookupLibrary(dart_mirrors);
 
@@ -660,7 +711,8 @@
 
   // Non-instance objects.
   {
-    DARTSCOPE(thread);
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     Dart_Handle lib1 = Dart_LookupLibrary(dart_core);
     Dart_Handle lib2 = Dart_LookupLibrary(dart_mirrors);
 
@@ -1182,14 +1234,17 @@
     Dart_ExitScope();
   }
 
-  EXPECT_EQ(40, peer8);
-  EXPECT_EQ(41, peer16);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(40, peer8);
-  EXPECT_EQ(41, peer16);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
-  EXPECT_EQ(80, peer8);
-  EXPECT_EQ(82, peer16);
+  {
+    TransitionNativeToVM transition(thread);
+    EXPECT_EQ(40, peer8);
+    EXPECT_EQ(41, peer16);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(40, peer8);
+    EXPECT_EQ(41, peer16);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
+    EXPECT_EQ(80, peer8);
+    EXPECT_EQ(82, peer16);
+  }
 }
 
 
@@ -1224,7 +1279,8 @@
         NULL);
     EXPECT_VALID(small16);
     {
-      DARTSCOPE(thread);
+      CHECK_API_SCOPE(thread);
+      HANDLESCOPE(thread);
       String& handle = String::Handle();
       handle ^= Api::UnwrapHandle(big8);
       EXPECT(handle.IsOld());
@@ -1258,7 +1314,8 @@
         kSmallLength);
     EXPECT_VALID(small);
     {
-      DARTSCOPE(thread);
+      CHECK_API_SCOPE(thread);
+      HANDLESCOPE(thread);
       ExternalTypedData& handle = ExternalTypedData::Handle();
       handle ^= Api::UnwrapHandle(big);
       EXPECT(handle.IsOld());
@@ -1733,7 +1790,7 @@
                                                   int arg_count,
                                                   bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   return &ByteDataNativeFunction;
 }
 
@@ -1795,7 +1852,7 @@
 static Dart_NativeFunction ExternalByteDataNativeResolver(
     Dart_Handle name, int arg_count, bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   return &ExternalByteDataNativeFunction;
 }
 
@@ -1848,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,
@@ -1869,7 +1929,7 @@
 static Dart_NativeFunction OptExternalByteDataNativeResolver(
     Dart_Handle name, int arg_count, bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   return &OptExternalByteDataNativeFunction;
 }
 
@@ -1916,6 +1976,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 static void TestTypedDataDirectAccess() {
   Dart_Handle str = Dart_NewStringFromCString("junk");
   Dart_Handle byte_array = Dart_NewTypedData(Dart_TypedData_kUint8, 10);
@@ -2311,11 +2374,14 @@
     EXPECT_VALID(obj);
     Dart_ExitScope();
   }
-  EXPECT(peer == 0);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT(peer == 0);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
-  EXPECT(peer == 42);
+  {
+    TransitionNativeToVM transition(thread);
+    EXPECT(peer == 0);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT(peer == 0);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
+    EXPECT(peer == 42);
+  }
 }
 
 
@@ -2367,8 +2433,11 @@
     CheckFloat32x4Data(lcl);
   }
   Dart_ExitScope();
-  Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
-  EXPECT(peer == 42);
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
+    EXPECT(peer == 42);
+  }
 }
 
 
@@ -2383,7 +2452,7 @@
   Dart_EnterScope();
   {
     EXPECT(thread->api_top_scope() != NULL);
-    DARTSCOPE(Thread::Current());
+    HANDLESCOPE(thread);
     const String& str1 = String::Handle(String::New("Test String"));
     Dart_Handle ref = Api::NewHandle(thread, str1.raw());
     String& str2 = String::Handle();
@@ -2409,7 +2478,8 @@
   Dart_PersistentHandle handles[2000];
   Dart_EnterScope();
   {
-    DARTSCOPE(Thread::Current());
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     Dart_Handle ref1 = Api::NewHandle(thread, String::New(kTestString1));
     for (int i = 0; i < 1000; i++) {
       handles[i] = Dart_NewPersistentHandle(ref1);
@@ -2471,7 +2541,9 @@
   EXPECT(isolate != NULL);
   ApiState* state = isolate->api_state();
   EXPECT(state != NULL);
-  DARTSCOPE(Thread::Current());
+  Thread* thread = Thread::Current();
+  CHECK_API_SCOPE(thread);
+  HANDLESCOPE(thread);
 
   // Start with a known persistent handle.
   Dart_PersistentHandle obj1 = Dart_NewPersistentHandle(Dart_True());
@@ -2498,7 +2570,9 @@
   const char* kTestString2 = "Test String2";
   TestIsolateScope __test_isolate__;
 
-  DARTSCOPE(Thread::Current());
+  Thread* T = Thread::Current();
+  CHECK_API_SCOPE(T);
+  HANDLESCOPE(T);
   Isolate* isolate = T->isolate();
   EXPECT(isolate != NULL);
   ApiState* state = isolate->api_state();
@@ -2581,7 +2655,8 @@
     // Create an object in old space.
     Dart_Handle old_ref;
     {
-      DARTSCOPE(Thread::Current());
+      CHECK_API_SCOPE(thread);
+      HANDLESCOPE(thread);
       old_ref = Api::NewHandle(thread, String::New("old string", Heap::kOld));
       EXPECT_VALID(old_ref);
     }
@@ -2602,8 +2677,11 @@
     EXPECT_VALID(AsHandle(weak_old_ref));
     EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
 
-    // Garbage collect new space.
-    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+    {
+      TransitionNativeToVM transition(thread);
+      // Garbage collect new space.
+      GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+    }
 
     // Nothing should be invalidated or cleared.
     EXPECT_VALID(new_ref);
@@ -2619,8 +2697,11 @@
     EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
     EXPECT(Dart_IdentityEquals(old_ref, AsHandle(weak_old_ref)));
 
-    // Garbage collect old space.
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    {
+      TransitionNativeToVM transition(thread);
+      // Garbage collect old space.
+      Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    }
 
     // Nothing should be invalidated or cleared.
     EXPECT_VALID(new_ref);
@@ -2640,8 +2721,11 @@
     Dart_ExitScope();
   }
 
-  // Garbage collect new space again.
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+  {
+    TransitionNativeToVM transition(thread);
+    // Garbage collect new space again.
+    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+  }
 
   {
     Dart_EnterScope();
@@ -2652,8 +2736,11 @@
     Dart_ExitScope();
   }
 
-  // Garbage collect old space again.
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+  {
+    TransitionNativeToVM transition(thread);
+    // Garbage collect old space again.
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+  }
 
   {
     Dart_EnterScope();
@@ -2663,9 +2750,12 @@
     Dart_ExitScope();
   }
 
-  // Garbage collect one last time to revisit deleted handles.
-  Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+  {
+    TransitionNativeToVM transition(thread);
+    // Garbage collect one last time to revisit deleted handles.
+    Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+  }
 }
 
 
@@ -2689,10 +2779,13 @@
     EXPECT(peer == 0);
     Dart_ExitScope();
   }
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT(peer == 0);
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-  EXPECT(peer == 42);
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT(peer == 0);
+    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+    EXPECT(peer == 42);
+  }
 }
 
 
@@ -2712,10 +2805,13 @@
   Dart_Isolate isolate = reinterpret_cast<Dart_Isolate>(Isolate::Current());
   Dart_DeleteWeakPersistentHandle(isolate, weak_ref);
   EXPECT(peer == 0);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT(peer == 0);
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-  EXPECT(peer == 0);
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT(peer == 0);
+    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+    EXPECT(peer == 0);
+  }
 }
 
 
@@ -2728,6 +2824,7 @@
                                &peer,
                                0,
                                WeakPersistentHandlePeerFinalizer);
+  Dart_ExitScope();
   Dart_ShutdownIsolate();
   EXPECT(peer == 42);
 }
@@ -2765,20 +2862,26 @@
     EXPECT_VALID(AsHandle(strong_ref));
     Dart_ExitScope();
   }
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT(heap->ExternalInWords(Heap::kNew) ==
-         (kWeak1ExternalSize + kWeak2ExternalSize) / kWordSize);
-  // Collect weakly referenced string, and promote strongly referenced string.
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-  EXPECT(heap->ExternalInWords(Heap::kNew) == 0);
-  EXPECT(heap->ExternalInWords(Heap::kOld) == kWeak2ExternalSize / kWordSize);
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT(heap->ExternalInWords(Heap::kNew) ==
+           (kWeak1ExternalSize + kWeak2ExternalSize) / kWordSize);
+    // Collect weakly referenced string, and promote strongly referenced string.
+    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+    EXPECT(heap->ExternalInWords(Heap::kNew) == 0);
+    EXPECT(heap->ExternalInWords(Heap::kOld) == kWeak2ExternalSize / kWordSize);
+  }
   Dart_Isolate isolate = reinterpret_cast<Dart_Isolate>(Isolate::Current());
   Dart_DeleteWeakPersistentHandle(isolate, weak1);
   Dart_DeleteWeakPersistentHandle(isolate, weak2);
   Dart_DeletePersistentHandle(strong_ref);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
+  }
 }
 
 
@@ -2808,7 +2911,8 @@
     // After the two scavenges above, 'obj' should now be promoted, hence its
     // external size charged to old space.
     {
-      DARTSCOPE(thread);
+      CHECK_API_SCOPE(thread);
+      HANDLESCOPE(thread);
       String& handle = String::Handle(thread->zone());
       handle ^= Api::UnwrapHandle(obj);
       EXPECT(handle.IsOld());
@@ -2818,8 +2922,11 @@
     Dart_ExitScope();
   }
   Dart_DeleteWeakPersistentHandle(isolate, weak1);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
+  }
 }
 
 
@@ -2886,8 +2993,11 @@
   Dart_Isolate isolate = reinterpret_cast<Dart_Isolate>(Isolate::Current());
   Dart_DeleteWeakPersistentHandle(isolate, weak1);
   Dart_DeleteWeakPersistentHandle(isolate, weak2);
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(0, heap->ExternalInWords(Heap::kOld));
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(0, heap->ExternalInWords(Heap::kOld));
+  }
 }
 
 
@@ -2915,7 +3025,8 @@
 
   Dart_EnterScope();
   {
-    DARTSCOPE(Thread::Current());
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
 
     Dart_Handle local = Api::NewHandle(
         thread, String::New("strongly reachable", Heap::kOld));
@@ -2957,7 +3068,10 @@
     Dart_ExitScope();
   }
 
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+  {
+    TransitionNativeToVM transition(thread);
+    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+  }
 
   {
     Dart_EnterScope();
@@ -2978,7 +3092,8 @@
 
   Dart_EnterScope();
   {
-    DARTSCOPE(Thread::Current());
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
 
     Dart_Handle local = Api::NewHandle(
         thread, String::New("strongly reachable", Heap::kOld));
@@ -3020,7 +3135,10 @@
     Dart_ExitScope();
   }
 
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+  }
 
   {
     Dart_EnterScope();
@@ -3098,99 +3216,109 @@
   EXPECT_VALID(Dart_SetGcCallbacks(&PrologueCallbackTimes2,
                                    &EpilogueCallbackNOP));
 
-  // Garbage collect new space ignoring callbacks.  This should not
-  // invoke the prologue callback.  No status values should change.
-  global_prologue_callback_status = 3;
-  global_epilogue_callback_status = 7;
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-  EXPECT_EQ(3, global_prologue_callback_status);
-  EXPECT_EQ(7, global_epilogue_callback_status);
+  {
+    TransitionNativeToVM transition(thread);
 
-  // Garbage collect new space invoking callbacks.  This should
-  // invoke the prologue callback.  No status values should change.
-  global_prologue_callback_status = 3;
-  global_epilogue_callback_status = 7;
-  GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
-  EXPECT_EQ(6, global_prologue_callback_status);
-  EXPECT_EQ(7, global_epilogue_callback_status);
+    // Garbage collect new space ignoring callbacks.  This should not
+    // invoke the prologue callback.  No status values should change.
+    global_prologue_callback_status = 3;
+    global_epilogue_callback_status = 7;
+    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+    EXPECT_EQ(3, global_prologue_callback_status);
+    EXPECT_EQ(7, global_epilogue_callback_status);
+
+    // Garbage collect new space invoking callbacks.  This should
+    // invoke the prologue callback.  No status values should change.
+    global_prologue_callback_status = 3;
+    global_epilogue_callback_status = 7;
+    GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
+    EXPECT_EQ(6, global_prologue_callback_status);
+    EXPECT_EQ(7, global_epilogue_callback_status);
 
   // Garbage collect old space ignoring callbacks.  This should invoke
   // the prologue callback.  The prologue status value should change.
-  global_prologue_callback_status = 3;
-  global_epilogue_callback_status = 7;
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
-                                             Heap::kIgnoreApiCallbacks,
-                                             Heap::kGCTestCase);
-  EXPECT_EQ(3, global_prologue_callback_status);
-  EXPECT_EQ(7, global_epilogue_callback_status);
+    global_prologue_callback_status = 3;
+    global_epilogue_callback_status = 7;
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
+                                               Heap::kIgnoreApiCallbacks,
+                                               Heap::kGCTestCase);
+    EXPECT_EQ(3, global_prologue_callback_status);
+    EXPECT_EQ(7, global_epilogue_callback_status);
 
-  // Garbage collect old space.  This should invoke the prologue
-  // callback.  The prologue status value should change.
-  global_prologue_callback_status = 3;
-  global_epilogue_callback_status = 7;
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(6, global_prologue_callback_status);
-  EXPECT_EQ(7, global_epilogue_callback_status);
+    // Garbage collect old space.  This should invoke the prologue
+    // callback.  The prologue status value should change.
+    global_prologue_callback_status = 3;
+    global_epilogue_callback_status = 7;
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(6, global_prologue_callback_status);
+    EXPECT_EQ(7, global_epilogue_callback_status);
 
-  // Garbage collect old space again.  Callbacks are persistent so the
-  // prologue status value should change again.
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(12, global_prologue_callback_status);
-  EXPECT_EQ(7, global_epilogue_callback_status);
+    // Garbage collect old space again.  Callbacks are persistent so the
+    // prologue status value should change again.
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(12, global_prologue_callback_status);
+    EXPECT_EQ(7, global_epilogue_callback_status);
+  }
 
   // Add an epilogue callback.
   EXPECT_VALID(Dart_SetGcCallbacks(NULL, NULL));
   EXPECT_VALID(Dart_SetGcCallbacks(&PrologueCallbackTimes2,
                                    &EpilogueCallbackTimes4));
 
-  // Garbage collect new space.  This should not invoke the prologue
-  // or the epilogue callback.  No status values should change.
-  global_prologue_callback_status = 3;
-  global_epilogue_callback_status = 7;
-  GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-  EXPECT_EQ(3, global_prologue_callback_status);
-  EXPECT_EQ(7, global_epilogue_callback_status);
+  {
+    TransitionNativeToVM transition(thread);
+    // Garbage collect new space.  This should not invoke the prologue
+    // or the epilogue callback.  No status values should change.
+    global_prologue_callback_status = 3;
+    global_epilogue_callback_status = 7;
+    GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
+    EXPECT_EQ(3, global_prologue_callback_status);
+    EXPECT_EQ(7, global_epilogue_callback_status);
 
-  // Garbage collect new space.  This should invoke the prologue and
-  // the epilogue callback.  The prologue and epilogue status values
-  // should change.
-  GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
-  EXPECT_EQ(6, global_prologue_callback_status);
-  EXPECT_EQ(28, global_epilogue_callback_status);
+    // Garbage collect new space.  This should invoke the prologue and
+    // the epilogue callback.  The prologue and epilogue status values
+    // should change.
+    GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
+    EXPECT_EQ(6, global_prologue_callback_status);
+    EXPECT_EQ(28, global_epilogue_callback_status);
 
-  // Garbage collect old space.  This should invoke the prologue and
-  // the epilogue callbacks.  The prologue and epilogue status values
-  // should change.
-  global_prologue_callback_status = 3;
-  global_epilogue_callback_status = 7;
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(6, global_prologue_callback_status);
-  EXPECT_EQ(28, global_epilogue_callback_status);
+    // Garbage collect old space.  This should invoke the prologue and
+    // the epilogue callbacks.  The prologue and epilogue status values
+    // should change.
+    global_prologue_callback_status = 3;
+    global_epilogue_callback_status = 7;
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(6, global_prologue_callback_status);
+    EXPECT_EQ(28, global_epilogue_callback_status);
 
-  // Garbage collect old space again without invoking callbacks.
-  // Nothing should change.
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
-                                             Heap::kIgnoreApiCallbacks,
-                                             Heap::kGCTestCase);
-  EXPECT_EQ(6, global_prologue_callback_status);
-  EXPECT_EQ(28, global_epilogue_callback_status);
+    // Garbage collect old space again without invoking callbacks.
+    // Nothing should change.
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
+                                               Heap::kIgnoreApiCallbacks,
+                                               Heap::kGCTestCase);
+    EXPECT_EQ(6, global_prologue_callback_status);
+    EXPECT_EQ(28, global_epilogue_callback_status);
 
-  // Garbage collect old space again.  Callbacks are persistent so the
-  // prologue and epilogue status values should change again.
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(12, global_prologue_callback_status);
-  EXPECT_EQ(112, global_epilogue_callback_status);
+    // Garbage collect old space again.  Callbacks are persistent so the
+    // prologue and epilogue status values should change again.
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(12, global_prologue_callback_status);
+    EXPECT_EQ(112, global_epilogue_callback_status);
+  }
 
   // Remove the prologue and epilogue callbacks
   EXPECT_VALID(Dart_SetGcCallbacks(NULL, NULL));
 
-  // Garbage collect old space.  No callbacks should be invoked.  No
-  // status values should change.
-  global_prologue_callback_status = 3;
-  global_epilogue_callback_status = 7;
-  Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(3, global_prologue_callback_status);
-  EXPECT_EQ(7, global_epilogue_callback_status);
+  {
+    TransitionNativeToVM transition(thread);
+    // Garbage collect old space.  No callbacks should be invoked.  No
+    // status values should change.
+    global_prologue_callback_status = 3;
+    global_epilogue_callback_status = 7;
+    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(3, global_prologue_callback_status);
+    EXPECT_EQ(7, global_epilogue_callback_status);
+  }
 }
 
 
@@ -4001,7 +4129,8 @@
   // Invoke a function which returns an object of type NativeFields.
   result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
   EXPECT_VALID(result);
-  DARTSCOPE(Thread::Current());
+  CHECK_API_SCOPE(thread);
+  HANDLESCOPE(thread);
   Instance& obj = Instance::Handle();
   obj ^= Api::UnwrapHandle(result);
   const Class& cls = Class::Handle(obj.clazz());
@@ -4071,7 +4200,8 @@
   // Invoke a function which returns an object of type NativeFields.
   result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
   EXPECT_VALID(result);
-  DARTSCOPE(Thread::Current());
+  CHECK_API_SCOPE(thread);
+  HANDLESCOPE(thread);
   Instance& obj = Instance::Handle();
   obj ^= Api::UnwrapHandle(result);
   const Class& cls = Class::Handle(obj.clazz());
@@ -4415,7 +4545,8 @@
       "  return () {};\n"
       "}\n";
   Dart_Handle result;
-  DARTSCOPE(Thread::Current());
+  CHECK_API_SCOPE(thread);
+  HANDLESCOPE(thread);
 
   // Create a test library and Load up a test script in it.
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
@@ -4493,7 +4624,8 @@
       "  };\n"
       "}\n";
 
-  DARTSCOPE(Thread::Current());
+  CHECK_API_SCOPE(thread);
+  HANDLESCOPE(thread);
 
   // Create a test library and Load up a test script in it.
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
@@ -5202,7 +5334,8 @@
       "  return InvokeClosure.method2(10);\n"
       "}\n";
   Dart_Handle result;
-  DARTSCOPE(Thread::Current());
+  CHECK_API_SCOPE(thread);
+  HANDLESCOPE(thread);
 
   // Create a test library and Load up a test script in it.
   Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
@@ -5255,7 +5388,7 @@
                                          int argument_count,
                                          bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   return reinterpret_cast<Dart_NativeFunction>(&ExceptionNative);
 }
 
@@ -5501,7 +5634,7 @@
                                        int argument_count,
                                        bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   return reinterpret_cast<Dart_NativeFunction>(&NativeArgumentCounter);
 }
 
@@ -5905,6 +6038,10 @@
   EXPECT_STREQ("library1_name", cstr);
 }
 
+
+#ifndef PRODUCT
+
+
 TEST_CASE(LibraryId) {
   const char* kLibrary1Chars =
       "library library1_name;";
@@ -5942,6 +6079,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 TEST_CASE(LibraryUrl) {
   const char* kLibrary1Chars =
       "library library1_name;";
@@ -6762,9 +6902,9 @@
 TEST_CASE(SetNativeResolver) {
   const char* kScriptChars =
       "class Test {"
-      "  static foo() native \"SomeNativeFunction\";"
-      "  static bar() native \"SomeNativeFunction2\";"
-      "  static baz() native \"SomeNativeFunction3\";"
+      "  static foo() native \"SomeNativeFunction\";\n"
+      "  static bar() native \"SomeNativeFunction2\";\n"
+      "  static baz() native \"SomeNativeFunction3\";\n"
       "}";
   Dart_Handle error = Dart_NewApiError("incoming error");
   Dart_Handle result;
@@ -7994,7 +8134,8 @@
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
   {
-    DARTSCOPE(Thread::Current());
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     Dart_Handle str = NewString("a string");
     EXPECT_VALID(str);
     EXPECT(Dart_IsString(str));
@@ -8008,15 +8149,21 @@
     out = &out;
     EXPECT_VALID(Dart_GetPeer(str, &out));
     EXPECT(out == reinterpret_cast<void*>(&peer));
-    isolate->heap()->CollectGarbage(Heap::kNew);
-    EXPECT_EQ(1, isolate->heap()->PeerCount());
+    {
+      TransitionNativeToVM transition(thread);
+      isolate->heap()->CollectGarbage(Heap::kNew);
+      EXPECT_EQ(1, isolate->heap()->PeerCount());
+    }
     out = &out;
     EXPECT_VALID(Dart_GetPeer(str, &out));
     EXPECT(out == reinterpret_cast<void*>(&peer));
   }
   Dart_ExitScope();
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  EXPECT_EQ(0, isolate->heap()->PeerCount());
+  {
+    TransitionNativeToVM transition(thread);
+    isolate->heap()->CollectGarbage(Heap::kNew);
+    EXPECT_EQ(0, isolate->heap()->PeerCount());
+  }
 }
 
 
@@ -8067,7 +8214,8 @@
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
   {
-    DARTSCOPE(Thread::Current());
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     Dart_Handle s1 = NewString("s1");
     EXPECT_VALID(s1);
     EXPECT(Dart_IsString(s1));
@@ -8094,8 +8242,11 @@
     EXPECT(o2 == reinterpret_cast<void*>(&p2));
   }
   Dart_ExitScope();
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  EXPECT_EQ(0, isolate->heap()->PeerCount());
+  {
+    TransitionNativeToVM transition(thread);
+    isolate->heap()->CollectGarbage(Heap::kNew);
+    EXPECT_EQ(0, isolate->heap()->PeerCount());
+  }
 }
 
 
@@ -8123,10 +8274,13 @@
     EXPECT(o == reinterpret_cast<void*>(&p[i]));
   }
   EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
+  {
+    TransitionNativeToVM transition(thread);
+    isolate->heap()->CollectGarbage(Heap::kNew);
+    EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
+    isolate->heap()->CollectGarbage(Heap::kNew);
+    EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
+  }
 }
 
 
@@ -8148,10 +8302,14 @@
   EXPECT(Dart_GetPeer(str, &out));
   EXPECT(out == reinterpret_cast<void*>(&peer));
   EXPECT_EQ(1, isolate->heap()->PeerCount());
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  isolate->heap()->CollectGarbage(Heap::kNew);
   {
-    DARTSCOPE(Thread::Current());
+    TransitionNativeToVM transition(thread);
+    isolate->heap()->CollectGarbage(Heap::kNew);
+    isolate->heap()->CollectGarbage(Heap::kNew);
+  }
+  {
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     String& handle = String::Handle();
     handle ^= Api::UnwrapHandle(str);
     EXPECT(handle.IsOld());
@@ -8185,8 +8343,11 @@
   out = &out;
   EXPECT_VALID(Dart_GetPeer(str, &out));
   EXPECT(out == reinterpret_cast<void*>(&peer));
-  isolate->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(1, isolate->heap()->PeerCount());
+  {
+    TransitionNativeToVM transition(thread);
+    isolate->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(1, isolate->heap()->PeerCount());
+  }
   EXPECT_VALID(Dart_GetPeer(str, &out));
   EXPECT(out == reinterpret_cast<void*>(&peer));
   EXPECT_VALID(Dart_SetPeer(str, NULL));
@@ -8204,7 +8365,9 @@
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
   {
-    DARTSCOPE(Thread::Current());
+    Thread* T = Thread::Current();
+    CHECK_API_SCOPE(T);
+    HANDLESCOPE(T);
     Dart_Handle str = Api::NewHandle(T, String::New("str", Heap::kOld));
     EXPECT_VALID(str);
     EXPECT(Dart_IsString(str));
@@ -8218,14 +8381,20 @@
     out = &out;
     EXPECT_VALID(Dart_GetPeer(str, &out));
     EXPECT(out == reinterpret_cast<void*>(&peer));
-    isolate->heap()->CollectGarbage(Heap::kOld);
-    EXPECT_EQ(1, isolate->heap()->PeerCount());
+    {
+      TransitionNativeToVM transition(thread);
+      isolate->heap()->CollectGarbage(Heap::kOld);
+      EXPECT_EQ(1, isolate->heap()->PeerCount());
+    }
     EXPECT_VALID(Dart_GetPeer(str, &out));
     EXPECT(out == reinterpret_cast<void*>(&peer));
   }
   Dart_ExitScope();
-  isolate->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(0, isolate->heap()->PeerCount());
+  {
+    TransitionNativeToVM transition(thread);
+    isolate->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(0, isolate->heap()->PeerCount());
+  }
 }
 
 
@@ -8280,7 +8449,9 @@
   Isolate* isolate = Isolate::Current();
   Dart_EnterScope();
   {
-    DARTSCOPE(Thread::Current());
+    Thread* T = Thread::Current();
+    CHECK_API_SCOPE(T);
+    HANDLESCOPE(T);
     Dart_Handle s1 = Api::NewHandle(T, String::New("s1", Heap::kOld));
     EXPECT_VALID(s1);
     EXPECT(Dart_IsString(s1));
@@ -8309,8 +8480,11 @@
     EXPECT(o2 == reinterpret_cast<void*>(&p2));
   }
   Dart_ExitScope();
-  isolate->heap()->CollectGarbage(Heap::kOld);
-  EXPECT_EQ(0, isolate->heap()->PeerCount());
+  {
+    TransitionNativeToVM transition(thread);
+    isolate->heap()->CollectGarbage(Heap::kOld);
+    EXPECT_EQ(0, isolate->heap()->PeerCount());
+  }
 }
 
 
@@ -8517,7 +8691,10 @@
   EXPECT_EQ(40, peer8);
   EXPECT_EQ(41, peer16);
   EXPECT_EQ(42, canonical_str_peer);
-  Isolate::Current()->heap()->CollectAllGarbage();
+  {
+    TransitionNativeToVM transition(thread);
+    Isolate::Current()->heap()->CollectAllGarbage();
+  }
   EXPECT_EQ(80, peer8);
   EXPECT_EQ(82, peer16);
   EXPECT_EQ(42, canonical_str_peer);  // "*" Symbol is not removed on GC.
@@ -8629,7 +8806,7 @@
 static Dart_NativeFunction ExternalStringDeoptimize_native_lookup(
     Dart_Handle name, int argument_count, bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   return reinterpret_cast<Dart_NativeFunction>(&A_change_str_native);
 }
 
@@ -9007,6 +9184,9 @@
 }
 
 
+#ifndef PRODUCT
+
+
 TEST_CASE(Timeline_Dart_TimelineDuration) {
   Isolate* isolate = Isolate::Current();
   // Grab embedder stream.
@@ -9592,4 +9772,6 @@
   EXPECT_SUBSTRING("\"function\":\"::_bar\"", buffer);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index e0f6e00..b510377 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -24,9 +24,6 @@
 
 namespace dart {
 
-DECLARE_DEBUG_FLAG(bool, trace_zones);
-DECLARE_DEBUG_FLAG(bool, trace_handles);
-
 // Implementation of Zone support for very fast allocation of small chunks
 // of memory. The chunks cannot be deallocated individually, but instead
 // zones support deallocating all chunks in one fast operation when the
@@ -41,13 +38,11 @@
     if (thread != NULL) {
       thread->set_zone(&zone_);
     }
-#ifdef DEBUG
     if (FLAG_trace_zones) {
       OS::PrintErr("*** Starting a new Api zone 0x%" Px "(0x%" Px ")\n",
                    reinterpret_cast<intptr_t>(this),
                    reinterpret_cast<intptr_t>(&zone_));
     }
-#endif
   }
 
   // Delete all memory associated with the zone.
@@ -62,13 +57,11 @@
     if ((thread != NULL) && (thread->zone() == &zone_)) {
       thread->set_zone(zone_.previous_);
     }
-#ifdef DEBUG
     if (FLAG_trace_zones) {
       OS::PrintErr("*** Deleting Api zone 0x%" Px "(0x%" Px ")\n",
                    reinterpret_cast<intptr_t>(this),
                    reinterpret_cast<intptr_t>(&zone_));
     }
-#endif
   }
 
   // Allocates an array sized to hold 'len' elements of type
@@ -220,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));
@@ -261,12 +258,14 @@
 
   // This part of external_data_ is the number of externally allocated bytes.
   // TODO(koda): Measure size in words instead.
-  class ExternalSizeBits : public BitField<intptr_t,
+  class ExternalSizeBits : public BitField<uword,
+                                           intptr_t,
                                            kExternalSizeBits,
-                                           kExternalSizeBitsSize> {};  // NOLINT
+                                           kExternalSizeBitsSize> {};
   // This bit of external_data_ is true if the referent was created in new
   // space and UpdateRelocated has not yet detected any promotion.
-  class ExternalNewSpaceBit : public BitField<bool, kExternalNewSpaceBit, 1> {};
+  class ExternalNewSpaceBit :
+      public BitField<uword, bool, kExternalNewSpaceBit, 1> {};
 
   friend class FinalizablePersistentHandles;
 
@@ -310,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_);
@@ -358,15 +353,12 @@
   LocalHandles() : Handles<kLocalHandleSizeInWords,
                            kLocalHandlesPerChunk,
                            kOffsetOfRawPtrInLocalHandle>() {
-#ifdef DEBUG
     if (FLAG_trace_handles) {
       OS::PrintErr("*** Starting a new Local handle block 0x%" Px "\n",
                    reinterpret_cast<intptr_t>(this));
     }
-#endif
   }
   ~LocalHandles() {
-#ifdef DEBUG
     if (FLAG_trace_handles) {
       OS::PrintErr("***   Handle Counts for 0x(%" Px "):Scoped = %d\n",
                    reinterpret_cast<intptr_t>(this),
@@ -374,7 +366,6 @@
       OS::PrintErr("*** Deleting Local handle block 0x%" Px "\n",
                    reinterpret_cast<intptr_t>(this));
     }
-#endif
   }
 
 
@@ -427,16 +418,13 @@
                                 kPersistentHandlesPerChunk,
                                 kOffsetOfRawPtrInPersistentHandle>(),
         free_list_(NULL) {
-#ifdef DEBUG
     if (FLAG_trace_handles) {
       OS::PrintErr("*** Starting a new Persistent handle block 0x%" Px "\n",
                    reinterpret_cast<intptr_t>(this));
     }
-#endif
   }
   ~PersistentHandles() {
     free_list_ = NULL;
-#ifdef DEBUG
     if (FLAG_trace_handles) {
       OS::PrintErr("***   Handle Counts for 0x(%" Px "):Scoped = %d\n",
                    reinterpret_cast<intptr_t>(this),
@@ -444,7 +432,6 @@
       OS::PrintErr("*** Deleting Persistent handle block 0x%" Px "\n",
                    reinterpret_cast<intptr_t>(this));
     }
-#endif
   }
 
   // Accessors.
@@ -458,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/dart_entry.cc b/runtime/vm/dart_entry.cc
index abb3e5d..3845949 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -10,14 +10,13 @@
 #include "vm/debugger.h"
 #include "vm/object_store.h"
 #include "vm/resolver.h"
+#include "vm/safepoint.h"
 #include "vm/simulator.h"
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
 
 namespace dart {
 
-DECLARE_FLAG(bool, lazy_dispatchers);
-
 // A cache of VM heap allocated arguments descriptors.
 RawArray* ArgumentsDescriptor::cached_args_descriptors_[kCachedDescriptorCount];
 
@@ -113,6 +112,7 @@
   ASSERT(thread->no_callback_scope_depth() == 0);
   ScopedIsolateStackLimits stack_limit(thread);
   SuspendLongJumpScope suspend_long_jump_scope(thread);
+  TransitionToGenerated transition(thread);
 #if defined(USING_SIMULATOR)
   return bit_copy<RawObject*, int64_t>(Simulator::Current()->Call(
       reinterpret_cast<intptr_t>(entrypoint),
@@ -192,7 +192,12 @@
         ASSERT(getter_result.IsNull() || getter_result.IsInstance());
 
         arguments.SetAt(0, getter_result);
-        return InvokeClosure(arguments, arguments_descriptor);
+        // This otherwise unnecessary handle is used to prevent clang from
+        // doing tail call elimination, which would make the stack overflow
+        // check above ineffective.
+        Object& result = Object::Handle(InvokeClosure(arguments,
+                                                      arguments_descriptor));
+        return result.raw();
       }
       cls = cls.SuperClass();
     }
@@ -549,7 +554,7 @@
   const Array& args = Array::Handle(zone, Array::New(kNumArguments));
   args.SetAt(0, handler);
   args.SetAt(1, message);
-  if (isolate->debugger()->IsStepping()) {
+  if (FLAG_support_debugger && isolate->debugger()->IsStepping()) {
     // If the isolate is being debugged and the debugger was stepping
     // through code, enable single stepping so debugger will stop
     // at the first location the user is interested in.
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index c533e3b..dda7b34 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -27,6 +27,7 @@
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
 #include "vm/thread_interrupter.h"
+#include "vm/token_position.h"
 #include "vm/visitor.h"
 
 
@@ -44,8 +45,11 @@
             "the VM service.");
 
 DECLARE_FLAG(bool, trace_isolates);
+DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
 
 
+#ifndef PRODUCT
+
 Debugger::EventHandler* Debugger::event_handler_ = NULL;
 
 
@@ -67,8 +71,8 @@
 
 // Create an unresolved breakpoint in given token range and script.
 BreakpointLocation::BreakpointLocation(const Script& script,
-                                       intptr_t token_pos,
-                                       intptr_t end_token_pos,
+                                       TokenPosition token_pos,
+                                       TokenPosition end_token_pos,
                                        intptr_t requested_line_number,
                                        intptr_t requested_column_number)
     : script_(script.raw()),
@@ -84,7 +88,7 @@
       line_number_(-1),
       column_number_(-1) {
   ASSERT(!script.IsNull());
-  ASSERT(token_pos_ >= 0);
+  ASSERT(token_pos_.IsReal());
 }
 
 // Create a latent breakpoint at given url and line number.
@@ -93,8 +97,8 @@
                                        intptr_t requested_column_number)
     : script_(Script::null()),
       url_(url.raw()),
-      token_pos_(Scanner::kNoSourcePos),
-      end_token_pos_(Scanner::kNoSourcePos),
+      token_pos_(TokenPosition::kNoSource),
+      end_token_pos_(TokenPosition::kNoSource),
       is_resolved_(false),
       next_(NULL),
       conditions_(NULL),
@@ -122,7 +126,8 @@
 }
 
 
-void BreakpointLocation::SetResolved(const Function& func, intptr_t token_pos) {
+void BreakpointLocation::SetResolved(const Function& func,
+                                     TokenPosition token_pos) {
   ASSERT(!IsLatent());
   ASSERT(func.script() == script_);
   ASSERT((func.token_pos() <= token_pos) &&
@@ -140,11 +145,11 @@
 // in more than one library, e.g. the text location of mixin functions.
 void BreakpointLocation::GetCodeLocation(Library* lib,
                                          Script* script,
-                                         intptr_t* pos) const {
+                                         TokenPosition* pos) const {
   if (IsLatent()) {
     *lib = Library::null();
     *script = Script::null();
-    *pos = -1;
+    *pos = TokenPosition::kNoSource;
   } else {
     *script = this->script();
     *pos = token_pos_;
@@ -212,6 +217,9 @@
 
   jsobj.AddFixedServiceId("breakpoints/%" Pd "", id());
   jsobj.AddProperty("breakpointNumber", id());
+  if (is_synthetic_async()) {
+    jsobj.AddProperty("isSyntheticAsyncContinuation", is_synthetic_async());
+  }
   jsobj.AddProperty("resolved", bpt_location_->IsResolved());
   if (bpt_location_->IsResolved()) {
     jsobj.AddLocation(bpt_location_);
@@ -239,7 +247,7 @@
       code_(Code::ZoneHandle(code.raw())),
       function_(Function::ZoneHandle(code.function())),
       token_pos_initialized_(false),
-      token_pos_(Scanner::kNoSourcePos),
+      token_pos_(TokenPosition::kNoSource),
       try_index_(-1),
       line_number_(-1),
       column_number_(-1),
@@ -281,7 +289,8 @@
     case DebuggerEvent::kBreakpointReached:
     case DebuggerEvent::kExceptionThrown:
     case DebuggerEvent::kIsolateInterrupted:
-      return Service::debug_stream.enabled();
+      return (Service::debug_stream.enabled() ||
+              FLAG_warn_on_pause_with_no_debugger);
 
     case DebuggerEvent::kIsolateCreated:
     case DebuggerEvent::kIsolateShutdown:
@@ -305,19 +314,24 @@
     Service::HandleEvent(&service_event);
   }
 
-  if ((FLAG_steal_breakpoints || (event_handler_ == NULL)) &&
-      event->IsPauseEvent()) {
-    // We allow the embedder's default breakpoint handler to be overridden.
-    isolate_->PauseEventHandler();
-  } else if (event_handler_ != NULL) {
-    (*event_handler_)(event);
+  {
+    TransitionVMToNative transition(Thread::Current());
+    if ((FLAG_steal_breakpoints || (event_handler_ == NULL)) &&
+        event->IsPauseEvent()) {
+      // We allow the embedder's default breakpoint handler to be overridden.
+      isolate_->PauseEventHandler();
+    } else if (event_handler_ != NULL) {
+      (*event_handler_)(event);
+    }
   }
 
   if (ServiceNeedsDebuggerEvent(event->type()) && event->IsPauseEvent()) {
     // If we were paused, notify the service that we have resumed.
     const Error& error =
-        Error::Handle(isolate_->object_store()->sticky_error());
-    ASSERT(error.IsNull() || error.IsUnwindError());
+        Error::Handle(Thread::Current()->sticky_error());
+    ASSERT(error.IsNull() ||
+           error.IsUnwindError() ||
+           error.IsUnhandledException());
 
     // Only send a resume event when the isolate is not unwinding.
     if (!error.IsUnwindError()) {
@@ -357,10 +371,9 @@
   }
 
   // If any error occurred while in the debug message loop, return it here.
-  const Error& error =
-      Error::Handle(isolate_->object_store()->sticky_error());
+  const Error& error = Error::Handle(Thread::Current()->sticky_error());
   ASSERT(error.IsNull() || error.IsUnwindError());
-  isolate_->object_store()->clear_sticky_error();
+  Thread::Current()->clear_sticky_error();
   return error.raw();
 }
 
@@ -421,7 +434,8 @@
 
 
 Breakpoint* BreakpointLocation::AddPerClosure(Debugger* dbg,
-                                              const Instance& closure) {
+                                              const Instance& closure,
+                                              bool for_over_await) {
   Breakpoint* bpt = breakpoints();
   while (bpt != NULL) {
     if (bpt->IsPerClosure() && bpt->closure() == closure.raw()) break;
@@ -430,6 +444,7 @@
   if (bpt == NULL) {
     bpt = new Breakpoint(dbg->nextId(), this);
     bpt->SetIsPerClosure(closure);
+    bpt->set_is_synthetic_async(for_over_await);
     AddBreakpoint(bpt, dbg);
   }
   return bpt;
@@ -451,7 +466,7 @@
 // Returns true if function contains the token position in the given script.
 static bool FunctionContains(const Function& func,
                              const Script& script,
-                             intptr_t token_pos) {
+                             TokenPosition token_pos) {
   if ((func.token_pos() <= token_pos) && (token_pos <= func.end_token_pos())) {
     // Check script equality second because it allocates
     // handles as a side effect.
@@ -563,10 +578,10 @@
 
 
 // Compute token_pos_ and try_index_ and token_pos_initialized_.
-intptr_t ActivationFrame::TokenPos() {
+TokenPosition ActivationFrame::TokenPos() {
   if (!token_pos_initialized_) {
     token_pos_initialized_ = true;
-    token_pos_ = Scanner::kNoSourcePos;
+    token_pos_ = TokenPosition::kNoSource;
     GetPcDescriptors();
     PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind);
     uword pc_offset = pc_ - code().EntryPoint();
@@ -592,9 +607,10 @@
 
 intptr_t ActivationFrame::LineNumber() {
   // Compute line number lazily since it causes scanning of the script.
-  if ((line_number_ < 0) && (TokenPos() >= 0)) {
+  if ((line_number_ < 0) && TokenPos().IsReal()) {
+    const TokenPosition token_pos = TokenPos();
     const Script& script = Script::Handle(SourceScript());
-    script.GetTokenLocation(TokenPos(), &line_number_, NULL);
+    script.GetTokenLocation(token_pos, &line_number_, NULL);
   }
   return line_number_;
 }
@@ -602,10 +618,11 @@
 
 intptr_t ActivationFrame::ColumnNumber() {
   // Compute column number lazily since it causes scanning of the script.
-  if ((column_number_ < 0) && (TokenPos() >= 0)) {
+  if ((column_number_ < 0) && TokenPos().IsReal()) {
+    const TokenPosition token_pos = TokenPos();
     const Script& script = Script::Handle(SourceScript());
     if (script.HasSource()) {
-      script.GetTokenLocation(TokenPos(), &line_number_, &column_number_);
+      script.GetTokenLocation(token_pos, &line_number_, &column_number_);
     } else {
       column_number_ = -1;
     }
@@ -647,14 +664,14 @@
     // for the code position of the frame? For now say we are at context
     // level 0.
     TokenPos();
-    if (token_pos_ == -1) {
+    if (token_pos_ == TokenPosition::kNoSource) {
       // No PcDescriptor.
       return context_level_;
     }
     ASSERT(!pc_desc_.IsNull());
-    intptr_t innermost_begin_pos = 0;
-    intptr_t activation_token_pos = TokenPos();
-    ASSERT(activation_token_pos >= 0);
+    TokenPosition innermost_begin_pos = TokenPosition::kMinSource;
+    TokenPosition activation_token_pos = TokenPos();
+    ASSERT(activation_token_pos.IsReal());
     GetVarDescriptors();
     intptr_t var_desc_len = var_descriptors_.Length();
     for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) {
@@ -766,8 +783,8 @@
   }
   GetVarDescriptors();
 
-  intptr_t activation_token_pos = TokenPos();
-  if (activation_token_pos < 0) {
+  TokenPosition activation_token_pos = TokenPos();
+  if (!activation_token_pos.IsDebugPause()) {
     // We don't have a token position for this frame, so can't determine
     // which variables are visible.
     vars_initialized_ = true;
@@ -927,8 +944,8 @@
 
 void ActivationFrame::VariableAt(intptr_t i,
                                  String* name,
-                                 intptr_t* token_pos,
-                                 intptr_t* end_pos,
+                                 TokenPosition* token_pos,
+                                 TokenPosition* end_pos,
                                  Object* value) {
   GetDescIndices();
   ASSERT(i < desc_indices_.length());
@@ -996,7 +1013,7 @@
   Object& value = Instance::Handle();
   const Array& list = Array::Handle(Array::New(2 * num_variables));
   for (intptr_t i = 0; i < num_variables; i++) {
-    intptr_t ignore;
+    TokenPosition ignore;
     VariableAt(i, &var_name, &ignore, &ignore, &value);
     list.SetAt(2 * i, var_name);
     list.SetAt((2 * i) + 1, value);
@@ -1011,7 +1028,7 @@
   String& var_name = String::Handle();
   Instance& value = Instance::Handle();
   for (intptr_t i = 0; i < num_variables; i++) {
-    intptr_t ignore;
+    TokenPosition ignore;
     VariableAt(i, &var_name, &ignore, &ignore, &value);
     if (var_name.Equals(Symbols::This())) {
       return value.raw();
@@ -1036,11 +1053,11 @@
   Object& value = Instance::Handle();
   intptr_t num_variables = desc_indices_.length();
   for (intptr_t i = 0; i < num_variables; i++) {
-    intptr_t ignore;
+    TokenPosition ignore;
     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);
@@ -1107,13 +1124,13 @@
     for (intptr_t v = 0; v < num_vars; v++) {
       String& var_name = String::Handle();
       Instance& var_value = Instance::Handle();
-      intptr_t token_pos;
-      intptr_t end_token_pos;
+      TokenPosition token_pos;
+      TokenPosition end_token_pos;
       VariableAt(v, &var_name, &token_pos, &end_token_pos, &var_value);
       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
@@ -1141,7 +1158,7 @@
 
 
 CodeBreakpoint::CodeBreakpoint(const Code& code,
-                               intptr_t token_pos,
+                               TokenPosition token_pos,
                                uword pc,
                                RawPcDescriptors::Kind kind)
     : code_(code.raw()),
@@ -1154,7 +1171,7 @@
       breakpoint_kind_(kind),
       saved_value_(Code::null()) {
   ASSERT(!code.IsNull());
-  ASSERT(token_pos_ > 0);
+  ASSERT(token_pos_.IsReal());
   ASSERT(pc_ != 0);
   ASSERT((breakpoint_kind_ & kSafepointKind) != 0);
 }
@@ -1256,6 +1273,8 @@
       obj_cache_(NULL),
       stack_trace_(NULL),
       stepping_fp_(0),
+      skip_next_step_(false),
+      synthetic_async_breakpoint_(NULL),
       exc_pause_info_(kNoPauseOnExceptions) {
 }
 
@@ -1268,6 +1287,7 @@
   ASSERT(code_breakpoints_ == NULL);
   ASSERT(stack_trace_ == NULL);
   ASSERT(obj_cache_ == NULL);
+  ASSERT(synthetic_async_breakpoint_ == NULL);
 }
 
 
@@ -1314,6 +1334,25 @@
 }
 
 
+bool Debugger::SetupStepOverAsyncSuspension() {
+  ActivationFrame* top_frame = TopDartFrame();
+  if (!IsAtAsyncJump(top_frame)) {
+    // Not at an async operation.
+    return false;
+  }
+  Object& closure = Object::Handle(top_frame->GetAsyncOperation());
+  ASSERT(!closure.IsNull());
+  ASSERT(closure.IsInstance());
+  ASSERT(Instance::Cast(closure).IsClosure());
+  Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true);
+  if (bpt == NULL) {
+    // Unable to set the breakpoint.
+    return false;
+  }
+  return true;
+}
+
+
 void Debugger::SetSingleStep() {
   resume_action_ = kSingleStep;
 }
@@ -1480,7 +1519,7 @@
     }
     if (frame->IsDartFrame()) {
       code = frame->LookupDartCode();
-      if (code.is_optimized() && !Compiler::always_optimize()) {
+      if (code.is_optimized() && !FLAG_precompiled_mode) {
         deopt_frame = DeoptimizeToArray(thread, frame, code);
         for (InlinedFunctionsIterator it(code, frame->pc());
              !it.Done();
@@ -1598,7 +1637,7 @@
 
 
 bool Debugger::ShouldPauseOnException(DebuggerStackTrace* stack_trace,
-                                      const Instance& exc) {
+                                      const Instance& exception) {
   if (exc_pause_info_ == kNoPauseOnExceptions) {
     return false;
   }
@@ -1606,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
@@ -1626,7 +1665,6 @@
   // interested in exception events.
   if (ignore_breakpoints_ ||
       IsPaused() ||
-      (!HasDebugEventHandler()) ||
       (exc_pause_info_ == kNoPauseOnExceptions)) {
     return;
   }
@@ -1636,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);
@@ -1645,12 +1684,15 @@
 }
 
 
-static intptr_t LastTokenOnLine(const TokenStream& tokens, intptr_t pos) {
-  TokenStream::Iterator iter(tokens, pos, TokenStream::Iterator::kAllTokens);
+static TokenPosition LastTokenOnLine(const TokenStream& tokens,
+                                     TokenPosition pos) {
+  TokenStream::Iterator iter(tokens,
+                             pos,
+                             TokenStream::Iterator::kAllTokens);
   ASSERT(iter.IsValid());
-  intptr_t last_pos = pos;
+  TokenPosition last_pos = pos;
   while ((iter.CurrentTokenKind() != Token::kNEWLINE) &&
-      (iter.CurrentTokenKind() != Token::kEOS)) {
+         (iter.CurrentTokenKind() != Token::kEOS)) {
     last_pos = iter.CurrentPosition();
     iter.Advance();
   }
@@ -1675,8 +1717,8 @@
 // and:
 //   - has the lowest token position number which satisfies the above.
 //
-// When we consider a column number, we look for the closed token
-// which intersects the desired column.  For example:
+// When we consider a column number, we look for the token which
+// intersects the desired column.  For example:
 //
 //          1         2         3
 // 12345678901234567890         0
@@ -1714,10 +1756,11 @@
 // algorithm, which would be simpler.  I believe that it only needs
 // two passes to support the recursive try-the-whole-function case.
 // Rewrite this later, once there are more tests in place.
-intptr_t Debugger::ResolveBreakpointPos(const Function& func,
-                                        intptr_t requested_token_pos,
-                                        intptr_t last_token_pos,
-                                        intptr_t requested_column) {
+TokenPosition Debugger::ResolveBreakpointPos(
+    const Function& func,
+    TokenPosition requested_token_pos,
+    TokenPosition last_token_pos,
+    intptr_t requested_column) {
   ASSERT(func.HasCode());
   ASSERT(!func.HasOptimizedCode());
 
@@ -1735,12 +1778,12 @@
 
   // First pass: find the safe point which is closest to the beginning
   // of the given token range.
-  intptr_t best_fit_pos = INT_MAX;
+  TokenPosition best_fit_pos = TokenPosition::kMaxSource;
   intptr_t best_column = INT_MAX;
   PcDescriptors::Iterator iter(desc, kSafepointKind);
   while (iter.MoveNext()) {
-    const intptr_t pos = iter.TokenPos();
-    if ((pos < 0) ||
+    const TokenPosition pos = iter.TokenPos();
+    if ((!pos.IsReal()) ||
         (pos < requested_token_pos) ||
         (pos > last_token_pos)) {
       // Token is not in the target range.
@@ -1777,16 +1820,16 @@
   // Second pass (if we found a safe point in the first pass).  Find
   // the token on the line which is at the best fit column (if column
   // was specified) and has the lowest code address.
-  if (best_fit_pos != INT_MAX) {
+  if (best_fit_pos != TokenPosition::kMaxSource) {
     const Script& script = Script::Handle(func.script());
     const TokenStream& tokens = TokenStream::Handle(script.tokens());
-    const intptr_t begin_pos = best_fit_pos;
-    const intptr_t end_of_line_pos = LastTokenOnLine(tokens, begin_pos);
+    const TokenPosition begin_pos = best_fit_pos;
+    const TokenPosition end_of_line_pos = LastTokenOnLine(tokens, begin_pos);
     uword lowest_pc_offset = kUwordMax;
     PcDescriptors::Iterator iter(desc, kSafepointKind);
     while (iter.MoveNext()) {
-      const intptr_t pos = iter.TokenPos();
-      if ((pos < 0) ||
+      const TokenPosition pos = iter.TokenPos();
+      if (!pos.IsReal() ||
           (pos < begin_pos) ||
           (pos > end_of_line_pos)) {
         // Token is not on same line as best fit.
@@ -1821,13 +1864,13 @@
     return ResolveBreakpointPos(func, last_token_pos, func.end_token_pos(),
                                 -1 /* no column */);
   }
-  return -1;
+  return TokenPosition::kNoSource;
 }
 
 
 void Debugger::MakeCodeBreakpointAt(const Function& func,
                                     BreakpointLocation* loc) {
-  ASSERT(loc->token_pos_ >= 0);
+  ASSERT(loc->token_pos_.IsReal());
   ASSERT((loc != NULL) && loc->IsResolved());
   ASSERT(!func.HasOptimizedCode());
   Code& code = Code::Handle(func.unoptimized_code());
@@ -1865,8 +1908,8 @@
 
 
 void Debugger::FindCompiledFunctions(const Script& script,
-                                     intptr_t start_pos,
-                                     intptr_t end_pos,
+                                     TokenPosition start_pos,
+                                     TokenPosition end_pos,
                                      GrowableObjectArray* function_list) {
   Zone* zone = Thread::Current()->zone();
   Class& cls = Class::Handle(zone);
@@ -1950,7 +1993,7 @@
 
 
 RawFunction* Debugger::FindBestFit(const Script& script,
-                                   intptr_t token_pos) {
+                                   TokenPosition token_pos) {
   Zone* zone = Thread::Current()->zone();
   Class& cls = Class::Handle(zone);
   Array& functions = Array::Handle(zone);
@@ -2009,8 +2052,8 @@
 
 
 BreakpointLocation* Debugger::SetBreakpoint(const Script& script,
-                                            intptr_t token_pos,
-                                            intptr_t last_token_pos,
+                                            TokenPosition token_pos,
+                                            TokenPosition last_token_pos,
                                             intptr_t requested_line,
                                             intptr_t requested_column) {
   Function& func = Function::Handle();
@@ -2035,9 +2078,9 @@
     // have already been compiled. We can resolve the breakpoint now.
     DeoptimizeWorld();
     func ^= functions.At(0);
-    intptr_t breakpoint_pos =
+    TokenPosition breakpoint_pos =
         ResolveBreakpointPos(func, token_pos, last_token_pos, requested_column);
-    if (breakpoint_pos >= 0) {
+    if (breakpoint_pos.IsReal()) {
       BreakpointLocation* bpt =
           GetBreakpointLocation(script, breakpoint_pos, requested_column);
       if (bpt != NULL) {
@@ -2115,7 +2158,7 @@
     SetBreakpointAtEntry(target_function, true);
     return Error::null();
   } else {
-    return isolate_->object_store()->sticky_error();
+    return Thread::Current()->sticky_error();
   }
 }
 
@@ -2140,17 +2183,18 @@
 }
 
 
-Breakpoint* Debugger::SetBreakpointAtActivation(const Instance& closure) {
+Breakpoint* Debugger::SetBreakpointAtActivation(
+    const Instance& closure, bool for_over_await) {
   if (!closure.IsClosure()) {
     return NULL;
   }
-  const Function& func = Function::Handle(Closure::function(closure));
+  const Function& func = Function::Handle(Closure::Cast(closure).function());
   const Script& script = Script::Handle(func.script());
   BreakpointLocation* bpt_location = SetBreakpoint(script,
                                                    func.token_pos(),
                                                    func.end_token_pos(),
                                                    -1, -1 /* no line/col */);
-  return bpt_location->AddPerClosure(this, closure);
+  return bpt_location->AddPerClosure(this, closure, for_over_await);
 }
 
 
@@ -2240,16 +2284,16 @@
     return NULL;
   }
   script ^= scripts.At(0);
-  intptr_t first_token_idx, last_token_idx;
+  TokenPosition first_token_idx, last_token_idx;
   script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx);
-  if (first_token_idx < 0) {
+  if (!first_token_idx.IsReal()) {
     // Script does not contain the given line number.
     if (FLAG_verbose_debug) {
       OS::Print("Script '%s' does not contain line number %" Pd "\n",
                 script_url.ToCString(), line_number);
     }
     return NULL;
-  } else if (last_token_idx < 0) {
+  } else if (!last_token_idx.IsReal()) {
     // Line does not contain any tokens.
     if (FLAG_verbose_debug) {
       OS::Print("No executable code at line %" Pd " in '%s'\n",
@@ -2263,7 +2307,7 @@
   while ((bpt == NULL) && (first_token_idx <= last_token_idx)) {
     bpt = SetBreakpoint(script, first_token_idx, last_token_idx,
                         line_number, column_number);
-    first_token_idx++;
+    first_token_idx.Next();
   }
   if ((bpt == NULL) && FLAG_verbose_debug) {
     OS::Print("No executable code at line %" Pd " in '%s'\n",
@@ -2309,7 +2353,7 @@
     args.SetAt(0, object);
     result = DartEntry::InvokeFunction(getter_func, args);
   } else {
-    result = isolate_->object_store()->sticky_error();
+    result = Thread::Current()->sticky_error();
   }
   ignore_breakpoints_ = saved_ignore_flag;
   return result.raw();
@@ -2343,7 +2387,7 @@
   if (setjmp(*jump.Set()) == 0) {
     result = DartEntry::InvokeFunction(getter_func, Object::empty_array());
   } else {
-    result = isolate_->object_store()->sticky_error();
+    result = Thread::Current()->sticky_error();
   }
   ignore_breakpoints_ = saved_ignore_flag;
   return result.raw();
@@ -2531,7 +2575,8 @@
 }
 
 
-void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace) {
+void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace,
+                                     bool skip_next_step) {
   stepping_fp_ = 0;
   if (resume_action_ == kSingleStep) {
     // When single stepping, we need to deoptimize because we might be
@@ -2541,11 +2586,19 @@
     // to call an optimized function.
     DeoptimizeWorld();
     isolate_->set_single_step(true);
+    skip_next_step_ = skip_next_step;
+    if (FLAG_verbose_debug) {
+      OS::Print("HandleSteppingRequest- kSingleStep\n");
+    }
   } else if (resume_action_ == kStepOver) {
     DeoptimizeWorld();
     isolate_->set_single_step(true);
+    skip_next_step_ = skip_next_step;
     ASSERT(stack_trace->Length() > 0);
     stepping_fp_ = stack_trace->FrameAt(0)->fp();
+    if (FLAG_verbose_debug) {
+      OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_);
+    }
   } else if (resume_action_ == kStepOut) {
     DeoptimizeWorld();
     isolate_->set_single_step(true);
@@ -2557,6 +2610,9 @@
         break;
       }
     }
+    if (FLAG_verbose_debug) {
+      OS::Print("HandleSteppingRequest- kStepOut %" Px "\n", stepping_fp_);
+    }
   }
 }
 
@@ -2590,30 +2646,38 @@
   DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached);
   event.set_top_frame(top_frame);
   event.set_breakpoint(bpt);
+  event.set_at_async_jump(IsAtAsyncJump(top_frame));
+  Pause(&event);
+}
+
+
+bool Debugger::IsAtAsyncJump(ActivationFrame* top_frame) {
   Object& closure_or_null = Object::Handle(top_frame->GetAsyncOperation());
   if (!closure_or_null.IsNull()) {
     ASSERT(closure_or_null.IsInstance());
     ASSERT(Instance::Cast(closure_or_null).IsClosure());
-    event.set_async_continuation(&closure_or_null);
     const Script& script = Script::Handle(top_frame->SourceScript());
     const TokenStream& tokens = TokenStream::Handle(script.tokens());
     TokenStream::Iterator iter(tokens, top_frame->TokenPos());
     if ((iter.CurrentTokenKind() == Token::kIDENT) &&
         ((iter.CurrentLiteral() == Symbols::Await().raw()) ||
          (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) {
-      event.set_at_async_jump(true);
+      return true;
     }
   }
-  Pause(&event);
+  return false;
 }
 
-
 RawError* Debugger::DebuggerStepCallback() {
   ASSERT(isolate_->single_step());
   // Don't pause recursively.
   if (IsPaused()) {
     return Error::null();
   }
+  if (skip_next_step_) {
+    skip_next_step_ = false;
+    return Error::null();
+  }
 
   // Check whether we are in a Dart function that the user is
   // interested in. If we saved the frame pointer of a stack frame
@@ -2627,7 +2691,7 @@
     // There is an "interesting frame" set. Only pause at appropriate
     // locations in this frame.
     if (stepping_fp_ > frame->fp()) {
-      // We are in a callee of the frame we're interested in.
+      // We are i n a callee of the frame we're interested in.
       // Ignore this stepping break.
       return Error::null();
     } else if (frame->fp() > stepping_fp_) {
@@ -2641,34 +2705,39 @@
   if (!frame->IsDebuggable()) {
     return Error::null();
   }
-  if (frame->TokenPos() < 0) {
+  if (!frame->TokenPos().IsDebugPause()) {
     return Error::null();
   }
 
-  // Don't pause for a single step if there is a breakpoint set
-  // at this location.
-  if (HasActiveBreakpoint(frame->pc())) {
-    return Error::null();
-  }
+  // If there is an active breakpoint at this pc, then we should have
+  // already bailed out of this function in the skip_next_step_ test
+  // above.
+  ASSERT(!HasActiveBreakpoint(frame->pc()));
 
   if (FLAG_verbose_debug) {
-    OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n",
+    OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n",
               String::Handle(frame->SourceUrl()).ToCString(),
               frame->LineNumber(),
               String::Handle(frame->QualifiedFunctionName()).ToCString(),
-              frame->TokenPos());
+              frame->TokenPos().ToCString());
   }
 
   ASSERT(stack_trace_ == NULL);
   stack_trace_ = CollectStackTrace();
-  SignalPausedEvent(frame, NULL);
+  // If this step callback is part of stepping over an await statement,
+  // we saved the synthetic async breakpoint in SignalBpReached. We report
+  // that we are paused at that breakpoint and then delete it after continuing.
+  SignalPausedEvent(frame, synthetic_async_breakpoint_);
+  if (synthetic_async_breakpoint_ != NULL) {
+    RemoveBreakpoint(synthetic_async_breakpoint_->id());
+    synthetic_async_breakpoint_ = NULL;
+  }
   HandleSteppingRequest(stack_trace_);
   stack_trace_ = NULL;
 
   // If any error occurred while in the debug message loop, return it here.
-  const Error& error =
-      Error::Handle(isolate_->object_store()->sticky_error());
-  isolate_->object_store()->clear_sticky_error();
+  const Error& error = Error::Handle(Thread::Current()->sticky_error());
+  Thread::Current()->clear_sticky_error();
   return error.raw();
 }
 
@@ -2735,29 +2804,60 @@
     return Error::null();
   }
 
+  if (bpt_hit->is_synthetic_async()) {
+    DebuggerStackTrace* stack_trace = CollectStackTrace();
+    ASSERT(stack_trace->Length() > 0);
+    ASSERT(stack_trace_ == NULL);
+    stack_trace_ = stack_trace;
+
+    // Hit a synthetic async breakpoint.
+    if (FLAG_verbose_debug) {
+      OS::Print(">>> hit synthetic breakpoint at %s:%" Pd " "
+                "(token %s) (address %#" Px ")\n",
+                String::Handle(cbpt->SourceUrl()).ToCString(),
+                cbpt->LineNumber(),
+                cbpt->token_pos().ToCString(),
+                top_frame->pc());
+    }
+
+    ASSERT(synthetic_async_breakpoint_ == NULL);
+    synthetic_async_breakpoint_ = bpt_hit;
+    bpt_hit = NULL;
+
+    // We are at the entry of an async function.
+    // We issue a step over to resume at the point after the await statement.
+    SetStepOver();
+    // When we single step from a user breakpoint, our next stepping
+    // point will be at the exact same pc.  Skip it.
+    HandleSteppingRequest(stack_trace_, true /* skip next step */);
+    stack_trace_ = NULL;
+    return Error::null();
+  }
+
   if (FLAG_verbose_debug) {
     OS::Print(">>> hit %s breakpoint at %s:%" Pd " "
-              "(token %" Pd ") (address %#" Px ")\n",
+              "(token %s) (address %#" Px ")\n",
               cbpt->IsInternal() ? "internal" : "user",
               String::Handle(cbpt->SourceUrl()).ToCString(),
               cbpt->LineNumber(),
-              cbpt->token_pos(),
+              cbpt->token_pos().ToCString(),
               top_frame->pc());
   }
 
   ASSERT(stack_trace_ == NULL);
   stack_trace_ = stack_trace;
   SignalPausedEvent(top_frame, bpt_hit);
-  HandleSteppingRequest(stack_trace_);
+  // When we single step from a user breakpoint, our next stepping
+  // point will be at the exact same pc.  Skip it.
+  HandleSteppingRequest(stack_trace_, true /* skip next step */);
   stack_trace_ = NULL;
   if (cbpt->IsInternal()) {
     RemoveInternalBreakpoints();
   }
 
   // If any error occurred while in the debug message loop, return it here.
-  const Error& error =
-      Error::Handle(isolate_->object_store()->sticky_error());
-  isolate_->object_store()->clear_sticky_error();
+  const Error& error = Error::Handle(Thread::Current()->sticky_error());
+  Thread::Current()->clear_sticky_error();
   return error.raw();
 }
 
@@ -2818,7 +2918,7 @@
 // Return innermost closure contained in 'function' that contains
 // the given token position.
 RawFunction* Debugger::FindInnermostClosure(const Function& function,
-                                            intptr_t token_pos) {
+                                            TokenPosition token_pos) {
   Zone* zone = Thread::Current()->zone();
   const Script& outer_origin = Script::Handle(zone, function.script());
   const GrowableObjectArray& closures =
@@ -2883,33 +2983,33 @@
       // and set the code breakpoints.
       if (!loc->IsResolved()) {
         // Resolve source breakpoint in the newly compiled function.
-        intptr_t bp_pos =
+        TokenPosition bp_pos =
             ResolveBreakpointPos(func, loc->token_pos(), loc->end_token_pos(),
                                  loc->requested_column_number());
-        if (bp_pos < 0) {
+        if (!bp_pos.IsDebugPause()) {
           if (FLAG_verbose_debug) {
             OS::Print("Failed resolving breakpoint for function '%s'\n",
                       String::Handle(func.name()).ToCString());
           }
           continue;
         }
-        intptr_t requested_pos = loc->token_pos();
-        intptr_t requested_end_pos = loc->end_token_pos();
+        TokenPosition requested_pos = loc->token_pos();
+        TokenPosition requested_end_pos = loc->end_token_pos();
         loc->SetResolved(func, bp_pos);
         Breakpoint* bpt = loc->breakpoints();
         while (bpt != NULL) {
           if (FLAG_verbose_debug) {
-            OS::Print("Resolved BP %" Pd " to pos %" Pd ", "
+            OS::Print("Resolved BP %" Pd " to pos %s, "
                       "line %" Pd " col %" Pd ", "
-                      "function '%s' (requested range %" Pd "-%" Pd ", "
+                      "function '%s' (requested range %s-%s, "
                       "requested col %" Pd ")\n",
                       bpt->id(),
-                      loc->token_pos(),
+                      loc->token_pos().ToCString(),
                       loc->LineNumber(),
                       loc->ColumnNumber(),
                       func.ToFullyQualifiedCString(),
-                      requested_pos,
-                      requested_end_pos,
+                      requested_pos.ToCString(),
+                      requested_end_pos.ToCString(),
                       loc->requested_column_number());
           }
           SignalBpResolved(bpt);
@@ -2972,10 +3072,9 @@
         intptr_t line_number = matched_loc->requested_line_number();
         intptr_t column_number = matched_loc->requested_column_number();
         ASSERT(line_number >= 0);
-        intptr_t first_token_pos, last_token_pos;
+        TokenPosition first_token_pos, last_token_pos;
         script.TokenRangeAtLine(line_number, &first_token_pos, &last_token_pos);
-        if ((first_token_pos < 0) ||
-            (last_token_pos < 0)) {
+        if (!first_token_pos.IsDebugPause() || !last_token_pos.IsDebugPause()) {
           // Script does not contain the given line number or there are no
           // tokens on the line. Drop the breakpoint silently.
           Breakpoint* bpt = matched_loc->breakpoints();
@@ -3111,7 +3210,7 @@
             pause_event_->breakpoint() == curr_bpt) {
           pause_event_->set_breakpoint(NULL);
         }
-        return;
+        break;
       }
 
       prev_bpt = curr_bpt;
@@ -3183,7 +3282,7 @@
 
 
 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script,
-                                                    intptr_t token_pos,
+                                                    TokenPosition token_pos,
                                                     intptr_t requested_column) {
   BreakpointLocation* bpt = breakpoint_locations_;
   while (bpt != NULL) {
@@ -3249,4 +3348,6 @@
   code_breakpoints_ = bpt;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index acb69ec..4d00a34 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -30,7 +30,8 @@
       kind_(Breakpoint::kNone),
       next_(NULL),
       closure_(Instance::null()),
-      bpt_location_(bpt_location) {}
+      bpt_location_(bpt_location),
+      is_synthetic_async_(false) {}
 
   intptr_t id() const { return id_; }
   Breakpoint* next() const { return next_; }
@@ -60,6 +61,14 @@
     closure_ = closure.raw();
   }
 
+  // Mark that this breakpoint is a result of a step OverAwait request.
+  void set_is_synthetic_async(bool is_synthetic_async) {
+    is_synthetic_async_ = is_synthetic_async;
+  }
+  bool is_synthetic_async() const {
+    return is_synthetic_async_;
+  }
+
   void PrintJSON(JSONStream* stream);
 
  private:
@@ -77,6 +86,7 @@
   Breakpoint* next_;
   RawInstance* closure_;
   BreakpointLocation* bpt_location_;
+  bool is_synthetic_async_;
 
   friend class BreakpointLocation;
   DISALLOW_COPY_AND_ASSIGN(Breakpoint);
@@ -98,8 +108,8 @@
  public:
   // Create a new unresolved breakpoint.
   BreakpointLocation(const Script& script,
-                     intptr_t token_pos,
-                     intptr_t end_token_pos,
+                     TokenPosition token_pos,
+                     TokenPosition end_token_pos,
                      intptr_t requested_line_number,
                      intptr_t requested_column_number);
   // Create a new latent breakpoint.
@@ -110,8 +120,8 @@
   ~BreakpointLocation();
 
   RawFunction* function() const { return function_; }
-  intptr_t token_pos() const { return token_pos_; }
-  intptr_t end_token_pos() const { return end_token_pos_; }
+  TokenPosition token_pos() const { return token_pos_; }
+  TokenPosition end_token_pos() const { return end_token_pos_; }
 
   RawScript* script() const { return script_; }
   RawString* url() const { return url_; }
@@ -124,20 +134,22 @@
 
   void GetCodeLocation(Library* lib,
                        Script* script,
-                       intptr_t* token_pos) const;
+                       TokenPosition* token_pos) const;
 
   Breakpoint* AddRepeated(Debugger* dbg);
   Breakpoint* AddSingleShot(Debugger* dbg);
-  Breakpoint* AddPerClosure(Debugger* dbg, const Instance& closure);
+  Breakpoint* AddPerClosure(Debugger* dbg,
+                            const Instance& closure,
+                            bool for_over_await);
 
   bool AnyEnabled() const;
   bool IsResolved() const { return is_resolved_; }
-  bool IsLatent() const { return token_pos_ < 0; }
+  bool IsLatent() const { return !token_pos_.IsReal(); }
 
  private:
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
-  void SetResolved(const Function& func, intptr_t token_pos);
+  void SetResolved(const Function& func, TokenPosition token_pos);
 
   BreakpointLocation* next() const { return this->next_; }
   void set_next(BreakpointLocation* value) { next_ = value; }
@@ -149,8 +161,8 @@
 
   RawScript* script_;
   RawString* url_;
-  intptr_t token_pos_;
-  intptr_t end_token_pos_;
+  TokenPosition token_pos_;
+  TokenPosition end_token_pos_;
   bool is_resolved_;
   BreakpointLocation* next_;
   Breakpoint* conditions_;
@@ -173,14 +185,14 @@
 class CodeBreakpoint {
  public:
   CodeBreakpoint(const Code& code,
-                 intptr_t token_pos,
+                 TokenPosition token_pos,
                  uword pc,
                  RawPcDescriptors::Kind kind);
   ~CodeBreakpoint();
 
   RawFunction* function() const;
   uword pc() const { return pc_; }
-  intptr_t token_pos() const { return token_pos_; }
+  TokenPosition token_pos() const { return token_pos_; }
   bool IsInternal() const { return bpt_location_ == NULL; }
 
   RawScript* SourceCode();
@@ -206,7 +218,7 @@
   void RestoreCode();
 
   RawCode* code_;
-  intptr_t token_pos_;
+  TokenPosition token_pos_;
   uword pc_;
   intptr_t line_number_;
   bool is_enabled_;
@@ -245,7 +257,7 @@
   RawString* SourceUrl();
   RawScript* SourceScript();
   RawLibrary* Library();
-  intptr_t TokenPos();
+  TokenPosition TokenPos();
   intptr_t LineNumber();
   intptr_t ColumnNumber();
 
@@ -264,8 +276,8 @@
 
   void VariableAt(intptr_t i,
                   String* name,
-                  intptr_t* token_pos,
-                  intptr_t* end_pos,
+                  TokenPosition* token_pos,
+                  TokenPosition* end_pos,
                   Object* value);
 
   RawArray* GetLocalVariables();
@@ -305,7 +317,7 @@
   const Code& code_;
   const Function& function_;
   bool token_pos_initialized_;
-  intptr_t token_pos_;
+  TokenPosition token_pos_;
   intptr_t try_index_;
 
   intptr_t line_number_;
@@ -467,7 +479,8 @@
   // Set breakpoint at closest location to function entry.
   Breakpoint* SetBreakpointAtEntry(const Function& target_function,
                                    bool single_shot);
-  Breakpoint* SetBreakpointAtActivation(const Instance& closure);
+  Breakpoint* SetBreakpointAtActivation(const Instance& closure,
+                                        bool for_over_await);
   Breakpoint* BreakpointAtActivation(const Instance& closure);
 
   // TODO(turnidge): script_url may no longer be specific enough.
@@ -486,6 +499,8 @@
   void RemoveBreakpoint(intptr_t bp_id);
   Breakpoint* GetBreakpointById(intptr_t id);
 
+  // Will return false if we are not at an await.
+  bool SetupStepOverAsyncSuspension();
   void SetStepOver();
   void SetSingleStep();
   void SetStepOut();
@@ -587,22 +602,22 @@
   static bool HasAnyEventHandler();
   static bool HasDebugEventHandler();
   void InvokeEventHandler(DebuggerEvent* event);
-
+  bool IsAtAsyncJump(ActivationFrame* top_frame);
   void FindCompiledFunctions(const Script& script,
-                             intptr_t start_pos,
-                             intptr_t end_pos,
+                             TokenPosition start_pos,
+                             TokenPosition end_pos,
                              GrowableObjectArray* function_list);
-  RawFunction* FindBestFit(const Script& script, intptr_t token_pos);
+  RawFunction* FindBestFit(const Script& script, TokenPosition token_pos);
   RawFunction* FindInnermostClosure(const Function& function,
-                                    intptr_t token_pos);
-  intptr_t ResolveBreakpointPos(const Function& func,
-                                intptr_t requested_token_pos,
-                                intptr_t last_token_pos,
-                                intptr_t requested_column);
+                                    TokenPosition token_pos);
+  TokenPosition ResolveBreakpointPos(const Function& func,
+                                       TokenPosition requested_token_pos,
+                                       TokenPosition last_token_pos,
+                                       intptr_t requested_column);
   void DeoptimizeWorld();
   BreakpointLocation* SetBreakpoint(const Script& script,
-                                    intptr_t token_pos,
-                                    intptr_t last_token_pos,
+                                    TokenPosition token_pos,
+                                    TokenPosition last_token_pos,
                                     intptr_t requested_line,
                                     intptr_t requested_column);
   void RemoveInternalBreakpoints();
@@ -613,7 +628,7 @@
   void RegisterBreakpointLocation(BreakpointLocation* bpt);
   void RegisterCodeBreakpoint(CodeBreakpoint* bpt);
   BreakpointLocation* GetBreakpointLocation(const Script& script,
-                                            intptr_t token_pos,
+                                            TokenPosition token_pos,
                                             intptr_t requested_column);
   void MakeCodeBreakpointAt(const Function& func,
                             BreakpointLocation* bpt);
@@ -651,7 +666,8 @@
   // interrupts, etc.
   void Pause(DebuggerEvent* event);
 
-  void HandleSteppingRequest(DebuggerStackTrace* stack_trace);
+  void HandleSteppingRequest(DebuggerStackTrace* stack_trace,
+                             bool skip_next_step = false);
 
   Isolate* isolate_;
   Dart_Port isolate_id_;  // A unique ID for the isolate in the debugger.
@@ -690,6 +706,16 @@
   // lower on the stack.
   uword stepping_fp_;
 
+  // If we step while at a breakpoint, we would hit the same pc twice.
+  // We use this field to let us skip the next single-step after a
+  // breakpoint.
+  bool skip_next_step_;
+
+  // We keep this breakpoint alive until after the debugger does the step over
+  // async continuation machinery so that we can report that we've stopped
+  // at the breakpoint.
+  Breakpoint* synthetic_async_breakpoint_;
+
   Dart_ExceptionPauseInfo exc_pause_info_;
 
   static EventHandler* event_handler_;
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 7e1ec45..829f0f5 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -18,6 +18,7 @@
 // Facilitate quick access to the current zone once we have the curren thread.
 #define Z (T->zone())
 
+#ifndef PRODUCT
 
 #define UNWRAP_AND_CHECK_PARAM(type, var, param)                               \
   type& var = type::Handle();                                                  \
@@ -122,7 +123,7 @@
       location.script_url = Api::NewHandle(thread, top_frame->SourceUrl());
       const Library& lib = Library::Handle(top_frame->Library());
       location.library_id = lib.index();
-      location.token_pos = top_frame->TokenPos();
+      location.token_pos = top_frame->TokenPos().Pos();
       intptr_t bp_id = 0;
       if (event->breakpoint() != NULL) {
         ASSERT(event->breakpoint()->id() != ILLEGAL_BREAKPOINT_ID);
@@ -138,11 +139,11 @@
       Zone* zone = thread->zone();
       Library& library = Library::Handle(zone);
       Script& script = Script::Handle(zone);
-      intptr_t token_pos;
+      TokenPosition token_pos;
       bpt->bpt_location()->GetCodeLocation(&library, &script, &token_pos);
       location.script_url = Api::NewHandle(thread, script.url());
       location.library_id = library.index();
-      location.token_pos = token_pos;
+      location.token_pos = token_pos.Pos();
       (*bp_resolved_handler)(isolate_id, bpt->id(), location);
     }
   } else if (event->type() == DebuggerEvent::kExceptionThrown) {
@@ -292,7 +293,7 @@
     location->script_url = Api::NewHandle(T, frame->SourceUrl());
     const Library& lib = Library::Handle(Z, frame->Library());
     location->library_id = lib.index();
-    location->token_pos = frame->TokenPos();
+    location->token_pos = frame->TokenPos().Pos();
   }
   return Api::Success();
 }
@@ -652,7 +653,7 @@
 
   // Construct the super type object, canonicalize it and return.
   Type& instantiated_type = Type::Handle(
-      Type::New(super_cls, super_type_args_array, Scanner::kNoSourcePos));
+      Type::New(super_cls, super_type_args_array, TokenPosition::kNoSource));
   ASSERT(!instantiated_type.IsNull());
   instantiated_type.SetIsFinalized();
   return Api::NewHandle(T, instantiated_type.Canonicalize());
@@ -671,7 +672,7 @@
   if (!instance.IsClosure()) {
     return Api::NewError("%s: parameter 0 is not a closure", CURRENT_FUNC);
   }
-  const Function& func = Function::Handle(Closure::function(instance));
+  const Function& func = Function::Handle(Closure::Cast(instance).function());
   ASSERT(!func.IsNull());
   if (name != NULL) {
     *name = Api::NewHandle(T, func.QualifiedUserVisibleName());
@@ -681,7 +682,7 @@
   }
 
   if (location != NULL) {
-    if (func.token_pos() >= 0) {
+    if (func.token_pos().IsReal()) {
       const Class& cls = Class::Handle(Z, func.origin());
       ASSERT(!cls.IsNull());
       const Library& lib = Library::Handle(Z, cls.library());
@@ -691,7 +692,7 @@
       ASSERT(!script.IsNull());
       location->script_url = Api::NewHandle(T, script.url());
       location->library_id = lib.index();
-      location->token_pos = func.token_pos();
+      location->token_pos = func.token_pos().Pos();
     } else {
       location->script_url = Api::NewHandle(T, String::null());
       location->library_id = -1;
@@ -960,4 +961,12 @@
   return isolate->debugger()->GetIsolateId();
 }
 
+#else
+
+DART_EXPORT void Dart_SetPausedEventHandler(Dart_PausedEventHandler handler) {
+  // NOOP.
+}
+
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 8487801..0be2d29 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -11,9 +11,9 @@
 
 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
 
 static bool breakpoint_hit = false;
 static int  breakpoint_hit_counter = 0;
@@ -1511,6 +1511,8 @@
 
 
 TEST_CASE(Debug_InterruptIsolate) {
+  bool saved_flag = FLAG_trace_shutdown;
+  FLAG_trace_shutdown = true;
   sync = new Monitor();
   Dart_SetIsolateEventHandler(&TestInterruptIsolate);
   EXPECT(interrupt_isolate_id == ILLEGAL_ISOLATE_ID);
@@ -1520,6 +1522,7 @@
 
   // Wait for the test isolate to be created.
   {
+    OS::PrintErr("Waiting for isolate to be created\n");
     MonitorLocker ml(sync);
     while (interrupt_isolate_id == ILLEGAL_ISOLATE_ID) {
       ml.Wait();
@@ -1533,6 +1536,7 @@
 
   // Wait for the test isolate to be interrupted.
   {
+    OS::PrintErr("Waiting for isolate to be interrupted\n");
     MonitorLocker ml(sync);
     while (!isolate_interrupted || !pause_event_handled) {
       ml.Wait();
@@ -1543,12 +1547,15 @@
 
   // Wait for the test isolate to shutdown.
   {
+    OS::PrintErr("Waiting for isolate to be shut down\n");
     MonitorLocker ml(sync);
     while (interrupt_isolate_id != ILLEGAL_ISOLATE_ID) {
       ml.Wait();
     }
   }
   EXPECT(interrupt_isolate_id == ILLEGAL_ISOLATE_ID);
+  OS::PrintErr("Complete\n");
+  FLAG_trace_shutdown = saved_flag;
 }
 
 
@@ -2327,4 +2334,6 @@
       tokens_cstr);
 }
 
+#endif
+
 }  // namespace dart
diff --git a/runtime/vm/debugger_arm.cc b/runtime/vm/debugger_arm.cc
index 1322b8d..1705b30 100644
--- a/runtime/vm/debugger_arm.cc
+++ b/runtime/vm/debugger_arm.cc
@@ -13,6 +13,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 RawCode* CodeBreakpoint::OrigStubAddress() const {
   return saved_value_;
 }
@@ -55,6 +57,8 @@
   is_enabled_ = false;
 }
 
+#endif   // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/debugger_arm64.cc b/runtime/vm/debugger_arm64.cc
index bf6423a..b8ab73c 100644
--- a/runtime/vm/debugger_arm64.cc
+++ b/runtime/vm/debugger_arm64.cc
@@ -13,6 +13,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 RawCode* CodeBreakpoint::OrigStubAddress() const {
   return saved_value_;
 }
@@ -57,6 +59,8 @@
   is_enabled_ = false;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM64
diff --git a/runtime/vm/debugger_ia32.cc b/runtime/vm/debugger_ia32.cc
index cc1c63d..9c4473b 100644
--- a/runtime/vm/debugger_ia32.cc
+++ b/runtime/vm/debugger_ia32.cc
@@ -17,6 +17,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 RawCode* CodeBreakpoint::OrigStubAddress() const {
   return saved_value_;
 }
@@ -70,6 +72,8 @@
   is_enabled_ = false;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_IA32
diff --git a/runtime/vm/debugger_mips.cc b/runtime/vm/debugger_mips.cc
index 8a02ca8..5fd151a 100644
--- a/runtime/vm/debugger_mips.cc
+++ b/runtime/vm/debugger_mips.cc
@@ -13,6 +13,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 RawCode* CodeBreakpoint::OrigStubAddress() const {
   return saved_value_;
 }
@@ -55,6 +57,8 @@
   is_enabled_ = false;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/debugger_test.cc b/runtime/vm/debugger_test.cc
index b418cbf..ffe3241 100644
--- a/runtime/vm/debugger_test.cc
+++ b/runtime/vm/debugger_test.cc
@@ -8,6 +8,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 // Search for the formatted string in buffer.
 //
 // TODO(turnidge): This function obscures the line number of failing
@@ -135,4 +137,6 @@
   EXPECT(saw_paused_event);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/debugger_x64.cc b/runtime/vm/debugger_x64.cc
index 4fe2e6a..7da5fc7 100644
--- a/runtime/vm/debugger_x64.cc
+++ b/runtime/vm/debugger_x64.cc
@@ -15,6 +15,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 RawCode* CodeBreakpoint::OrigStubAddress() const {
   return saved_value_;
 }
@@ -58,6 +60,7 @@
   is_enabled_ = false;
 }
 
+#endif  // !PRODUCT
 
 }  // namespace dart
 
diff --git a/runtime/vm/debuginfo.h b/runtime/vm/debuginfo.h
deleted file mode 100644
index fd94268..0000000
--- a/runtime/vm/debuginfo.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef VM_DEBUGINFO_H_
-#define VM_DEBUGINFO_H_
-
-#include "platform/assert.h"
-#include "platform/utils.h"
-#include "vm/globals.h"
-
-namespace dart {
-
-// DebugInfo is used to generate minimal debug information containing code,
-// symbols, and line numbers for generated code in the dart VM. This information
-// can be used in two ways:
-// - for debugging using a debugger
-// - for generating information to be read by pprof to analyze Dart programs.
-class DebugInfo {
- public:
-  // A basic ByteBuffer which is growable and uses malloc/free.
-  class ByteBuffer {
-   public:
-    ByteBuffer() : size_(0), capacity_(0), data_(NULL) { }
-    ~ByteBuffer() {
-      free(data_);
-      size_ = 0;
-      capacity_ = 0;
-      data_ = NULL;
-    }
-
-    uint8_t at(int index) const {
-      ASSERT(0 <= index);
-      ASSERT(index < size_);
-      ASSERT(size_ <= capacity_);
-      return data_[index];
-    }
-
-    uint8_t* data() const { return data_; }
-    void set_data(uint8_t* value) { data_ = value; }
-    int size() const { return size_; }
-
-    // Append an element.
-    void Add(const uint8_t value) {
-      Resize(size() + 1);
-      data_[size() - 1] = value;
-    }
-
-   private:
-    void Resize(int new_size) {
-      if (new_size > capacity_) {
-        int new_capacity = Utils::RoundUpToPowerOfTwo(new_size);
-        uint8_t* new_data =
-            reinterpret_cast<uint8_t*>(realloc(data_, new_capacity));
-        ASSERT(new_data != NULL);
-        data_ = new_data;
-        capacity_ = new_capacity;
-      }
-      size_ = new_size;
-    }
-
-    int size_;
-    int capacity_;
-    uint8_t* data_;
-
-    // Disallow assignment
-    DISALLOW_COPY_AND_ASSIGN(ByteBuffer);
-  };
-
-  ~DebugInfo();
-
-  // Add the code starting at pc.
-  void AddCode(uword pc, intptr_t size);
-
-  // Add symbol information for a region (includes the start and end symbol),
-  // does not add the actual code.
-  void AddCodeRegion(const char* name, uword pc, intptr_t size);
-
-  // Write out all the debug information info the memory region.
-  bool WriteToMemory(ByteBuffer* region);
-
-  // Create a new debug information generator.
-  static DebugInfo* NewGenerator();
-
-  // Register this generated section with debuggger using the JIT interface.
-  static void RegisterSection(const char* name,
-                              uword entry_point,
-                              intptr_t size);
-
-  // Unregister all generated section from debuggger.
-  static void UnregisterAllSections();
-
- private:
-  void* handle_;
-  DebugInfo();
-
-  DISALLOW_COPY_AND_ASSIGN(DebugInfo);
-};
-
-}  // namespace dart
-
-#endif  // VM_DEBUGINFO_H_
diff --git a/runtime/vm/debuginfo_android.cc b/runtime/vm/debuginfo_android.cc
deleted file mode 100644
index ee4015c..0000000
--- a/runtime/vm/debuginfo_android.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/globals.h"
-#if defined(TARGET_OS_ANDROID)
-
-#include "vm/debuginfo.h"
-
-#include "vm/elfgen.h"
-#include "vm/gdbjit_android.h"
-
-namespace dart {
-
-DebugInfo::DebugInfo() {
-  handle_ = reinterpret_cast<void*>(new ElfGen());
-  ASSERT(handle_ != NULL);
-}
-
-
-DebugInfo::~DebugInfo() {
-  ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
-  delete elf_gen;
-}
-
-
-void DebugInfo::AddCode(uword pc, intptr_t size) {
-  ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
-  elf_gen->AddCode(pc, size);
-}
-
-
-void DebugInfo::AddCodeRegion(const char* name, uword pc, intptr_t size) {
-  ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
-  elf_gen->AddCodeRegion(name, pc, size);
-}
-
-
-bool DebugInfo::WriteToMemory(ByteBuffer* region) {
-  ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
-  return elf_gen->WriteToMemory(region);
-}
-
-
-DebugInfo* DebugInfo::NewGenerator() {
-  return new DebugInfo();
-}
-
-
-void DebugInfo::RegisterSection(const char* name,
-                                uword entry_point,
-                                intptr_t size) {
-  ElfGen* elf_section = new ElfGen();
-  ASSERT(elf_section != NULL);
-  elf_section->AddCode(entry_point, size);
-  elf_section->AddCodeRegion(name, entry_point, size);
-
-  ByteBuffer* dynamic_region = new ByteBuffer();
-  ASSERT(dynamic_region != NULL);
-
-  elf_section->WriteToMemory(dynamic_region);
-
-  ::addDynamicSection(reinterpret_cast<const char*>(dynamic_region->data()),
-                      dynamic_region->size());
-  dynamic_region->set_data(NULL);
-  delete dynamic_region;
-  delete elf_section;
-}
-
-
-void DebugInfo::UnregisterAllSections() {
-  ::deleteDynamicSections();
-}
-
-}  // namespace dart
-
-#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/debuginfo_linux.cc b/runtime/vm/debuginfo_linux.cc
deleted file mode 100644
index 9e73553..0000000
--- a/runtime/vm/debuginfo_linux.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/globals.h"
-#if defined(TARGET_OS_LINUX)
-
-#include "vm/debuginfo.h"
-
-#include "vm/elfgen.h"
-#include "vm/gdbjit_linux.h"
-
-namespace dart {
-
-DebugInfo::DebugInfo() {
-  handle_ = reinterpret_cast<void*>(new ElfGen());
-  ASSERT(handle_ != NULL);
-}
-
-
-DebugInfo::~DebugInfo() {
-  ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
-  delete elf_gen;
-}
-
-
-void DebugInfo::AddCode(uword pc, intptr_t size) {
-  ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
-  elf_gen->AddCode(pc, size);
-}
-
-
-void DebugInfo::AddCodeRegion(const char* name, uword pc, intptr_t size) {
-  ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
-  elf_gen->AddCodeRegion(name, pc, size);
-}
-
-
-bool DebugInfo::WriteToMemory(ByteBuffer* region) {
-  ElfGen* elf_gen = reinterpret_cast<ElfGen*>(handle_);
-  return elf_gen->WriteToMemory(region);
-}
-
-
-DebugInfo* DebugInfo::NewGenerator() {
-  return new DebugInfo();
-}
-
-
-void DebugInfo::RegisterSection(const char* name,
-                                uword entry_point,
-                                intptr_t size) {
-  ElfGen* elf_section = new ElfGen();
-  ASSERT(elf_section != NULL);
-  elf_section->AddCode(entry_point, size);
-  elf_section->AddCodeRegion(name, entry_point, size);
-
-  ByteBuffer* dynamic_region = new ByteBuffer();
-  ASSERT(dynamic_region != NULL);
-
-  elf_section->WriteToMemory(dynamic_region);
-
-  ::addDynamicSection(reinterpret_cast<const char*>(dynamic_region->data()),
-                      dynamic_region->size());
-  dynamic_region->set_data(NULL);
-  delete dynamic_region;
-  delete elf_section;
-}
-
-
-void DebugInfo::UnregisterAllSections() {
-  ::deleteDynamicSections();
-}
-
-}  // namespace dart
-
-#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index 71a734a..d3f89c7 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -304,6 +304,48 @@
         }
       }
     }
+  } else if (cls.id() == kClosureCid) {
+    // TODO(regis): It would be better to programmatically add these fields to
+    // the VM Closure class. Declaring them in the Dart class _Closure does not
+    // work, because the class is prefinalized and CalculateFieldOffsets is
+    // therefore not called. Resetting the finalization state may be an option.
+    const Closure& closure = Closure::Cast(*object_);
+
+    Smi& offset = Smi::Handle();
+    Object& value = Object::Handle();
+
+    for (intptr_t i = 0; i < field_count_; i++) {
+      offset ^= GetFieldOffset(i);
+      if (offset.Value() == Closure::type_arguments_offset()) {
+        TypeArguments& arguments = TypeArguments::Handle();
+        arguments ^= GetValue(i);
+        closure.SetTypeArguments(arguments);
+        if (FLAG_trace_deoptimization_verbose) {
+          OS::PrintErr("    closure@type_arguments (offset %" Pd ") <- %s\n",
+                       offset.Value(),
+                       value.ToCString());
+        }
+      } else if (offset.Value() == Closure::function_offset()) {
+        Function& function = Function::Handle();
+        function ^= GetValue(i);
+        closure.set_function(function);
+        if (FLAG_trace_deoptimization_verbose) {
+          OS::PrintErr("    closure@function (offset %" Pd ") <- %s\n",
+                       offset.Value(),
+                       value.ToCString());
+        }
+      } else {
+        ASSERT(offset.Value() == Closure::context_offset());
+        Context& context = Context::Handle();
+        context ^= GetValue(i);
+        closure.set_context(context);
+        if (FLAG_trace_deoptimization_verbose) {
+          OS::PrintErr("    closure@context (offset %" Pd ") <- %s\n",
+                       offset.Value(),
+                       value.ToCString());
+        }
+      }
+    }
   } else {
     const Instance& obj = Instance::Cast(*object_);
 
@@ -324,8 +366,7 @@
                        value.ToCString());
         }
       } else {
-        ASSERT(cls.IsSignatureClass() ||
-               (offset.Value() == cls.type_arguments_field_offset()));
+        ASSERT(offset.Value() == cls.type_arguments_field_offset());
         obj.SetFieldAtOffset(offset.Value(), value);
         if (FLAG_trace_deoptimization_verbose) {
           OS::PrintErr("    null Field @ offset(%" Pd ") <- %s\n",
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 4970e59..1aa11b7 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -138,23 +138,26 @@
   delete[] deferred_objects_;
   deferred_objects_ = NULL;
   deferred_objects_count_ = 0;
-  if (deopt_start_micros_ != 0) {
+  if (FLAG_support_timeline && (deopt_start_micros_ != 0)) {
     Isolate* isolate = Isolate::Current();
     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();
@@ -356,7 +359,7 @@
     const Code& code = Code::Handle(top_frame->LookupDartCode());
     const Function& top_function = Function::Handle(code.function());
     const Script& script = Script::Handle(top_function.script());
-    const intptr_t token_pos = code.GetTokenIndexOfPC(top_frame->pc());
+    const TokenPosition token_pos = code.GetTokenIndexOfPC(top_frame->pc());
     intptr_t line, column;
     script.GetTokenLocation(token_pos, &line, &column);
     String& line_string = String::Handle(script.GetLine(line));
@@ -423,8 +426,10 @@
 
  private:
   static const intptr_t kFieldWidth = kBitsPerWord / 2;
-  class ObjectTableIndex : public BitField<intptr_t, 0, kFieldWidth> { };
-  class DeoptId : public BitField<intptr_t, kFieldWidth, kFieldWidth> { };
+  class ObjectTableIndex :
+      public BitField<intptr_t, intptr_t, 0, kFieldWidth> { };
+  class DeoptId :
+      public BitField<intptr_t, intptr_t, kFieldWidth, kFieldWidth> { };
 
   const intptr_t object_table_index_;
   const intptr_t deopt_id_;
@@ -547,8 +552,9 @@
 
  private:
   static const intptr_t kFieldWidth = kBitsPerWord / 2;
-  class LoRegister : public BitField<intptr_t, 0, kFieldWidth> { };
-  class HiRegister : public BitField<intptr_t, kFieldWidth, kFieldWidth> { };
+  class LoRegister : public BitField<intptr_t, intptr_t, 0, kFieldWidth> { };
+  class HiRegister :
+      public BitField<intptr_t, intptr_t, kFieldWidth, kFieldWidth> { };
 
   const CpuRegisterSource lo_;
   const CpuRegisterSource hi_;
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index acbf92b..229a0aa 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -399,8 +399,9 @@
   }
 
  private:
-  class KindField : public BitField<intptr_t, 0, 1> { };
-  class RawIndexField : public BitField<intptr_t, 1, kBitsPerWord - 1> { };
+  class KindField : public BitField<intptr_t, intptr_t, 0, 1> { };
+  class RawIndexField :
+      public BitField<intptr_t, intptr_t, 1, kBitsPerWord - 1> { };
 
   bool is_register() const {
     return KindField::decode(source_index_) == kRegister;
@@ -484,7 +485,10 @@
   intptr_t CalculateStackIndex(const Location& source_loc) const;
 
   intptr_t FrameSize() const {
-    return instructions_.length() - frame_start_;
+    ASSERT(frame_start_ != -1);
+    const intptr_t frame_size = instructions_.length() - frame_start_;
+    ASSERT(frame_size >= 0);
+    return frame_size;
   }
 
   void AddConstant(const Object& obj, intptr_t dest_index);
@@ -543,8 +547,9 @@
                     FlagsField::encode(flags));
   }
 
-  class ReasonField : public BitField<ICData::DeoptReasonId, 0, 8> { };
-  class FlagsField : public BitField<uint32_t, 8, 8> { };
+  class ReasonField :
+      public BitField<intptr_t, ICData::DeoptReasonId, 0, 8> { };
+  class FlagsField : public BitField<intptr_t, uint32_t, 8, 8> { };
 
  private:
   static const intptr_t kEntrySize = 3;
diff --git a/runtime/vm/disassembler.cc b/runtime/vm/disassembler.cc
index 99b13ce..1fe4215 100644
--- a/runtime/vm/disassembler.cc
+++ b/runtime/vm/disassembler.cc
@@ -5,6 +5,7 @@
 #include "vm/disassembler.h"
 
 #include "vm/assembler.h"
+#include "vm/deopt_instructions.h"
 #include "vm/globals.h"
 #include "vm/il_printer.h"
 #include "vm/instructions.h"
@@ -16,6 +17,10 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
+DECLARE_FLAG(bool, trace_inlining_intervals);
+
 void DisassembleToStdout::ConsumeInstruction(const Code& code,
                                              char* hex_buffer,
                                              intptr_t hex_size,
@@ -179,4 +184,147 @@
   }
 }
 
+
+void Disassembler::DisassembleCode(const Function& function, bool optimized) {
+  const char* function_fullname = function.ToFullyQualifiedCString();
+  THR_Print("Code for %sfunction '%s' {\n",
+            optimized ? "optimized " : "",
+            function_fullname);
+  const Code& code = Code::Handle(function.CurrentCode());
+  code.Disassemble();
+  THR_Print("}\n");
+
+  THR_Print("Pointer offsets for function: {\n");
+  // Pointer offsets are stored in descending order.
+  Object& obj = Object::Handle();
+  for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) {
+    const uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint();
+    obj = *reinterpret_cast<RawObject**>(addr);
+    THR_Print(" %d : %#" Px " '%s'\n",
+              code.GetPointerOffsetAt(i), addr, obj.ToCString());
+  }
+  THR_Print("}\n");
+
+  THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
+  PcDescriptors::PrintHeaderString();
+  const PcDescriptors& descriptors =
+      PcDescriptors::Handle(code.pc_descriptors());
+  THR_Print("%s}\n", descriptors.ToCString());
+
+  uword start = Instructions::Handle(code.instructions()).EntryPoint();
+  const Array& deopt_table = Array::Handle(code.deopt_info_array());
+  intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
+  if (deopt_table_length > 0) {
+    THR_Print("DeoptInfo: {\n");
+    Smi& offset = Smi::Handle();
+    TypedData& info = TypedData::Handle();
+    Smi& reason_and_flags = Smi::Handle();
+    for (intptr_t i = 0; i < deopt_table_length; ++i) {
+      DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags);
+      const intptr_t reason =
+          DeoptTable::ReasonField::decode(reason_and_flags.Value());
+      ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons));
+      THR_Print("%4" Pd ": 0x%" Px "  %s  (%s)\n",
+                i,
+                start + offset.Value(),
+                DeoptInfo::ToCString(deopt_table, info),
+                DeoptReasonToCString(
+                    static_cast<ICData::DeoptReasonId>(reason)));
+    }
+    THR_Print("}\n");
+  }
+
+  const ObjectPool& object_pool = ObjectPool::Handle(code.GetObjectPool());
+  object_pool.DebugPrint();
+
+  THR_Print("Stackmaps for function '%s' {\n", function_fullname);
+  if (code.stackmaps() != Array::null()) {
+    const Array& stackmap_table = Array::Handle(code.stackmaps());
+    Stackmap& map = Stackmap::Handle();
+    for (intptr_t i = 0; i < stackmap_table.Length(); ++i) {
+      map ^= stackmap_table.At(i);
+      THR_Print("%s\n", map.ToCString());
+    }
+  }
+  THR_Print("}\n");
+
+  THR_Print("Variable Descriptors for function '%s' {\n",
+            function_fullname);
+  const LocalVarDescriptors& var_descriptors =
+      LocalVarDescriptors::Handle(code.GetLocalVarDescriptors());
+  intptr_t var_desc_length =
+      var_descriptors.IsNull() ? 0 : var_descriptors.Length();
+  String& var_name = String::Handle();
+  for (intptr_t i = 0; i < var_desc_length; i++) {
+    var_name = var_descriptors.GetName(i);
+    RawLocalVarDescriptors::VarInfo var_info;
+    var_descriptors.GetInfo(i, &var_info);
+    const int8_t kind = var_info.kind();
+    if (kind == RawLocalVarDescriptors::kSavedCurrentContext) {
+      THR_Print("  saved current CTX reg offset %d\n", var_info.index());
+    } else {
+      if (kind == RawLocalVarDescriptors::kContextLevel) {
+        THR_Print("  context level %d scope %d", var_info.index(),
+            var_info.scope_id);
+      } else if (kind == RawLocalVarDescriptors::kStackVar) {
+        THR_Print("  stack var '%s' offset %d",
+          var_name.ToCString(), var_info.index());
+      } else {
+        ASSERT(kind == RawLocalVarDescriptors::kContextVar);
+        THR_Print("  context var '%s' level %d offset %d",
+            var_name.ToCString(), var_info.scope_id, var_info.index());
+      }
+      THR_Print(" (valid %s-%s)\n", var_info.begin_pos.ToCString(),
+                                    var_info.end_pos.ToCString());
+    }
+  }
+  THR_Print("}\n");
+
+  THR_Print("Exception Handlers for function '%s' {\n", function_fullname);
+  const ExceptionHandlers& handlers =
+        ExceptionHandlers::Handle(code.exception_handlers());
+  THR_Print("%s}\n", handlers.ToCString());
+
+  {
+    THR_Print("Static call target functions {\n");
+    const Array& table = Array::Handle(code.static_calls_target_table());
+    Smi& offset = Smi::Handle();
+    Function& function = Function::Handle();
+    Code& code = Code::Handle();
+    for (intptr_t i = 0; i < table.Length();
+        i += Code::kSCallTableEntryLength) {
+      offset ^= table.At(i + Code::kSCallTableOffsetEntry);
+      function ^= table.At(i + Code::kSCallTableFunctionEntry);
+      code ^= table.At(i + Code::kSCallTableCodeEntry);
+      if (function.IsNull()) {
+        Class& cls = Class::Handle();
+        cls ^= code.owner();
+        if (cls.IsNull()) {
+          const String& code_name = String::Handle(code.Name());
+          THR_Print("  0x%" Px ": %s, %p\n",
+              start + offset.Value(),
+              code_name.ToCString(),
+              code.raw());
+        } else {
+          THR_Print("  0x%" Px ": allocation stub for %s, %p\n",
+              start + offset.Value(),
+              cls.ToCString(),
+              code.raw());
+        }
+      } else {
+        THR_Print("  0x%" Px ": %s, %p\n",
+            start + offset.Value(),
+            function.ToFullyQualifiedCString(),
+            code.raw());
+      }
+    }
+    THR_Print("}\n");
+  }
+  if (optimized && FLAG_trace_inlining_intervals) {
+    code.DumpInlinedIntervals();
+  }
+}
+
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/disassembler.h b/runtime/vm/disassembler.h
index e89ab21..c7a1eec 100644
--- a/runtime/vm/disassembler.h
+++ b/runtime/vm/disassembler.h
@@ -136,6 +136,8 @@
 
   static bool CanFindOldObject(uword addr);
 
+  static void DisassembleCode(const Function& function, bool optimized);
+
  private:
   static const int kHexadecimalBufferSize = 32;
   static const int kUserReadableBufferSize = 256;
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index a544e3c..437bee8 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -12,6 +12,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 class ARMDecoder : public ValueObject {
  public:
   ARMDecoder(char* buffer, size_t buffer_size)
@@ -1540,6 +1542,8 @@
   }
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/disassembler_arm64.cc b/runtime/vm/disassembler_arm64.cc
index e414221..a238641 100644
--- a/runtime/vm/disassembler_arm64.cc
+++ b/runtime/vm/disassembler_arm64.cc
@@ -10,6 +10,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 class ARM64Decoder : public ValueObject {
  public:
   ARM64Decoder(char* buffer, size_t buffer_size)
@@ -332,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;
@@ -740,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: {
@@ -847,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)) {
@@ -948,6 +979,8 @@
     DecodeLoadStoreRegPair(instr);
   } else if (instr->IsLoadRegLiteralOp()) {
     DecodeLoadRegLiteral(instr);
+  } else if (instr->IsLoadStoreExclusiveOp()) {
+    DecodeLoadStoreExclusive(instr);
   } else {
     Unknown(instr);
   }
@@ -1465,6 +1498,8 @@
   }
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index 0f6dc74..31e4fdba 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -15,6 +15,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 // Tables used for decoding of x86 instructions.
 enum OperandOrder {
   UNSET_OP_ORDER = 0,
@@ -1862,6 +1864,8 @@
   }
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_IA32
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index aabaafe..b9e0987 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -10,6 +10,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 class MIPSDecoder : public ValueObject {
  public:
   MIPSDecoder(char* buffer, size_t buffer_size)
@@ -710,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;
@@ -726,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;
@@ -774,6 +784,8 @@
   }
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_MIPS
diff --git a/runtime/vm/disassembler_test.cc b/runtime/vm/disassembler_test.cc
index 1c33942..d07e174 100644
--- a/runtime/vm/disassembler_test.cc
+++ b/runtime/vm/disassembler_test.cc
@@ -9,6 +9,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 TEST_CASE(Disassembler) {
   Assembler assembler;
   // The used instructions work on all platforms.
@@ -22,4 +24,6 @@
   Disassembler::Disassemble(test.entry(), test.entry() + assembler.CodeSize());
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 4778695..37d8184 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -15,6 +15,7 @@
 
 namespace dart {
 
+#ifndef PRODUCT
 
 enum OperandType {
   UNSET_OP_ORDER = 0,
@@ -1947,6 +1948,8 @@
   }
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined TARGET_ARCH_X64
diff --git a/runtime/vm/elfgen.h b/runtime/vm/elfgen.h
deleted file mode 100644
index f3fcd70..0000000
--- a/runtime/vm/elfgen.h
+++ /dev/null
@@ -1,509 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef VM_ELFGEN_H_
-#define VM_ELFGEN_H_
-
-#include "vm/lockers.h"
-#include "vm/os_thread.h"
-
-namespace dart {
-
-// -----------------------------------------------------------------------------
-// Implementation of ElfGen
-//
-// Specification documents:
-//   http://refspecs.freestandards.org
-//
-//   ELF generic ABI:
-//     http://refspecs.freestandards.org/elf/gabi4+/contents.html
-//   ELF processor-specific supplement for X86_64:
-//     http://refspecs.freestandards.org/elf/x86_64-SysV-psABI.pdf
-//   DWARF 2.0:
-//     http://refspecs.freestandards.org/dwarf/dwarf-2.0.0.pdf
-
-// Forward declarations.
-class File;
-
-// ElfGen is used to generate minimal ELF information containing code, symbols,
-// and line numbers for generated code in the dart VM. This information is
-// used in two ways:
-// - it is used to generate in-memory ELF information which is then
-//   registered with gdb using the JIT interface.
-// - it is also used to generate a file with the ELF information. This file
-//   is not executed, but read by pprof to analyze Dart programs.
-
-class ElfGen {
- public:
-  ElfGen();
-  ~ElfGen();
-
-  // Add the code starting at pc.
-  void AddCode(uword pc, intptr_t size);
-
-  // Add symbol information for a region (includes the start and end symbol),
-  // does not add the actual code.
-  void AddCodeRegion(const char* name, uword pc, intptr_t size);
-
-  // Add specified symbol information, does not add the actual code.
-  int AddFunction(const char* name, uword pc, intptr_t size);
-
-  // Write out all the Elf information using the specified handle.
-  bool WriteToFile(File* handle);
-  bool WriteToMemory(DebugInfo::ByteBuffer* region);
-
-  // Register this generated section with GDB using the JIT interface.
-  static void RegisterSectionWithGDB(const char* name,
-                                     uword entry_point,
-                                     intptr_t size);
-
-  // Unregister all generated section from GDB.
-  static void UnregisterAllSectionsWithGDB();
-
- private:
-  // ELF helpers
-  typedef int (*OutputWriter)(void* handle,
-                              const DebugInfo::ByteBuffer& section);
-  typedef void (*OutputPadder)(void* handle, int padding_size);
-
-  int AddString(DebugInfo::ByteBuffer* buf, const char* str);
-  int AddSectionName(const char* str);
-  int AddName(const char* str);
-  void AddELFHeader(int shoff);
-  void AddSectionHeader(int section, int offset);
-  int PadSection(DebugInfo::ByteBuffer* section, int offset, int alignment);
-  bool WriteOutput(void* handle, OutputWriter writer, OutputPadder padder);
-
-  uword text_vma_;  // text section vma
-  intptr_t text_size_;  // text section size
-  int text_padding_;  // padding preceding text section
-
-  static const int kNumSections = 5;  // we generate 5 sections
-  int section_name_[kNumSections];  // array of section name indices
-  DebugInfo::ByteBuffer section_buf_[kNumSections];  // array of section buffers
-  DebugInfo::ByteBuffer header_;  // ELF header buffer
-  DebugInfo::ByteBuffer sheaders_;  // section header table buffer
-  DebugInfo::ByteBuffer lineprog_;  // line statement program, part of
-                                    // '.debug_line' section
-
-  // current state of the DWARF line info generator
-  uintptr_t cur_addr_;  // current pc
-  int map_offset_;
-  uword map_begin_;
-  uword map_end_;
-
-  Mutex lock_;
-};
-
-
-enum {
-  // Various constant sizes for ELF files.
-  kAddrSize = sizeof(uword),
-  kPageSize = 4*1024,  // Memory mapping page size.
-  kTextAlign = 16,
-  kELFHeaderSize = 40 + 3*kAddrSize,
-  kProgramHeaderEntrySize = 8 + 6*kAddrSize,
-  kSectionHeaderEntrySize = 16 + 6*kAddrSize,
-  kSymbolSize = 8 + 2*kAddrSize,
-
-  // Our own layout of sections.
-  kUndef = 0,   // Undefined section.
-  kText,        // Text section.
-  kShStrtab,    // Section header string table.
-  kStrtab,      // String table.
-  kSymtab,      // Symbol table.
-  kNumSections,  // Num of section header entries in section header table.
-
-  // Various ELF constants.
-  kELFCLASS32 = 1,
-  kELFCLASS64 = 2,
-  kELFDATA2LSB = 1,
-  kELFDATA2MSB = 2,
-  kEM_386 = 3,
-  kEM_MIPS = 8,
-  kEM_ARM = 40,
-  kEM_X86_64 = 62,
-  kEV_CURRENT = 1,
-  kET_EXEC = 2,  // not used
-  kET_DYN = 3,
-  kSHT_PROGBITS = 1,
-  kSHT_SYMTAB = 2,
-  kSHT_STRTAB = 3,
-  kSHF_WRITE = 1,  // not used
-  kSHF_ALLOC = 2,
-  kSHF_EXECINSTR = 4,
-  kSTB_LOCAL = 0,
-  kSTB_EXPORTED = 1,
-  kSTT_FUNC = 2,
-};
-
-
-// ELF and DWARF constants.
-static const char* kEI_MAG0_MAG3 = "\177ELF";
-static const uint8_t kSpecialOpcodeLengths[] = { 0, 1, 1, 1, 1, 0, 0, 0, 1 };
-
-
-// Section attributes.
-// The field names correspond to the field names of Elf32_Shdr and Elf64_Shdr.
-static const struct {
-  // Section header index (only used to check correct section order).
-  int shndx;
-  const char* name;  // sh_name will be the index of name inserted in shstrtab.
-  int sh_type;
-  int sh_flags;
-  int sh_link;
-  int sh_addralign;
-  int sh_entsize;
-} section_attr[kNumSections + 1] = {
-  { kUndef,      "",               0,             0,
-    0,       0,           0           },
-  { kText,       ".text",          kSHT_PROGBITS, kSHF_ALLOC|kSHF_EXECINSTR,
-    0,       kTextAlign,  0           },
-  { kShStrtab,   ".shstrtab",      kSHT_STRTAB,   0,
-    0,       1,           0           },
-  { kStrtab,     ".strtab",        kSHT_STRTAB,   0,
-    0,       1,           0           },
-  { kSymtab,     ".symtab",        kSHT_SYMTAB,   0,
-    kStrtab, kAddrSize,   kSymbolSize },
-  // Sentinel to pad the last section
-  // for proper alignment of section header table.
-  { 0,          "",               0,             0,
-    0,       kAddrSize,   0           }
-};
-
-
-// Convenience function aligning an integer.
-static inline uintptr_t Align(uintptr_t x, intptr_t size) {
-  // size is a power of 2
-  ASSERT((size & (size-1)) == 0);
-  return (x + (size-1)) & ~(size-1);
-}
-
-
-// Convenience function writing a single byte to a ByteBuffer.
-static inline void WriteByte(DebugInfo::ByteBuffer* buf, uint8_t byte) {
-  buf->Add(byte);
-}
-
-
-// Convenience function writing an unsigned native word to a ByteBuffer.
-// The word is 32-bit wide in 32-bit mode and 64-bit wide in 64-bit mode.
-static inline void WriteWord(DebugInfo::ByteBuffer* buf, uword word) {
-  uint8_t* p = reinterpret_cast<uint8_t*>(&word);
-  for (size_t i = 0; i < sizeof(word); i++) {
-    buf->Add(p[i]);
-  }
-}
-
-static inline void WriteInt(DebugInfo::ByteBuffer* buf, int word) {
-  uint8_t* p = reinterpret_cast<uint8_t*>(&word);
-  for (size_t i = 0; i < sizeof(word); i++) {
-    buf->Add(p[i]);
-  }
-}
-
-static inline void WriteShort(DebugInfo::ByteBuffer* buf, uint16_t word) {
-  uint8_t* p = reinterpret_cast<uint8_t*>(&word);
-  for (size_t i = 0; i < sizeof(word); i++) {
-    buf->Add(p[i]);
-  }
-}
-
-static inline void WriteString(DebugInfo::ByteBuffer* buf, const char* str) {
-  for (size_t i = 0; i < strlen(str); i++) {
-    buf->Add(static_cast<uint8_t>(str[i]));
-  }
-}
-
-static inline void Write(DebugInfo::ByteBuffer* buf,
-                         const void* mem,
-                         int length) {
-  const uint8_t* p = reinterpret_cast<const uint8_t*>(mem);
-  for (int i = 0; i < length; i++) {
-    buf->Add(p[i]);
-  }
-}
-
-
-// Write given section to file and return written size.
-static int WriteSectionToFile(void* handle,
-                              const DebugInfo::ByteBuffer& section) {
-#if 0
-  File* fp = reinterpret_cast<File*>(handle);
-  int size = section.size();
-  fp->WriteFully(section.data(), size);
-  return size;
-#else
-  return 0;
-#endif
-}
-
-
-// Pad output file to specified padding size.
-static void PadFile(void* handle, int padding_size) {
-#if 0
-  File* fp = reinterpret_cast<File*>(handle);
-  for (int i = 0; i < padding_size; i++) {
-    fp->WriteFully("", 1);
-  }
-#endif
-}
-
-
-// Write given section to specified memory region and return written size.
-static int WriteSectionToMemory(void* handle,
-                                const DebugInfo::ByteBuffer& section) {
-  DebugInfo::ByteBuffer* buffer =
-      reinterpret_cast<DebugInfo::ByteBuffer*>(handle);
-  int size = section.size();
-  for (int i = 0; i < size; i++) {
-    buffer->Add(static_cast<uint8_t>(section.data()[i]));
-  }
-  return size;
-}
-
-
-// Pad memory to specified padding size.
-static void PadMemory(void* handle, int padding_size) {
-  DebugInfo::ByteBuffer* buffer =
-      reinterpret_cast<DebugInfo::ByteBuffer*>(handle);
-  for (int i = 0; i < padding_size; i++) {
-    buffer->Add(static_cast<uint8_t>(0));
-  }
-}
-
-
-// Constructor
-ElfGen::ElfGen()
-    : text_vma_(0), text_size_(0), text_padding_(0), map_offset_(0), lock_() {
-  for (int i = 0; i < kNumSections; i++) {
-    ASSERT(section_attr[i].shndx == i);  // Verify layout of sections.
-    section_name_[i] = AddSectionName(section_attr[i].name);
-  }
-  // Section header string table always starts with an empty string, which is
-  // the name of the kUndef section.
-  ASSERT((section_attr[0].name[0] == '\0') && (section_name_[0] == 0));
-
-  // String table always starts with an empty string.
-  AddName("");
-  ASSERT(section_buf_[kStrtab].size() == 1);
-
-  // Symbol at index 0 in symtab is always STN_UNDEF (all zero):
-  DebugInfo::ByteBuffer* symtab = &section_buf_[kSymtab];
-  while (symtab->size() < kSymbolSize) {
-    WriteInt(symtab, 0);
-  }
-  ASSERT(symtab->size() == kSymbolSize);
-}
-
-
-// Destructor
-ElfGen::~ElfGen() {
-}
-
-
-void ElfGen::AddCode(uword pc, intptr_t size) {
-  MutexLocker ml(&lock_);
-  text_vma_ = pc;
-  text_size_ = size;
-  // We pad the text section in the file to align absolute code addresses with
-  // corresponding file offsets as if the code had been loaded by memory
-  // mapping.
-  if (text_vma_ % kPageSize < kELFHeaderSize) {
-    text_padding_ = text_vma_ % kPageSize + kPageSize - kELFHeaderSize;
-  } else {
-    text_padding_ = text_vma_ % kPageSize - kELFHeaderSize;
-  }
-
-  Write(&section_buf_[kText], reinterpret_cast<void*>(pc), size);
-  // map_offset is the file offset of the first mapped page.
-  map_offset_ = (kELFHeaderSize + text_padding_)/kPageSize*kPageSize;
-  map_begin_ = Align(text_vma_ - kPageSize + 1, kPageSize);
-  map_end_ = Align(text_vma_ + size, kPageSize);
-}
-
-
-void ElfGen::AddCodeRegion(const char* name, uword pc, intptr_t size) {
-  MutexLocker ml(&lock_);
-  AddFunction(name, pc, size);
-  char end_name[256];
-  OS::SNPrint(end_name, sizeof(end_name), "%s_end", name);
-  AddFunction(end_name, pc + size, 0);
-}
-
-
-int ElfGen::AddFunction(const char* name, uword pc, intptr_t size) {
-  ASSERT(text_vma_ != 0);  // code must have been added
-  DebugInfo::ByteBuffer* symtab = &section_buf_[kSymtab];
-  const int beg = symtab->size();
-  WriteInt(symtab, AddName(name));  // st_name
-#if defined(ARCH_IS_64_BIT)
-  WriteShort(symtab, (kSTB_LOCAL << 4) + kSTT_FUNC);  // st_info + (st_other<<8)
-  WriteShort(symtab, kText);  // st_shndx
-#endif
-  WriteWord(symtab, pc);  // st_value
-  WriteWord(symtab, size);  // st_size
-#if defined(ARCH_IS_32_BIT)
-  // st_info + (st_other<<8)
-  WriteShort(symtab, (kSTB_EXPORTED << 4) + kSTT_FUNC);
-  WriteShort(symtab, kText);  // st_shndx
-#endif
-  ASSERT(symtab->size() - beg == kSymbolSize);
-  return beg / kSymbolSize;  // symbol index in symtab
-}
-
-
-bool ElfGen::WriteToFile(File* handle) {
-  return WriteOutput(handle, WriteSectionToFile, PadFile);
-}
-
-
-bool ElfGen::WriteToMemory(DebugInfo::ByteBuffer* region) {
-  return WriteOutput(region, WriteSectionToMemory, PadMemory);
-}
-
-
-int ElfGen::AddString(DebugInfo::ByteBuffer* buf, const char* str) {
-  const int str_index = buf->size();
-  WriteString(buf, str);
-  WriteByte(buf, 0);  // terminating '\0'
-  return str_index;
-}
-
-
-int ElfGen::AddSectionName(const char* str) {
-  return AddString(&section_buf_[kShStrtab], str);
-}
-
-
-int ElfGen::AddName(const char* str) {
-  return AddString(&section_buf_[kStrtab], str);
-}
-
-
-void ElfGen::AddELFHeader(int shoff) {
-  ASSERT(text_vma_ != 0);  // Code must have been added.
-  Write(&header_, kEI_MAG0_MAG3, 4);  // EI_MAG0..EI_MAG3
-#if defined(ARCH_IS_32_BIT)
-  WriteByte(&header_, kELFCLASS32);  // EI_CLASS
-#elif defined(ARCH_IS_64_BIT)
-  WriteByte(&header_, kELFCLASS64);  // EI_CLASS
-#else
-#error Unknown architecture.
-#endif
-  WriteByte(&header_, kELFDATA2LSB);  // EI_DATA
-  WriteByte(&header_, kEV_CURRENT);  // EI_VERSION
-  WriteByte(&header_, 0);  // EI_PAD
-  WriteInt(&header_, 0);  // EI_PAD
-  WriteInt(&header_, 0);  // EI_PAD
-  WriteShort(&header_, kET_DYN);  // e_type, fake a shared object.
-#if defined(TARGET_ARCH_IA32)
-  WriteShort(&header_, kEM_386);  // e_machine
-#elif defined(TARGET_ARCH_X64)
-  WriteShort(&header_, kEM_X86_64);  // e_machine
-#elif defined(TARGET_ARCH_ARM)
-  WriteShort(&header_, kEM_ARM);  // e_machine
-#elif defined(TARGET_ARCH_ARM64)
-  // TODO(zra): Find the right ARM64 constant.
-  WriteShort(&header_, kEM_ARM);  // e_machine
-#elif defined(TARGET_ARCH_MIPS)
-  WriteShort(&header_, kEM_MIPS);  // e_machine
-#else
-#error Unknown architecture.
-#endif
-  WriteInt(&header_, kEV_CURRENT);  // e_version
-  WriteWord(&header_, 0);  // e_entry: none
-  WriteWord(&header_, 0);  // e_phoff: no program header table.
-  WriteWord(&header_, shoff);  // e_shoff: section header table offset.
-  WriteInt(&header_, 0);  // e_flags: no flags.
-  WriteShort(&header_, kELFHeaderSize);  // e_ehsize: header size.
-  WriteShort(&header_, kProgramHeaderEntrySize);  // e_phentsize
-  WriteShort(&header_, 0);  // e_phnum: no entries program header table.
-  WriteShort(&header_, kSectionHeaderEntrySize);  // e_shentsize
-  // e_shnum: number of section header entries.
-  WriteShort(&header_, kNumSections);
-  WriteShort(&header_, kShStrtab);  // e_shstrndx: index of shstrtab.
-  ASSERT(header_.size() == kELFHeaderSize);
-}
-
-
-void ElfGen::AddSectionHeader(int section, int offset) {
-  WriteInt(&sheaders_, section_name_[section]);
-  WriteInt(&sheaders_, section_attr[section].sh_type);
-  WriteWord(&sheaders_, section_attr[section].sh_flags);
-  // sh_addr: abs addr
-  WriteWord(&sheaders_, (section == kText) ? text_vma_ : 0);
-  WriteWord(&sheaders_, offset);  // sh_offset: section file offset.
-  WriteWord(&sheaders_, section_buf_[section].size());
-  WriteInt(&sheaders_, section_attr[section].sh_link);
-  WriteInt(&sheaders_, 0);
-  WriteWord(&sheaders_, section_attr[section].sh_addralign);
-  WriteWord(&sheaders_, section_attr[section].sh_entsize);
-  ASSERT(sheaders_.size() == kSectionHeaderEntrySize * (section + 1));
-}
-
-
-// Pads the given section with zero bytes for the given aligment, assuming the
-// section starts at given file offset; returns file offset after padded
-// section.
-int ElfGen::PadSection(DebugInfo::ByteBuffer* section,
-                       int offset,
-                       int alignment) {
-  offset += section->size();
-  int aligned_offset = Align(offset, alignment);
-  while (offset++ < aligned_offset) {
-    WriteByte(section, 0);  // one byte padding.
-  }
-  return aligned_offset;
-}
-
-
-bool ElfGen::WriteOutput(void* handle,
-                         OutputWriter writer,
-                         OutputPadder padder) {
-  if (handle == NULL || writer == NULL || padder == NULL) {
-    return false;
-  }
-
-  // Align all sections before writing the ELF header in order to calculate the
-  // file offset of the section header table, which is needed in the ELF header.
-  // Pad each section as required by the aligment constraint of the immediately
-  // following section, except the ELF header section, which requires special
-  // padding (text_padding_) to align the text_ section.
-  int offset = kELFHeaderSize + text_padding_;
-  for (int i = kText; i < kNumSections; i++) {
-    offset = PadSection(&section_buf_[i],
-                        offset,
-                        section_attr[i+1].sh_addralign);
-  }
-
-  const int shoff = offset;  // Section header table offset.
-
-  // Write elf header.
-  AddELFHeader(shoff);
-  offset = (*writer)(handle, header_);
-
-  // Pad file before writing text section in order to align vma with file
-  // offset.
-  (*padder)(handle, text_padding_);
-
-  offset += text_padding_;
-  ASSERT((text_vma_ - offset) % kPageSize == 0);
-
-  // Section header at index 0 in section header table is always SHN_UNDEF:
-  for (int i = 0; i < kNumSections; i++) {
-    AddSectionHeader(i, offset);
-    offset += (*writer)(handle, section_buf_[i]);
-  }
-  // Write section header table.
-  ASSERT(offset == shoff);
-  offset += (*writer)(handle, sheaders_);
-  ASSERT(offset == shoff + kNumSections * kSectionHeaderEntrySize);
-
-  return true;
-}
-
-}  // namespace dart
-
-#endif  // VM_ELFGEN_H_
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 99563bb..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);
@@ -424,7 +433,7 @@
 
 // Allocate, initialize, and throw a TypeError or CastError.
 // If error_msg is not null, throw a TypeError, even for a type cast.
-void Exceptions::CreateAndThrowTypeError(intptr_t location,
+void Exceptions::CreateAndThrowTypeError(TokenPosition location,
                                          const String& src_type_name,
                                          const String& dst_type_name,
                                          const String& dst_name,
@@ -472,6 +481,7 @@
       OS::Print("type error.\n");
     }
   }
+
   // Throw TypeError or CastError instance.
   Exceptions::ThrowByType(exception_type, args);
   UNREACHABLE();
@@ -482,10 +492,12 @@
   // Do not notify debugger on stack overflow and out of memory exceptions.
   // The VM would crash when the debugger calls back into the VM to
   // get values of variables.
-  Isolate* isolate = thread->isolate();
-  if (exception.raw() != isolate->object_store()->out_of_memory() &&
-      exception.raw() != isolate->object_store()->stack_overflow()) {
-    isolate->debugger()->SignalExceptionThrown(exception);
+  if (FLAG_support_debugger) {
+    Isolate* isolate = thread->isolate();
+    if (exception.raw() != isolate->object_store()->out_of_memory() &&
+        exception.raw() != isolate->object_store()->stack_overflow()) {
+      isolate->debugger()->SignalExceptionThrown(exception);
+    }
   }
   // Null object is a valid exception object.
   ThrowExceptionHelper(thread, exception,
@@ -624,14 +636,6 @@
       library = Library::IsolateLibrary();
       class_name = &Symbols::IsolateSpawnException();
       break;
-    case kJavascriptIntegerOverflowError:
-      library = Library::CoreLibrary();
-      class_name = &Symbols::JavascriptIntegerOverflowError();
-      break;
-    case kJavascriptCompatibilityError:
-      library = Library::CoreLibrary();
-      class_name = &Symbols::JavascriptCompatibilityError();
-      break;
     case kAssertion:
       library = Library::CoreLibrary();
       class_name = &Symbols::AssertionError();
@@ -669,12 +673,4 @@
 }
 
 
-// Throw JavascriptCompatibilityError exception.
-void Exceptions::ThrowJavascriptCompatibilityError(const char* msg) {
-  const Array& exc_args = Array::Handle(Array::New(1));
-  const String& msg_str = String::Handle(String::New(msg));
-  exc_args.SetAt(0, msg_str);
-  Exceptions::ThrowByType(Exceptions::kJavascriptCompatibilityError, exc_args);
-}
-
 }  // namespace dart
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 4282bb5..86e3261 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -6,6 +6,7 @@
 #define VM_EXCEPTIONS_H_
 
 #include "vm/allocation.h"
+#include "vm/token_position.h"
 
 namespace dart {
 
@@ -42,7 +43,7 @@
   static RawStacktrace* CurrentStacktrace();
   static RawScript* GetCallerScript(DartFrameIterator* iterator);
   static RawInstance* NewInstance(const char* class_name);
-  static void CreateAndThrowTypeError(intptr_t location,
+  static void CreateAndThrowTypeError(TokenPosition location,
                                       const String& src_type_name,
                                       const String& dst_type_name,
                                       const String& dst_name,
@@ -60,8 +61,6 @@
     kOutOfMemory,
     kNullThrown,
     kIsolateSpawn,
-    kJavascriptIntegerOverflowError,
-    kJavascriptCompatibilityError,
     kAssertion,
     kCast,
     kType,
@@ -80,7 +79,6 @@
                               const Integer& argument_value,
                               intptr_t expected_from,
                               intptr_t expected_to);
-  static void ThrowJavascriptCompatibilityError(const char* msg);
 
   // Returns a RawInstance if the exception is successfully created,
   // otherwise returns a RawError.
diff --git a/runtime/vm/exceptions_test.cc b/runtime/vm/exceptions_test.cc
index 1901c58..355bc01 100644
--- a/runtime/vm/exceptions_test.cc
+++ b/runtime/vm/exceptions_test.cc
@@ -79,7 +79,7 @@
                                          int argument_count,
                                          bool* auto_setup_scope) {
   ASSERT(auto_setup_scope != NULL);
-  *auto_setup_scope = false;
+  *auto_setup_scope = true;
   const Object& obj = Object::Handle(Api::UnwrapHandle(name));
   ASSERT(obj.IsString());
   const char* function_name = obj.ToCString();
diff --git a/runtime/vm/find_code_object_test.cc b/runtime/vm/find_code_object_test.cc
index 96ff8d3..caece81 100644
--- a/runtime/vm/find_code_object_test.cc
+++ b/runtime/vm/find_code_object_test.cc
@@ -13,7 +13,7 @@
 
 namespace dart {
 
-TEST_CASE(FindCodeObject) {
+VM_TEST_CASE(FindCodeObject) {
 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
   const int kLoopCount = 50000;
 #else
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
new file mode 100644
index 0000000..35a7756
--- /dev/null
+++ b/runtime/vm/flag_list.h
@@ -0,0 +1,147 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_FLAG_LIST_H_
+#define VM_FLAG_LIST_H_
+
+// List of all flags in the VM.
+// Flags can be one of three categories:
+// * P roduct flags: Can be set in any of the deployment modes, including in
+//   production.
+// * D ebug flags: Can only be set in debug VMs, which also have assertions
+//   enabled.
+// * R elease flags: Generally available flags except when building product.
+// * pre C ompile flags: Generally available flags except when building product
+//   or precompiled runtime.
+//
+// Usage:
+//   P(name, type, default_value, comment)
+//   D(name, type, default_value, comment)
+//   R(name, product_value, type, default_value, comment)
+//   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,                                             \
+  "Disassemble dart code.")                                                    \
+R(disassemble_optimized, false, bool, false,                                   \
+  "Disassemble optimized code.")                                               \
+R(dump_symbol_stats, false, bool, false,                                       \
+  "Dump symbol table statistics")                                              \
+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,                                    \
+    "Maximum number of polymorphic checks in equality operator,")              \
+P(merge_sin_cos, bool, false,                                                  \
+  "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")                  \
+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,                                      \
+  "Support the AST printer.")                                                  \
+R(support_compiler_stats, false, bool, true,                                   \
+  "Support compiler stats.")                                                   \
+R(support_debugger, false, bool, true,                                         \
+  "Support the debugger.")                                                     \
+R(support_disassembler, false, bool, true,                                     \
+  "Support the disassembler.")                                                 \
+R(support_il_printer, false, bool, true,                                       \
+  "Support the IL printer.")                                                   \
+R(support_service, false, bool, true,                                          \
+  "Support the service protocol.")                                             \
+R(support_coverage, false, bool, true,                                         \
+  "Support code coverage.")                                                    \
+R(support_timeline, false, bool, true,                                         \
+  "Support timeline.")                                                         \
+D(trace_cha, bool, false,                                                      \
+  "Trace CHA operations")                                                      \
+D(trace_field_guards, bool, false,                                             \
+  "Trace changes in field's cids.")                                            \
+D(trace_handles, bool, false,                                                  \
+  "Traces allocation of handles.")                                             \
+D(trace_optimization, bool, false,                                             \
+  "Print optimization details.");                                              \
+D(trace_zones, bool, false,                                                    \
+  "Traces allocation sizes in the zone.")                                      \
+P(truncating_left_shift, bool, true,                                           \
+  "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,                                                     \
+  "Print verbose GC header interval.")                                         \
+R(verify_after_gc, false, bool, false,                                         \
+  "Enables heap verification after GC.")                                       \
+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 c1ec041..cb76c91 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -14,6 +14,73 @@
 DEFINE_FLAG(bool, ignore_unrecognized_flags, false,
     "Ignore unrecognized flags.");
 
+#define PRODUCT_FLAG_MARCO(name, type, default_value, comment) \
+  type FLAG_##name = Flags::Register_##type(&FLAG_##name,                      \
+                                            #name,                             \
+                                            default_value,                     \
+                                            comment);
+
+#if defined(DEBUG)
+#define DEBUG_FLAG_MARCO(name, type, default_value, comment) \
+  type FLAG_##name = Flags::Register_##type(&FLAG_##name,                      \
+                                            #name,                             \
+                                            default_value,                     \
+                                            comment);
+#else  // defined(DEBUG)
+#define DEBUG_FLAG_MARCO(name, type, default_value, comment)
+#endif  // defined(DEBUG)
+
+#if defined(PRODUCT) && defined(DART_PRECOMPILED_RUNTIME)
+// Nothing to be done for the product flag definitions.
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)
+// Nothing to be done for the precompilation flag definitions.
+#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type,            \
+                              default_value, comment)
+
+#elif defined(PRODUCT)  // !PRECOMPILED
+// Nothing to be done for the product flag definitions.
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)
+// Nothing to be done for the precompilation flag definitions.
+#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type,            \
+                              default_value, comment)
+
+#elif defined(DART_PRECOMPILED_RUNTIME)  // !PRODUCT
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  type FLAG_##name = Flags::Register_##type(&FLAG_##name,                      \
+                                            #name,                             \
+                                            default_value,                     \
+                                            comment);
+// Nothing to be done for the precompilation flag definitions.
+#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type,            \
+                              default_value, comment)
+
+#else  // !PRODUCT && !PRECOMPILED
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  type FLAG_##name = Flags::Register_##type(&FLAG_##name,                      \
+                                            #name,                             \
+                                            default_value,                     \
+                                            comment);
+#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type,            \
+                              default_value, comment)                          \
+  type FLAG_##name = Flags::Register_##type(&FLAG_##name,                      \
+                                            #name,                             \
+                                            default_value,                     \
+                                            comment);
+#endif
+
+
+// Define all of the non-product flags here.
+FLAG_LIST(PRODUCT_FLAG_MARCO,
+          RELEASE_FLAG_MARCO,
+          DEBUG_FLAG_MARCO,
+          PRECOMPILE_FLAG_MARCO)
+
+#undef RELEASE_FLAG_MARCO
+#undef DEBUG_FLAG_MARCO
+#undef PRODUCT_FLAG_MARCO
+#undef PRECOMPILE_FLAG_MARCO
+
+
 bool Flags::initialized_ = false;
 
 // List of registered flags.
@@ -421,6 +488,9 @@
 
 
 void Flags::PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag) {
+  if (!FLAG_support_service) {
+    return;
+  }
   if (flag->IsUnrecognized() || flag->type_ == Flag::kFunc) {
     return;
   }
@@ -462,6 +532,9 @@
 
 
 void Flags::PrintJSON(JSONStream* js) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "FlagList");
   JSONArray jsarr(&jsobj, "flags");
diff --git a/runtime/vm/flags.h b/runtime/vm/flags.h
index f703c10..81f594e 100644
--- a/runtime/vm/flags.h
+++ b/runtime/vm/flags.h
@@ -6,6 +6,7 @@
 #define VM_FLAGS_H_
 
 #include "platform/assert.h"
+#include "vm/flag_list.h"
 #include "vm/globals.h"
 
 typedef const char* charp;
@@ -17,21 +18,12 @@
   type FLAG_##name = Flags::Register_##type(&FLAG_##name,                      \
                                             #name,                             \
                                             default_value,                     \
-                                            comment)
+                                            comment);
 
 #define DEFINE_FLAG_HANDLER(handler, name, comment)                            \
-  bool DUMMY_##name = Flags::Register_func(handler, #name, comment)
+  bool DUMMY_##name = Flags::Register_func(handler, #name, comment);
 
 
-#if defined(DEBUG)
-#define DECLARE_DEBUG_FLAG(type, name) DECLARE_FLAG(type, name)
-#define DEFINE_DEBUG_FLAG(type, name, default_value, comment)                  \
-  DEFINE_FLAG(type, name, default_value, comment)
-#else
-#define DECLARE_DEBUG_FLAG(type, name)
-#define DEFINE_DEBUG_FLAG(type, name, default_value, comment)
-#endif
-
 namespace dart {
 
 typedef void (*FlagHandler)(bool value);
@@ -107,6 +99,58 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Flags);
 };
 
+#define PRODUCT_FLAG_MARCO(name, type, default_value, comment) \
+  extern type FLAG_##name;
+
+#if defined(DEBUG)
+#define DEBUG_FLAG_MARCO(name, type, default_value, comment)                   \
+  extern type FLAG_##name;
+#else  // defined(DEBUG)
+#define DEBUG_FLAG_MARCO(name, type, default_value, comment)                   \
+  const type FLAG_##name = default_value;
+#endif  // defined(DEBUG)
+
+#if defined(PRODUCT) && defined(DART_PRECOMPILED_RUNTIME)
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  const type FLAG_##name = product_value;
+#define PRECOMPILE_FLAG_MARCO(name, precompiled_value, product_value, type,    \
+                              default_value, comment)                          \
+  const type FLAG_##name = precompiled_value;
+
+#elif defined(PRODUCT)  // !PRECOMPILED
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  const type FLAG_##name = product_value;
+#define PRECOMPILE_FLAG_MARCO(name, precompiled_value, product_value, type,    \
+                              default_value, comment)                          \
+  const type FLAG_##name = product_value;
+
+#elif defined(DART_PRECOMPILED_RUNTIME)  // !PRODUCT
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  extern type FLAG_##name;
+#define PRECOMPILE_FLAG_MARCO(name, precompiled_value, product_value, type,    \
+                              default_value, comment)                          \
+  const type FLAG_##name = precompiled_value;
+
+#else  // !PRODUCT && !PRECOMPILED
+#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+  extern type FLAG_##name;
+#define PRECOMPILE_FLAG_MARCO(name, precompiled_value, product_value, type,    \
+                              default_value, comment)                          \
+  extern type FLAG_##name;
+
+#endif
+
+// Now declare all flags here.
+FLAG_LIST(PRODUCT_FLAG_MARCO,
+          RELEASE_FLAG_MARCO,
+          DEBUG_FLAG_MARCO,
+          PRECOMPILE_FLAG_MARCO)
+
+#undef RELEASE_FLAG_MARCO
+#undef DEBUG_FLAG_MARCO
+#undef PRODUCT_FLAG_MARCO
+#undef PRECOMPILE_FLAG_MARCO
+
 }  // namespace dart
 
 #endif  // VM_FLAGS_H_
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 4097af5..3296e09 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -6,18 +6,20 @@
 
 #include "vm/bit_vector.h"
 #include "vm/flow_graph_builder.h"
+#include "vm/flow_graph_compiler.h"
+#include "vm/flow_graph_range_analysis.h"
 #include "vm/il_printer.h"
 #include "vm/intermediate_language.h"
 #include "vm/growable_array.h"
 #include "vm/object_store.h"
-#include "vm/report.h"
 
 namespace dart {
 
+#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32)
+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, trace_optimization);
 DECLARE_FLAG(bool, verify_compiler);
 
 
@@ -43,8 +45,6 @@
     licm_allowed_(true),
     loop_headers_(NULL),
     loop_invariant_loads_(NULL),
-    guarded_fields_(parsed_function.guarded_fields()),
-    deoptimize_dependent_code_(),
     deferred_prefixes_(parsed_function.deferred_prefixes()),
     captured_parameters_(new(zone()) BitVector(zone(), variable_count())),
     inlining_id_(-1) {
@@ -52,19 +52,39 @@
 }
 
 
-void FlowGraph::AddToGuardedFields(
-    ZoneGrowableArray<const Field*>* array,
-    const Field* field) {
-  if ((field->guarded_cid() == kDynamicCid) ||
-      (field->guarded_cid() == kIllegalCid)) {
-    return;
+void FlowGraph::EnsureSSATempIndex(Definition* defn,
+                                   Definition* replacement) {
+  if ((replacement->ssa_temp_index() == -1) &&
+      (defn->ssa_temp_index() != -1)) {
+    AllocateSSAIndexes(replacement);
   }
-  for (intptr_t j = 0; j < array->length(); j++) {
-    if ((*array)[j]->raw() == field->raw()) {
-      return;
+}
+
+
+void FlowGraph::ReplaceCurrentInstruction(ForwardInstructionIterator* iterator,
+                                          Instruction* current,
+                                          Instruction* replacement) {
+  Definition* current_defn = current->AsDefinition();
+  if ((replacement != NULL) && (current_defn != NULL)) {
+    Definition* replacement_defn = replacement->AsDefinition();
+    ASSERT(replacement_defn != NULL);
+    current_defn->ReplaceUsesWith(replacement_defn);
+    EnsureSSATempIndex(current_defn, replacement_defn);
+
+    if (FLAG_trace_optimization) {
+      THR_Print("Replacing v%" Pd " with v%" Pd "\n",
+                current_defn->ssa_temp_index(),
+                replacement_defn->ssa_temp_index());
+    }
+  } else if (FLAG_trace_optimization) {
+    if (current_defn == NULL) {
+      THR_Print("Removing %s\n", current->DebugName());
+    } else {
+      ASSERT(!current_defn->HasUses());
+      THR_Print("Removing v%" Pd ".\n", current_defn->ssa_temp_index());
     }
   }
-  array->Add(field);
+  iterator->RemoveCurrentFromGraph();
 }
 
 
@@ -1397,4 +1417,566 @@
       from->postorder_number());
 }
 
+
+// Quick access to the current zone.
+#define Z (zone())
+
+
+void FlowGraph::ConvertUse(Value* use, Representation from_rep) {
+  const Representation to_rep =
+      use->instruction()->RequiredInputRepresentation(use->use_index());
+  if (from_rep == to_rep || to_rep == kNoRepresentation) {
+    return;
+  }
+  InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/ false);
+}
+
+
+static bool IsUnboxedInteger(Representation rep) {
+  return (rep == kUnboxedInt32) ||
+         (rep == kUnboxedUint32) ||
+         (rep == kUnboxedMint);
+}
+
+
+static bool ShouldInlineSimd() {
+  return FlowGraphCompiler::SupportsUnboxedSimd128();
+}
+
+
+static bool CanUnboxDouble() {
+  return FlowGraphCompiler::SupportsUnboxedDoubles();
+}
+
+
+static bool CanConvertUnboxedMintToDouble() {
+  return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
+}
+
+
+void FlowGraph::InsertConversion(Representation from,
+                                 Representation to,
+                                 Value* use,
+                                 bool is_environment_use) {
+  Instruction* insert_before;
+  Instruction* deopt_target;
+  PhiInstr* phi = use->instruction()->AsPhi();
+  if (phi != NULL) {
+    ASSERT(phi->is_alive());
+    // For phis conversions have to be inserted in the predecessor.
+    insert_before =
+        phi->block()->PredecessorAt(use->use_index())->last_instruction();
+    deopt_target = NULL;
+  } else {
+    deopt_target = insert_before = use->instruction();
+  }
+
+  Definition* converted = NULL;
+  if (IsUnboxedInteger(from) && IsUnboxedInteger(to)) {
+    const intptr_t deopt_id = (to == kUnboxedInt32) && (deopt_target != NULL) ?
+      deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
+    converted = new(Z) UnboxedIntConverterInstr(from,
+                                                to,
+                                                use->CopyWithType(),
+                                                deopt_id);
+  } else if ((from == kUnboxedInt32) && (to == kUnboxedDouble)) {
+    converted = new Int32ToDoubleInstr(use->CopyWithType());
+  } else if ((from == kUnboxedMint) &&
+             (to == kUnboxedDouble) &&
+             CanConvertUnboxedMintToDouble()) {
+    const intptr_t deopt_id = (deopt_target != NULL) ?
+        deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
+    ASSERT(CanUnboxDouble());
+    converted = new MintToDoubleInstr(use->CopyWithType(), deopt_id);
+  } else if ((from == kTagged) && Boxing::Supports(to)) {
+    const intptr_t deopt_id = (deopt_target != NULL) ?
+        deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
+    converted = UnboxInstr::Create(to, use->CopyWithType(), deopt_id);
+  } else if ((to == kTagged) && Boxing::Supports(from)) {
+    converted = BoxInstr::Create(from, use->CopyWithType());
+  } else {
+    // We have failed to find a suitable conversion instruction.
+    // Insert two "dummy" conversion instructions with the correct
+    // "from" and "to" representation. The inserted instructions will
+    // trigger a deoptimization if executed. See #12417 for a discussion.
+    const intptr_t deopt_id = (deopt_target != NULL) ?
+        deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
+    ASSERT(Boxing::Supports(from));
+    ASSERT(Boxing::Supports(to));
+    Definition* boxed = BoxInstr::Create(from, use->CopyWithType());
+    use->BindTo(boxed);
+    InsertBefore(insert_before, boxed, NULL, FlowGraph::kValue);
+    converted = UnboxInstr::Create(to, new(Z) Value(boxed), deopt_id);
+  }
+  ASSERT(converted != NULL);
+  InsertBefore(insert_before, converted, use->instruction()->env(),
+               FlowGraph::kValue);
+  if (is_environment_use) {
+    use->BindToEnvironment(converted);
+  } else {
+    use->BindTo(converted);
+  }
+
+  if ((to == kUnboxedInt32) && (phi != NULL)) {
+    // Int32 phis are unboxed optimistically. Ensure that unboxing
+    // has deoptimization target attached from the goto instruction.
+    CopyDeoptTarget(converted, insert_before);
+  }
+}
+
+
+void FlowGraph::ConvertEnvironmentUse(Value* use, Representation from_rep) {
+  const Representation to_rep = kTagged;
+  if (from_rep == to_rep) {
+    return;
+  }
+  InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/ true);
+}
+
+
+void FlowGraph::InsertConversionsFor(Definition* def) {
+  const Representation from_rep = def->representation();
+
+  for (Value::Iterator it(def->input_use_list());
+       !it.Done();
+       it.Advance()) {
+    ConvertUse(it.Current(), from_rep);
+  }
+
+  if (graph_entry()->SuccessorCount() > 1) {
+    for (Value::Iterator it(def->env_use_list());
+         !it.Done();
+         it.Advance()) {
+      Value* use = it.Current();
+      if (use->instruction()->MayThrow() &&
+          use->instruction()->GetBlock()->InsideTryBlock()) {
+        // Environment uses at calls inside try-blocks must be converted to
+        // tagged representation.
+        ConvertEnvironmentUse(it.Current(), from_rep);
+      }
+    }
+  }
+}
+
+
+static void UnboxPhi(PhiInstr* phi) {
+  Representation unboxed = phi->representation();
+
+  switch (phi->Type()->ToCid()) {
+    case kDoubleCid:
+      if (CanUnboxDouble()) {
+        unboxed = kUnboxedDouble;
+      }
+      break;
+    case kFloat32x4Cid:
+      if (ShouldInlineSimd()) {
+        unboxed = kUnboxedFloat32x4;
+      }
+      break;
+    case kInt32x4Cid:
+      if (ShouldInlineSimd()) {
+        unboxed = kUnboxedInt32x4;
+      }
+      break;
+    case kFloat64x2Cid:
+      if (ShouldInlineSimd()) {
+        unboxed = kUnboxedFloat64x2;
+      }
+      break;
+  }
+
+  if ((kSmiBits < 32) &&
+      (unboxed == kTagged) &&
+      phi->Type()->IsInt() &&
+      RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt64)) {
+    // On 32-bit platforms conservatively unbox phis that:
+    //   - are proven to be of type Int;
+    //   - fit into 64bits range;
+    //   - have either constants or Box() operations as inputs;
+    //   - have at least one Box() operation as an input;
+    //   - are used in at least 1 Unbox() operation.
+    bool should_unbox = false;
+    for (intptr_t i = 0; i < phi->InputCount(); i++) {
+      Definition* input = phi->InputAt(i)->definition();
+      if (input->IsBox() &&
+          RangeUtils::Fits(input->range(),
+                           RangeBoundary::kRangeBoundaryInt64)) {
+        should_unbox = true;
+      } else if (!input->IsConstant()) {
+        should_unbox = false;
+        break;
+      }
+    }
+
+    if (should_unbox) {
+      // We checked inputs. Check if phi is used in at least one unbox
+      // operation.
+      bool has_unboxed_use = false;
+      for (Value* use = phi->input_use_list();
+           use != NULL;
+           use = use->next_use()) {
+        Instruction* instr = use->instruction();
+        if (instr->IsUnbox()) {
+          has_unboxed_use = true;
+          break;
+        } else if (IsUnboxedInteger(
+            instr->RequiredInputRepresentation(use->use_index()))) {
+          has_unboxed_use = true;
+          break;
+        }
+      }
+
+      if (!has_unboxed_use) {
+        should_unbox = false;
+      }
+    }
+
+    if (should_unbox) {
+      unboxed =
+          RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)
+          ? kUnboxedInt32 : kUnboxedMint;
+    }
+  }
+
+  phi->set_representation(unboxed);
+}
+
+
+void FlowGraph::SelectRepresentations() {
+  // Conservatively unbox all phis that were proven to be of Double,
+  // Float32x4, or Int32x4 type.
+  for (BlockIterator block_it = reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    JoinEntryInstr* join_entry = block_it.Current()->AsJoinEntry();
+    if (join_entry != NULL) {
+      for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
+        PhiInstr* phi = it.Current();
+        UnboxPhi(phi);
+      }
+    }
+  }
+
+  // Process all instructions and insert conversions where needed.
+  // Visit incoming parameters and constants.
+  for (intptr_t i = 0;
+       i < graph_entry()->initial_definitions()->length();
+       i++) {
+    InsertConversionsFor((*graph_entry()->initial_definitions())[i]);
+  }
+
+  for (BlockIterator block_it = reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    BlockEntryInstr* entry = block_it.Current();
+    JoinEntryInstr* join_entry = entry->AsJoinEntry();
+    if (join_entry != NULL) {
+      for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
+        PhiInstr* phi = it.Current();
+        ASSERT(phi != NULL);
+        ASSERT(phi->is_alive());
+        InsertConversionsFor(phi);
+      }
+    }
+    CatchBlockEntryInstr* catch_entry = entry->AsCatchBlockEntry();
+    if (catch_entry != NULL) {
+      for (intptr_t i = 0;
+           i < catch_entry->initial_definitions()->length();
+           i++) {
+        InsertConversionsFor((*catch_entry->initial_definitions())[i]);
+      }
+    }
+    for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
+      Definition* def = it.Current()->AsDefinition();
+      if (def != NULL) {
+        InsertConversionsFor(def);
+      }
+    }
+  }
+}
+
+
+#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32)
+// Smi widening pass is only meaningful on platforms where Smi
+// is smaller than 32bit. For now only support it on ARM and ia32.
+static bool CanBeWidened(BinarySmiOpInstr* smi_op) {
+  return BinaryInt32OpInstr::IsSupported(smi_op->op_kind(),
+                                         smi_op->left(),
+                                         smi_op->right());
+}
+
+
+static bool BenefitsFromWidening(BinarySmiOpInstr* smi_op) {
+  // TODO(vegorov): when shifts with non-constants shift count are supported
+  // add them here as we save untagging for the count.
+  switch (smi_op->op_kind()) {
+    case Token::kMUL:
+    case Token::kSHR:
+      // For kMUL we save untagging of the argument for kSHR
+      // we save tagging of the result.
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+
+void FlowGraph::WidenSmiToInt32() {
+  GrowableArray<BinarySmiOpInstr*> candidates;
+
+  // Step 1. Collect all instructions that potentially benefit from widening of
+  // their operands (or their result) into int32 range.
+  for (BlockIterator block_it = reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    for (ForwardInstructionIterator instr_it(block_it.Current());
+         !instr_it.Done();
+         instr_it.Advance()) {
+      BinarySmiOpInstr* smi_op = instr_it.Current()->AsBinarySmiOp();
+      if ((smi_op != NULL) &&
+          smi_op->HasSSATemp() &&
+          BenefitsFromWidening(smi_op) &&
+          CanBeWidened(smi_op)) {
+        candidates.Add(smi_op);
+      }
+    }
+  }
+
+  if (candidates.is_empty()) {
+    return;
+  }
+
+  // Step 2. For each block in the graph compute which loop it belongs to.
+  // We will use this information later during computation of the widening's
+  // gain: we are going to assume that only conversion occuring inside the
+  // same loop should be counted against the gain, all other conversions
+  // can be hoisted and thus cost nothing compared to the loop cost itself.
+  const ZoneGrowableArray<BlockEntryInstr*>& loop_headers = LoopHeaders();
+
+  GrowableArray<intptr_t> loops(preorder().length());
+  for (intptr_t i = 0; i < preorder().length(); i++) {
+    loops.Add(-1);
+  }
+
+  for (intptr_t loop_id = 0; loop_id < loop_headers.length(); ++loop_id) {
+    for (BitVector::Iterator loop_it(loop_headers[loop_id]->loop_info());
+         !loop_it.Done();
+         loop_it.Advance()) {
+      loops[loop_it.Current()] = loop_id;
+    }
+  }
+
+  // Step 3. For each candidate transitively collect all other BinarySmiOpInstr
+  // and PhiInstr that depend on it and that it depends on and count amount of
+  // untagging operations that we save in assumption that this whole graph of
+  // values is using kUnboxedInt32 representation instead of kTagged.
+  // Convert those graphs that have positive gain to kUnboxedInt32.
+
+  // BitVector containing SSA indexes of all processed definitions. Used to skip
+  // those candidates that belong to dependency graph of another candidate.
+  BitVector* processed =
+      new(Z) BitVector(Z, current_ssa_temp_index());
+
+  // Worklist used to collect dependency graph.
+  DefinitionWorklist worklist(this, candidates.length());
+  for (intptr_t i = 0; i < candidates.length(); i++) {
+    BinarySmiOpInstr* op = candidates[i];
+    if (op->WasEliminated() || processed->Contains(op->ssa_temp_index())) {
+      continue;
+    }
+
+    if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+      THR_Print("analysing candidate: %s\n", op->ToCString());
+    }
+    worklist.Clear();
+    worklist.Add(op);
+
+    // Collect dependency graph. Note: more items are added to worklist
+    // inside this loop.
+    intptr_t gain = 0;
+    for (intptr_t j = 0; j < worklist.definitions().length(); j++) {
+      Definition* defn = worklist.definitions()[j];
+
+      if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+        THR_Print("> %s\n", defn->ToCString());
+      }
+
+      if (defn->IsBinarySmiOp() &&
+          BenefitsFromWidening(defn->AsBinarySmiOp())) {
+        gain++;
+        if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+          THR_Print("^ [%" Pd "] (o) %s\n", gain, defn->ToCString());
+        }
+      }
+
+      const intptr_t defn_loop = loops[defn->GetBlock()->preorder_number()];
+
+      // Process all inputs.
+      for (intptr_t k = 0; k < defn->InputCount(); k++) {
+        Definition* input = defn->InputAt(k)->definition();
+        if (input->IsBinarySmiOp() &&
+            CanBeWidened(input->AsBinarySmiOp())) {
+          worklist.Add(input);
+        } else if (input->IsPhi() && (input->Type()->ToCid() == kSmiCid)) {
+          worklist.Add(input);
+        } else if (input->IsBinaryMintOp()) {
+          // Mint operation produces untagged result. We avoid tagging.
+          gain++;
+          if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+            THR_Print("^ [%" Pd "] (i) %s\n", gain, input->ToCString());
+          }
+        } else if (defn_loop == loops[input->GetBlock()->preorder_number()] &&
+                   (input->Type()->ToCid() == kSmiCid)) {
+          // Input comes from the same loop, is known to be smi and requires
+          // untagging.
+          // TODO(vegorov) this heuristic assumes that values that are not
+          // known to be smi have to be checked and this check can be
+          // coalesced with untagging. Start coalescing them.
+          gain--;
+          if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+            THR_Print("v [%" Pd "] (i) %s\n", gain, input->ToCString());
+          }
+        }
+      }
+
+      // Process all uses.
+      for (Value* use = defn->input_use_list();
+           use != NULL;
+           use = use->next_use()) {
+        Instruction* instr = use->instruction();
+        Definition* use_defn = instr->AsDefinition();
+        if (use_defn == NULL) {
+          // We assume that tagging before returning or pushing argument costs
+          // very little compared to the cost of the return/call itself.
+          if (!instr->IsReturn() && !instr->IsPushArgument()) {
+            gain--;
+            if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+              THR_Print("v [%" Pd "] (u) %s\n",
+                        gain,
+                        use->instruction()->ToCString());
+            }
+          }
+          continue;
+        } else if (use_defn->IsBinarySmiOp() &&
+                   CanBeWidened(use_defn->AsBinarySmiOp())) {
+          worklist.Add(use_defn);
+        } else if (use_defn->IsPhi() &&
+                   use_defn->AsPhi()->Type()->ToCid() == kSmiCid) {
+          worklist.Add(use_defn);
+        } else if (use_defn->IsBinaryMintOp()) {
+          // BinaryMintOp requires untagging of its inputs.
+          // Converting kUnboxedInt32 to kUnboxedMint is essentially zero cost
+          // sign extension operation.
+          gain++;
+          if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+            THR_Print("^ [%" Pd "] (u) %s\n",
+                      gain,
+                      use->instruction()->ToCString());
+          }
+        } else if (defn_loop == loops[instr->GetBlock()->preorder_number()]) {
+          gain--;
+          if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+            THR_Print("v [%" Pd "] (u) %s\n",
+                      gain,
+                      use->instruction()->ToCString());
+          }
+        }
+      }
+    }
+
+    processed->AddAll(worklist.contains_vector());
+
+    if (FLAG_support_il_printer && FLAG_trace_smi_widening) {
+      THR_Print("~ %s gain %" Pd "\n", op->ToCString(), gain);
+    }
+
+    if (gain > 0) {
+      // We have positive gain from widening. Convert all BinarySmiOpInstr into
+      // BinaryInt32OpInstr and set representation of all phis to kUnboxedInt32.
+      for (intptr_t j = 0; j < worklist.definitions().length(); j++) {
+        Definition* defn = worklist.definitions()[j];
+        ASSERT(defn->IsPhi() || defn->IsBinarySmiOp());
+
+        if (defn->IsBinarySmiOp()) {
+          BinarySmiOpInstr* smi_op = defn->AsBinarySmiOp();
+          BinaryInt32OpInstr* int32_op = new(Z) BinaryInt32OpInstr(
+            smi_op->op_kind(),
+            smi_op->left()->CopyWithType(),
+            smi_op->right()->CopyWithType(),
+            smi_op->DeoptimizationTarget());
+
+          smi_op->ReplaceWith(int32_op, NULL);
+        } else if (defn->IsPhi()) {
+          defn->AsPhi()->set_representation(kUnboxedInt32);
+          ASSERT(defn->Type()->IsInt());
+        }
+      }
+    }
+  }
+}
+#else
+void FlowGraph::WidenSmiToInt32() {
+  // TODO(vegorov) ideally on 64-bit platforms we would like to narrow smi
+  // operations to 32-bit where it saves tagging and untagging and allows
+  // to use shorted (and faster) instructions. But we currently don't
+  // save enough range information in the ICData to drive this decision.
+}
+#endif
+
+
+void FlowGraph::EliminateEnvironments() {
+  // After this pass we can no longer perform LICM and hoist instructions
+  // that can deoptimize.
+
+  disallow_licm();
+  for (BlockIterator block_it = reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    BlockEntryInstr* block = block_it.Current();
+    block->RemoveEnvironment();
+    for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+      Instruction* current = it.Current();
+      if (!current->CanDeoptimize()) {
+        // TODO(srdjan): --source-lines needs deopt environments to get at
+        // the code for this instruction, however, leaving the environment
+        // changes code.
+        current->RemoveEnvironment();
+      }
+    }
+  }
+}
+
+
+bool FlowGraph::Canonicalize() {
+  bool changed = false;
+
+  for (BlockIterator block_it = reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    for (ForwardInstructionIterator it(block_it.Current());
+         !it.Done();
+         it.Advance()) {
+      Instruction* current = it.Current();
+      if (current->HasUnmatchedInputRepresentations()) {
+        // Can't canonicalize this instruction until all conversions for its
+        // inputs are inserted.
+        continue;
+      }
+
+      Instruction* replacement = current->Canonicalize(this);
+
+      if (replacement != current) {
+        // For non-definitions Canonicalize should return either NULL or
+        // this.
+        ASSERT((replacement == NULL) || current->IsDefinition());
+        ReplaceCurrentInstruction(&it, current, replacement);
+        changed = true;
+      }
+    }
+  }
+  return changed;
+}
+
+
 }  // namespace dart
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index cf62e82..d4d9d2f 100644
--- a/runtime/vm/flow_graph.h
+++ b/runtime/vm/flow_graph.h
@@ -144,6 +144,12 @@
     return BlockIterator(postorder());
   }
 
+  void EnsureSSATempIndex(Definition* defn, Definition* replacement);
+
+  void ReplaceCurrentInstruction(ForwardInstructionIterator* iterator,
+                                 Instruction* current,
+                                 Instruction* replacement);
+
   intptr_t current_ssa_temp_index() const { return current_ssa_temp_index_; }
   void set_current_ssa_temp_index(intptr_t index) {
     current_ssa_temp_index_ = index;
@@ -271,18 +277,8 @@
 
   bool IsCompiledForOsr() const { return graph_entry()->IsCompiledForOsr(); }
 
-  static void AddToGuardedFields(ZoneGrowableArray<const Field*>* array,
-                                 const Field* field);
   void AddToDeferredPrefixes(ZoneGrowableArray<const LibraryPrefix*>* from);
 
-  ZoneGrowableArray<const Field*>* guarded_fields() const {
-    return guarded_fields_;
-  }
-
-  GrowableArray<const Field*>& deoptimize_dependent_code() {
-    return deoptimize_dependent_code_;
-  }
-
   ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
     return deferred_prefixes_;
   }
@@ -294,6 +290,16 @@
   intptr_t inlining_id() const { return inlining_id_; }
   void set_inlining_id(intptr_t value) { inlining_id_ = value; }
 
+  // Returns true if any instructions were canonicalized away.
+  bool Canonicalize();
+
+  void SelectRepresentations();
+
+  void WidenSmiToInt32();
+
+  // Remove environments from the instructions which do not deoptimize.
+  void EliminateEnvironments();
+
  private:
   friend class IfConverter;
   friend class BranchSimplifier;
@@ -338,6 +344,14 @@
   // indicates membership in the loop.
   BitVector* FindLoop(BlockEntryInstr* m, BlockEntryInstr* n) const;
 
+  void InsertConversionsFor(Definition* def);
+  void ConvertUse(Value* use, Representation from);
+  void ConvertEnvironmentUse(Value* use, Representation from);
+  void InsertConversion(Representation from,
+                        Representation to,
+                        Value* use,
+                        bool is_environment_use);
+
   Thread* thread_;
 
   // DiscoverBlocks computes parent_ and assigned_vars_ which are then used
@@ -366,8 +380,6 @@
 
   ZoneGrowableArray<BlockEntryInstr*>* loop_headers_;
   ZoneGrowableArray<BitVector*>* loop_invariant_loads_;
-  ZoneGrowableArray<const Field*>* guarded_fields_;
-  GrowableArray<const Field*> deoptimize_dependent_code_;
   ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes_;
   DirectChainedHashMap<ConstantPoolTrait> constant_instr_pool_;
   BitVector* captured_parameters_;
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index e832212..b9bb33c 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -2969,8 +2969,12 @@
 
     THR_Print("-- [before ssa allocator] ir [%s] -------------\n",
               function.ToFullyQualifiedCString());
-    FlowGraphPrinter printer(flow_graph_, true);
-    printer.PrintBlocks();
+    if (FLAG_support_il_printer) {
+#ifndef PRODUCT
+      FlowGraphPrinter printer(flow_graph_, true);
+      printer.PrintBlocks();
+#endif
+    }
     THR_Print("----------------------------------------------\n");
   }
 
@@ -3010,8 +3014,12 @@
 
     THR_Print("-- [after ssa allocator] ir [%s] -------------\n",
               function.ToFullyQualifiedCString());
-    FlowGraphPrinter printer(flow_graph_, true);
-    printer.PrintBlocks();
+    if (FLAG_support_il_printer) {
+#ifndef PRODUCT
+      FlowGraphPrinter printer(flow_graph_, true);
+      printer.PrintBlocks();
+#endif
+    }
     THR_Print("----------------------------------------------\n");
   }
 }
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index fed89bb..c5460be 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -36,18 +36,17 @@
             "Eliminate type checks when allowed by static type analysis.");
 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree.");
 DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables.");
-DEFINE_FLAG(bool, support_debugger, true, "Emit code needed for debugging");
 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, warn_on_javascript_compatibility);
-DECLARE_FLAG(bool, use_field_guards);
 
 // Quick access to the locally defined zone() method.
 #define Z (zone())
 
+// Quick synthetic token position.
+#define ST(token_pos) ((token_pos).ToSynthetic())
+
 // TODO(srdjan): Allow compiler to add constants as they are encountered in
 // the compilation.
 const double kCommonDoubleConstants[] =
@@ -172,7 +171,7 @@
   if (break_target_ == NULL) {
     break_target_ =
         new(owner()->zone()) JoinEntryInstr(owner()->AllocateBlockId(),
-                                            owner()->try_index());
+                                            try_index());
   }
   return break_target_;
 }
@@ -248,7 +247,7 @@
   if (continue_target_ == NULL) {
     continue_target_ =
         new(owner()->zone()) JoinEntryInstr(owner()->AllocateBlockId(),
-                                               try_index());
+                                            try_index());
   }
   return continue_target_;
 }
@@ -292,7 +291,7 @@
     if (case_targets_[i] == NULL) {
       case_targets_[i] =
           new(owner()->zone()) JoinEntryInstr(owner()->AllocateBlockId(),
-                                                 try_index());
+                                              try_index());
     }
     return case_targets_[i];
   }
@@ -557,7 +556,7 @@
     ConstantInstr* true_const = caller_graph_->GetConstant(Bool::True());
     BranchInstr* branch =
         new(Z) BranchInstr(
-            new(Z) StrictCompareInstr(call_block->start_pos(),
+            new(Z) StrictCompareInstr(TokenPosition::kNoSource,
                                       Token::kEQ_STRICT,
                                       new(Z) Value(true_const),
                                       new(Z) Value(true_const),
@@ -704,7 +703,8 @@
 }
 
 
-void EffectGraphVisitor::AddReturnExit(intptr_t token_pos, Value* value) {
+void EffectGraphVisitor::AddReturnExit(TokenPosition token_pos,
+                                       Value* value) {
   ASSERT(is_open());
   ReturnInstr* return_instr = new(Z) ReturnInstr(token_pos, value);
   AddInstruction(return_instr);
@@ -778,7 +778,7 @@
 
 
 void EffectGraphVisitor::TieLoop(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const TestGraphVisitor& test_fragment,
     const EffectGraphVisitor& body_fragment,
     const EffectGraphVisitor& test_preamble_fragment) {
@@ -829,28 +829,34 @@
 
 
 Definition* EffectGraphVisitor::BuildStoreTemp(const LocalVariable& local,
-                                               Value* value) {
+                                               Value* value,
+                                               TokenPosition token_pos) {
   ASSERT(!local.is_captured());
-  return new(Z) StoreLocalInstr(local, value);
+  ASSERT(!token_pos.IsClassifying());
+  return new(Z) StoreLocalInstr(local, value, ST(token_pos));
 }
 
 
-Definition* EffectGraphVisitor::BuildStoreExprTemp(Value* value) {
+Definition* EffectGraphVisitor::BuildStoreExprTemp(Value* value,
+                                                   TokenPosition token_pos) {
   return BuildStoreTemp(*owner()->parsed_function().expression_temp_var(),
-                        value);
+                        value,
+                        token_pos);
 }
 
 
-Definition* EffectGraphVisitor::BuildLoadExprTemp() {
-  return BuildLoadLocal(*owner()->parsed_function().expression_temp_var());
+Definition* EffectGraphVisitor::BuildLoadExprTemp(TokenPosition token_pos) {
+  ASSERT(!token_pos.IsClassifying());
+  return BuildLoadLocal(*owner()->parsed_function().expression_temp_var(),
+                        token_pos);
 }
 
 
 Definition* EffectGraphVisitor::BuildStoreLocal(const LocalVariable& local,
                                                 Value* value,
-                                                intptr_t token_pos) {
+                                                TokenPosition token_pos) {
   if (local.is_captured()) {
-    LocalVariable* tmp_var = EnterTempLocalScope(value);
+    LocalVariable* tmp_var = EnterTempLocalScope(value, token_pos);
     intptr_t delta =
         owner()->context_level() - local.owner()->context_level();
     ASSERT(delta >= 0);
@@ -860,7 +866,7 @@
           context, Context::parent_offset(), Type::ZoneHandle(Z, Type::null()),
           token_pos));
     }
-    Value* tmp_val = Bind(new(Z) LoadLocalInstr(*tmp_var));
+    Value* tmp_val = Bind(new(Z) LoadLocalInstr(*tmp_var, token_pos));
     StoreInstanceFieldInstr* store =
         new(Z) StoreInstanceFieldInstr(Context::variable_offset(local.index()),
                                        context,
@@ -868,7 +874,7 @@
                                        kEmitStoreBarrier,
                                        token_pos);
     Do(store);
-    return ExitTempLocalScope(tmp_var);
+    return ExitTempLocalScope(tmp_var, token_pos);
   } else {
     return new(Z) StoreLocalInstr(local, value, token_pos);
   }
@@ -876,7 +882,7 @@
 
 
 Definition* EffectGraphVisitor::BuildLoadLocal(const LocalVariable& local,
-                                               intptr_t token_pos) {
+                                               TokenPosition token_pos) {
   if (local.IsConst()) {
     return new(Z) ConstantInstr(*local.ConstValue(), token_pos);
   } else if (local.is_captured()) {
@@ -902,7 +908,8 @@
 // Stores current context into the 'variable'
 void EffectGraphVisitor::BuildSaveContext(
     const LocalVariable& variable,
-    intptr_t token_pos) {
+    TokenPosition token_pos) {
+  ASSERT(token_pos.IsSynthetic() || token_pos.IsNoSource());
   Value* context = Bind(BuildCurrentContext(token_pos));
   Do(BuildStoreLocal(variable, context, token_pos));
 }
@@ -911,20 +918,20 @@
 // Loads context saved in 'context_variable' into the current context.
 void EffectGraphVisitor::BuildRestoreContext(
     const LocalVariable& variable,
-    intptr_t token_pos) {
+    TokenPosition token_pos) {
   Value* load_saved_context = Bind(BuildLoadLocal(variable, token_pos));
   Do(BuildStoreContext(load_saved_context, token_pos));
 }
 
 
 Definition* EffectGraphVisitor::BuildStoreContext(
-    Value* value, intptr_t token_pos) {
+    Value* value, TokenPosition token_pos) {
   return new(Z) StoreLocalInstr(
       *owner()->parsed_function().current_context_var(), value, token_pos);
 }
 
 
-Definition* EffectGraphVisitor::BuildCurrentContext(intptr_t token_pos) {
+Definition* EffectGraphVisitor::BuildCurrentContext(TokenPosition token_pos) {
   return new(Z) LoadLocalInstr(
       *owner()->parsed_function().current_context_var(),
       token_pos);
@@ -986,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()));
@@ -1021,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();
@@ -1031,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(),
@@ -1053,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);
@@ -1122,7 +1129,8 @@
   // statements for which there is no associated source position.
   const Function& function = owner()->function();
   if (FLAG_support_debugger &&
-      (node->token_pos() >= 0) && !function.is_native()) {
+      node->token_pos().IsDebugPause() &&
+      !function.is_native()) {
     AddInstruction(new(Z) DebugStepCheckInstr(node->token_pos(),
                                               RawPcDescriptors::kRuntimeCall));
   }
@@ -1145,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) ||
@@ -1177,7 +1185,7 @@
   if (function.IsAsyncClosure() &&
       (node->return_type() == ReturnNode::kRegular)) {
     // Temporary store the computed return value.
-    Do(BuildStoreExprTemp(return_value));
+    Do(BuildStoreExprTemp(return_value, node->token_pos()));
 
     LocalVariable* rcv_var =
         node->scope()->LookupVariable(Symbols::AsyncCompleter(), false);
@@ -1186,7 +1194,7 @@
         new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
     Value* rcv_value = Bind(BuildLoadLocal(*rcv_var, node->token_pos()));
     arguments->Add(PushArgument(rcv_value));
-    Value* returned_value = Bind(BuildLoadExprTemp());
+    Value* returned_value = Bind(BuildLoadExprTemp(node->token_pos()));
     arguments->Add(PushArgument(returned_value));
     InstanceCallInstr* call = new(Z) InstanceCallInstr(
         node->token_pos(),
@@ -1199,7 +1207,7 @@
     Do(call);
 
     // Rebind the return value for the actual return call to be null.
-    return_value = BuildNullValue();
+    return_value = BuildNullValue(node->token_pos());
   }
 
   intptr_t current_context_level = owner()->context_level();
@@ -1256,7 +1264,7 @@
 // Returns true if the type check can be skipped, for example, if the
 // destination type is dynamic or if the compile type of the value is a subtype
 // of the destination type.
-bool EffectGraphVisitor::CanSkipTypeCheck(intptr_t token_pos,
+bool EffectGraphVisitor::CanSkipTypeCheck(TokenPosition token_pos,
                                           Value* value,
                                           const AbstractType& dst_type,
                                           const String& dst_name) {
@@ -1346,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();
@@ -1413,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));
@@ -1425,22 +1433,22 @@
                                                  right_value,
                                                  constant_true,
                                                  false));  // No number check.
-    for_right.Do(BuildStoreExprTemp(compare));
+    for_right.Do(BuildStoreExprTemp(compare, node->token_pos()));
 
     if (node->kind() == Token::kAND) {
       ValueGraphVisitor for_false(owner());
       Value* constant_false =
           for_false.Bind(new(Z) ConstantInstr(Bool::False()));
-      for_false.Do(BuildStoreExprTemp(constant_false));
+      for_false.Do(BuildStoreExprTemp(constant_false, node->token_pos()));
       Join(for_test, for_right, for_false);
     } else {
       ASSERT(node->kind() == Token::kOR);
       ValueGraphVisitor for_true(owner());
       Value* constant_true = for_true.Bind(new(Z) ConstantInstr(Bool::True()));
-      for_true.Do(BuildStoreExprTemp(constant_true));
+      for_true.Do(BuildStoreExprTemp(constant_true, node->token_pos()));
       Join(for_test, for_true, for_right);
     }
-    ReturnDefinition(BuildLoadExprTemp());
+    ReturnDefinition(BuildLoadExprTemp(node->token_pos()));
     return;
   }
 
@@ -1497,14 +1505,14 @@
 
 
 void EffectGraphVisitor::BuildTypecheckPushArguments(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     PushArgumentInstr** push_instantiator_type_arguments_result) {
   const Class& instantiator_class = Class::Handle(
       Z, owner()->function().Owner());
   // Since called only when type tested against is not instantiated.
-  ASSERT(instantiator_class.NumTypeParameters() > 0);
+  ASSERT(instantiator_class.IsGeneric());
   Value* instantiator_type_arguments = NULL;
-  Value* instantiator = BuildInstantiator(instantiator_class);
+  Value* instantiator = BuildInstantiator(token_pos);
   if (instantiator == NULL) {
     // No instantiator when inside factory.
     instantiator_type_arguments =
@@ -1520,15 +1528,15 @@
 
 
 void EffectGraphVisitor::BuildTypecheckArguments(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     Value** instantiator_type_arguments_result) {
   Value* instantiator = NULL;
   Value* instantiator_type_arguments = NULL;
   const Class& instantiator_class = Class::Handle(
       Z, owner()->function().Owner());
   // Since called only when type tested against is not instantiated.
-  ASSERT(instantiator_class.NumTypeParameters() > 0);
-  instantiator = BuildInstantiator(instantiator_class);
+  ASSERT(instantiator_class.IsGeneric());
+  instantiator = BuildInstantiator(token_pos);
   if (instantiator == NULL) {
     // No instantiator when inside factory.
     instantiator_type_arguments =
@@ -1541,21 +1549,22 @@
 }
 
 
-Value* EffectGraphVisitor::BuildNullValue() {
-  return Bind(new(Z) ConstantInstr(Object::ZoneHandle(Z, Object::null())));
+Value* EffectGraphVisitor::BuildNullValue(TokenPosition token_pos) {
+  return Bind(new(Z) ConstantInstr(Object::ZoneHandle(Z, Object::null()),
+                                   token_pos));
 }
 
 
 // Used for testing incoming arguments.
 AssertAssignableInstr* EffectGraphVisitor::BuildAssertAssignable(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     Value* value,
     const AbstractType& dst_type,
     const String& dst_name) {
   // Build the type check computation.
   Value* instantiator_type_arguments = NULL;
   if (dst_type.IsInstantiated()) {
-    instantiator_type_arguments = BuildNullValue();
+    instantiator_type_arguments = BuildNullValue(token_pos);
   } else {
     BuildTypecheckArguments(token_pos, &instantiator_type_arguments);
   }
@@ -1571,7 +1580,7 @@
 
 
 // Used for type casts and to test assignments.
-Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos,
+Value* EffectGraphVisitor::BuildAssignableValue(TokenPosition token_pos,
                                                 Value* value,
                                                 const AbstractType& dst_type,
                                                 const String& dst_name) {
@@ -1582,30 +1591,6 @@
 }
 
 
-bool FlowGraphBuilder::WarnOnJSIntegralNumTypeTest(
-    AstNode* node, const AbstractType& type) const {
-  if (!(node->IsLiteralNode() && (type.IsIntType() || type.IsDoubleType()))) {
-    return false;
-  }
-  const Instance& instance = node->AsLiteralNode()->literal();
-  if (type.IsIntType()) {
-    if (instance.IsDouble()) {
-      const Double& double_instance = Double::Cast(instance);
-      double value = double_instance.value();
-      if (floor(value) == value) {
-        return true;
-      }
-    }
-  } else {
-    ASSERT(type.IsDoubleType());
-    if (instance.IsInteger()) {
-      return true;
-    }
-  }
-  return false;
-}
-
-
 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) {
   ASSERT(Token::IsTypeTestOperator(node->kind()));
   const AbstractType& type = node->right()->AsTypeNode()->type();
@@ -1614,7 +1599,7 @@
   // All objects are instances of type T if Object type is a subtype of type T.
   const Type& object_type = Type::Handle(Z, Type::ObjectType());
   if (type.IsInstantiated() &&
-      object_type.IsSubtypeOf(type, NULL, Heap::kOld)) {
+      object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
     // Must evaluate left side.
     EffectGraphVisitor for_left_value(owner());
     node->left()->Visit(&for_left_value);
@@ -1626,47 +1611,45 @@
   node->left()->Visit(&for_left_value);
   Append(for_left_value);
 
-  if (!FLAG_warn_on_javascript_compatibility) {
-    if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType() ||
-        type.IsSmiType() || type.IsStringType()) {
-      String& method_name = String::ZoneHandle(Z);
-      if (type.IsNumberType()) {
-        method_name = Symbols::_instanceOfNum().raw();
-      } else if (type.IsIntType()) {
-        method_name = Symbols::_instanceOfInt().raw();
-      } else if (type.IsDoubleType()) {
-        method_name = Symbols::_instanceOfDouble().raw();
-      } else if (type.IsSmiType()) {
-        method_name = Symbols::_instanceOfSmi().raw();
-      } else if (type.IsStringType()) {
-        method_name = Symbols::_instanceOfString().raw();
-      }
-      ASSERT(!method_name.IsNull());
-      PushArgumentInstr* push_left = PushArgument(for_left_value.value());
-      ZoneGrowableArray<PushArgumentInstr*>* arguments =
-          new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
-      arguments->Add(push_left);
-      const Bool& negate = Bool::Get(node->kind() == Token::kISNOT);
-      Value* negate_arg = Bind(new(Z) ConstantInstr(negate));
-      arguments->Add(PushArgument(negate_arg));
-      const intptr_t kNumArgsChecked = 1;
-      InstanceCallInstr* call = new(Z) InstanceCallInstr(
-          node->token_pos(),
-          Library::PrivateCoreLibName(method_name),
-          node->kind(),
-          arguments,
-          Object::null_array(),  // No argument names.
-          kNumArgsChecked,
-          owner()->ic_data_array());
-      ReturnDefinition(call);
-      return;
+  if (type.IsNumberType() || type.IsIntType() || type.IsDoubleType() ||
+      type.IsSmiType() || type.IsStringType()) {
+    String& method_name = String::ZoneHandle(Z);
+    if (type.IsNumberType()) {
+      method_name = Symbols::_instanceOfNum().raw();
+    } else if (type.IsIntType()) {
+      method_name = Symbols::_instanceOfInt().raw();
+    } else if (type.IsDoubleType()) {
+      method_name = Symbols::_instanceOfDouble().raw();
+    } else if (type.IsSmiType()) {
+      method_name = Symbols::_instanceOfSmi().raw();
+    } else if (type.IsStringType()) {
+      method_name = Symbols::_instanceOfString().raw();
     }
+    ASSERT(!method_name.IsNull());
+    PushArgumentInstr* push_left = PushArgument(for_left_value.value());
+    ZoneGrowableArray<PushArgumentInstr*>* arguments =
+        new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
+    arguments->Add(push_left);
+    const Bool& negate = Bool::Get(node->kind() == Token::kISNOT);
+    Value* negate_arg = Bind(new(Z) ConstantInstr(negate));
+    arguments->Add(PushArgument(negate_arg));
+    const intptr_t kNumArgsChecked = 1;
+    InstanceCallInstr* call = new(Z) InstanceCallInstr(
+        node->token_pos(),
+        Library::PrivateCoreLibName(method_name),
+        node->kind(),
+        arguments,
+        Object::null_array(),  // No argument names.
+        kNumArgsChecked,
+        owner()->ic_data_array());
+    ReturnDefinition(call);
+    return;
   }
 
   PushArgumentInstr* push_left = PushArgument(for_left_value.value());
   PushArgumentInstr* push_type_args = NULL;
   if (type.IsInstantiated()) {
-    push_type_args = PushArgument(BuildNullValue());
+    push_type_args = PushArgument(BuildNullValue(node->token_pos()));
   } else {
     BuildTypecheckPushArguments(node->token_pos(), &push_type_args);
   }
@@ -1707,18 +1690,13 @@
                        for_value.value(),
                        type,
                        dst_name)) {
-    // Check for javascript compatibility.
-    // Do not skip type check if javascript compatibility warning is required.
-    if (!FLAG_warn_on_javascript_compatibility ||
-        !owner()->WarnOnJSIntegralNumTypeTest(node->left(), type)) {
-      ReturnValue(for_value.value());
-      return;
-    }
+    ReturnValue(for_value.value());
+    return;
   }
   PushArgumentInstr* push_left = PushArgument(for_value.value());
   PushArgumentInstr* push_type_args = NULL;
   if (type.IsInstantiated()) {
-    push_type_args = PushArgument(BuildNullValue());
+    push_type_args = PushArgument(BuildNullValue(node->token_pos()));
   } else {
     BuildTypecheckPushArguments(node->token_pos(), &push_type_args);
   }
@@ -1741,10 +1719,11 @@
 }
 
 
-StrictCompareInstr* EffectGraphVisitor::BuildStrictCompare(AstNode* left,
-                                                           AstNode* right,
-                                                           Token::Kind kind,
-                                                           intptr_t token_pos) {
+StrictCompareInstr* EffectGraphVisitor::BuildStrictCompare(
+    AstNode* left,
+    AstNode* right,
+    Token::Kind kind,
+    TokenPosition token_pos) {
   ValueGraphVisitor for_left_value(owner());
   left->Visit(&for_left_value);
   Append(for_left_value);
@@ -1821,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);
       }
@@ -1868,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));
     }
@@ -1917,15 +1896,17 @@
   ValueGraphVisitor for_true(owner());
   node->true_expr()->Visit(&for_true);
   ASSERT(for_true.is_open());
-  for_true.Do(BuildStoreExprTemp(for_true.value()));
+  for_true.Do(BuildStoreExprTemp(for_true.value(),
+                                 node->true_expr()->token_pos()));
 
   ValueGraphVisitor for_false(owner());
   node->false_expr()->Visit(&for_false);
   ASSERT(for_false.is_open());
-  for_false.Do(BuildStoreExprTemp(for_false.value()));
+  for_false.Do(BuildStoreExprTemp(for_false.value(),
+                                  node->false_expr()->token_pos()));
 
   Join(for_test, for_true, for_false);
-  ReturnDefinition(BuildLoadExprTemp());
+  ReturnDefinition(BuildLoadExprTemp(node->token_pos()));
 }
 
 
@@ -2273,6 +2254,7 @@
   // We need to create a new await state which involves:
   // * Increase the jump counter. Sanity check against the list of targets.
   // * Save the current context for resuming.
+  ASSERT(node->token_pos().IsSynthetic() || node->token_pos().IsNoSource());
   ASSERT(node->async_scope() != NULL);
   ASSERT(node->await_scope() != NULL);
   LocalVariable* jump_var = node->async_scope()->LookupVariable(
@@ -2288,8 +2270,8 @@
   ASSERT(jump_count == owner()->await_joins()->length());
   // Store the counter in :await_jump_var.
   Value* jump_val = Bind(new(Z) ConstantInstr(
-      Smi::ZoneHandle(Z, Smi::New(jump_count))));
-  Do(BuildStoreLocal(*jump_var, jump_val));
+      Smi::ZoneHandle(Z, Smi::New(jump_count)), node->token_pos()));
+  Do(BuildStoreLocal(*jump_var, jump_val, node->token_pos()));
   // Save the current context for resuming.
   BuildSaveContext(*ctx_var, node->token_pos());
 }
@@ -2304,7 +2286,8 @@
 }
 
 
-LocalVariable* EffectGraphVisitor::EnterTempLocalScope(Value* value) {
+LocalVariable* EffectGraphVisitor::EnterTempLocalScope(
+    Value* value, TokenPosition token_pos) {
   Do(new(Z) PushTempInstr(value));
   owner()->AllocateTemp();
 
@@ -2313,7 +2296,7 @@
   char name[64];
   OS::SNPrint(name, 64, ":tmp_local%" Pd, index);
   LocalVariable*  var =
-      new(Z) LocalVariable(Scanner::kNoSourcePos,
+      new(Z) LocalVariable(TokenPosition::kNoSource,
                            String::ZoneHandle(Z, Symbols::New(name)),
                            *value->Type()->ToAbstractType());
   var->set_index(index);
@@ -2321,8 +2304,9 @@
 }
 
 
-Definition* EffectGraphVisitor::ExitTempLocalScope(LocalVariable* var) {
-  Value* tmp = Bind(new(Z) LoadLocalInstr(*var));
+Definition* EffectGraphVisitor::ExitTempLocalScope(
+    LocalVariable* var, TokenPosition token_pos) {
+  Value* tmp = Bind(new(Z) LoadLocalInstr(*var, token_pos));
   owner()->DeallocateTemps(1);
   ASSERT(GetCurrentTempLocalIndex() == var->index());
   return new(Z) DropTempsInstr(1, tmp);
@@ -2400,13 +2384,14 @@
                                                      num_elements);
   Value* array_val = Bind(create);
 
-  { LocalVariable* tmp_var = EnterTempLocalScope(array_val);
+  { LocalVariable* tmp_var = EnterTempLocalScope(array_val, node->token_pos());
     const intptr_t class_id = kArrayCid;
     const intptr_t deopt_id = Thread::kNoDeoptId;
     for (int i = 0; i < node->length(); ++i) {
-      Value* array = Bind(new(Z) LoadLocalInstr(*tmp_var));
+      Value* array = Bind(new(Z) LoadLocalInstr(*tmp_var, node->token_pos()));
       Value* index =
-          Bind(new(Z) ConstantInstr(Smi::ZoneHandle(Z, Smi::New(i))));
+          Bind(new(Z) ConstantInstr(Smi::ZoneHandle(Z, Smi::New(i)),
+                                    node->token_pos()));
       ValueGraphVisitor for_value(owner());
       node->ElementAt(i)->Visit(&for_value);
       Append(for_value);
@@ -2421,7 +2406,7 @@
           index_scale, class_id, deopt_id, node->token_pos());
       Do(store);
     }
-    ReturnDefinition(ExitTempLocalScope(tmp_var));
+    ReturnDefinition(ExitTempLocalScope(tmp_var, node->token_pos()));
   }
 }
 
@@ -2500,36 +2485,45 @@
       isolate()->AddClosureFunction(function);
     }
   }
-  ZoneGrowableArray<PushArgumentInstr*>* arguments =
-      new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
   ASSERT(function.context_scope() != ContextScope::null());
 
   // The function type of a closure may have type arguments. In that case,
   // pass the type arguments of the instantiator.
-  const Class& cls = Class::ZoneHandle(Z, function.signature_class());
-  ASSERT(!cls.IsNull());
-  const bool requires_type_arguments = cls.NumTypeArguments() > 0;
-  Value* type_arguments = NULL;
-  if (requires_type_arguments) {
-    ASSERT(cls.type_arguments_field_offset() ==
-           Closure::type_arguments_offset());
-    ASSERT(cls.instance_size() == Closure::InstanceSize());
-    const Class& instantiator_class = Class::Handle(
-        Z, owner()->function().Owner());
-    type_arguments = BuildInstantiatorTypeArguments(node->token_pos(),
-                                                    instantiator_class,
-                                                    NULL);
-    arguments->Add(PushArgument(type_arguments));
-  }
+  const Class& closure_class =
+      Class::ZoneHandle(Z, isolate()->object_store()->closure_class());
+  ZoneGrowableArray<PushArgumentInstr*>* no_arguments =
+      new(Z) ZoneGrowableArray<PushArgumentInstr*>(0);
   AllocateObjectInstr* alloc = new(Z) AllocateObjectInstr(node->token_pos(),
-                                                          cls,
-                                                          arguments);
+                                                          closure_class,
+                                                          no_arguments);
   alloc->set_closure_function(function);
 
   Value* closure_val = Bind(alloc);
-  { LocalVariable* closure_tmp_var = EnterTempLocalScope(closure_val);
+  { LocalVariable* closure_tmp_var = EnterTempLocalScope(closure_val,
+                                                         node->token_pos());
+    // Store type arguments if scope class is generic.
+    const FunctionType& function_type =
+        FunctionType::ZoneHandle(Z, function.SignatureType());
+    const Class& scope_cls = Class::ZoneHandle(Z, function_type.scope_class());
+    if (scope_cls.IsGeneric()) {
+      ASSERT(function.Owner() == scope_cls.raw());
+      Value* closure_tmp_val = Bind(new(Z) LoadLocalInstr(*closure_tmp_var,
+                                                          node->token_pos()));
+      const Class& instantiator_class = Class::Handle(
+          Z, owner()->function().Owner());
+      Value* type_arguments = BuildInstantiatorTypeArguments(node->token_pos(),
+                                                             instantiator_class,
+                                                             NULL);
+      Do(new(Z) StoreInstanceFieldInstr(Closure::type_arguments_offset(),
+                                        closure_tmp_val,
+                                        type_arguments,
+                                        kEmitStoreBarrier,
+                                        node->token_pos()));
+    }
+
     // Store function.
-    Value* closure_tmp_val = Bind(new(Z) LoadLocalInstr(*closure_tmp_var));
+    Value* closure_tmp_val =
+        Bind(new(Z) LoadLocalInstr(*closure_tmp_var, node->token_pos()));
     Value* func_val =
         Bind(new(Z) ConstantInstr(Function::ZoneHandle(Z, function.raw())));
     Do(new(Z) StoreInstanceFieldInstr(Closure::function_offset(),
@@ -2543,9 +2537,11 @@
       Value* allocated_context =
           Bind(new(Z) AllocateContextInstr(node->token_pos(),
                                            kNumContextVariables));
-      { LocalVariable* context_tmp_var = EnterTempLocalScope(allocated_context);
+      { LocalVariable* context_tmp_var =
+            EnterTempLocalScope(allocated_context, node->token_pos());
         // Store receiver in context.
-        Value* context_tmp_val = Bind(new(Z) LoadLocalInstr(*context_tmp_var));
+        Value* context_tmp_val =
+            Bind(new(Z) LoadLocalInstr(*context_tmp_var, node->token_pos()));
         ValueGraphVisitor for_receiver(owner());
         node->receiver()->Visit(&for_receiver);
         Append(for_receiver);
@@ -2556,14 +2552,16 @@
                                           kEmitStoreBarrier,
                                           node->token_pos()));
         // Store new context in closure.
-        closure_tmp_val = Bind(new(Z) LoadLocalInstr(*closure_tmp_var));
-        context_tmp_val = Bind(new(Z) LoadLocalInstr(*context_tmp_var));
+        closure_tmp_val =
+            Bind(new(Z) LoadLocalInstr(*closure_tmp_var, node->token_pos()));
+        context_tmp_val =
+            Bind(new(Z) LoadLocalInstr(*context_tmp_var, node->token_pos()));
         Do(new(Z) StoreInstanceFieldInstr(Closure::context_offset(),
                                           closure_tmp_val,
                                           context_tmp_val,
                                           kEmitStoreBarrier,
                                           node->token_pos()));
-        Do(ExitTempLocalScope(context_tmp_var));
+        Do(ExitTempLocalScope(context_tmp_var, node->token_pos()));
       }
     } else {
       // Store current context in closure.
@@ -2576,7 +2574,7 @@
                                         kEmitStoreBarrier,
                                         node->token_pos()));
     }
-    ReturnDefinition(ExitTempLocalScope(closure_tmp_var));
+    ReturnDefinition(ExitTempLocalScope(closure_tmp_var, node->token_pos()));
   }
 }
 
@@ -2595,34 +2593,34 @@
 
 
 void EffectGraphVisitor::BuildInstanceCallConditional(InstanceCallNode* node) {
+  const TokenPosition token_pos = node->token_pos();
   LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
-  LoadLocalNode* load_temp =
-      new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
+  LoadLocalNode* load_temp = new(Z) LoadLocalNode(token_pos, temp_var);
 
   LiteralNode* null_constant =
-      new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
+      new(Z) LiteralNode(ST(token_pos), Object::null_instance());
   ComparisonNode* check_is_null =
-      new(Z) ComparisonNode(Scanner::kNoSourcePos,
+      new(Z) ComparisonNode(ST(token_pos),
                             Token::kEQ,
                             load_temp,
                             null_constant);
-  TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+  TestGraphVisitor for_test(owner(), ST(token_pos));
   check_is_null->Visit(&for_test);
 
   EffectGraphVisitor for_true(owner());
   EffectGraphVisitor for_false(owner());
 
   StoreLocalNode* store_null =
-      new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, null_constant);
+      new(Z) StoreLocalNode(ST(token_pos), temp_var, null_constant);
   store_null->Visit(&for_true);
 
   InstanceCallNode* call =
-      new(Z) InstanceCallNode(node->token_pos(),
+      new(Z) InstanceCallNode(token_pos,
                               load_temp,
                               node->function_name(),
                               node->arguments());
   StoreLocalNode* store_result =
-      new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, call);
+      new(Z) StoreLocalNode(ST(token_pos), temp_var, call);
   store_result->Visit(&for_false);
 
   Join(for_test, for_true, for_false);
@@ -2634,9 +2632,9 @@
     ValueGraphVisitor for_receiver(owner());
     node->receiver()->Visit(&for_receiver);
     Append(for_receiver);
-    Do(BuildStoreExprTemp(for_receiver.value()));
+    Do(BuildStoreExprTemp(for_receiver.value(), node->token_pos()));
     BuildInstanceCallConditional(node);
-    ReturnDefinition(BuildLoadExprTemp());
+    ReturnDefinition(BuildLoadExprTemp(node->token_pos()));
   } else {
     EffectGraphVisitor::VisitInstanceCallNode(node);
   }
@@ -2648,7 +2646,7 @@
   node->receiver()->Visit(&for_receiver);
   Append(for_receiver);
   if (node->is_conditional()) {
-    Do(BuildStoreExprTemp(for_receiver.value()));
+    Do(BuildStoreExprTemp(for_receiver.value(), node->token_pos()));
     BuildInstanceCallConditional(node);
   } else {
     PushArgumentInstr* push_receiver = PushArgument(for_receiver.value());
@@ -2730,16 +2728,17 @@
   node->closure()->Visit(&for_closure);
   Append(for_closure);
 
-  LocalVariable* tmp_var = EnterTempLocalScope(for_closure.value());
+  LocalVariable* tmp_var =
+      EnterTempLocalScope(for_closure.value(), node->token_pos());
 
   ZoneGrowableArray<PushArgumentInstr*>* arguments =
       new(Z) ZoneGrowableArray<PushArgumentInstr*>(node->arguments()->length());
-  Value* closure_val = Bind(new(Z) LoadLocalInstr(*tmp_var));
+  Value* closure_val = Bind(new(Z) LoadLocalInstr(*tmp_var, node->token_pos()));
   PushArgumentInstr* push_closure = PushArgument(closure_val);
   arguments->Add(push_closure);
   BuildPushArguments(*node->arguments(), arguments);
 
-  closure_val = Bind(new(Z) LoadLocalInstr(*tmp_var));
+  closure_val = Bind(new(Z) LoadLocalInstr(*tmp_var, node->token_pos()));
   LoadFieldInstr* function_load = new(Z) LoadFieldInstr(
       closure_val,
       Closure::function_offset(),
@@ -2752,11 +2751,11 @@
       new(Z) ClosureCallInstr(function_val, node, arguments);
   if (result_needed) {
     Value* result = Bind(closure_call);
-    Do(new(Z) StoreLocalInstr(*tmp_var, result));
+    Do(new(Z) StoreLocalInstr(*tmp_var, result, ST(node->token_pos())));
   } else {
     Do(closure_call);
   }
-  ReturnDefinition(ExitTempLocalScope(tmp_var));
+  ReturnDefinition(ExitTempLocalScope(tmp_var, node->token_pos()));
 }
 
 
@@ -2771,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()));
 }
 
@@ -2886,8 +2886,7 @@
 }
 
 
-Value* EffectGraphVisitor::BuildInstantiator(const Class& instantiator_class) {
-  ASSERT(instantiator_class.NumTypeParameters() > 0);
+Value* EffectGraphVisitor::BuildInstantiator(TokenPosition token_pos) {
   Function& outer_function = Function::Handle(Z, owner()->function().raw());
   while (outer_function.IsLocalFunction()) {
     outer_function = outer_function.parent_function();
@@ -2898,7 +2897,7 @@
 
   LocalVariable* instantiator = owner()->parsed_function().instantiator();
   ASSERT(instantiator != NULL);
-  Value* result = Bind(BuildLoadLocal(*instantiator));
+  Value* result = Bind(BuildLoadLocal(*instantiator, token_pos));
   return result;
 }
 
@@ -2906,10 +2905,10 @@
 // 'expression_temp_var' may not be used inside this method if 'instantiator'
 // is not NULL.
 Value* EffectGraphVisitor::BuildInstantiatorTypeArguments(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const Class& instantiator_class,
     Value* instantiator) {
-  if (instantiator_class.NumTypeParameters() == 0) {
+  if (!instantiator_class.IsGeneric()) {
     // The type arguments are compile time constants.
     TypeArguments& type_arguments =
         TypeArguments::ZoneHandle(Z, TypeArguments::null());
@@ -2934,10 +2933,10 @@
     LocalVariable* instantiator_var =
         owner()->parsed_function().instantiator();
     ASSERT(instantiator_var != NULL);
-    return Bind(BuildLoadLocal(*instantiator_var));
+    return Bind(BuildLoadLocal(*instantiator_var, token_pos));
   }
   if (instantiator == NULL) {
-    instantiator = BuildInstantiator(instantiator_class);
+    instantiator = BuildInstantiator(token_pos);
   }
   // The instantiator is the receiver of the caller, which is not a factory.
   // The receiver cannot be null; extract its TypeArguments object.
@@ -2951,12 +2950,12 @@
       instantiator,
       type_arguments_field_offset,
       Type::ZoneHandle(Z, Type::null()),  // Not an instance, no type.
-      Scanner::kNoSourcePos));
+      token_pos));
 }
 
 
 Value* EffectGraphVisitor::BuildInstantiatedTypeArguments(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const TypeArguments& type_arguments) {
   if (type_arguments.IsNull() || type_arguments.IsInstantiated()) {
     return Bind(new(Z) ConstantInstr(type_arguments));
@@ -2995,11 +2994,12 @@
   //   tn       <- LoadLocal(temp)
 
   Value* allocate = BuildObjectAllocation(node);
-  { LocalVariable* tmp_var = EnterTempLocalScope(allocate);
-    Value* allocated_tmp = Bind(new(Z) LoadLocalInstr(*tmp_var));
+  { LocalVariable* tmp_var = EnterTempLocalScope(allocate, node->token_pos());
+    Value* allocated_tmp =
+        Bind(new(Z) LoadLocalInstr(*tmp_var, node->token_pos()));
     PushArgumentInstr* push_allocated_value = PushArgument(allocated_tmp);
     BuildConstructorCall(node, push_allocated_value);
-    ReturnDefinition(ExitTempLocalScope(tmp_var));
+    ReturnDefinition(ExitTempLocalScope(tmp_var, node->token_pos()));
   }
 }
 
@@ -3007,33 +3007,32 @@
 
 void EffectGraphVisitor::BuildInstanceGetterConditional(
     InstanceGetterNode* node) {
+  const TokenPosition token_pos = node->token_pos();
   LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
-  LoadLocalNode* load_temp =
-      new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
+  LoadLocalNode* load_temp = new(Z) LoadLocalNode(token_pos, temp_var);
 
   LiteralNode* null_constant =
-      new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
+      new(Z) LiteralNode(ST(token_pos), Object::null_instance());
   ComparisonNode* check_is_null =
-      new(Z) ComparisonNode(Scanner::kNoSourcePos,
+      new(Z) ComparisonNode(ST(token_pos),
                             Token::kEQ,
                             load_temp,
                             null_constant);
-  TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+  TestGraphVisitor for_test(owner(), ST(token_pos));
   check_is_null->Visit(&for_test);
 
   EffectGraphVisitor for_true(owner());
   EffectGraphVisitor for_false(owner());
 
   StoreLocalNode* store_null =
-      new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, null_constant);
+      new(Z) StoreLocalNode(ST(token_pos), temp_var, null_constant);
   store_null->Visit(&for_true);
 
-  InstanceGetterNode* getter =
-      new(Z) InstanceGetterNode(node->token_pos(),
-                                load_temp,
-                                node->field_name());
+  InstanceGetterNode* getter = new(Z) InstanceGetterNode(token_pos,
+                                                         load_temp,
+                                                         node->field_name());
   StoreLocalNode* store_getter =
-      new(Z) StoreLocalNode(Scanner::kNoSourcePos, temp_var, getter);
+      new(Z) StoreLocalNode(ST(token_pos), temp_var, getter);
   store_getter->Visit(&for_false);
 
   Join(for_test, for_true, for_false);
@@ -3045,9 +3044,9 @@
     ValueGraphVisitor for_receiver(owner());
     node->receiver()->Visit(&for_receiver);
     Append(for_receiver);
-    Do(BuildStoreExprTemp(for_receiver.value()));
+    Do(BuildStoreExprTemp(for_receiver.value(), node->token_pos()));
     BuildInstanceGetterConditional(node);
-    ReturnDefinition(BuildLoadExprTemp());
+    ReturnDefinition(BuildLoadExprTemp(node->token_pos()));
   } else {
     EffectGraphVisitor::VisitInstanceGetterNode(node);
   }
@@ -3059,7 +3058,7 @@
   node->receiver()->Visit(&for_receiver);
   Append(for_receiver);
   if (node->is_conditional()) {
-    Do(BuildStoreExprTemp(for_receiver.value()));
+    Do(BuildStoreExprTemp(for_receiver.value(), node->token_pos()));
     BuildInstanceGetterConditional(node);
   } else {
     PushArgumentInstr* push_receiver = PushArgument(for_receiver.value());
@@ -3095,7 +3094,7 @@
 
   Value* value = NULL;
   if (result_is_needed) {
-    value = Bind(BuildStoreExprTemp(for_value.value()));
+    value = Bind(BuildStoreExprTemp(for_value.value(), node->token_pos()));
   } else {
     value = for_value.value();
   }
@@ -3104,30 +3103,31 @@
 
 
 void EffectGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) {
+  const TokenPosition token_pos = node->token_pos();
   if (node->is_conditional()) {
     ValueGraphVisitor for_receiver(owner());
     node->receiver()->Visit(&for_receiver);
     Append(for_receiver);
-    Do(BuildStoreExprTemp(for_receiver.value()));
+    Do(BuildStoreExprTemp(for_receiver.value(), token_pos));
 
     LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
     LoadLocalNode* load_temp =
-        new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
+        new(Z) LoadLocalNode(ST(token_pos), temp_var);
     LiteralNode* null_constant =
-        new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
+        new(Z) LiteralNode(ST(token_pos), Object::null_instance());
     ComparisonNode* check_is_null =
-        new(Z) ComparisonNode(Scanner::kNoSourcePos,
+        new(Z) ComparisonNode(ST(token_pos),
                               Token::kEQ,
                               load_temp,
                               null_constant);
-    TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+    TestGraphVisitor for_test(owner(), ST(token_pos));
     check_is_null->Visit(&for_test);
 
     EffectGraphVisitor for_true(owner());
     EffectGraphVisitor for_false(owner());
 
     InstanceSetterNode* setter =
-        new(Z) InstanceSetterNode(node->token_pos(),
+        new(Z) InstanceSetterNode(token_pos,
                                   load_temp,
                                   node->field_name(),
                                   node->value());
@@ -3141,7 +3141,7 @@
   const String& name =
       String::ZoneHandle(Z, Field::SetterSymbol(node->field_name()));
   const intptr_t kNumArgsChecked = 1;  // Do not check value type.
-  InstanceCallInstr* call = new(Z) InstanceCallInstr(node->token_pos(),
+  InstanceCallInstr* call = new(Z) InstanceCallInstr(token_pos,
                                                      name,
                                                      Token::kSET,
                                                      arguments,
@@ -3153,40 +3153,41 @@
 
 
 void ValueGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) {
+  const TokenPosition token_pos = node->token_pos();
   if (node->is_conditional()) {
     ValueGraphVisitor for_receiver(owner());
     node->receiver()->Visit(&for_receiver);
     Append(for_receiver);
-    Do(BuildStoreExprTemp(for_receiver.value()));
+    Do(BuildStoreExprTemp(for_receiver.value(), token_pos));
 
     LocalVariable* temp_var = owner()->parsed_function().expression_temp_var();
     LoadLocalNode* load_temp =
-        new(Z) LoadLocalNode(Scanner::kNoSourcePos, temp_var);
+        new(Z) LoadLocalNode(ST(token_pos), temp_var);
     LiteralNode* null_constant =
-        new(Z) LiteralNode(Scanner::kNoSourcePos, Object::null_instance());
+        new(Z) LiteralNode(ST(token_pos), Object::null_instance());
     ComparisonNode* check_is_null =
-        new(Z) ComparisonNode(Scanner::kNoSourcePos,
+        new(Z) ComparisonNode(ST(token_pos),
                               Token::kEQ,
                               load_temp,
                               null_constant);
-    TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+    TestGraphVisitor for_test(owner(), ST(token_pos));
     check_is_null->Visit(&for_test);
 
     ValueGraphVisitor for_true(owner());
     null_constant->Visit(&for_true);
-    for_true.Do(BuildStoreExprTemp(for_true.value()));
+    for_true.Do(BuildStoreExprTemp(for_true.value(), token_pos));
 
     ValueGraphVisitor for_false(owner());
     InstanceSetterNode* setter =
-        new(Z) InstanceSetterNode(node->token_pos(),
+        new(Z) InstanceSetterNode(token_pos,
                                   load_temp,
                                   node->field_name(),
                                   node->value());
     setter->Visit(&for_false);
-    for_false.Do(BuildStoreExprTemp(for_false.value()));
+    for_false.Do(BuildStoreExprTemp(for_false.value(), token_pos));
 
     Join(for_test, for_true, for_false);
-    ReturnDefinition(BuildLoadExprTemp());
+    ReturnDefinition(BuildLoadExprTemp(token_pos));
     return;
   }
   ZoneGrowableArray<PushArgumentInstr*>* arguments =
@@ -3195,14 +3196,14 @@
   const String& name =
       String::ZoneHandle(Z, Field::SetterSymbol(node->field_name()));
   const intptr_t kNumArgsChecked = 1;  // Do not check value type.
-  Do(new(Z) InstanceCallInstr(node->token_pos(),
+  Do(new(Z) InstanceCallInstr(token_pos,
                               name,
                               Token::kSET,
                               arguments,
                               Object::null_array(),
                               kNumArgsChecked,
                               owner()->ic_data_array()));
-  ReturnDefinition(BuildLoadExprTemp());
+  ReturnDefinition(BuildLoadExprTemp(token_pos));
 }
 
 
@@ -3284,6 +3285,7 @@
       String::ZoneHandle(Z, Field::SetterSymbol(node->field_name()));
   ZoneGrowableArray<PushArgumentInstr*>* arguments =
       new(Z) ZoneGrowableArray<PushArgumentInstr*>(1);
+  const TokenPosition token_pos = node->token_pos();
   // A super setter is an instance setter whose setter function is
   // resolved at compile time (in the caller instance getter's super class).
   // Unlike a static getter, a super getter has a receiver parameter.
@@ -3294,7 +3296,7 @@
     if (is_super_setter) {
       ASSERT(node->receiver() != NULL);
       // Resolve and call noSuchMethod.
-      ArgumentListNode* arguments = new(Z) ArgumentListNode(node->token_pos());
+      ArgumentListNode* arguments = new(Z) ArgumentListNode(token_pos);
       arguments->Add(node->receiver());
       arguments->Add(node->value());
       call = BuildStaticNoSuchMethodCall(
@@ -3306,10 +3308,10 @@
           true);  // Super invocation.
     } else {
       // Throw a NoSuchMethodError.
-      ArgumentListNode* arguments = new(Z) ArgumentListNode(node->token_pos());
+      ArgumentListNode* arguments = new(Z) ArgumentListNode(token_pos);
       arguments->Add(node->value());
       call = BuildThrowNoSuchMethodError(
-          node->token_pos(),
+          token_pos,
           node->cls(),
           setter_name,
           arguments,  // Argument is the value passed to the setter.
@@ -3332,13 +3334,13 @@
     Append(for_value);
     Value* value = NULL;
     if (result_is_needed) {
-      value = Bind(BuildStoreExprTemp(for_value.value()));
+      value = Bind(BuildStoreExprTemp(for_value.value(), token_pos));
     } else {
       value = for_value.value();
     }
     arguments->Add(PushArgument(value));
 
-    call = new(Z) StaticCallInstr(node->token_pos(),
+    call = new(Z) StaticCallInstr(token_pos,
                                   setter_function,
                                   Object::null_array(),  // No names.
                                   arguments,
@@ -3346,7 +3348,7 @@
   }
   if (result_is_needed) {
     Do(call);
-    ReturnDefinition(BuildLoadExprTemp());
+    ReturnDefinition(BuildLoadExprTemp(token_pos));
   } else {
     ReturnDefinition(call);
   }
@@ -3382,10 +3384,11 @@
 }
 
 
-LoadLocalInstr* EffectGraphVisitor::BuildLoadThisVar(LocalScope* scope) {
+LoadLocalInstr* EffectGraphVisitor::BuildLoadThisVar(
+    LocalScope* scope, TokenPosition token_pos) {
   LocalVariable* receiver_var = scope->LookupVariable(Symbols::This(),
                                                       true);  // Test only.
-  return new(Z) LoadLocalInstr(*receiver_var);
+  return new(Z) LoadLocalInstr(*receiver_var, token_pos);
 }
 
 
@@ -3395,7 +3398,7 @@
     intptr_t offset,
     const Type& type,
     intptr_t class_id) {
-  Value* receiver = Bind(BuildLoadThisVar(node->scope()));
+  Value* receiver = Bind(BuildLoadThisVar(node->scope(), node->token_pos()));
   LoadFieldInstr* load = new(Z) LoadFieldInstr(receiver,
                                                offset,
                                                type,
@@ -3410,10 +3413,10 @@
     NativeBodyNode* node,
     intptr_t offset,
     StoreBarrierType emit_store_barrier) {
-  Value* receiver = Bind(BuildLoadThisVar(node->scope()));
+  Value* receiver = Bind(BuildLoadThisVar(node->scope(), node->token_pos()));
   LocalVariable* value_var =
       node->scope()->LookupVariable(Symbols::Value(), true);
-  Value* value = Bind(new(Z) LoadLocalInstr(*value_var));
+  Value* value = Bind(new(Z) LoadLocalInstr(*value_var, node->token_pos()));
   StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
       offset,
       receiver,
@@ -3427,19 +3430,20 @@
 
 void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) {
   const Function& function = owner()->function();
+  const TokenPosition token_pos = node->token_pos();
   if (!function.IsClosureFunction()) {
     MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
     switch (kind) {
       case MethodRecognizer::kObjectEquals: {
-        Value* receiver = Bind(BuildLoadThisVar(node->scope()));
+        Value* receiver = Bind(BuildLoadThisVar(node->scope(), token_pos));
         LocalVariable* other_var =
             node->scope()->LookupVariable(Symbols::Other(),
                                           true);  // Test only.
-        Value* other = Bind(new(Z) LoadLocalInstr(*other_var));
+        Value* other = Bind(new(Z) LoadLocalInstr(*other_var, token_pos));
         // Receiver is not a number because numbers override equality.
         const bool kNoNumberCheck = false;
         StrictCompareInstr* compare =
-            new(Z) StrictCompareInstr(node->token_pos(),
+            new(Z) StrictCompareInstr(token_pos,
                                       Token::kEQ_STRICT,
                                       receiver,
                                       other,
@@ -3463,11 +3467,11 @@
             Smi::ZoneHandle(Z, Smi::New(0))));
         Value* load_val = Bind(load);
         StrictCompareInstr* compare =
-            new(Z) StrictCompareInstr(node->token_pos(),
-                                   Token::kEQ_STRICT,
-                                   load_val,
-                                   zero_val,
-                                   false);  // No number check.
+            new(Z) StrictCompareInstr(token_pos,
+                                      Token::kEQ_STRICT,
+                                      load_val,
+                                      zero_val,
+                                      false);  // No number check.
         return ReturnDefinition(compare);
       }
       case MethodRecognizer::kGrowableArrayLength:
@@ -3483,12 +3487,12 @@
       case MethodRecognizer::kClassIDgetID: {
         LocalVariable* value_var =
             node->scope()->LookupVariable(Symbols::Value(), true);
-        Value* value = Bind(new(Z) LoadLocalInstr(*value_var));
+        Value* value = Bind(new(Z) LoadLocalInstr(*value_var, token_pos));
         LoadClassIdInstr* load = new(Z) LoadClassIdInstr(value);
         return ReturnDefinition(load);
       }
       case MethodRecognizer::kGrowableArrayCapacity: {
-        Value* receiver = Bind(BuildLoadThisVar(node->scope()));
+        Value* receiver = Bind(BuildLoadThisVar(node->scope(), token_pos));
         LoadFieldInstr* data_load = new(Z) LoadFieldInstr(
             receiver,
             Array::data_offset(),
@@ -3509,12 +3513,14 @@
         LocalVariable* type_args_parameter =
             node->scope()->LookupVariable(Symbols::TypeArgumentsParameter(),
                                           true);
-        Value* element_type = Bind(new(Z) LoadLocalInstr(*type_args_parameter));
+        Value* element_type =
+            Bind(new(Z) LoadLocalInstr(*type_args_parameter, token_pos));
         LocalVariable* length_parameter =
             node->scope()->LookupVariable(Symbols::Length(), true);
-        Value* length = Bind(new(Z) LoadLocalInstr(*length_parameter));
+        Value* length =
+            Bind(new(Z) LoadLocalInstr(*length_parameter, token_pos));
         CreateArrayInstr* create_array =
-            new CreateArrayInstr(node->token_pos(), element_type, length);
+            new CreateArrayInstr(token_pos, element_type, length);
         return ReturnDefinition(create_array);
       }
       case MethodRecognizer::kBigint_getDigits: {
@@ -3627,7 +3633,7 @@
             !node->value()->AsLoadLocalNode()->local().IsInternal()) ||
         node->value()->IsClosureNode()) &&
         !node->local().IsInternal() &&
-        (node->token_pos() >= 0)) {
+        node->token_pos().IsDebugPause()) {
       AddInstruction(new(Z) DebugStepCheckInstr(
           node->token_pos(), RawPcDescriptors::kRuntimeCall));
     }
@@ -3637,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(),
@@ -3665,7 +3671,7 @@
         (node->field().guarded_cid() == kNullCid)) {
       load->set_result_cid(node->field().guarded_cid());
     }
-    FlowGraph::AddToGuardedFields(owner()->guarded_fields(), &node->field());
+    owner()->parsed_function().AddToGuardedFields(&node->field());
   }
   ReturnDefinition(load);
 }
@@ -3673,6 +3679,7 @@
 
 void EffectGraphVisitor::VisitStoreInstanceFieldNode(
     StoreInstanceFieldNode* node) {
+  const TokenPosition token_pos = node->token_pos();
   ValueGraphVisitor for_instance(owner());
   node->instance()->Visit(&for_instance);
   Append(for_instance);
@@ -3680,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());
@@ -3691,26 +3698,26 @@
   }
 
   if (FLAG_use_field_guards) {
-    store_value = Bind(BuildStoreExprTemp(store_value));
+    store_value = Bind(BuildStoreExprTemp(store_value, token_pos));
     GuardFieldClassInstr* guard_field_class =
         new(Z) GuardFieldClassInstr(store_value,
-                                 node->field(),
-                                 thread()->GetNextDeoptId());
+                                    node->field(),
+                                    thread()->GetNextDeoptId());
     AddInstruction(guard_field_class);
-    store_value = Bind(BuildLoadExprTemp());
+    store_value = Bind(BuildLoadExprTemp(token_pos));
     GuardFieldLengthInstr* guard_field_length =
         new(Z) GuardFieldLengthInstr(store_value,
                                      node->field(),
                                      thread()->GetNextDeoptId());
     AddInstruction(guard_field_length);
-    store_value = Bind(BuildLoadExprTemp());
+    store_value = Bind(BuildLoadExprTemp(token_pos));
   }
   StoreInstanceFieldInstr* store =
       new(Z) StoreInstanceFieldInstr(node->field(),
                                      for_instance.value(),
                                      store_value,
                                      kEmitStoreBarrier,
-                                     node->token_pos());
+                                     token_pos);
   // Maybe initializing unboxed store.
   store->set_is_potential_unboxed_initialization(true);
   ReturnDefinition(store);
@@ -3718,7 +3725,7 @@
 
 
 void EffectGraphVisitor::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
-  const intptr_t token_pos = node->token_pos();
+  const TokenPosition token_pos = node->token_pos();
   if (node->field().is_const()) {
     ASSERT(node->field().StaticValue() != Object::sentinel().raw());
     ASSERT(node->field().StaticValue() !=
@@ -3727,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);
@@ -3737,13 +3745,13 @@
 Definition* EffectGraphVisitor::BuildStoreStaticField(
     StoreStaticFieldNode* node,
     bool result_is_needed,
-    intptr_t token_pos) {
+    TokenPosition token_pos) {
   ValueGraphVisitor for_value(owner());
   node->value()->Visit(&for_value);
   Append(for_value);
   Value* store_value = NULL;
   if (result_is_needed) {
-    store_value = Bind(BuildStoreExprTemp(for_value.value()));
+    store_value = Bind(BuildStoreExprTemp(for_value.value(), token_pos));
   } else {
     store_value = for_value.value();
   }
@@ -3752,7 +3760,7 @@
 
   if (result_is_needed) {
     Do(store);
-    return BuildLoadExprTemp();
+    return BuildLoadExprTemp(token_pos);
   } else {
     return store;
   }
@@ -3835,6 +3843,7 @@
     StoreIndexedNode* node,
     bool result_is_needed) {
   Function* super_function = NULL;
+  const TokenPosition token_pos = node->token_pos();
   if (node->IsSuperStore()) {
     // Resolve the store indexed operator in the super class.
     super_function = &Function::ZoneHandle(
@@ -3843,7 +3852,7 @@
     if (super_function->IsNull()) {
       // Could not resolve super operator. Generate call noSuchMethod() of the
       // super class instead.
-      ArgumentListNode* arguments = new(Z) ArgumentListNode(node->token_pos());
+      ArgumentListNode* arguments = new(Z) ArgumentListNode(token_pos);
       arguments->Add(node->array());
       arguments->Add(node->index_expr());
       arguments->Add(node->value());
@@ -3857,7 +3866,7 @@
       if (result_is_needed) {
         Do(call);
         // BuildStaticNoSuchMethodCall stores the value in expression_temp.
-        return BuildLoadExprTemp();
+        return BuildLoadExprTemp(token_pos);
       } else {
         return call;
       }
@@ -3881,7 +3890,7 @@
   Append(for_value);
   Value* value = NULL;
   if (result_is_needed) {
-    value = Bind(BuildStoreExprTemp(for_value.value()));
+    value = Bind(BuildStoreExprTemp(for_value.value(), token_pos));
   } else {
     value = for_value.value();
   }
@@ -3891,14 +3900,14 @@
     // Generate static call to super operator []=.
 
     StaticCallInstr* store =
-        new(Z) StaticCallInstr(node->token_pos(),
+        new(Z) StaticCallInstr(token_pos,
                                *super_function,
                                Object::null_array(),
                                arguments,
                                owner()->ic_data_array());
     if (result_is_needed) {
       Do(store);
-      return BuildLoadExprTemp();
+      return BuildLoadExprTemp(token_pos);
     } else {
       return store;
     }
@@ -3908,7 +3917,7 @@
     const String& name =
         String::ZoneHandle(Z, Symbols::New(Token::Str(Token::kASSIGN_INDEX)));
     InstanceCallInstr* store =
-        new(Z) InstanceCallInstr(node->token_pos(),
+        new(Z) InstanceCallInstr(token_pos,
                                  name,
                                  Token::kASSIGN_INDEX,
                                  arguments,
@@ -3917,7 +3926,7 @@
                                  owner()->ic_data_array());
     if (result_is_needed) {
       Do(store);
-      return BuildLoadExprTemp();
+      return BuildLoadExprTemp(token_pos);
     } else {
       return store;
     }
@@ -3944,7 +3953,7 @@
 
 void EffectGraphVisitor::UnchainContexts(intptr_t n) {
   // TODO(johnmccutchan): Pass this in.
-  const intptr_t token_pos = ClassifyingTokenPositions::kContext;
+  const TokenPosition token_pos = TokenPosition::kContext;
   if (n > 0) {
     Value* context = Bind(BuildCurrentContext(token_pos));
     while (n-- > 0) {
@@ -4008,7 +4017,8 @@
     Value* allocated_context =
         Bind(new(Z) AllocateContextInstr(node->token_pos(),
                                          num_context_variables));
-    { LocalVariable* tmp_var = EnterTempLocalScope(allocated_context);
+    { LocalVariable* tmp_var =
+          EnterTempLocalScope(allocated_context, node->token_pos());
       if (!is_top_level_sequence || HasContextScope()) {
         ASSERT(is_top_level_sequence ||
                (nested_block.ContextLevel() ==
@@ -4023,7 +4033,7 @@
                                           node->token_pos()));
       }
       Do(BuildStoreContext(
-          Bind(ExitTempLocalScope(tmp_var)),
+          Bind(ExitTempLocalScope(tmp_var, node->token_pos())),
           node->token_pos()));
     }
 
@@ -4041,7 +4051,7 @@
           // Create a temporary local describing the original position.
           const String& temp_name = Symbols::TempParam();
           LocalVariable* temp_local = new(Z) LocalVariable(
-              Scanner::kNoSourcePos,  // Token index.
+              TokenPosition::kNoSource,  // Token index.
               temp_name,
               Object::dynamic_type());  // Type.
           temp_local->set_index(param_frame_index);
@@ -4053,14 +4063,16 @@
           temp_local->set_is_captured_parameter(true);
 
           // Copy parameter from local frame to current context.
-          Value* load = Bind(BuildLoadLocal(*temp_local));
-          Do(BuildStoreLocal(parameter, load));
+          Value* load = Bind(BuildLoadLocal(*temp_local, node->token_pos()));
+          Do(BuildStoreLocal(parameter, load, ST(node->token_pos())));
           // Write NULL to the source location to detect buggy accesses and
           // allow GC of passed value if it gets overwritten by a new value in
           // the function.
           Value* null_constant = Bind(new(Z) ConstantInstr(
               Object::ZoneHandle(Z, Object::null())));
-          Do(BuildStoreLocal(*temp_local, null_constant));
+          Do(BuildStoreLocal(*temp_local,
+                             null_constant,
+                             ST(node->token_pos())));
         }
       }
     }
@@ -4074,15 +4086,16 @@
     // basic block. Place this check at the last parameter to ensure parameters
     // are in scope in the debugger at method entry.
     const int num_params = function.NumParameters();
-    intptr_t check_pos = Scanner::kNoSourcePos;
+    TokenPosition check_pos = TokenPosition::kNoSource;
     if (num_params > 0) {
       const LocalVariable& parameter = *scope->VariableAt(num_params - 1);
       check_pos = parameter.token_pos();
     }
-    if (check_pos < 0) {
+
+    if (!check_pos.IsDebugPause()) {
       // No parameters or synthetic parameters.
       check_pos = node->token_pos();
-      ASSERT(check_pos >= 0);
+      ASSERT(check_pos.IsDebugPause());
     }
     AddInstruction(new(Z) DebugStepCheckInstr(check_pos,
                                               RawPcDescriptors::kRuntimeCall));
@@ -4105,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() ||
@@ -4122,7 +4135,8 @@
                             NULL,
                             parameter.type(),
                             parameter.name())) {
-        Value* parameter_value = Bind(BuildLoadLocal(parameter));
+        Value* parameter_value =
+            Bind(BuildLoadLocal(parameter, parameter.token_pos()));
         Do(BuildAssertAssignable(parameter.token_pos(),
                                  parameter_value,
                                  parameter.type(),
@@ -4181,7 +4195,7 @@
     exit_ = NULL;
 
     LoadLocalNode* load_jump_count =
-        new(Z) LoadLocalNode(Scanner::kNoSourcePos, jump_var);
+        new(Z) LoadLocalNode(node->token_pos(), jump_var);
     ComparisonNode* check_jump_count;
     const intptr_t num_await_states = owner()->await_joins()->length();
 
@@ -4189,12 +4203,12 @@
         Symbols::AwaitContextVar(), false);
     for (intptr_t i = 0; i < num_await_states; i++) {
       check_jump_count = new(Z) ComparisonNode(
-          Scanner::kNoSourcePos,
+          ST(node->token_pos()),
           Token::kEQ,
           load_jump_count,
           new(Z) LiteralNode(
-              Scanner::kNoSourcePos, Smi::ZoneHandle(Z, Smi::New(i))));
-      TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos);
+              ST(node->token_pos()), Smi::ZoneHandle(Z, Smi::New(i))));
+      TestGraphVisitor for_test(owner(), ST(node->token_pos()));
       check_jump_count->Visit(&for_test);
       EffectGraphVisitor for_true(owner());
       EffectGraphVisitor for_false(owner());
@@ -4206,7 +4220,7 @@
 
       // Restore the saved continuation context, i.e. the context that was
       // saved into :await_ctx_var before the closure suspended.
-      for_true.BuildRestoreContext(*old_context, Scanner::kNoSourcePos);
+      for_true.BuildRestoreContext(*old_context, ST(node->token_pos()));
 
       // Goto saved join.
       for_true.Goto((*owner()->await_joins())[i]);
@@ -4264,7 +4278,7 @@
   owner()->set_try_index(try_handler_index);
 
   // Preserve current context into local variable ':saved_try_context_var'.
-  BuildSaveContext(node->context_var(), node->token_pos());
+  BuildSaveContext(node->context_var(), ST(node->token_pos()));
 
   EffectGraphVisitor for_try(owner());
   node->try_block()->Visit(&for_try);
@@ -4341,11 +4355,11 @@
     node->rethrow_clause()->Visit(&for_finally);
     if (for_finally.is_open()) {
       // Rethrow the exception.  Manually build the graph for rethrow.
-      Value* exception = for_finally.Bind(
-          for_finally.BuildLoadLocal(catch_block->rethrow_exception_var()));
+      Value* exception = for_finally.Bind(for_finally.BuildLoadLocal(
+          catch_block->rethrow_exception_var(), finally_block->token_pos()));
       for_finally.PushArgument(exception);
-      Value* stacktrace = for_finally.Bind(
-          for_finally.BuildLoadLocal(catch_block->rethrow_stacktrace_var()));
+      Value* stacktrace = for_finally.Bind(for_finally.BuildLoadLocal(
+          catch_block->rethrow_stacktrace_var(), finally_block->token_pos()));
       for_finally.PushArgument(stacktrace);
       for_finally.AddInstruction(
           new(Z) ReThrowInstr(catch_block->token_pos(), catch_handler_index));
@@ -4385,7 +4399,7 @@
     ArgumentListNode* method_arguments,
     bool save_last_arg,
     bool is_super_invocation) {
-  intptr_t args_pos = method_arguments->token_pos();
+  TokenPosition args_pos = method_arguments->token_pos();
   LocalVariable* temp = NULL;
   if (save_last_arg) {
     temp = owner()->parsed_function().expression_temp_var();
@@ -4396,8 +4410,23 @@
                                          *method_arguments,
                                          temp,
                                          is_super_invocation);
-  const Function& no_such_method_func = Function::ZoneHandle(Z,
-      Resolver::ResolveDynamicAnyArgs(target_class, Symbols::NoSuchMethod()));
+  // Make sure we resolve to a compatible noSuchMethod, otherwise call
+  // noSuchMethod of class Object.
+  const int kNumArguments = 2;
+  ArgumentsDescriptor args_desc(
+      Array::ZoneHandle(Z, ArgumentsDescriptor::New(kNumArguments)));
+  Function& no_such_method_func = Function::ZoneHandle(Z,
+      Resolver::ResolveDynamicForReceiverClass(target_class,
+                                               Symbols::NoSuchMethod(),
+                                               args_desc));
+  if (no_such_method_func.IsNull()) {
+    const Class& object_class =
+        Class::ZoneHandle(Z, isolate()->object_store()->object_class());
+    no_such_method_func =
+        Resolver::ResolveDynamicForReceiverClass(object_class,
+                                                 Symbols::NoSuchMethod(),
+                                                 args_desc);
+  }
   // We are guaranteed to find noSuchMethod of class Object.
   ASSERT(!no_such_method_func.IsNull());
   ZoneGrowableArray<PushArgumentInstr*>* push_arguments =
@@ -4412,7 +4441,7 @@
 
 
 StaticCallInstr* EffectGraphVisitor::BuildThrowNoSuchMethodError(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const Class& function_class,
     const String& function_name,
     ArgumentListNode* function_arguments,
@@ -4420,7 +4449,7 @@
   ZoneGrowableArray<PushArgumentInstr*>* arguments =
       new(Z) ZoneGrowableArray<PushArgumentInstr*>();
   // Object receiver, actually a class literal of the unresolved method's owner.
-  Type& type = Type::ZoneHandle(
+  AbstractType& type = Type::ZoneHandle(
       Z,
       Type::New(function_class,
                 TypeArguments::Handle(Z, TypeArguments::null()),
@@ -4576,11 +4605,11 @@
   VMTagScope tagScope(Thread::Current(),
                       VMTag::kCompileFlowGraphBuilderTagId,
                       FLAG_profile_vm);
-  if (FLAG_print_ast) {
+  if (FLAG_support_ast_printer && FLAG_print_ast) {
     // Print the function ast before IL generation.
     AstPrinter::PrintFunctionNodes(parsed_function());
   }
-  if (FLAG_print_scopes) {
+  if (FLAG_support_ast_printer && FLAG_print_scopes) {
     AstPrinter::PrintFunctionScope(parsed_function());
   }
   TargetEntryInstr* normal_entry =
@@ -4621,6 +4650,7 @@
   Report::MessageF(Report::kBailout,
                    Script::Handle(function.script()),
                    function.token_pos(),
+                   Report::AtLocation,
                    "FlowGraphBuilder Bailout: %s %s",
                    String::Handle(function.name()).ToCString(),
                    reason);
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 94c9444..474bc4f 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -113,11 +113,6 @@
     return ic_data_array_;
   }
 
-  // Return true if a Javascript compatibility warning should be emitted at
-  // runtime for this type test.
-  bool WarnOnJSIntegralNumTypeTest(AstNode* node,
-                                   const AbstractType& type) const;
-
   void Bailout(const char* reason) const;
 
   intptr_t AllocateBlockId() { return ++last_used_block_id_; }
@@ -158,10 +153,6 @@
   bool IsInlining() const { return (exit_collector_ != NULL); }
   InlineExitCollector* exit_collector() const { return exit_collector_; }
 
-  ZoneGrowableArray<const Field*>* guarded_fields() const {
-    return parsed_function_.guarded_fields();
-  }
-
   ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
     return parsed_function_.deferred_prefixes();
   }
@@ -288,7 +279,7 @@
   // Append a 'while loop' test and back edge to this graph, depending on
   // which parts are reachable.  Afterward, the graph exit is the false
   // successor of the loop condition.
-  void TieLoop(intptr_t token_pos,
+  void TieLoop(TokenPosition token_pos,
                const TestGraphVisitor& test_fragment,
                const EffectGraphVisitor& body_fragment,
                const EffectGraphVisitor& test_preamble_fragment);
@@ -300,19 +291,22 @@
   // This implementation shares state among visitors by using the builder.
   // The implementation is incorrect if a visitor that hits a return is not
   // actually added to the graph.
-  void AddReturnExit(intptr_t token_pos, Value* value);
+  void AddReturnExit(TokenPosition token_pos, Value* value);
 
  protected:
-  Definition* BuildStoreTemp(const LocalVariable& local, Value* value);
-  Definition* BuildStoreExprTemp(Value* value);
-  Definition* BuildLoadExprTemp();
+  Definition* BuildStoreTemp(const LocalVariable& local,
+                             Value* value,
+                             TokenPosition token_pos);
+  Definition* BuildStoreExprTemp(Value* value, TokenPosition token_pos);
+  Definition* BuildLoadExprTemp(TokenPosition token_pos);
 
   Definition* BuildStoreLocal(const LocalVariable& local,
                               Value* value,
-                              intptr_t token_pos = Scanner::kNoSourcePos);
+                              TokenPosition token_pos);
   Definition* BuildLoadLocal(const LocalVariable& local,
-                             intptr_t token_pos = Scanner::kNoSourcePos);
-  LoadLocalInstr* BuildLoadThisVar(LocalScope* scope);
+                             TokenPosition token_pos);
+  LoadLocalInstr* BuildLoadThisVar(LocalScope* scope,
+                                   TokenPosition token_pos);
   LoadFieldInstr* BuildNativeGetter(
       NativeBodyNode* node,
       MethodRecognizer::Kind kind,
@@ -333,27 +327,27 @@
   // allocation call.
   // May be called only if allocating an object of a parameterized class.
   Value* BuildInstantiatedTypeArguments(
-      intptr_t token_pos,
+      TokenPosition token_pos,
       const TypeArguments& type_arguments);
 
   void BuildTypecheckPushArguments(
-      intptr_t token_pos,
+      TokenPosition token_pos,
       PushArgumentInstr** push_instantiator_type_arguments);
-  void BuildTypecheckArguments(intptr_t token_pos,
+  void BuildTypecheckArguments(TokenPosition token_pos,
                                Value** instantiator_type_arguments);
-  Value* BuildInstantiator(const Class& instantiator_class);
-  Value* BuildInstantiatorTypeArguments(intptr_t token_pos,
+  Value* BuildInstantiator(TokenPosition token_pos);
+  Value* BuildInstantiatorTypeArguments(TokenPosition token_pos,
                                         const Class& instantiator_class,
                                         Value* instantiator);
 
   // Perform a type check on the given value.
-  AssertAssignableInstr* BuildAssertAssignable(intptr_t token_pos,
+  AssertAssignableInstr* BuildAssertAssignable(TokenPosition token_pos,
                                                Value* value,
                                                const AbstractType& dst_type,
                                                const String& dst_name);
 
   // Perform a type check on the given value and return it.
-  Value* BuildAssignableValue(intptr_t token_pos,
+  Value* BuildAssignableValue(TokenPosition token_pos,
                               Value* value,
                               const AbstractType& dst_type,
                               const String& dst_name);
@@ -372,7 +366,7 @@
   StrictCompareInstr* BuildStrictCompare(AstNode* left,
                                          AstNode* right,
                                          Token::Kind kind,
-                                         intptr_t token_pos);
+                                         TokenPosition token_pos);
 
   virtual void BuildTypeTest(ComparisonNode* node);
   virtual void BuildTypeCast(ComparisonNode* node);
@@ -397,12 +391,12 @@
                             PushArgumentInstr* alloc_value);
 
   void BuildSaveContext(const LocalVariable& variable,
-                        intptr_t token_pos);
+                        TokenPosition token_pos);
   void BuildRestoreContext(const LocalVariable& variable,
-                           intptr_t token_pos);
+                           TokenPosition token_pos);
 
-  Definition* BuildStoreContext(Value* value, intptr_t token_pos);
-  Definition* BuildCurrentContext(intptr_t token_pos);
+  Definition* BuildStoreContext(Value* value, TokenPosition token_pos);
+  Definition* BuildCurrentContext(TokenPosition token_pos);
 
   void BuildThrowNode(ThrowNode* node);
 
@@ -415,7 +409,7 @@
       bool is_super_invocation);
 
   StaticCallInstr* BuildThrowNoSuchMethodError(
-      intptr_t token_pos,
+      TokenPosition token_pos,
       const Class& function_class,
       const String& function_name,
       ArgumentListNode* function_arguments,
@@ -424,22 +418,22 @@
   void BuildStaticSetter(StaticSetterNode* node, bool result_is_needed);
   Definition* BuildStoreStaticField(StoreStaticFieldNode* node,
                                     bool result_is_needed,
-                                    intptr_t token_pos);
+                                    TokenPosition token_pos);
 
   void BuildClosureCall(ClosureCallNode* node, bool result_needed);
 
-  Value* BuildNullValue();
+  Value* BuildNullValue(TokenPosition token_pos);
 
   // Returns true if the run-time type check can be eliminated.
-  bool CanSkipTypeCheck(intptr_t token_pos,
+  bool CanSkipTypeCheck(TokenPosition token_pos,
                         Value* value,
                         const AbstractType& dst_type,
                         const String& dst_name);
 
   // Helpers for allocating and deallocating temporary locals on top of the
   // expression stack.
-  LocalVariable* EnterTempLocalScope(Value* value);
-  Definition* ExitTempLocalScope(LocalVariable* var);
+  LocalVariable* EnterTempLocalScope(Value* value, TokenPosition token_pos);
+  Definition* ExitTempLocalScope(LocalVariable* var, TokenPosition token_pos);
 
   void BuildLetTempExpressions(LetNode* node);
 
@@ -543,7 +537,7 @@
 class TestGraphVisitor : public ValueGraphVisitor {
  public:
   TestGraphVisitor(FlowGraphBuilder* owner,
-                   intptr_t condition_token_pos)
+                   TokenPosition condition_token_pos)
       : ValueGraphVisitor(owner),
         true_successor_addresses_(1),
         false_successor_addresses_(1),
@@ -557,7 +551,7 @@
 
   virtual void VisitBinaryOpNode(BinaryOpNode* node);
 
-  intptr_t condition_token_pos() const { return condition_token_pos_; }
+  TokenPosition condition_token_pos() const { return condition_token_pos_; }
 
  private:
   // Construct and concatenate a Branch instruction to this graph fragment.
@@ -582,7 +576,7 @@
   GrowableArray<TargetEntryInstr**> true_successor_addresses_;
   GrowableArray<TargetEntryInstr**> false_successor_addresses_;
 
-  intptr_t condition_token_pos_;
+  TokenPosition condition_token_pos_;
 };
 
 }  // namespace dart
diff --git a/runtime/vm/flow_graph_builder_test.cc b/runtime/vm/flow_graph_builder_test.cc
index 91a13b2..36eebc1 100644
--- a/runtime/vm/flow_graph_builder_test.cc
+++ b/runtime/vm/flow_graph_builder_test.cc
@@ -11,6 +11,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 #define DUMP_ASSERT(condition)                                                 \
   if (!(condition)) {                                                          \
     dart::Expect(__FILE__, __LINE__).Fail("expected: %s", #condition);         \
@@ -95,6 +97,26 @@
     DUMP_ASSERT(count > 0);
   }
 
+  // Expect to find an instance call at |line| and |column|.
+  void InstanceCallAt(const char* needle,
+                      intptr_t line,
+                      intptr_t column = -1) {
+    ZoneGrowableArray<Instruction*>* instructions =
+        FindInstructionsAt(line, column);
+    intptr_t count = 0;
+    for (intptr_t i = 0; i < instructions->length(); i++) {
+      Instruction* instr = instructions->At(i);
+      EXPECT(instr != NULL);
+      if (instr->IsInstanceCall()) {
+        const char* haystack = instr->ToCString();
+        if (strstr(haystack, needle) != NULL) {
+          count++;
+        }
+      }
+    }
+    DUMP_ASSERT(count > 0);
+  }
+
   // Expect to find at least one static call at |line| and |column|. The
   // static call will have |needle| in its |ToCString| representation.
   void StaticCallAt(const char* needle,
@@ -146,12 +168,29 @@
     }
   }
 
+  // Fails if any of the IR nodes has a token position of
+  // TokenPosition::kNoSourcePos.
+  void EnsureSourcePositions() {
+    for (intptr_t i = 0; i < blocks_->length(); i++) {
+      BlockEntryInstr* entry = (*blocks_)[i];
+      DUMP_ASSERT(entry->token_pos() != TokenPosition::kNoSource);
+      for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
+        Instruction* instr = it.Current();
+        DUMP_ASSERT(instr->token_pos() != TokenPosition::kNoSource);
+      }
+    }
+  }
+
  private:
   void DumpInstruction(Instruction* instr) {
-    const intptr_t token_pos = instr->token_pos();
-    if (token_pos < 0) {
-      const char* token_pos_string =
-          ClassifyingTokenPositions::ToCString(token_pos);
+    TokenPosition token_pos = instr->token_pos();
+    bool synthetic = false;
+    if (token_pos.IsSynthetic()) {
+      synthetic = true;
+      token_pos = token_pos.FromSynthetic();
+    }
+    if (token_pos.IsClassifying()) {
+      const char* token_pos_string = token_pos.ToCString();
       THR_Print("%12s -- %s\n", token_pos_string, instr->ToCString());
       return;
     }
@@ -161,10 +200,17 @@
                                   &token_line,
                                   &token_column,
                                   NULL);
-    THR_Print("       %02d:%02d -- %s\n",
-              static_cast<int>(token_line),
-              static_cast<int>(token_column),
-              instr->ToCString());
+    if (synthetic) {
+      THR_Print("      *%02d:%02d -- %s\n",
+                static_cast<int>(token_line),
+                static_cast<int>(token_column),
+                instr->ToCString());
+    } else {
+      THR_Print("       %02d:%02d -- %s\n",
+                static_cast<int>(token_line),
+                static_cast<int>(token_column),
+                instr->ToCString());
+    }
   }
 
   Instruction* FindFirstInstructionAt(intptr_t line, intptr_t column) {
@@ -184,8 +230,11 @@
       BlockEntryInstr* entry = (*blocks_)[i];
       for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
         Instruction* instr = it.Current();
-        intptr_t token_pos = instr->token_pos();
-        if (token_pos < 0) {
+        TokenPosition token_pos = instr->token_pos();
+        if (token_pos.IsSynthetic()) {
+          token_pos = token_pos.FromSynthetic();
+        }
+        if (!token_pos.IsReal()) {
           continue;
         }
         intptr_t token_line = -1;
@@ -211,7 +260,7 @@
       BlockEntryInstr* entry = (*blocks_)[i];
       for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
         Instruction* instr = it.Current();
-        if (instr->token_pos() == token_pos) {
+        if (instr->token_pos().value() == token_pos) {
           instructions->Add(instr);
         }
       }
@@ -267,6 +316,8 @@
   spt.InstanceCallAt(4, 13, Token::kADD);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 5, 3);
   spt.FuzzyInstructionMatchAt("Return", 5, 3);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -294,6 +345,8 @@
   spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 10);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 3);
   spt.FuzzyInstructionMatchAt("Return", 7, 3);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -323,6 +376,8 @@
   spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 10);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 3);
   spt.FuzzyInstructionMatchAt("Return", 7, 3);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -370,6 +425,8 @@
   spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3);
   spt.FuzzyInstructionMatchAt("Return", 10, 3);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -408,6 +465,8 @@
   spt.FuzzyInstructionMatchAt("LoadStaticField", 10, 10);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 10, 3);
   spt.FuzzyInstructionMatchAt("Return", 10, 3);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -445,6 +504,8 @@
   spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1);
   spt.FuzzyInstructionMatchAt("Return", 6, 1);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -487,6 +548,8 @@
   spt.FuzzyInstructionMatchAt("Constant(#null)", 6, 1);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 6, 1);
   spt.FuzzyInstructionMatchAt("Return", 6, 1);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -535,6 +598,8 @@
   spt.FuzzyInstructionMatchAt("LoadLocal(z", 9, 10);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3);
   spt.FuzzyInstructionMatchAt("Return", 9, 3);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -563,6 +628,8 @@
   spt.FuzzyInstructionMatchAt("LoadStaticField", 7, 12);
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 5);
   spt.FuzzyInstructionMatchAt("Return", 7, 5);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -607,6 +674,8 @@
   spt.FuzzyInstructionMatchAt("Constant(#5", 7, 21);             // '5'
   spt.FuzzyInstructionMatchAt("DebugStepCheck", 7, 14);
   spt.FuzzyInstructionMatchAt("Return", 7, 14);
+
+  spt.EnsureSourcePositions();
 }
 
 
@@ -657,6 +726,85 @@
 
   spt.FuzzyInstructionMatchAt("Constant(#99", 10, 12);                 // '9'
   spt.FuzzyInstructionMatchAt("Return", 10, 5);                        // 'r'
+
+  spt.EnsureSourcePositions();
+}
+
+
+TEST_CASE(SourcePosition_InstanceFields) {
+  const char* kScript =
+      "class A {\n"
+      "  var x;\n"
+      "  var y;\n"
+      "}\n"
+      "main() {\n"
+      "  var z = new A();\n"
+      "  z.x = 99;\n"
+      "  z.y = z.x;\n"
+      "  return z.y;\n"
+      "}\n";
+
+  SourcePositionTest spt(thread, kScript);
+  spt.BuildGraphFor("main");
+  spt.FuzzyInstructionMatchAt("AllocateObject(A)", 6, 15);       // 'A'
+  spt.FuzzyInstructionMatchAt("StaticCall", 6, 15);              // 'A'
+  spt.FuzzyInstructionMatchAt("StoreLocal(z", 6, 9);             // '='
+  spt.InstanceCallAt("set:x", 7, 5);                             // 'x'
+  spt.InstanceCallAt("get:x", 8, 11);                            // 'x'
+  spt.InstanceCallAt("set:y", 8, 5);                             // 'y'
+
+  spt.InstanceCallAt("get:y", 9, 12);                            // 'y'
+  spt.FuzzyInstructionMatchAt("DebugStepCheck", 9, 3);
+  spt.FuzzyInstructionMatchAt("Return", 9, 3);
+
+  spt.EnsureSourcePositions();
+}
+
+
+TEST_CASE(SourcePosition_Async) {
+  const char* kScript =
+      "import 'dart:async';\n"
+      "var x = 5;\n"
+      "var y = 5;\n"
+      "foo(Future f1, Future f2) async {\n"
+      "  await f1;\n"
+      "  await f2;\n"
+      "  return 55;\n"
+      "}\n"
+      "main() {\n"
+      "  foo(new Future.value(33));\n"
+      "}\n";
+
+  SourcePositionTest spt(thread, kScript);
+  spt.BuildGraphFor("foo");
+  spt.EnsureSourcePositions();
+  spt.Dump();
+}
+
+#endif  // !PRODUCT
+
+static bool SyntheticRoundTripTest(TokenPosition token_pos) {
+  const TokenPosition synthetic_token_pos = token_pos.ToSynthetic();
+  return synthetic_token_pos.FromSynthetic() == token_pos;
+}
+
+
+UNIT_TEST_CASE(SourcePosition_SyntheticTokens) {
+  EXPECT(TokenPosition::kNoSourcePos == -1);
+  EXPECT(TokenPosition::kMinSourcePos == 0);
+  EXPECT(TokenPosition::kMaxSourcePos > 0);
+  EXPECT(TokenPosition::kMaxSourcePos > TokenPosition::kMinSourcePos);
+  EXPECT(TokenPosition::kMinSource.value() == TokenPosition::kMinSourcePos);
+  EXPECT(TokenPosition::kMaxSource.value() == TokenPosition::kMaxSourcePos);
+  EXPECT(!TokenPosition(0).IsSynthetic());
+  EXPECT(TokenPosition(0).ToSynthetic().IsSynthetic());
+  EXPECT(TokenPosition(9).ToSynthetic().IsSynthetic());
+  EXPECT(!TokenPosition(-1).FromSynthetic().IsSynthetic());
+  EXPECT(!TokenPosition::kNoSource.IsSynthetic());
+  EXPECT(!TokenPosition::kLast.IsSynthetic());
+  EXPECT(SyntheticRoundTripTest(TokenPosition(0)));
+  EXPECT(SyntheticRoundTripTest(TokenPosition::kMaxSource));
+  EXPECT(SyntheticRoundTripTest(TokenPosition::kMinSource));
 }
 
 }  // namespace dart
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 1f02942..5bc26af 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -13,6 +13,7 @@
 #include "vm/debugger.h"
 #include "vm/deopt_instructions.h"
 #include "vm/exceptions.h"
+#include "vm/flags.h"
 #include "vm/flow_graph_allocator.h"
 #include "vm/il_printer.h"
 #include "vm/intrinsifier.h"
@@ -29,54 +30,25 @@
 
 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,
     "The minimum invocation count for a function.");
 DEFINE_FLAG(int, optimization_counter_scale, 2000,
     "The scale of invocation count, by size of the function.");
-DEFINE_FLAG(bool, polymorphic_with_deopt, true,
-    "Polymorphic calls can be generated so that failure either causes "
-    "deoptimization or falls through to a megamorphic call");
 DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment.");
 DEFINE_FLAG(bool, trace_inlining_intervals, false,
     "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, disassemble);
-DECLARE_FLAG(bool, disassemble_optimized);
-DECLARE_FLAG(bool, emit_edge_counters);
-DECLARE_FLAG(bool, fields_may_be_reset);
-DECLARE_FLAG(bool, guess_icdata_cid);
-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, support_debugger);
-DECLARE_FLAG(bool, use_field_guards);
-DECLARE_FLAG(bool, use_cha_deopt);
-DECLARE_FLAG(bool, use_osr);
-DECLARE_FLAG(bool, warn_on_javascript_compatibility);
-DECLARE_FLAG(bool, print_stop_message);
-DECLARE_FLAG(bool, lazy_dispatchers);
-DECLARE_FLAG(bool, interpret_irregexp);
-DECLARE_FLAG(bool, enable_mirrors);
-DECLARE_FLAG(bool, link_natives_lazily);
 DECLARE_FLAG(bool, trace_compiler);
 DECLARE_FLAG(int, inlining_hotness);
 DECLARE_FLAG(int, inlining_size_threshold);
@@ -87,45 +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_polymorphic_with_deopt = false;
-    FLAG_optimization_counter_threshold = -1;
-    FLAG_use_field_guards = false;
-    FLAG_use_osr = false;
-    FLAG_emit_edge_counters = false;
+#if defined(PRODUCT)
+    FATAL("dart_noopt not supported in product mode");
+#else
     FLAG_support_debugger = false;
-    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.
-    Compiler::set_always_optimize(true);
-    // Triggers assert if we try to recompile (e.g., because of deferred
-    // loading, deoptimization, ...). Noopt mode simulates behavior
-    // of precompiled code, therefore do not allow recompilation.
-    Compiler::set_allow_recompilation(false);
-    // Precompilation finalizes all classes and thus allows CHA optimizations.
-    // Do not require CHA triggered deoptimization.
-    FLAG_use_cha_deopt = false;
-    // Calling the PrintStopMessage stub is not supported in precompiled code
-    // since it is done at places where no pool pointer is loaded.
-    FLAG_print_stop_message = false;
 
-    FLAG_lazy_dispatchers = false;
-    FLAG_interpret_irregexp = true;
-    FLAG_enable_mirrors = false;
-    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;
@@ -136,22 +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;
+    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;
+    FLAG_precompiled_mode = true;
+    FLAG_print_stop_message = false;
+    FLAG_use_cha_deopt = false;
+    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
@@ -189,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()),
@@ -200,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_(),
@@ -226,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());
@@ -274,17 +268,17 @@
 
 
 void FlowGraphCompiler::InitCompiler() {
+#ifndef PRODUCT
   TimelineDurationScope tds(thread(),
                             isolate()->GetCompilerStream(),
                             "InitCompiler");
+#endif  // !PRODUCT
   pc_descriptors_list_ = new(zone()) DescriptorList(64);
   exception_handlers_list_ = new(zone()) ExceptionHandlerList();
   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.
@@ -449,7 +443,7 @@
 
 
 void FlowGraphCompiler::EmitSourceLine(Instruction* instr) {
-  if ((instr->token_pos() < 0) || (instr->env() == NULL)) {
+  if (!instr->token_pos().IsReal() || (instr->env() == NULL)) {
     return;
   }
   const Script& script =
@@ -485,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());
   }
 };
 
@@ -508,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.
@@ -528,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;
           }
@@ -553,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)
@@ -575,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();
@@ -627,6 +633,7 @@
   Report::MessageF(Report::kBailout,
                    Script::Handle(function.script()),
                    function.token_pos(),
+                   Report::AtLocation,
                    "FlowGraphCompiler Bailout: %s %s",
                    String::Handle(function.name()).ToCString(),
                    reason);
@@ -734,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);
   }
 }
 
@@ -763,7 +774,7 @@
 // Uses current pc position and try-index.
 void FlowGraphCompiler::AddCurrentDescriptor(RawPcDescriptors::Kind kind,
                                              intptr_t deopt_id,
-                                             intptr_t token_pos) {
+                                             TokenPosition token_pos) {
   // When running with optimizations disabled, don't emit deopt-descriptors.
   if (!CanOptimize() && (kind == RawPcDescriptors::kDeopt)) return;
   pc_descriptors_list()->AddDescriptor(kind,
@@ -789,7 +800,7 @@
 
 
 void FlowGraphCompiler::AddDeoptIndexAtCall(intptr_t deopt_id,
-                                            intptr_t token_pos) {
+                                            TokenPosition token_pos) {
   ASSERT(is_optimizing());
   ASSERT(!intrinsic_mode());
   CompilerDeoptInfo* info =
@@ -938,8 +949,8 @@
     return &intrinsic_slow_path_label_;
   }
 
-  // No deoptimization allowed when 'always_optimize' is set.
-  if (Compiler::always_optimize()) {
+  // 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",
@@ -986,8 +997,8 @@
 
 
 RawArray* FlowGraphCompiler::CreateDeoptInfo(Assembler* assembler) {
-  // No deopt information if we 'always_optimize' (no deoptimization allowed).
-  if (Compiler::always_optimize()) {
+  // No deopt information if we precompile (no deoptimization allowed).
+  if (FLAG_precompiled_mode) {
     return Array::empty_array().raw();
   }
   // For functions with optional arguments, all incoming arguments are copied
@@ -1048,8 +1059,8 @@
     RawLocalVarDescriptors::VarInfo info;
     info.set_kind(RawLocalVarDescriptors::kSavedCurrentContext);
     info.scope_id = 0;
-    info.begin_pos = 0;
-    info.end_pos = 0;
+    info.begin_pos = TokenPosition::kMinSource;
+    info.end_pos = TokenPosition::kMinSource;
     info.set_index(parsed_function().current_context_var()->index());
     var_descs.SetVar(0, Symbols::CurrentContextVar(), &info);
   }
@@ -1087,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();
@@ -1101,7 +1112,7 @@
       // Reading from a mutable double box requires allocating a fresh double.
       if (load_node.field().guarded_cid() == kDynamicCid) {
         GenerateInlinedGetter(load_node.field().Offset());
-        return true;
+        return !FLAG_use_field_guards;
       }
       return false;
     }
@@ -1116,7 +1127,7 @@
           *sequence_node.NodeAt(0)->AsStoreInstanceFieldNode();
       if (store_node.field().guarded_cid() == kDynamicCid) {
         GenerateInlinedSetter(store_node.field().Offset());
-        return true;
+        return !FLAG_use_field_guards;
       }
     }
   }
@@ -1139,12 +1150,12 @@
 
 void FlowGraphCompiler::GenerateInstanceCall(
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     intptr_t argument_count,
     LocationSummary* locs,
     const ICData& ic_data_in) {
   const ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original());
-  if (Compiler::always_optimize()) {
+  if (FLAG_precompiled_mode) {
     EmitSwitchableInstanceCall(ic_data, argument_count,
                                deopt_id, token_pos, locs);
     return;
@@ -1176,12 +1187,7 @@
     return;
   }
 
-  if (is_optimizing() &&
-      // Do not make the instance call megamorphic if the callee needs to decode
-      // the calling code sequence to lookup the ic data and verify if a JS
-      // warning has already been issued or not.
-      (!FLAG_warn_on_javascript_compatibility ||
-       !ic_data.MayCheckForJSWarning())) {
+  if (is_optimizing()) {
     EmitMegamorphicInstanceCall(ic_data, argument_count,
                                 deopt_id, token_pos, locs);
     return;
@@ -1205,7 +1211,7 @@
 
 
 void FlowGraphCompiler::GenerateStaticCall(intptr_t deopt_id,
-                                           intptr_t token_pos,
+                                           TokenPosition token_pos,
                                            const Function& function,
                                            intptr_t argument_count,
                                            const Array& argument_names,
@@ -1216,12 +1222,7 @@
       ic_data.IsNull() ? ArgumentsDescriptor::New(argument_count,
                                                   argument_names)
                        : ic_data.arguments_descriptor());
-  // Proper reporting of Javascript incompatibilities requires icdata and
-  // may therefore prevent the optimization of some static calls.
-  if (is_optimizing() &&
-      !(FLAG_warn_on_javascript_compatibility &&
-        (MethodRecognizer::RecognizeKind(function) ==
-         MethodRecognizer::kObjectIdentical))) {
+  if (is_optimizing()) {
     EmitOptimizedStaticCall(function, arguments_descriptor,
                             argument_count, deopt_id, token_pos, locs);
   } else {
@@ -1286,10 +1287,15 @@
 
 
 void FlowGraphCompiler::EmitComment(Instruction* instr) {
+  if (!FLAG_support_il_printer || !FLAG_support_disassembler) {
+    return;
+  }
+#ifndef PRODUCT
   char buffer[256];
   BufferFormatter f(buffer, sizeof(buffer));
   instr->PrintTo(&f);
   assembler()->Comment("%s", buffer);
+#endif
 }
 
 
@@ -1439,7 +1445,9 @@
     const MoveOperands& move = *moves_[i];
     if (!move.IsEliminated()) {
       ASSERT(move.src().IsConstant());
+      compiler_->BeginCodeSourceRange();
       EmitMove(i);
+      compiler_->EndCodeSourceRange(TokenPosition::kParallelMove);
     }
   }
 
@@ -1515,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);
 }
 
 
@@ -1764,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();
@@ -1779,12 +1806,36 @@
 }
 
 
+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,
     const Array& argument_names,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   if (FLAG_polymorphic_with_deopt) {
     Label* deopt = AddDeoptStub(deopt_id,
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index b6d4c4c..60ce384 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -219,7 +219,7 @@
   MegamorphicSlowPath(const ICData& ic_data,
                       intptr_t argument_count,
                       intptr_t deopt_id,
-                      intptr_t token_pos,
+                      TokenPosition token_pos,
                       LocationSummary* locs,
                       intptr_t try_index)
     : SlowPathCode(),
@@ -237,7 +237,7 @@
   const ICData& ic_data_;
   intptr_t argument_count_;
   intptr_t deopt_id_;
-  intptr_t token_pos_;
+  TokenPosition token_pos_;
   LocationSummary* locs_;
   const intptr_t try_index_;  // For try/catch ranges.
 
@@ -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();
@@ -311,6 +312,7 @@
   static bool SupportsSinCos();
   static bool SupportsUnboxedSimd128();
   static bool SupportsHardwareDivision();
+  static bool CanConvertUnboxedMintToDouble();
 
   static bool IsUnboxedField(const Field& field);
   static bool IsPotentialUnboxedField(const Field& field);
@@ -365,43 +367,49 @@
   // Returns 'true' if regular code generation should be skipped.
   bool TryIntrinsify();
 
-  void GenerateRuntimeCall(intptr_t token_pos,
+  void GenerateRuntimeCall(TokenPosition token_pos,
                            intptr_t deopt_id,
                            const RuntimeEntry& entry,
                            intptr_t argument_count,
                            LocationSummary* locs);
 
-  void GenerateCall(intptr_t token_pos,
+  void GenerateCall(TokenPosition token_pos,
                     const StubEntry& stub_entry,
                     RawPcDescriptors::Kind kind,
                     LocationSummary* locs);
 
   void GenerateDartCall(intptr_t deopt_id,
-                        intptr_t token_pos,
+                        TokenPosition token_pos,
                         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(intptr_t token_pos,
+  void GenerateAssertAssignable(TokenPosition token_pos,
                                 intptr_t deopt_id,
                                 const AbstractType& dst_type,
                                 const String& dst_name,
                                 LocationSummary* locs);
 
-  void GenerateInstanceOf(intptr_t token_pos,
+  void GenerateInstanceOf(TokenPosition token_pos,
                           intptr_t deopt_id,
                           const AbstractType& type,
                           bool negate_result,
                           LocationSummary* locs);
 
   void GenerateInstanceCall(intptr_t deopt_id,
-                            intptr_t token_pos,
+                            TokenPosition token_pos,
                             intptr_t argument_count,
                             LocationSummary* locs,
                             const ICData& ic_data);
 
   void GenerateStaticCall(intptr_t deopt_id,
-                          intptr_t token_pos,
+                          TokenPosition token_pos,
                           const Function& function,
                           intptr_t argument_count,
                           const Array& argument_names,
@@ -428,21 +436,21 @@
                                  const ICData& ic_data,
                                  intptr_t argument_count,
                                  intptr_t deopt_id,
-                                 intptr_t token_pos,
+                                 TokenPosition token_pos,
                                  LocationSummary* locs);
 
   void EmitInstanceCall(const StubEntry& stub_entry,
                         const ICData& ic_data,
                         intptr_t argument_count,
                         intptr_t deopt_id,
-                        intptr_t token_pos,
+                        TokenPosition token_pos,
                         LocationSummary* locs);
 
   void EmitPolymorphicInstanceCall(const ICData& ic_data,
                                    intptr_t argument_count,
                                    const Array& argument_names,
                                    intptr_t deopt_id,
-                                   intptr_t token_pos,
+                                   TokenPosition token_pos,
                                    LocationSummary* locs);
 
   // Pass a value for try-index where block is not available (e.g. slow path).
@@ -450,14 +458,14 @@
       const ICData& ic_data,
       intptr_t argument_count,
       intptr_t deopt_id,
-      intptr_t token_pos,
+      TokenPosition token_pos,
       LocationSummary* locs,
       intptr_t try_index = CatchClauseNode::kInvalidTryIndex);
 
   void EmitSwitchableInstanceCall(const ICData& ic_data,
                                   intptr_t argument_count,
                                   intptr_t deopt_id,
-                                  intptr_t token_pos,
+                                  TokenPosition token_pos,
                                   LocationSummary* locs);
 
   void EmitTestAndCall(const ICData& ic_data,
@@ -466,17 +474,17 @@
                        Label* failed,
                        Label* match_found,
                        intptr_t deopt_id,
-                       intptr_t token_index,
+                       TokenPosition token_index,
                        LocationSummary* locs);
 
   Condition EmitEqualityRegConstCompare(Register reg,
                                         const Object& obj,
                                         bool needs_number_check,
-                                        intptr_t token_pos);
+                                        TokenPosition token_pos);
   Condition EmitEqualityRegRegCompare(Register left,
                                       Register right,
                                       bool needs_number_check,
-                                      intptr_t token_pos);
+                                      TokenPosition token_pos);
 
   void EmitTrySync(Instruction* instr, intptr_t try_index);
 
@@ -504,7 +512,7 @@
   void SetNeedsStacktrace(intptr_t try_index);
   void AddCurrentDescriptor(RawPcDescriptors::Kind kind,
                             intptr_t deopt_id,
-                            intptr_t token_pos);
+                            TokenPosition token_pos);
 
   void RecordSafepoint(LocationSummary* locs);
 
@@ -512,7 +520,7 @@
                       ICData::DeoptReasonId reason,
                       uint32_t flags = 0);
 
-  void AddDeoptIndexAtCall(intptr_t deopt_id, intptr_t token_pos);
+  void AddDeoptIndexAtCall(intptr_t deopt_id, TokenPosition token_pos);
 
   void AddSlowPathCode(SlowPathCode* slow_path);
 
@@ -583,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_.
 
@@ -605,12 +624,12 @@
                                const Array& arguments_descriptor,
                                intptr_t argument_count,
                                intptr_t deopt_id,
-                               intptr_t token_pos,
+                               TokenPosition token_pos,
                                LocationSummary* locs);
 
   void EmitUnoptimizedStaticCall(intptr_t argument_count,
                                  intptr_t deopt_id,
-                                 intptr_t token_pos,
+                                 TokenPosition token_pos,
                                  LocationSummary* locs,
                                  const ICData& ic_data);
 
@@ -620,30 +639,30 @@
                      Label* is_instance_lbl,
                      Label* is_not_instance_lbl);
 
-  RawSubtypeTestCache* GenerateInlineInstanceof(intptr_t token_pos,
+  RawSubtypeTestCache* GenerateInlineInstanceof(TokenPosition token_pos,
                                                 const AbstractType& type,
                                                 Label* is_instance_lbl,
                                                 Label* is_not_instance_lbl);
 
   RawSubtypeTestCache* GenerateInstantiatedTypeWithArgumentsTest(
-      intptr_t token_pos,
+      TokenPosition token_pos,
       const AbstractType& dst_type,
       Label* is_instance_lbl,
       Label* is_not_instance_lbl);
 
-  bool GenerateInstantiatedTypeNoArgumentsTest(intptr_t token_pos,
+  bool GenerateInstantiatedTypeNoArgumentsTest(TokenPosition token_pos,
                                                const AbstractType& dst_type,
                                                Label* is_instance_lbl,
                                                Label* is_not_instance_lbl);
 
   RawSubtypeTestCache* GenerateUninstantiatedTypeTest(
-      intptr_t token_pos,
+      TokenPosition token_pos,
       const AbstractType& dst_type,
       Label* is_instance_lbl,
       Label* is_not_instance_label);
 
   RawSubtypeTestCache* GenerateSubtype1TestCacheLookup(
-      intptr_t token_pos,
+      TokenPosition token_pos,
       const Class& type_class,
       Label* is_instance_lbl,
       Label* is_not_instance_lbl);
@@ -743,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_;
@@ -780,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 abd8b65..8d6816a 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -77,6 +77,13 @@
 }
 
 
+bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() {
+  // ARM does not have a short instruction sequence for converting int64 to
+  // double.
+  return false;
+}
+
+
 void FlowGraphCompiler::EnterIntrinsicMode() {
   ASSERT(!intrinsic_mode());
   intrinsic_mode_ = true;
@@ -266,18 +273,19 @@
 // Clobbers R2.
 RawSubtypeTestCache*
 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeWithArgumentsTest");
   ASSERT(type.IsInstantiated());
   const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-  ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+  ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
   const Register kInstanceReg = R0;
   Error& bound_error = Error::Handle(zone());
   const Type& int_type = Type::Handle(zone(), Type::IntType());
-  const bool smi_is_ok = int_type.IsSubtypeOf(type, &bound_error, Heap::kOld);
+  const bool smi_is_ok =
+      int_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
   // Malformed type should have been handled at graph construction time.
   ASSERT(smi_is_ok || bound_error.IsNull());
   __ tst(kInstanceReg, Operand(kSmiTagMask));
@@ -286,15 +294,15 @@
   } else {
     __ b(is_not_instance_lbl, EQ);
   }
-  const intptr_t num_type_args = type_class.NumTypeArguments();
-  const intptr_t num_type_params = type_class.NumTypeParameters();
-  const intptr_t from_index = num_type_args - num_type_params;
-  const TypeArguments& type_arguments =
-      TypeArguments::ZoneHandle(zone(), type.arguments());
-  const bool is_raw_type = type_arguments.IsNull() ||
-      type_arguments.IsRaw(from_index, num_type_params);
-  // Signature class is an instantiated parameterized type.
-  if (!type_class.IsSignatureClass()) {
+  // A function type test requires checking the function signature.
+  if (!type.IsFunctionType()) {
+    const intptr_t num_type_args = type_class.NumTypeArguments();
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::ZoneHandle(zone(), type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
     if (is_raw_type) {
       const Register kClassIdReg = R2;
       // dynamic type argument, check only classes.
@@ -317,7 +325,7 @@
         ASSERT(tp_argument.HasResolvedTypeClass());
         // Check if type argument is dynamic or Object.
         const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-        if (object_type.IsSubtypeOf(tp_argument, NULL, Heap::kOld)) {
+        if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
           // Instance class test only necessary.
           return GenerateSubtype1TestCacheLookup(
               token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -356,12 +364,16 @@
 // Clobbers R2, R3.
 // Returns true if there is a fallthrough.
 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeNoArgumentsTest");
   ASSERT(type.IsInstantiated());
+  if (type.IsFunctionType()) {
+    // Fallthrough.
+    return true;
+  }
   const Class& type_class = Class::Handle(zone(), type.type_class());
   ASSERT(type_class.NumTypeArguments() == 0);
 
@@ -373,6 +385,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ b(is_instance_lbl, EQ);
   } else {
@@ -392,17 +405,15 @@
     __ b(is_not_instance_lbl);
     return false;
   }
-  if (type.IsFunctionType()) {
+  if (type.IsDartFunctionType()) {
     // Check if instance is a closure.
-    __ LoadClassById(R3, kClassIdReg);
-    __ ldr(R3, FieldAddress(R3, Class::signature_function_offset()));
-    __ CompareObject(R3, Object::null_object());
-    __ b(is_instance_lbl, NE);
+    __ CompareImmediate(kClassIdReg, kClosureCid);
+    __ b(is_instance_lbl, EQ);
   }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
   if (type.IsSubtypeOf(
-        Type::Handle(zone(), Type::Number()), NULL, Heap::kOld)) {
+        Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -424,7 +435,7 @@
 // arrays can grow too high, but they may be useful when optimizing
 // code (type-feedback).
 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const Class& type_class,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -452,7 +463,7 @@
 // Generates inlined check if 'type' is a type parameter or type itself
 // R0: instance (preserved).
 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -505,7 +516,7 @@
     __ Bind(&fall_through);
     return type_test_cache.raw();
   }
-  if (type.IsType()) {
+  if (type.IsType() || type.IsFunctionType()) {
     const Register kInstanceReg = R0;
     const Register kTypeArgumentsReg = R1;
     __ tst(kInstanceReg, Operand(kSmiTagMask));  // Is instance Smi?
@@ -535,7 +546,7 @@
 // may fall through to it. Otherwise, this inline code will jump to the label
 // is_instance or to the label is_not_instance.
 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -547,10 +558,10 @@
   }
   if (type.IsInstantiated()) {
     const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-    // A class equality check is only applicable with a dst type of a
-    // non-parameterized class, non-signature class, or with a raw dst type of
+    // A class equality check is only applicable with a dst type (not a
+    // function type) of a non-parameterized class or with a raw dst type of
     // a parameterized class.
-    if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+    if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
       return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
                                                        type,
                                                        is_instance_lbl,
@@ -588,7 +599,7 @@
 // - R1: instantiator type arguments or raw_null.
 // Returns:
 // - true or false in R0.
-void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
+void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
                                            intptr_t deopt_id,
                                            const AbstractType& type,
                                            bool negate_result,
@@ -668,12 +679,12 @@
 // - object in R0 for successful assignable check (or throws TypeError).
 // Performance notes: positive checks must be quick, negative checks can be slow
 // as they throw an exception.
-void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
+void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
                                                  intptr_t deopt_id,
                                                  const AbstractType& dst_type,
                                                  const String& dst_name,
                                                  LocationSummary* locs) {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+  ASSERT(!token_pos.IsClassifying());
   ASSERT(!dst_type.IsNull());
   ASSERT(dst_type.IsFinalized());
   // Assignable check is skipped in FlowGraphBuilder, not here.
@@ -1116,13 +1127,15 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   VisitBlocks();
 
   __ bkpt(0);
   ASSERT(assembler()->constant_pool_allowed());
   GenerateDeferredCode();
 
-  if (is_optimizing() && Compiler::allow_recompilation()) {
+  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;
@@ -1133,10 +1146,11 @@
     lazy_deopt_pc_offset_ = assembler()->CodeSize();
     __ Branch(*StubCode::DeoptimizeLazy_entry());
   }
+  EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
 }
 
 
-void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
+void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
                                      const StubEntry& stub_entry,
                                      RawPcDescriptors::Kind kind,
                                      LocationSummary* locs) {
@@ -1147,7 +1161,7 @@
 
 
 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          const StubEntry& stub_entry,
                                          RawPcDescriptors::Kind kind,
                                          LocationSummary* locs) {
@@ -1168,7 +1182,36 @@
 }
 
 
-void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos,
+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,
                                             intptr_t argument_count,
@@ -1222,7 +1265,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
   // Each ICData propagated from unoptimized to optimized code contains the
@@ -1247,7 +1290,7 @@
                                          const ICData& ic_data,
                                          intptr_t argument_count,
                                          intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
   __ LoadUniqueObject(R9, ic_data);
@@ -1264,7 +1307,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     intptr_t try_index) {
   const String& name = String::Handle(zone(), ic_data.target_name());
@@ -1286,7 +1329,7 @@
 
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
-  if (Compiler::always_optimize()) {
+  if (FLAG_precompiled_mode) {
     // Megamorphic calls may occur in slow path stubs.
     // If valid use try_index argument.
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1317,7 +1360,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ Comment("SwitchableCall");
   __ LoadFromOffset(kWord, R0, SP, (argument_count - 1) * kWordSize);
@@ -1356,7 +1399,7 @@
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     const ICData& ic_data) {
   const StubEntry* stub_entry =
@@ -1376,17 +1419,17 @@
     const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ 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);
 }
 
@@ -1395,7 +1438,7 @@
     Register reg,
     const Object& obj,
     bool needs_number_check,
-    intptr_t token_pos) {
+    TokenPosition token_pos) {
   if (needs_number_check) {
     ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint());
     __ Push(reg);
@@ -1407,7 +1450,7 @@
       __ BranchLinkPatchable(
           *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1422,10 +1465,11 @@
 }
 
 
-Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
-                                                       Register right,
-                                                       bool needs_number_check,
-                                                       intptr_t token_pos) {
+Condition FlowGraphCompiler::EmitEqualityRegRegCompare(
+    Register left,
+    Register right,
+    bool needs_number_check,
+    TokenPosition token_pos) {
   if (needs_number_check) {
     __ Push(left);
     __ Push(right);
@@ -1436,7 +1480,7 @@
       __ BranchLinkPatchable(
           *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1550,7 +1594,7 @@
                                         Label* failed,
                                         Label* match_found,
                                         intptr_t deopt_id,
-                                        intptr_t token_index,
+                                        TokenPosition token_index,
                                         LocationSummary* locs) {
   ASSERT(is_optimizing());
   __ Comment("EmitTestAndCall");
@@ -1578,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);
@@ -1620,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 359c89c..618e60d 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -69,6 +69,13 @@
 }
 
 
+bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() {
+  // ARM does not have a short instruction sequence for converting int64 to
+  // double.
+  return false;
+}
+
+
 bool FlowGraphCompiler::SupportsHardwareDivision() {
   return true;
 }
@@ -258,18 +265,19 @@
 // Clobbers R2.
 RawSubtypeTestCache*
 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeWithArgumentsTest");
   ASSERT(type.IsInstantiated());
   const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-  ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+  ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
   const Register kInstanceReg = R0;
   Error& bound_error = Error::Handle(zone());
   const Type& int_type = Type::Handle(zone(), Type::IntType());
-  const bool smi_is_ok = int_type.IsSubtypeOf(type, &bound_error, Heap::kOld);
+  const bool smi_is_ok =
+      int_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
   // Malformed type should have been handled at graph construction time.
   ASSERT(smi_is_ok || bound_error.IsNull());
   __ tsti(kInstanceReg, Immediate(kSmiTagMask));
@@ -278,15 +286,15 @@
   } else {
     __ b(is_not_instance_lbl, EQ);
   }
-  const intptr_t num_type_args = type_class.NumTypeArguments();
-  const intptr_t num_type_params = type_class.NumTypeParameters();
-  const intptr_t from_index = num_type_args - num_type_params;
-  const TypeArguments& type_arguments =
-      TypeArguments::ZoneHandle(zone(), type.arguments());
-  const bool is_raw_type = type_arguments.IsNull() ||
-      type_arguments.IsRaw(from_index, num_type_params);
-  // Signature class is an instantiated parameterized type.
-  if (!type_class.IsSignatureClass()) {
+  // A function type test requires checking the function signature.
+  if (!type.IsFunctionType()) {
+    const intptr_t num_type_args = type_class.NumTypeArguments();
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::ZoneHandle(zone(), type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
     if (is_raw_type) {
       const Register kClassIdReg = R2;
       // dynamic type argument, check only classes.
@@ -309,7 +317,7 @@
         ASSERT(tp_argument.HasResolvedTypeClass());
         // Check if type argument is dynamic or Object.
         const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-        if (object_type.IsSubtypeOf(tp_argument, NULL, Heap::kOld)) {
+        if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
           // Instance class test only necessary.
           return GenerateSubtype1TestCacheLookup(
               token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -348,12 +356,16 @@
 // Clobbers R2, R3.
 // Returns true if there is a fallthrough.
 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeNoArgumentsTest");
   ASSERT(type.IsInstantiated());
+  if (type.IsFunctionType()) {
+    // Fallthrough.
+    return true;
+  }
   const Class& type_class = Class::Handle(zone(), type.type_class());
   ASSERT(type_class.NumTypeArguments() == 0);
 
@@ -365,6 +377,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ b(is_instance_lbl, EQ);
   } else {
@@ -384,17 +397,15 @@
     __ b(is_not_instance_lbl);
     return false;
   }
-  if (type.IsFunctionType()) {
+  if (type.IsDartFunctionType()) {
     // Check if instance is a closure.
-    __ LoadClassById(R3, kClassIdReg);
-    __ LoadFieldFromOffset(R3, R3, Class::signature_function_offset());
-    __ CompareObject(R3, Object::null_object());
-    __ b(is_instance_lbl, NE);
+    __ CompareImmediate(kClassIdReg, kClosureCid);
+    __ b(is_instance_lbl, EQ);
   }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
   if (type.IsSubtypeOf(
-          Type::Handle(zone(), Type::Number()), NULL, Heap::kOld)) {
+          Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -416,7 +427,7 @@
 // arrays can grow too high, but they may be useful when optimizing
 // code (type-feedback).
 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const Class& type_class,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -444,7 +455,7 @@
 // Generates inlined check if 'type' is a type parameter or type itself
 // R0: instance (preserved).
 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -497,7 +508,7 @@
     __ Bind(&fall_through);
     return type_test_cache.raw();
   }
-  if (type.IsType()) {
+  if (type.IsType() || type.IsFunctionType()) {
     const Register kInstanceReg = R0;
     const Register kTypeArgumentsReg = R1;
     __ tsti(kInstanceReg, Immediate(kSmiTagMask));  // Is instance Smi?
@@ -527,7 +538,7 @@
 // may fall through to it. Otherwise, this inline code will jump to the label
 // is_instance or to the label is_not_instance.
 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -539,10 +550,10 @@
   }
   if (type.IsInstantiated()) {
     const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-    // A class equality check is only applicable with a dst type of a
-    // non-parameterized class, non-signature class, or with a raw dst type of
+    // A class equality check is only applicable with a dst type (not a
+    // function type) of a non-parameterized class or with a raw dst type of
     // a parameterized class.
-    if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+    if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
       return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
                                                        type,
                                                        is_instance_lbl,
@@ -580,7 +591,7 @@
 // - R1: instantiator type arguments or raw_null.
 // Returns:
 // - true or false in R0.
-void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
+void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
                                            intptr_t deopt_id,
                                            const AbstractType& type,
                                            bool negate_result,
@@ -660,12 +671,12 @@
 // - object in R0 for successful assignable check (or throws TypeError).
 // Performance notes: positive checks must be quick, negative checks can be slow
 // as they throw an exception.
-void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
+void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
                                                  intptr_t deopt_id,
                                                  const AbstractType& dst_type,
                                                  const String& dst_name,
                                                  LocationSummary* locs) {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+  ASSERT(!TokenPosition(token_pos).IsClassifying());
   ASSERT(!dst_type.IsNull());
   ASSERT(dst_type.IsFinalized());
   // Assignable check is skipped in FlowGraphBuilder, not here.
@@ -1109,13 +1120,15 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   VisitBlocks();
 
   __ brk(0);
   ASSERT(assembler()->constant_pool_allowed());
   GenerateDeferredCode();
 
-  if (is_optimizing() && Compiler::allow_recompilation()) {
+  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;
@@ -1124,12 +1137,13 @@
       __ orr(R0, ZR, Operand(R0));  // nop
     }
     lazy_deopt_pc_offset_ = assembler()->CodeSize();
-  __ BranchPatchable(*StubCode::DeoptimizeLazy_entry());
+    __ BranchPatchable(*StubCode::DeoptimizeLazy_entry());
   }
+  EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
 }
 
 
-void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
+void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
                                      const StubEntry& stub_entry,
                                      RawPcDescriptors::Kind kind,
                                      LocationSummary* locs) {
@@ -1140,7 +1154,7 @@
 
 
 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          const StubEntry& stub_entry,
                                          RawPcDescriptors::Kind kind,
                                          LocationSummary* locs) {
@@ -1160,7 +1174,35 @@
 }
 
 
-void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos,
+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,
                                             intptr_t argument_count,
@@ -1204,7 +1246,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
   // Each ICData propagated from unoptimized to optimized code contains the
@@ -1229,7 +1271,7 @@
                                          const ICData& ic_data,
                                          intptr_t argument_count,
                                          intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
   __ LoadUniqueObject(R5, ic_data);
@@ -1246,7 +1288,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     intptr_t try_index) {
   const String& name = String::Handle(zone(), ic_data.target_name());
@@ -1268,7 +1310,7 @@
 
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
-  if (Compiler::always_optimize()) {
+  if (FLAG_precompiled_mode) {
     // Megamorphic calls may occur in slow path stubs.
     // If valid use try_index argument.
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1298,7 +1340,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ Comment("SwitchableCall");
   __ LoadFromOffset(R0, SP, (argument_count - 1) * kWordSize);
@@ -1337,7 +1379,7 @@
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     const ICData& ic_data) {
   const StubEntry* stub_entry =
@@ -1357,17 +1399,17 @@
     const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ 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);
 }
 
@@ -1376,7 +1418,7 @@
     Register reg,
     const Object& obj,
     bool needs_number_check,
-    intptr_t token_pos) {
+    TokenPosition token_pos) {
   if (needs_number_check) {
     ASSERT(!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint());
     __ Push(reg);
@@ -1388,7 +1430,7 @@
       __ BranchLinkPatchable(
           *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1403,10 +1445,11 @@
 }
 
 
-Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
-                                                       Register right,
-                                                       bool needs_number_check,
-                                                       intptr_t token_pos) {
+Condition FlowGraphCompiler::EmitEqualityRegRegCompare(
+    Register left,
+    Register right,
+    bool needs_number_check,
+    TokenPosition token_pos) {
   if (needs_number_check) {
     __ Push(left);
     __ Push(right);
@@ -1417,7 +1460,7 @@
       __ BranchLinkPatchable(
           *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1506,7 +1549,7 @@
                                         Label* failed,
                                         Label* match_found,
                                         intptr_t deopt_id,
-                                        intptr_t token_index,
+                                        TokenPosition token_index,
                                         LocationSummary* locs) {
   ASSERT(is_optimizing());
 
@@ -1535,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);
@@ -1577,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 b2272fe9..2ede9e0 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -80,6 +80,11 @@
 }
 
 
+bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() {
+  return true;
+}
+
+
 void FlowGraphCompiler::EnterIntrinsicMode() {
   ASSERT(!intrinsic_mode());
   intrinsic_mode_ = true;
@@ -270,18 +275,19 @@
 // Clobbers ECX, EDI.
 RawSubtypeTestCache*
 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeWithArgumentsTest");
   ASSERT(type.IsInstantiated());
   const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-  ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+  ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
   const Register kInstanceReg = EAX;
   Error& bound_error = Error::Handle(zone());
   const Type& int_type = Type::Handle(zone(), Type::IntType());
-  const bool smi_is_ok = int_type.IsSubtypeOf(type, &bound_error, Heap::kOld);
+  const bool smi_is_ok =
+      int_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
   // Malformed type should have been handled at graph construction time.
   ASSERT(smi_is_ok || bound_error.IsNull());
   __ testl(kInstanceReg, Immediate(kSmiTagMask));
@@ -290,15 +296,15 @@
   } else {
     __ j(ZERO, is_not_instance_lbl);
   }
-  const intptr_t num_type_args = type_class.NumTypeArguments();
-  const intptr_t num_type_params = type_class.NumTypeParameters();
-  const intptr_t from_index = num_type_args - num_type_params;
-  const TypeArguments& type_arguments =
-      TypeArguments::ZoneHandle(zone(), type.arguments());
-  const bool is_raw_type = type_arguments.IsNull() ||
-      type_arguments.IsRaw(from_index, num_type_params);
-  // Signature class is an instantiated parameterized type.
-  if (!type_class.IsSignatureClass()) {
+  // A function type test requires checking the function signature.
+  if (!type.IsFunctionType()) {
+    const intptr_t num_type_args = type_class.NumTypeArguments();
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::ZoneHandle(zone(), type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
     if (is_raw_type) {
       const Register kClassIdReg = ECX;
       // dynamic type argument, check only classes.
@@ -321,7 +327,7 @@
         ASSERT(tp_argument.HasResolvedTypeClass());
         // Check if type argument is dynamic or Object.
         const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-        if (object_type.IsSubtypeOf(tp_argument, NULL, Heap::kOld)) {
+        if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
           // Instance class test only necessary.
           return GenerateSubtype1TestCacheLookup(
               token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -359,12 +365,16 @@
 // Clobbers ECX, EDI.
 // Returns true if there is a fallthrough.
 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeNoArgumentsTest");
   ASSERT(type.IsInstantiated());
+  if (type.IsFunctionType()) {
+    // Fallthrough.
+    return true;
+  }
   const Class& type_class = Class::Handle(zone(), type.type_class());
   ASSERT(type_class.NumTypeArguments() == 0);
 
@@ -376,6 +386,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ j(ZERO, is_instance_lbl);
   } else {
@@ -395,19 +406,15 @@
     __ jmp(is_not_instance_lbl);
     return false;
   }
-  if (type.IsFunctionType()) {
+  if (type.IsDartFunctionType()) {
     // Check if instance is a closure.
-    const Immediate& raw_null =
-        Immediate(reinterpret_cast<intptr_t>(Object::null()));
-    __ LoadClassById(EDI, kClassIdReg);
-    __ movl(EDI, FieldAddress(EDI, Class::signature_function_offset()));
-    __ cmpl(EDI, raw_null);
-    __ j(NOT_EQUAL, is_instance_lbl);
+    __ cmpl(kClassIdReg, Immediate(kClosureCid));
+    __ j(EQUAL, is_instance_lbl);
   }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
   if (type.IsSubtypeOf(
-          Type::Handle(zone(), Type::Number()), NULL, Heap::kOld)) {
+          Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -429,7 +436,7 @@
 // arrays can grow too high, but they may be useful when optimizing
 // code (type-feedback).
 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const Class& type_class,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -458,7 +465,7 @@
 // EAX: instance (preserved).
 // Clobbers EDX, EDI, ECX.
 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -513,7 +520,7 @@
     __ Bind(&fall_through);
     return type_test_cache.raw();
   }
-  if (type.IsType()) {
+  if (type.IsType() || type.IsFunctionType()) {
     const Register kInstanceReg = EAX;
     const Register kTypeArgumentsReg = EDX;
     __ testl(kInstanceReg, Immediate(kSmiTagMask));  // Is instance Smi?
@@ -543,7 +550,7 @@
 // may fall through to it. Otherwise, this inline code will jump to the label
 // is_instance or to the label is_not_instance.
 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -555,10 +562,10 @@
   }
   if (type.IsInstantiated()) {
     const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-    // A class equality check is only applicable with a dst type of a
-    // non-parameterized class, non-signature class, or with a raw dst type of
+    // A class equality check is only applicable with a dst type (not a
+    // function type) of a non-parameterized class or with a raw dst type of
     // a parameterized class.
-    if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+    if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
       return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
                                                        type,
                                                        is_instance_lbl,
@@ -597,7 +604,7 @@
 // Clobbers EDX.
 // Returns:
 // - true or false in EAX.
-void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
+void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
                                            intptr_t deopt_id,
                                            const AbstractType& type,
                                            bool negate_result,
@@ -679,12 +686,12 @@
 // - object in EAX for successful assignable check (or throws TypeError).
 // Performance notes: positive checks must be quick, negative checks can be slow
 // as they throw an exception.
-void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
+void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
                                                  intptr_t deopt_id,
                                                  const AbstractType& dst_type,
                                                  const String& dst_name,
                                                  LocationSummary* locs) {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+  ASSERT(!token_pos.IsClassifying());
   ASSERT(!dst_type.IsNull());
   ASSERT(dst_type.IsFinalized());
   // Assignable check is skipped in FlowGraphBuilder, not here.
@@ -1131,23 +1138,26 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   ASSERT(!block_order().is_empty());
   VisitBlocks();
 
   __ int3();
   GenerateDeferredCode();
 
-  if (is_optimizing() && Compiler::allow_recompilation()) {
+  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);
 }
 
 
-void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
+void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
                                      const StubEntry& stub_entry,
                                      RawPcDescriptors::Kind kind,
                                      LocationSummary* locs) {
@@ -1158,7 +1168,7 @@
 
 
 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          const StubEntry& stub_entry,
                                          RawPcDescriptors::Kind kind,
                                          LocationSummary* locs) {
@@ -1178,7 +1188,7 @@
 }
 
 
-void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos,
+void FlowGraphCompiler::GenerateRuntimeCall(TokenPosition token_pos,
                                             intptr_t deopt_id,
                                             const RuntimeEntry& entry,
                                             intptr_t argument_count,
@@ -1204,7 +1214,7 @@
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     const ICData& ic_data) {
   const StubEntry& stub_entry =
@@ -1237,7 +1247,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
   // Each ICData propagated from unoptimized to optimized code contains the
@@ -1261,7 +1271,7 @@
                                          const ICData& ic_data,
                                          intptr_t argument_count,
                                          intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(ic_data.arguments_descriptor()).Length() > 0);
   __ LoadObject(ECX, ic_data);
@@ -1278,7 +1288,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     intptr_t try_index) {
   const String& name = String::Handle(zone(), ic_data.target_name());
@@ -1303,7 +1313,7 @@
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
   // Precompilation not implemented on ia32 platform.
-  ASSERT(!Compiler::always_optimize());
+  ASSERT(!FLAG_precompiled_mode);
   if (is_optimizing()) {
     AddDeoptIndexAtCall(deopt_id_after, token_pos);
   } else {
@@ -1319,7 +1329,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   // Only generated with precompilation.
   UNREACHABLE();
@@ -1331,7 +1341,7 @@
     const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ LoadObject(EDX, arguments_descriptor);
   // Do not use the code from the function, but let the code be patched so that
@@ -1350,7 +1360,7 @@
     Register reg,
     const Object& obj,
     bool needs_number_check,
-    intptr_t token_pos) {
+    TokenPosition token_pos) {
   ASSERT(!needs_number_check ||
          (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()));
 
@@ -1368,7 +1378,7 @@
     } else {
       __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1383,10 +1393,11 @@
 }
 
 
-Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
-                                                       Register right,
-                                                       bool needs_number_check,
-                                                       intptr_t token_pos) {
+Condition FlowGraphCompiler::EmitEqualityRegRegCompare(
+    Register left,
+    Register right,
+    bool needs_number_check,
+    TokenPosition token_pos) {
   if (needs_number_check) {
     __ pushl(left);
     __ pushl(right);
@@ -1395,7 +1406,7 @@
     } else {
       __ Call(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1492,7 +1503,7 @@
                                         Label* failed,
                                         Label* match_found,
                                         intptr_t deopt_id,
-                                        intptr_t token_index,
+                                        TokenPosition token_index,
                                         LocationSummary* locs) {
   ASSERT(is_optimizing());
   __ Comment("EmitTestAndCall");
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index f98bb67..8f51f86 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -72,6 +72,13 @@
 }
 
 
+bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() {
+  // TODO(johnmccutchan): Investigate possibility on MIPS once
+  // mints are implemented there.
+  return false;
+}
+
+
 void FlowGraphCompiler::EnterIntrinsicMode() {
   ASSERT(!intrinsic_mode());
   intrinsic_mode_ = true;
@@ -258,18 +265,19 @@
 // Clobbers T0.
 RawSubtypeTestCache*
 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeWithArgumentsTest");
   ASSERT(type.IsInstantiated());
   const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-  ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+  ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
   const Register kInstanceReg = A0;
   Error& bound_error = Error::Handle(zone());
   const Type& int_type = Type::Handle(zone(), Type::IntType());
-  const bool smi_is_ok = int_type.IsSubtypeOf(type, &bound_error, Heap::kOld);
+  const bool smi_is_ok =
+      int_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
   // Malformed type should have been handled at graph construction time.
   ASSERT(smi_is_ok || bound_error.IsNull());
   __ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask));
@@ -278,15 +286,15 @@
   } else {
     __ beq(CMPRES1, ZR, is_not_instance_lbl);
   }
-  const intptr_t num_type_args = type_class.NumTypeArguments();
-  const intptr_t num_type_params = type_class.NumTypeParameters();
-  const intptr_t from_index = num_type_args - num_type_params;
-  const TypeArguments& type_arguments =
-      TypeArguments::ZoneHandle(zone(), type.arguments());
-  const bool is_raw_type = type_arguments.IsNull() ||
-      type_arguments.IsRaw(from_index, num_type_params);
-  // Signature class is an instantiated parameterized type.
-  if (!type_class.IsSignatureClass()) {
+  // A function type test requires checking the function signature.
+  if (!type.IsFunctionType()) {
+    const intptr_t num_type_args = type_class.NumTypeArguments();
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::ZoneHandle(zone(), type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
     if (is_raw_type) {
       const Register kClassIdReg = T0;
       // dynamic type argument, check only classes.
@@ -308,7 +316,7 @@
         ASSERT(tp_argument.HasResolvedTypeClass());
         // Check if type argument is dynamic or Object.
         const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-        if (object_type.IsSubtypeOf(tp_argument, NULL, Heap::kOld)) {
+        if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
           // Instance class test only necessary.
           return GenerateSubtype1TestCacheLookup(
               token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -347,12 +355,16 @@
 // Clobbers: T0, T1, T2
 // Returns true if there is a fallthrough.
 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeNoArgumentsTest");
   ASSERT(type.IsInstantiated());
+  if (type.IsFunctionType()) {
+    // Fallthrough.
+    return true;
+  }
   const Class& type_class = Class::Handle(zone(), type.type_class());
   ASSERT(type_class.NumTypeArguments() == 0);
 
@@ -364,6 +376,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ beq(T0, ZR, is_instance_lbl);
   } else {
@@ -382,16 +395,14 @@
     __ b(is_not_instance_lbl);
     return false;
   }
-  if (type.IsFunctionType()) {
+  if (type.IsDartFunctionType()) {
     // Check if instance is a closure.
-    __ LoadClassById(T1, kClassIdReg);
-    __ lw(T1, FieldAddress(T1, Class::signature_function_offset()));
-    __ BranchNotEqual(T1, Object::null_object(), is_instance_lbl);
+    __ BranchEqual(kClassIdReg, Immediate(kClosureCid), is_instance_lbl);
   }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
   if (type.IsSubtypeOf(
-          Type::Handle(zone(), Type::Number()), NULL, Heap::kOld)) {
+          Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -413,7 +424,7 @@
 // arrays can grow too high, but they may be useful when optimizing
 // code (type-feedback).
 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const Class& type_class,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -440,7 +451,7 @@
 // Generates inlined check if 'type' is a type parameter or type itself
 // A0: instance (preserved).
 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -493,7 +504,7 @@
     __ Bind(&fall_through);
     return type_test_cache.raw();
   }
-  if (type.IsType()) {
+  if (type.IsType() || type.IsFunctionType()) {
     const Register kInstanceReg = A0;
     const Register kTypeArgumentsReg = A1;
     __ andi(CMPRES1, kInstanceReg, Immediate(kSmiTagMask));
@@ -523,7 +534,7 @@
 // may fall through to it. Otherwise, this inline code will jump to the label
 // is_instance or to the label is_not_instance.
 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -535,10 +546,10 @@
   }
   if (type.IsInstantiated()) {
     const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-    // A class equality check is only applicable with a dst type of a
-    // non-parameterized class, non-signature class, or with a raw dst type of
+    // A class equality check is only applicable with a dst type (not a
+    // function type) of a non-parameterized class or with a raw dst type of
     // a parameterized class.
-    if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+    if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
       return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
                                                        type,
                                                        is_instance_lbl,
@@ -576,7 +587,7 @@
 // - A1: instantiator type arguments or raw_null.
 // Returns:
 // - true or false in V0.
-void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
+void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
                                            intptr_t deopt_id,
                                            const AbstractType& type,
                                            bool negate_result,
@@ -661,13 +672,13 @@
 // Clobbers: T0, T1, T2
 // Performance notes: positive checks must be quick, negative checks can be slow
 // as they throw an exception.
-void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
+void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
                                                  intptr_t deopt_id,
                                                  const AbstractType& dst_type,
                                                  const String& dst_name,
                                                  LocationSummary* locs) {
   __ Comment("AssertAssignable");
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+  ASSERT(!token_pos.IsClassifying());
   ASSERT(!dst_type.IsNull());
   ASSERT(dst_type.IsFinalized());
   // Assignable check is skipped in FlowGraphBuilder, not here.
@@ -1130,12 +1141,14 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   VisitBlocks();
 
   __ break_(0);
   GenerateDeferredCode();
 
-  if (is_optimizing() && Compiler::allow_recompilation()) {
+  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;
@@ -1146,10 +1159,11 @@
     lazy_deopt_pc_offset_ = assembler()->CodeSize();
     __ Branch(*StubCode::DeoptimizeLazy_entry());
   }
+  EndCodeSourceRange(TokenPosition::kDartCodeEpilogue);
 }
 
 
-void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
+void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
                                      const StubEntry& stub_entry,
                                      RawPcDescriptors::Kind kind,
                                      LocationSummary* locs) {
@@ -1160,7 +1174,7 @@
 
 
 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          const StubEntry& stub_entry,
                                          RawPcDescriptors::Kind kind,
                                          LocationSummary* locs) {
@@ -1182,7 +1196,37 @@
 }
 
 
-void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos,
+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,
                                             intptr_t argument_count,
@@ -1227,7 +1271,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
   // Each ICData propagated from unoptimized to optimized code contains the
@@ -1252,7 +1296,7 @@
                                          const ICData& ic_data,
                                          intptr_t argument_count,
                                          intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
   __ Comment("InstanceCall");
@@ -1271,7 +1315,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     intptr_t try_index) {
   const String& name = String::Handle(zone(), ic_data.target_name());
@@ -1293,7 +1337,7 @@
 
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
-  if (Compiler::always_optimize()) {
+  if (FLAG_precompiled_mode) {
     // Megamorphic calls may occur in slow path stubs.
     // If valid use try_index argument.
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1323,7 +1367,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ Comment("SwitchableCall");
   __ lw(T0, Address(SP, (argument_count - 1) * kWordSize));
@@ -1362,7 +1406,7 @@
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     const ICData& ic_data) {
   const StubEntry* stub_entry =
@@ -1382,18 +1426,18 @@
     const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ Comment("StaticCall");
   __ 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);
 }
 
@@ -1402,7 +1446,7 @@
     Register reg,
     const Object& obj,
     bool needs_number_check,
-    intptr_t token_pos) {
+    TokenPosition token_pos) {
   __ Comment("EqualityRegConstCompare");
   ASSERT(!needs_number_check ||
          (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()));
@@ -1419,7 +1463,7 @@
       __ BranchLinkPatchable(
           *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1437,10 +1481,11 @@
 }
 
 
-Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
-                                                       Register right,
-                                                       bool needs_number_check,
-                                                       intptr_t token_pos) {
+Condition FlowGraphCompiler::EmitEqualityRegRegCompare(
+    Register left,
+    Register right,
+    bool needs_number_check,
+    TokenPosition token_pos) {
   __ Comment("EqualityRegRegCompare");
   if (needs_number_check) {
     __ addiu(SP, SP, Immediate(-2 * kWordSize));
@@ -1453,7 +1498,7 @@
       __ BranchLinkPatchable(
           *StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1573,7 +1618,7 @@
                                         Label* failed,
                                         Label* match_found,
                                         intptr_t deopt_id,
-                                        intptr_t token_index,
+                                        TokenPosition token_index,
                                         LocationSummary* locs) {
   ASSERT(is_optimizing());
   __ Comment("EmitTestAndCall");
@@ -1601,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);
@@ -1642,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 d15e4a1..800e1dc 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -28,7 +28,6 @@
 DECLARE_FLAG(bool, enable_simd_inline);
 DECLARE_FLAG(bool, use_megamorphic_stub);
 
-
 void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
   Assembler* assembler = compiler->assembler();
 #define __ assembler->
@@ -77,6 +76,11 @@
 }
 
 
+bool FlowGraphCompiler::CanConvertUnboxedMintToDouble() {
+  return false;
+}
+
+
 void FlowGraphCompiler::EnterIntrinsicMode() {
   ASSERT(!intrinsic_mode());
   intrinsic_mode_ = true;
@@ -267,18 +271,19 @@
 // Clobbers R10.
 RawSubtypeTestCache*
 FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeWithArgumentsTest");
   ASSERT(type.IsInstantiated());
   const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-  ASSERT((type_class.NumTypeArguments() > 0) || type_class.IsSignatureClass());
+  ASSERT(type.IsFunctionType() || (type_class.NumTypeArguments() > 0));
   const Register kInstanceReg = RAX;
   Error& bound_error = Error::Handle(zone());
   const Type& int_type = Type::Handle(zone(), Type::IntType());
-  const bool smi_is_ok = int_type.IsSubtypeOf(type, &bound_error, Heap::kOld);
+  const bool smi_is_ok =
+      int_type.IsSubtypeOf(type, &bound_error, NULL, Heap::kOld);
   // Malformed type should have been handled at graph construction time.
   ASSERT(smi_is_ok || bound_error.IsNull());
   __ testq(kInstanceReg, Immediate(kSmiTagMask));
@@ -287,15 +292,15 @@
   } else {
     __ j(ZERO, is_not_instance_lbl);
   }
-  const intptr_t num_type_args = type_class.NumTypeArguments();
-  const intptr_t num_type_params = type_class.NumTypeParameters();
-  const intptr_t from_index = num_type_args - num_type_params;
-  const TypeArguments& type_arguments =
-      TypeArguments::ZoneHandle(zone(), type.arguments());
-  const bool is_raw_type = type_arguments.IsNull() ||
-      type_arguments.IsRaw(from_index, num_type_params);
-  // Signature class is an instantiated parameterized type.
-  if (!type_class.IsSignatureClass()) {
+  // A function type test requires checking the function signature.
+  if (!type.IsFunctionType()) {
+    const intptr_t num_type_args = type_class.NumTypeArguments();
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::ZoneHandle(zone(), type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
     if (is_raw_type) {
       const Register kClassIdReg = R10;
       // dynamic type argument, check only classes.
@@ -318,7 +323,7 @@
         ASSERT(tp_argument.HasResolvedTypeClass());
         // Check if type argument is dynamic or Object.
         const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-        if (object_type.IsSubtypeOf(tp_argument, NULL, Heap::kOld)) {
+        if (object_type.IsSubtypeOf(tp_argument, NULL, NULL, Heap::kOld)) {
           // Instance class test only necessary.
           return GenerateSubtype1TestCacheLookup(
               token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -356,12 +361,16 @@
 // Clobbers R10, R13.
 // Returns true if there is a fallthrough.
 bool FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
   __ Comment("InstantiatedTypeNoArgumentsTest");
   ASSERT(type.IsInstantiated());
+  if (type.IsFunctionType()) {
+    // Fallthrough.
+    return true;
+  }
   const Class& type_class = Class::Handle(zone(), type.type_class());
   ASSERT(type_class.NumTypeArguments() == 0);
 
@@ -373,6 +382,7 @@
                             type_class,
                             TypeArguments::Handle(zone()),
                             NULL,
+                            NULL,
                             Heap::kOld)) {
     __ j(ZERO, is_instance_lbl);
   } else {
@@ -392,17 +402,15 @@
     __ jmp(is_not_instance_lbl);
     return false;
   }
-  if (type.IsFunctionType()) {
+  if (type.IsDartFunctionType()) {
     // Check if instance is a closure.
-    __ LoadClassById(R13, kClassIdReg);
-    __ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
-    __ CompareObject(R13, Object::null_object());
-    __ j(NOT_EQUAL, is_instance_lbl);
+    __ cmpq(kClassIdReg, Immediate(kClosureCid));
+    __ j(EQUAL, is_instance_lbl);
   }
   // Custom checking for numbers (Smi, Mint, Bigint and Double).
   // Note that instance is not Smi (checked above).
   if (type.IsSubtypeOf(
-      Type::Handle(zone(), Type::Number()), NULL, Heap::kOld)) {
+      Type::Handle(zone(), Type::Number()), NULL, NULL, Heap::kOld)) {
     GenerateNumberTypeCheck(
         kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
     return false;
@@ -424,7 +432,7 @@
 // arrays can grow too high, but they may be useful when optimizing
 // code (type-feedback).
 RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const Class& type_class,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -453,7 +461,7 @@
 // RAX: instance (preserved).
 // Clobbers RDI, RDX, R10.
 RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -507,7 +515,7 @@
     __ Bind(&fall_through);
     return type_test_cache.raw();
   }
-  if (type.IsType()) {
+  if (type.IsType() || type.IsFunctionType()) {
     const Register kInstanceReg = RAX;
     const Register kTypeArgumentsReg = RDX;
     __ testq(kInstanceReg, Immediate(kSmiTagMask));  // Is instance Smi?
@@ -537,7 +545,7 @@
 // may fall through to it. Otherwise, this inline code will jump to the label
 // is_instance or to the label is_not_instance.
 RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const AbstractType& type,
     Label* is_instance_lbl,
     Label* is_not_instance_lbl) {
@@ -549,10 +557,10 @@
   }
   if (type.IsInstantiated()) {
     const Class& type_class = Class::ZoneHandle(zone(), type.type_class());
-    // A class equality check is only applicable with a dst type of a
-    // non-parameterized class, non-signature class, or with a raw dst type of
+    // A class equality check is only applicable with a dst type (not a
+    // function type) of a non-parameterized class or with a raw dst type of
     // a parameterized class.
-    if (type_class.IsSignatureClass() || (type_class.NumTypeArguments() > 0)) {
+    if (type.IsFunctionType() || (type_class.NumTypeArguments() > 0)) {
       return GenerateInstantiatedTypeWithArgumentsTest(token_pos,
                                                        type,
                                                        is_instance_lbl,
@@ -591,7 +599,7 @@
 // Clobbers RDX.
 // Returns:
 // - true or false in RAX.
-void FlowGraphCompiler::GenerateInstanceOf(intptr_t token_pos,
+void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos,
                                            intptr_t deopt_id,
                                            const AbstractType& type,
                                            bool negate_result,
@@ -671,12 +679,12 @@
 // - object in RAX for successful assignable check (or throws TypeError).
 // Performance notes: positive checks must be quick, negative checks can be slow
 // as they throw an exception.
-void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos,
+void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos,
                                                  intptr_t deopt_id,
                                                  const AbstractType& dst_type,
                                                  const String& dst_name,
                                                  LocationSummary* locs) {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+  ASSERT(!token_pos.IsClassifying());
   ASSERT(!dst_type.IsNull());
   ASSERT(dst_type.IsFinalized());
   // Assignable check is skipped in FlowGraphBuilder, not here.
@@ -1128,6 +1136,7 @@
     }
   }
 
+  EndCodeSourceRange(TokenPosition::kDartCodePrologue);
   ASSERT(!block_order().is_empty());
   VisitBlocks();
 
@@ -1137,17 +1146,19 @@
   // Emit function patching code. This will be swapped with the first 13 bytes
   // at entry point.
 
-  if (is_optimizing() && Compiler::allow_recompilation()) {
+  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);
 }
 
 
-void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
+void FlowGraphCompiler::GenerateCall(TokenPosition token_pos,
                                      const StubEntry& stub_entry,
                                      RawPcDescriptors::Kind kind,
                                      LocationSummary* locs) {
@@ -1158,7 +1169,7 @@
 
 
 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          const StubEntry& stub_entry,
                                          RawPcDescriptors::Kind kind,
                                          LocationSummary* locs) {
@@ -1178,7 +1189,35 @@
 }
 
 
-void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos,
+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,
                                             intptr_t argument_count,
@@ -1204,7 +1243,7 @@
 void FlowGraphCompiler::EmitUnoptimizedStaticCall(
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     const ICData& ic_data) {
   const StubEntry* stub_entry =
@@ -1238,7 +1277,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
   // Each ICData propagated from unoptimized to optimized code contains the
@@ -1262,7 +1301,7 @@
                                          const ICData& ic_data,
                                          intptr_t argument_count,
                                          intptr_t deopt_id,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          LocationSummary* locs) {
   ASSERT(Array::Handle(zone(), ic_data.arguments_descriptor()).Length() > 0);
   __ LoadUniqueObject(RBX, ic_data);
@@ -1279,7 +1318,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs,
     intptr_t try_index) {
   const String& name = String::Handle(zone(), ic_data.target_name());
@@ -1301,7 +1340,7 @@
 
   RecordSafepoint(locs);
   const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id);
-  if (Compiler::always_optimize()) {
+  if (FLAG_precompiled_mode) {
     // Megamorphic calls may occur in slow path stubs.
     // If valid use try_index argument.
     if (try_index == CatchClauseNode::kInvalidTryIndex) {
@@ -1331,7 +1370,7 @@
     const ICData& ic_data,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ Comment("SwitchableCall");
   __ movq(RDI, Address(RSP, (argument_count - 1) * kWordSize));
@@ -1372,17 +1411,17 @@
     const Array& arguments_descriptor,
     intptr_t argument_count,
     intptr_t deopt_id,
-    intptr_t token_pos,
+    TokenPosition token_pos,
     LocationSummary* locs) {
   __ 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);
 }
 
@@ -1391,7 +1430,7 @@
     Register reg,
     const Object& obj,
     bool needs_number_check,
-    intptr_t token_pos) {
+    TokenPosition token_pos) {
   ASSERT(!needs_number_check ||
          (!obj.IsMint() && !obj.IsDouble() && !obj.IsBigint()));
 
@@ -1409,7 +1448,7 @@
     } else {
       __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1424,10 +1463,11 @@
 }
 
 
-Condition FlowGraphCompiler::EmitEqualityRegRegCompare(Register left,
-                                                       Register right,
-                                                       bool needs_number_check,
-                                                       intptr_t token_pos) {
+Condition FlowGraphCompiler::EmitEqualityRegRegCompare(
+    Register left,
+    Register right,
+    bool needs_number_check,
+    TokenPosition token_pos) {
   if (needs_number_check) {
     __ pushq(left);
     __ pushq(right);
@@ -1436,7 +1476,7 @@
     } else {
       __ CallPatchable(*StubCode::UnoptimizedIdenticalWithNumberCheck_entry());
     }
-    if (token_pos >= 0) {
+    if (token_pos.IsReal()) {
       AddCurrentDescriptor(RawPcDescriptors::kRuntimeCall,
                            Thread::kNoDeoptId,
                            token_pos);
@@ -1492,7 +1532,7 @@
                                         Label* failed,
                                         Label* match_found,
                                         intptr_t deopt_id,
-                                        intptr_t token_index,
+                                        TokenPosition token_index,
                                         LocationSummary* locs) {
   ASSERT(is_optimizing());
 
@@ -1521,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);
@@ -1563,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 bc5d7bc..95a1c9f 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -4,16 +4,18 @@
 
 #include "vm/flow_graph_inliner.h"
 
+#include "vm/aot_optimizer.h"
 #include "vm/block_scheduler.h"
+#include "vm/branch_optimizer.h"
 #include "vm/compiler.h"
 #include "vm/flags.h"
 #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"
@@ -60,13 +62,13 @@
 
 DECLARE_FLAG(bool, compiler_stats);
 DECLARE_FLAG(int, max_deoptimization_counter_threshold);
-DECLARE_FLAG(bool, polymorphic_with_deopt);
 DECLARE_FLAG(bool, print_flow_graph);
 DECLARE_FLAG(bool, print_flow_graph_optimized);
 DECLARE_FLAG(bool, verify_compiler);
 
 // Quick access to the current zone.
 #define Z (zone())
+#define I (isolate())
 
 #define TRACE_INLINING(statement)                                              \
   do {                                                                         \
@@ -629,7 +631,7 @@
 
     // Function has no type feedback. With precompilation we don't rely on
     // type feedback.
-    if (!Compiler::always_optimize() &&
+    if (!FLAG_precompiled_mode &&
         function.ic_data_array() == Object::null()) {
       TRACE_INLINING(THR_Print("     Bailout: not compiled yet\n"));
       PRINT_INLINING_TREE("Not compiled",
@@ -687,213 +689,251 @@
     // Save and clear deopt id.
     const intptr_t prev_deopt_id = thread()->deopt_id();
     thread()->set_deopt_id(0);
-    // Install bailout jump.
-    LongJumpScope jump;
-    if (setjmp(*jump.Set()) == 0) {
-      // Parse the callee function.
-      bool in_cache;
-      ParsedFunction* parsed_function;
-      {
-        CSTAT_TIMER_SCOPE(thread(), graphinliner_parse_timer);
-        parsed_function = GetParsedFunction(function, &in_cache);
-      }
+    Error& error = Error::Handle();
+    {
+      // Install bailout jump.
+      LongJumpScope jump;
+      if (setjmp(*jump.Set()) == 0) {
+        // Parse the callee function.
+        bool in_cache;
+        ParsedFunction* parsed_function;
+        {
+          CSTAT_TIMER_SCOPE(thread(), graphinliner_parse_timer);
+          parsed_function = GetParsedFunction(function, &in_cache);
+        }
 
-      // Load IC data for the callee.
-      ZoneGrowableArray<const ICData*>* ic_data_array =
-            new(Z) ZoneGrowableArray<const ICData*>();
-      const bool clone_descriptors = Compiler::IsBackgroundCompilation();
-      function.RestoreICDataMap(ic_data_array, clone_descriptors);
+        // Load IC data for the callee.
+        ZoneGrowableArray<const ICData*>* ic_data_array =
+              new(Z) ZoneGrowableArray<const ICData*>();
+        const bool clone_ic_data = Compiler::IsBackgroundCompilation();
+        function.RestoreICDataMap(ic_data_array, clone_ic_data);
+        if (Compiler::IsBackgroundCompilation() &&
+            (function.ic_data_array() == Array::null())) {
+          Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
+        }
 
-      // Build the callee graph.
-      InlineExitCollector* exit_collector =
-          new(Z) InlineExitCollector(caller_graph_, call);
-      FlowGraphBuilder builder(*parsed_function,
-                               *ic_data_array,
-                               exit_collector,
-                               Compiler::kNoOSRDeoptId);
-      builder.SetInitialBlockId(caller_graph_->max_block_id());
-      FlowGraph* callee_graph;
-      {
-        CSTAT_TIMER_SCOPE(thread(), graphinliner_build_timer);
-        callee_graph = builder.BuildGraph();
-      }
+        // Build the callee graph.
+        InlineExitCollector* exit_collector =
+            new(Z) InlineExitCollector(caller_graph_, call);
+        FlowGraphBuilder builder(*parsed_function,
+                                 *ic_data_array,
+                                 exit_collector,
+                                 Compiler::kNoOSRDeoptId);
+        builder.SetInitialBlockId(caller_graph_->max_block_id());
+        FlowGraph* callee_graph;
+        {
+          CSTAT_TIMER_SCOPE(thread(), graphinliner_build_timer);
+          callee_graph = builder.BuildGraph();
+        }
 
-      // The parameter stubs are a copy of the actual arguments providing
-      // concrete information about the values, for example constant values,
-      // without linking between the caller and callee graphs.
-      // TODO(zerny): Put more information in the stubs, eg, type information.
-      ZoneGrowableArray<Definition*>* param_stubs =
-          new(Z) ZoneGrowableArray<Definition*>(
-              function.NumParameters());
+        // The parameter stubs are a copy of the actual arguments providing
+        // concrete information about the values, for example constant values,
+        // without linking between the caller and callee graphs.
+        // TODO(zerny): Put more information in the stubs, eg, type information.
+        ZoneGrowableArray<Definition*>* param_stubs =
+            new(Z) ZoneGrowableArray<Definition*>(
+                function.NumParameters());
 
-      // Create a parameter stub for each fixed positional parameter.
-      for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) {
-        param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph));
-      }
+        // Create a parameter stub for each fixed positional parameter.
+        for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) {
+          param_stubs->Add(CreateParameterStub(i, (*arguments)[i],
+                                               callee_graph));
+        }
 
-      // If the callee has optional parameters, rebuild the argument and stub
-      // arrays so that actual arguments are in one-to-one with the formal
-      // parameters.
-      if (function.HasOptionalParameters()) {
-        TRACE_INLINING(THR_Print("     adjusting for optional parameters\n"));
-        if (!AdjustForOptionalParameters(*parsed_function,
-                                         argument_names,
-                                         arguments,
-                                         param_stubs,
-                                         callee_graph)) {
-          function.set_is_inlinable(false);
-          TRACE_INLINING(THR_Print("     Bailout: optional arg mismatch\n"));
-          PRINT_INLINING_TREE("Optional arg mismatch",
+        // If the callee has optional parameters, rebuild the argument and stub
+        // arrays so that actual arguments are in one-to-one with the formal
+        // parameters.
+        if (function.HasOptionalParameters()) {
+          TRACE_INLINING(THR_Print("     adjusting for optional parameters\n"));
+          if (!AdjustForOptionalParameters(*parsed_function,
+                                           argument_names,
+                                           arguments,
+                                           param_stubs,
+                                           callee_graph)) {
+            function.set_is_inlinable(false);
+            TRACE_INLINING(THR_Print("     Bailout: optional arg mismatch\n"));
+            PRINT_INLINING_TREE("Optional arg mismatch",
+                &call_data->caller, &function, call_data->call);
+            return false;
+          }
+        }
+
+        // After treating optional parameters the actual/formal count must
+        // match.
+        ASSERT(arguments->length() == function.NumParameters());
+        ASSERT(param_stubs->length() == callee_graph->parameter_count());
+
+        // Update try-index of the callee graph.
+        BlockEntryInstr* call_block = call_data->call->GetBlock();
+        if (call_block->InsideTryBlock()) {
+          intptr_t try_index = call_block->try_index();
+          for (BlockIterator it = callee_graph->reverse_postorder_iterator();
+               !it.Done(); it.Advance()) {
+            BlockEntryInstr* block = it.Current();
+            block->set_try_index(try_index);
+          }
+        }
+
+        BlockScheduler block_scheduler(callee_graph);
+        block_scheduler.AssignEdgeWeights();
+
+        {
+          CSTAT_TIMER_SCOPE(thread(), graphinliner_ssa_timer);
+          // Compute SSA on the callee graph, catching bailouts.
+          callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(),
+                                   param_stubs);
+          DEBUG_ASSERT(callee_graph->VerifyUseLists());
+        }
+
+        {
+          CSTAT_TIMER_SCOPE(thread(), graphinliner_opt_timer);
+          // TODO(fschneider): Improve suppression of speculative inlining.
+          // Deopt-ids overlap between caller and callee.
+          if (FLAG_precompiled_mode) {
+            AotOptimizer optimizer(callee_graph,
+                                   inliner_->use_speculative_inlining_,
+                                   inliner_->inlining_black_list_);
+            optimizer.PopulateWithICData();
+
+            optimizer.ApplyClassIds();
+            DEBUG_ASSERT(callee_graph->VerifyUseLists());
+
+            FlowGraphTypePropagator::Propagate(callee_graph);
+            DEBUG_ASSERT(callee_graph->VerifyUseLists());
+
+            optimizer.ApplyICData();
+            DEBUG_ASSERT(callee_graph->VerifyUseLists());
+
+            // Optimize (a << b) & c patterns, merge instructions. Must occur
+            // before 'SelectRepresentations' which inserts conversion nodes.
+            optimizer.TryOptimizePatterns();
+            DEBUG_ASSERT(callee_graph->VerifyUseLists());
+          } else {
+            JitOptimizer optimizer(callee_graph);
+            optimizer.ApplyICData();
+            DEBUG_ASSERT(callee_graph->VerifyUseLists());
+
+            // Optimize (a << b) & c patterns, merge instructions. Must occur
+            // before 'SelectRepresentations' which inserts conversion nodes.
+            optimizer.TryOptimizePatterns();
+            DEBUG_ASSERT(callee_graph->VerifyUseLists());
+          }
+        }
+
+        if (FLAG_support_il_printer && FLAG_trace_inlining &&
+            (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
+          THR_Print("Callee graph for inlining %s\n",
+                    function.ToFullyQualifiedCString());
+          FlowGraphPrinter printer(*callee_graph);
+          printer.PrintBlocks();
+        }
+
+        // Collect information about the call site and caller graph.
+        // TODO(zerny): Do this after CP and dead code elimination.
+        intptr_t constants_count = 0;
+        for (intptr_t i = 0; i < param_stubs->length(); ++i) {
+          if ((*param_stubs)[i]->IsConstant()) ++constants_count;
+        }
+
+        FlowGraphInliner::CollectGraphInfo(callee_graph);
+        const intptr_t size = function.optimized_instruction_count();
+        const intptr_t call_site_count = function.optimized_call_site_count();
+
+        function.set_optimized_instruction_count(size);
+        function.set_optimized_call_site_count(call_site_count);
+
+        // Use heuristics do decide if this call should be inlined.
+        if (!ShouldWeInline(function, size, call_site_count, constants_count)) {
+          // If size is larger than all thresholds, don't consider it again.
+          if ((size > FLAG_inlining_size_threshold) &&
+              (call_site_count > FLAG_inlining_callee_call_sites_threshold) &&
+              (size > FLAG_inlining_constant_arguments_min_size_threshold) &&
+              (size > FLAG_inlining_constant_arguments_max_size_threshold)) {
+            function.set_is_inlinable(false);
+          }
+          thread()->set_deopt_id(prev_deopt_id);
+          TRACE_INLINING(THR_Print("     Bailout: heuristics with "
+                                   "code size:  %" Pd ", "
+                                   "call sites: %" Pd ", "
+                                   "const args: %" Pd "\n",
+                                   size,
+                                   call_site_count,
+                                   constants_count));
+          PRINT_INLINING_TREE("Heuristic fail",
               &call_data->caller, &function, call_data->call);
           return false;
         }
-      }
 
-      // After treating optional parameters the actual/formal count must match.
-      ASSERT(arguments->length() == function.NumParameters());
-      ASSERT(param_stubs->length() == callee_graph->parameter_count());
+        // Inline dispatcher methods regardless of the current depth.
+        const intptr_t depth =
+            (function.IsInvokeFieldDispatcher() ||
+             function.IsNoSuchMethodDispatcher()) ? 0 : inlining_depth_;
+        collected_call_sites_->FindCallSites(callee_graph, depth,
+                                             &inlined_info_);
 
-      // Update try-index of the callee graph.
-      BlockEntryInstr* call_block = call_data->call->GetBlock();
-      if (call_block->InsideTryBlock()) {
-        intptr_t try_index = call_block->try_index();
-        for (BlockIterator it = callee_graph->reverse_postorder_iterator();
-             !it.Done(); it.Advance()) {
-          BlockEntryInstr* block = it.Current();
-          block->set_try_index(try_index);
+        // Add the function to the cache.
+        if (!in_cache) {
+          function_cache_.Add(parsed_function);
         }
-      }
 
-      BlockScheduler block_scheduler(callee_graph);
-      block_scheduler.AssignEdgeWeights();
-
-      {
-        CSTAT_TIMER_SCOPE(thread(), graphinliner_ssa_timer);
-        // Compute SSA on the callee graph, catching bailouts.
-        callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(),
-                                 param_stubs);
-        DEBUG_ASSERT(callee_graph->VerifyUseLists());
-      }
-
-      {
-        CSTAT_TIMER_SCOPE(thread(), graphinliner_opt_timer);
-        // TODO(fschneider): Improve suppression of speculative inlining.
-        // Deopt-ids overlap between caller and callee.
-        FlowGraphOptimizer optimizer(callee_graph,
-                                     inliner_->use_speculative_inlining_,
-                                     inliner_->inlining_black_list_);
-        if (Compiler::always_optimize()) {
-          optimizer.PopulateWithICData();
-
-          optimizer.ApplyClassIds();
-          DEBUG_ASSERT(callee_graph->VerifyUseLists());
-
-          FlowGraphTypePropagator::Propagate(callee_graph);
-          DEBUG_ASSERT(callee_graph->VerifyUseLists());
-        }
-        optimizer.ApplyICData();
-        DEBUG_ASSERT(callee_graph->VerifyUseLists());
-
-        // Optimize (a << b) & c patterns, merge instructions. Must occur before
-        // 'SelectRepresentations' which inserts conversion nodes.
-        optimizer.TryOptimizePatterns();
-        DEBUG_ASSERT(callee_graph->VerifyUseLists());
-      }
-
-      if (FLAG_trace_inlining &&
-          (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
-        THR_Print("Callee graph for inlining %s\n",
-                  function.ToFullyQualifiedCString());
-        FlowGraphPrinter printer(*callee_graph);
-        printer.PrintBlocks();
-      }
-
-      // Collect information about the call site and caller graph.
-      // TODO(zerny): Do this after CP and dead code elimination.
-      intptr_t constants_count = 0;
-      for (intptr_t i = 0; i < param_stubs->length(); ++i) {
-        if ((*param_stubs)[i]->IsConstant()) ++constants_count;
-      }
-
-      FlowGraphInliner::CollectGraphInfo(callee_graph);
-      const intptr_t size = function.optimized_instruction_count();
-      const intptr_t call_site_count = function.optimized_call_site_count();
-
-      function.set_optimized_instruction_count(size);
-      function.set_optimized_call_site_count(call_site_count);
-
-      // Use heuristics do decide if this call should be inlined.
-      if (!ShouldWeInline(function, size, call_site_count, constants_count)) {
-        // If size is larger than all thresholds, don't consider it again.
-        if ((size > FLAG_inlining_size_threshold) &&
-            (call_site_count > FLAG_inlining_callee_call_sites_threshold) &&
-            (size > FLAG_inlining_constant_arguments_min_size_threshold) &&
-            (size > FLAG_inlining_constant_arguments_max_size_threshold)) {
-          function.set_is_inlinable(false);
+        // Build succeeded so we restore the bailout jump.
+        inlined_ = true;
+        inlined_size_ += size;
+        if (is_recursive_call) {
+          inlined_recursive_call_ = true;
         }
         thread()->set_deopt_id(prev_deopt_id);
-        TRACE_INLINING(THR_Print("     Bailout: heuristics with "
-                                 "code size:  %" Pd ", "
-                                 "call sites: %" Pd ", "
-                                 "const args: %" Pd "\n",
-                                 size,
-                                 call_site_count,
-                                 constants_count));
-        PRINT_INLINING_TREE("Heuristic fail",
-            &call_data->caller, &function, call_data->call);
-        return false;
+
+        call_data->callee_graph = callee_graph;
+        call_data->parameter_stubs = param_stubs;
+        call_data->exit_collector = exit_collector;
+
+        // When inlined, we add the guarded fields of the callee to the caller's
+        // list of guarded fields.
+        const ZoneGrowableArray<const Field*>& callee_guarded_fields =
+            *callee_graph->parsed_function().guarded_fields();
+        for (intptr_t i = 0; i < callee_guarded_fields.length(); ++i) {
+          caller_graph()->
+              parsed_function().AddToGuardedFields(callee_guarded_fields[i]);
+        }
+        // When inlined, we add the deferred prefixes of the callee to the
+        // caller's list of deferred prefixes.
+        caller_graph()->AddToDeferredPrefixes(
+            callee_graph->deferred_prefixes());
+
+        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,
+            &call_data->caller, &function, call);
+        return true;
+      } else {
+        error = thread()->sticky_error();
+        thread()->clear_sticky_error();
+        ASSERT(error.IsLanguageError());
+
+        if (LanguageError::Cast(error).kind() == Report::kBailout) {
+          thread()->set_deopt_id(prev_deopt_id);
+          TRACE_INLINING(THR_Print("     Bailout: %s\n",
+                                   error.ToErrorCString()));
+          PRINT_INLINING_TREE("Bailout",
+              &call_data->caller, &function, call);
+          return false;
+        } else {
+          // Fall through to exit long jump scope.
+        }
       }
-
-      // Inline dispatcher methods regardless of the current depth.
-      const intptr_t depth =
-          (function.IsInvokeFieldDispatcher() ||
-           function.IsNoSuchMethodDispatcher()) ? 0 : inlining_depth_;
-      collected_call_sites_->FindCallSites(callee_graph, depth, &inlined_info_);
-
-      // Add the function to the cache.
-      if (!in_cache) {
-        function_cache_.Add(parsed_function);
-      }
-
-      // Build succeeded so we restore the bailout jump.
-      inlined_ = true;
-      inlined_size_ += size;
-      if (is_recursive_call) {
-        inlined_recursive_call_ = true;
-      }
-      thread()->set_deopt_id(prev_deopt_id);
-
-      call_data->callee_graph = callee_graph;
-      call_data->parameter_stubs = param_stubs;
-      call_data->exit_collector = exit_collector;
-
-      // When inlined, we add the guarded fields of the callee to the caller's
-      // list of guarded fields.
-      for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) {
-        FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(),
-                                      (*callee_graph->guarded_fields())[i]);
-      }
-      // When inlined, we add the deferred prefixes of the callee to the
-      // caller's list of deferred prefixes.
-      caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes());
-
-      FlowGraphInliner::SetInliningId(callee_graph,
-          inliner_->NextInlineId(callee_graph->function(),
-                                 call_data->caller_inlining_id_));
-      TRACE_INLINING(THR_Print("     Success\n"));
-      PRINT_INLINING_TREE(NULL,
-          &call_data->caller, &function, call);
-      return true;
-    } else {
-      Error& error = Error::Handle();
-      error = isolate()->object_store()->sticky_error();
-      isolate()->object_store()->clear_sticky_error();
-      thread()->set_deopt_id(prev_deopt_id);
-      TRACE_INLINING(THR_Print("     Bailout: %s\n", error.ToErrorCString()));
-      PRINT_INLINING_TREE("Bailout",
-          &call_data->caller, &function, call);
-      return false;
     }
+
+    // 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_precompiled_mode);
+    Thread::Current()->long_jump_base()->Jump(1, error);
+    UNREACHABLE();
+    return false;
   }
 
   void PrintInlinedInfo(const Function& top) {
@@ -1105,14 +1145,13 @@
           call->ArgumentAt(0)->OriginalDefinition()->AsAllocateObject();
       if ((alloc != NULL) && !alloc->closure_function().IsNull()) {
         target ^= alloc->closure_function().raw();
-        ASSERT(target.signature_class() == alloc->cls().raw());
+        ASSERT(alloc->cls().IsClosureClass());
       }
       ConstantInstr* constant =
           call->ArgumentAt(0)->OriginalDefinition()->AsConstant();
       if ((constant != NULL) &&
-          constant->value().IsInstance() &&
-          Instance::Cast(constant->value()).IsClosure()) {
-        target ^= Closure::function(Instance::Cast(constant->value()));
+          constant->value().IsClosure()) {
+        target ^= Closure::Cast(constant->value()).function();
       }
 
       if (target.IsNull()) {
@@ -1479,9 +1518,6 @@
 
 bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid,
                                                    const Function& target) {
-  FlowGraphOptimizer optimizer(owner_->caller_graph(),
-                               false,  // Speculative inlining not applicable.
-                               NULL);
   TargetEntryInstr* entry;
   Definition* last;
   // Replace the receiver argument with a redefinition to prevent code from
@@ -1492,13 +1528,15 @@
         new(Z) RedefinitionInstr(new(Z) Value(receiver));
     redefinition->set_ssa_temp_index(
         owner_->caller_graph()->alloc_ssa_temp_index());
-  if (optimizer.TryInlineRecognizedMethod(receiver_cid,
-                                          target,
-                                          call_,
-                                          redefinition,
-                                          call_->instance_call()->token_pos(),
-                                          *call_->instance_call()->ic_data(),
-                                          &entry, &last)) {
+  if (FlowGraphInliner::TryInlineRecognizedMethod(
+          owner_->caller_graph(),
+          receiver_cid,
+          target,
+          call_,
+          redefinition,
+          call_->instance_call()->token_pos(),
+          *call_->instance_call()->ic_data(),
+          &entry, &last)) {
     // Create a graph fragment.
     redefinition->InsertAfter(entry);
     InlineExitCollector* exit_collector =
@@ -1787,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),
@@ -1880,7 +1920,8 @@
 
   TRACE_INLINING(THR_Print("Inlining calls in %s\n", top.ToCString()));
 
-  if (trace_inlining() &&
+  if (FLAG_support_il_printer &&
+      trace_inlining() &&
       (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
     THR_Print("Before Inlining of %s\n", flow_graph_->
               function().ToFullyQualifiedCString());
@@ -1898,7 +1939,8 @@
     flow_graph_->DiscoverBlocks();
     if (trace_inlining()) {
       THR_Print("Inlining growth factor: %f\n", inliner.GrowthFactor());
-      if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
+      if (FLAG_support_il_printer &&
+          (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
         THR_Print("After Inlining of %s\n", flow_graph_->
                   function().ToFullyQualifiedCString());
         FlowGraphPrinter printer(*flow_graph_);
@@ -1910,12 +1952,1121 @@
 
 
 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;
 }
 
 
+static bool ShouldInlineSimd() {
+  return FlowGraphCompiler::SupportsUnboxedSimd128();
+}
+
+
+static bool CanUnboxDouble() {
+  return FlowGraphCompiler::SupportsUnboxedDoubles();
+}
+
+
+static bool ShouldInlineInt64ArrayOps() {
+#if defined(TARGET_ARCH_X64)
+  return true;
+#else
+  return false;
+#endif
+}
+
+
+static bool CanUnboxInt32() {
+  // Int32/Uint32 can be unboxed if it fits into a smi or the platform
+  // supports unboxed mints.
+  return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints();
+}
+
+
+// Quick access to the current one.
+#undef Z
+#define Z (flow_graph->zone())
+
+static intptr_t PrepareInlineIndexedOp(FlowGraph* flow_graph,
+                                       Instruction* call,
+                                       intptr_t array_cid,
+                                       Definition** array,
+                                       Definition* index,
+                                       Instruction** cursor) {
+  // Insert index smi check.
+  *cursor = flow_graph->AppendTo(
+      *cursor,
+      new(Z) CheckSmiInstr(new(Z) Value(index),
+                           call->deopt_id(),
+                           call->token_pos()),
+      call->env(),
+      FlowGraph::kEffect);
+
+  // Insert array length load and bounds check.
+  LoadFieldInstr* length =
+      new(Z) LoadFieldInstr(
+          new(Z) Value(*array),
+          CheckArrayBoundInstr::LengthOffsetFor(array_cid),
+          Type::ZoneHandle(Z, Type::SmiType()),
+          call->token_pos());
+  length->set_is_immutable(
+      CheckArrayBoundInstr::IsFixedLengthArrayType(array_cid));
+  length->set_result_cid(kSmiCid);
+  length->set_recognized_kind(
+      LoadFieldInstr::RecognizedKindFromArrayCid(array_cid));
+  *cursor = flow_graph->AppendTo(*cursor,
+                                 length,
+                                 NULL,
+                                 FlowGraph::kValue);
+
+  *cursor = flow_graph->AppendTo(*cursor,
+                                 new(Z) CheckArrayBoundInstr(
+                                     new(Z) Value(length),
+                                     new(Z) Value(index),
+                                     call->deopt_id()),
+                                 call->env(),
+                                 FlowGraph::kEffect);
+
+  if (array_cid == kGrowableObjectArrayCid) {
+    // Insert data elements load.
+    LoadFieldInstr* elements =
+        new(Z) LoadFieldInstr(
+            new(Z) Value(*array),
+            GrowableObjectArray::data_offset(),
+            Object::dynamic_type(),
+            call->token_pos());
+    elements->set_result_cid(kArrayCid);
+    *cursor = flow_graph->AppendTo(*cursor,
+                                   elements,
+                                   NULL,
+                                   FlowGraph::kValue);
+    // Load from the data from backing store which is a fixed-length array.
+    *array = elements;
+    array_cid = kArrayCid;
+  } else if (RawObject::IsExternalTypedDataClassId(array_cid)) {
+    LoadUntaggedInstr* elements =
+        new(Z) LoadUntaggedInstr(new(Z) Value(*array),
+                                 ExternalTypedData::data_offset());
+    *cursor = flow_graph->AppendTo(*cursor,
+                                   elements,
+                                   NULL,
+                                   FlowGraph::kValue);
+    *array = elements;
+  }
+  return array_cid;
+}
+
+
+static intptr_t MethodKindToCid(MethodRecognizer::Kind kind) {
+  switch (kind) {
+    case MethodRecognizer::kImmutableArrayGetIndexed:
+      return kImmutableArrayCid;
+
+    case MethodRecognizer::kObjectArrayGetIndexed:
+    case MethodRecognizer::kObjectArraySetIndexed:
+      return kArrayCid;
+
+    case MethodRecognizer::kGrowableArrayGetIndexed:
+    case MethodRecognizer::kGrowableArraySetIndexed:
+      return kGrowableObjectArrayCid;
+
+    case MethodRecognizer::kFloat32ArrayGetIndexed:
+    case MethodRecognizer::kFloat32ArraySetIndexed:
+      return kTypedDataFloat32ArrayCid;
+
+    case MethodRecognizer::kFloat64ArrayGetIndexed:
+    case MethodRecognizer::kFloat64ArraySetIndexed:
+      return kTypedDataFloat64ArrayCid;
+
+    case MethodRecognizer::kInt8ArrayGetIndexed:
+    case MethodRecognizer::kInt8ArraySetIndexed:
+      return kTypedDataInt8ArrayCid;
+
+    case MethodRecognizer::kUint8ArrayGetIndexed:
+    case MethodRecognizer::kUint8ArraySetIndexed:
+      return kTypedDataUint8ArrayCid;
+
+    case MethodRecognizer::kUint8ClampedArrayGetIndexed:
+    case MethodRecognizer::kUint8ClampedArraySetIndexed:
+      return kTypedDataUint8ClampedArrayCid;
+
+    case MethodRecognizer::kExternalUint8ArrayGetIndexed:
+    case MethodRecognizer::kExternalUint8ArraySetIndexed:
+      return kExternalTypedDataUint8ArrayCid;
+
+    case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
+    case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
+      return kExternalTypedDataUint8ClampedArrayCid;
+
+    case MethodRecognizer::kInt16ArrayGetIndexed:
+    case MethodRecognizer::kInt16ArraySetIndexed:
+      return kTypedDataInt16ArrayCid;
+
+    case MethodRecognizer::kUint16ArrayGetIndexed:
+    case MethodRecognizer::kUint16ArraySetIndexed:
+      return kTypedDataUint16ArrayCid;
+
+    case MethodRecognizer::kInt32ArrayGetIndexed:
+    case MethodRecognizer::kInt32ArraySetIndexed:
+      return kTypedDataInt32ArrayCid;
+
+    case MethodRecognizer::kUint32ArrayGetIndexed:
+    case MethodRecognizer::kUint32ArraySetIndexed:
+      return kTypedDataUint32ArrayCid;
+
+    case MethodRecognizer::kInt64ArrayGetIndexed:
+    case MethodRecognizer::kInt64ArraySetIndexed:
+      return kTypedDataInt64ArrayCid;
+
+    case MethodRecognizer::kFloat32x4ArrayGetIndexed:
+    case MethodRecognizer::kFloat32x4ArraySetIndexed:
+      return kTypedDataFloat32x4ArrayCid;
+
+    case MethodRecognizer::kInt32x4ArrayGetIndexed:
+    case MethodRecognizer::kInt32x4ArraySetIndexed:
+      return kTypedDataInt32x4ArrayCid;
+
+    case MethodRecognizer::kFloat64x2ArrayGetIndexed:
+    case MethodRecognizer::kFloat64x2ArraySetIndexed:
+      return kTypedDataFloat64x2ArrayCid;
+
+    default:
+      break;
+  }
+  return kIllegalCid;
+}
+
+
+static Instruction* GetCheckClass(FlowGraph* flow_graph,
+                                  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),
+                                deopt_id,
+                                token_pos);
+  }
+  return new(Z) CheckClassInstr(
+      new(Z) Value(to_check), deopt_id, unary_checks, token_pos);
+}
+
+
+static bool InlineGetIndexed(FlowGraph* flow_graph,
+                             MethodRecognizer::Kind kind,
+                             Instruction* call,
+                             Definition* receiver,
+                             TargetEntryInstr** entry,
+                             Definition** last) {
+  intptr_t array_cid = MethodKindToCid(kind);
+  ASSERT(array_cid != kIllegalCid);
+
+  Definition* array = receiver;
+  Definition* index = call->ArgumentAt(1);
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+
+  array_cid = PrepareInlineIndexedOp(flow_graph,
+                                     call,
+                                     array_cid,
+                                     &array,
+                                     index,
+                                     &cursor);
+
+  intptr_t deopt_id = Thread::kNoDeoptId;
+  if ((array_cid == kTypedDataInt32ArrayCid) ||
+      (array_cid == kTypedDataUint32ArrayCid)) {
+    // Deoptimization may be needed if result does not always fit in a Smi.
+    deopt_id = (kSmiBits >= 32) ? Thread::kNoDeoptId : call->deopt_id();
+  }
+
+  // Array load and return.
+  intptr_t index_scale = Instance::ElementSizeFor(array_cid);
+  *last = new(Z) LoadIndexedInstr(new(Z) Value(array),
+                                  new(Z) Value(index),
+                                  index_scale,
+                                  array_cid,
+                                  deopt_id,
+                                  call->token_pos());
+  cursor = flow_graph->AppendTo(
+      cursor,
+      *last,
+      deopt_id != Thread::kNoDeoptId ? call->env() : NULL,
+      FlowGraph::kValue);
+
+  if (array_cid == kTypedDataFloat32ArrayCid) {
+    *last = new(Z) FloatToDoubleInstr(new(Z) Value(*last), deopt_id);
+    flow_graph->AppendTo(cursor,
+                         *last,
+                         deopt_id != Thread::kNoDeoptId ? call->env() : NULL,
+                         FlowGraph::kValue);
+  }
+  return true;
+}
+
+
+static bool InlineSetIndexed(FlowGraph* flow_graph,
+                             MethodRecognizer::Kind kind,
+                             const Function& target,
+                             Instruction* call,
+                             Definition* receiver,
+                             TokenPosition token_pos,
+                             const ICData& value_check,
+                             TargetEntryInstr** entry,
+                             Definition** last) {
+  intptr_t array_cid = MethodKindToCid(kind);
+  ASSERT(array_cid != kIllegalCid);
+
+  Definition* array = receiver;
+  Definition* index = call->ArgumentAt(1);
+  Definition* stored_value = call->ArgumentAt(2);
+
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+  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.
+    const AbstractType& value_type =
+        AbstractType::ZoneHandle(Z, target.ParameterTypeAt(2));
+    Definition* type_args = NULL;
+    switch (array_cid) {
+      case kArrayCid:
+      case kGrowableObjectArrayCid: {
+        const Class& instantiator_class =  Class::Handle(Z, target.Owner());
+        intptr_t type_arguments_field_offset =
+            instantiator_class.type_arguments_field_offset();
+        LoadFieldInstr* load_type_args =
+            new(Z) LoadFieldInstr(new(Z) Value(array),
+                                  type_arguments_field_offset,
+                                  Type::ZoneHandle(Z),  // No type.
+                                  call->token_pos());
+        cursor = flow_graph->AppendTo(cursor,
+                                      load_type_args,
+                                      NULL,
+                                      FlowGraph::kValue);
+
+        type_args = load_type_args;
+        break;
+      }
+      case kTypedDataInt8ArrayCid:
+      case kTypedDataUint8ArrayCid:
+      case kTypedDataUint8ClampedArrayCid:
+      case kExternalTypedDataUint8ArrayCid:
+      case kExternalTypedDataUint8ClampedArrayCid:
+      case kTypedDataInt16ArrayCid:
+      case kTypedDataUint16ArrayCid:
+      case kTypedDataInt32ArrayCid:
+      case kTypedDataUint32ArrayCid:
+      case kTypedDataInt64ArrayCid:
+        ASSERT(value_type.IsIntType());
+        // Fall through.
+      case kTypedDataFloat32ArrayCid:
+      case kTypedDataFloat64ArrayCid: {
+        type_args = flow_graph->constant_null();
+        ASSERT((array_cid != kTypedDataFloat32ArrayCid &&
+                array_cid != kTypedDataFloat64ArrayCid) ||
+               value_type.IsDoubleType());
+        ASSERT(value_type.IsInstantiated());
+        break;
+      }
+      case kTypedDataFloat32x4ArrayCid: {
+        type_args = flow_graph->constant_null();
+        ASSERT((array_cid != kTypedDataFloat32x4ArrayCid) ||
+               value_type.IsFloat32x4Type());
+        ASSERT(value_type.IsInstantiated());
+        break;
+      }
+      case kTypedDataFloat64x2ArrayCid: {
+        type_args = flow_graph->constant_null();
+        ASSERT((array_cid != kTypedDataFloat64x2ArrayCid) ||
+               value_type.IsFloat64x2Type());
+        ASSERT(value_type.IsInstantiated());
+        break;
+      }
+      default:
+        // TODO(fschneider): Add support for other array types.
+        UNREACHABLE();
+    }
+    AssertAssignableInstr* assert_value =
+        new(Z) AssertAssignableInstr(token_pos,
+                                     new(Z) Value(stored_value),
+                                     new(Z) Value(type_args),
+                                     value_type,
+                                     Symbols::Value(),
+                                     call->deopt_id());
+    cursor = flow_graph->AppendTo(cursor,
+                                  assert_value,
+                                  call->env(),
+                                  FlowGraph::kValue);
+  }
+
+  array_cid = PrepareInlineIndexedOp(flow_graph,
+                                     call,
+                                     array_cid,
+                                     &array,
+                                     index,
+                                     &cursor);
+
+  // Check if store barrier is needed. Byte arrays don't need a store barrier.
+  StoreBarrierType needs_store_barrier =
+      (RawObject::IsTypedDataClassId(array_cid) ||
+       RawObject::IsTypedDataViewClassId(array_cid) ||
+       RawObject::IsExternalTypedDataClassId(array_cid)) ? kNoStoreBarrier
+                                                         : kEmitStoreBarrier;
+
+  // No need to class check stores to Int32 and Uint32 arrays because
+  // we insert unboxing instructions below which include a class check.
+  if ((array_cid != kTypedDataUint32ArrayCid) &&
+      (array_cid != kTypedDataInt32ArrayCid) &&
+      !value_check.IsNull()) {
+    // No store barrier needed because checked value is a smi, an unboxed mint,
+    // an unboxed double, an unboxed Float32x4, or unboxed Int32x4.
+    needs_store_barrier = kNoStoreBarrier;
+    Instruction* check = GetCheckClass(flow_graph,
+                                       stored_value,
+                                       value_check,
+                                       call->deopt_id(),
+                                       call->token_pos());
+    cursor = flow_graph->AppendTo(cursor,
+                                  check,
+                                  call->env(),
+                                  FlowGraph::kEffect);
+  }
+
+  if (array_cid == kTypedDataFloat32ArrayCid) {
+    stored_value =
+        new(Z) DoubleToFloatInstr(
+            new(Z) Value(stored_value), call->deopt_id());
+    cursor = flow_graph->AppendTo(cursor,
+                                  stored_value,
+                                  NULL,
+                                  FlowGraph::kValue);
+  } else if (array_cid == kTypedDataInt32ArrayCid) {
+    stored_value = new(Z) UnboxInt32Instr(
+        UnboxInt32Instr::kTruncate,
+        new(Z) Value(stored_value),
+        call->deopt_id());
+    cursor = flow_graph->AppendTo(cursor,
+                                  stored_value,
+                                  call->env(),
+                                  FlowGraph::kValue);
+  } else if (array_cid == kTypedDataUint32ArrayCid) {
+    stored_value = new(Z) UnboxUint32Instr(
+        new(Z) Value(stored_value),
+        call->deopt_id());
+    ASSERT(stored_value->AsUnboxInteger()->is_truncating());
+    cursor = flow_graph->AppendTo(cursor,
+                                  stored_value,
+                                  call->env(),
+                                  FlowGraph::kValue);
+  }
+
+  const intptr_t index_scale = Instance::ElementSizeFor(array_cid);
+  *last = new(Z) StoreIndexedInstr(new(Z) Value(array),
+                                   new(Z) Value(index),
+                                   new(Z) Value(stored_value),
+                                   needs_store_barrier,
+                                   index_scale,
+                                   array_cid,
+                                   call->deopt_id(),
+                                   call->token_pos());
+  flow_graph->AppendTo(cursor,
+                       *last,
+                       call->env(),
+                       FlowGraph::kEffect);
+  return true;
+}
+
+
+static bool InlineDoubleOp(FlowGraph* flow_graph,
+                           Token::Kind op_kind,
+                           Instruction* call,
+                           TargetEntryInstr** entry,
+                           Definition** last) {
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  // Arguments are checked. No need for class check.
+  BinaryDoubleOpInstr* double_bin_op =
+      new(Z) BinaryDoubleOpInstr(op_kind,
+                                 new(Z) Value(left),
+                                 new(Z) Value(right),
+                                 call->deopt_id(), call->token_pos());
+  flow_graph->AppendTo(*entry, double_bin_op, call->env(), FlowGraph::kValue);
+  *last = double_bin_op;
+
+  return true;
+}
+
+
+static intptr_t PrepareInlineByteArrayBaseOp(
+    FlowGraph* flow_graph,
+    Instruction* call,
+    intptr_t array_cid,
+    intptr_t view_cid,
+    Definition** array,
+    Definition* byte_index,
+    Instruction** cursor) {
+  // Insert byte_index smi check.
+  *cursor = flow_graph->AppendTo(*cursor,
+                                 new(Z) CheckSmiInstr(
+                                     new(Z) Value(byte_index),
+                                     call->deopt_id(),
+                                     call->token_pos()),
+                                 call->env(),
+                                 FlowGraph::kEffect);
+
+  LoadFieldInstr* length =
+      new(Z) LoadFieldInstr(
+          new(Z) Value(*array),
+          CheckArrayBoundInstr::LengthOffsetFor(array_cid),
+          Type::ZoneHandle(Z, Type::SmiType()),
+          call->token_pos());
+  length->set_is_immutable(true);
+  length->set_result_cid(kSmiCid);
+  length->set_recognized_kind(
+      LoadFieldInstr::RecognizedKindFromArrayCid(array_cid));
+  *cursor = flow_graph->AppendTo(*cursor,
+                                 length,
+                                 NULL,
+                                 FlowGraph::kValue);
+
+  intptr_t element_size = Instance::ElementSizeFor(array_cid);
+  ConstantInstr* bytes_per_element =
+      flow_graph->GetConstant(Smi::Handle(Z, Smi::New(element_size)));
+  BinarySmiOpInstr* len_in_bytes =
+      new(Z) BinarySmiOpInstr(Token::kMUL,
+                              new(Z) Value(length),
+                              new(Z) Value(bytes_per_element),
+                              call->deopt_id());
+  *cursor = flow_graph->AppendTo(*cursor, len_in_bytes, call->env(),
+                                 FlowGraph::kValue);
+
+  // adjusted_length = len_in_bytes - (element_size - 1).
+  Definition* adjusted_length = len_in_bytes;
+  intptr_t adjustment = Instance::ElementSizeFor(view_cid) - 1;
+  if (adjustment > 0) {
+    ConstantInstr* length_adjustment =
+        flow_graph->GetConstant(Smi::Handle(Z, Smi::New(adjustment)));
+    adjusted_length =
+        new(Z) BinarySmiOpInstr(Token::kSUB,
+                                new(Z) Value(len_in_bytes),
+                                new(Z) Value(length_adjustment),
+                                call->deopt_id());
+    *cursor = flow_graph->AppendTo(*cursor, adjusted_length, call->env(),
+                                   FlowGraph::kValue);
+  }
+
+  // Check adjusted_length > 0.
+  ConstantInstr* zero =
+      flow_graph->GetConstant(Smi::Handle(Z, Smi::New(0)));
+  *cursor = flow_graph->AppendTo(*cursor,
+                                 new(Z) CheckArrayBoundInstr(
+                                     new(Z) Value(adjusted_length),
+                                     new(Z) Value(zero),
+                                     call->deopt_id()),
+                                 call->env(),
+                                 FlowGraph::kEffect);
+  // Check 0 <= byte_index < adjusted_length.
+  *cursor = flow_graph->AppendTo(*cursor,
+                                 new(Z) CheckArrayBoundInstr(
+                                     new(Z) Value(adjusted_length),
+                                     new(Z) Value(byte_index),
+                                     call->deopt_id()),
+                                 call->env(),
+                                 FlowGraph::kEffect);
+
+  if (RawObject::IsExternalTypedDataClassId(array_cid)) {
+    LoadUntaggedInstr* elements =
+        new(Z) LoadUntaggedInstr(new(Z) Value(*array),
+                                 ExternalTypedData::data_offset());
+    *cursor = flow_graph->AppendTo(*cursor,
+                                   elements,
+                                   NULL,
+                                   FlowGraph::kValue);
+    *array = elements;
+  }
+  return array_cid;
+}
+
+
+static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph,
+                                    Instruction* call,
+                                    Definition* receiver,
+                                    intptr_t array_cid,
+                                    intptr_t view_cid,
+                                    TargetEntryInstr** entry,
+                                    Definition** last) {
+  ASSERT(array_cid != kIllegalCid);
+  Definition* array = receiver;
+  Definition* index = call->ArgumentAt(1);
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+
+  array_cid = PrepareInlineByteArrayBaseOp(flow_graph,
+                                           call,
+                                           array_cid,
+                                           view_cid,
+                                           &array,
+                                           index,
+                                           &cursor);
+
+  intptr_t deopt_id = Thread::kNoDeoptId;
+  if ((array_cid == kTypedDataInt32ArrayCid) ||
+      (array_cid == kTypedDataUint32ArrayCid)) {
+    // Deoptimization may be needed if result does not always fit in a Smi.
+    deopt_id = (kSmiBits >= 32) ? Thread::kNoDeoptId : call->deopt_id();
+  }
+
+  *last = new(Z) LoadIndexedInstr(new(Z) Value(array),
+                                  new(Z) Value(index),
+                                  1,
+                                  view_cid,
+                                  deopt_id,
+                                  call->token_pos());
+  cursor = flow_graph->AppendTo(
+      cursor,
+      *last,
+      deopt_id != Thread::kNoDeoptId ? call->env() : NULL,
+      FlowGraph::kValue);
+
+  if (view_cid == kTypedDataFloat32ArrayCid) {
+    *last = new(Z) FloatToDoubleInstr(new(Z) Value(*last), deopt_id);
+    flow_graph->AppendTo(cursor,
+                         *last,
+                         deopt_id != Thread::kNoDeoptId ? call->env() : NULL,
+                         FlowGraph::kValue);
+  }
+  return true;
+}
+
+
+static bool InlineByteArrayBaseStore(FlowGraph* flow_graph,
+                                     const Function& target,
+                                     Instruction* call,
+                                     Definition* receiver,
+                                     intptr_t array_cid,
+                                     intptr_t view_cid,
+                                     TargetEntryInstr** entry,
+                                     Definition** last) {
+  ASSERT(array_cid != kIllegalCid);
+  Definition* array = receiver;
+  Definition* index = call->ArgumentAt(1);
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+  Instruction* cursor = *entry;
+
+  array_cid = PrepareInlineByteArrayBaseOp(flow_graph,
+                                           call,
+                                           array_cid,
+                                           view_cid,
+                                           &array,
+                                           index,
+                                           &cursor);
+
+  // Extract the instance call so we can use the function_name in the stored
+  // value check ICData.
+  InstanceCallInstr* i_call = NULL;
+  if (call->IsPolymorphicInstanceCall()) {
+    i_call = call->AsPolymorphicInstanceCall()->instance_call();
+  } else {
+    ASSERT(call->IsInstanceCall());
+    i_call = call->AsInstanceCall();
+  }
+  ASSERT(i_call != NULL);
+  ICData& value_check = ICData::ZoneHandle(Z);
+  switch (view_cid) {
+    case kTypedDataInt8ArrayCid:
+    case kTypedDataUint8ArrayCid:
+    case kTypedDataUint8ClampedArrayCid:
+    case kExternalTypedDataUint8ArrayCid:
+    case kExternalTypedDataUint8ClampedArrayCid:
+    case kTypedDataInt16ArrayCid:
+    case kTypedDataUint16ArrayCid: {
+      // Check that value is always smi.
+      value_check = ICData::New(flow_graph->function(),
+                                i_call->function_name(),
+                                Object::empty_array(),  // Dummy args. descr.
+                                Thread::kNoDeoptId,
+                                1);
+      value_check.AddReceiverCheck(kSmiCid, target);
+      break;
+    }
+    case kTypedDataInt32ArrayCid:
+    case kTypedDataUint32ArrayCid:
+      // On 64-bit platforms assume that stored value is always a smi.
+      if (kSmiBits >= 32) {
+        value_check = ICData::New(flow_graph->function(),
+                                  i_call->function_name(),
+                                  Object::empty_array(),  // Dummy args. descr.
+                                  Thread::kNoDeoptId,
+                                  1);
+        value_check.AddReceiverCheck(kSmiCid, target);
+      }
+      break;
+    case kTypedDataFloat32ArrayCid:
+    case kTypedDataFloat64ArrayCid: {
+      // Check that value is always double.
+      value_check = ICData::New(flow_graph->function(),
+                                i_call->function_name(),
+                                Object::empty_array(),  // Dummy args. descr.
+                                Thread::kNoDeoptId,
+                                1);
+      value_check.AddReceiverCheck(kDoubleCid, target);
+      break;
+    }
+    case kTypedDataInt32x4ArrayCid: {
+      // Check that value is always Int32x4.
+      value_check = ICData::New(flow_graph->function(),
+                                i_call->function_name(),
+                                Object::empty_array(),  // Dummy args. descr.
+                                Thread::kNoDeoptId,
+                                1);
+      value_check.AddReceiverCheck(kInt32x4Cid, target);
+      break;
+    }
+    case kTypedDataFloat32x4ArrayCid: {
+      // Check that value is always Float32x4.
+      value_check = ICData::New(flow_graph->function(),
+                                i_call->function_name(),
+                                Object::empty_array(),  // Dummy args. descr.
+                                Thread::kNoDeoptId,
+                                1);
+      value_check.AddReceiverCheck(kFloat32x4Cid, target);
+      break;
+    }
+    default:
+      // Array cids are already checked in the caller.
+      UNREACHABLE();
+  }
+
+  Definition* stored_value = call->ArgumentAt(2);
+  if (!value_check.IsNull()) {
+    Instruction* check = GetCheckClass(flow_graph,
+                                       stored_value,
+                                       value_check,
+                                       call->deopt_id(),
+                                       call->token_pos());
+    cursor = flow_graph->AppendTo(cursor,
+                                  check,
+                                  call->env(),
+                                  FlowGraph::kEffect);
+  }
+
+  if (view_cid == kTypedDataFloat32ArrayCid) {
+    stored_value = new(Z) DoubleToFloatInstr(
+        new(Z) Value(stored_value), call->deopt_id());
+    cursor = flow_graph->AppendTo(cursor,
+                                  stored_value,
+                                  NULL,
+                                  FlowGraph::kValue);
+  } else if (view_cid == kTypedDataInt32ArrayCid) {
+    stored_value = new(Z) UnboxInt32Instr(
+        UnboxInt32Instr::kTruncate,
+        new(Z) Value(stored_value),
+        call->deopt_id());
+    cursor = flow_graph->AppendTo(cursor,
+                                  stored_value,
+                                  call->env(),
+                                  FlowGraph::kValue);
+  } else if (view_cid == kTypedDataUint32ArrayCid) {
+    stored_value = new(Z) UnboxUint32Instr(
+        new(Z) Value(stored_value),
+        call->deopt_id());
+    ASSERT(stored_value->AsUnboxInteger()->is_truncating());
+    cursor = flow_graph->AppendTo(cursor,
+                                  stored_value,
+                                  call->env(),
+                                  FlowGraph::kValue);
+  }
+
+  StoreBarrierType needs_store_barrier = kNoStoreBarrier;
+  *last = new(Z) StoreIndexedInstr(new(Z) Value(array),
+                                   new(Z) Value(index),
+                                   new(Z) Value(stored_value),
+                                   needs_store_barrier,
+                                   1,  // Index scale
+                                   view_cid,
+                                   call->deopt_id(),
+                                   call->token_pos());
+
+  flow_graph->AppendTo(cursor,
+                       *last,
+                       call->deopt_id() != Thread::kNoDeoptId ?
+                          call->env() : NULL,
+                       FlowGraph::kEffect);
+  return true;
+}
+
+
+
+// Returns the LoadIndexedInstr.
+static Definition* PrepareInlineStringIndexOp(
+    FlowGraph* flow_graph,
+    Instruction* call,
+    intptr_t cid,
+    Definition* str,
+    Definition* index,
+    Instruction* cursor) {
+
+  cursor = flow_graph->AppendTo(cursor,
+                                new(Z) CheckSmiInstr(
+                                    new(Z) Value(index),
+                                    call->deopt_id(),
+                                    call->token_pos()),
+                                call->env(),
+                                FlowGraph::kEffect);
+
+  // Load the length of the string.
+  // Treat length loads as mutable (i.e. affected by side effects) to avoid
+  // hoisting them since we can't hoist the preceding class-check. This
+  // is because of externalization of strings that affects their class-id.
+  LoadFieldInstr* length = new(Z) LoadFieldInstr(
+      new(Z) Value(str),
+      String::length_offset(),
+      Type::ZoneHandle(Z, Type::SmiType()),
+      str->token_pos());
+  length->set_result_cid(kSmiCid);
+  length->set_recognized_kind(MethodRecognizer::kStringBaseLength);
+
+  cursor = flow_graph->AppendTo(cursor, length, NULL, FlowGraph::kValue);
+  // Bounds check.
+  cursor = flow_graph->AppendTo(cursor,
+                                new(Z) CheckArrayBoundInstr(
+                                    new(Z) Value(length),
+                                    new(Z) Value(index),
+                                    call->deopt_id()),
+                                call->env(),
+                                FlowGraph::kEffect);
+
+  LoadIndexedInstr* load_indexed = new(Z) LoadIndexedInstr(
+      new(Z) Value(str),
+      new(Z) Value(index),
+      Instance::ElementSizeFor(cid),
+      cid,
+      Thread::kNoDeoptId,
+      call->token_pos());
+
+  cursor = flow_graph->AppendTo(cursor, load_indexed, NULL, FlowGraph::kValue);
+  ASSERT(cursor == load_indexed);
+  return load_indexed;
+}
+
+
+static bool InlineStringBaseCharAt(
+    FlowGraph* flow_graph,
+    Instruction* call,
+    intptr_t cid,
+    TargetEntryInstr** entry,
+    Definition** last) {
+  // TODO(johnmccutchan): Handle external strings in PrepareInlineStringIndexOp.
+  if (RawObject::IsExternalStringClassId(cid) || cid != kOneByteStringCid) {
+    return false;
+  }
+  Definition* str = call->ArgumentAt(0);
+  Definition* index = call->ArgumentAt(1);
+
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+
+  *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry);
+
+  StringFromCharCodeInstr* char_at = new(Z) StringFromCharCodeInstr(
+      new(Z) Value(*last), cid);
+
+  flow_graph->AppendTo(*last, char_at, NULL, FlowGraph::kValue);
+  *last = char_at;
+
+  return true;
+}
+
+
+static bool InlineStringCodeUnitAt(
+    FlowGraph* flow_graph,
+    Instruction* call,
+    intptr_t cid,
+    TargetEntryInstr** entry,
+    Definition** last) {
+  // TODO(johnmccutchan): Handle external strings in PrepareInlineStringIndexOp.
+  if (RawObject::IsExternalStringClassId(cid)) {
+    return false;
+  }
+
+  Definition* str = call->ArgumentAt(0);
+  Definition* index = call->ArgumentAt(1);
+
+  *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+                                   call->GetBlock()->try_index());
+  (*entry)->InheritDeoptTarget(Z, call);
+
+  *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry);
+
+  return true;
+}
+
+
+bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph,
+                                                 intptr_t receiver_cid,
+                                                 const Function& target,
+                                                 Instruction* call,
+                                                 Definition* receiver,
+                                                 TokenPosition token_pos,
+                                                 const ICData& ic_data,
+                                                 TargetEntryInstr** entry,
+                                                 Definition** last) {
+  ICData& value_check = ICData::ZoneHandle(Z);
+  MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target);
+  switch (kind) {
+    // Recognized [] operators.
+    case MethodRecognizer::kImmutableArrayGetIndexed:
+    case MethodRecognizer::kObjectArrayGetIndexed:
+    case MethodRecognizer::kGrowableArrayGetIndexed:
+    case MethodRecognizer::kInt8ArrayGetIndexed:
+    case MethodRecognizer::kUint8ArrayGetIndexed:
+    case MethodRecognizer::kUint8ClampedArrayGetIndexed:
+    case MethodRecognizer::kExternalUint8ArrayGetIndexed:
+    case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
+    case MethodRecognizer::kInt16ArrayGetIndexed:
+    case MethodRecognizer::kUint16ArrayGetIndexed:
+      return InlineGetIndexed(flow_graph, kind, call, receiver, entry, last);
+    case MethodRecognizer::kFloat32ArrayGetIndexed:
+    case MethodRecognizer::kFloat64ArrayGetIndexed:
+      if (!CanUnboxDouble()) {
+        return false;
+      }
+      return InlineGetIndexed(flow_graph, kind, call, receiver, entry, last);
+    case MethodRecognizer::kFloat32x4ArrayGetIndexed:
+    case MethodRecognizer::kFloat64x2ArrayGetIndexed:
+      if (!ShouldInlineSimd()) {
+        return false;
+      }
+      return InlineGetIndexed(flow_graph, kind, call, receiver, entry, last);
+    case MethodRecognizer::kInt32ArrayGetIndexed:
+    case MethodRecognizer::kUint32ArrayGetIndexed:
+      if (!CanUnboxInt32()) return false;
+      return InlineGetIndexed(flow_graph, kind, call, receiver, entry, last);
+
+    case MethodRecognizer::kInt64ArrayGetIndexed:
+      if (!ShouldInlineInt64ArrayOps()) {
+        return false;
+      }
+      return InlineGetIndexed(flow_graph, kind, call, receiver, entry, last);
+    // Recognized []= operators.
+    case MethodRecognizer::kObjectArraySetIndexed:
+    case MethodRecognizer::kGrowableArraySetIndexed:
+      return InlineSetIndexed(flow_graph, kind, target, call, receiver,
+                              token_pos, value_check, entry, last);
+    case MethodRecognizer::kInt8ArraySetIndexed:
+    case MethodRecognizer::kUint8ArraySetIndexed:
+    case MethodRecognizer::kUint8ClampedArraySetIndexed:
+    case MethodRecognizer::kExternalUint8ArraySetIndexed:
+    case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
+    case MethodRecognizer::kInt16ArraySetIndexed:
+    case MethodRecognizer::kUint16ArraySetIndexed:
+      // Optimistically assume Smi.
+      if (ic_data.HasDeoptReason(ICData::kDeoptCheckSmi)) {
+        // Optimistic assumption failed at least once.
+        return false;
+      }
+      value_check = ic_data.AsUnaryClassChecksForCid(kSmiCid, target);
+      return InlineSetIndexed(flow_graph, kind, target, call, receiver,
+                              token_pos, value_check, entry, last);
+    case MethodRecognizer::kInt32ArraySetIndexed:
+    case MethodRecognizer::kUint32ArraySetIndexed: {
+      // Value check not needed for Int32 and Uint32 arrays because they
+      // implicitly contain unboxing instructions which check for right type.
+      ICData& value_check = ICData::Handle();
+      return InlineSetIndexed(flow_graph, kind, target, call, receiver,
+                              token_pos, value_check, entry, last);
+    }
+    case MethodRecognizer::kInt64ArraySetIndexed:
+      if (!ShouldInlineInt64ArrayOps()) {
+        return false;
+      }
+      return InlineSetIndexed(flow_graph, kind, target, call, receiver,
+                              token_pos, value_check, entry, last);
+    case MethodRecognizer::kFloat32ArraySetIndexed:
+    case MethodRecognizer::kFloat64ArraySetIndexed:
+      if (!CanUnboxDouble()) {
+        return false;
+      }
+      value_check = ic_data.AsUnaryClassChecksForCid(kDoubleCid, target);
+      return InlineSetIndexed(flow_graph, kind, target, call, receiver,
+                              token_pos, value_check, entry, last);
+    case MethodRecognizer::kFloat32x4ArraySetIndexed:
+      if (!ShouldInlineSimd()) {
+        return false;
+      }
+      value_check = ic_data.AsUnaryClassChecksForCid(kFloat32x4Cid, target);
+
+      return InlineSetIndexed(flow_graph, kind, target, call, receiver,
+                              token_pos, value_check, entry, last);
+    case MethodRecognizer::kFloat64x2ArraySetIndexed:
+      if (!ShouldInlineSimd()) {
+        return false;
+      }
+      value_check = ic_data.AsUnaryClassChecksForCid(kFloat64x2Cid, target);
+      return InlineSetIndexed(flow_graph, kind, target, call, receiver,
+                              token_pos, value_check, entry, last);
+    case MethodRecognizer::kByteArrayBaseGetInt8:
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataInt8ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetUint8:
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataUint8ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetInt16:
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataInt16ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetUint16:
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataUint16ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetInt32:
+      if (!CanUnboxInt32()) {
+        return false;
+      }
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataInt32ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetUint32:
+      if (!CanUnboxInt32()) {
+        return false;
+      }
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataUint32ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetFloat32:
+      if (!CanUnboxDouble()) {
+        return false;
+      }
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataFloat32ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetFloat64:
+      if (!CanUnboxDouble()) {
+        return false;
+      }
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataFloat64ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetFloat32x4:
+      if (!ShouldInlineSimd()) {
+        return false;
+      }
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataFloat32x4ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseGetInt32x4:
+      if (!ShouldInlineSimd()) {
+        return false;
+      }
+      return InlineByteArrayBaseLoad(flow_graph, call, receiver, receiver_cid,
+                                     kTypedDataInt32x4ArrayCid,
+                                     entry, last);
+    case MethodRecognizer::kByteArrayBaseSetInt8:
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid, kTypedDataInt8ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetUint8:
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataUint8ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetInt16:
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataInt16ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetUint16:
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataUint16ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetInt32:
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataInt32ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetUint32:
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataUint32ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetFloat32:
+      if (!CanUnboxDouble()) {
+        return false;
+      }
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataFloat32ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetFloat64:
+      if (!CanUnboxDouble()) {
+        return false;
+      }
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataFloat64ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetFloat32x4:
+      if (!ShouldInlineSimd()) {
+        return false;
+      }
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataFloat32x4ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kByteArrayBaseSetInt32x4:
+      if (!ShouldInlineSimd()) {
+        return false;
+      }
+      return InlineByteArrayBaseStore(flow_graph, target, call, receiver,
+                                      receiver_cid,
+                                      kTypedDataInt32x4ArrayCid,
+                                      entry, last);
+    case MethodRecognizer::kStringBaseCodeUnitAt:
+      return InlineStringCodeUnitAt(
+          flow_graph, call, receiver_cid, entry, last);
+    case MethodRecognizer::kStringBaseCharAt:
+      return InlineStringBaseCharAt(
+          flow_graph, call, receiver_cid, entry, last);
+    case MethodRecognizer::kDoubleAdd:
+      return InlineDoubleOp(flow_graph, Token::kADD, call, entry, last);
+    case MethodRecognizer::kDoubleSub:
+      return InlineDoubleOp(flow_graph, Token::kSUB, call, entry, last);
+    case MethodRecognizer::kDoubleMul:
+      return InlineDoubleOp(flow_graph, Token::kMUL, call, entry, last);
+    case MethodRecognizer::kDoubleDiv:
+      return InlineDoubleOp(flow_graph, Token::kDIV, call, entry, last);
+    default:
+      return false;
+  }
+}
+
+
 }  // namespace dart
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index 6e3ce09..ade98b5 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -10,14 +10,18 @@
 
 namespace dart {
 
+class Definition;
 class Field;
 class FlowGraph;
 class Function;
+class Instruction;
+class TargetEntryInstr;
 
 class FlowGraphInliner : ValueObject {
  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);
@@ -32,15 +36,28 @@
   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_; }
 
+  static bool TryInlineRecognizedMethod(FlowGraph* flow_graph,
+                                        intptr_t receiver_cid,
+                                        const Function& target,
+                                        Instruction* call,
+                                        Definition* receiver,
+                                        TokenPosition token_pos,
+                                        const ICData& ic_data,
+                                        TargetEntryInstr** entry,
+                                        Definition** last);
+
  private:
   friend class CallSiteInliner;
 
   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_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
deleted file mode 100644
index c36bf53..0000000
--- a/runtime/vm/flow_graph_optimizer.cc
+++ /dev/null
@@ -1,8867 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/flow_graph_optimizer.h"
-
-#include "vm/bit_vector.h"
-#include "vm/cha.h"
-#include "vm/compiler.h"
-#include "vm/cpu.h"
-#include "vm/dart_entry.h"
-#include "vm/exceptions.h"
-#include "vm/flow_graph_builder.h"
-#include "vm/flow_graph_compiler.h"
-#include "vm/flow_graph_range_analysis.h"
-#include "vm/hash_map.h"
-#include "vm/il_printer.h"
-#include "vm/intermediate_language.h"
-#include "vm/object_store.h"
-#include "vm/parser.h"
-#include "vm/precompiler.h"
-#include "vm/resolver.h"
-#include "vm/scopes.h"
-#include "vm/stack_frame.h"
-#include "vm/symbols.h"
-
-namespace dart {
-
-DEFINE_FLAG(int, getter_setter_ratio, 13,
-    "Ratio of getter/setter usage used for double field unboxing heuristics");
-DEFINE_FLAG(bool, guess_icdata_cid, true,
-    "Artificially create type feedback for arithmetic etc. operations"
-    " by guessing the other unknown argument cid");
-DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination.");
-DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores");
-DEFINE_FLAG(int, max_polymorphic_checks, 4,
-    "Maximum number of polymorphic check, otherwise it is megamorphic.");
-DEFINE_FLAG(int, max_equality_polymorphic_checks, 32,
-    "Maximum number of polymorphic checks in equality operator,"
-    " otherwise use megamorphic dispatch.");
-DEFINE_FLAG(bool, merge_sin_cos, false, "Merge sin/cos into sincos");
-DEFINE_FLAG(bool, trace_load_optimization, false,
-    "Print live sets for load optimization pass.");
-DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details.");
-DEFINE_FLAG(bool, truncating_left_shift, true,
-    "Optimize left shift to truncate if possible");
-DEFINE_FLAG(bool, use_cha_deopt, true,
-    "Use class hierarchy analysis even if it can cause deoptimization.");
-#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32)
-DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass.");
-#endif
-
-DECLARE_FLAG(bool, precompilation);
-DECLARE_FLAG(bool, polymorphic_with_deopt);
-DECLARE_FLAG(bool, source_lines);
-DECLARE_FLAG(bool, trace_cha);
-DECLARE_FLAG(bool, trace_field_guards);
-DECLARE_FLAG(bool, trace_type_check_elimination);
-DECLARE_FLAG(bool, warn_on_javascript_compatibility);
-DECLARE_FLAG(bool, fields_may_be_reset);
-
-// Quick access to the current isolate and zone.
-#define I (isolate())
-#define Z (zone())
-
-static bool ShouldInlineSimd() {
-  return FlowGraphCompiler::SupportsUnboxedSimd128();
-}
-
-
-static bool CanUnboxDouble() {
-  return FlowGraphCompiler::SupportsUnboxedDoubles();
-}
-
-
-static bool ShouldInlineInt64ArrayOps() {
-#if defined(TARGET_ARCH_X64)
-  return true;
-#endif
-  return false;
-}
-
-static bool CanConvertUnboxedMintToDouble() {
-#if defined(TARGET_ARCH_IA32)
-  return true;
-#else
-  // ARM does not have a short instruction sequence for converting int64 to
-  // double.
-  // TODO(johnmccutchan): Investigate possibility on MIPS once
-  // mints are implemented there.
-  return false;
-#endif
-}
-
-
-// Optimize instance calls using ICData.
-void FlowGraphOptimizer::ApplyICData() {
-  VisitBlocks();
-}
-
-
-void FlowGraphOptimizer::PopulateWithICData() {
-  ASSERT(current_iterator_ == NULL);
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    BlockEntryInstr* entry = block_order_[i];
-    ForwardInstructionIterator it(entry);
-    for (; !it.Done(); it.Advance()) {
-      Instruction* instr = it.Current();
-      if (instr->IsInstanceCall()) {
-        InstanceCallInstr* call = instr->AsInstanceCall();
-        if (!call->HasICData()) {
-          const Array& arguments_descriptor =
-              Array::Handle(zone(),
-                  ArgumentsDescriptor::New(call->ArgumentCount(),
-                                           call->argument_names()));
-          const ICData& ic_data = ICData::ZoneHandle(zone(), ICData::New(
-              function(), call->function_name(),
-              arguments_descriptor, call->deopt_id(),
-              call->checked_argument_count()));
-          call->set_ic_data(&ic_data);
-        }
-      }
-    }
-    current_iterator_ = NULL;
-  }
-}
-
-
-// Optimize instance calls using cid.  This is called after optimizer
-// converted instance calls to instructions. Any remaining
-// instance calls are either megamorphic calls, cannot be optimized or
-// 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() {
-  ASSERT(current_iterator_ == NULL);
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    BlockEntryInstr* entry = block_order_[i];
-    ForwardInstructionIterator it(entry);
-    current_iterator_ = &it;
-    for (; !it.Done(); it.Advance()) {
-      Instruction* instr = it.Current();
-      if (instr->IsInstanceCall()) {
-        InstanceCallInstr* call = instr->AsInstanceCall();
-        if (call->HasICData()) {
-          if (TryCreateICData(call)) {
-            VisitInstanceCall(call);
-          }
-        }
-      } else if (instr->IsPolymorphicInstanceCall()) {
-        SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall());
-      } else if (instr->IsStrictCompare()) {
-        VisitStrictCompare(instr->AsStrictCompare());
-      } else if (instr->IsBranch()) {
-        ComparisonInstr* compare = instr->AsBranch()->comparison();
-        if (compare->IsStrictCompare()) {
-          VisitStrictCompare(compare->AsStrictCompare());
-        }
-      }
-    }
-    current_iterator_ = NULL;
-  }
-}
-
-
-// TODO(srdjan): Test/support other number types as well.
-static bool IsNumberCid(intptr_t cid) {
-  return (cid == kSmiCid) || (cid == kDoubleCid);
-}
-
-
-bool FlowGraphOptimizer::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
-    // to megamorphic call.
-    return false;
-  }
-  if (FLAG_warn_on_javascript_compatibility) {
-    // Do not make the instance call megamorphic if the callee needs to decode
-    // the calling code sequence to lookup the ic data and verify if a warning
-    // has already been issued or not.
-    if (call->ic_data()->MayCheckForJSWarning()) {
-      return false;
-    }
-  }
-  GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
-  ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
-  for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
-    class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid());
-  }
-
-  const Token::Kind op_kind = call->token_kind();
-  if (Token::IsRelationalOperator(op_kind) ||
-      Token::IsEqualityOperator(op_kind) ||
-      Token::IsBinaryOperator(op_kind)) {
-    // Guess cid: if one of the inputs is a number assume that the other
-    // is a number of same type.
-    if (FLAG_guess_icdata_cid) {
-      const intptr_t cid_0 = class_ids[0];
-      const intptr_t cid_1 = class_ids[1];
-      if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) {
-        class_ids[0] = cid_1;
-      } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) {
-        class_ids[1] = cid_0;
-      }
-    }
-  }
-
-  bool all_cids_known = true;
-  for (intptr_t i = 0; i < class_ids.length(); i++) {
-    if (class_ids[i] == kDynamicCid) {
-      // Not all cid-s known.
-      all_cids_known = false;
-      break;
-    }
-  }
-
-  if (all_cids_known) {
-    const Class& receiver_class = Class::Handle(Z,
-        isolate()->class_table()->At(class_ids[0]));
-    if (!receiver_class.is_finalized()) {
-      // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can
-      // cause class finalization, since callee's receiver class may not be
-      // finalized yet.
-      return false;
-    }
-    // Do not run the optimization below if in background compilation since
-    // resolution of method extractor functions may create new signature
-    // classes.
-    // TODO(regis): Remove test for background compilation once signature
-    // classes are not generated any longer.
-    if (!thread()->IsMutatorThread()) {
-      return false;
-    }
-    const Array& args_desc_array = Array::Handle(Z,
-        ArgumentsDescriptor::New(call->ArgumentCount(),
-                                 call->argument_names()));
-    ArgumentsDescriptor args_desc(args_desc_array);
-    const Function& function = Function::Handle(Z,
-        Resolver::ResolveDynamicForReceiverClass(
-            receiver_class,
-            call->function_name(),
-            args_desc));
-    if (function.IsNull()) {
-      return false;
-    }
-
-    // Create new ICData, do not modify the one attached to the instruction
-    // since it is attached to the assembly instruction itself.
-    // TODO(srdjan): Prevent modification of ICData object that is
-    // referenced in assembly code.
-    const ICData& ic_data = ICData::ZoneHandle(Z,
-        ICData::NewFrom(*call->ic_data(), class_ids.length()));
-    if (class_ids.length() > 1) {
-      ic_data.AddCheck(class_ids, function);
-    } else {
-      ASSERT(class_ids.length() == 1);
-      ic_data.AddReceiverCheck(class_ids[0], function);
-    }
-    call->set_ic_data(&ic_data);
-    return true;
-  }
-
-  if (Compiler::always_optimize() &&
-      (isolate()->object_store()->unique_dynamic_targets() != Array::null())) {
-    // Check if the target is unique.
-    Function& target_function = Function::Handle(Z);
-    Precompiler::GetUniqueDynamicTarget(
-        isolate(), call->function_name(), &target_function);
-    // Calls with named arguments must be resolved/checked at runtime.
-    String& error_message = String::Handle(Z);
-    if (!target_function.IsNull() &&
-        !target_function.HasOptionalNamedParameters() &&
-        target_function.AreValidArgumentCounts(call->ArgumentCount(), 0,
-                                               &error_message)) {
-      const intptr_t cid = Class::Handle(Z, target_function.Owner()).id();
-      const ICData& ic_data = ICData::ZoneHandle(Z,
-          ICData::NewFrom(*call->ic_data(), 1));
-      ic_data.AddReceiverCheck(cid, target_function);
-      call->set_ic_data(&ic_data);
-      return true;
-    }
-  }
-
-  // Check if getter or setter in function's class and class is currently leaf.
-  // Do not run the optimization below if in background compilation since
-  // resolution of getter functions may create new signature classes.
-  // TODO(regis): Remove test for background compilation once signature classes
-  // are not generated any longer.
-  if (thread()->IsMutatorThread() &&
-      FLAG_guess_icdata_cid &&
-      ((call->token_kind() == Token::kGET) ||
-          (call->token_kind() == Token::kSET))) {
-    const Class& owner_class = Class::Handle(Z, function().Owner());
-    if (!owner_class.is_abstract() &&
-        !CHA::HasSubclasses(owner_class) &&
-        !CHA::IsImplemented(owner_class)) {
-      const Array& args_desc_array = Array::Handle(Z,
-          ArgumentsDescriptor::New(call->ArgumentCount(),
-                                   call->argument_names()));
-      ArgumentsDescriptor args_desc(args_desc_array);
-      const Function& function = Function::Handle(Z,
-          Resolver::ResolveDynamicForReceiverClass(owner_class,
-                                                   call->function_name(),
-                                                   args_desc));
-      if (!function.IsNull()) {
-        const ICData& ic_data = ICData::ZoneHandle(Z,
-            ICData::NewFrom(*call->ic_data(), class_ids.length()));
-        ic_data.AddReceiverCheck(owner_class.id(), function);
-        call->set_ic_data(&ic_data);
-        return true;
-      }
-    }
-  }
-
-  return false;
-}
-
-
-const ICData& FlowGraphOptimizer::TrySpecializeICData(const ICData& ic_data,
-                                                      intptr_t cid) {
-  ASSERT(ic_data.NumArgsTested() == 1);
-
-  if ((ic_data.NumberOfUsedChecks() == 1) && ic_data.HasReceiverClassId(cid)) {
-    return ic_data;  // Nothing to do
-  }
-
-  const Function& function =
-      Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid));
-  // TODO(fschneider): Try looking up the function on the class if it is
-  // not found in the ICData.
-  if (!function.IsNull()) {
-    const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New(
-        Function::Handle(Z, ic_data.Owner()),
-        String::Handle(Z, ic_data.target_name()),
-        Object::empty_array(),  // Dummy argument descriptor.
-        ic_data.deopt_id(),
-        ic_data.NumArgsTested()));
-    new_ic_data.SetDeoptReasons(ic_data.DeoptReasons());
-    new_ic_data.AddReceiverCheck(cid, function);
-    return new_ic_data;
-  }
-
-  return ic_data;
-}
-
-
-void FlowGraphOptimizer::SpecializePolymorphicInstanceCall(
-    PolymorphicInstanceCallInstr* call) {
-  if (!FLAG_polymorphic_with_deopt) {
-    // Specialization adds receiver checks which can lead to deoptimization.
-    return;
-  }
-  if (!call->with_checks()) {
-    return;  // Already specialized.
-  }
-
-  const intptr_t receiver_cid =
-      call->PushArgumentAt(0)->value()->Type()->ToCid();
-  if (receiver_cid == kDynamicCid) {
-    return;  // No information about receiver was infered.
-  }
-
-  const ICData& ic_data = TrySpecializeICData(call->ic_data(), receiver_cid);
-  if (ic_data.raw() == call->ic_data().raw()) {
-    // No specialization.
-    return;
-  }
-
-  const bool with_checks = false;
-  PolymorphicInstanceCallInstr* specialized =
-      new(Z) PolymorphicInstanceCallInstr(call->instance_call(),
-                                          ic_data,
-                                          with_checks);
-  call->ReplaceWith(specialized, current_iterator());
-}
-
-
-static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
-  BinarySmiOpInstr* instr = d->AsBinarySmiOp();
-  if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
-    return instr;
-  }
-  return NULL;
-}
-
-
-static bool IsPositiveOrZeroSmiConst(Definition* d) {
-  ConstantInstr* const_instr = d->AsConstant();
-  if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
-    return Smi::Cast(const_instr->value()).Value() >= 0;
-  }
-  return false;
-}
-
-
-void FlowGraphOptimizer::OptimizeLeftShiftBitAndSmiOp(
-    Definition* bit_and_instr,
-    Definition* left_instr,
-    Definition* right_instr) {
-  ASSERT(bit_and_instr != NULL);
-  ASSERT((left_instr != NULL) && (right_instr != NULL));
-
-  // Check for pattern, smi_shift_left must be single-use.
-  bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
-  if (!is_positive_or_zero) {
-    is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
-  }
-  if (!is_positive_or_zero) return;
-
-  BinarySmiOpInstr* smi_shift_left = NULL;
-  if (bit_and_instr->InputAt(0)->IsSingleUse()) {
-    smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
-  }
-  if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
-    smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
-  }
-  if (smi_shift_left == NULL) return;
-
-  // Pattern recognized.
-  smi_shift_left->mark_truncating();
-  ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
-  if (bit_and_instr->IsBinaryMintOp()) {
-    // Replace Mint op with Smi op.
-    BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
-        Token::kBIT_AND,
-        new(Z) Value(left_instr),
-        new(Z) Value(right_instr),
-        Thread::kNoDeoptId);  // BIT_AND cannot deoptimize.
-    bit_and_instr->ReplaceWith(smi_op, current_iterator());
-  }
-}
-
-
-
-// Used by TryMergeDivMod.
-// Inserts a load-indexed instruction between a TRUNCDIV or MOD instruction,
-// and the using instruction. This is an intermediate step before merging.
-void FlowGraphOptimizer::AppendLoadIndexedForMerged(Definition* instr,
-                                                    intptr_t ix,
-                                                    intptr_t cid) {
-  const intptr_t index_scale = Instance::ElementSizeFor(cid);
-  ConstantInstr* index_instr =
-      flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(ix)));
-  LoadIndexedInstr* load =
-      new(Z) LoadIndexedInstr(new(Z) Value(instr),
-                                      new(Z) Value(index_instr),
-                                      index_scale,
-                                      cid,
-                                      Thread::kNoDeoptId,
-                                      instr->token_pos());
-  instr->ReplaceUsesWith(load);
-  flow_graph()->InsertAfter(instr, load, NULL, FlowGraph::kValue);
-}
-
-
-void FlowGraphOptimizer::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);
-  flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
-}
-
-
-// Dart:
-//  var x = d % 10;
-//  var y = d ~/ 10;
-//  var z = x + y;
-//
-// IL:
-//  v4 <- %(v2, v3)
-//  v5 <- ~/(v2, v3)
-//  v6 <- +(v4, v5)
-//
-// IL optimized:
-//  v4 <- DIVMOD(v2, v3);
-//  v5 <- LoadIndexed(v4, 0); // ~/ result
-//  v6 <- LoadIndexed(v4, 1); // % result
-//  v7 <- +(v5, v6)
-// Because of the environment it is important that merged instruction replaces
-// first original instruction encountered.
-void FlowGraphOptimizer::TryMergeTruncDivMod(
-    GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
-  if (merge_candidates->length() < 2) {
-    // Need at least a TRUNCDIV and a MOD.
-    return;
-  }
-  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
-    BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
-    if (curr_instr == NULL) {
-      // Instruction was merged already.
-      continue;
-    }
-    ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
-           (curr_instr->op_kind() == Token::kMOD));
-    // Check if there is kMOD/kTRUNDIV binop with same inputs.
-    const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
-        Token::kMOD : Token::kTRUNCDIV;
-    Definition* left_def = curr_instr->left()->definition();
-    Definition* right_def = curr_instr->right()->definition();
-    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
-      BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
-      // 'other_binop' can be NULL if it was already merged.
-      if ((other_binop != NULL) &&
-          (other_binop->op_kind() == other_kind) &&
-          (other_binop->left()->definition() == left_def) &&
-          (other_binop->right()->definition() == right_def)) {
-        (*merge_candidates)[k] = NULL;  // Clear it.
-        ASSERT(curr_instr->HasUses());
-        AppendExtractNthOutputForMerged(
-            curr_instr,
-            MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
-            kTagged, kSmiCid);
-        ASSERT(other_binop->HasUses());
-        AppendExtractNthOutputForMerged(
-            other_binop,
-            MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
-            kTagged, kSmiCid);
-
-        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
-        args->Add(new(Z) Value(curr_instr->left()->definition()));
-        args->Add(new(Z) Value(curr_instr->right()->definition()));
-
-        // Replace with TruncDivMod.
-        MergedMathInstr* div_mod = new(Z) MergedMathInstr(
-            args,
-            curr_instr->deopt_id(),
-            MergedMathInstr::kTruncDivMod);
-        curr_instr->ReplaceWith(div_mod, current_iterator());
-        other_binop->ReplaceUsesWith(div_mod);
-        other_binop->RemoveFromGraph();
-        // Only one merge possible. Because canonicalization happens later,
-        // more candidates are possible.
-        // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
-        break;
-      }
-    }
-  }
-}
-
-
-// Tries to merge MathUnary operations, in this case sinus and cosinus.
-void FlowGraphOptimizer::TryMergeMathUnary(
-    GrowableArray<MathUnaryInstr*>* merge_candidates) {
-  if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
-      !FLAG_merge_sin_cos) {
-    return;
-  }
-  if (merge_candidates->length() < 2) {
-    // Need at least a SIN and a COS.
-    return;
-  }
-  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
-    MathUnaryInstr* curr_instr = (*merge_candidates)[i];
-    if (curr_instr == NULL) {
-      // Instruction was merged already.
-      continue;
-    }
-    const intptr_t kind = curr_instr->kind();
-    ASSERT((kind == MathUnaryInstr::kSin) ||
-           (kind == MathUnaryInstr::kCos));
-    // Check if there is sin/cos binop with same inputs.
-    const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
-        MathUnaryInstr::kCos : MathUnaryInstr::kSin;
-    Definition* def = curr_instr->value()->definition();
-    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
-      MathUnaryInstr* other_op = (*merge_candidates)[k];
-      // 'other_op' can be NULL if it was already merged.
-      if ((other_op != NULL) && (other_op->kind() == other_kind) &&
-          (other_op->value()->definition() == def)) {
-        (*merge_candidates)[k] = NULL;  // Clear it.
-        ASSERT(curr_instr->HasUses());
-        AppendExtractNthOutputForMerged(curr_instr,
-                                        MergedMathInstr::OutputIndexOf(kind),
-                                        kUnboxedDouble, kDoubleCid);
-        ASSERT(other_op->HasUses());
-        AppendExtractNthOutputForMerged(
-            other_op,
-            MergedMathInstr::OutputIndexOf(other_kind),
-            kUnboxedDouble, kDoubleCid);
-        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
-        args->Add(new(Z) Value(curr_instr->value()->definition()));
-        // Replace with SinCos.
-        MergedMathInstr* sin_cos =
-            new(Z) MergedMathInstr(args,
-                                   curr_instr->DeoptimizationTarget(),
-                                   MergedMathInstr::kSinCos);
-        curr_instr->ReplaceWith(sin_cos, current_iterator());
-        other_op->ReplaceUsesWith(sin_cos);
-        other_op->RemoveFromGraph();
-        // Only one merge possible. Because canonicalization happens later,
-        // more candidates are possible.
-        // TODO(srdjan): Allow merging of sin/cos into sincos.
-        break;
-      }
-    }
-  }
-}
-
-
-// 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() {
-  if (!FLAG_truncating_left_shift) return;
-  ASSERT(current_iterator_ == NULL);
-  GrowableArray<BinarySmiOpInstr*> div_mod_merge;
-  GrowableArray<MathUnaryInstr*> sin_cos_merge;
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    // Merging only per basic-block.
-    div_mod_merge.Clear();
-    sin_cos_merge.Clear();
-    BlockEntryInstr* entry = block_order_[i];
-    ForwardInstructionIterator it(entry);
-    current_iterator_ = &it;
-    for (; !it.Done(); it.Advance()) {
-      if (it.Current()->IsBinarySmiOp()) {
-        BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
-        if (binop->op_kind() == Token::kBIT_AND) {
-          OptimizeLeftShiftBitAndSmiOp(binop,
-                                       binop->left()->definition(),
-                                       binop->right()->definition());
-        } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
-                   (binop->op_kind() == Token::kMOD)) {
-          if (binop->HasUses()) {
-            div_mod_merge.Add(binop);
-          }
-        }
-      } else if (it.Current()->IsBinaryMintOp()) {
-        BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
-        if (mintop->op_kind() == Token::kBIT_AND) {
-          OptimizeLeftShiftBitAndSmiOp(mintop,
-                                       mintop->left()->definition(),
-                                       mintop->right()->definition());
-        }
-      } else if (it.Current()->IsMathUnary()) {
-        MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
-        if ((math_unary->kind() == MathUnaryInstr::kSin) ||
-            (math_unary->kind() == MathUnaryInstr::kCos)) {
-          if (math_unary->HasUses()) {
-            sin_cos_merge.Add(math_unary);
-          }
-        }
-      }
-    }
-    TryMergeTruncDivMod(&div_mod_merge);
-    TryMergeMathUnary(&sin_cos_merge);
-    current_iterator_ = NULL;
-  }
-}
-
-
-static void EnsureSSATempIndex(FlowGraph* graph,
-                               Definition* defn,
-                               Definition* replacement) {
-  if ((replacement->ssa_temp_index() == -1) &&
-      (defn->ssa_temp_index() != -1)) {
-    graph->AllocateSSAIndexes(replacement);
-  }
-}
-
-
-static void ReplaceCurrentInstruction(ForwardInstructionIterator* iterator,
-                                      Instruction* current,
-                                      Instruction* replacement,
-                                      FlowGraph* graph) {
-  Definition* current_defn = current->AsDefinition();
-  if ((replacement != NULL) && (current_defn != NULL)) {
-    Definition* replacement_defn = replacement->AsDefinition();
-    ASSERT(replacement_defn != NULL);
-    current_defn->ReplaceUsesWith(replacement_defn);
-    EnsureSSATempIndex(graph, current_defn, replacement_defn);
-
-    if (FLAG_trace_optimization) {
-      THR_Print("Replacing v%" Pd " with v%" Pd "\n",
-                current_defn->ssa_temp_index(),
-                replacement_defn->ssa_temp_index());
-    }
-  } else if (FLAG_trace_optimization) {
-    if (current_defn == NULL) {
-      THR_Print("Removing %s\n", current->DebugName());
-    } else {
-      ASSERT(!current_defn->HasUses());
-      THR_Print("Removing v%" Pd ".\n", current_defn->ssa_temp_index());
-    }
-  }
-  iterator->RemoveCurrentFromGraph();
-}
-
-
-bool FlowGraphOptimizer::Canonicalize() {
-  bool changed = false;
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    BlockEntryInstr* entry = block_order_[i];
-    for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
-      Instruction* current = it.Current();
-      if (current->HasUnmatchedInputRepresentations()) {
-        // Can't canonicalize this instruction until all conversions for its
-        // inputs are inserted.
-        continue;
-      }
-
-      Instruction* replacement = current->Canonicalize(flow_graph());
-
-      if (replacement != current) {
-        // For non-definitions Canonicalize should return either NULL or
-        // this.
-        ASSERT((replacement == NULL) || current->IsDefinition());
-        ReplaceCurrentInstruction(&it, current, replacement, flow_graph_);
-        changed = true;
-      }
-    }
-  }
-  return changed;
-}
-
-
-static bool IsUnboxedInteger(Representation rep) {
-  return (rep == kUnboxedInt32) ||
-         (rep == kUnboxedUint32) ||
-         (rep == kUnboxedMint);
-}
-
-
-void FlowGraphOptimizer::InsertConversion(Representation from,
-                                          Representation to,
-                                          Value* use,
-                                          bool is_environment_use) {
-  Instruction* insert_before;
-  Instruction* deopt_target;
-  PhiInstr* phi = use->instruction()->AsPhi();
-  if (phi != NULL) {
-    ASSERT(phi->is_alive());
-    // For phis conversions have to be inserted in the predecessor.
-    insert_before =
-        phi->block()->PredecessorAt(use->use_index())->last_instruction();
-    deopt_target = NULL;
-  } else {
-    deopt_target = insert_before = use->instruction();
-  }
-
-  Definition* converted = NULL;
-  if (IsUnboxedInteger(from) && IsUnboxedInteger(to)) {
-    const intptr_t deopt_id = (to == kUnboxedInt32) && (deopt_target != NULL) ?
-      deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
-    converted = new(Z) UnboxedIntConverterInstr(from,
-                                                to,
-                                                use->CopyWithType(),
-                                                deopt_id);
-  } else if ((from == kUnboxedInt32) && (to == kUnboxedDouble)) {
-    converted = new Int32ToDoubleInstr(use->CopyWithType());
-  } else if ((from == kUnboxedMint) &&
-             (to == kUnboxedDouble) &&
-             CanConvertUnboxedMintToDouble()) {
-    const intptr_t deopt_id = (deopt_target != NULL) ?
-        deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
-    ASSERT(CanUnboxDouble());
-    converted = new MintToDoubleInstr(use->CopyWithType(), deopt_id);
-  } else if ((from == kTagged) && Boxing::Supports(to)) {
-    const intptr_t deopt_id = (deopt_target != NULL) ?
-        deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
-    converted = UnboxInstr::Create(to, use->CopyWithType(), deopt_id);
-  } else if ((to == kTagged) && Boxing::Supports(from)) {
-    converted = BoxInstr::Create(from, use->CopyWithType());
-  } else {
-    // We have failed to find a suitable conversion instruction.
-    // Insert two "dummy" conversion instructions with the correct
-    // "from" and "to" representation. The inserted instructions will
-    // trigger a deoptimization if executed. See #12417 for a discussion.
-    const intptr_t deopt_id = (deopt_target != NULL) ?
-        deopt_target->DeoptimizationTarget() : Thread::kNoDeoptId;
-    ASSERT(Boxing::Supports(from));
-    ASSERT(Boxing::Supports(to));
-    Definition* boxed = BoxInstr::Create(from, use->CopyWithType());
-    use->BindTo(boxed);
-    InsertBefore(insert_before, boxed, NULL, FlowGraph::kValue);
-    converted = UnboxInstr::Create(to, new(Z) Value(boxed), deopt_id);
-  }
-  ASSERT(converted != NULL);
-  InsertBefore(insert_before, converted, use->instruction()->env(),
-               FlowGraph::kValue);
-  if (is_environment_use) {
-    use->BindToEnvironment(converted);
-  } else {
-    use->BindTo(converted);
-  }
-
-  if ((to == kUnboxedInt32) && (phi != NULL)) {
-    // Int32 phis are unboxed optimistically. Ensure that unboxing
-    // has deoptimization target attached from the goto instruction.
-    flow_graph_->CopyDeoptTarget(converted, insert_before);
-  }
-}
-
-
-void FlowGraphOptimizer::ConvertUse(Value* use, Representation from_rep) {
-  const Representation to_rep =
-      use->instruction()->RequiredInputRepresentation(use->use_index());
-  if (from_rep == to_rep || to_rep == kNoRepresentation) {
-    return;
-  }
-  InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/ false);
-}
-
-
-void FlowGraphOptimizer::ConvertEnvironmentUse(Value* use,
-                                               Representation from_rep) {
-  const Representation to_rep = kTagged;
-  if (from_rep == to_rep) {
-    return;
-  }
-  InsertConversion(from_rep, to_rep, use, /*is_environment_use=*/ true);
-}
-
-
-void FlowGraphOptimizer::InsertConversionsFor(Definition* def) {
-  const Representation from_rep = def->representation();
-
-  for (Value::Iterator it(def->input_use_list());
-       !it.Done();
-       it.Advance()) {
-    ConvertUse(it.Current(), from_rep);
-  }
-
-  if (flow_graph()->graph_entry()->SuccessorCount() > 1) {
-    for (Value::Iterator it(def->env_use_list());
-         !it.Done();
-         it.Advance()) {
-      Value* use = it.Current();
-      if (use->instruction()->MayThrow() &&
-          use->instruction()->GetBlock()->InsideTryBlock()) {
-        // Environment uses at calls inside try-blocks must be converted to
-        // tagged representation.
-        ConvertEnvironmentUse(it.Current(), from_rep);
-      }
-    }
-  }
-}
-
-
-static void UnboxPhi(PhiInstr* phi) {
-  Representation unboxed = phi->representation();
-
-  switch (phi->Type()->ToCid()) {
-    case kDoubleCid:
-      if (CanUnboxDouble()) {
-        unboxed = kUnboxedDouble;
-      }
-      break;
-    case kFloat32x4Cid:
-      if (ShouldInlineSimd()) {
-        unboxed = kUnboxedFloat32x4;
-      }
-      break;
-    case kInt32x4Cid:
-      if (ShouldInlineSimd()) {
-        unboxed = kUnboxedInt32x4;
-      }
-      break;
-    case kFloat64x2Cid:
-      if (ShouldInlineSimd()) {
-        unboxed = kUnboxedFloat64x2;
-      }
-      break;
-  }
-
-  if ((kSmiBits < 32) &&
-      (unboxed == kTagged) &&
-      phi->Type()->IsInt() &&
-      RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt64)) {
-    // On 32-bit platforms conservatively unbox phis that:
-    //   - are proven to be of type Int;
-    //   - fit into 64bits range;
-    //   - have either constants or Box() operations as inputs;
-    //   - have at least one Box() operation as an input;
-    //   - are used in at least 1 Unbox() operation.
-    bool should_unbox = false;
-    for (intptr_t i = 0; i < phi->InputCount(); i++) {
-      Definition* input = phi->InputAt(i)->definition();
-      if (input->IsBox() &&
-          RangeUtils::Fits(input->range(),
-                           RangeBoundary::kRangeBoundaryInt64)) {
-        should_unbox = true;
-      } else if (!input->IsConstant()) {
-        should_unbox = false;
-        break;
-      }
-    }
-
-    if (should_unbox) {
-      // We checked inputs. Check if phi is used in at least one unbox
-      // operation.
-      bool has_unboxed_use = false;
-      for (Value* use = phi->input_use_list();
-           use != NULL;
-           use = use->next_use()) {
-        Instruction* instr = use->instruction();
-        if (instr->IsUnbox()) {
-          has_unboxed_use = true;
-          break;
-        } else if (IsUnboxedInteger(
-            instr->RequiredInputRepresentation(use->use_index()))) {
-          has_unboxed_use = true;
-          break;
-        }
-      }
-
-      if (!has_unboxed_use) {
-        should_unbox = false;
-      }
-    }
-
-    if (should_unbox) {
-      unboxed =
-          RangeUtils::Fits(phi->range(), RangeBoundary::kRangeBoundaryInt32)
-          ? kUnboxedInt32 : kUnboxedMint;
-    }
-  }
-
-  phi->set_representation(unboxed);
-}
-
-
-void FlowGraphOptimizer::SelectRepresentations() {
-  // Conservatively unbox all phis that were proven to be of Double,
-  // Float32x4, or Int32x4 type.
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    JoinEntryInstr* join_entry = block_order_[i]->AsJoinEntry();
-    if (join_entry != NULL) {
-      for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
-        PhiInstr* phi = it.Current();
-        UnboxPhi(phi);
-      }
-    }
-  }
-
-  // Process all instructions and insert conversions where needed.
-  GraphEntryInstr* graph_entry = block_order_[0]->AsGraphEntry();
-
-  // Visit incoming parameters and constants.
-  for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) {
-    InsertConversionsFor((*graph_entry->initial_definitions())[i]);
-  }
-
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    BlockEntryInstr* entry = block_order_[i];
-    JoinEntryInstr* join_entry = entry->AsJoinEntry();
-    if (join_entry != NULL) {
-      for (PhiIterator it(join_entry); !it.Done(); it.Advance()) {
-        PhiInstr* phi = it.Current();
-        ASSERT(phi != NULL);
-        ASSERT(phi->is_alive());
-        InsertConversionsFor(phi);
-      }
-    }
-    CatchBlockEntryInstr* catch_entry = entry->AsCatchBlockEntry();
-    if (catch_entry != NULL) {
-      for (intptr_t i = 0;
-           i < catch_entry->initial_definitions()->length();
-           i++) {
-        InsertConversionsFor((*catch_entry->initial_definitions())[i]);
-      }
-    }
-    for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
-      Definition* def = it.Current()->AsDefinition();
-      if (def != NULL) {
-        InsertConversionsFor(def);
-      }
-    }
-  }
-}
-
-
-static bool ClassIdIsOneOf(intptr_t class_id,
-                           const GrowableArray<intptr_t>& class_ids) {
-  for (intptr_t i = 0; i < class_ids.length(); i++) {
-    ASSERT(class_ids[i] != kIllegalCid);
-    if (class_ids[i] == class_id) {
-      return true;
-    }
-  }
-  return false;
-}
-
-
-// Returns true if ICData tests two arguments and all ICData cids are in the
-// required sets 'receiver_class_ids' or 'argument_class_ids', respectively.
-static bool ICDataHasOnlyReceiverArgumentClassIds(
-    const ICData& ic_data,
-    const GrowableArray<intptr_t>& receiver_class_ids,
-    const GrowableArray<intptr_t>& argument_class_ids) {
-  if (ic_data.NumArgsTested() != 2) {
-    return false;
-  }
-  const intptr_t len = ic_data.NumberOfChecks();
-  GrowableArray<intptr_t> class_ids;
-  for (intptr_t i = 0; i < len; i++) {
-    if (ic_data.IsUsedAt(i)) {
-      ic_data.GetClassIdsAt(i, &class_ids);
-      ASSERT(class_ids.length() == 2);
-      if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
-          !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-
-static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
-                                              intptr_t receiver_class_id,
-                                              intptr_t argument_class_id) {
-  if (ic_data.NumArgsTested() != 2) {
-    return false;
-  }
-  const intptr_t len = ic_data.NumberOfChecks();
-  for (intptr_t i = 0; i < len; i++) {
-    if (ic_data.IsUsedAt(i)) {
-      GrowableArray<intptr_t> class_ids;
-      ic_data.GetClassIdsAt(i, &class_ids);
-      ASSERT(class_ids.length() == 2);
-      if ((class_ids[0] == receiver_class_id) &&
-          (class_ids[1] == argument_class_id)) {
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-
-static bool HasOnlyOneSmi(const ICData& ic_data) {
-  return (ic_data.NumberOfUsedChecks() == 1)
-      && ic_data.HasReceiverClassId(kSmiCid);
-}
-
-
-static bool HasOnlySmiOrMint(const ICData& ic_data) {
-  if (ic_data.NumberOfUsedChecks() == 1) {
-    return ic_data.HasReceiverClassId(kSmiCid)
-        || ic_data.HasReceiverClassId(kMintCid);
-  }
-  return (ic_data.NumberOfUsedChecks() == 2)
-      && ic_data.HasReceiverClassId(kSmiCid)
-      && ic_data.HasReceiverClassId(kMintCid);
-}
-
-
-static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
-  if (ic_data.NumberOfUsedChecks() != 1) {
-    return false;
-  }
-  GrowableArray<intptr_t> first;
-  GrowableArray<intptr_t> second;
-  ic_data.GetUsedCidsForTwoArgs(&first, &second);
-  return (first[0] == cid) && (second[0] == cid);
-}
-
-// Returns false if the ICData contains anything other than the 4 combinations
-// of Mint and Smi for the receiver and argument classes.
-static bool HasTwoMintOrSmi(const ICData& ic_data) {
-  GrowableArray<intptr_t> first;
-  GrowableArray<intptr_t> second;
-  ic_data.GetUsedCidsForTwoArgs(&first, &second);
-  for (intptr_t i = 0; i < first.length(); i++) {
-    if ((first[i] != kSmiCid) && (first[i] != kMintCid)) {
-      return false;
-    }
-    if ((second[i] != kSmiCid) && (second[i] != kMintCid)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-
-// Returns false if the ICData contains anything other than the 4 combinations
-// of Double and Smi for the receiver and argument classes.
-static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
-  GrowableArray<intptr_t> class_ids(2);
-  class_ids.Add(kSmiCid);
-  class_ids.Add(kDoubleCid);
-  return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
-}
-
-
-static bool HasOnlyOneDouble(const ICData& ic_data) {
-  return (ic_data.NumberOfUsedChecks() == 1)
-      && ic_data.HasReceiverClassId(kDoubleCid);
-}
-
-
-static bool ShouldSpecializeForDouble(const ICData& ic_data) {
-  // Don't specialize for double if we can't unbox them.
-  if (!CanUnboxDouble()) {
-    return false;
-  }
-
-  // Unboxed double operation can't handle case of two smis.
-  if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
-    return false;
-  }
-
-  // Check that it have seen only smis and doubles.
-  return HasTwoDoubleOrSmi(ic_data);
-}
-
-
-void FlowGraphOptimizer::ReplaceCall(Definition* call,
-                                     Definition* replacement) {
-  // Remove the original push arguments.
-  for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-    PushArgumentInstr* push = call->PushArgumentAt(i);
-    push->ReplaceUsesWith(push->value()->definition());
-    push->RemoveFromGraph();
-  }
-  call->ReplaceWith(replacement, current_iterator());
-}
-
-
-void FlowGraphOptimizer::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),
-                                      deopt_id,
-                                      insert_before->token_pos()),
-                 deopt_environment,
-                 FlowGraph::kEffect);
-  }
-}
-
-
-Instruction* FlowGraphOptimizer::GetCheckClass(Definition* to_check,
-                                               const ICData& unary_checks,
-                                               intptr_t deopt_id,
-                                               intptr_t token_pos) {
-  if ((unary_checks.NumberOfUsedChecks() == 1) &&
-      unary_checks.HasReceiverClassId(kSmiCid)) {
-    return new(Z) CheckSmiInstr(new(Z) Value(to_check),
-                                deopt_id,
-                                token_pos);
-  }
-  return new(Z) CheckClassInstr(
-      new(Z) Value(to_check), deopt_id, unary_checks, token_pos);
-}
-
-
-void FlowGraphOptimizer::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());
-  InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
-}
-
-
-void FlowGraphOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
-                call->deopt_id(),
-                call->env(),
-                call);
-}
-
-
-static bool ArgIsAlways(intptr_t cid,
-                        const ICData& ic_data,
-                        intptr_t arg_number) {
-  ASSERT(ic_data.NumArgsTested() > arg_number);
-  if (ic_data.NumberOfUsedChecks() == 0) {
-    return false;
-  }
-  const intptr_t num_checks = ic_data.NumberOfChecks();
-  for (intptr_t i = 0; i < num_checks; i++) {
-    if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
-      return false;
-    }
-  }
-  return true;
-}
-
-
-static bool CanUnboxInt32() {
-  // Int32/Uint32 can be unboxed if it fits into a smi or the platform
-  // supports unboxed mints.
-  return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints();
-}
-
-
-static intptr_t MethodKindToCid(MethodRecognizer::Kind kind) {
-  switch (kind) {
-    case MethodRecognizer::kImmutableArrayGetIndexed:
-      return kImmutableArrayCid;
-
-    case MethodRecognizer::kObjectArrayGetIndexed:
-    case MethodRecognizer::kObjectArraySetIndexed:
-      return kArrayCid;
-
-    case MethodRecognizer::kGrowableArrayGetIndexed:
-    case MethodRecognizer::kGrowableArraySetIndexed:
-      return kGrowableObjectArrayCid;
-
-    case MethodRecognizer::kFloat32ArrayGetIndexed:
-    case MethodRecognizer::kFloat32ArraySetIndexed:
-      return kTypedDataFloat32ArrayCid;
-
-    case MethodRecognizer::kFloat64ArrayGetIndexed:
-    case MethodRecognizer::kFloat64ArraySetIndexed:
-      return kTypedDataFloat64ArrayCid;
-
-    case MethodRecognizer::kInt8ArrayGetIndexed:
-    case MethodRecognizer::kInt8ArraySetIndexed:
-      return kTypedDataInt8ArrayCid;
-
-    case MethodRecognizer::kUint8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ArraySetIndexed:
-      return kTypedDataUint8ArrayCid;
-
-    case MethodRecognizer::kUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kUint8ClampedArraySetIndexed:
-      return kTypedDataUint8ClampedArrayCid;
-
-    case MethodRecognizer::kExternalUint8ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ArraySetIndexed:
-      return kExternalTypedDataUint8ArrayCid;
-
-    case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
-      return kExternalTypedDataUint8ClampedArrayCid;
-
-    case MethodRecognizer::kInt16ArrayGetIndexed:
-    case MethodRecognizer::kInt16ArraySetIndexed:
-      return kTypedDataInt16ArrayCid;
-
-    case MethodRecognizer::kUint16ArrayGetIndexed:
-    case MethodRecognizer::kUint16ArraySetIndexed:
-      return kTypedDataUint16ArrayCid;
-
-    case MethodRecognizer::kInt32ArrayGetIndexed:
-    case MethodRecognizer::kInt32ArraySetIndexed:
-      return kTypedDataInt32ArrayCid;
-
-    case MethodRecognizer::kUint32ArrayGetIndexed:
-    case MethodRecognizer::kUint32ArraySetIndexed:
-      return kTypedDataUint32ArrayCid;
-
-    case MethodRecognizer::kInt64ArrayGetIndexed:
-    case MethodRecognizer::kInt64ArraySetIndexed:
-      return kTypedDataInt64ArrayCid;
-
-    case MethodRecognizer::kFloat32x4ArrayGetIndexed:
-    case MethodRecognizer::kFloat32x4ArraySetIndexed:
-      return kTypedDataFloat32x4ArrayCid;
-
-    case MethodRecognizer::kInt32x4ArrayGetIndexed:
-    case MethodRecognizer::kInt32x4ArraySetIndexed:
-      return kTypedDataInt32x4ArrayCid;
-
-    case MethodRecognizer::kFloat64x2ArrayGetIndexed:
-    case MethodRecognizer::kFloat64x2ArraySetIndexed:
-      return kTypedDataFloat64x2ArrayCid;
-
-    default:
-      break;
-  }
-  return kIllegalCid;
-}
-
-
-bool FlowGraphOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
-  // Check for monomorphic IC data.
-  if (!call->HasICData()) return false;
-  const ICData& ic_data =
-      ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
-  if (ic_data.NumberOfChecks() != 1) {
-    return false;
-  }
-  return TryReplaceInstanceCallWithInline(call);
-}
-
-
-bool FlowGraphOptimizer::InlineSetIndexed(
-    MethodRecognizer::Kind kind,
-    const Function& target,
-    Instruction* call,
-    Definition* receiver,
-    intptr_t token_pos,
-    const ICData& value_check,
-    TargetEntryInstr** entry,
-    Definition** last) {
-  intptr_t array_cid = MethodKindToCid(kind);
-  ASSERT(array_cid != kIllegalCid);
-
-  Definition* array = receiver;
-  Definition* index = call->ArgumentAt(1);
-  Definition* stored_value = call->ArgumentAt(2);
-
-  *entry = new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
-                                   call->GetBlock()->try_index());
-  (*entry)->InheritDeoptTarget(Z, call);
-  Instruction* cursor = *entry;
-  if (I->flags().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.
-    const AbstractType& value_type =
-        AbstractType::ZoneHandle(Z, target.ParameterTypeAt(2));
-    Definition* type_args = NULL;
-    switch (array_cid) {
-      case kArrayCid:
-      case kGrowableObjectArrayCid: {
-        const Class& instantiator_class =  Class::Handle(Z, target.Owner());
-        intptr_t type_arguments_field_offset =
-            instantiator_class.type_arguments_field_offset();
-        LoadFieldInstr* load_type_args =
-            new(Z) LoadFieldInstr(new(Z) Value(array),
-                                  type_arguments_field_offset,
-                                  Type::ZoneHandle(Z),  // No type.
-                                  call->token_pos());
-        cursor = flow_graph()->AppendTo(cursor,
-                                        load_type_args,
-                                        NULL,
-                                        FlowGraph::kValue);
-
-        type_args = load_type_args;
-        break;
-      }
-      case kTypedDataInt8ArrayCid:
-      case kTypedDataUint8ArrayCid:
-      case kTypedDataUint8ClampedArrayCid:
-      case kExternalTypedDataUint8ArrayCid:
-      case kExternalTypedDataUint8ClampedArrayCid:
-      case kTypedDataInt16ArrayCid:
-      case kTypedDataUint16ArrayCid:
-      case kTypedDataInt32ArrayCid:
-      case kTypedDataUint32ArrayCid:
-      case kTypedDataInt64ArrayCid:
-        ASSERT(value_type.IsIntType());
-        // Fall through.
-      case kTypedDataFloat32ArrayCid:
-      case kTypedDataFloat64ArrayCid: {
-        type_args = flow_graph_->constant_null();
-        ASSERT((array_cid != kTypedDataFloat32ArrayCid &&
-                array_cid != kTypedDataFloat64ArrayCid) ||
-               value_type.IsDoubleType());
-        ASSERT(value_type.IsInstantiated());
-        break;
-      }
-      case kTypedDataFloat32x4ArrayCid: {
-        type_args = flow_graph_->constant_null();
-        ASSERT((array_cid != kTypedDataFloat32x4ArrayCid) ||
-               value_type.IsFloat32x4Type());
-        ASSERT(value_type.IsInstantiated());
-        break;
-      }
-      case kTypedDataFloat64x2ArrayCid: {
-        type_args = flow_graph_->constant_null();
-        ASSERT((array_cid != kTypedDataFloat64x2ArrayCid) ||
-               value_type.IsFloat64x2Type());
-        ASSERT(value_type.IsInstantiated());
-        break;
-      }
-      default:
-        // TODO(fschneider): Add support for other array types.
-        UNREACHABLE();
-    }
-    AssertAssignableInstr* assert_value =
-        new(Z) AssertAssignableInstr(token_pos,
-                                     new(Z) Value(stored_value),
-                                     new(Z) Value(type_args),
-                                     value_type,
-                                     Symbols::Value(),
-                                     call->deopt_id());
-    cursor = flow_graph()->AppendTo(cursor,
-                                    assert_value,
-                                    call->env(),
-                                    FlowGraph::kValue);
-  }
-
-  array_cid = PrepareInlineIndexedOp(call,
-                                     array_cid,
-                                     &array,
-                                     index,
-                                     &cursor);
-
-  // Check if store barrier is needed. Byte arrays don't need a store barrier.
-  StoreBarrierType needs_store_barrier =
-      (RawObject::IsTypedDataClassId(array_cid) ||
-       RawObject::IsTypedDataViewClassId(array_cid) ||
-       RawObject::IsExternalTypedDataClassId(array_cid)) ? kNoStoreBarrier
-                                                         : kEmitStoreBarrier;
-
-  // No need to class check stores to Int32 and Uint32 arrays because
-  // we insert unboxing instructions below which include a class check.
-  if ((array_cid != kTypedDataUint32ArrayCid) &&
-      (array_cid != kTypedDataInt32ArrayCid) &&
-      !value_check.IsNull()) {
-    // No store barrier needed because checked value is a smi, an unboxed mint,
-    // an unboxed double, an unboxed Float32x4, or unboxed Int32x4.
-    needs_store_barrier = kNoStoreBarrier;
-    Instruction* check = GetCheckClass(
-        stored_value, value_check, call->deopt_id(), call->token_pos());
-    cursor = flow_graph()->AppendTo(cursor,
-                                    check,
-                                    call->env(),
-                                    FlowGraph::kEffect);
-  }
-
-  if (array_cid == kTypedDataFloat32ArrayCid) {
-    stored_value =
-        new(Z) DoubleToFloatInstr(
-            new(Z) Value(stored_value), call->deopt_id());
-    cursor = flow_graph()->AppendTo(cursor,
-                                    stored_value,
-                                    NULL,
-                                    FlowGraph::kValue);
-  } else if (array_cid == kTypedDataInt32ArrayCid) {
-    stored_value = new(Z) UnboxInt32Instr(
-        UnboxInt32Instr::kTruncate,
-        new(Z) Value(stored_value),
-        call->deopt_id());
-    cursor = flow_graph()->AppendTo(cursor,
-                                    stored_value,
-                                    call->env(),
-                                    FlowGraph::kValue);
-  } else if (array_cid == kTypedDataUint32ArrayCid) {
-    stored_value = new(Z) UnboxUint32Instr(
-        new(Z) Value(stored_value),
-        call->deopt_id());
-    ASSERT(stored_value->AsUnboxInteger()->is_truncating());
-    cursor = flow_graph()->AppendTo(cursor,
-                                    stored_value,
-                                    call->env(),
-                                    FlowGraph::kValue);
-  }
-
-  const intptr_t index_scale = Instance::ElementSizeFor(array_cid);
-  *last = new(Z) StoreIndexedInstr(new(Z) Value(array),
-                                   new(Z) Value(index),
-                                   new(Z) Value(stored_value),
-                                   needs_store_barrier,
-                                   index_scale,
-                                   array_cid,
-                                   call->deopt_id(),
-                                   call->token_pos());
-  flow_graph()->AppendTo(cursor,
-                         *last,
-                         call->env(),
-                         FlowGraph::kEffect);
-  return true;
-}
-
-
-bool FlowGraphOptimizer::TryInlineRecognizedMethod(intptr_t receiver_cid,
-                                                   const Function& target,
-                                                   Instruction* call,
-                                                   Definition* receiver,
-                                                   intptr_t token_pos,
-                                                   const ICData& ic_data,
-                                                   TargetEntryInstr** entry,
-                                                   Definition** last) {
-  ICData& value_check = ICData::ZoneHandle(Z);
-  MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target);
-  switch (kind) {
-    // Recognized [] operators.
-    case MethodRecognizer::kImmutableArrayGetIndexed:
-    case MethodRecognizer::kObjectArrayGetIndexed:
-    case MethodRecognizer::kGrowableArrayGetIndexed:
-    case MethodRecognizer::kInt8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ArrayGetIndexed:
-    case MethodRecognizer::kUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ArrayGetIndexed:
-    case MethodRecognizer::kExternalUint8ClampedArrayGetIndexed:
-    case MethodRecognizer::kInt16ArrayGetIndexed:
-    case MethodRecognizer::kUint16ArrayGetIndexed:
-      return InlineGetIndexed(kind, call, receiver, entry, last);
-    case MethodRecognizer::kFloat32ArrayGetIndexed:
-    case MethodRecognizer::kFloat64ArrayGetIndexed:
-      if (!CanUnboxDouble()) {
-        return false;
-      }
-      return InlineGetIndexed(kind, call, receiver, entry, last);
-    case MethodRecognizer::kFloat32x4ArrayGetIndexed:
-    case MethodRecognizer::kFloat64x2ArrayGetIndexed:
-      if (!ShouldInlineSimd()) {
-        return false;
-      }
-      return InlineGetIndexed(kind, call, receiver, entry, last);
-    case MethodRecognizer::kInt32ArrayGetIndexed:
-    case MethodRecognizer::kUint32ArrayGetIndexed:
-      if (!CanUnboxInt32()) return false;
-      return InlineGetIndexed(kind, call, receiver, entry, last);
-
-    case MethodRecognizer::kInt64ArrayGetIndexed:
-      if (!ShouldInlineInt64ArrayOps()) {
-        return false;
-      }
-      return InlineGetIndexed(kind, call, receiver, entry, last);
-    // Recognized []= operators.
-    case MethodRecognizer::kObjectArraySetIndexed:
-    case MethodRecognizer::kGrowableArraySetIndexed:
-      return InlineSetIndexed(kind, target, call, receiver, token_pos,
-                              value_check, entry, last);
-    case MethodRecognizer::kInt8ArraySetIndexed:
-    case MethodRecognizer::kUint8ArraySetIndexed:
-    case MethodRecognizer::kUint8ClampedArraySetIndexed:
-    case MethodRecognizer::kExternalUint8ArraySetIndexed:
-    case MethodRecognizer::kExternalUint8ClampedArraySetIndexed:
-    case MethodRecognizer::kInt16ArraySetIndexed:
-    case MethodRecognizer::kUint16ArraySetIndexed:
-      // Optimistically assume Smi.
-      if (ic_data.HasDeoptReason(ICData::kDeoptCheckSmi)) {
-        // Optimistic assumption failed at least once.
-        return false;
-      }
-      value_check = ic_data.AsUnaryClassChecksForCid(kSmiCid, target);
-      return InlineSetIndexed(kind, target, call, receiver, token_pos,
-                              value_check, entry, last);
-    case MethodRecognizer::kInt32ArraySetIndexed:
-    case MethodRecognizer::kUint32ArraySetIndexed: {
-      // Value check not needed for Int32 and Uint32 arrays because they
-      // implicitly contain unboxing instructions which check for right type.
-      ICData& value_check = ICData::Handle();
-      return InlineSetIndexed(kind, target, call, receiver, token_pos,
-                              value_check, entry, last);
-    }
-    case MethodRecognizer::kInt64ArraySetIndexed:
-      if (!ShouldInlineInt64ArrayOps()) {
-        return false;
-      }
-      return InlineSetIndexed(kind, target, call, receiver, token_pos,
-                              value_check, entry, last);
-    case MethodRecognizer::kFloat32ArraySetIndexed:
-    case MethodRecognizer::kFloat64ArraySetIndexed:
-      if (!CanUnboxDouble()) {
-        return false;
-      }
-      value_check = ic_data.AsUnaryClassChecksForCid(kDoubleCid, target);
-      return InlineSetIndexed(kind, target, call, receiver, token_pos,
-                              value_check, entry, last);
-    case MethodRecognizer::kFloat32x4ArraySetIndexed:
-      if (!ShouldInlineSimd()) {
-        return false;
-      }
-      value_check = ic_data.AsUnaryClassChecksForCid(kFloat32x4Cid, target);
-
-      return InlineSetIndexed(kind, target, call, receiver, token_pos,
-                              value_check, entry, last);
-    case MethodRecognizer::kFloat64x2ArraySetIndexed:
-      if (!ShouldInlineSimd()) {
-        return false;
-      }
-      value_check = ic_data.AsUnaryClassChecksForCid(kFloat64x2Cid, target);
-      return InlineSetIndexed(kind, target, call, receiver, token_pos,
-                              value_check, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetInt8:
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataInt8ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetUint8:
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataUint8ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetInt16:
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataInt16ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetUint16:
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataUint16ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetInt32:
-      if (!CanUnboxInt32()) {
-        return false;
-      }
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataInt32ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetUint32:
-      if (!CanUnboxInt32()) {
-        return false;
-      }
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataUint32ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetFloat32:
-      if (!CanUnboxDouble()) {
-        return false;
-      }
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataFloat32ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetFloat64:
-      if (!CanUnboxDouble()) {
-        return false;
-      }
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataFloat64ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetFloat32x4:
-      if (!ShouldInlineSimd()) {
-        return false;
-      }
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataFloat32x4ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseGetInt32x4:
-      if (!ShouldInlineSimd()) {
-        return false;
-      }
-      return InlineByteArrayBaseLoad(call, receiver, receiver_cid,
-                                     kTypedDataInt32x4ArrayCid,
-                                     ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetInt8:
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataInt8ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetUint8:
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataUint8ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetInt16:
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataInt16ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetUint16:
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataUint16ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetInt32:
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataInt32ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetUint32:
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataUint32ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetFloat32:
-      if (!CanUnboxDouble()) {
-        return false;
-      }
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataFloat32ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetFloat64:
-      if (!CanUnboxDouble()) {
-        return false;
-      }
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataFloat64ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetFloat32x4:
-      if (!ShouldInlineSimd()) {
-        return false;
-      }
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataFloat32x4ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kByteArrayBaseSetInt32x4:
-      if (!ShouldInlineSimd()) {
-        return false;
-      }
-      return InlineByteArrayBaseStore(target, call, receiver, receiver_cid,
-                                      kTypedDataInt32x4ArrayCid,
-                                      ic_data, entry, last);
-    case MethodRecognizer::kStringBaseCodeUnitAt:
-      return InlineStringCodeUnitAt(call, receiver_cid, entry, last);
-    case MethodRecognizer::kStringBaseCharAt:
-      return InlineStringBaseCharAt(call, receiver_cid, entry, last);
-    case MethodRecognizer::kDoubleAdd:
-      return InlineDoubleOp(Token::kADD, call, entry, last);
-    case MethodRecognizer::kDoubleSub:
-      return InlineDoubleOp(Token::kSUB, call, entry, last);
-    case MethodRecognizer::kDoubleMul:
-      return InlineDoubleOp(Token::kMUL, call, entry, last);
-    case MethodRecognizer::kDoubleDiv:
-      return InlineDoubleOp(Token::kDIV, call, entry, last);
-    default:
-      return false;
-  }
-}
-
-
-intptr_t FlowGraphOptimizer::PrepareInlineIndexedOp(Instruction* call,
-                                                    intptr_t array_cid,
-                                                    Definition** array,
-                                                    Definition* index,
-                                                    Instruction** cursor) {
-  // Insert index smi check.
-  *cursor = flow_graph()->AppendTo(
-      *cursor,
-      new(Z) CheckSmiInstr(new(Z) Value(index),
-                           call->deopt_id(),
-                           call->token_pos()),
-      call->env(),
-      FlowGraph::kEffect);
-
-  // Insert array length load and bounds check.
-  LoadFieldInstr* length =
-      new(Z) LoadFieldInstr(
-          new(Z) Value(*array),
-          CheckArrayBoundInstr::LengthOffsetFor(array_cid),
-          Type::ZoneHandle(Z, Type::SmiType()),
-          call->token_pos());
-  length->set_is_immutable(
-      CheckArrayBoundInstr::IsFixedLengthArrayType(array_cid));
-  length->set_result_cid(kSmiCid);
-  length->set_recognized_kind(
-      LoadFieldInstr::RecognizedKindFromArrayCid(array_cid));
-  *cursor = flow_graph()->AppendTo(*cursor,
-                                   length,
-                                   NULL,
-                                   FlowGraph::kValue);
-
-  *cursor = flow_graph()->AppendTo(*cursor,
-                                   new(Z) CheckArrayBoundInstr(
-                                       new(Z) Value(length),
-                                       new(Z) Value(index),
-                                       call->deopt_id()),
-                                   call->env(),
-                                   FlowGraph::kEffect);
-
-  if (array_cid == kGrowableObjectArrayCid) {
-    // Insert data elements load.
-    LoadFieldInstr* elements =
-        new(Z) LoadFieldInstr(
-            new(Z) Value(*array),
-            GrowableObjectArray::data_offset(),
-            Object::dynamic_type(),
-            call->token_pos());
-    elements->set_result_cid(kArrayCid);
-    *cursor = flow_graph()->AppendTo(*cursor,
-                                     elements,
-                                     NULL,
-                                     FlowGraph::kValue);
-    // Load from the data from backing store which is a fixed-length array.
-    *array = elements;
-    array_cid = kArrayCid;
-  } else if (RawObject::IsExternalTypedDataClassId(array_cid)) {
-    LoadUntaggedInstr* elements =
-        new(Z) LoadUntaggedInstr(new(Z) Value(*array),
-                                 ExternalTypedData::data_offset());
-    *cursor = flow_graph()->AppendTo(*cursor,
-                                     elements,
-                                     NULL,
-                                     FlowGraph::kValue);
-    *array = elements;
-  }
-  return array_cid;
-}
-
-
-bool FlowGraphOptimizer::InlineGetIndexed(MethodRecognizer::Kind kind,
-                                          Instruction* call,
-                                          Definition* receiver,
-                                          TargetEntryInstr** entry,
-                                          Definition** last) {
-  intptr_t array_cid = MethodKindToCid(kind);
-  ASSERT(array_cid != kIllegalCid);
-
-  Definition* array = receiver;
-  Definition* index = call->ArgumentAt(1);
-  *entry = new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
-                                   call->GetBlock()->try_index());
-  (*entry)->InheritDeoptTarget(Z, call);
-  Instruction* cursor = *entry;
-
-  array_cid = PrepareInlineIndexedOp(call,
-                                     array_cid,
-                                     &array,
-                                     index,
-                                     &cursor);
-
-  intptr_t deopt_id = Thread::kNoDeoptId;
-  if ((array_cid == kTypedDataInt32ArrayCid) ||
-      (array_cid == kTypedDataUint32ArrayCid)) {
-    // Deoptimization may be needed if result does not always fit in a Smi.
-    deopt_id = (kSmiBits >= 32) ? Thread::kNoDeoptId : call->deopt_id();
-  }
-
-  // Array load and return.
-  intptr_t index_scale = Instance::ElementSizeFor(array_cid);
-  *last = new(Z) LoadIndexedInstr(new(Z) Value(array),
-                                  new(Z) Value(index),
-                                  index_scale,
-                                  array_cid,
-                                  deopt_id,
-                                  call->token_pos());
-  cursor = flow_graph()->AppendTo(
-      cursor,
-      *last,
-      deopt_id != Thread::kNoDeoptId ? call->env() : NULL,
-      FlowGraph::kValue);
-
-  if (array_cid == kTypedDataFloat32ArrayCid) {
-    *last = new(Z) FloatToDoubleInstr(new(Z) Value(*last), deopt_id);
-    flow_graph()->AppendTo(cursor,
-                           *last,
-                           deopt_id != Thread::kNoDeoptId ? call->env() : NULL,
-                           FlowGraph::kValue);
-  }
-  return true;
-}
-
-
-// Return true if d is a string of length one (a constant or result from
-// from string-from-char-code instruction.
-static bool IsLengthOneString(Definition* d) {
-  if (d->IsConstant()) {
-    const Object& obj = d->AsConstant()->value();
-    if (obj.IsString()) {
-      return String::Cast(obj).Length() == 1;
-    } else {
-      return false;
-    }
-  } else {
-    return d->IsStringFromCharCode();
-  }
-}
-
-
-// Returns true if the string comparison was converted into char-code
-// 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) {
-  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.
-  Definition* left = call->ArgumentAt(0);
-  Definition* right = call->ArgumentAt(1);
-  Value* left_val = NULL;
-  Definition* to_remove_left = NULL;
-  if (IsLengthOneString(right)) {
-    // Swap, since we know that both arguments are strings
-    Definition* temp = left;
-    left = right;
-    right = temp;
-  }
-  if (IsLengthOneString(left)) {
-    // Optimize if left is a string with length one (either constant or
-    // result of string-from-char-code.
-    if (left->IsConstant()) {
-      ConstantInstr* left_const = left->AsConstant();
-      const String& str = String::Cast(left_const->value());
-      ASSERT(str.Length() == 1);
-      ConstantInstr* char_code_left = flow_graph()->GetConstant(
-          Smi::ZoneHandle(Z, Smi::New(static_cast<intptr_t>(str.CharAt(0)))));
-      left_val = new(Z) Value(char_code_left);
-    } else if (left->IsStringFromCharCode()) {
-      // Use input of string-from-charcode as left value.
-      StringFromCharCodeInstr* instr = left->AsStringFromCharCode();
-      left_val = new(Z) Value(instr->char_code()->definition());
-      to_remove_left = instr;
-    } else {
-      // IsLengthOneString(left) should have been false.
-      UNREACHABLE();
-    }
-
-    Definition* to_remove_right = NULL;
-    Value* right_val = NULL;
-    if (right->IsStringFromCharCode()) {
-      // Skip string-from-char-code, and use its input as right value.
-      StringFromCharCodeInstr* right_instr = right->AsStringFromCharCode();
-      right_val = new(Z) Value(right_instr->char_code()->definition());
-      to_remove_right = right_instr;
-    } else {
-      const ICData& unary_checks_1 =
-          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
-      AddCheckClass(right,
-                    unary_checks_1,
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      // String-to-char-code instructions returns -1 (illegal charcode) if
-      // string is not of length one.
-      StringToCharCodeInstr* char_code_right =
-          new(Z) StringToCharCodeInstr(new(Z) Value(right), kOneByteStringCid);
-      InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue);
-      right_val = new(Z) Value(char_code_right);
-    }
-
-    // Comparing char-codes instead of strings.
-    EqualityCompareInstr* comp =
-        new(Z) EqualityCompareInstr(call->token_pos(),
-                                    op_kind,
-                                    left_val,
-                                    right_val,
-                                    kSmiCid,
-                                    call->deopt_id());
-    ReplaceCall(call, comp);
-
-    // Remove dead instructions.
-    if ((to_remove_left != NULL) &&
-        (to_remove_left->input_use_list() == NULL)) {
-      to_remove_left->ReplaceUsesWith(flow_graph()->constant_null());
-      to_remove_left->RemoveFromGraph();
-    }
-    if ((to_remove_right != NULL) &&
-        (to_remove_right->input_use_list() == NULL)) {
-      to_remove_right->ReplaceUsesWith(flow_graph()->constant_null());
-      to_remove_right->RemoveFromGraph();
-    }
-    return true;
-  }
-  return false;
-}
-
-
-static bool SmiFitsInDouble() { return kSmiBits < 53; }
-
-bool FlowGraphOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
-                                                  Token::Kind op_kind) {
-  const ICData& ic_data = *call->ic_data();
-  ASSERT(ic_data.NumArgsTested() == 2);
-
-  ASSERT(call->ArgumentCount() == 2);
-  Definition* left = call->ArgumentAt(0);
-  Definition* right = call->ArgumentAt(1);
-
-  intptr_t cid = kIllegalCid;
-  if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
-    if (TryStringLengthOneEquality(call, op_kind)) {
-      return true;
-    } else {
-      return false;
-    }
-  } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-    InsertBefore(call,
-                 new(Z) CheckSmiInstr(new(Z) Value(left),
-                                      call->deopt_id(),
-                                      call->token_pos()),
-                 call->env(),
-                 FlowGraph::kEffect);
-    InsertBefore(call,
-                 new(Z) CheckSmiInstr(new(Z) Value(right),
-                                      call->deopt_id(),
-                                      call->token_pos()),
-                 call->env(),
-                 FlowGraph::kEffect);
-    cid = kSmiCid;
-  } else if (HasTwoMintOrSmi(ic_data) &&
-             FlowGraphCompiler::SupportsUnboxedMints()) {
-    cid = kMintCid;
-  } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
-    // Use double comparison.
-    if (SmiFitsInDouble()) {
-      cid = kDoubleCid;
-    } else {
-      if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
-        // We cannot use double comparison on two smis. Need polymorphic
-        // call.
-        return false;
-      } else {
-        InsertBefore(call,
-                     new(Z) CheckEitherNonSmiInstr(
-                         new(Z) Value(left),
-                         new(Z) Value(right),
-                         call->deopt_id()),
-                     call->env(),
-                     FlowGraph::kEffect);
-        cid = kDoubleCid;
-      }
-    }
-  } else {
-    // Check if ICDData contains checks with Smi/Null combinations. In that case
-    // we can still emit the optimized Smi equality operation but need to add
-    // checks for null or Smi.
-    GrowableArray<intptr_t> smi_or_null(2);
-    smi_or_null.Add(kSmiCid);
-    smi_or_null.Add(kNullCid);
-    if (ICDataHasOnlyReceiverArgumentClassIds(ic_data,
-                                              smi_or_null,
-                                              smi_or_null)) {
-      const ICData& unary_checks_0 =
-          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
-      AddCheckClass(left,
-                    unary_checks_0,
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-
-      const ICData& unary_checks_1 =
-          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
-      AddCheckClass(right,
-                    unary_checks_1,
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      cid = kSmiCid;
-    } else {
-      // Shortcut for equality with null.
-      ConstantInstr* right_const = right->AsConstant();
-      ConstantInstr* left_const = left->AsConstant();
-      if ((right_const != NULL && right_const->value().IsNull()) ||
-          (left_const != NULL && left_const->value().IsNull())) {
-        StrictCompareInstr* comp =
-            new(Z) StrictCompareInstr(call->token_pos(),
-                                      Token::kEQ_STRICT,
-                                      new(Z) Value(left),
-                                      new(Z) Value(right),
-                                      false);  // No number check.
-        ReplaceCall(call, comp);
-        return true;
-      }
-      return false;
-    }
-  }
-  ASSERT(cid != kIllegalCid);
-  EqualityCompareInstr* comp = new(Z) EqualityCompareInstr(call->token_pos(),
-                                                           op_kind,
-                                                           new(Z) Value(left),
-                                                           new(Z) Value(right),
-                                                           cid,
-                                                           call->deopt_id());
-  ReplaceCall(call, comp);
-  return true;
-}
-
-
-bool FlowGraphOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
-                                                    Token::Kind op_kind) {
-  const ICData& ic_data = *call->ic_data();
-  ASSERT(ic_data.NumArgsTested() == 2);
-
-  ASSERT(call->ArgumentCount() == 2);
-  Definition* left = call->ArgumentAt(0);
-  Definition* right = call->ArgumentAt(1);
-
-  intptr_t cid = kIllegalCid;
-  if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-    InsertBefore(call,
-                 new(Z) CheckSmiInstr(new(Z) Value(left),
-                                      call->deopt_id(),
-                                      call->token_pos()),
-                 call->env(),
-                 FlowGraph::kEffect);
-    InsertBefore(call,
-                 new(Z) CheckSmiInstr(new(Z) Value(right),
-                                      call->deopt_id(),
-                                      call->token_pos()),
-                 call->env(),
-                 FlowGraph::kEffect);
-    cid = kSmiCid;
-  } else if (HasTwoMintOrSmi(ic_data) &&
-             FlowGraphCompiler::SupportsUnboxedMints()) {
-    cid = kMintCid;
-  } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
-    // Use double comparison.
-    if (SmiFitsInDouble()) {
-      cid = kDoubleCid;
-    } else {
-      if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
-        // We cannot use double comparison on two smis. Need polymorphic
-        // call.
-        return false;
-      } else {
-        InsertBefore(call,
-                     new(Z) CheckEitherNonSmiInstr(
-                         new(Z) Value(left),
-                         new(Z) Value(right),
-                         call->deopt_id()),
-                     call->env(),
-                     FlowGraph::kEffect);
-        cid = kDoubleCid;
-      }
-    }
-  } else {
-    return false;
-  }
-  ASSERT(cid != kIllegalCid);
-  RelationalOpInstr* comp = new(Z) RelationalOpInstr(call->token_pos(),
-                                                     op_kind,
-                                                     new(Z) Value(left),
-                                                     new(Z) Value(right),
-                                                     cid,
-                                                     call->deopt_id());
-  ReplaceCall(call, comp);
-  return true;
-}
-
-
-bool FlowGraphOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
-                                                Token::Kind op_kind) {
-  intptr_t operands_type = kIllegalCid;
-  ASSERT(call->HasICData());
-  const ICData& ic_data = *call->ic_data();
-  switch (op_kind) {
-    case Token::kADD:
-    case Token::kSUB:
-    case Token::kMUL:
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-        // Don't generate smi code if the IC data is marked because
-        // of an overflow.
-        operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
-            ? kMintCid
-            : kSmiCid;
-      } else if (HasTwoMintOrSmi(ic_data) &&
-                 FlowGraphCompiler::SupportsUnboxedMints()) {
-        // Don't generate mint code if the IC data is marked because of an
-        // overflow.
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) return false;
-        operands_type = kMintCid;
-      } else if (ShouldSpecializeForDouble(ic_data)) {
-        operands_type = kDoubleCid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
-        operands_type = kFloat32x4Cid;
-      } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
-        ASSERT(op_kind != Token::kMUL);  // Int32x4 doesn't have a multiply op.
-        operands_type = kInt32x4Cid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
-        operands_type = kFloat64x2Cid;
-      } else {
-        return false;
-      }
-      break;
-    case Token::kDIV:
-      if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
-      if (ShouldSpecializeForDouble(ic_data) ||
-          HasOnlyTwoOf(ic_data, kSmiCid)) {
-        operands_type = kDoubleCid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
-        operands_type = kFloat32x4Cid;
-      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
-        operands_type = kFloat64x2Cid;
-      } else {
-        return false;
-      }
-      break;
-    case Token::kBIT_AND:
-    case Token::kBIT_OR:
-    case Token::kBIT_XOR:
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-        operands_type = kSmiCid;
-      } else if (HasTwoMintOrSmi(ic_data)) {
-        operands_type = kMintCid;
-      } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
-        operands_type = kInt32x4Cid;
-      } else {
-        return false;
-      }
-      break;
-    case Token::kSHR:
-    case Token::kSHL:
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-        // Left shift may overflow from smi into mint or big ints.
-        // Don't generate smi code if the IC data is marked because
-        // of an overflow.
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
-          return false;
-        }
-        operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
-            ? kMintCid
-            : kSmiCid;
-      } else if (HasTwoMintOrSmi(ic_data) &&
-                 HasOnlyOneSmi(ICData::Handle(Z,
-                     ic_data.AsUnaryClassChecksForArgNr(1)))) {
-        // Don't generate mint code if the IC data is marked because of an
-        // overflow.
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
-          return false;
-        }
-        // Check for smi/mint << smi or smi/mint >> smi.
-        operands_type = kMintCid;
-      } else {
-        return false;
-      }
-      break;
-    case Token::kMOD:
-    case Token::kTRUNCDIV:
-      if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
-      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-        if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) {
-          return false;
-        }
-        operands_type = kSmiCid;
-      } else {
-        return false;
-      }
-      break;
-    default:
-      UNREACHABLE();
-  }
-
-  ASSERT(call->ArgumentCount() == 2);
-  Definition* left = call->ArgumentAt(0);
-  Definition* right = call->ArgumentAt(1);
-  if (operands_type == kDoubleCid) {
-    if (!CanUnboxDouble()) {
-      return false;
-    }
-    // Check that either left or right are not a smi.  Result of a
-    // binary operation with two smis is a smi not a double, except '/' which
-    // returns a double for two smis.
-    if (op_kind != Token::kDIV) {
-      InsertBefore(call,
-                   new(Z) CheckEitherNonSmiInstr(
-                       new(Z) Value(left),
-                       new(Z) Value(right),
-                       call->deopt_id()),
-                   call->env(),
-                   FlowGraph::kEffect);
-    }
-
-    BinaryDoubleOpInstr* double_bin_op =
-        new(Z) BinaryDoubleOpInstr(op_kind,
-                                   new(Z) Value(left),
-                                   new(Z) Value(right),
-                                   call->deopt_id(), call->token_pos());
-    ReplaceCall(call, double_bin_op);
-  } else if (operands_type == kMintCid) {
-    if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
-    if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
-      ShiftMintOpInstr* shift_op =
-          new(Z) ShiftMintOpInstr(
-              op_kind, new(Z) Value(left), new(Z) Value(right),
-              call->deopt_id());
-      ReplaceCall(call, shift_op);
-    } else {
-      BinaryMintOpInstr* bin_op =
-          new(Z) BinaryMintOpInstr(
-              op_kind, new(Z) Value(left), new(Z) Value(right),
-              call->deopt_id());
-      ReplaceCall(call, bin_op);
-    }
-  } else if (operands_type == kFloat32x4Cid) {
-    return InlineFloat32x4BinaryOp(call, op_kind);
-  } else if (operands_type == kInt32x4Cid) {
-    return InlineInt32x4BinaryOp(call, op_kind);
-  } else if (operands_type == kFloat64x2Cid) {
-    return InlineFloat64x2BinaryOp(call, op_kind);
-  } else if (op_kind == Token::kMOD) {
-    ASSERT(operands_type == kSmiCid);
-    if (right->IsConstant()) {
-      const Object& obj = right->AsConstant()->value();
-      if (obj.IsSmi() && Utils::IsPowerOfTwo(Smi::Cast(obj).Value())) {
-        // Insert smi check and attach a copy of the original environment
-        // because the smi operation can still deoptimize.
-        InsertBefore(call,
-                     new(Z) CheckSmiInstr(new(Z) Value(left),
-                                          call->deopt_id(),
-                                          call->token_pos()),
-                     call->env(),
-                     FlowGraph::kEffect);
-        ConstantInstr* constant =
-            flow_graph()->GetConstant(Smi::Handle(Z,
-                Smi::New(Smi::Cast(obj).Value() - 1)));
-        BinarySmiOpInstr* bin_op =
-            new(Z) BinarySmiOpInstr(Token::kBIT_AND,
-                                    new(Z) Value(left),
-                                    new(Z) Value(constant),
-                                    call->deopt_id());
-        ReplaceCall(call, bin_op);
-        return true;
-      }
-    }
-    // Insert two smi checks and attach a copy of the original
-    // environment because the smi operation can still deoptimize.
-    AddCheckSmi(left, call->deopt_id(), call->env(), call);
-    AddCheckSmi(right, call->deopt_id(), call->env(), call);
-    BinarySmiOpInstr* bin_op =
-        new(Z) BinarySmiOpInstr(op_kind,
-                                new(Z) Value(left),
-                                new(Z) Value(right),
-                                call->deopt_id());
-    ReplaceCall(call, bin_op);
-  } else {
-    ASSERT(operands_type == kSmiCid);
-    // Insert two smi checks and attach a copy of the original
-    // environment because the smi operation can still deoptimize.
-    AddCheckSmi(left, call->deopt_id(), call->env(), call);
-    AddCheckSmi(right, call->deopt_id(), call->env(), call);
-    if (left->IsConstant() &&
-        ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) {
-      // Constant should be on the right side.
-      Definition* temp = left;
-      left = right;
-      right = temp;
-    }
-    BinarySmiOpInstr* bin_op =
-        new(Z) BinarySmiOpInstr(
-            op_kind,
-            new(Z) Value(left),
-            new(Z) Value(right),
-            call->deopt_id());
-    ReplaceCall(call, bin_op);
-  }
-  return true;
-}
-
-
-bool FlowGraphOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
-                                               Token::Kind op_kind) {
-  ASSERT(call->ArgumentCount() == 1);
-  Definition* input = call->ArgumentAt(0);
-  Definition* unary_op = NULL;
-  if (HasOnlyOneSmi(*call->ic_data())) {
-    InsertBefore(call,
-                 new(Z) CheckSmiInstr(new(Z) Value(input),
-                                      call->deopt_id(),
-                                      call->token_pos()),
-                 call->env(),
-                 FlowGraph::kEffect);
-    unary_op = new(Z) UnarySmiOpInstr(
-        op_kind, new(Z) Value(input), call->deopt_id());
-  } else if ((op_kind == Token::kBIT_NOT) &&
-             HasOnlySmiOrMint(*call->ic_data()) &&
-             FlowGraphCompiler::SupportsUnboxedMints()) {
-    unary_op = new(Z) UnaryMintOpInstr(
-        op_kind, new(Z) Value(input), call->deopt_id());
-  } else if (HasOnlyOneDouble(*call->ic_data()) &&
-             (op_kind == Token::kNEGATE) &&
-             CanUnboxDouble()) {
-    AddReceiverCheck(call);
-    unary_op = new(Z) UnaryDoubleOpInstr(
-        Token::kNEGATE, new(Z) Value(input), call->deopt_id());
-  } else {
-    return false;
-  }
-  ASSERT(unary_op != NULL);
-  ReplaceCall(call, unary_op);
-  return true;
-}
-
-
-// Using field class
-RawField* FlowGraphOptimizer::GetField(intptr_t class_id,
-                                       const String& field_name) {
-  Class& cls = Class::Handle(Z, isolate()->class_table()->At(class_id));
-  Field& field = Field::Handle(Z);
-  while (!cls.IsNull()) {
-    field = cls.LookupInstanceField(field_name);
-    if (!field.IsNull()) {
-      return field.raw();
-    }
-    cls = cls.SuperClass();
-  }
-  return Field::null();
-}
-
-
-// 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(
-    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
-    // may later add overriding methods.
-    return true;
-  }
-  Definition* callee_receiver = call->ArgumentAt(0);
-  ASSERT(callee_receiver != NULL);
-  const Function& function = flow_graph_->function();
-  if (function.IsDynamicFunction() &&
-      callee_receiver->IsParameter() &&
-      (callee_receiver->AsParameter()->index() == 0)) {
-    const String& name = (kind == RawFunction::kMethodExtractor)
-        ? String::Handle(Z, Field::NameFromGetter(call->function_name()))
-        : call->function_name();
-    const Class& cls = Class::Handle(Z, function.Owner());
-    if (!thread()->cha()->HasOverride(cls, name)) {
-      if (FLAG_trace_cha) {
-        THR_Print("  **(CHA) Instance call needs no check, "
-            "no overrides of '%s' '%s'\n",
-            name.ToCString(), cls.ToCString());
-      }
-      thread()->cha()->AddToLeafClasses(cls);
-      return false;
-    }
-  }
-  return true;
-}
-
-
-bool FlowGraphOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call,
-                                                      bool allow_check) {
-  ASSERT(call->HasICData());
-  const ICData& ic_data = *call->ic_data();
-  ASSERT(ic_data.HasOneTarget());
-  GrowableArray<intptr_t> class_ids;
-  ic_data.GetClassIdsAt(0, &class_ids);
-  ASSERT(class_ids.length() == 1);
-  // Inline implicit instance getter.
-  const String& field_name =
-      String::Handle(Z, Field::NameFromGetter(call->function_name()));
-  const Field& field =
-      Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
-  ASSERT(!field.IsNull());
-
-  if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) {
-    if (!allow_check) {
-      return false;
-    }
-    AddReceiverCheck(call);
-  }
-  LoadFieldInstr* load = new(Z) LoadFieldInstr(
-      new(Z) Value(call->ArgumentAt(0)),
-      &field,
-      AbstractType::ZoneHandle(Z, field.type()),
-      call->token_pos());
-  load->set_is_immutable(field.is_final());
-  if (field.guarded_cid() != kIllegalCid) {
-    if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) {
-      load->set_result_cid(field.guarded_cid());
-    }
-    FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field);
-  }
-
-  // Discard the environment from the original instruction because the load
-  // can't deoptimize.
-  call->RemoveEnvironment();
-  ReplaceCall(call, load);
-
-  if (load->result_cid() != kDynamicCid) {
-    // Reset value types if guarded_cid was used.
-    for (Value::Iterator it(load->input_use_list());
-         !it.Done();
-         it.Advance()) {
-      it.Current()->SetReachingType(NULL);
-    }
-  }
-  return true;
-}
-
-
-bool FlowGraphOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
-                                               MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  intptr_t mask = 0;
-  if ((getter == MethodRecognizer::kFloat32x4Shuffle) ||
-      (getter == MethodRecognizer::kFloat32x4ShuffleMix)) {
-    // Extract shuffle mask.
-    Definition* mask_definition = NULL;
-    if (getter == MethodRecognizer::kFloat32x4Shuffle) {
-      ASSERT(call->ArgumentCount() == 2);
-      mask_definition = call->ArgumentAt(1);
-    } else {
-      ASSERT(getter == MethodRecognizer::kFloat32x4ShuffleMix);
-      ASSERT(call->ArgumentCount() == 3);
-      mask_definition = call->ArgumentAt(2);
-    }
-    if (!mask_definition->IsConstant()) {
-      return false;
-    }
-    ASSERT(mask_definition->IsConstant());
-    ConstantInstr* constant_instruction = mask_definition->AsConstant();
-    const Object& constant_mask = constant_instruction->value();
-    if (!constant_mask.IsSmi()) {
-      return false;
-    }
-    ASSERT(constant_mask.IsSmi());
-    mask = Smi::Cast(constant_mask).Value();
-    if ((mask < 0) || (mask > 255)) {
-      // Not a valid mask.
-      return false;
-    }
-  }
-  if (getter == MethodRecognizer::kFloat32x4GetSignMask) {
-    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kFloat32x4ShuffleMix) {
-    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        new(Z) Value(call->ArgumentAt(1)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else {
-    ASSERT((getter == MethodRecognizer::kFloat32x4Shuffle)  ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleX) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleY) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleZ) ||
-           (getter == MethodRecognizer::kFloat32x4ShuffleW));
-    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-  UNREACHABLE();
-  return false;
-}
-
-
-bool FlowGraphOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
-                                               MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  if ((getter == MethodRecognizer::kFloat64x2GetX) ||
-      (getter == MethodRecognizer::kFloat64x2GetY)) {
-    Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        0,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-  UNREACHABLE();
-  return false;
-}
-
-
-bool FlowGraphOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
-                                              MethodRecognizer::Kind getter) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  AddCheckClass(call->ArgumentAt(0),
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  intptr_t mask = 0;
-  if ((getter == MethodRecognizer::kInt32x4Shuffle) ||
-      (getter == MethodRecognizer::kInt32x4ShuffleMix)) {
-    // Extract shuffle mask.
-    Definition* mask_definition = NULL;
-    if (getter == MethodRecognizer::kInt32x4Shuffle) {
-      ASSERT(call->ArgumentCount() == 2);
-      mask_definition = call->ArgumentAt(1);
-    } else {
-      ASSERT(getter == MethodRecognizer::kInt32x4ShuffleMix);
-      ASSERT(call->ArgumentCount() == 3);
-      mask_definition = call->ArgumentAt(2);
-    }
-    if (!mask_definition->IsConstant()) {
-      return false;
-    }
-    ASSERT(mask_definition->IsConstant());
-    ConstantInstr* constant_instruction = mask_definition->AsConstant();
-    const Object& constant_mask = constant_instruction->value();
-    if (!constant_mask.IsSmi()) {
-      return false;
-    }
-    ASSERT(constant_mask.IsSmi());
-    mask = Smi::Cast(constant_mask).Value();
-    if ((mask < 0) || (mask > 255)) {
-      // Not a valid mask.
-      return false;
-    }
-  }
-  if (getter == MethodRecognizer::kInt32x4GetSignMask) {
-    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kInt32x4ShuffleMix) {
-    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        new(Z) Value(call->ArgumentAt(1)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else if (getter == MethodRecognizer::kInt32x4Shuffle) {
-    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        mask,
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  } else {
-    Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr(
-        getter,
-        new(Z) Value(call->ArgumentAt(0)),
-        call->deopt_id());
-    ReplaceCall(call, instr);
-    return true;
-  }
-}
-
-
-bool FlowGraphOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
-                                                 Token::Kind op_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->ArgumentCount() == 2);
-  Definition* left = call->ArgumentAt(0);
-  Definition* right = call->ArgumentAt(1);
-  // Type check left.
-  AddCheckClass(left,
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  // Type check right.
-  AddCheckClass(right,
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  // Replace call.
-  BinaryFloat32x4OpInstr* float32x4_bin_op =
-      new(Z) BinaryFloat32x4OpInstr(
-          op_kind, new(Z) Value(left), new(Z) Value(right),
-          call->deopt_id());
-  ReplaceCall(call, float32x4_bin_op);
-
-  return true;
-}
-
-
-bool FlowGraphOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
-                                                Token::Kind op_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->ArgumentCount() == 2);
-  Definition* left = call->ArgumentAt(0);
-  Definition* right = call->ArgumentAt(1);
-  // Type check left.
-  AddCheckClass(left,
-                ICData::ZoneHandle(
-                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  // Type check right.
-  AddCheckClass(right,
-                ICData::ZoneHandle(Z,
-                    call->ic_data()->AsUnaryClassChecksForArgNr(1)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  // Replace call.
-  BinaryInt32x4OpInstr* int32x4_bin_op =
-      new(Z) BinaryInt32x4OpInstr(
-          op_kind, new(Z) Value(left), new(Z) Value(right),
-          call->deopt_id());
-  ReplaceCall(call, int32x4_bin_op);
-  return true;
-}
-
-
-bool FlowGraphOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
-                                                 Token::Kind op_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->ArgumentCount() == 2);
-  Definition* left = call->ArgumentAt(0);
-  Definition* right = call->ArgumentAt(1);
-  // Type check left.
-  AddCheckClass(left,
-                ICData::ZoneHandle(
-                    call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  // Type check right.
-  AddCheckClass(right,
-                ICData::ZoneHandle(
-                    call->ic_data()->AsUnaryClassChecksForArgNr(1)),
-                call->deopt_id(),
-                call->env(),
-                call);
-  // Replace call.
-  BinaryFloat64x2OpInstr* float64x2_bin_op =
-      new(Z) BinaryFloat64x2OpInstr(
-          op_kind, new(Z) Value(left), new(Z) Value(right),
-          call->deopt_id());
-  ReplaceCall(call, float64x2_bin_op);
-  return true;
-}
-
-
-// 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) {
-  ASSERT(call->HasICData());
-  const ICData& ic_data = *call->ic_data();
-  if (ic_data.NumberOfUsedChecks() == 0) {
-    // No type feedback collected.
-    return false;
-  }
-
-  if (!ic_data.HasOneTarget()) {
-    // Polymorphic sites are inlined like normal methods by conventional
-    // inlining in FlowGraphInliner.
-    return false;
-  }
-
-  const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0));
-  if (target.kind() != RawFunction::kImplicitGetter) {
-    // Non-implicit getters are inlined like normal methods by conventional
-    // inlining in FlowGraphInliner.
-    return false;
-  }
-  return InlineImplicitInstanceGetter(call, allow_check);
-}
-
-
-bool FlowGraphOptimizer::TryReplaceInstanceCallWithInline(
-    InstanceCallInstr* call) {
-  Function& target = Function::Handle(Z);
-  GrowableArray<intptr_t> class_ids;
-  call->ic_data()->GetCheckAt(0, &class_ids, &target);
-  const intptr_t receiver_cid = class_ids[0];
-
-  TargetEntryInstr* entry;
-  Definition* last;
-  if (!TryInlineRecognizedMethod(receiver_cid,
-                                 target,
-                                 call,
-                                 call->ArgumentAt(0),
-                                 call->token_pos(),
-                                 *call->ic_data(),
-                                 &entry, &last)) {
-    return false;
-  }
-
-  // Insert receiver class check.
-  AddReceiverCheck(call);
-  // Remove the original push arguments.
-  for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-    PushArgumentInstr* push = call->PushArgumentAt(i);
-    push->ReplaceUsesWith(push->value()->definition());
-    push->RemoveFromGraph();
-  }
-  // Replace all uses of this definition with the result.
-  call->ReplaceUsesWith(last);
-  // Finally insert the sequence other definition in place of this one in the
-  // graph.
-  call->previous()->LinkTo(entry->next());
-  entry->UnuseAllInputs();  // Entry block is not in the graph.
-  last->LinkTo(call);
-  // Remove through the iterator.
-  ASSERT(current_iterator()->Current() == call);
-  current_iterator()->RemoveCurrentFromGraph();
-  call->set_previous(NULL);
-  call->set_next(NULL);
-  return true;
-}
-
-
-// Returns the LoadIndexedInstr.
-Definition* FlowGraphOptimizer::PrepareInlineStringIndexOp(
-    Instruction* call,
-    intptr_t cid,
-    Definition* str,
-    Definition* index,
-    Instruction* cursor) {
-
-  cursor = flow_graph()->AppendTo(cursor,
-                                  new(Z) CheckSmiInstr(
-                                      new(Z) Value(index),
-                                      call->deopt_id(),
-                                      call->token_pos()),
-                                  call->env(),
-                                  FlowGraph::kEffect);
-
-  // Load the length of the string.
-  // Treat length loads as mutable (i.e. affected by side effects) to avoid
-  // hoisting them since we can't hoist the preceding class-check. This
-  // is because of externalization of strings that affects their class-id.
-  LoadFieldInstr* length = new(Z) LoadFieldInstr(
-      new(Z) Value(str),
-      String::length_offset(),
-      Type::ZoneHandle(Z, Type::SmiType()),
-      str->token_pos());
-  length->set_result_cid(kSmiCid);
-  length->set_recognized_kind(MethodRecognizer::kStringBaseLength);
-
-  cursor = flow_graph()->AppendTo(cursor, length, NULL, FlowGraph::kValue);
-  // Bounds check.
-  cursor = flow_graph()->AppendTo(cursor,
-                                   new(Z) CheckArrayBoundInstr(
-                                       new(Z) Value(length),
-                                       new(Z) Value(index),
-                                       call->deopt_id()),
-                                   call->env(),
-                                   FlowGraph::kEffect);
-
-  LoadIndexedInstr* load_indexed = new(Z) LoadIndexedInstr(
-      new(Z) Value(str),
-      new(Z) Value(index),
-      Instance::ElementSizeFor(cid),
-      cid,
-      Thread::kNoDeoptId,
-      call->token_pos());
-
-  cursor = flow_graph()->AppendTo(cursor,
-                                  load_indexed,
-                                  NULL,
-                                  FlowGraph::kValue);
-  ASSERT(cursor == load_indexed);
-  return load_indexed;
-}
-
-
-bool FlowGraphOptimizer::InlineStringCodeUnitAt(
-    Instruction* call,
-    intptr_t cid,
-    TargetEntryInstr** entry,
-    Definition** last) {
-  // TODO(johnmccutchan): Handle external strings in PrepareInlineStringIndexOp.
-  if (RawObject::IsExternalStringClassId(cid)) {
-    return false;
-  }
-
-  Definition* str = call->ArgumentAt(0);
-  Definition* index = call->ArgumentAt(1);
-
-  *entry = new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
-                                   call->GetBlock()->try_index());
-  (*entry)->InheritDeoptTarget(Z, call);
-
-  *last = PrepareInlineStringIndexOp(call, cid, str, index, *entry);
-
-  return true;
-}
-
-
-bool FlowGraphOptimizer::InlineStringBaseCharAt(
-    Instruction* call,
-    intptr_t cid,
-    TargetEntryInstr** entry,
-    Definition** last) {
-  // TODO(johnmccutchan): Handle external strings in PrepareInlineStringIndexOp.
-  if (RawObject::IsExternalStringClassId(cid) || cid != kOneByteStringCid) {
-    return false;
-  }
-  Definition* str = call->ArgumentAt(0);
-  Definition* index = call->ArgumentAt(1);
-
-  *entry = new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
-                                   call->GetBlock()->try_index());
-  (*entry)->InheritDeoptTarget(Z, call);
-
-  *last = PrepareInlineStringIndexOp(call, cid, str, index, *entry);
-
-  StringFromCharCodeInstr* char_at = new(Z) StringFromCharCodeInstr(
-      new(Z) Value(*last), cid);
-
-  flow_graph()->AppendTo(*last, char_at, NULL, FlowGraph::kValue);
-  *last = char_at;
-
-  return true;
-}
-
-
-bool FlowGraphOptimizer::InlineDoubleOp(
-    Token::Kind op_kind,
-    Instruction* call,
-    TargetEntryInstr** entry,
-    Definition** last) {
-  Definition* left = call->ArgumentAt(0);
-  Definition* right = call->ArgumentAt(1);
-
-  *entry = new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
-                                   call->GetBlock()->try_index());
-  (*entry)->InheritDeoptTarget(Z, call);
-  // Arguments are checked. No need for class check.
-  BinaryDoubleOpInstr* double_bin_op =
-      new(Z) BinaryDoubleOpInstr(op_kind,
-                                 new(Z) Value(left),
-                                 new(Z) Value(right),
-                                 call->deopt_id(), call->token_pos());
-  flow_graph()->AppendTo(*entry, double_bin_op, call->env(), FlowGraph::kValue);
-  *last = double_bin_op;
-
-  return true;
-}
-
-
-void FlowGraphOptimizer::ReplaceWithMathCFunction(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  AddReceiverCheck(call);
-  ZoneGrowableArray<Value*>* args =
-      new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
-  for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
-    args->Add(new(Z) Value(call->ArgumentAt(i)));
-  }
-  InvokeMathCFunctionInstr* invoke =
-      new(Z) InvokeMathCFunctionInstr(args,
-                                      call->deopt_id(),
-                                      recognized_kind,
-                                      call->token_pos());
-  ReplaceCall(call, invoke);
-}
-
-
-static bool IsSupportedByteArrayViewCid(intptr_t cid) {
-  switch (cid) {
-    case kTypedDataInt8ArrayCid:
-    case kTypedDataUint8ArrayCid:
-    case kExternalTypedDataUint8ArrayCid:
-    case kTypedDataUint8ClampedArrayCid:
-    case kExternalTypedDataUint8ClampedArrayCid:
-    case kTypedDataInt16ArrayCid:
-    case kTypedDataUint16ArrayCid:
-    case kTypedDataInt32ArrayCid:
-    case kTypedDataUint32ArrayCid:
-    case kTypedDataFloat32ArrayCid:
-    case kTypedDataFloat64ArrayCid:
-    case kTypedDataFloat32x4ArrayCid:
-    case kTypedDataInt32x4ArrayCid:
-      return true;
-    default:
-      return false;
-  }
-}
-
-
-// Inline only simple, frequently called core library methods.
-bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
-  ASSERT(call->HasICData());
-  const ICData& ic_data = *call->ic_data();
-  if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
-    // No type feedback collected or multiple targets found.
-    return false;
-  }
-
-  Function& target = Function::Handle(Z);
-  GrowableArray<intptr_t> class_ids;
-  ic_data.GetCheckAt(0, &class_ids, &target);
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(target);
-
-  if ((recognized_kind == MethodRecognizer::kGrowableArraySetData) &&
-      (ic_data.NumberOfChecks() == 1) &&
-      (class_ids[0] == kGrowableObjectArrayCid)) {
-    // This is an internal method, no need to check argument types.
-    Definition* array = call->ArgumentAt(0);
-    Definition* value = call->ArgumentAt(1);
-    StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
-        GrowableObjectArray::data_offset(),
-        new(Z) Value(array),
-        new(Z) Value(value),
-        kEmitStoreBarrier,
-        call->token_pos());
-    ReplaceCall(call, store);
-    return true;
-  }
-
-  if ((recognized_kind == MethodRecognizer::kGrowableArraySetLength) &&
-      (ic_data.NumberOfChecks() == 1) &&
-      (class_ids[0] == kGrowableObjectArrayCid)) {
-    // This is an internal method, no need to check argument types nor
-    // range.
-    Definition* array = call->ArgumentAt(0);
-    Definition* value = call->ArgumentAt(1);
-    StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
-        GrowableObjectArray::length_offset(),
-        new(Z) Value(array),
-        new(Z) Value(value),
-        kNoStoreBarrier,
-        call->token_pos());
-    ReplaceCall(call, store);
-    return true;
-  }
-
-  if (((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) ||
-       (recognized_kind == MethodRecognizer::kStringBaseCharAt)) &&
-      (ic_data.NumberOfChecks() == 1) &&
-      ((class_ids[0] == kOneByteStringCid) ||
-       (class_ids[0] == kTwoByteStringCid))) {
-    return TryReplaceInstanceCallWithInline(call);
-  }
-
-  if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) {
-    if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
-      // This is an internal method, no need to check argument types nor
-      // range.
-      Definition* str = call->ArgumentAt(0);
-      Definition* index = call->ArgumentAt(1);
-      Definition* value = call->ArgumentAt(2);
-      StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr(
-          new(Z) Value(str),
-          new(Z) Value(index),
-          new(Z) Value(value),
-          kNoStoreBarrier,
-          1,  // Index scale
-          kOneByteStringCid,
-          call->deopt_id(),
-          call->token_pos());
-      ReplaceCall(call, store_op);
-      return true;
-    }
-    return false;
-  }
-
-  if (CanUnboxDouble() &&
-      (recognized_kind == MethodRecognizer::kIntegerToDouble) &&
-      (ic_data.NumberOfChecks() == 1)) {
-    if (class_ids[0] == kSmiCid) {
-      AddReceiverCheck(call);
-      ReplaceCall(call,
-                  new(Z) SmiToDoubleInstr(
-                      new(Z) Value(call->ArgumentAt(0)),
-                      call->token_pos()));
-      return true;
-    } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) {
-      AddReceiverCheck(call);
-      ReplaceCall(call,
-                  new(Z) MintToDoubleInstr(new(Z) Value(call->ArgumentAt(0)),
-                                           call->deopt_id()));
-      return true;
-    }
-  }
-
-  if (class_ids[0] == kDoubleCid) {
-    if (!CanUnboxDouble()) {
-      return false;
-    }
-    switch (recognized_kind) {
-      case MethodRecognizer::kDoubleToInteger: {
-        AddReceiverCheck(call);
-        ASSERT(call->HasICData());
-        const ICData& ic_data = *call->ic_data();
-        Definition* input = call->ArgumentAt(0);
-        Definition* d2i_instr = NULL;
-        if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) {
-          // Do not repeatedly deoptimize because result didn't fit into Smi.
-          d2i_instr =  new(Z) DoubleToIntegerInstr(
-              new(Z) Value(input), call);
-        } else {
-          // Optimistically assume result fits into Smi.
-          d2i_instr = new(Z) DoubleToSmiInstr(
-              new(Z) Value(input), call->deopt_id());
-        }
-        ReplaceCall(call, d2i_instr);
-        return true;
-      }
-      case MethodRecognizer::kDoubleMod:
-      case MethodRecognizer::kDoubleRound:
-        ReplaceWithMathCFunction(call, recognized_kind);
-        return true;
-      case MethodRecognizer::kDoubleTruncate:
-      case MethodRecognizer::kDoubleFloor:
-      case MethodRecognizer::kDoubleCeil:
-        if (!TargetCPUFeatures::double_truncate_round_supported()) {
-          ReplaceWithMathCFunction(call, recognized_kind);
-        } else {
-          AddReceiverCheck(call);
-          DoubleToDoubleInstr* d2d_instr =
-              new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)),
-                                         recognized_kind, call->deopt_id());
-          ReplaceCall(call, d2d_instr);
-        }
-        return true;
-      case MethodRecognizer::kDoubleAdd:
-      case MethodRecognizer::kDoubleSub:
-      case MethodRecognizer::kDoubleMul:
-      case MethodRecognizer::kDoubleDiv:
-        return TryReplaceInstanceCallWithInline(call);
-      default:
-        // Unsupported method.
-        return false;
-    }
-  }
-
-  if (IsSupportedByteArrayViewCid(class_ids[0]) &&
-      (ic_data.NumberOfChecks() == 1)) {
-    return TryReplaceInstanceCallWithInline(call);
-  }
-
-  if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
-    return TryInlineFloat32x4Method(call, recognized_kind);
-  }
-
-  if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
-    return TryInlineInt32x4Method(call, recognized_kind);
-  }
-
-  if ((class_ids[0] == kFloat64x2Cid) && (ic_data.NumberOfChecks() == 1)) {
-    return TryInlineFloat64x2Method(call, recognized_kind);
-  }
-
-  if (recognized_kind == MethodRecognizer::kIntegerLeftShiftWithMask32) {
-    ASSERT(call->ArgumentCount() == 3);
-    ASSERT(ic_data.NumArgsTested() == 2);
-    Definition* value = call->ArgumentAt(0);
-    Definition* count = call->ArgumentAt(1);
-    Definition* int32_mask = call->ArgumentAt(2);
-    if (HasOnlyTwoOf(ic_data, kSmiCid)) {
-      if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
-        return false;
-      }
-      // We cannot overflow. The input value must be a Smi
-      AddCheckSmi(value, call->deopt_id(), call->env(), call);
-      AddCheckSmi(count, call->deopt_id(), call->env(), call);
-      ASSERT(int32_mask->IsConstant());
-      const Integer& mask_literal = Integer::Cast(
-          int32_mask->AsConstant()->value());
-      const int64_t mask_value = mask_literal.AsInt64Value();
-      ASSERT(mask_value >= 0);
-      if (mask_value > Smi::kMaxValue) {
-        // The result will not be Smi.
-        return false;
-      }
-      BinarySmiOpInstr* left_shift =
-          new(Z) BinarySmiOpInstr(Token::kSHL,
-                                  new(Z) Value(value),
-                                  new(Z) Value(count),
-                                  call->deopt_id());
-      left_shift->mark_truncating();
-      if ((kBitsPerWord == 32) && (mask_value == 0xffffffffLL)) {
-        // No BIT_AND operation needed.
-        ReplaceCall(call, left_shift);
-      } else {
-        InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
-        BinarySmiOpInstr* bit_and =
-            new(Z) BinarySmiOpInstr(Token::kBIT_AND,
-                                    new(Z) Value(left_shift),
-                                    new(Z) Value(int32_mask),
-                                    call->deopt_id());
-        ReplaceCall(call, bit_and);
-      }
-      return true;
-    }
-
-    if (HasTwoMintOrSmi(ic_data) &&
-        HasOnlyOneSmi(ICData::Handle(Z,
-                                     ic_data.AsUnaryClassChecksForArgNr(1)))) {
-      if (!FlowGraphCompiler::SupportsUnboxedMints() ||
-          ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
-        return false;
-      }
-      ShiftMintOpInstr* left_shift =
-          new(Z) ShiftMintOpInstr(Token::kSHL,
-                                  new(Z) Value(value),
-                                  new(Z) Value(count),
-                                  call->deopt_id());
-      InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
-      BinaryMintOpInstr* bit_and =
-          new(Z) BinaryMintOpInstr(Token::kBIT_AND,
-                                   new(Z) Value(left_shift),
-                                   new(Z) Value(int32_mask),
-                                   call->deopt_id());
-      ReplaceCall(call, bit_and);
-      return true;
-    }
-  }
-  return false;
-}
-
-
-bool FlowGraphOptimizer::TryInlineFloat32x4Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (Compiler::always_optimize()) {
-    // Cannot handle unboxed instructions.
-    return false;
-  }
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  if (recognized_kind == MethodRecognizer::kFloat32x4Zero) {
-    Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr();
-    ReplaceCall(call, zero);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) {
-    Float32x4SplatInstr* splat =
-        new(Z) Float32x4SplatInstr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, splat);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) {
-    Float32x4ConstructorInstr* con =
-        new(Z) Float32x4ConstructorInstr(
-            new(Z) Value(call->ArgumentAt(1)),
-            new(Z) Value(call->ArgumentAt(2)),
-            new(Z) Value(call->ArgumentAt(3)),
-            new(Z) Value(call->ArgumentAt(4)),
-            call->deopt_id());
-    ReplaceCall(call, con);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat32x4FromInt32x4Bits) {
-    Int32x4ToFloat32x4Instr* cast =
-        new(Z) Int32x4ToFloat32x4Instr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, cast);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2) {
-    Float64x2ToFloat32x4Instr* cast =
-        new(Z) Float64x2ToFloat32x4Instr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, cast);
-    return true;
-  }
-  return false;
-}
-
-
-bool FlowGraphOptimizer::TryInlineFloat64x2Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (Compiler::always_optimize()) {
-    // Cannot handle unboxed instructions.
-    return false;
-  }
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  if (recognized_kind == MethodRecognizer::kFloat64x2Zero) {
-    Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr();
-    ReplaceCall(call, zero);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) {
-    Float64x2SplatInstr* splat =
-        new(Z) Float64x2SplatInstr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, splat);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat64x2Constructor) {
-    Float64x2ConstructorInstr* con =
-        new(Z) Float64x2ConstructorInstr(
-            new(Z) Value(call->ArgumentAt(1)),
-            new(Z) Value(call->ArgumentAt(2)),
-            call->deopt_id());
-    ReplaceCall(call, con);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4) {
-    Float32x4ToFloat64x2Instr* cast =
-        new(Z) Float32x4ToFloat64x2Instr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, cast);
-    return true;
-  }
-  return false;
-}
-
-
-bool FlowGraphOptimizer::TryInlineInt32x4Constructor(
-    StaticCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (Compiler::always_optimize()) {
-    // Cannot handle unboxed instructions.
-    return false;
-  }
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) {
-    Int32x4BoolConstructorInstr* con =
-        new(Z) Int32x4BoolConstructorInstr(
-            new(Z) Value(call->ArgumentAt(1)),
-            new(Z) Value(call->ArgumentAt(2)),
-            new(Z) Value(call->ArgumentAt(3)),
-            new(Z) Value(call->ArgumentAt(4)),
-            call->deopt_id());
-    ReplaceCall(call, con);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kInt32x4FromFloat32x4Bits) {
-    Float32x4ToInt32x4Instr* cast =
-        new(Z) Float32x4ToInt32x4Instr(
-            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
-    ReplaceCall(call, cast);
-    return true;
-  } else if (recognized_kind == MethodRecognizer::kInt32x4Constructor) {
-    Int32x4ConstructorInstr* con =
-        new(Z) Int32x4ConstructorInstr(
-            new(Z) Value(call->ArgumentAt(1)),
-            new(Z) Value(call->ArgumentAt(2)),
-            new(Z) Value(call->ArgumentAt(3)),
-            new(Z) Value(call->ArgumentAt(4)),
-            call->deopt_id());
-    ReplaceCall(call, con);
-    return true;
-  }
-  return false;
-}
-
-
-bool FlowGraphOptimizer::TryInlineFloat32x4Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->HasICData());
-  switch (recognized_kind) {
-    case MethodRecognizer::kFloat32x4ShuffleX:
-    case MethodRecognizer::kFloat32x4ShuffleY:
-    case MethodRecognizer::kFloat32x4ShuffleZ:
-    case MethodRecognizer::kFloat32x4ShuffleW:
-    case MethodRecognizer::kFloat32x4GetSignMask:
-      ASSERT(call->ic_data()->HasReceiverClassId(kFloat32x4Cid));
-      ASSERT(call->ic_data()->HasOneTarget());
-      return InlineFloat32x4Getter(call, recognized_kind);
-
-    case MethodRecognizer::kFloat32x4Equal:
-    case MethodRecognizer::kFloat32x4GreaterThan:
-    case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
-    case MethodRecognizer::kFloat32x4LessThan:
-    case MethodRecognizer::kFloat32x4LessThanOrEqual:
-    case MethodRecognizer::kFloat32x4NotEqual: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      // Replace call.
-      Float32x4ComparisonInstr* cmp =
-          new(Z) Float32x4ComparisonInstr(recognized_kind,
-                                          new(Z) Value(left),
-                                          new(Z) Value(right),
-                                          call->deopt_id());
-      ReplaceCall(call, cmp);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Min:
-    case MethodRecognizer::kFloat32x4Max: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Float32x4MinMaxInstr* minmax =
-          new(Z) Float32x4MinMaxInstr(
-              recognized_kind,
-              new(Z) Value(left),
-              new(Z) Value(right),
-              call->deopt_id());
-      ReplaceCall(call, minmax);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Scale: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      // Left and right values are swapped when handed to the instruction,
-      // this is done so that the double value is loaded into the output
-      // register and can be destroyed.
-      Float32x4ScaleInstr* scale =
-          new(Z) Float32x4ScaleInstr(recognized_kind,
-                                     new(Z) Value(right),
-                                     new(Z) Value(left),
-                                     call->deopt_id());
-      ReplaceCall(call, scale);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Sqrt:
-    case MethodRecognizer::kFloat32x4ReciprocalSqrt:
-    case MethodRecognizer::kFloat32x4Reciprocal: {
-      Definition* left = call->ArgumentAt(0);
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Float32x4SqrtInstr* sqrt =
-          new(Z) Float32x4SqrtInstr(recognized_kind,
-                                    new(Z) Value(left),
-                                    call->deopt_id());
-      ReplaceCall(call, sqrt);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4WithX:
-    case MethodRecognizer::kFloat32x4WithY:
-    case MethodRecognizer::kFloat32x4WithZ:
-    case MethodRecognizer::kFloat32x4WithW: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Float32x4WithInstr* with = new(Z) Float32x4WithInstr(recognized_kind,
-                                                           new(Z) Value(left),
-                                                           new(Z) Value(right),
-                                                           call->deopt_id());
-      ReplaceCall(call, with);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Absolute:
-    case MethodRecognizer::kFloat32x4Negate: {
-      Definition* left = call->ArgumentAt(0);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Float32x4ZeroArgInstr* zeroArg =
-          new(Z) Float32x4ZeroArgInstr(
-              recognized_kind, new(Z) Value(left), call->deopt_id());
-      ReplaceCall(call, zeroArg);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4Clamp: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* lower = call->ArgumentAt(1);
-      Definition* upper = call->ArgumentAt(2);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Float32x4ClampInstr* clamp = new(Z) Float32x4ClampInstr(
-          new(Z) Value(left),
-          new(Z) Value(lower),
-          new(Z) Value(upper),
-          call->deopt_id());
-      ReplaceCall(call, clamp);
-      return true;
-    }
-    case MethodRecognizer::kFloat32x4ShuffleMix:
-    case MethodRecognizer::kFloat32x4Shuffle: {
-      return InlineFloat32x4Getter(call, recognized_kind);
-    }
-    default:
-      return false;
-  }
-}
-
-
-bool FlowGraphOptimizer::TryInlineFloat64x2Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->HasICData());
-  switch (recognized_kind) {
-    case MethodRecognizer::kFloat64x2GetX:
-    case MethodRecognizer::kFloat64x2GetY:
-      ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid));
-      ASSERT(call->ic_data()->HasOneTarget());
-      return InlineFloat64x2Getter(call, recognized_kind);
-    case MethodRecognizer::kFloat64x2Negate:
-    case MethodRecognizer::kFloat64x2Abs:
-    case MethodRecognizer::kFloat64x2Sqrt:
-    case MethodRecognizer::kFloat64x2GetSignMask: {
-      Definition* left = call->ArgumentAt(0);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Float64x2ZeroArgInstr* zeroArg =
-          new(Z) Float64x2ZeroArgInstr(
-              recognized_kind, new(Z) Value(left), call->deopt_id());
-      ReplaceCall(call, zeroArg);
-      return true;
-    }
-    case MethodRecognizer::kFloat64x2Scale:
-    case MethodRecognizer::kFloat64x2WithX:
-    case MethodRecognizer::kFloat64x2WithY:
-    case MethodRecognizer::kFloat64x2Min:
-    case MethodRecognizer::kFloat64x2Max: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* right = call->ArgumentAt(1);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Float64x2OneArgInstr* zeroArg =
-          new(Z) Float64x2OneArgInstr(recognized_kind,
-                                      new(Z) Value(left),
-                                      new(Z) Value(right),
-                                      call->deopt_id());
-      ReplaceCall(call, zeroArg);
-      return true;
-    }
-    default:
-      return false;
-  }
-}
-
-
-bool FlowGraphOptimizer::TryInlineInt32x4Method(
-    InstanceCallInstr* call,
-    MethodRecognizer::Kind recognized_kind) {
-  if (!ShouldInlineSimd()) {
-    return false;
-  }
-  ASSERT(call->HasICData());
-  switch (recognized_kind) {
-    case MethodRecognizer::kInt32x4ShuffleMix:
-    case MethodRecognizer::kInt32x4Shuffle:
-    case MethodRecognizer::kInt32x4GetFlagX:
-    case MethodRecognizer::kInt32x4GetFlagY:
-    case MethodRecognizer::kInt32x4GetFlagZ:
-    case MethodRecognizer::kInt32x4GetFlagW:
-    case MethodRecognizer::kInt32x4GetSignMask:
-      ASSERT(call->ic_data()->HasReceiverClassId(kInt32x4Cid));
-      ASSERT(call->ic_data()->HasOneTarget());
-      return InlineInt32x4Getter(call, recognized_kind);
-
-    case MethodRecognizer::kInt32x4Select: {
-      Definition* mask = call->ArgumentAt(0);
-      Definition* trueValue = call->ArgumentAt(1);
-      Definition* falseValue = call->ArgumentAt(2);
-      // Type check left.
-      AddCheckClass(mask,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Int32x4SelectInstr* select = new(Z) Int32x4SelectInstr(
-          new(Z) Value(mask),
-          new(Z) Value(trueValue),
-          new(Z) Value(falseValue),
-          call->deopt_id());
-      ReplaceCall(call, select);
-      return true;
-    }
-    case MethodRecognizer::kInt32x4WithFlagX:
-    case MethodRecognizer::kInt32x4WithFlagY:
-    case MethodRecognizer::kInt32x4WithFlagZ:
-    case MethodRecognizer::kInt32x4WithFlagW: {
-      Definition* left = call->ArgumentAt(0);
-      Definition* flag = call->ArgumentAt(1);
-      // Type check left.
-      AddCheckClass(left,
-                    ICData::ZoneHandle(
-                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
-                    call->deopt_id(),
-                    call->env(),
-                    call);
-      Int32x4SetFlagInstr* setFlag = new(Z) Int32x4SetFlagInstr(
-          recognized_kind,
-          new(Z) Value(left),
-          new(Z) Value(flag),
-          call->deopt_id());
-      ReplaceCall(call, setFlag);
-      return true;
-    }
-    default:
-      return false;
-  }
-}
-
-
-bool FlowGraphOptimizer::InlineByteArrayBaseLoad(Instruction* call,
-                                                 Definition* receiver,
-                                                 intptr_t array_cid,
-                                                 intptr_t view_cid,
-                                                 const ICData& ic_data,
-                                                 TargetEntryInstr** entry,
-                                                 Definition** last) {
-  ASSERT(array_cid != kIllegalCid);
-  Definition* array = receiver;
-  Definition* index = call->ArgumentAt(1);
-  *entry = new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
-                                   call->GetBlock()->try_index());
-  (*entry)->InheritDeoptTarget(Z, call);
-  Instruction* cursor = *entry;
-
-  array_cid = PrepareInlineByteArrayBaseOp(call,
-                                           array_cid,
-                                           view_cid,
-                                           &array,
-                                           index,
-                                           &cursor);
-
-  intptr_t deopt_id = Thread::kNoDeoptId;
-  if ((array_cid == kTypedDataInt32ArrayCid) ||
-      (array_cid == kTypedDataUint32ArrayCid)) {
-    // Deoptimization may be needed if result does not always fit in a Smi.
-    deopt_id = (kSmiBits >= 32) ? Thread::kNoDeoptId : call->deopt_id();
-  }
-
-  *last = new(Z) LoadIndexedInstr(new(Z) Value(array),
-                                  new(Z) Value(index),
-                                  1,
-                                  view_cid,
-                                  deopt_id,
-                                  call->token_pos());
-  cursor = flow_graph()->AppendTo(
-      cursor,
-      *last,
-      deopt_id != Thread::kNoDeoptId ? call->env() : NULL,
-      FlowGraph::kValue);
-
-  if (view_cid == kTypedDataFloat32ArrayCid) {
-    *last = new(Z) FloatToDoubleInstr(new(Z) Value(*last), deopt_id);
-    flow_graph()->AppendTo(cursor,
-                           *last,
-                           deopt_id != Thread::kNoDeoptId ? call->env() : NULL,
-                           FlowGraph::kValue);
-  }
-  return true;
-}
-
-
-bool FlowGraphOptimizer::InlineByteArrayBaseStore(const Function& target,
-                                                  Instruction* call,
-                                                  Definition* receiver,
-                                                  intptr_t array_cid,
-                                                  intptr_t view_cid,
-                                                  const ICData& ic_data,
-                                                  TargetEntryInstr** entry,
-                                                  Definition** last) {
-  ASSERT(array_cid != kIllegalCid);
-  Definition* array = receiver;
-  Definition* index = call->ArgumentAt(1);
-  *entry = new(Z) TargetEntryInstr(flow_graph()->allocate_block_id(),
-                                   call->GetBlock()->try_index());
-  (*entry)->InheritDeoptTarget(Z, call);
-  Instruction* cursor = *entry;
-
-  array_cid = PrepareInlineByteArrayBaseOp(call,
-                                           array_cid,
-                                           view_cid,
-                                           &array,
-                                           index,
-                                           &cursor);
-
-  // Extract the instance call so we can use the function_name in the stored
-  // value check ICData.
-  InstanceCallInstr* i_call = NULL;
-  if (call->IsPolymorphicInstanceCall()) {
-    i_call = call->AsPolymorphicInstanceCall()->instance_call();
-  } else {
-    ASSERT(call->IsInstanceCall());
-    i_call = call->AsInstanceCall();
-  }
-  ASSERT(i_call != NULL);
-  ICData& value_check = ICData::ZoneHandle(Z);
-  switch (view_cid) {
-    case kTypedDataInt8ArrayCid:
-    case kTypedDataUint8ArrayCid:
-    case kTypedDataUint8ClampedArrayCid:
-    case kExternalTypedDataUint8ArrayCid:
-    case kExternalTypedDataUint8ClampedArrayCid:
-    case kTypedDataInt16ArrayCid:
-    case kTypedDataUint16ArrayCid: {
-      // Check that value is always smi.
-      value_check = ICData::New(flow_graph_->function(),
-                                i_call->function_name(),
-                                Object::empty_array(),  // Dummy args. descr.
-                                Thread::kNoDeoptId,
-                                1);
-      value_check.AddReceiverCheck(kSmiCid, target);
-      break;
-    }
-    case kTypedDataInt32ArrayCid:
-    case kTypedDataUint32ArrayCid:
-      // On 64-bit platforms assume that stored value is always a smi.
-      if (kSmiBits >= 32) {
-        value_check = ICData::New(flow_graph_->function(),
-                                  i_call->function_name(),
-                                  Object::empty_array(),  // Dummy args. descr.
-                                  Thread::kNoDeoptId,
-                                  1);
-        value_check.AddReceiverCheck(kSmiCid, target);
-      }
-      break;
-    case kTypedDataFloat32ArrayCid:
-    case kTypedDataFloat64ArrayCid: {
-      // Check that value is always double.
-      value_check = ICData::New(flow_graph_->function(),
-                                i_call->function_name(),
-                                Object::empty_array(),  // Dummy args. descr.
-                                Thread::kNoDeoptId,
-                                1);
-      value_check.AddReceiverCheck(kDoubleCid, target);
-      break;
-    }
-    case kTypedDataInt32x4ArrayCid: {
-      // Check that value is always Int32x4.
-      value_check = ICData::New(flow_graph_->function(),
-                                i_call->function_name(),
-                                Object::empty_array(),  // Dummy args. descr.
-                                Thread::kNoDeoptId,
-                                1);
-      value_check.AddReceiverCheck(kInt32x4Cid, target);
-      break;
-    }
-    case kTypedDataFloat32x4ArrayCid: {
-      // Check that value is always Float32x4.
-      value_check = ICData::New(flow_graph_->function(),
-                                i_call->function_name(),
-                                Object::empty_array(),  // Dummy args. descr.
-                                Thread::kNoDeoptId,
-                                1);
-      value_check.AddReceiverCheck(kFloat32x4Cid, target);
-      break;
-    }
-    default:
-      // Array cids are already checked in the caller.
-      UNREACHABLE();
-  }
-
-  Definition* stored_value = call->ArgumentAt(2);
-  if (!value_check.IsNull()) {
-    AddCheckClass(stored_value, value_check, call->deopt_id(), call->env(),
-                  call);
-  }
-
-  if (view_cid == kTypedDataFloat32ArrayCid) {
-    stored_value = new(Z) DoubleToFloatInstr(
-        new(Z) Value(stored_value), call->deopt_id());
-    cursor = flow_graph()->AppendTo(cursor,
-                                    stored_value,
-                                    NULL,
-                                    FlowGraph::kValue);
-  } else if (view_cid == kTypedDataInt32ArrayCid) {
-    stored_value = new(Z) UnboxInt32Instr(
-        UnboxInt32Instr::kTruncate,
-        new(Z) Value(stored_value),
-        call->deopt_id());
-    cursor = flow_graph()->AppendTo(cursor,
-                                    stored_value,
-                                    call->env(),
-                                    FlowGraph::kValue);
-  } else if (view_cid == kTypedDataUint32ArrayCid) {
-    stored_value = new(Z) UnboxUint32Instr(
-        new(Z) Value(stored_value),
-        call->deopt_id());
-    ASSERT(stored_value->AsUnboxInteger()->is_truncating());
-    cursor = flow_graph()->AppendTo(cursor,
-                                    stored_value,
-                                    call->env(),
-                                    FlowGraph::kValue);
-  }
-
-  StoreBarrierType needs_store_barrier = kNoStoreBarrier;
-  *last = new(Z) StoreIndexedInstr(new(Z) Value(array),
-                                   new(Z) Value(index),
-                                   new(Z) Value(stored_value),
-                                   needs_store_barrier,
-                                   1,  // Index scale
-                                   view_cid,
-                                   call->deopt_id(),
-                                   call->token_pos());
-
-  flow_graph()->AppendTo(cursor,
-                         *last,
-                         call->deopt_id() != Thread::kNoDeoptId ?
-                            call->env() : NULL,
-                         FlowGraph::kEffect);
-  return true;
-}
-
-
-
-intptr_t FlowGraphOptimizer::PrepareInlineByteArrayBaseOp(
-    Instruction* call,
-    intptr_t array_cid,
-    intptr_t view_cid,
-    Definition** array,
-    Definition* byte_index,
-    Instruction** cursor) {
-  // Insert byte_index smi check.
-  *cursor = flow_graph()->AppendTo(*cursor,
-                                   new(Z) CheckSmiInstr(
-                                       new(Z) Value(byte_index),
-                                       call->deopt_id(),
-                                       call->token_pos()),
-                                   call->env(),
-                                   FlowGraph::kEffect);
-
-  LoadFieldInstr* length =
-      new(Z) LoadFieldInstr(
-          new(Z) Value(*array),
-          CheckArrayBoundInstr::LengthOffsetFor(array_cid),
-          Type::ZoneHandle(Z, Type::SmiType()),
-          call->token_pos());
-  length->set_is_immutable(true);
-  length->set_result_cid(kSmiCid);
-  length->set_recognized_kind(
-      LoadFieldInstr::RecognizedKindFromArrayCid(array_cid));
-  *cursor = flow_graph()->AppendTo(*cursor,
-                                   length,
-                                   NULL,
-                                   FlowGraph::kValue);
-
-  intptr_t element_size = Instance::ElementSizeFor(array_cid);
-  ConstantInstr* bytes_per_element =
-      flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(element_size)));
-  BinarySmiOpInstr* len_in_bytes =
-      new(Z) BinarySmiOpInstr(Token::kMUL,
-                              new(Z) Value(length),
-                              new(Z) Value(bytes_per_element),
-                              call->deopt_id());
-  *cursor = flow_graph()->AppendTo(*cursor, len_in_bytes, call->env(),
-                                   FlowGraph::kValue);
-
-  // adjusted_length = len_in_bytes - (element_size - 1).
-  Definition* adjusted_length = len_in_bytes;
-  intptr_t adjustment = Instance::ElementSizeFor(view_cid) - 1;
-  if (adjustment > 0) {
-    ConstantInstr* length_adjustment =
-        flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(adjustment)));
-    adjusted_length =
-        new(Z) BinarySmiOpInstr(Token::kSUB,
-                                new(Z) Value(len_in_bytes),
-                                new(Z) Value(length_adjustment),
-                                call->deopt_id());
-    *cursor = flow_graph()->AppendTo(*cursor, adjusted_length, call->env(),
-                                     FlowGraph::kValue);
-  }
-
-  // Check adjusted_length > 0.
-  ConstantInstr* zero =
-      flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(0)));
-  *cursor = flow_graph()->AppendTo(*cursor,
-                                   new(Z) CheckArrayBoundInstr(
-                                       new(Z) Value(adjusted_length),
-                                       new(Z) Value(zero),
-                                       call->deopt_id()),
-                                   call->env(),
-                                   FlowGraph::kEffect);
-  // Check 0 <= byte_index < adjusted_length.
-  *cursor = flow_graph()->AppendTo(*cursor,
-                                   new(Z) CheckArrayBoundInstr(
-                                       new(Z) Value(adjusted_length),
-                                       new(Z) Value(byte_index),
-                                       call->deopt_id()),
-                                   call->env(),
-                                   FlowGraph::kEffect);
-
-  if (RawObject::IsExternalTypedDataClassId(array_cid)) {
-    LoadUntaggedInstr* elements =
-        new(Z) LoadUntaggedInstr(new(Z) Value(*array),
-                                 ExternalTypedData::data_offset());
-    *cursor = flow_graph()->AppendTo(*cursor,
-                                     elements,
-                                     NULL,
-                                     FlowGraph::kValue);
-    *array = elements;
-  }
-  return array_cid;
-}
-
-
-// If type tests specified by 'ic_data' do not depend on type arguments,
-// return mapping cid->result in 'results' (i : cid; i + 1: result).
-// If all tests yield the same result, return it otherwise return Bool::null.
-// 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(
-    const ICData& ic_data,
-    const AbstractType& type,
-    ZoneGrowableArray<intptr_t>* results) const {
-  ASSERT(results->is_empty());
-  ASSERT(ic_data.NumArgsTested() == 1);  // Unary checks only.
-  if (!type.IsInstantiated() || type.IsMalformedOrMalbounded()) {
-    return Bool::null();
-  }
-  const Class& type_class = Class::Handle(Z, type.type_class());
-  const intptr_t num_type_args = type_class.NumTypeArguments();
-  if (num_type_args > 0) {
-    // Only raw types can be directly compared, thus disregarding type
-    // arguments.
-    const intptr_t num_type_params = type_class.NumTypeParameters();
-    const intptr_t from_index = num_type_args - num_type_params;
-    const TypeArguments& type_arguments =
-        TypeArguments::Handle(Z, type.arguments());
-    const bool is_raw_type = type_arguments.IsNull() ||
-        type_arguments.IsRaw(from_index, num_type_params);
-    if (!is_raw_type) {
-      // Unknown result.
-      return Bool::null();
-    }
-  }
-
-  const ClassTable& class_table = *isolate()->class_table();
-  Bool& prev = Bool::Handle(Z);
-  Class& cls = Class::Handle(Z);
-
-  bool results_differ = false;
-  for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
-    cls = class_table.At(ic_data.GetReceiverClassIdAt(i));
-    if (cls.NumTypeArguments() > 0) {
-      return Bool::null();
-    }
-    const bool is_subtype = cls.IsSubtypeOf(
-        TypeArguments::Handle(Z),
-        type_class,
-        TypeArguments::Handle(Z),
-        NULL,
-        Heap::kOld);
-    results->Add(cls.id());
-    results->Add(is_subtype);
-    if (prev.IsNull()) {
-      prev = Bool::Get(is_subtype).raw();
-    } else {
-      if (is_subtype != prev.value()) {
-        results_differ = true;
-      }
-    }
-  }
-  return results_differ ?  Bool::null() : prev.raw();
-}
-
-
-// Returns true if checking against this type is a direct class id comparison.
-bool FlowGraphOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
-  ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
-  // Requires CHA.
-  if (!type.IsInstantiated()) return false;
-  const Class& type_class = Class::Handle(type.type_class());
-  // Signature classes have different type checking rules.
-  if (type_class.IsSignatureClass()) return false;
-  // Could be an interface check?
-  if (CHA::IsImplemented(type_class)) return false;
-  // Check if there are subclasses.
-  if (CHA::HasSubclasses(type_class)) {
-    return false;
-  }
-
-  // Private classes cannot be subclassed by later loaded libs.
-  if (!type_class.IsPrivate()) {
-    if (FLAG_use_cha_deopt || isolate()->all_classes_finalized()) {
-      if (FLAG_trace_cha) {
-        THR_Print("  **(CHA) Typecheck as class equality since no "
-            "subclasses: %s\n",
-            type_class.ToCString());
-      }
-      if (FLAG_use_cha_deopt) {
-        thread()->cha()->AddToLeafClasses(type_class);
-      }
-    } else {
-      return false;
-    }
-  }
-  const intptr_t num_type_args = type_class.NumTypeArguments();
-  if (num_type_args > 0) {
-    // Only raw types can be directly compared, thus disregarding type
-    // arguments.
-    const intptr_t num_type_params = type_class.NumTypeParameters();
-    const intptr_t from_index = num_type_args - num_type_params;
-    const TypeArguments& type_arguments =
-        TypeArguments::Handle(type.arguments());
-    const bool is_raw_type = type_arguments.IsNull() ||
-        type_arguments.IsRaw(from_index, num_type_params);
-    return is_raw_type;
-  }
-  return true;
-}
-
-
-static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results,
-                                   intptr_t test_cid) {
-  for (intptr_t i = 0; i < results.length(); i += 2) {
-    if (results[i] == test_cid) return true;
-  }
-  return false;
-}
-
-
-static void TryAddTest(ZoneGrowableArray<intptr_t>* results,
-                       intptr_t test_cid,
-                       bool result) {
-  if (!CidTestResultsContains(*results, test_cid)) {
-    results->Add(test_cid);
-    results->Add(result);
-  }
-}
-
-
-// Tries to add cid tests to 'results' so that no deoptimization is
-// necessary.
-// TODO(srdjan): Do also for other than 'int' type.
-static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results,
-                                    const AbstractType& type) {
-  ASSERT(results->length() >= 2);  // At least on eentry.
-  const ClassTable& class_table = *Isolate::Current()->class_table();
-  if ((*results)[0] != kSmiCid) {
-    const Class& cls = Class::Handle(class_table.At(kSmiCid));
-    const Class& type_class = Class::Handle(type.type_class());
-    const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(),
-                                                type_class,
-                                                TypeArguments::Handle(),
-                                                NULL,
-                                                Heap::kOld);
-    results->Add((*results)[results->length() - 2]);
-    results->Add((*results)[results->length() - 2]);
-    for (intptr_t i = results->length() - 3; i > 1; --i) {
-      (*results)[i] = (*results)[i - 2];
-    }
-    (*results)[0] = kSmiCid;
-    (*results)[1] = smi_is_subtype;
-  }
-
-  ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded());
-  ASSERT(results->length() >= 2);
-  if (type.IsIntType()) {
-    ASSERT((*results)[0] == kSmiCid);
-    TryAddTest(results, kMintCid, true);
-    TryAddTest(results, kBigintCid, true);
-    // Cannot deoptimize since all tests returning true have been added.
-    return false;
-  }
-
-  return true;  // May deoptimize since we have not identified all 'true' tests.
-}
-
-
-// TODO(srdjan): Use ICData to check if always true or false.
-void FlowGraphOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
-  ASSERT(Token::IsTypeTestOperator(call->token_kind()));
-  Definition* left = call->ArgumentAt(0);
-  Definition* type_args = NULL;
-  AbstractType& type = AbstractType::ZoneHandle(Z);
-  bool negate = false;
-  if (call->ArgumentCount() == 2) {
-    type_args = flow_graph()->constant_null();
-    if (call->function_name().raw() ==
-        Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) {
-      type = Type::Number();
-    } else if (call->function_name().raw() ==
-        Library::PrivateCoreLibName(Symbols::_instanceOfInt()).raw()) {
-      type = Type::IntType();
-    } else if (call->function_name().raw() ==
-        Library::PrivateCoreLibName(Symbols::_instanceOfSmi()).raw()) {
-      type = Type::SmiType();
-    } else if (call->function_name().raw() ==
-        Library::PrivateCoreLibName(Symbols::_instanceOfDouble()).raw()) {
-      type = Type::Double();
-    } else if (call->function_name().raw() ==
-        Library::PrivateCoreLibName(Symbols::_instanceOfString()).raw()) {
-      type = Type::StringType();
-    } else {
-      UNIMPLEMENTED();
-    }
-    negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition()
-        ->AsConstant()->value()).value();
-  } else {
-    type_args = call->ArgumentAt(1);
-    type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw();
-    negate = Bool::Cast(call->ArgumentAt(3)->OriginalDefinition()
-        ->AsConstant()->value()).value();
-  }
-  const ICData& unary_checks =
-      ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
-  if (FLAG_warn_on_javascript_compatibility &&
-      !unary_checks.IssuedJSWarning() &&
-      (type.IsIntType() || type.IsDoubleType() || !type.IsInstantiated())) {
-    // No warning was reported yet for this type check, either because it has
-    // not been executed yet, or because no problematic combinations of instance
-    // type and test type have been encountered so far. A warning may still be
-    // reported, so do not replace the instance call.
-    return;
-  }
-  if ((unary_checks.NumberOfChecks() > 0) &&
-      (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
-    ZoneGrowableArray<intptr_t>* results =
-        new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
-    Bool& as_bool =
-        Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results));
-    if (as_bool.IsNull()) {
-      if (results->length() == unary_checks.NumberOfChecks() * 2) {
-        const bool can_deopt = TryExpandTestCidsResult(results, type);
-        TestCidsInstr* test_cids = new(Z) TestCidsInstr(
-            call->token_pos(),
-            negate ? Token::kISNOT : Token::kIS,
-            new(Z) Value(left),
-            *results,
-            can_deopt ? call->deopt_id() : Thread::kNoDeoptId);
-        // Remove type.
-        ReplaceCall(call, test_cids);
-        return;
-      }
-    } else {
-      // TODO(srdjan): Use TestCidsInstr also for this case.
-      // One result only.
-      AddReceiverCheck(call);
-      if (negate) {
-        as_bool = Bool::Get(!as_bool.value()).raw();
-      }
-      ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool);
-      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-        PushArgumentInstr* push = call->PushArgumentAt(i);
-        push->ReplaceUsesWith(push->value()->definition());
-        push->RemoveFromGraph();
-      }
-      call->ReplaceUsesWith(bool_const);
-      ASSERT(current_iterator()->Current() == call);
-      current_iterator()->RemoveCurrentFromGraph();
-      return;
-    }
-  }
-
-  if (TypeCheckAsClassEquality(type)) {
-    LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left));
-    InsertBefore(call,
-                 left_cid,
-                 NULL,
-                 FlowGraph::kValue);
-    const intptr_t type_cid = Class::Handle(Z, type.type_class()).id();
-    ConstantInstr* cid =
-        flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid)));
-
-    StrictCompareInstr* check_cid =
-        new(Z) StrictCompareInstr(
-            call->token_pos(),
-            negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
-            new(Z) Value(left_cid),
-            new(Z) Value(cid),
-            false);  // No number check.
-    ReplaceCall(call, check_cid);
-    return;
-  }
-
-  InstanceOfInstr* instance_of =
-      new(Z) InstanceOfInstr(call->token_pos(),
-                             new(Z) Value(left),
-                             new(Z) Value(type_args),
-                             type,
-                             negate,
-                             call->deopt_id());
-  ReplaceCall(call, instance_of);
-}
-
-
-// TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
-void FlowGraphOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
-  ASSERT(Token::IsTypeCastOperator(call->token_kind()));
-  Definition* left = call->ArgumentAt(0);
-  Definition* type_args = call->ArgumentAt(1);
-  const AbstractType& type =
-      AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
-  ASSERT(!type.IsMalformedOrMalbounded());
-  const ICData& unary_checks =
-      ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
-  if (FLAG_warn_on_javascript_compatibility &&
-      !unary_checks.IssuedJSWarning() &&
-      (type.IsIntType() || type.IsDoubleType() || !type.IsInstantiated())) {
-    // No warning was reported yet for this type check, either because it has
-    // not been executed yet, or because no problematic combinations of instance
-    // type and test type have been encountered so far. A warning may still be
-    // reported, so do not replace the instance call.
-    return;
-  }
-  if ((unary_checks.NumberOfChecks() > 0) &&
-      (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
-    ZoneGrowableArray<intptr_t>* results =
-        new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
-    const Bool& as_bool = Bool::ZoneHandle(Z,
-        InstanceOfAsBool(unary_checks, type, results));
-    if (as_bool.raw() == Bool::True().raw()) {
-      AddReceiverCheck(call);
-      // Remove the original push arguments.
-      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-        PushArgumentInstr* push = call->PushArgumentAt(i);
-        push->ReplaceUsesWith(push->value()->definition());
-        push->RemoveFromGraph();
-      }
-      // Remove call, replace it with 'left'.
-      call->ReplaceUsesWith(left);
-      ASSERT(current_iterator()->Current() == call);
-      current_iterator()->RemoveCurrentFromGraph();
-      return;
-    }
-  }
-  const String& dst_name = String::ZoneHandle(Z,
-      Symbols::New(Exceptions::kCastErrorDstName));
-  AssertAssignableInstr* assert_as =
-      new(Z) AssertAssignableInstr(call->token_pos(),
-                                   new(Z) Value(left),
-                                   new(Z) Value(type_args),
-                                   type,
-                                   dst_name,
-                                   call->deopt_id());
-  ReplaceCall(call, assert_as);
-}
-
-
-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) {
-  if (Compiler::always_optimize()) {
-    InstanceCallNoopt(instr);
-    return;
-  }
-
-  if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
-    return;
-  }
-  const Token::Kind op_kind = instr->token_kind();
-
-  // Type test is special as it always gets converted into inlined code.
-  if (Token::IsTypeTestOperator(op_kind)) {
-    ReplaceWithInstanceOf(instr);
-    return;
-  }
-
-  if (Token::IsTypeCastOperator(op_kind)) {
-    ReplaceWithTypeCast(instr);
-    return;
-  }
-
-  const ICData& unary_checks =
-      ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
-
-  const intptr_t max_checks = (op_kind == Token::kEQ)
-      ? FLAG_max_equality_polymorphic_checks
-      : FLAG_max_polymorphic_checks;
-  if ((unary_checks.NumberOfChecks() > max_checks) &&
-      InstanceCallNeedsClassCheck(instr, RawFunction::kRegularFunction)) {
-    // Too many checks, it will be megamorphic which needs unary checks.
-    instr->set_ic_data(&unary_checks);
-    return;
-  }
-
-  if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
-    return;
-  }
-  if ((op_kind == Token::kINDEX) && 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;
-  }
-  if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) {
-    return;
-  }
-  if ((op_kind == Token::kSET) &&
-      TryInlineInstanceSetter(instr, unary_checks)) {
-    return;
-  }
-  if (TryInlineInstanceMethod(instr)) {
-    return;
-  }
-
-  bool has_one_target = 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,
-                                              /* call_with_checks = */ false);
-      instr->ReplaceWith(call, current_iterator());
-      return;
-    }
-  }
-
-  if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
-    bool call_with_checks;
-    if (has_one_target && FLAG_polymorphic_with_deopt) {
-      // Type propagation has not run yet, we cannot eliminate the check.
-      AddReceiverCheck(instr);
-      // Call can still deoptimize, do not detach environment from instr.
-      call_with_checks = false;
-    } else {
-      call_with_checks = true;
-    }
-    PolymorphicInstanceCallInstr* call =
-        new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
-                                            call_with_checks);
-    instr->ReplaceWith(call, current_iterator());
-  }
-}
-
-
-void FlowGraphOptimizer::VisitStaticCall(StaticCallInstr* call) {
-  if (!CanUnboxDouble()) {
-    return;
-  }
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(call->function());
-  MathUnaryInstr::MathUnaryKind unary_kind;
-  switch (recognized_kind) {
-    case MethodRecognizer::kMathSqrt:
-      unary_kind = MathUnaryInstr::kSqrt;
-      break;
-    case MethodRecognizer::kMathSin:
-      unary_kind = MathUnaryInstr::kSin;
-      break;
-    case MethodRecognizer::kMathCos:
-      unary_kind = MathUnaryInstr::kCos;
-      break;
-    default:
-      unary_kind = MathUnaryInstr::kIllegal;
-      break;
-  }
-  if (unary_kind != MathUnaryInstr::kIllegal) {
-    if (Compiler::always_optimize()) {
-      // TODO(srdjan): Adapt MathUnaryInstr to allow tagged inputs as well.
-    } else {
-      MathUnaryInstr* math_unary =
-          new(Z) MathUnaryInstr(unary_kind,
-                                new(Z) Value(call->ArgumentAt(0)),
-                                call->deopt_id());
-      ReplaceCall(call, math_unary);
-    }
-  } else if ((recognized_kind == MethodRecognizer::kFloat32x4Zero) ||
-             (recognized_kind == MethodRecognizer::kFloat32x4Splat) ||
-             (recognized_kind == MethodRecognizer::kFloat32x4Constructor) ||
-             (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2)) {
-    TryInlineFloat32x4Constructor(call, recognized_kind);
-  } else if ((recognized_kind == MethodRecognizer::kFloat64x2Constructor) ||
-             (recognized_kind == MethodRecognizer::kFloat64x2Zero) ||
-             (recognized_kind == MethodRecognizer::kFloat64x2Splat) ||
-             (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4)) {
-    TryInlineFloat64x2Constructor(call, recognized_kind);
-  } else if ((recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) ||
-             (recognized_kind == MethodRecognizer::kInt32x4Constructor)) {
-    TryInlineInt32x4Constructor(call, recognized_kind);
-  } else if (recognized_kind == MethodRecognizer::kObjectConstructor) {
-    // Remove the original push arguments.
-    for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
-      PushArgumentInstr* push = call->PushArgumentAt(i);
-      push->ReplaceUsesWith(push->value()->definition());
-      push->RemoveFromGraph();
-    }
-    // Manually replace call with global null constant. ReplaceCall can't
-    // be used for definitions that are already in the graph.
-    call->ReplaceUsesWith(flow_graph_->constant_null());
-    ASSERT(current_iterator()->Current() == call);
-    current_iterator()->RemoveCurrentFromGraph();;
-  } else if ((recognized_kind == MethodRecognizer::kMathMin) ||
-             (recognized_kind == MethodRecognizer::kMathMax)) {
-    // We can handle only monomorphic min/max call sites with both arguments
-    // being either doubles or smis.
-    if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
-      const ICData& ic_data = *call->ic_data();
-      intptr_t result_cid = kIllegalCid;
-      if (ICDataHasReceiverArgumentClassIds(ic_data, kDoubleCid, kDoubleCid)) {
-        result_cid = kDoubleCid;
-      } else if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
-        result_cid = kSmiCid;
-      }
-      if (result_cid != kIllegalCid) {
-        MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr(
-            recognized_kind,
-            new(Z) Value(call->ArgumentAt(0)),
-            new(Z) Value(call->ArgumentAt(1)),
-            call->deopt_id(),
-            result_cid);
-        const ICData& unary_checks =
-            ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks());
-        AddCheckClass(min_max->left()->definition(),
-                      unary_checks,
-                      call->deopt_id(),
-                      call->env(),
-                      call);
-        AddCheckClass(min_max->right()->definition(),
-                      unary_checks,
-                      call->deopt_id(),
-                      call->env(),
-                      call);
-        ReplaceCall(call, min_max);
-      }
-    }
-  } else if (recognized_kind == MethodRecognizer::kMathDoublePow) {
-    if (Compiler::always_optimize()) {
-      // No UnboxDouble instructons allowed.
-      return;
-    }
-    // We know that first argument is double, the second is num.
-    // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
-    // instructions contain type checks and conversions to double.
-    ZoneGrowableArray<Value*>* args =
-        new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
-    for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
-      args->Add(new(Z) Value(call->ArgumentAt(i)));
-    }
-    InvokeMathCFunctionInstr* invoke =
-        new(Z) InvokeMathCFunctionInstr(args,
-                                        call->deopt_id(),
-                                        recognized_kind,
-                                        call->token_pos());
-    ReplaceCall(call, invoke);
-  } else if (recognized_kind == MethodRecognizer::kDoubleFromInteger) {
-    if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
-      const ICData& ic_data = *call->ic_data();
-      if (CanUnboxDouble()) {
-        if (ArgIsAlways(kSmiCid, ic_data, 1)) {
-          Definition* arg = call->ArgumentAt(1);
-          AddCheckSmi(arg, call->deopt_id(), call->env(), call);
-          ReplaceCall(call,
-                      new(Z) SmiToDoubleInstr(new(Z) Value(arg),
-                                              call->token_pos()));
-        } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
-                   CanConvertUnboxedMintToDouble()) {
-          Definition* arg = call->ArgumentAt(1);
-          ReplaceCall(call,
-                      new(Z) MintToDoubleInstr(new(Z) Value(arg),
-                                               call->deopt_id()));
-        }
-      }
-    }
-  } else if (call->function().IsFactory()) {
-    const Class& function_class =
-        Class::Handle(Z, call->function().Owner());
-    if ((function_class.library() == Library::CoreLibrary()) ||
-        (function_class.library() == Library::TypedDataLibrary())) {
-      intptr_t cid = FactoryRecognizer::ResultCid(call->function());
-      switch (cid) {
-        case kArrayCid: {
-          Value* type = new(Z) Value(call->ArgumentAt(0));
-          Value* num_elements = new(Z) Value(call->ArgumentAt(1));
-          if (num_elements->BindsToConstant() &&
-              num_elements->BoundConstant().IsSmi()) {
-            intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
-            if (length >= 0 && length <= Array::kMaxElements) {
-              CreateArrayInstr* create_array =
-                  new(Z) CreateArrayInstr(
-                      call->token_pos(), type, num_elements);
-              ReplaceCall(call, create_array);
-            }
-          }
-        }
-        default:
-          break;
-      }
-    }
-  }
-}
-
-
-void FlowGraphOptimizer::VisitStoreInstanceField(
-    StoreInstanceFieldInstr* instr) {
-  if (instr->IsUnboxedStore()) {
-    ASSERT(instr->is_potential_unboxed_initialization_);
-    // Determine if this field should be unboxed based on the usage of getter
-    // and setter functions: The heuristic requires that the setter has a
-    // 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 String& field_name = String::Handle(Z, field.name());
-    const Class& owner = Class::Handle(Z, field.owner());
-    const Function& getter =
-        Function::Handle(Z, owner.LookupGetterFunction(field_name));
-    const Function& setter =
-        Function::Handle(Z, owner.LookupSetterFunction(field_name));
-    bool unboxed_field = false;
-    if (!getter.IsNull() && !setter.IsNull()) {
-      if (field.is_double_initialized()) {
-        unboxed_field = true;
-      } else if ((setter.usage_counter() > 0) &&
-                 ((FLAG_getter_setter_ratio * setter.usage_counter()) >=
-                   getter.usage_counter())) {
-        unboxed_field = true;
-      }
-    }
-    if (!unboxed_field) {
-      if (FLAG_trace_optimization || FLAG_trace_field_guards) {
-        THR_Print("Disabling unboxing of %s\n", field.ToCString());
-        if (!setter.IsNull()) {
-          OS::Print("  setter usage count: %" Pd "\n", setter.usage_counter());
-        }
-        if (!getter.IsNull()) {
-          OS::Print("  getter usage count: %" Pd "\n", getter.usage_counter());
-        }
-      }
-      field.set_is_unboxing_candidate(false);
-      if (Compiler::IsBackgroundCompilation()) {
-        // Delay deoptimization of dependent code to the code installation time.
-        // The invalidation of the background compilation result occurs only
-        // when the deoptimization is triggered at code installation.
-        flow_graph()->deoptimize_dependent_code().Add(&field);
-      } else {
-        field.DeoptimizeDependentCode();
-      }
-    } else {
-      FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field);
-    }
-  }
-}
-
-
-void FlowGraphOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
-  // Replace generic allocation with a sequence of inlined allocation and
-  // explicit initalizing stores.
-  AllocateUninitializedContextInstr* replacement =
-      new AllocateUninitializedContextInstr(instr->token_pos(),
-                                            instr->num_context_variables());
-  instr->ReplaceWith(replacement, current_iterator());
-
-  StoreInstanceFieldInstr* store =
-      new(Z) StoreInstanceFieldInstr(Context::parent_offset(),
-                                     new Value(replacement),
-                                     new Value(flow_graph_->constant_null()),
-                                     kNoStoreBarrier,
-                                     instr->token_pos());
-  // Storing into uninitialized memory; remember to prevent dead store
-  // elimination and ensure proper GC barrier.
-  store->set_is_object_reference_initialization(true);
-  flow_graph_->InsertAfter(replacement, store, NULL, FlowGraph::kEffect);
-  Definition* cursor = store;
-  for (intptr_t i = 0; i < instr->num_context_variables(); ++i) {
-    store =
-        new(Z) StoreInstanceFieldInstr(Context::variable_offset(i),
-                                       new Value(replacement),
-                                       new Value(flow_graph_->constant_null()),
-                                       kNoStoreBarrier,
-                                       instr->token_pos());
-    // Storing into uninitialized memory; remember to prevent dead store
-    // elimination and ensure proper GC barrier.
-    store->set_is_object_reference_initialization(true);
-    flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect);
-    cursor = store;
-  }
-}
-
-
-void FlowGraphOptimizer::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())
-    instr->set_representation(kUnboxedMint);
-#endif
-}
-
-
-bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
-                                                 const ICData& unary_ic_data,
-                                                 bool allow_checks) {
-  ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
-      (unary_ic_data.NumArgsTested() == 1));
-  if (I->flags().type_checks()) {
-    // Checked mode setters are inlined like normal methods by conventional
-    // inlining.
-    return false;
-  }
-
-  ASSERT(instr->HasICData());
-  if (unary_ic_data.NumberOfChecks() == 0) {
-    // No type feedback collected.
-    return false;
-  }
-  if (!unary_ic_data.HasOneTarget()) {
-    // Polymorphic sites are inlined like normal method calls by conventional
-    // inlining.
-    return false;
-  }
-  Function& target = Function::Handle(Z);
-  intptr_t class_id;
-  unary_ic_data.GetOneClassCheckAt(0, &class_id, &target);
-  if (target.kind() != RawFunction::kImplicitSetter) {
-    // Non-implicit setter are inlined like normal method calls.
-    return false;
-  }
-  // Inline implicit instance setter.
-  const String& field_name =
-      String::Handle(Z, Field::NameFromSetter(instr->function_name()));
-  const Field& field =
-      Field::ZoneHandle(Z, GetField(class_id, field_name));
-  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);
-  }
-
-  // Field guard was detached.
-  StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
-      field,
-      new(Z) Value(instr->ArgumentAt(0)),
-      new(Z) Value(instr->ArgumentAt(1)),
-      kEmitStoreBarrier,
-      instr->token_pos());
-
-  if (store->IsUnboxedStore()) {
-    FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field);
-  }
-
-  // Discard the environment from the original instruction because the store
-  // can't deoptimize.
-  instr->RemoveEnvironment();
-  ReplaceCall(instr, store);
-  return true;
-}
-
-
-#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_IA32)
-// Smi widening pass is only meaningful on platforms where Smi
-// is smaller than 32bit. For now only support it on ARM and ia32.
-static bool CanBeWidened(BinarySmiOpInstr* smi_op) {
-  return BinaryInt32OpInstr::IsSupported(smi_op->op_kind(),
-                                         smi_op->left(),
-                                         smi_op->right());
-}
-
-
-static bool BenefitsFromWidening(BinarySmiOpInstr* smi_op) {
-  // TODO(vegorov): when shifts with non-constants shift count are supported
-  // add them here as we save untagging for the count.
-  switch (smi_op->op_kind()) {
-    case Token::kMUL:
-    case Token::kSHR:
-      // For kMUL we save untagging of the argument for kSHR
-      // we save tagging of the result.
-      return true;
-
-    default:
-      return false;
-  }
-}
-
-
-void FlowGraphOptimizer::WidenSmiToInt32() {
-  GrowableArray<BinarySmiOpInstr*> candidates;
-
-  // Step 1. Collect all instructions that potentially benefit from widening of
-  // their operands (or their result) into int32 range.
-  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
-       !block_it.Done();
-       block_it.Advance()) {
-    for (ForwardInstructionIterator instr_it(block_it.Current());
-         !instr_it.Done();
-         instr_it.Advance()) {
-      BinarySmiOpInstr* smi_op = instr_it.Current()->AsBinarySmiOp();
-      if ((smi_op != NULL) &&
-          smi_op->HasSSATemp() &&
-          BenefitsFromWidening(smi_op) &&
-          CanBeWidened(smi_op)) {
-        candidates.Add(smi_op);
-      }
-    }
-  }
-
-  if (candidates.is_empty()) {
-    return;
-  }
-
-  // Step 2. For each block in the graph compute which loop it belongs to.
-  // We will use this information later during computation of the widening's
-  // gain: we are going to assume that only conversion occuring inside the
-  // same loop should be counted against the gain, all other conversions
-  // can be hoisted and thus cost nothing compared to the loop cost itself.
-  const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
-      flow_graph()->LoopHeaders();
-
-  GrowableArray<intptr_t> loops(flow_graph_->preorder().length());
-  for (intptr_t i = 0; i < flow_graph_->preorder().length(); i++) {
-    loops.Add(-1);
-  }
-
-  for (intptr_t loop_id = 0; loop_id < loop_headers.length(); ++loop_id) {
-    for (BitVector::Iterator loop_it(loop_headers[loop_id]->loop_info());
-         !loop_it.Done();
-         loop_it.Advance()) {
-      loops[loop_it.Current()] = loop_id;
-    }
-  }
-
-  // Step 3. For each candidate transitively collect all other BinarySmiOpInstr
-  // and PhiInstr that depend on it and that it depends on and count amount of
-  // untagging operations that we save in assumption that this whole graph of
-  // values is using kUnboxedInt32 representation instead of kTagged.
-  // Convert those graphs that have positive gain to kUnboxedInt32.
-
-  // BitVector containing SSA indexes of all processed definitions. Used to skip
-  // those candidates that belong to dependency graph of another candidate.
-  BitVector* processed =
-      new(Z) BitVector(Z, flow_graph_->current_ssa_temp_index());
-
-  // Worklist used to collect dependency graph.
-  DefinitionWorklist worklist(flow_graph_, candidates.length());
-  for (intptr_t i = 0; i < candidates.length(); i++) {
-    BinarySmiOpInstr* op = candidates[i];
-    if (op->WasEliminated() || processed->Contains(op->ssa_temp_index())) {
-      continue;
-    }
-
-    if (FLAG_trace_smi_widening) {
-      THR_Print("analysing candidate: %s\n", op->ToCString());
-    }
-    worklist.Clear();
-    worklist.Add(op);
-
-    // Collect dependency graph. Note: more items are added to worklist
-    // inside this loop.
-    intptr_t gain = 0;
-    for (intptr_t j = 0; j < worklist.definitions().length(); j++) {
-      Definition* defn = worklist.definitions()[j];
-
-      if (FLAG_trace_smi_widening) {
-        THR_Print("> %s\n", defn->ToCString());
-      }
-
-      if (defn->IsBinarySmiOp() &&
-          BenefitsFromWidening(defn->AsBinarySmiOp())) {
-        gain++;
-        if (FLAG_trace_smi_widening) {
-          THR_Print("^ [%" Pd "] (o) %s\n", gain, defn->ToCString());
-        }
-      }
-
-      const intptr_t defn_loop = loops[defn->GetBlock()->preorder_number()];
-
-      // Process all inputs.
-      for (intptr_t k = 0; k < defn->InputCount(); k++) {
-        Definition* input = defn->InputAt(k)->definition();
-        if (input->IsBinarySmiOp() &&
-            CanBeWidened(input->AsBinarySmiOp())) {
-          worklist.Add(input);
-        } else if (input->IsPhi() && (input->Type()->ToCid() == kSmiCid)) {
-          worklist.Add(input);
-        } else if (input->IsBinaryMintOp()) {
-          // Mint operation produces untagged result. We avoid tagging.
-          gain++;
-          if (FLAG_trace_smi_widening) {
-            THR_Print("^ [%" Pd "] (i) %s\n", gain, input->ToCString());
-          }
-        } else if (defn_loop == loops[input->GetBlock()->preorder_number()] &&
-                   (input->Type()->ToCid() == kSmiCid)) {
-          // Input comes from the same loop, is known to be smi and requires
-          // untagging.
-          // TODO(vegorov) this heuristic assumes that values that are not
-          // known to be smi have to be checked and this check can be
-          // coalesced with untagging. Start coalescing them.
-          gain--;
-          if (FLAG_trace_smi_widening) {
-            THR_Print("v [%" Pd "] (i) %s\n", gain, input->ToCString());
-          }
-        }
-      }
-
-      // Process all uses.
-      for (Value* use = defn->input_use_list();
-           use != NULL;
-           use = use->next_use()) {
-        Instruction* instr = use->instruction();
-        Definition* use_defn = instr->AsDefinition();
-        if (use_defn == NULL) {
-          // We assume that tagging before returning or pushing argument costs
-          // very little compared to the cost of the return/call itself.
-          if (!instr->IsReturn() && !instr->IsPushArgument()) {
-            gain--;
-            if (FLAG_trace_smi_widening) {
-              THR_Print("v [%" Pd "] (u) %s\n",
-                        gain,
-                        use->instruction()->ToCString());
-            }
-          }
-          continue;
-        } else if (use_defn->IsBinarySmiOp() &&
-                   CanBeWidened(use_defn->AsBinarySmiOp())) {
-          worklist.Add(use_defn);
-        } else if (use_defn->IsPhi() &&
-                   use_defn->AsPhi()->Type()->ToCid() == kSmiCid) {
-          worklist.Add(use_defn);
-        } else if (use_defn->IsBinaryMintOp()) {
-          // BinaryMintOp requires untagging of its inputs.
-          // Converting kUnboxedInt32 to kUnboxedMint is essentially zero cost
-          // sign extension operation.
-          gain++;
-          if (FLAG_trace_smi_widening) {
-            THR_Print("^ [%" Pd "] (u) %s\n",
-                      gain,
-                      use->instruction()->ToCString());
-          }
-        } else if (defn_loop == loops[instr->GetBlock()->preorder_number()]) {
-          gain--;
-          if (FLAG_trace_smi_widening) {
-            THR_Print("v [%" Pd "] (u) %s\n",
-                      gain,
-                      use->instruction()->ToCString());
-          }
-        }
-      }
-    }
-
-    processed->AddAll(worklist.contains_vector());
-
-    if (FLAG_trace_smi_widening) {
-      THR_Print("~ %s gain %" Pd "\n", op->ToCString(), gain);
-    }
-
-    if (gain > 0) {
-      // We have positive gain from widening. Convert all BinarySmiOpInstr into
-      // BinaryInt32OpInstr and set representation of all phis to kUnboxedInt32.
-      for (intptr_t j = 0; j < worklist.definitions().length(); j++) {
-        Definition* defn = worklist.definitions()[j];
-        ASSERT(defn->IsPhi() || defn->IsBinarySmiOp());
-
-        if (defn->IsBinarySmiOp()) {
-          BinarySmiOpInstr* smi_op = defn->AsBinarySmiOp();
-          BinaryInt32OpInstr* int32_op = new(Z) BinaryInt32OpInstr(
-            smi_op->op_kind(),
-            smi_op->left()->CopyWithType(),
-            smi_op->right()->CopyWithType(),
-            smi_op->DeoptimizationTarget());
-
-          smi_op->ReplaceWith(int32_op, NULL);
-        } else if (defn->IsPhi()) {
-          defn->AsPhi()->set_representation(kUnboxedInt32);
-          ASSERT(defn->Type()->IsInt());
-        }
-      }
-    }
-  }
-}
-#else
-void FlowGraphOptimizer::WidenSmiToInt32() {
-  // TODO(vegorov) ideally on 64-bit platforms we would like to narrow smi
-  // operations to 32-bit where it saves tagging and untagging and allows
-  // to use shorted (and faster) instructions. But we currently don't
-  // save enough range information in the ICData to drive this decision.
-}
-#endif
-
-void FlowGraphOptimizer::InferIntRanges() {
-  RangeAnalysis range_analysis(flow_graph_);
-  range_analysis.Analyze();
-}
-
-
-void TryCatchAnalyzer::Optimize(FlowGraph* flow_graph) {
-  // For every catch-block: Iterate over all call instructions inside the
-  // corresponding try-block and figure out for each environment value if it
-  // is the same constant at all calls. If yes, replace the initial definition
-  // at the catch-entry with this constant.
-  const GrowableArray<CatchBlockEntryInstr*>& catch_entries =
-      flow_graph->graph_entry()->catch_entries();
-  intptr_t base = kFirstLocalSlotFromFp + flow_graph->num_non_copied_params();
-  for (intptr_t catch_idx = 0;
-       catch_idx < catch_entries.length();
-       ++catch_idx) {
-    CatchBlockEntryInstr* catch_entry = catch_entries[catch_idx];
-
-    // Initialize cdefs with the original initial definitions (ParameterInstr).
-    // The following representation is used:
-    // ParameterInstr => unknown
-    // ConstantInstr => known constant
-    // NULL => non-constant
-    GrowableArray<Definition*>* idefs = catch_entry->initial_definitions();
-    GrowableArray<Definition*> cdefs(idefs->length());
-    cdefs.AddArray(*idefs);
-
-    // exception_var and stacktrace_var are never constant.
-    intptr_t ex_idx = base - catch_entry->exception_var().index();
-    intptr_t st_idx = base - catch_entry->stacktrace_var().index();
-    cdefs[ex_idx] = cdefs[st_idx] = NULL;
-
-    for (BlockIterator block_it = flow_graph->reverse_postorder_iterator();
-         !block_it.Done();
-         block_it.Advance()) {
-      BlockEntryInstr* block = block_it.Current();
-      if (block->try_index() == catch_entry->catch_try_index()) {
-        for (ForwardInstructionIterator instr_it(block);
-             !instr_it.Done();
-             instr_it.Advance()) {
-          Instruction* current = instr_it.Current();
-          if (current->MayThrow()) {
-            Environment* env = current->env()->Outermost();
-            ASSERT(env != NULL);
-            for (intptr_t env_idx = 0; env_idx < cdefs.length(); ++env_idx) {
-              if (cdefs[env_idx] != NULL &&
-                  env->ValueAt(env_idx)->BindsToConstant()) {
-                cdefs[env_idx] = env->ValueAt(env_idx)->definition();
-              }
-              if (cdefs[env_idx] != env->ValueAt(env_idx)->definition()) {
-                cdefs[env_idx] = NULL;
-              }
-            }
-          }
-        }
-      }
-    }
-    for (intptr_t j = 0; j < idefs->length(); ++j) {
-      if (cdefs[j] != NULL && cdefs[j]->IsConstant()) {
-        // TODO(fschneider): Use constants from the constant pool.
-        Definition* old = (*idefs)[j];
-        ConstantInstr* orig = cdefs[j]->AsConstant();
-        ConstantInstr* copy =
-            new(flow_graph->zone()) ConstantInstr(orig->value());
-        copy->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index());
-        old->ReplaceUsesWith(copy);
-        (*idefs)[j] = copy;
-      }
-    }
-  }
-}
-
-
-LICM::LICM(FlowGraph* flow_graph) : flow_graph_(flow_graph) {
-  ASSERT(flow_graph->is_licm_allowed());
-}
-
-
-void LICM::Hoist(ForwardInstructionIterator* it,
-                 BlockEntryInstr* pre_header,
-                 Instruction* current) {
-  if (current->IsCheckClass()) {
-    current->AsCheckClass()->set_licm_hoisted(true);
-  } else if (current->IsCheckSmi()) {
-    current->AsCheckSmi()->set_licm_hoisted(true);
-  } else if (current->IsCheckEitherNonSmi()) {
-    current->AsCheckEitherNonSmi()->set_licm_hoisted(true);
-  } else if (current->IsCheckArrayBound()) {
-    current->AsCheckArrayBound()->set_licm_hoisted(true);
-  }
-  if (FLAG_trace_optimization) {
-    THR_Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n",
-              current->DebugName(),
-              current->GetDeoptId(),
-              current->GetBlock()->block_id(),
-              pre_header->block_id());
-  }
-  // Move the instruction out of the loop.
-  current->RemoveEnvironment();
-  if (it != NULL) {
-    it->RemoveCurrentFromGraph();
-  } else {
-    current->RemoveFromGraph();
-  }
-  GotoInstr* last = pre_header->last_instruction()->AsGoto();
-  // Using kind kEffect will not assign a fresh ssa temporary index.
-  flow_graph()->InsertBefore(last, current, last->env(), FlowGraph::kEffect);
-  current->CopyDeoptIdFrom(*last);
-}
-
-
-void LICM::TrySpecializeSmiPhi(PhiInstr* phi,
-                               BlockEntryInstr* header,
-                               BlockEntryInstr* pre_header) {
-  if (phi->Type()->ToCid() == kSmiCid) {
-    return;
-  }
-
-  // Check if there is only a single kDynamicCid input to the phi that
-  // comes from the pre-header.
-  const intptr_t kNotFound = -1;
-  intptr_t non_smi_input = kNotFound;
-  for (intptr_t i = 0; i < phi->InputCount(); ++i) {
-    Value* input = phi->InputAt(i);
-    if (input->Type()->ToCid() != kSmiCid) {
-      if ((non_smi_input != kNotFound) ||
-          (input->Type()->ToCid() != kDynamicCid)) {
-        // There are multiple kDynamicCid inputs or there is an input that is
-        // known to be non-smi.
-        return;
-      } else {
-        non_smi_input = i;
-      }
-    }
-  }
-
-  if ((non_smi_input == kNotFound) ||
-      (phi->block()->PredecessorAt(non_smi_input) != pre_header)) {
-    return;
-  }
-
-  CheckSmiInstr* check = NULL;
-  for (Value* use = phi->input_use_list();
-       (use != NULL) && (check == NULL);
-       use = use->next_use()) {
-    check = use->instruction()->AsCheckSmi();
-  }
-
-  if (check == NULL) {
-    return;
-  }
-
-  // Host CheckSmi instruction and make this phi smi one.
-  Hoist(NULL, pre_header, check);
-
-  // Replace value we are checking with phi's input.
-  check->value()->BindTo(phi->InputAt(non_smi_input)->definition());
-
-  phi->UpdateType(CompileType::FromCid(kSmiCid));
-}
-
-
-// Load instructions handled by load elimination.
-static bool IsLoadEliminationCandidate(Instruction* instr) {
-  return instr->IsLoadField()
-      || instr->IsLoadIndexed()
-      || instr->IsLoadStaticField();
-}
-
-
-static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets,
-                                intptr_t loop_header_index,
-                                Instruction* instr) {
-  return IsLoadEliminationCandidate(instr) &&
-      (sets != NULL) &&
-      instr->HasPlaceId() &&
-      ((*sets)[loop_header_index] != NULL) &&
-      (*sets)[loop_header_index]->Contains(instr->place_id());
-}
-
-
-void LICM::OptimisticallySpecializeSmiPhis() {
-  if (!flow_graph()->function().allows_hoisting_check_class() ||
-      Compiler::always_optimize()) {
-    // Do not hoist any: Either deoptimized on a hoisted check,
-    // or compiling precompiled code where we can't do optimistic
-    // hoisting of checks.
-    return;
-  }
-
-  const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
-      flow_graph()->LoopHeaders();
-
-  for (intptr_t i = 0; i < loop_headers.length(); ++i) {
-    JoinEntryInstr* header = loop_headers[i]->AsJoinEntry();
-    // Skip loop that don't have a pre-header block.
-    BlockEntryInstr* pre_header = header->ImmediateDominator();
-    if (pre_header == NULL) continue;
-
-    for (PhiIterator it(header); !it.Done(); it.Advance()) {
-      TrySpecializeSmiPhi(it.Current(), header, pre_header);
-    }
-  }
-}
-
-
-void LICM::Optimize() {
-  if (!flow_graph()->function().allows_hoisting_check_class()) {
-    // Do not hoist any.
-    return;
-  }
-
-  const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
-      flow_graph()->LoopHeaders();
-
-  ZoneGrowableArray<BitVector*>* loop_invariant_loads =
-      flow_graph()->loop_invariant_loads();
-
-  BlockEffects* block_effects = flow_graph()->block_effects();
-
-  for (intptr_t i = 0; i < loop_headers.length(); ++i) {
-    BlockEntryInstr* header = loop_headers[i];
-    // Skip loop that don't have a pre-header block.
-    BlockEntryInstr* pre_header = header->ImmediateDominator();
-    if (pre_header == NULL) continue;
-
-    for (BitVector::Iterator loop_it(header->loop_info());
-         !loop_it.Done();
-         loop_it.Advance()) {
-      BlockEntryInstr* block = flow_graph()->preorder()[loop_it.Current()];
-      for (ForwardInstructionIterator it(block);
-           !it.Done();
-           it.Advance()) {
-        Instruction* current = it.Current();
-        if ((current->AllowsCSE() &&
-             block_effects->CanBeMovedTo(current, pre_header)) ||
-            IsLoopInvariantLoad(loop_invariant_loads, i, current)) {
-          bool inputs_loop_invariant = true;
-          for (int i = 0; i < current->InputCount(); ++i) {
-            Definition* input_def = current->InputAt(i)->definition();
-            if (!input_def->GetBlock()->Dominates(pre_header)) {
-              inputs_loop_invariant = false;
-              break;
-            }
-          }
-          if (inputs_loop_invariant &&
-              !current->IsAssertAssignable() &&
-              !current->IsAssertBoolean()) {
-            // TODO(fschneider): Enable hoisting of Assert-instructions
-            // if it safe to do.
-            Hoist(&it, pre_header, current);
-          }
-        }
-      }
-    }
-  }
-}
-
-
-// Place describes an abstract location (e.g. field) that IR can load
-// from or store to.
-//
-// Places are also used to describe wild-card locations also known as aliases,
-// that essentially represent sets of places that alias each other. Places A
-// and B are said to alias each other if store into A can affect load from B.
-//
-// We distinguish the following aliases:
-//
-//   - for fields
-//     - *.f, *.@offs - field inside some object;
-//     - X.f, X.@offs - field inside an allocated object X;
-//   - for indexed accesses
-//     - *[*] - non-constant index inside some object;
-//     - *[C] - constant index inside some object;
-//     - X[*] - non-constant index inside an allocated object X;
-//     - X[C] - constant index inside an allocated object X.
-//
-// Constant indexed places are divided into two subcategories:
-//
-//   - Access to homogeneous array-like objects: Array, ImmutableArray,
-//     OneByteString, TwoByteString. These objects can only be accessed
-//     on element by element basis with all elements having the same size.
-//     This means X[C] aliases X[K] if and only if C === K.
-//   - TypedData accesses. TypedData allow to read one of the primitive
-//     data types at the given byte offset. When TypedData is accessed through
-//     index operator on a typed array or a typed array view it is guaranteed
-//     that the byte offset is always aligned by the element size. We write
-//     these accesses as X[C|S], where C is constant byte offset and S is size
-//     of the data type. Obviously X[C|S] and X[K|U] alias if and only if either
-//     C = RoundDown(K, S) or K = RoundDown(C, U).
-//     Note that not all accesses to typed data are aligned: e.g. ByteData
-//     allows unanaligned access through it's get*/set* methods.
-//     Check in Place::SetIndex ensures that we never create a place X[C|S]
-//     such that C is not aligned by S.
-//
-// Separating allocations from other objects improves precision of the
-// load forwarding pass because of the following two properties:
-//
-//   - if X can be proven to have no aliases itself (i.e. there is no other SSA
-//     variable that points to X) then no place inside X can be aliased with any
-//     wildcard dependent place (*.f, *.@offs, *[*], *[C]);
-//   - given allocations X and Y no place inside X can be aliased with any place
-//     inside Y even if any of them or both escape.
-//
-// It important to realize that single place can belong to multiple aliases.
-// For example place X.f with aliased allocation X belongs both to X.f and *.f
-// aliases. Likewise X[C] with non-aliased allocation X belongs to X[C] and X[*]
-// aliases.
-//
-class Place : public ValueObject {
- public:
-  enum Kind {
-    kNone,
-
-    // Field location. For instance fields is represented as a pair of a Field
-    // object and an instance (SSA definition) that is being accessed.
-    // For static fields instance is NULL.
-    kField,
-
-    // VMField location. Represented as a pair of an instance (SSA definition)
-    // being accessed and offset to the field.
-    kVMField,
-
-    // Indexed location with a non-constant index.
-    kIndexed,
-
-    // Indexed location with a constant index.
-    kConstantIndexed,
-  };
-
-  // Size of the element accessed by constant index. Size is only important
-  // for TypedData because those accesses can alias even when constant indexes
-  // are not the same: X[0|4] aliases X[0|2] and X[2|2].
-  enum ElementSize {
-    // If indexed access is not a TypedData access then element size is not
-    // important because there is only a single possible access size depending
-    // on the receiver - X[C] aliases X[K] if and only if C == K.
-    // This is the size set for Array, ImmutableArray, OneByteString and
-    // TwoByteString accesses.
-    kNoSize,
-
-    // 1 byte (Int8List, Uint8List, Uint8ClampedList).
-    kInt8,
-
-    // 2 bytes (Int16List, Uint16List).
-    kInt16,
-
-    // 4 bytes (Int32List, Uint32List, Float32List).
-    kInt32,
-
-    // 8 bytes (Int64List, Uint64List, Float64List).
-    kInt64,
-
-    // 16 bytes (Int32x4List, Float32x4List, Float64x2List).
-    kInt128,
-
-    kLargestElementSize = kInt128,
-  };
-
-  Place(const Place& other)
-      : ValueObject(),
-        flags_(other.flags_),
-        instance_(other.instance_),
-        raw_selector_(other.raw_selector_),
-        id_(other.id_) {
-  }
-
-  // Construct a place from instruction if instruction accesses any place.
-  // Otherwise constructs kNone place.
-  Place(Instruction* instr, bool* is_load, bool* is_store)
-      : flags_(0),
-        instance_(NULL),
-        raw_selector_(0),
-        id_(0) {
-    switch (instr->tag()) {
-      case Instruction::kLoadField: {
-        LoadFieldInstr* load_field = instr->AsLoadField();
-        set_representation(load_field->representation());
-        instance_ = load_field->instance()->definition()->OriginalDefinition();
-        if (load_field->field() != NULL) {
-          set_kind(kField);
-          field_ = load_field->field();
-        } else {
-          set_kind(kVMField);
-          offset_in_bytes_ = load_field->offset_in_bytes();
-        }
-        *is_load = true;
-        break;
-      }
-
-      case Instruction::kStoreInstanceField: {
-        StoreInstanceFieldInstr* store =
-            instr->AsStoreInstanceField();
-        set_representation(store->RequiredInputRepresentation(
-            StoreInstanceFieldInstr::kValuePos));
-        instance_ = store->instance()->definition()->OriginalDefinition();
-        if (!store->field().IsNull()) {
-          set_kind(kField);
-          field_ = &store->field();
-        } else {
-          set_kind(kVMField);
-          offset_in_bytes_ = store->offset_in_bytes();
-        }
-        *is_store = true;
-        break;
-      }
-
-      case Instruction::kLoadStaticField:
-        set_kind(kField);
-        set_representation(instr->AsLoadStaticField()->representation());
-        field_ = &instr->AsLoadStaticField()->StaticField();
-        *is_load = true;
-        break;
-
-      case Instruction::kStoreStaticField:
-        set_kind(kField);
-        set_representation(instr->AsStoreStaticField()->
-            RequiredInputRepresentation(StoreStaticFieldInstr::kValuePos));
-        field_ = &instr->AsStoreStaticField()->field();
-        *is_store = true;
-        break;
-
-      case Instruction::kLoadIndexed: {
-        LoadIndexedInstr* load_indexed = instr->AsLoadIndexed();
-        set_representation(load_indexed->representation());
-        instance_ = load_indexed->array()->definition()->OriginalDefinition();
-        SetIndex(load_indexed->index()->definition(),
-                 load_indexed->index_scale(),
-                 load_indexed->class_id());
-        *is_load = true;
-        break;
-      }
-
-      case Instruction::kStoreIndexed: {
-        StoreIndexedInstr* store_indexed = instr->AsStoreIndexed();
-        set_representation(store_indexed->
-            RequiredInputRepresentation(StoreIndexedInstr::kValuePos));
-        instance_ = store_indexed->array()->definition()->OriginalDefinition();
-        SetIndex(store_indexed->index()->definition(),
-                 store_indexed->index_scale(),
-                 store_indexed->class_id());
-        *is_store = true;
-        break;
-      }
-
-      default:
-        break;
-    }
-  }
-
-  // Create object representing *[*] alias.
-  static Place* CreateAnyInstanceAnyIndexAlias(Zone* zone,
-                                               intptr_t id) {
-    return Wrap(zone, Place(
-        EncodeFlags(kIndexed, kNoRepresentation, kNoSize),
-        NULL,
-        0), id);
-  }
-
-  // Return least generic alias for this place. Given that aliases are
-  // essentially sets of places we define least generic alias as a smallest
-  // alias that contains this place.
-  //
-  // We obtain such alias by a simple transformation:
-  //
-  //    - for places that depend on an instance X.f, X.@offs, X[i], X[C]
-  //      we drop X if X is not an allocation because in this case X does not
-  //      posess an identity obtaining aliases *.f, *.@offs, *[i] and *[C]
-  //      respectively;
-  //    - for non-constant indexed places X[i] we drop information about the
-  //      index obtaining alias X[*].
-  //    - we drop information about representation, but keep element size
-  //      if any.
-  //
-  Place ToAlias() const {
-    return Place(
-        RepresentationBits::update(kNoRepresentation, flags_),
-        (DependsOnInstance() && IsAllocation(instance())) ? instance() : NULL,
-        (kind() == kIndexed) ? 0 : raw_selector_);
-  }
-
-  bool DependsOnInstance() const {
-    switch (kind()) {
-      case kField:
-      case kVMField:
-      case kIndexed:
-      case kConstantIndexed:
-        return true;
-
-      case kNone:
-        return false;
-    }
-
-    UNREACHABLE();
-    return false;
-  }
-
-  // Given instance dependent alias X.f, X.@offs, X[C], X[*] return
-  // wild-card dependent alias *.f, *.@offs, *[C] or *[*] respectively.
-  Place CopyWithoutInstance() const {
-    ASSERT(DependsOnInstance());
-    return Place(flags_, NULL, raw_selector_);
-  }
-
-  // Given alias X[C] or *[C] return X[*] and *[*] respectively.
-  Place CopyWithoutIndex() const {
-    ASSERT(kind() == kConstantIndexed);
-    return Place(EncodeFlags(kIndexed, kNoRepresentation, kNoSize),
-                 instance_,
-                 0);
-  }
-
-  // Given alias X[ByteOffs|S] and a larger element size S', return
-  // alias X[RoundDown(ByteOffs, S')|S'] - this is the byte offset of a larger
-  // typed array element that contains this typed array element.
-  // In other words this method computes the only possible place with the given
-  // size that can alias this place (due to alignment restrictions).
-  // For example for X[9|kInt8] and target size kInt32 we would return
-  // X[8|kInt32].
-  Place ToLargerElement(ElementSize to) const {
-    ASSERT(kind() == kConstantIndexed);
-    ASSERT(element_size() != kNoSize);
-    ASSERT(element_size() < to);
-    return Place(ElementSizeBits::update(to, flags_),
-                 instance_,
-                 RoundByteOffset(to, index_constant_));
-  }
-
-
-  intptr_t id() const { return id_; }
-
-  Kind kind() const { return KindBits::decode(flags_); }
-
-  Representation representation() const {
-    return RepresentationBits::decode(flags_);
-  }
-
-  Definition* instance() const {
-    ASSERT(DependsOnInstance());
-    return instance_;
-  }
-
-  void set_instance(Definition* def) {
-    ASSERT(DependsOnInstance());
-    instance_ = def->OriginalDefinition();
-  }
-
-  const Field& field() const {
-    ASSERT(kind() == kField);
-    return *field_;
-  }
-
-  intptr_t offset_in_bytes() const {
-    ASSERT(kind() == kVMField);
-    return offset_in_bytes_;
-  }
-
-  Definition* index() const {
-    ASSERT(kind() == kIndexed);
-    return index_;
-  }
-
-  ElementSize element_size() const {
-    return ElementSizeBits::decode(flags_);
-  }
-
-  intptr_t index_constant() const {
-    ASSERT(kind() == kConstantIndexed);
-    return index_constant_;
-  }
-
-  static const char* DefinitionName(Definition* def) {
-    if (def == NULL) {
-      return "*";
-    } else {
-      return Thread::Current()->zone()->PrintToString(
-            "v%" Pd, def->ssa_temp_index());
-    }
-  }
-
-  const char* ToCString() const {
-    switch (kind()) {
-      case kNone:
-        return "<none>";
-
-      case kField: {
-        const char* field_name = String::Handle(field().name()).ToCString();
-        if (field().is_static()) {
-          return Thread::Current()->zone()->PrintToString(
-              "<%s>", field_name);
-        } else {
-          return Thread::Current()->zone()->PrintToString(
-              "<%s.%s>", DefinitionName(instance()), field_name);
-        }
-      }
-
-      case kVMField:
-        return Thread::Current()->zone()->PrintToString(
-            "<%s.@%" Pd ">",
-            DefinitionName(instance()),
-            offset_in_bytes());
-
-      case kIndexed:
-        return Thread::Current()->zone()->PrintToString(
-            "<%s[%s]>",
-            DefinitionName(instance()),
-            DefinitionName(index()));
-
-      case kConstantIndexed:
-        if (element_size() == kNoSize) {
-          return Thread::Current()->zone()->PrintToString(
-              "<%s[%" Pd "]>",
-              DefinitionName(instance()),
-              index_constant());
-        } else {
-          return Thread::Current()->zone()->PrintToString(
-              "<%s[%" Pd "|%" Pd "]>",
-              DefinitionName(instance()),
-              index_constant(),
-              ElementSizeMultiplier(element_size()));
-        }
-    }
-    UNREACHABLE();
-    return "<?>";
-  }
-
-  // Fields that are considered immutable by load optimization.
-  // Handle static finals as non-final with precompilation because
-  // they may be reset to uninitialized after compilation.
-  bool IsImmutableField() const {
-    return (kind() == kField)
-        && field().is_final()
-        && (!field().is_static() || !FLAG_fields_may_be_reset);
-  }
-
-  intptr_t Hashcode() const {
-    return (flags_ * 63 + reinterpret_cast<intptr_t>(instance_)) * 31 +
-        FieldHashcode();
-  }
-
-  bool Equals(const Place* other) const {
-    return (flags_ == other->flags_) &&
-        (instance_ == other->instance_) &&
-        SameField(other);
-  }
-
-  // Create a zone allocated copy of this place and assign given id to it.
-  static Place* Wrap(Zone* zone, const Place& place, intptr_t id);
-
-  static bool IsAllocation(Definition* defn) {
-    return (defn != NULL) &&
-        (defn->IsAllocateObject() ||
-         defn->IsCreateArray() ||
-         defn->IsAllocateUninitializedContext() ||
-         (defn->IsStaticCall() &&
-          defn->AsStaticCall()->IsRecognizedFactory()));
-  }
-
- private:
-  Place(uword flags, Definition* instance, intptr_t selector)
-      : flags_(flags),
-        instance_(instance),
-        raw_selector_(selector),
-        id_(0) {
-  }
-
-  bool SameField(const Place* other) const {
-    return (kind() == kField) ? (field().raw() == other->field().raw())
-                              : (offset_in_bytes_ == other->offset_in_bytes_);
-  }
-
-  intptr_t FieldHashcode() const {
-    return (kind() == kField) ? reinterpret_cast<intptr_t>(field().raw())
-                              : offset_in_bytes_;
-  }
-
-  void set_representation(Representation rep) {
-    flags_ = RepresentationBits::update(rep, flags_);
-  }
-
-  void set_kind(Kind kind) {
-    flags_ = KindBits::update(kind, flags_);
-  }
-
-  void set_element_size(ElementSize scale) {
-    flags_ = ElementSizeBits::update(scale, flags_);
-  }
-
-  void SetIndex(Definition* index, intptr_t scale, intptr_t class_id) {
-    ConstantInstr* index_constant = index->AsConstant();
-    if ((index_constant != NULL) && index_constant->value().IsSmi()) {
-      const intptr_t index_value = Smi::Cast(index_constant->value()).Value();
-      const ElementSize size = ElementSizeFor(class_id);
-      const bool is_typed_data = (size != kNoSize);
-
-      // If we are writing into the typed data scale the index to
-      // get byte offset. Otherwise ignore the scale.
-      if (!is_typed_data) {
-        scale = 1;
-      }
-
-      // Guard against potential multiplication overflow and negative indices.
-      if ((0 <= index_value) && (index_value < (kMaxInt32 / scale))) {
-        const intptr_t scaled_index = index_value * scale;
-
-        // Guard against unaligned byte offsets.
-        if (!is_typed_data ||
-            Utils::IsAligned(scaled_index, ElementSizeMultiplier(size))) {
-          set_kind(kConstantIndexed);
-          set_element_size(size);
-          index_constant_ = scaled_index;
-          return;
-        }
-      }
-
-      // Fallthrough: create generic _[*] place.
-    }
-
-    set_kind(kIndexed);
-    index_ = index;
-  }
-
-  static uword EncodeFlags(Kind kind, Representation rep, ElementSize scale) {
-    ASSERT((kind == kConstantIndexed) || (scale == kNoSize));
-    return KindBits::encode(kind) |
-        RepresentationBits::encode(rep) |
-        ElementSizeBits::encode(scale);
-  }
-
-  static ElementSize ElementSizeFor(intptr_t class_id) {
-    switch (class_id) {
-      case kArrayCid:
-      case kImmutableArrayCid:
-      case kOneByteStringCid:
-      case kTwoByteStringCid:
-        // Object arrays and strings do not allow accessing them through
-        // different types. No need to attach scale.
-        return kNoSize;
-
-      case kTypedDataInt8ArrayCid:
-      case kTypedDataUint8ArrayCid:
-      case kTypedDataUint8ClampedArrayCid:
-      case kExternalTypedDataUint8ArrayCid:
-      case kExternalTypedDataUint8ClampedArrayCid:
-        return kInt8;
-
-      case kTypedDataInt16ArrayCid:
-      case kTypedDataUint16ArrayCid:
-        return kInt16;
-
-      case kTypedDataInt32ArrayCid:
-      case kTypedDataUint32ArrayCid:
-      case kTypedDataFloat32ArrayCid:
-        return kInt32;
-
-      case kTypedDataInt64ArrayCid:
-      case kTypedDataUint64ArrayCid:
-      case kTypedDataFloat64ArrayCid:
-        return kInt64;
-
-      case kTypedDataInt32x4ArrayCid:
-      case kTypedDataFloat32x4ArrayCid:
-      case kTypedDataFloat64x2ArrayCid:
-        return kInt128;
-
-      default:
-        UNREACHABLE();
-        return kNoSize;
-    }
-  }
-
-  static intptr_t ElementSizeMultiplier(ElementSize size) {
-    return 1 << (static_cast<intptr_t>(size) - static_cast<intptr_t>(kInt8));
-  }
-
-  static intptr_t RoundByteOffset(ElementSize size, intptr_t offset) {
-    return offset & ~(ElementSizeMultiplier(size) - 1);
-  }
-
-  typedef BitField<Kind, 0, 3> KindBits;
-  typedef BitField<Representation, KindBits::kNextBit, 11> RepresentationBits;
-  typedef BitField<
-      ElementSize, RepresentationBits::kNextBit, 3> ElementSizeBits;
-
-  uword flags_;
-  Definition* instance_;
-  union {
-    intptr_t raw_selector_;
-    const Field* field_;
-    intptr_t offset_in_bytes_;
-    intptr_t index_constant_;
-    Definition* index_;
-  };
-
-  intptr_t id_;
-};
-
-
-class ZonePlace : public ZoneAllocated {
- public:
-  explicit ZonePlace(const Place& place) : place_(place) { }
-
-  Place* place() { return &place_; }
-
- private:
-  Place place_;
-};
-
-
-Place* Place::Wrap(Zone* zone, const Place& place, intptr_t id) {
-  Place* wrapped = (new(zone) ZonePlace(place))->place();
-  wrapped->id_ = id;
-  return wrapped;
-}
-
-
-// Correspondence between places connected through outgoing phi moves on the
-// edge that targets join.
-class PhiPlaceMoves : public ZoneAllocated {
- public:
-  // Record a move from the place with id |from| to the place with id |to| at
-  // the given block.
-  void CreateOutgoingMove(Zone* zone,
-                          BlockEntryInstr* block, intptr_t from, intptr_t to) {
-    const intptr_t block_num = block->preorder_number();
-    while (moves_.length() <= block_num) {
-      moves_.Add(NULL);
-    }
-
-    if (moves_[block_num] == NULL) {
-      moves_[block_num] = new(zone) ZoneGrowableArray<Move>(5);
-    }
-
-    moves_[block_num]->Add(Move(from, to));
-  }
-
-  class Move {
-   public:
-    Move(intptr_t from, intptr_t to) : from_(from), to_(to) { }
-
-    intptr_t from() const { return from_; }
-    intptr_t to() const { return to_; }
-
-   private:
-    intptr_t from_;
-    intptr_t to_;
-  };
-
-  typedef const ZoneGrowableArray<Move>* MovesList;
-
-  MovesList GetOutgoingMoves(BlockEntryInstr* block) const {
-    const intptr_t block_num = block->preorder_number();
-    return (block_num < moves_.length()) ?
-        moves_[block_num] : NULL;
-  }
-
- private:
-  GrowableArray<ZoneGrowableArray<Move>* > moves_;
-};
-
-
-// A map from aliases to a set of places sharing the alias. Additionally
-// carries a set of places that can be aliased by side-effects, essentially
-// those that are affected by calls.
-class AliasedSet : public ZoneAllocated {
- public:
-  AliasedSet(Zone* zone,
-             DirectChainedHashMap<PointerKeyValueTrait<Place> >* places_map,
-             ZoneGrowableArray<Place*>* places,
-             PhiPlaceMoves* phi_moves)
-      : zone_(zone),
-        places_map_(places_map),
-        places_(*places),
-        phi_moves_(phi_moves),
-        aliases_(5),
-        aliases_map_(),
-        typed_data_access_sizes_(),
-        representatives_(),
-        killed_(),
-        aliased_by_effects_(new(zone) BitVector(zone, places->length())) {
-    InsertAlias(Place::CreateAnyInstanceAnyIndexAlias(zone_,
-        kAnyInstanceAnyIndexAlias));
-    for (intptr_t i = 0; i < places_.length(); i++) {
-      AddRepresentative(places_[i]);
-    }
-    ComputeKillSets();
-  }
-
-  intptr_t LookupAliasId(const Place& alias) {
-    const Place* result = aliases_map_.Lookup(&alias);
-    return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias);
-  }
-
-  BitVector* GetKilledSet(intptr_t alias) {
-    return (alias < killed_.length()) ? killed_[alias] : NULL;
-  }
-
-  intptr_t max_place_id() const { return places().length(); }
-  bool IsEmpty() const { return max_place_id() == 0; }
-
-  BitVector* aliased_by_effects() const { return aliased_by_effects_; }
-
-  const ZoneGrowableArray<Place*>& places() const {
-    return places_;
-  }
-
-  Place* LookupCanonical(Place* place) const {
-    return places_map_->Lookup(place);
-  }
-
-  void PrintSet(BitVector* set) {
-    bool comma = false;
-    for (BitVector::Iterator it(set);
-         !it.Done();
-         it.Advance()) {
-      if (comma) {
-        THR_Print(", ");
-      }
-      THR_Print("%s", places_[it.Current()]->ToCString());
-      comma = true;
-    }
-  }
-
-  const PhiPlaceMoves* phi_moves() const { return phi_moves_; }
-
-  void RollbackAliasedIdentites() {
-    for (intptr_t i = 0; i < identity_rollback_.length(); ++i) {
-      identity_rollback_[i]->SetIdentity(AliasIdentity::Unknown());
-    }
-  }
-
-  // Returns false if the result of an allocation instruction can't be aliased
-  // by another SSA variable and true otherwise.
-  bool CanBeAliased(Definition* alloc) {
-    if (!Place::IsAllocation(alloc)) {
-      return true;
-    }
-
-    if (alloc->Identity().IsUnknown()) {
-      ComputeAliasing(alloc);
-    }
-
-    return !alloc->Identity().IsNotAliased();
-  }
-
-  enum {
-    kNoAlias = 0
-  };
-
- private:
-  enum {
-    // Artificial alias that is used to collect all representatives of the
-    // *[C], X[C] aliases for arbitrary C.
-    kAnyConstantIndexedAlias = 1,
-
-    // Artificial alias that is used to collect all representatives of
-    // *[C] alias for arbitrary C.
-    kUnknownInstanceConstantIndexedAlias = 2,
-
-    // Artificial alias that is used to collect all representatives of
-    // X[*] alias for all X.
-    kAnyAllocationIndexedAlias = 3,
-
-    // *[*] alias.
-    kAnyInstanceAnyIndexAlias = 4
-  };
-
-  // Compute least generic alias for the place and assign alias id to it.
-  void AddRepresentative(Place* place) {
-    if (!place->IsImmutableField()) {
-      const Place* alias = CanonicalizeAlias(place->ToAlias());
-      EnsureSet(&representatives_, alias->id())->Add(place->id());
-
-      // Update cumulative representative sets that are used during
-      // killed sets computation.
-      if (alias->kind() == Place::kConstantIndexed) {
-        if (CanBeAliased(alias->instance())) {
-          EnsureSet(&representatives_, kAnyConstantIndexedAlias)->
-              Add(place->id());
-        }
-
-        if (alias->instance() == NULL) {
-          EnsureSet(&representatives_, kUnknownInstanceConstantIndexedAlias)->
-              Add(place->id());
-        }
-
-        // Collect all element sizes used to access TypedData arrays in
-        // the function. This is used to skip sizes without representatives
-        // when computing kill sets.
-        if (alias->element_size() != Place::kNoSize) {
-          typed_data_access_sizes_.Add(alias->element_size());
-        }
-      } else if ((alias->kind() == Place::kIndexed) &&
-                 CanBeAliased(place->instance())) {
-        EnsureSet(&representatives_, kAnyAllocationIndexedAlias)->
-            Add(place->id());
-      }
-
-      if (!IsIndependentFromEffects(place)) {
-        aliased_by_effects_->Add(place->id());
-      }
-    }
-  }
-
-  void ComputeKillSets() {
-    for (intptr_t i = 0; i < aliases_.length(); ++i) {
-      const Place* alias = aliases_[i];
-      // Add all representatives to the kill set.
-      AddAllRepresentatives(alias->id(), alias->id());
-      ComputeKillSet(alias);
-    }
-
-    if (FLAG_trace_load_optimization) {
-      THR_Print("Aliases KILL sets:\n");
-      for (intptr_t i = 0; i < aliases_.length(); ++i) {
-        const Place* alias = aliases_[i];
-        BitVector* kill = GetKilledSet(alias->id());
-
-        THR_Print("%s: ", alias->ToCString());
-        if (kill != NULL) {
-          PrintSet(kill);
-        }
-        THR_Print("\n");
-      }
-    }
-  }
-
-  void InsertAlias(const Place* alias) {
-    aliases_map_.Insert(alias);
-    aliases_.Add(alias);
-  }
-
-  const Place* CanonicalizeAlias(const Place& alias) {
-    const Place* canonical = aliases_map_.Lookup(&alias);
-    if (canonical == NULL) {
-      canonical = Place::Wrap(zone_,
-                              alias,
-                              kAnyInstanceAnyIndexAlias + aliases_.length());
-      InsertAlias(canonical);
-    }
-    ASSERT(aliases_map_.Lookup(&alias) == canonical);
-    return canonical;
-  }
-
-  BitVector* GetRepresentativesSet(intptr_t alias) {
-    return (alias < representatives_.length()) ? representatives_[alias] : NULL;
-  }
-
-  BitVector* EnsureSet(GrowableArray<BitVector*>* sets,
-                       intptr_t alias) {
-    while (sets->length() <= alias) {
-      sets->Add(NULL);
-    }
-
-    BitVector* set = (*sets)[alias];
-    if (set == NULL) {
-      (*sets)[alias] = set = new(zone_) BitVector(zone_, max_place_id());
-    }
-    return set;
-  }
-
-  void AddAllRepresentatives(const Place* to, intptr_t from) {
-    AddAllRepresentatives(to->id(), from);
-  }
-
-  void AddAllRepresentatives(intptr_t to, intptr_t from) {
-    BitVector* from_set = GetRepresentativesSet(from);
-    if (from_set != NULL) {
-      EnsureSet(&killed_, to)->AddAll(from_set);
-    }
-  }
-
-  void CrossAlias(const Place* to, const Place& from) {
-    const intptr_t from_id = LookupAliasId(from);
-    if (from_id == kNoAlias) {
-      return;
-    }
-    CrossAlias(to, from_id);
-  }
-
-  void CrossAlias(const Place* to, intptr_t from) {
-    AddAllRepresentatives(to->id(), from);
-    AddAllRepresentatives(from, to->id());
-  }
-
-  // When computing kill sets we let less generic alias insert its
-  // representatives into more generic alias'es kill set. For example
-  // when visiting alias X[*] instead of searching for all aliases X[C]
-  // and inserting their representatives into kill set for X[*] we update
-  // kill set for X[*] each time we visit new X[C] for some C.
-  // There is an exception however: if both aliases are parametric like *[C]
-  // and X[*] which cross alias when X is an aliased allocation then we use
-  // artificial aliases that contain all possible representatives for the given
-  // alias for any value of the parameter to compute resulting kill set.
-  void ComputeKillSet(const Place* alias) {
-    switch (alias->kind()) {
-      case Place::kIndexed:  // Either *[*] or X[*] alias.
-        if (alias->instance() == NULL) {
-          // *[*] aliases with X[*], X[C], *[C].
-          AddAllRepresentatives(alias, kAnyConstantIndexedAlias);
-          AddAllRepresentatives(alias, kAnyAllocationIndexedAlias);
-        } else if (CanBeAliased(alias->instance())) {
-          // X[*] aliases with X[C].
-          // If X can be aliased then X[*] also aliases with *[C], *[*].
-          CrossAlias(alias, kAnyInstanceAnyIndexAlias);
-          AddAllRepresentatives(alias, kUnknownInstanceConstantIndexedAlias);
-        }
-        break;
-
-      case Place::kConstantIndexed:  // Either X[C] or *[C] alias.
-        if (alias->element_size() != Place::kNoSize) {
-          const bool has_aliased_instance =
-              (alias->instance() != NULL) && CanBeAliased(alias->instance());
-
-          // If this is a TypedData access then X[C|S] aliases larger elements
-          // covering this one X[RoundDown(C, S')|S'] for all S' > S and
-          // all smaller elements being covered by this one X[C'|S'] for
-          // some S' < S and all C' such that C = RoundDown(C', S).
-          // In the loop below it's enough to only propagate aliasing to
-          // larger aliases because propagation is symmetric: smaller aliases
-          // (if there are any) would update kill set for this alias when they
-          // are visited.
-          for (intptr_t i = static_cast<intptr_t>(alias->element_size()) + 1;
-               i <= Place::kLargestElementSize;
-               i++) {
-            // Skip element sizes that a guaranteed to have no representatives.
-            if (!typed_data_access_sizes_.Contains(alias->element_size())) {
-              continue;
-            }
-
-            // X[C|S] aliases with X[RoundDown(C, S')|S'] and likewise
-            // *[C|S] aliases with *[RoundDown(C, S')|S'].
-            const Place larger_alias =
-                alias->ToLargerElement(static_cast<Place::ElementSize>(i));
-            CrossAlias(alias, larger_alias);
-            if (has_aliased_instance) {
-              // If X is an aliased instance then X[C|S] aliases
-              // with *[RoundDown(C, S')|S'].
-              CrossAlias(alias, larger_alias.CopyWithoutInstance());
-            }
-          }
-        }
-
-        if (alias->instance() == NULL) {
-          // *[C] aliases with X[C], X[*], *[*].
-          AddAllRepresentatives(alias, kAnyAllocationIndexedAlias);
-          CrossAlias(alias, kAnyInstanceAnyIndexAlias);
-        } else {
-          // X[C] aliases with X[*].
-          // If X can be aliased then X[C] also aliases with *[C], *[*].
-          CrossAlias(alias, alias->CopyWithoutIndex());
-          if (CanBeAliased(alias->instance())) {
-            CrossAlias(alias, alias->CopyWithoutInstance());
-            CrossAlias(alias, kAnyInstanceAnyIndexAlias);
-          }
-        }
-        break;
-
-      case Place::kField:
-      case Place::kVMField:
-        if (CanBeAliased(alias->instance())) {
-          // X.f or X.@offs alias with *.f and *.@offs respectively.
-          CrossAlias(alias, alias->CopyWithoutInstance());
-        }
-        break;
-
-      case Place::kNone:
-        UNREACHABLE();
-    }
-  }
-
-  // Returns true if the given load is unaffected by external side-effects.
-  // This essentially means that no stores to the same location can
-  // occur in other functions.
-  bool IsIndependentFromEffects(Place* place) {
-    if (place->IsImmutableField()) {
-      // Note that we can't use LoadField's is_immutable attribute here because
-      // some VM-fields (those that have no corresponding Field object and
-      // accessed through offset alone) can share offset but have different
-      // immutability properties.
-      // One example is the length property of growable and fixed size list. If
-      // loads of these two properties occur in the same function for the same
-      // receiver then they will get the same expression number. However
-      // immutability of the length of fixed size list does not mean that
-      // growable list also has immutable property. Thus we will make a
-      // conservative assumption for the VM-properties.
-      // TODO(vegorov): disambiguate immutable and non-immutable VM-fields with
-      // the same offset e.g. through recognized kind.
-      return true;
-    }
-
-    return ((place->kind() == Place::kField) ||
-         (place->kind() == Place::kVMField)) &&
-        !CanBeAliased(place->instance());
-  }
-
-  // Returns true if there are direct loads from the given place.
-  bool HasLoadsFromPlace(Definition* defn, const Place* place) {
-    ASSERT((place->kind() == Place::kField) ||
-           (place->kind() == Place::kVMField));
-
-    for (Value* use = defn->input_use_list();
-         use != NULL;
-         use = use->next_use()) {
-      Instruction* instr = use->instruction();
-      if ((instr->IsRedefinition() ||
-           instr->IsAssertAssignable()) &&
-          HasLoadsFromPlace(instr->AsDefinition(), place)) {
-        return true;
-      }
-      bool is_load = false, is_store;
-      Place load_place(instr, &is_load, &is_store);
-
-      if (is_load && load_place.Equals(place)) {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  // Check if any use of the definition can create an alias.
-  // Can add more objects into aliasing_worklist_.
-  bool AnyUseCreatesAlias(Definition* defn) {
-    for (Value* use = defn->input_use_list();
-         use != NULL;
-         use = use->next_use()) {
-      Instruction* instr = use->instruction();
-      if (instr->IsPushArgument() ||
-          (instr->IsStoreIndexed()
-           && (use->use_index() == StoreIndexedInstr::kValuePos)) ||
-          instr->IsStoreStaticField() ||
-          instr->IsPhi()) {
-        return true;
-      } else if ((instr->IsAssertAssignable() || instr->IsRedefinition()) &&
-                 AnyUseCreatesAlias(instr->AsDefinition())) {
-        return true;
-      } else if ((instr->IsStoreInstanceField()
-           && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) {
-        ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos);
-        // If we store this value into an object that is not aliased itself
-        // and we never load again then the store does not create an alias.
-        StoreInstanceFieldInstr* store = instr->AsStoreInstanceField();
-        Definition* instance =
-            store->instance()->definition()->OriginalDefinition();
-        if (Place::IsAllocation(instance) &&
-            !instance->Identity().IsAliased()) {
-          bool is_load, is_store;
-          Place store_place(instr, &is_load, &is_store);
-
-          if (!HasLoadsFromPlace(instance, &store_place)) {
-            // No loads found that match this store. If it is yet unknown if
-            // the object is not aliased then optimistically assume this but
-            // add it to the worklist to check its uses transitively.
-            if (instance->Identity().IsUnknown()) {
-              instance->SetIdentity(AliasIdentity::NotAliased());
-              aliasing_worklist_.Add(instance);
-            }
-            continue;
-          }
-        }
-        return true;
-      }
-    }
-    return false;
-  }
-
-  // Mark any value stored into the given object as potentially aliased.
-  void MarkStoredValuesEscaping(Definition* defn) {
-    // Find all stores into this object.
-    for (Value* use = defn->input_use_list();
-         use != NULL;
-         use = use->next_use()) {
-      if (use->instruction()->IsRedefinition() ||
-          use->instruction()->IsAssertAssignable()) {
-        MarkStoredValuesEscaping(use->instruction()->AsDefinition());
-        continue;
-      }
-      if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) &&
-          use->instruction()->IsStoreInstanceField()) {
-        StoreInstanceFieldInstr* store =
-            use->instruction()->AsStoreInstanceField();
-        Definition* value = store->value()->definition()->OriginalDefinition();
-        if (value->Identity().IsNotAliased()) {
-          value->SetIdentity(AliasIdentity::Aliased());
-          identity_rollback_.Add(value);
-
-          // Add to worklist to propagate the mark transitively.
-          aliasing_worklist_.Add(value);
-        }
-      }
-    }
-  }
-
-  // Determine if the given definition can't be aliased.
-  void ComputeAliasing(Definition* alloc) {
-    ASSERT(Place::IsAllocation(alloc));
-    ASSERT(alloc->Identity().IsUnknown());
-    ASSERT(aliasing_worklist_.is_empty());
-
-    alloc->SetIdentity(AliasIdentity::NotAliased());
-    aliasing_worklist_.Add(alloc);
-
-    while (!aliasing_worklist_.is_empty()) {
-      Definition* defn = aliasing_worklist_.RemoveLast();
-      ASSERT(Place::IsAllocation(defn));
-      // If the definition in the worklist was optimistically marked as
-      // not-aliased check that optimistic assumption still holds: check if
-      // any of its uses can create an alias.
-      if (!defn->Identity().IsAliased() && AnyUseCreatesAlias(defn)) {
-        defn->SetIdentity(AliasIdentity::Aliased());
-        identity_rollback_.Add(defn);
-      }
-
-      // If the allocation site is marked as aliased conservatively mark
-      // any values stored into the object aliased too.
-      if (defn->Identity().IsAliased()) {
-        MarkStoredValuesEscaping(defn);
-      }
-    }
-  }
-
-  Zone* zone_;
-
-  DirectChainedHashMap<PointerKeyValueTrait<Place> >* places_map_;
-
-  const ZoneGrowableArray<Place*>& places_;
-
-  const PhiPlaceMoves* phi_moves_;
-
-  // A list of all seen aliases and a map that allows looking up canonical
-  // alias object.
-  GrowableArray<const Place*> aliases_;
-  DirectChainedHashMap<PointerKeyValueTrait<const Place> > aliases_map_;
-
-  SmallSet<Place::ElementSize> typed_data_access_sizes_;
-
-  // Maps alias id to set of ids of places representing the alias.
-  // Place represents an alias if this alias is least generic alias for
-  // the place.
-  // (see ToAlias for the definition of least generic alias).
-  GrowableArray<BitVector*> representatives_;
-
-  // Maps alias id to set of ids of places aliased.
-  GrowableArray<BitVector*> killed_;
-
-  // Set of ids of places that can be affected by side-effects other than
-  // explicit stores (i.e. through calls).
-  BitVector* aliased_by_effects_;
-
-  // Worklist used during alias analysis.
-  GrowableArray<Definition*> aliasing_worklist_;
-
-  // List of definitions that had their identity set to Aliased. At the end
-  // of load optimization their identity will be rolled back to Unknown to
-  // avoid treating them as Aliased at later stages without checking first
-  // as optimizations can potentially eliminate instructions leading to
-  // aliasing.
-  GrowableArray<Definition*> identity_rollback_;
-};
-
-
-static Definition* GetStoredValue(Instruction* instr) {
-  if (instr->IsStoreIndexed()) {
-    return instr->AsStoreIndexed()->value()->definition();
-  }
-
-  StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField();
-  if (store_instance_field != NULL) {
-    return store_instance_field->value()->definition();
-  }
-
-  StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
-  if (store_static_field != NULL) {
-    return store_static_field->value()->definition();
-  }
-
-  UNREACHABLE();  // Should only be called for supported store instructions.
-  return NULL;
-}
-
-
-static bool IsPhiDependentPlace(Place* place) {
-  return ((place->kind() == Place::kField) ||
-          (place->kind() == Place::kVMField)) &&
-        (place->instance() != NULL) &&
-        place->instance()->IsPhi();
-}
-
-
-// For each place that depends on a phi ensure that equivalent places
-// corresponding to phi input are numbered and record outgoing phi moves
-// for each block which establish correspondence between phi dependent place
-// and phi input's place that is flowing in.
-static PhiPlaceMoves* ComputePhiMoves(
-    DirectChainedHashMap<PointerKeyValueTrait<Place> >* map,
-    ZoneGrowableArray<Place*>* places) {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  PhiPlaceMoves* phi_moves = new(zone) PhiPlaceMoves();
-
-  for (intptr_t i = 0; i < places->length(); i++) {
-    Place* place = (*places)[i];
-
-    if (IsPhiDependentPlace(place)) {
-      PhiInstr* phi = place->instance()->AsPhi();
-      BlockEntryInstr* block = phi->GetBlock();
-
-      if (FLAG_trace_optimization) {
-        THR_Print("phi dependent place %s\n", place->ToCString());
-      }
-
-      Place input_place(*place);
-      for (intptr_t j = 0; j < phi->InputCount(); j++) {
-        input_place.set_instance(phi->InputAt(j)->definition());
-
-        Place* result = map->Lookup(&input_place);
-        if (result == NULL) {
-          result = Place::Wrap(zone, input_place, places->length());
-          map->Insert(result);
-          places->Add(result);
-          if (FLAG_trace_optimization) {
-            THR_Print("  adding place %s as %" Pd "\n",
-                      result->ToCString(),
-                      result->id());
-          }
-        }
-        phi_moves->CreateOutgoingMove(zone,
-                                      block->PredecessorAt(j),
-                                      result->id(),
-                                      place->id());
-      }
-    }
-  }
-
-  return phi_moves;
-}
-
-
-enum CSEMode {
-  kOptimizeLoads,
-  kOptimizeStores
-};
-
-
-static AliasedSet* NumberPlaces(
-    FlowGraph* graph,
-    DirectChainedHashMap<PointerKeyValueTrait<Place> >* map,
-    CSEMode mode) {
-  // Loads representing different expression ids will be collected and
-  // used to build per offset kill sets.
-  Zone* zone = graph->zone();
-  ZoneGrowableArray<Place*>* places =
-      new(zone) ZoneGrowableArray<Place*>(10);
-
-  bool has_loads = false;
-  bool has_stores = false;
-  for (BlockIterator it = graph->reverse_postorder_iterator();
-       !it.Done();
-       it.Advance()) {
-    BlockEntryInstr* block = it.Current();
-
-    for (ForwardInstructionIterator instr_it(block);
-         !instr_it.Done();
-         instr_it.Advance()) {
-      Instruction* instr = instr_it.Current();
-      Place place(instr, &has_loads, &has_stores);
-      if (place.kind() == Place::kNone) {
-        continue;
-      }
-
-      Place* result = map->Lookup(&place);
-      if (result == NULL) {
-        result = Place::Wrap(zone, place, places->length());
-        map->Insert(result);
-        places->Add(result);
-
-        if (FLAG_trace_optimization) {
-          THR_Print("numbering %s as %" Pd "\n",
-                    result->ToCString(),
-                    result->id());
-        }
-      }
-
-      instr->set_place_id(result->id());
-    }
-  }
-
-  if ((mode == kOptimizeLoads) && !has_loads) {
-    return NULL;
-  }
-  if ((mode == kOptimizeStores) && !has_stores) {
-    return NULL;
-  }
-
-  PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places);
-
-  // Build aliasing sets mapping aliases to loads.
-  return new(zone) AliasedSet(zone, map, places, phi_moves);
-}
-
-
-class LoadOptimizer : public ValueObject {
- public:
-  LoadOptimizer(FlowGraph* graph, AliasedSet* aliased_set)
-      : graph_(graph),
-        aliased_set_(aliased_set),
-        in_(graph_->preorder().length()),
-        out_(graph_->preorder().length()),
-        gen_(graph_->preorder().length()),
-        kill_(graph_->preorder().length()),
-        exposed_values_(graph_->preorder().length()),
-        out_values_(graph_->preorder().length()),
-        phis_(5),
-        worklist_(5),
-        congruency_worklist_(6),
-        in_worklist_(NULL),
-        forwarded_(false) {
-    const intptr_t num_blocks = graph_->preorder().length();
-    for (intptr_t i = 0; i < num_blocks; i++) {
-      out_.Add(NULL);
-      gen_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id()));
-      kill_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id()));
-      in_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id()));
-
-      exposed_values_.Add(NULL);
-      out_values_.Add(NULL);
-    }
-  }
-
-  ~LoadOptimizer() {
-    aliased_set_->RollbackAliasedIdentites();
-  }
-
-  Isolate* isolate() const { return graph_->isolate(); }
-  Zone* zone() const { return graph_->zone(); }
-
-  static bool OptimizeGraph(FlowGraph* graph) {
-    ASSERT(FLAG_load_cse);
-    if (FLAG_trace_load_optimization) {
-      FlowGraphPrinter::PrintGraph("Before LoadOptimizer", graph);
-    }
-
-    DirectChainedHashMap<PointerKeyValueTrait<Place> > map;
-    AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeLoads);
-    if ((aliased_set != NULL) && !aliased_set->IsEmpty()) {
-      // If any loads were forwarded return true from Optimize to run load
-      // forwarding again. This will allow to forward chains of loads.
-      // This is especially important for context variables as they are built
-      // as loads from loaded context.
-      // TODO(vegorov): renumber newly discovered congruences during the
-      // forwarding to forward chains without running whole pass twice.
-      LoadOptimizer load_optimizer(graph, aliased_set);
-      return load_optimizer.Optimize();
-    }
-    return false;
-  }
-
- private:
-  bool Optimize() {
-    ComputeInitialSets();
-    ComputeOutSets();
-    ComputeOutValues();
-    if (graph_->is_licm_allowed()) {
-      MarkLoopInvariantLoads();
-    }
-    ForwardLoads();
-    EmitPhis();
-
-    if (FLAG_trace_load_optimization) {
-      FlowGraphPrinter::PrintGraph("After LoadOptimizer", graph_);
-    }
-
-    return forwarded_;
-  }
-
-  // Compute sets of loads generated and killed by each block.
-  // Additionally compute upwards exposed and generated loads for each block.
-  // Exposed loads are those that can be replaced if a corresponding
-  // reaching load will be found.
-  // Loads that are locally redundant will be replaced as we go through
-  // instructions.
-  void ComputeInitialSets() {
-    for (BlockIterator block_it = graph_->reverse_postorder_iterator();
-         !block_it.Done();
-         block_it.Advance()) {
-      BlockEntryInstr* block = block_it.Current();
-      const intptr_t preorder_number = block->preorder_number();
-
-      BitVector* kill = kill_[preorder_number];
-      BitVector* gen = gen_[preorder_number];
-
-      ZoneGrowableArray<Definition*>* exposed_values = NULL;
-      ZoneGrowableArray<Definition*>* out_values = NULL;
-
-      for (ForwardInstructionIterator instr_it(block);
-           !instr_it.Done();
-           instr_it.Advance()) {
-        Instruction* instr = instr_it.Current();
-
-        bool is_load = false, is_store = false;
-        Place place(instr, &is_load, &is_store);
-
-        BitVector* killed = NULL;
-        if (is_store) {
-          const intptr_t alias_id =
-              aliased_set_->LookupAliasId(place.ToAlias());
-          if (alias_id != AliasedSet::kNoAlias) {
-            killed = aliased_set_->GetKilledSet(alias_id);
-          } else if (!place.IsImmutableField()) {
-            // We encountered unknown alias: this means intrablock load
-            // forwarding refined parameter of this store, for example
-            //
-            //     o   <- alloc()
-            //     a.f <- o
-            //     u   <- a.f
-            //     u.x <- null ;; this store alias is *.x
-            //
-            // after intrablock load forwarding
-            //
-            //     o   <- alloc()
-            //     a.f <- o
-            //     o.x <- null ;; this store alias is o.x
-            //
-            // In this case we fallback to using place id recorded in the
-            // instruction that still points to the old place with a more
-            // generic alias.
-            const intptr_t old_alias_id = aliased_set_->LookupAliasId(
-                aliased_set_->places()[instr->place_id()]->ToAlias());
-            killed = aliased_set_->GetKilledSet(old_alias_id);
-          }
-
-          if (killed != NULL) {
-            kill->AddAll(killed);
-            // There is no need to clear out_values when clearing GEN set
-            // because only those values that are in the GEN set
-            // will ever be used.
-            gen->RemoveAll(killed);
-          }
-
-          // Only forward stores to normal arrays, float64, and simd arrays
-          // to loads because other array stores (intXX/uintXX/float32)
-          // may implicitly convert the value stored.
-          StoreIndexedInstr* array_store = instr->AsStoreIndexed();
-          if ((array_store == NULL) ||
-              (array_store->class_id() == kArrayCid) ||
-              (array_store->class_id() == kTypedDataFloat64ArrayCid) ||
-              (array_store->class_id() == kTypedDataFloat32ArrayCid) ||
-              (array_store->class_id() == kTypedDataFloat32x4ArrayCid)) {
-            Place* canonical_place = aliased_set_->LookupCanonical(&place);
-            if (canonical_place != NULL) {
-              // Store has a corresponding numbered place that might have a
-              // load. Try forwarding stored value to it.
-              gen->Add(canonical_place->id());
-              if (out_values == NULL) out_values = CreateBlockOutValues();
-              (*out_values)[canonical_place->id()] = GetStoredValue(instr);
-            }
-          }
-
-          ASSERT(!instr->IsDefinition() ||
-                 !IsLoadEliminationCandidate(instr->AsDefinition()));
-          continue;
-        } else if (is_load) {
-          // Check if this load needs renumbering because of the intrablock
-          // load forwarding.
-          const Place* canonical = aliased_set_->LookupCanonical(&place);
-          if ((canonical != NULL) &&
-            (canonical->id() != instr->AsDefinition()->place_id())) {
-            instr->AsDefinition()->set_place_id(canonical->id());
-          }
-        }
-
-        // If instruction has effects then kill all loads affected.
-        if (!instr->Effects().IsNone()) {
-          kill->AddAll(aliased_set_->aliased_by_effects());
-          // There is no need to clear out_values when removing values from GEN
-          // set because only those values that are in the GEN set
-          // will ever be used.
-          gen->RemoveAll(aliased_set_->aliased_by_effects());
-          continue;
-        }
-
-        Definition* defn = instr->AsDefinition();
-        if (defn == NULL) {
-          continue;
-        }
-
-        // For object allocation forward initial values of the fields to
-        // subsequent loads. For skip final fields.  Final fields are
-        // initialized in constructor that potentially can be not inlined into
-        // the function that we are currently optimizing. However at the same
-        // time we assume that values of the final fields can be forwarded
-        // across side-effects. If we add 'null' as known values for these
-        // fields here we will incorrectly propagate this null across
-        // constructor invocation.
-        AllocateObjectInstr* alloc = instr->AsAllocateObject();
-        if ((alloc != NULL)) {
-          for (Value* use = alloc->input_use_list();
-               use != NULL;
-               use = use->next_use()) {
-            // Look for all immediate loads from this object.
-            if (use->use_index() != 0) {
-              continue;
-            }
-
-            LoadFieldInstr* load = use->instruction()->AsLoadField();
-            if (load != NULL) {
-              // Found a load. Initialize current value of the field to null for
-              // normal fields, or with type arguments.
-
-              // Forward for all fields for non-escaping objects and only
-              // non-final fields and type arguments for escaping ones.
-              if (aliased_set_->CanBeAliased(alloc) &&
-                  (load->field() != NULL) &&
-                  load->field()->is_final()) {
-                continue;
-              }
-
-              Definition* forward_def = graph_->constant_null();
-              if (alloc->ArgumentCount() > 0) {
-                ASSERT(alloc->ArgumentCount() == 1);
-                intptr_t type_args_offset =
-                    alloc->cls().type_arguments_field_offset();
-                if (load->offset_in_bytes() == type_args_offset) {
-                  forward_def = alloc->PushArgumentAt(0)->value()->definition();
-                }
-              }
-              gen->Add(load->place_id());
-              if (out_values == NULL) out_values = CreateBlockOutValues();
-              (*out_values)[load->place_id()] = forward_def;
-            }
-          }
-          continue;
-        }
-
-        if (!IsLoadEliminationCandidate(defn)) {
-          continue;
-        }
-
-        const intptr_t place_id = defn->place_id();
-        if (gen->Contains(place_id)) {
-          // This is a locally redundant load.
-          ASSERT((out_values != NULL) && ((*out_values)[place_id] != NULL));
-
-          Definition* replacement = (*out_values)[place_id];
-          EnsureSSATempIndex(graph_, defn, replacement);
-          if (FLAG_trace_optimization) {
-            THR_Print("Replacing load v%" Pd " with v%" Pd "\n",
-                      defn->ssa_temp_index(),
-                      replacement->ssa_temp_index());
-          }
-
-          defn->ReplaceUsesWith(replacement);
-          instr_it.RemoveCurrentFromGraph();
-          forwarded_ = true;
-          continue;
-        } else if (!kill->Contains(place_id)) {
-          // This is an exposed load: it is the first representative of a
-          // given expression id and it is not killed on the path from
-          // the block entry.
-          if (exposed_values == NULL) {
-            static const intptr_t kMaxExposedValuesInitialSize = 5;
-            exposed_values = new(Z) ZoneGrowableArray<Definition*>(
-                Utils::Minimum(kMaxExposedValuesInitialSize,
-                               aliased_set_->max_place_id()));
-          }
-
-          exposed_values->Add(defn);
-        }
-
-        gen->Add(place_id);
-
-        if (out_values == NULL) out_values = CreateBlockOutValues();
-        (*out_values)[place_id] = defn;
-      }
-
-      exposed_values_[preorder_number] = exposed_values;
-      out_values_[preorder_number] = out_values;
-    }
-  }
-
-  static void PerformPhiMoves(PhiPlaceMoves::MovesList phi_moves,
-                              BitVector* out,
-                              BitVector* forwarded_loads) {
-    forwarded_loads->Clear();
-
-    for (intptr_t i = 0; i < phi_moves->length(); i++) {
-      const intptr_t from = (*phi_moves)[i].from();
-      const intptr_t to = (*phi_moves)[i].to();
-      if (from == to) continue;
-
-      if (out->Contains(from)) {
-        forwarded_loads->Add(to);
-      }
-    }
-
-    for (intptr_t i = 0; i < phi_moves->length(); i++) {
-      const intptr_t from = (*phi_moves)[i].from();
-      const intptr_t to = (*phi_moves)[i].to();
-      if (from == to) continue;
-
-      out->Remove(to);
-    }
-
-    out->AddAll(forwarded_loads);
-  }
-
-  // Compute OUT sets by propagating them iteratively until fix point
-  // is reached.
-  void ComputeOutSets() {
-    BitVector* temp = new(Z) BitVector(Z, aliased_set_->max_place_id());
-    BitVector* forwarded_loads =
-        new(Z) BitVector(Z, aliased_set_->max_place_id());
-    BitVector* temp_out = new(Z) BitVector(Z, aliased_set_->max_place_id());
-
-    bool changed = true;
-    while (changed) {
-      changed = false;
-
-      for (BlockIterator block_it = graph_->reverse_postorder_iterator();
-           !block_it.Done();
-           block_it.Advance()) {
-        BlockEntryInstr* block = block_it.Current();
-
-        const intptr_t preorder_number = block->preorder_number();
-
-        BitVector* block_in = in_[preorder_number];
-        BitVector* block_out = out_[preorder_number];
-        BitVector* block_kill = kill_[preorder_number];
-        BitVector* block_gen = gen_[preorder_number];
-
-        // Compute block_in as the intersection of all out(p) where p
-        // is a predecessor of the current block.
-        if (block->IsGraphEntry()) {
-          temp->Clear();
-        } else {
-          temp->SetAll();
-          ASSERT(block->PredecessorCount() > 0);
-          for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
-            BlockEntryInstr* pred = block->PredecessorAt(i);
-            BitVector* pred_out = out_[pred->preorder_number()];
-            if (pred_out == NULL) continue;
-            PhiPlaceMoves::MovesList phi_moves =
-                aliased_set_->phi_moves()->GetOutgoingMoves(pred);
-            if (phi_moves != NULL) {
-              // If there are phi moves, perform intersection with
-              // a copy of pred_out where the phi moves are applied.
-              temp_out->CopyFrom(pred_out);
-              PerformPhiMoves(phi_moves, temp_out, forwarded_loads);
-              pred_out = temp_out;
-            }
-            temp->Intersect(pred_out);
-          }
-        }
-
-        if (!temp->Equals(*block_in) || (block_out == NULL)) {
-          // If IN set has changed propagate the change to OUT set.
-          block_in->CopyFrom(temp);
-
-          temp->RemoveAll(block_kill);
-          temp->AddAll(block_gen);
-
-          if ((block_out == NULL) || !block_out->Equals(*temp)) {
-            if (block_out == NULL) {
-              block_out = out_[preorder_number] =
-                  new(Z) BitVector(Z, aliased_set_->max_place_id());
-            }
-            block_out->CopyFrom(temp);
-            changed = true;
-          }
-        }
-      }
-    }
-  }
-
-  // Compute out_values mappings by propagating them in reverse postorder once
-  // through the graph. Generate phis on back edges where eager merge is
-  // impossible.
-  // No replacement is done at this point and thus any out_value[place_id] is
-  // changed at most once: from NULL to an actual value.
-  // When merging incoming loads we might need to create a phi.
-  // These phis are not inserted at the graph immediately because some of them
-  // might become redundant after load forwarding is done.
-  void ComputeOutValues() {
-    GrowableArray<PhiInstr*> pending_phis(5);
-    ZoneGrowableArray<Definition*>* temp_forwarded_values = NULL;
-
-    for (BlockIterator block_it = graph_->reverse_postorder_iterator();
-         !block_it.Done();
-         block_it.Advance()) {
-      BlockEntryInstr* block = block_it.Current();
-
-      const bool can_merge_eagerly = CanMergeEagerly(block);
-
-      const intptr_t preorder_number = block->preorder_number();
-
-      ZoneGrowableArray<Definition*>* block_out_values =
-          out_values_[preorder_number];
-
-
-      // If OUT set has changed then we have new values available out of
-      // the block. Compute these values creating phi where necessary.
-      for (BitVector::Iterator it(out_[preorder_number]);
-           !it.Done();
-           it.Advance()) {
-        const intptr_t place_id = it.Current();
-
-        if (block_out_values == NULL) {
-          out_values_[preorder_number] = block_out_values =
-              CreateBlockOutValues();
-        }
-
-        if ((*block_out_values)[place_id] == NULL) {
-          ASSERT(block->PredecessorCount() > 0);
-          Definition* in_value = can_merge_eagerly ?
-              MergeIncomingValues(block, place_id) : NULL;
-          if ((in_value == NULL) &&
-              (in_[preorder_number]->Contains(place_id))) {
-            PhiInstr* phi = new(Z) PhiInstr(block->AsJoinEntry(),
-                                            block->PredecessorCount());
-            phi->set_place_id(place_id);
-            pending_phis.Add(phi);
-            in_value = phi;
-          }
-          (*block_out_values)[place_id] = in_value;
-        }
-      }
-
-      // If the block has outgoing phi moves perform them. Use temporary list
-      // of values to ensure that cyclic moves are performed correctly.
-      PhiPlaceMoves::MovesList phi_moves =
-          aliased_set_->phi_moves()->GetOutgoingMoves(block);
-      if ((phi_moves != NULL) && (block_out_values != NULL)) {
-        if (temp_forwarded_values == NULL) {
-          temp_forwarded_values = CreateBlockOutValues();
-        }
-
-        for (intptr_t i = 0; i < phi_moves->length(); i++) {
-          const intptr_t from = (*phi_moves)[i].from();
-          const intptr_t to = (*phi_moves)[i].to();
-          if (from == to) continue;
-
-          (*temp_forwarded_values)[to] = (*block_out_values)[from];
-        }
-
-        for (intptr_t i = 0; i < phi_moves->length(); i++) {
-          const intptr_t from = (*phi_moves)[i].from();
-          const intptr_t to = (*phi_moves)[i].to();
-          if (from == to) continue;
-
-          (*block_out_values)[to] = (*temp_forwarded_values)[to];
-        }
-      }
-
-      if (FLAG_trace_load_optimization) {
-        THR_Print("B%" Pd "\n", block->block_id());
-        THR_Print("  IN: ");
-        aliased_set_->PrintSet(in_[preorder_number]);
-        THR_Print("\n");
-
-        THR_Print("  KILL: ");
-        aliased_set_->PrintSet(kill_[preorder_number]);
-        THR_Print("\n");
-
-        THR_Print("  OUT: ");
-        aliased_set_->PrintSet(out_[preorder_number]);
-        THR_Print("\n");
-      }
-    }
-
-    // All blocks were visited. Fill pending phis with inputs
-    // that flow on back edges.
-    for (intptr_t i = 0; i < pending_phis.length(); i++) {
-      FillPhiInputs(pending_phis[i]);
-    }
-  }
-
-  bool CanMergeEagerly(BlockEntryInstr* block) {
-    for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
-      BlockEntryInstr* pred = block->PredecessorAt(i);
-      if (pred->postorder_number() < block->postorder_number()) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  void MarkLoopInvariantLoads() {
-    const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
-        graph_->LoopHeaders();
-
-    ZoneGrowableArray<BitVector*>* invariant_loads =
-        new(Z) ZoneGrowableArray<BitVector*>(loop_headers.length());
-
-    for (intptr_t i = 0; i < loop_headers.length(); i++) {
-      BlockEntryInstr* header = loop_headers[i];
-      BlockEntryInstr* pre_header = header->ImmediateDominator();
-      if (pre_header == NULL) {
-        invariant_loads->Add(NULL);
-        continue;
-      }
-
-      BitVector* loop_gen = new(Z) BitVector(Z, aliased_set_->max_place_id());
-      for (BitVector::Iterator loop_it(header->loop_info());
-           !loop_it.Done();
-           loop_it.Advance()) {
-        const intptr_t preorder_number = loop_it.Current();
-        loop_gen->AddAll(gen_[preorder_number]);
-      }
-
-      for (BitVector::Iterator loop_it(header->loop_info());
-           !loop_it.Done();
-           loop_it.Advance()) {
-        const intptr_t preorder_number = loop_it.Current();
-        loop_gen->RemoveAll(kill_[preorder_number]);
-      }
-
-      if (FLAG_trace_optimization) {
-        for (BitVector::Iterator it(loop_gen); !it.Done(); it.Advance()) {
-          THR_Print("place %s is loop invariant for B%" Pd "\n",
-                    aliased_set_->places()[it.Current()]->ToCString(),
-                    header->block_id());
-        }
-      }
-
-      invariant_loads->Add(loop_gen);
-    }
-
-    graph_->set_loop_invariant_loads(invariant_loads);
-  }
-
-  // Compute incoming value for the given expression id.
-  // Will create a phi if different values are incoming from multiple
-  // predecessors.
-  Definition* MergeIncomingValues(BlockEntryInstr* block, intptr_t place_id) {
-    // First check if the same value is coming in from all predecessors.
-    static Definition* const kDifferentValuesMarker =
-        reinterpret_cast<Definition*>(-1);
-    Definition* incoming = NULL;
-    for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
-      BlockEntryInstr* pred = block->PredecessorAt(i);
-      ZoneGrowableArray<Definition*>* pred_out_values =
-          out_values_[pred->preorder_number()];
-      if ((pred_out_values == NULL) || ((*pred_out_values)[place_id] == NULL)) {
-        return NULL;
-      } else if (incoming == NULL) {
-        incoming = (*pred_out_values)[place_id];
-      } else if (incoming != (*pred_out_values)[place_id]) {
-        incoming = kDifferentValuesMarker;
-      }
-    }
-
-    if (incoming != kDifferentValuesMarker) {
-      ASSERT(incoming != NULL);
-      return incoming;
-    }
-
-    // Incoming values are different. Phi is required to merge.
-    PhiInstr* phi = new(Z) PhiInstr(
-        block->AsJoinEntry(), block->PredecessorCount());
-    phi->set_place_id(place_id);
-    FillPhiInputs(phi);
-    return phi;
-  }
-
-  void FillPhiInputs(PhiInstr* phi) {
-    BlockEntryInstr* block = phi->GetBlock();
-    const intptr_t place_id = phi->place_id();
-
-    for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
-      BlockEntryInstr* pred = block->PredecessorAt(i);
-      ZoneGrowableArray<Definition*>* pred_out_values =
-          out_values_[pred->preorder_number()];
-      ASSERT((*pred_out_values)[place_id] != NULL);
-
-      // Sets of outgoing values are not linked into use lists so
-      // they might contain values that were replaced and removed
-      // from the graph by this iteration.
-      // To prevent using them we additionally mark definitions themselves
-      // as replaced and store a pointer to the replacement.
-      Definition* replacement = (*pred_out_values)[place_id]->Replacement();
-      Value* input = new(Z) Value(replacement);
-      phi->SetInputAt(i, input);
-      replacement->AddInputUse(input);
-    }
-
-    graph_->AllocateSSAIndexes(phi);
-    phis_.Add(phi);  // Postpone phi insertion until after load forwarding.
-
-    if (FLAG_trace_load_optimization) {
-      THR_Print("created pending phi %s for %s at B%" Pd "\n",
-                phi->ToCString(),
-                aliased_set_->places()[place_id]->ToCString(),
-                block->block_id());
-    }
-  }
-
-  // Iterate over basic blocks and replace exposed loads with incoming
-  // values.
-  void ForwardLoads() {
-    for (BlockIterator block_it = graph_->reverse_postorder_iterator();
-         !block_it.Done();
-         block_it.Advance()) {
-      BlockEntryInstr* block = block_it.Current();
-
-      ZoneGrowableArray<Definition*>* loads =
-          exposed_values_[block->preorder_number()];
-      if (loads == NULL) continue;  // No exposed loads.
-
-      BitVector* in = in_[block->preorder_number()];
-
-      for (intptr_t i = 0; i < loads->length(); i++) {
-        Definition* load = (*loads)[i];
-        if (!in->Contains(load->place_id())) continue;  // No incoming value.
-
-        Definition* replacement = MergeIncomingValues(block, load->place_id());
-        ASSERT(replacement != NULL);
-
-        // Sets of outgoing values are not linked into use lists so
-        // they might contain values that were replace and removed
-        // from the graph by this iteration.
-        // To prevent using them we additionally mark definitions themselves
-        // as replaced and store a pointer to the replacement.
-        replacement = replacement->Replacement();
-
-        if (load != replacement) {
-          EnsureSSATempIndex(graph_, load, replacement);
-
-          if (FLAG_trace_optimization) {
-            THR_Print("Replacing load v%" Pd " with v%" Pd "\n",
-                      load->ssa_temp_index(),
-                      replacement->ssa_temp_index());
-          }
-
-          load->ReplaceUsesWith(replacement);
-          load->RemoveFromGraph();
-          load->SetReplacement(replacement);
-          forwarded_ = true;
-        }
-      }
-    }
-  }
-
-  // Check if the given phi take the same value on all code paths.
-  // Eliminate it as redundant if this is the case.
-  // When analyzing phi operands assumes that only generated during
-  // this load phase can be redundant. They can be distinguished because
-  // they are not marked alive.
-  // TODO(vegorov): move this into a separate phase over all phis.
-  bool EliminateRedundantPhi(PhiInstr* phi) {
-    Definition* value = NULL;  // Possible value of this phi.
-
-    worklist_.Clear();
-    if (in_worklist_ == NULL) {
-      in_worklist_ = new(Z) BitVector(Z, graph_->current_ssa_temp_index());
-    } else {
-      in_worklist_->Clear();
-    }
-
-    worklist_.Add(phi);
-    in_worklist_->Add(phi->ssa_temp_index());
-
-    for (intptr_t i = 0; i < worklist_.length(); i++) {
-      PhiInstr* phi = worklist_[i];
-
-      for (intptr_t i = 0; i < phi->InputCount(); i++) {
-        Definition* input = phi->InputAt(i)->definition();
-        if (input == phi) continue;
-
-        PhiInstr* phi_input = input->AsPhi();
-        if ((phi_input != NULL) && !phi_input->is_alive()) {
-          if (!in_worklist_->Contains(phi_input->ssa_temp_index())) {
-            worklist_.Add(phi_input);
-            in_worklist_->Add(phi_input->ssa_temp_index());
-          }
-          continue;
-        }
-
-        if (value == NULL) {
-          value = input;
-        } else if (value != input) {
-          return false;  // This phi is not redundant.
-        }
-      }
-    }
-
-    // All phis in the worklist are redundant and have the same computed
-    // value on all code paths.
-    ASSERT(value != NULL);
-    for (intptr_t i = 0; i < worklist_.length(); i++) {
-      worklist_[i]->ReplaceUsesWith(value);
-    }
-
-    return true;
-  }
-
-  // Returns true if definitions are congruent assuming their inputs
-  // are congruent.
-  bool CanBeCongruent(Definition* a, Definition* b) {
-    return (a->tag() == b->tag()) &&
-       ((a->IsPhi() && (a->GetBlock() == b->GetBlock())) ||
-        (a->AllowsCSE() && a->Dependencies().IsNone() &&
-         a->AttributesEqual(b)));
-  }
-
-  // Given two definitions check if they are congruent under assumption that
-  // their inputs will be proven congruent. If they are - add them to the
-  // worklist to check their inputs' congruency.
-  // Returns true if pair was added to the worklist or is already in the
-  // worklist and false if a and b are not congruent.
-  bool AddPairToCongruencyWorklist(Definition* a, Definition* b) {
-    if (!CanBeCongruent(a, b)) {
-      return false;
-    }
-
-    // If a is already in the worklist check if it is being compared to b.
-    // Give up if it is not.
-    if (in_worklist_->Contains(a->ssa_temp_index())) {
-      for (intptr_t i = 0; i < congruency_worklist_.length(); i += 2) {
-        if (a == congruency_worklist_[i]) {
-          return (b == congruency_worklist_[i + 1]);
-        }
-      }
-      UNREACHABLE();
-    } else if (in_worklist_->Contains(b->ssa_temp_index())) {
-      return AddPairToCongruencyWorklist(b, a);
-    }
-
-    congruency_worklist_.Add(a);
-    congruency_worklist_.Add(b);
-    in_worklist_->Add(a->ssa_temp_index());
-    return true;
-  }
-
-  bool AreInputsCongruent(Definition* a, Definition* b) {
-    ASSERT(a->tag() == b->tag());
-    ASSERT(a->InputCount() == b->InputCount());
-    for (intptr_t j = 0; j < a->InputCount(); j++) {
-      Definition* inputA = a->InputAt(j)->definition();
-      Definition* inputB = b->InputAt(j)->definition();
-
-      if (inputA != inputB) {
-        if (!AddPairToCongruencyWorklist(inputA, inputB)) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
-  // Returns true if instruction dom dominates instruction other.
-  static bool Dominates(Instruction* dom, Instruction* other) {
-    BlockEntryInstr* dom_block = dom->GetBlock();
-    BlockEntryInstr* other_block = other->GetBlock();
-
-    if (dom_block == other_block) {
-      for (Instruction* current = dom->next();
-           current != NULL;
-           current = current->next()) {
-        if (current == other) {
-          return true;
-        }
-      }
-      return false;
-    }
-
-    return dom_block->Dominates(other_block);
-  }
-
-  // Replace the given phi with another if they are congruent.
-  // Returns true if succeeds.
-  bool ReplacePhiWith(PhiInstr* phi, PhiInstr* replacement) {
-    ASSERT(phi->InputCount() == replacement->InputCount());
-    ASSERT(phi->block() == replacement->block());
-
-    congruency_worklist_.Clear();
-    if (in_worklist_ == NULL) {
-      in_worklist_ = new(Z) BitVector(Z, graph_->current_ssa_temp_index());
-    } else {
-      in_worklist_->Clear();
-    }
-
-    // During the comparison worklist contains pairs of definitions to be
-    // compared.
-    if (!AddPairToCongruencyWorklist(phi, replacement)) {
-      return false;
-    }
-
-    // Process the worklist. It might grow during each comparison step.
-    for (intptr_t i = 0; i < congruency_worklist_.length(); i += 2) {
-      if (!AreInputsCongruent(congruency_worklist_[i],
-                              congruency_worklist_[i + 1])) {
-        return false;
-      }
-    }
-
-    // At this point worklist contains pairs of congruent definitions.
-    // Replace the one member of the pair with another maintaining proper
-    // domination relation between definitions and uses.
-    for (intptr_t i = 0; i < congruency_worklist_.length(); i += 2) {
-      Definition* a = congruency_worklist_[i];
-      Definition* b = congruency_worklist_[i + 1];
-
-      // If these definitions are not phis then we need to pick up one
-      // that dominates another as the replacement: if a dominates b swap them.
-      // Note: both a and b are used as a phi input at the same block B which
-      // means a dominates B and b dominates B, which guarantees that either
-      // a dominates b or b dominates a.
-      if (!a->IsPhi()) {
-        if (Dominates(a, b)) {
-          Definition* t = a;
-          a = b;
-          b = t;
-        }
-        ASSERT(Dominates(b, a));
-      }
-
-      if (FLAG_trace_load_optimization) {
-        THR_Print("Replacing %s with congruent %s\n",
-                  a->ToCString(),
-                  b->ToCString());
-      }
-
-      a->ReplaceUsesWith(b);
-      if (a->IsPhi()) {
-        // We might be replacing a phi introduced by the load forwarding
-        // that is not inserted in the graph yet.
-        ASSERT(b->IsPhi());
-        PhiInstr* phi_a = a->AsPhi();
-        if (phi_a->is_alive()) {
-          phi_a->mark_dead();
-          phi_a->block()->RemovePhi(phi_a);
-          phi_a->UnuseAllInputs();
-        }
-      } else {
-        a->RemoveFromGraph();
-      }
-    }
-
-    return true;
-  }
-
-  // Insert the given phi into the graph. Attempt to find an equal one in the
-  // target block first.
-  // Returns true if the phi was inserted and false if it was replaced.
-  bool EmitPhi(PhiInstr* phi) {
-    for (PhiIterator it(phi->block()); !it.Done(); it.Advance()) {
-      if (ReplacePhiWith(phi, it.Current())) {
-        return false;
-      }
-    }
-
-    phi->mark_alive();
-    phi->block()->InsertPhi(phi);
-    return true;
-  }
-
-  // Phis have not yet been inserted into the graph but they have uses of
-  // their inputs.  Insert the non-redundant ones and clear the input uses
-  // of the redundant ones.
-  void EmitPhis() {
-    // First eliminate all redundant phis.
-    for (intptr_t i = 0; i < phis_.length(); i++) {
-      PhiInstr* phi = phis_[i];
-      if (!phi->HasUses() || EliminateRedundantPhi(phi)) {
-        phi->UnuseAllInputs();
-        phis_[i] = NULL;
-      }
-    }
-
-    // Now emit phis or replace them with equal phis already present in the
-    // graph.
-    for (intptr_t i = 0; i < phis_.length(); i++) {
-      PhiInstr* phi = phis_[i];
-      if ((phi != NULL) && (!phi->HasUses() || !EmitPhi(phi))) {
-        phi->UnuseAllInputs();
-      }
-    }
-  }
-
-  ZoneGrowableArray<Definition*>* CreateBlockOutValues() {
-    ZoneGrowableArray<Definition*>* out =
-        new(Z) ZoneGrowableArray<Definition*>(aliased_set_->max_place_id());
-    for (intptr_t i = 0; i < aliased_set_->max_place_id(); i++) {
-      out->Add(NULL);
-    }
-    return out;
-  }
-
-  FlowGraph* graph_;
-  DirectChainedHashMap<PointerKeyValueTrait<Place> >* map_;
-
-  // Mapping between field offsets in words and expression ids of loads from
-  // that offset.
-  AliasedSet* aliased_set_;
-
-  // Per block sets of expression ids for loads that are: incoming (available
-  // on the entry), outgoing (available on the exit), generated and killed.
-  GrowableArray<BitVector*> in_;
-  GrowableArray<BitVector*> out_;
-  GrowableArray<BitVector*> gen_;
-  GrowableArray<BitVector*> kill_;
-
-  // Per block list of upwards exposed loads.
-  GrowableArray<ZoneGrowableArray<Definition*>*> exposed_values_;
-
-  // Per block mappings between expression ids and outgoing definitions that
-  // represent those ids.
-  GrowableArray<ZoneGrowableArray<Definition*>*> out_values_;
-
-  // List of phis generated during ComputeOutValues and ForwardLoads.
-  // Some of these phis might be redundant and thus a separate pass is
-  // needed to emit only non-redundant ones.
-  GrowableArray<PhiInstr*> phis_;
-
-  // Auxiliary worklist used by redundant phi elimination.
-  GrowableArray<PhiInstr*> worklist_;
-  GrowableArray<Definition*> congruency_worklist_;
-  BitVector* in_worklist_;
-
-
-  // True if any load was eliminated.
-  bool forwarded_;
-
-  DISALLOW_COPY_AND_ASSIGN(LoadOptimizer);
-};
-
-
-class StoreOptimizer : public LivenessAnalysis {
- public:
-  StoreOptimizer(FlowGraph* graph,
-                 AliasedSet* aliased_set,
-                 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map)
-      : LivenessAnalysis(aliased_set->max_place_id(), graph->postorder()),
-        graph_(graph),
-        map_(map),
-        aliased_set_(aliased_set),
-        exposed_stores_(graph_->postorder().length()) {
-    const intptr_t num_blocks = graph_->postorder().length();
-    for (intptr_t i = 0; i < num_blocks; i++) {
-      exposed_stores_.Add(NULL);
-    }
-  }
-
-  static void OptimizeGraph(FlowGraph* graph) {
-    ASSERT(FLAG_load_cse);
-    if (FLAG_trace_load_optimization) {
-      FlowGraphPrinter::PrintGraph("Before StoreOptimizer", graph);
-    }
-
-    DirectChainedHashMap<PointerKeyValueTrait<Place> > map;
-    AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeStores);
-    if ((aliased_set != NULL) && !aliased_set->IsEmpty()) {
-      StoreOptimizer store_optimizer(graph, aliased_set, &map);
-      store_optimizer.Optimize();
-    }
-  }
-
- private:
-  void Optimize() {
-    Analyze();
-    if (FLAG_trace_load_optimization) {
-      Dump();
-    }
-    EliminateDeadStores();
-    if (FLAG_trace_load_optimization) {
-      FlowGraphPrinter::PrintGraph("After StoreOptimizer", graph_);
-    }
-  }
-
-  bool CanEliminateStore(Instruction* instr) {
-    switch (instr->tag()) {
-      case Instruction::kStoreInstanceField: {
-        StoreInstanceFieldInstr* store_instance = instr->AsStoreInstanceField();
-        // Can't eliminate stores that initialize fields.
-        return !(store_instance->is_potential_unboxed_initialization() ||
-                 store_instance->is_object_reference_initialization());
-      }
-      case Instruction::kStoreIndexed:
-      case Instruction::kStoreStaticField:
-        return true;
-      default:
-        UNREACHABLE();
-        return false;
-    }
-  }
-
-  virtual void ComputeInitialSets() {
-    Zone* zone = graph_->zone();
-    BitVector* all_places = new(zone) BitVector(zone,
-        aliased_set_->max_place_id());
-    all_places->SetAll();
-    for (BlockIterator block_it = graph_->postorder_iterator();
-         !block_it.Done();
-         block_it.Advance()) {
-      BlockEntryInstr* block = block_it.Current();
-      const intptr_t postorder_number = block->postorder_number();
-
-      BitVector* kill = kill_[postorder_number];
-      BitVector* live_in = live_in_[postorder_number];
-      BitVector* live_out = live_out_[postorder_number];
-
-      ZoneGrowableArray<Instruction*>* exposed_stores = NULL;
-
-      // Iterate backwards starting at the last instruction.
-      for (BackwardInstructionIterator instr_it(block);
-           !instr_it.Done();
-           instr_it.Advance()) {
-        Instruction* instr = instr_it.Current();
-
-        bool is_load = false;
-        bool is_store = false;
-        Place place(instr, &is_load, &is_store);
-        if (place.IsImmutableField()) {
-          // Loads/stores of final fields do not participate.
-          continue;
-        }
-
-        // Handle stores.
-        if (is_store) {
-          if (kill->Contains(instr->place_id())) {
-            if (!live_in->Contains(instr->place_id()) &&
-                CanEliminateStore(instr)) {
-              if (FLAG_trace_optimization) {
-                THR_Print(
-                    "Removing dead store to place %" Pd " in block B%" Pd "\n",
-                    instr->place_id(), block->block_id());
-              }
-              instr_it.RemoveCurrentFromGraph();
-            }
-          } else if (!live_in->Contains(instr->place_id())) {
-            // Mark this store as down-ward exposed: They are the only
-            // candidates for the global store elimination.
-            if (exposed_stores == NULL) {
-              const intptr_t kMaxExposedStoresInitialSize = 5;
-              exposed_stores = new(zone) ZoneGrowableArray<Instruction*>(
-                  Utils::Minimum(kMaxExposedStoresInitialSize,
-                                 aliased_set_->max_place_id()));
-            }
-            exposed_stores->Add(instr);
-          }
-          // Interfering stores kill only loads from the same place.
-          kill->Add(instr->place_id());
-          live_in->Remove(instr->place_id());
-          continue;
-        }
-
-        // Handle side effects, deoptimization and function return.
-        if (!instr->Effects().IsNone() ||
-            instr->CanDeoptimize() ||
-            instr->IsThrow() ||
-            instr->IsReThrow() ||
-            instr->IsReturn()) {
-          // Instructions that return from the function, instructions with side
-          // effects and instructions that can deoptimize are considered as
-          // loads from all places.
-          live_in->CopyFrom(all_places);
-          if (instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) {
-            // Initialize live-out for exit blocks since it won't be computed
-            // otherwise during the fixed point iteration.
-            live_out->CopyFrom(all_places);
-          }
-          continue;
-        }
-
-        // Handle loads.
-        Definition* defn = instr->AsDefinition();
-        if ((defn != NULL) && IsLoadEliminationCandidate(defn)) {
-          const intptr_t alias = aliased_set_->LookupAliasId(place.ToAlias());
-          live_in->AddAll(aliased_set_->GetKilledSet(alias));
-          continue;
-        }
-      }
-      exposed_stores_[postorder_number] = exposed_stores;
-    }
-    if (FLAG_trace_load_optimization) {
-      Dump();
-      THR_Print("---\n");
-    }
-  }
-
-  void EliminateDeadStores() {
-    // Iteration order does not matter here.
-    for (BlockIterator block_it = graph_->postorder_iterator();
-         !block_it.Done();
-         block_it.Advance()) {
-      BlockEntryInstr* block = block_it.Current();
-      const intptr_t postorder_number = block->postorder_number();
-
-      BitVector* live_out = live_out_[postorder_number];
-
-      ZoneGrowableArray<Instruction*>* exposed_stores =
-        exposed_stores_[postorder_number];
-      if (exposed_stores == NULL) continue;  // No exposed stores.
-
-      // Iterate over candidate stores.
-      for (intptr_t i = 0; i < exposed_stores->length(); ++i) {
-        Instruction* instr = (*exposed_stores)[i];
-        bool is_load = false;
-        bool is_store = false;
-        Place place(instr, &is_load, &is_store);
-        ASSERT(!is_load && is_store);
-        if (place.IsImmutableField()) {
-          // Final field do not participate in dead store elimination.
-          continue;
-        }
-        // Eliminate a downward exposed store if the corresponding place is not
-        // in live-out.
-        if (!live_out->Contains(instr->place_id()) &&
-            CanEliminateStore(instr)) {
-          if (FLAG_trace_optimization) {
-            THR_Print("Removing dead store to place %" Pd " block B%" Pd "\n",
-                      instr->place_id(), block->block_id());
-          }
-          instr->RemoveFromGraph(/* ignored */ false);
-        }
-      }
-    }
-  }
-
-  FlowGraph* graph_;
-  DirectChainedHashMap<PointerKeyValueTrait<Place> >* map_;
-
-  // Mapping between field offsets in words and expression ids of loads from
-  // that offset.
-  AliasedSet* aliased_set_;
-
-  // Per block list of downward exposed stores.
-  GrowableArray<ZoneGrowableArray<Instruction*>*> exposed_stores_;
-
-  DISALLOW_COPY_AND_ASSIGN(StoreOptimizer);
-};
-
-
-void DeadStoreElimination::Optimize(FlowGraph* graph) {
-  if (FLAG_dead_store_elimination) {
-    StoreOptimizer::OptimizeGraph(graph);
-  }
-}
-
-
-// Returns true iff this definition is used in a non-phi instruction.
-static bool HasRealUse(Definition* def) {
-  // Environment uses are real (non-phi) uses.
-  if (def->env_use_list() != NULL) return true;
-
-  for (Value::Iterator it(def->input_use_list());
-       !it.Done();
-       it.Advance()) {
-    if (!it.Current()->instruction()->IsPhi()) return true;
-  }
-  return false;
-}
-
-
-void DeadCodeElimination::EliminateDeadPhis(FlowGraph* flow_graph) {
-  GrowableArray<PhiInstr*> live_phis;
-  for (BlockIterator b = flow_graph->postorder_iterator();
-       !b.Done();
-       b.Advance()) {
-    JoinEntryInstr* join = b.Current()->AsJoinEntry();
-    if (join != NULL) {
-      for (PhiIterator it(join); !it.Done(); it.Advance()) {
-        PhiInstr* phi = it.Current();
-        // Phis that have uses and phis inside try blocks are
-        // marked as live.
-        if (HasRealUse(phi) || join->InsideTryBlock()) {
-          live_phis.Add(phi);
-          phi->mark_alive();
-        } else {
-          phi->mark_dead();
-        }
-      }
-    }
-  }
-
-  while (!live_phis.is_empty()) {
-    PhiInstr* phi = live_phis.RemoveLast();
-    for (intptr_t i = 0; i < phi->InputCount(); i++) {
-      Value* val = phi->InputAt(i);
-      PhiInstr* used_phi = val->definition()->AsPhi();
-      if ((used_phi != NULL) && !used_phi->is_alive()) {
-        used_phi->mark_alive();
-        live_phis.Add(used_phi);
-      }
-    }
-  }
-
-  for (BlockIterator it(flow_graph->postorder_iterator());
-       !it.Done();
-       it.Advance()) {
-    JoinEntryInstr* join = it.Current()->AsJoinEntry();
-    if (join != NULL) {
-      if (join->phis_ == NULL) continue;
-
-      // Eliminate dead phis and compact the phis_ array of the block.
-      intptr_t to_index = 0;
-      for (intptr_t i = 0; i < join->phis_->length(); ++i) {
-        PhiInstr* phi = (*join->phis_)[i];
-        if (phi != NULL) {
-          if (!phi->is_alive()) {
-            phi->ReplaceUsesWith(flow_graph->constant_null());
-            phi->UnuseAllInputs();
-            (*join->phis_)[i] = NULL;
-            if (FLAG_trace_optimization) {
-              THR_Print("Removing dead phi v%" Pd "\n", phi->ssa_temp_index());
-            }
-          } else if (phi->IsRedundant()) {
-            phi->ReplaceUsesWith(phi->InputAt(0)->definition());
-            phi->UnuseAllInputs();
-            (*join->phis_)[i] = NULL;
-            if (FLAG_trace_optimization) {
-              THR_Print("Removing redundant phi v%" Pd "\n",
-                         phi->ssa_temp_index());
-            }
-          } else {
-            (*join->phis_)[to_index++] = phi;
-          }
-        }
-      }
-      if (to_index == 0) {
-        join->phis_ = NULL;
-      } else {
-        join->phis_->TruncateTo(to_index);
-      }
-    }
-  }
-}
-
-
-class CSEInstructionMap : public ValueObject {
- public:
-  // Right now CSE and LICM track a single effect: possible externalization of
-  // strings.
-  // Other effects like modifications of fields are tracked in a separate load
-  // forwarding pass via Alias structure.
-  COMPILE_ASSERT(EffectSet::kLastEffect == 1);
-
-  CSEInstructionMap() : independent_(), dependent_() { }
-  explicit CSEInstructionMap(const CSEInstructionMap& other)
-      : ValueObject(),
-        independent_(other.independent_),
-        dependent_(other.dependent_) {
-  }
-
-  void RemoveAffected(EffectSet effects) {
-    if (!effects.IsNone()) {
-      dependent_.Clear();
-    }
-  }
-
-  Instruction* Lookup(Instruction* other) const {
-    return GetMapFor(other)->Lookup(other);
-  }
-
-  void Insert(Instruction* instr) {
-    return GetMapFor(instr)->Insert(instr);
-  }
-
- private:
-  typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> >  Map;
-
-  Map* GetMapFor(Instruction* instr) {
-    return instr->Dependencies().IsNone() ? &independent_ : &dependent_;
-  }
-
-  const Map* GetMapFor(Instruction* instr) const {
-    return instr->Dependencies().IsNone() ? &independent_ : &dependent_;
-  }
-
-  // All computations that are not affected by any side-effect.
-  // Majority of computations are not affected by anything and will be in
-  // this map.
-  Map independent_;
-
-  // All computations that are affected by side effect.
-  Map dependent_;
-};
-
-
-bool DominatorBasedCSE::Optimize(FlowGraph* graph) {
-  bool changed = false;
-  if (FLAG_load_cse) {
-    changed = LoadOptimizer::OptimizeGraph(graph) || changed;
-  }
-
-  CSEInstructionMap map;
-  changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed;
-
-  return changed;
-}
-
-
-bool DominatorBasedCSE::OptimizeRecursive(
-    FlowGraph* graph,
-    BlockEntryInstr* block,
-    CSEInstructionMap* map) {
-  bool changed = false;
-  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
-    Instruction* current = it.Current();
-    if (current->AllowsCSE()) {
-      Instruction* replacement = map->Lookup(current);
-      if ((replacement != NULL) &&
-          graph->block_effects()->IsAvailableAt(replacement, block)) {
-        // Replace current with lookup result.
-        ReplaceCurrentInstruction(&it, current, replacement, graph);
-        changed = true;
-        continue;
-      }
-
-      // For simplicity we assume that instruction either does not depend on
-      // anything or does not affect anything. If this is not the case then
-      // we should first remove affected instructions from the map and
-      // then add instruction to the map so that it does not kill itself.
-      ASSERT(current->Effects().IsNone() || current->Dependencies().IsNone());
-      map->Insert(current);
-    }
-
-    map->RemoveAffected(current->Effects());
-  }
-
-  // Process children in the dominator tree recursively.
-  intptr_t num_children = block->dominated_blocks().length();
-  for (intptr_t i = 0; i < num_children; ++i) {
-    BlockEntryInstr* child = block->dominated_blocks()[i];
-    if (i  < num_children - 1) {
-      // Copy map.
-      CSEInstructionMap child_map(*map);
-      changed = OptimizeRecursive(graph, child, &child_map) || changed;
-    } else {
-      // Reuse map for the last child.
-      changed = OptimizeRecursive(graph, child, map) || changed;
-    }
-  }
-  return changed;
-}
-
-
-// Returns true if the given phi has a single input use and
-// is used in the environments either at the corresponding block entry or
-// at the same instruction where input use is.
-static bool PhiHasSingleUse(PhiInstr* phi, Value* use) {
-  if ((use->next_use() != NULL) || (phi->input_use_list() != use)) {
-    return false;
-  }
-
-  BlockEntryInstr* block = phi->block();
-  for (Value* env_use = phi->env_use_list();
-       env_use != NULL;
-       env_use = env_use->next_use()) {
-    if ((env_use->instruction() != block) &&
-        (env_use->instruction() != use->instruction())) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-
-bool BranchSimplifier::Match(JoinEntryInstr* block) {
-  // Match the pattern of a branch on a comparison whose left operand is a
-  // phi from the same block, and whose right operand is a constant.
-  //
-  //   Branch(Comparison(kind, Phi, Constant))
-  //
-  // These are the branches produced by inlining in a test context.  Also,
-  // the phi has no other uses so they can simply be eliminated.  The block
-  // has no other phis and no instructions intervening between the phi and
-  // branch so the block can simply be eliminated.
-  BranchInstr* branch = block->last_instruction()->AsBranch();
-  ASSERT(branch != NULL);
-  ComparisonInstr* comparison = branch->comparison();
-  Value* left = comparison->left();
-  PhiInstr* phi = left->definition()->AsPhi();
-  Value* right = comparison->right();
-  ConstantInstr* constant =
-      (right == NULL) ? NULL : right->definition()->AsConstant();
-  return (phi != NULL) &&
-      (constant != NULL) &&
-      (phi->GetBlock() == block) &&
-      PhiHasSingleUse(phi, left) &&
-      (block->next() == branch) &&
-      (block->phis()->length() == 1);
-}
-
-
-JoinEntryInstr* BranchSimplifier::ToJoinEntry(Zone* zone,
-                                              TargetEntryInstr* target) {
-  // Convert a target block into a join block.  Branches will be duplicated
-  // so the former true and false targets become joins of the control flows
-  // from all the duplicated branches.
-  JoinEntryInstr* join =
-      new(zone) JoinEntryInstr(target->block_id(), target->try_index());
-  join->InheritDeoptTarget(zone, target);
-  join->LinkTo(target->next());
-  join->set_last_instruction(target->last_instruction());
-  target->UnuseAllInputs();
-  return join;
-}
-
-
-BranchInstr* BranchSimplifier::CloneBranch(Zone* zone,
-                                           BranchInstr* branch,
-                                           Value* new_left,
-                                           Value* new_right) {
-  ComparisonInstr* comparison = branch->comparison();
-  ComparisonInstr* new_comparison =
-      comparison->CopyWithNewOperands(new_left, new_right);
-  BranchInstr* new_branch = new(zone) BranchInstr(new_comparison);
-  new_branch->set_is_checked(branch->is_checked());
-  return new_branch;
-}
-
-
-void BranchSimplifier::Simplify(FlowGraph* flow_graph) {
-  // Optimize some branches that test the value of a phi.  When it is safe
-  // to do so, push the branch to each of the predecessor blocks.  This is
-  // an optimization when (a) it can avoid materializing a boolean object at
-  // the phi only to test its value, and (b) it can expose opportunities for
-  // constant propagation and unreachable code elimination.  This
-  // optimization is intended to run after inlining which creates
-  // opportunities for optimization (a) and before constant folding which
-  // can perform optimization (b).
-
-  // Begin with a worklist of join blocks ending in branches.  They are
-  // candidates for the pattern below.
-  Zone* zone = flow_graph->zone();
-  const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder();
-  GrowableArray<BlockEntryInstr*> worklist(postorder.length());
-  for (BlockIterator it(postorder); !it.Done(); it.Advance()) {
-    BlockEntryInstr* block = it.Current();
-    if (block->IsJoinEntry() && block->last_instruction()->IsBranch()) {
-      worklist.Add(block);
-    }
-  }
-
-  // Rewrite until no more instance of the pattern exists.
-  bool changed = false;
-  while (!worklist.is_empty()) {
-    // All blocks in the worklist are join blocks (ending with a branch).
-    JoinEntryInstr* block = worklist.RemoveLast()->AsJoinEntry();
-    ASSERT(block != NULL);
-
-    if (Match(block)) {
-      changed = true;
-
-      // The branch will be copied and pushed to all the join's
-      // predecessors.  Convert the true and false target blocks into join
-      // blocks to join the control flows from all of the true
-      // (respectively, false) targets of the copied branches.
-      //
-      // The converted join block will have no phis, so it cannot be another
-      // instance of the pattern.  There is thus no need to add it to the
-      // worklist.
-      BranchInstr* branch = block->last_instruction()->AsBranch();
-      ASSERT(branch != NULL);
-      JoinEntryInstr* join_true =
-          ToJoinEntry(zone, branch->true_successor());
-      JoinEntryInstr* join_false =
-          ToJoinEntry(zone, branch->false_successor());
-
-      ComparisonInstr* comparison = branch->comparison();
-      PhiInstr* phi = comparison->left()->definition()->AsPhi();
-      ConstantInstr* constant = comparison->right()->definition()->AsConstant();
-      ASSERT(constant != NULL);
-      // Copy the constant and branch and push it to all the predecessors.
-      for (intptr_t i = 0, count = block->PredecessorCount(); i < count; ++i) {
-        GotoInstr* old_goto =
-            block->PredecessorAt(i)->last_instruction()->AsGoto();
-        ASSERT(old_goto != NULL);
-
-        // Replace the goto in each predecessor with a rewritten branch,
-        // rewritten to use the corresponding phi input instead of the phi.
-        Value* new_left = phi->InputAt(i)->Copy(zone);
-        Value* new_right = new(zone) Value(constant);
-        BranchInstr* new_branch =
-            CloneBranch(zone, branch, new_left, new_right);
-        if (branch->env() == NULL) {
-          new_branch->InheritDeoptTarget(zone, old_goto);
-        } else {
-          // Take the environment from the branch if it has one.
-          new_branch->InheritDeoptTarget(zone, branch);
-          // InheritDeoptTarget gave the new branch's comparison the same
-          // deopt id that it gave the new branch.  The id should be the
-          // deopt id of the original comparison.
-          new_branch->comparison()->SetDeoptId(*comparison);
-          // The phi can be used in the branch's environment.  Rename such
-          // uses.
-          for (Environment::DeepIterator it(new_branch->env());
-               !it.Done();
-               it.Advance()) {
-            Value* use = it.CurrentValue();
-            if (use->definition() == phi) {
-              Definition* replacement = phi->InputAt(i)->definition();
-              use->RemoveFromUseList();
-              use->set_definition(replacement);
-              replacement->AddEnvUse(use);
-            }
-          }
-        }
-
-        new_branch->InsertBefore(old_goto);
-        new_branch->set_next(NULL);  // Detaching the goto from the graph.
-        old_goto->UnuseAllInputs();
-
-        // Update the predecessor block.  We may have created another
-        // instance of the pattern so add it to the worklist if necessary.
-        BlockEntryInstr* branch_block = new_branch->GetBlock();
-        branch_block->set_last_instruction(new_branch);
-        if (branch_block->IsJoinEntry()) worklist.Add(branch_block);
-
-        // Connect the branch to the true and false joins, via empty target
-        // blocks.
-        TargetEntryInstr* true_target =
-            new(zone) TargetEntryInstr(flow_graph->max_block_id() + 1,
-                                          block->try_index());
-        true_target->InheritDeoptTarget(zone, join_true);
-        TargetEntryInstr* false_target =
-            new(zone) TargetEntryInstr(flow_graph->max_block_id() + 2,
-                                          block->try_index());
-        false_target->InheritDeoptTarget(zone, join_false);
-        flow_graph->set_max_block_id(flow_graph->max_block_id() + 2);
-        *new_branch->true_successor_address() = true_target;
-        *new_branch->false_successor_address() = false_target;
-        GotoInstr* goto_true = new(zone) GotoInstr(join_true);
-        goto_true->InheritDeoptTarget(zone, join_true);
-        true_target->LinkTo(goto_true);
-        true_target->set_last_instruction(goto_true);
-        GotoInstr* goto_false = new(zone) GotoInstr(join_false);
-        goto_false->InheritDeoptTarget(zone, join_false);
-        false_target->LinkTo(goto_false);
-        false_target->set_last_instruction(goto_false);
-      }
-      // When all predecessors have been rewritten, the original block is
-      // unreachable from the graph.
-      phi->UnuseAllInputs();
-      branch->UnuseAllInputs();
-      block->UnuseAllInputs();
-      ASSERT(!phi->HasUses());
-    }
-  }
-
-  if (changed) {
-    // We may have changed the block order and the dominator tree.
-    flow_graph->DiscoverBlocks();
-    GrowableArray<BitVector*> dominance_frontier;
-    flow_graph->ComputeDominators(&dominance_frontier);
-  }
-}
-
-
-static bool IsTrivialBlock(BlockEntryInstr* block, Definition* defn) {
-  return (block->IsTargetEntry() && (block->PredecessorCount() == 1)) &&
-    ((block->next() == block->last_instruction()) ||
-     ((block->next() == defn) && (defn->next() == block->last_instruction())));
-}
-
-
-static void EliminateTrivialBlock(BlockEntryInstr* block,
-                                  Definition* instr,
-                                  IfThenElseInstr* before) {
-  block->UnuseAllInputs();
-  block->last_instruction()->UnuseAllInputs();
-
-  if ((block->next() == instr) &&
-      (instr->next() == block->last_instruction())) {
-    before->previous()->LinkTo(instr);
-    instr->LinkTo(before);
-  }
-}
-
-
-void IfConverter::Simplify(FlowGraph* flow_graph) {
-  Zone* zone = flow_graph->zone();
-  bool changed = false;
-
-  const GrowableArray<BlockEntryInstr*>& postorder = flow_graph->postorder();
-  for (BlockIterator it(postorder); !it.Done(); it.Advance()) {
-    BlockEntryInstr* block = it.Current();
-    JoinEntryInstr* join = block->AsJoinEntry();
-
-    // Detect diamond control flow pattern which materializes a value depending
-    // on the result of the comparison:
-    //
-    // B_pred:
-    //   ...
-    //   Branch if COMP goto (B_pred1, B_pred2)
-    // B_pred1: -- trivial block that contains at most one definition
-    //   v1 = Constant(...)
-    //   goto B_block
-    // B_pred2: -- trivial block that contains at most one definition
-    //   v2 = Constant(...)
-    //   goto B_block
-    // B_block:
-    //   v3 = phi(v1, v2) -- single phi
-    //
-    // and replace it with
-    //
-    // Ba:
-    //   v3 = IfThenElse(COMP ? v1 : v2)
-    //
-    if ((join != NULL) &&
-        (join->phis() != NULL) &&
-        (join->phis()->length() == 1) &&
-        (block->PredecessorCount() == 2)) {
-      BlockEntryInstr* pred1 = block->PredecessorAt(0);
-      BlockEntryInstr* pred2 = block->PredecessorAt(1);
-
-      PhiInstr* phi = (*join->phis())[0];
-      Value* v1 = phi->InputAt(0);
-      Value* v2 = phi->InputAt(1);
-
-      if (IsTrivialBlock(pred1, v1->definition()) &&
-          IsTrivialBlock(pred2, v2->definition()) &&
-          (pred1->PredecessorAt(0) == pred2->PredecessorAt(0))) {
-        BlockEntryInstr* pred = pred1->PredecessorAt(0);
-        BranchInstr* branch = pred->last_instruction()->AsBranch();
-        ComparisonInstr* comparison = branch->comparison();
-
-        // Check if the platform supports efficient branchless IfThenElseInstr
-        // for the given combination of comparison and values flowing from
-        // false and true paths.
-        if (IfThenElseInstr::Supports(comparison, v1, v2)) {
-          Value* if_true = (pred1 == branch->true_successor()) ? v1 : v2;
-          Value* if_false = (pred2 == branch->true_successor()) ? v1 : v2;
-
-          ComparisonInstr* new_comparison =
-              comparison->CopyWithNewOperands(
-                  comparison->left()->Copy(zone),
-                  comparison->right()->Copy(zone));
-          IfThenElseInstr* if_then_else = new(zone) IfThenElseInstr(
-              new_comparison,
-              if_true->Copy(zone),
-              if_false->Copy(zone));
-          flow_graph->InsertBefore(branch,
-                                   if_then_else,
-                                   NULL,
-                                   FlowGraph::kValue);
-
-          phi->ReplaceUsesWith(if_then_else);
-
-          // Connect IfThenElseInstr to the first instruction in the merge block
-          // effectively eliminating diamond control flow.
-          // Current block as well as pred1 and pred2 blocks are no longer in
-          // the graph at this point.
-          if_then_else->LinkTo(join->next());
-          pred->set_last_instruction(join->last_instruction());
-
-          // Resulting block must inherit block id from the eliminated current
-          // block to guarantee that ordering of phi operands in its successor
-          // stays consistent.
-          pred->set_block_id(block->block_id());
-
-          // If v1 and v2 were defined inside eliminated blocks pred1/pred2
-          // move them out to the place before inserted IfThenElse instruction.
-          EliminateTrivialBlock(pred1, v1->definition(), if_then_else);
-          EliminateTrivialBlock(pred2, v2->definition(), if_then_else);
-
-          // Update use lists to reflect changes in the graph.
-          phi->UnuseAllInputs();
-          branch->UnuseAllInputs();
-          block->UnuseAllInputs();
-
-          // The graph has changed. Recompute dominators and block orders after
-          // this pass is finished.
-          changed = true;
-        }
-      }
-    }
-  }
-
-  if (changed) {
-    // We may have changed the block order and the dominator tree.
-    flow_graph->DiscoverBlocks();
-    GrowableArray<BitVector*> dominance_frontier;
-    flow_graph->ComputeDominators(&dominance_frontier);
-  }
-}
-
-
-void FlowGraphOptimizer::EliminateEnvironments() {
-  // After this pass we can no longer perform LICM and hoist instructions
-  // that can deoptimize.
-
-  flow_graph_->disallow_licm();
-  for (intptr_t i = 0; i < block_order_.length(); ++i) {
-    BlockEntryInstr* block = block_order_[i];
-    block->RemoveEnvironment();
-    for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
-      Instruction* current = it.Current();
-      if (!current->CanDeoptimize()) {
-        // TODO(srdjan): --source-lines needs deopt environments to get at
-        // the code for this instruction, however, leaving the environment
-        // changes code.
-        current->RemoveEnvironment();
-      }
-    }
-  }
-}
-
-
-enum SafeUseCheck { kOptimisticCheck, kStrictCheck };
-
-// Check if the use is safe for allocation sinking. Allocation sinking
-// candidates can only be used at store instructions:
-//
-//     - any store into the allocation candidate itself is unconditionally safe
-//       as it just changes the rematerialization state of this candidate;
-//     - store into another object is only safe if another object is allocation
-//       candidate.
-//
-// We use a simple fix-point algorithm to discover the set of valid candidates
-// (see CollectCandidates method), that's why this IsSafeUse can operate in two
-// modes:
-//
-//     - optimistic, when every allocation is assumed to be an allocation
-//       sinking candidate;
-//     - strict, when only marked allocations are assumed to be allocation
-//       sinking candidates.
-//
-// Fix-point algorithm in CollectCandiates first collects a set of allocations
-// optimistically and then checks each collected candidate strictly and unmarks
-// invalid candidates transitively until only strictly valid ones remain.
-static bool IsSafeUse(Value* use, SafeUseCheck check_type) {
-  if (use->instruction()->IsMaterializeObject()) {
-    return true;
-  }
-
-  StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
-  if (store != NULL) {
-    if (use == store->value()) {
-      Definition* instance = store->instance()->definition();
-      return instance->IsAllocateObject() &&
-          ((check_type == kOptimisticCheck) ||
-           instance->Identity().IsAllocationSinkingCandidate());
-    }
-    return true;
-  }
-
-  return false;
-}
-
-
-// Right now we are attempting to sink allocation only into
-// deoptimization exit. So candidate should only be used in StoreInstanceField
-// instructions that write into fields of the allocated object.
-// We do not support materialization of the object that has type arguments.
-static bool IsAllocationSinkingCandidate(Definition* alloc,
-                                         SafeUseCheck check_type) {
-  for (Value* use = alloc->input_use_list();
-       use != NULL;
-       use = use->next_use()) {
-    if (!IsSafeUse(use, check_type)) {
-      if (FLAG_trace_optimization) {
-        THR_Print("use of %s at %s is unsafe for allocation sinking\n",
-                  alloc->ToCString(),
-                  use->instruction()->ToCString());
-      }
-      return false;
-    }
-  }
-
-  return true;
-}
-
-
-// If the given use is a store into an object then return an object we are
-// storing into.
-static Definition* StoreInto(Value* use) {
-  StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
-  if (store != NULL) {
-    return store->instance()->definition();
-  }
-
-  return NULL;
-}
-
-
-// Remove the given allocation from the graph. It is not observable.
-// If deoptimization occurs the object will be materialized.
-void AllocationSinking::EliminateAllocation(Definition* alloc) {
-  ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck));
-
-  if (FLAG_trace_optimization) {
-    THR_Print("removing allocation from the graph: v%" Pd "\n",
-              alloc->ssa_temp_index());
-  }
-
-  // As an allocation sinking candidate it is only used in stores to its own
-  // fields. Remove these stores.
-  for (Value* use = alloc->input_use_list();
-       use != NULL;
-       use = alloc->input_use_list()) {
-    use->instruction()->RemoveFromGraph();
-  }
-
-  // There should be no environment uses. The pass replaced them with
-  // MaterializeObject instructions.
-#ifdef DEBUG
-  for (Value* use = alloc->env_use_list();
-       use != NULL;
-       use = use->next_use()) {
-    ASSERT(use->instruction()->IsMaterializeObject());
-  }
-#endif
-  ASSERT(alloc->input_use_list() == NULL);
-  alloc->RemoveFromGraph();
-  if (alloc->ArgumentCount() > 0) {
-    ASSERT(alloc->ArgumentCount() == 1);
-    for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) {
-      alloc->PushArgumentAt(i)->RemoveFromGraph();
-    }
-  }
-}
-
-
-// Find allocation instructions that can be potentially eliminated and
-// rematerialized at deoptimization exits if needed. See IsSafeUse
-// for the description of algorithm used below.
-void AllocationSinking::CollectCandidates() {
-  // Optimistically collect all potential candidates.
-  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
-       !block_it.Done();
-       block_it.Advance()) {
-    BlockEntryInstr* block = block_it.Current();
-    for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
-      { AllocateObjectInstr* alloc = it.Current()->AsAllocateObject();
-        if ((alloc != NULL) &&
-            IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) {
-          alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate());
-          candidates_.Add(alloc);
-        }
-      }
-      { AllocateUninitializedContextInstr* alloc =
-            it.Current()->AsAllocateUninitializedContext();
-        if ((alloc != NULL) &&
-            IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) {
-          alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate());
-          candidates_.Add(alloc);
-        }
-      }
-    }
-  }
-
-  // Transitively unmark all candidates that are not strictly valid.
-  bool changed;
-  do {
-    changed = false;
-    for (intptr_t i = 0; i < candidates_.length(); i++) {
-      Definition* alloc = candidates_[i];
-      if (alloc->Identity().IsAllocationSinkingCandidate()) {
-        if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) {
-          alloc->SetIdentity(AliasIdentity::Unknown());
-          changed = true;
-        }
-      }
-    }
-  } while (changed);
-
-  // Shrink the list of candidates removing all unmarked ones.
-  intptr_t j = 0;
-  for (intptr_t i = 0; i < candidates_.length(); i++) {
-    Definition* alloc = candidates_[i];
-    if (alloc->Identity().IsAllocationSinkingCandidate()) {
-      if (FLAG_trace_optimization) {
-        THR_Print("discovered allocation sinking candidate: v%" Pd "\n",
-                  alloc->ssa_temp_index());
-      }
-
-      if (j != i) {
-        candidates_[j] = alloc;
-      }
-      j++;
-    }
-  }
-  candidates_.TruncateTo(j);
-}
-
-
-// If materialization references an allocation sinking candidate then replace
-// this reference with a materialization which should have been computed for
-// this side-exit. CollectAllExits should have collected this exit.
-void AllocationSinking::NormalizeMaterializations() {
-  for (intptr_t i = 0; i < candidates_.length(); i++) {
-    Definition* alloc = candidates_[i];
-
-    Value* next_use;
-    for (Value* use = alloc->input_use_list();
-         use != NULL;
-         use = next_use) {
-      next_use = use->next_use();
-      if (use->instruction()->IsMaterializeObject()) {
-        use->BindTo(MaterializationFor(alloc, use->instruction()));
-      }
-    }
-  }
-}
-
-
-// We transitively insert materializations at each deoptimization exit that
-// might see the given allocation (see ExitsCollector). Some of this
-// materializations are not actually used and some fail to compute because
-// they are inserted in the block that is not dominated by the allocation.
-// Remove them unused materializations from the graph.
-void AllocationSinking::RemoveUnusedMaterializations() {
-  intptr_t j = 0;
-  for (intptr_t i = 0; i < materializations_.length(); i++) {
-    MaterializeObjectInstr* mat = materializations_[i];
-    if ((mat->input_use_list() == NULL) && (mat->env_use_list() == NULL)) {
-      // Check if this materialization failed to compute and remove any
-      // unforwarded loads. There were no loads from any allocation sinking
-      // candidate in the beggining so it is safe to assume that any encountered
-      // load was inserted by CreateMaterializationAt.
-      for (intptr_t i = 0; i < mat->InputCount(); i++) {
-        LoadFieldInstr* load = mat->InputAt(i)->definition()->AsLoadField();
-        if ((load != NULL) &&
-            (load->instance()->definition() == mat->allocation())) {
-          load->ReplaceUsesWith(flow_graph_->constant_null());
-          load->RemoveFromGraph();
-        }
-      }
-      mat->RemoveFromGraph();
-    } else {
-      if (j != i) {
-        materializations_[j] = mat;
-      }
-      j++;
-    }
-  }
-  materializations_.TruncateTo(j);
-}
-
-
-// Some candidates might stop being eligible for allocation sinking after
-// the load forwarding because they flow into phis that load forwarding
-// inserts. Discover such allocations and remove them from the list
-// of allocation sinking candidates undoing all changes that we did
-// in preparation for sinking these allocations.
-void AllocationSinking::DiscoverFailedCandidates() {
-  // Transitively unmark all candidates that are not strictly valid.
-  bool changed;
-  do {
-    changed = false;
-    for (intptr_t i = 0; i < candidates_.length(); i++) {
-      Definition* alloc = candidates_[i];
-      if (alloc->Identity().IsAllocationSinkingCandidate()) {
-        if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) {
-          alloc->SetIdentity(AliasIdentity::Unknown());
-          changed = true;
-        }
-      }
-    }
-  } while (changed);
-
-  // Remove all failed candidates from the candidates list.
-  intptr_t j = 0;
-  for (intptr_t i = 0; i < candidates_.length(); i++) {
-    Definition* alloc = candidates_[i];
-    if (!alloc->Identity().IsAllocationSinkingCandidate()) {
-      if (FLAG_trace_optimization) {
-        THR_Print("allocation v%" Pd " can't be eliminated\n",
-                  alloc->ssa_temp_index());
-      }
-
-#ifdef DEBUG
-      for (Value* use = alloc->env_use_list();
-           use != NULL;
-           use = use->next_use()) {
-        ASSERT(use->instruction()->IsMaterializeObject());
-      }
-#endif
-
-      // All materializations will be removed from the graph. Remove inserted
-      // loads first and detach materializations from allocation's environment
-      // use list: we will reconstruct it when we start removing
-      // materializations.
-      alloc->set_env_use_list(NULL);
-      for (Value* use = alloc->input_use_list();
-           use != NULL;
-           use = use->next_use()) {
-        if (use->instruction()->IsLoadField()) {
-          LoadFieldInstr* load = use->instruction()->AsLoadField();
-          load->ReplaceUsesWith(flow_graph_->constant_null());
-          load->RemoveFromGraph();
-        } else {
-          ASSERT(use->instruction()->IsMaterializeObject() ||
-                 use->instruction()->IsPhi() ||
-                 use->instruction()->IsStoreInstanceField());
-        }
-      }
-    } else {
-      if (j != i) {
-        candidates_[j] = alloc;
-      }
-      j++;
-    }
-  }
-
-  if (j != candidates_.length()) {  // Something was removed from candidates.
-    intptr_t k = 0;
-    for (intptr_t i = 0; i < materializations_.length(); i++) {
-      MaterializeObjectInstr* mat = materializations_[i];
-      if (!mat->allocation()->Identity().IsAllocationSinkingCandidate()) {
-        // Restore environment uses of the allocation that were replaced
-        // by this materialization and drop materialization.
-        mat->ReplaceUsesWith(mat->allocation());
-        mat->RemoveFromGraph();
-      } else {
-        if (k != i) {
-          materializations_[k] = mat;
-        }
-        k++;
-      }
-    }
-    materializations_.TruncateTo(k);
-  }
-
-  candidates_.TruncateTo(j);
-}
-
-
-void AllocationSinking::Optimize() {
-  CollectCandidates();
-
-  // Insert MaterializeObject instructions that will describe the state of the
-  // object at all deoptimization points. Each inserted materialization looks
-  // like this (where v_0 is allocation that we are going to eliminate):
-  //   v_1     <- LoadField(v_0, field_1)
-  //           ...
-  //   v_N     <- LoadField(v_0, field_N)
-  //   v_{N+1} <- MaterializeObject(field_1 = v_1, ..., field_N = v_{N})
-  for (intptr_t i = 0; i < candidates_.length(); i++) {
-    InsertMaterializations(candidates_[i]);
-  }
-
-  // Run load forwarding to eliminate LoadField instructions inserted above.
-  // All loads will be successfully eliminated because:
-  //   a) they use fields (not offsets) and thus provide precise aliasing
-  //      information
-  //   b) candidate does not escape and thus its fields is not affected by
-  //      external effects from calls.
-  LoadOptimizer::OptimizeGraph(flow_graph_);
-
-  NormalizeMaterializations();
-
-  RemoveUnusedMaterializations();
-
-  // If any candidates are no longer eligible for allocation sinking abort
-  // the optimization for them and undo any changes we did in preparation.
-  DiscoverFailedCandidates();
-
-  // At this point we have computed the state of object at each deoptimization
-  // point and we can eliminate it. Loads inserted above were forwarded so there
-  // are no uses of the allocation just as in the begging of the pass.
-  for (intptr_t i = 0; i < candidates_.length(); i++) {
-    EliminateAllocation(candidates_[i]);
-  }
-
-  // Process materializations and unbox their arguments: materializations
-  // are part of the environment and can materialize boxes for double/mint/simd
-  // values when needed.
-  // TODO(vegorov): handle all box types here.
-  for (intptr_t i = 0; i < materializations_.length(); i++) {
-    MaterializeObjectInstr* mat = materializations_[i];
-    for (intptr_t j = 0; j < mat->InputCount(); j++) {
-      Definition* defn = mat->InputAt(j)->definition();
-      if (defn->IsBox()) {
-        mat->InputAt(j)->BindTo(defn->InputAt(0)->definition());
-      }
-    }
-  }
-}
-
-
-// Remove materializations from the graph. Register allocator will treat them
-// as part of the environment not as a real instruction.
-void AllocationSinking::DetachMaterializations() {
-  for (intptr_t i = 0; i < materializations_.length(); i++) {
-    materializations_[i]->previous()->LinkTo(materializations_[i]->next());
-  }
-}
-
-
-// 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) {
-  for (intptr_t i = 0; i < slots->length(); i++) {
-    if ((*slots)[i]->raw() == slot.raw()) {
-      return false;
-    }
-  }
-  slots->Add(&slot);
-  return true;
-}
-
-
-// Find deoptimization exit for the given materialization assuming that all
-// materializations are emitted right before the instruction which is a
-// deoptimization exit.
-static Instruction* ExitForMaterialization(MaterializeObjectInstr* mat) {
-  while (mat->next()->IsMaterializeObject()) {
-    mat = mat->next()->AsMaterializeObject();
-  }
-  return mat->next();
-}
-
-
-// Given the deoptimization exit find first materialization that was inserted
-// before it.
-static Instruction* FirstMaterializationAt(Instruction* exit) {
-  while (exit->previous()->IsMaterializeObject()) {
-    exit = exit->previous();
-  }
-  return exit;
-}
-
-
-// Given the allocation and deoptimization exit try to find MaterializeObject
-// instruction corresponding to this allocation at this exit.
-MaterializeObjectInstr* AllocationSinking::MaterializationFor(
-    Definition* alloc, Instruction* exit) {
-  if (exit->IsMaterializeObject()) {
-    exit = ExitForMaterialization(exit->AsMaterializeObject());
-  }
-
-  for (MaterializeObjectInstr* mat = exit->previous()->AsMaterializeObject();
-       mat != NULL;
-       mat = mat->previous()->AsMaterializeObject()) {
-    if (mat->allocation() == alloc) {
-      return mat;
-    }
-  }
-
-  return NULL;
-}
-
-
-// Insert MaterializeObject instruction for the given allocation before
-// the given instruction that can deoptimize.
-void AllocationSinking::CreateMaterializationAt(
-    Instruction* exit,
-    Definition* alloc,
-    const ZoneGrowableArray<const Object*>& slots) {
-  ZoneGrowableArray<Value*>* values =
-      new(Z) ZoneGrowableArray<Value*>(slots.length());
-
-  // All loads should be inserted before the first materialization so that
-  // IR follows the following pattern: loads, materializations, deoptimizing
-  // instruction.
-  Instruction* load_point = FirstMaterializationAt(exit);
-
-  // Insert load instruction for every field.
-  for (intptr_t i = 0; i < slots.length(); i++) {
-    LoadFieldInstr* load = slots[i]->IsField()
-        ? new(Z) LoadFieldInstr(
-            new(Z) Value(alloc),
-            &Field::Cast(*slots[i]),
-            AbstractType::ZoneHandle(Z),
-            alloc->token_pos())
-        : new(Z) LoadFieldInstr(
-            new(Z) Value(alloc),
-            Smi::Cast(*slots[i]).Value(),
-            AbstractType::ZoneHandle(Z),
-            alloc->token_pos());
-    flow_graph_->InsertBefore(
-        load_point, load, NULL, FlowGraph::kValue);
-    values->Add(new(Z) Value(load));
-  }
-
-  MaterializeObjectInstr* mat = NULL;
-  if (alloc->IsAllocateObject()) {
-    mat = new(Z) MaterializeObjectInstr(
-        alloc->AsAllocateObject(), slots, values);
-  } else {
-    ASSERT(alloc->IsAllocateUninitializedContext());
-    mat = new(Z) MaterializeObjectInstr(
-        alloc->AsAllocateUninitializedContext(), slots, values);
-  }
-
-  flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue);
-
-  // Replace all mentions of this allocation with a newly inserted
-  // MaterializeObject instruction.
-  // We must preserve the identity: all mentions are replaced by the same
-  // materialization.
-  for (Environment::DeepIterator env_it(exit->env());
-       !env_it.Done();
-       env_it.Advance()) {
-    Value* use = env_it.CurrentValue();
-    if (use->definition() == alloc) {
-      use->RemoveFromUseList();
-      use->set_definition(mat);
-      mat->AddEnvUse(use);
-    }
-  }
-
-  // Mark MaterializeObject as an environment use of this allocation.
-  // This will allow us to discover it when we are looking for deoptimization
-  // exits for another allocation that potentially flows into this one.
-  Value* val = new(Z) Value(alloc);
-  val->set_instruction(mat);
-  alloc->AddEnvUse(val);
-
-  // Record inserted materialization.
-  materializations_.Add(mat);
-}
-
-
-// Add given instruction to the list of the instructions if it is not yet
-// present there.
-template<typename T>
-void AddInstruction(GrowableArray<T*>* list, T* value) {
-  ASSERT(!value->IsGraphEntry());
-  for (intptr_t i = 0; i < list->length(); i++) {
-    if ((*list)[i] == value) {
-      return;
-    }
-  }
-  list->Add(value);
-}
-
-
-// Transitively collect all deoptimization exits that might need this allocation
-// rematerialized. It is not enough to collect only environment uses of this
-// allocation because it can flow into other objects that will be
-// dematerialized and that are referenced by deopt environments that
-// don't contain this allocation explicitly.
-void AllocationSinking::ExitsCollector::Collect(Definition* alloc) {
-  for (Value* use = alloc->env_use_list();
-       use != NULL;
-       use = use->next_use()) {
-    if (use->instruction()->IsMaterializeObject()) {
-      AddInstruction(&exits_, ExitForMaterialization(
-          use->instruction()->AsMaterializeObject()));
-    } else {
-      AddInstruction(&exits_, use->instruction());
-    }
-  }
-
-  // Check if this allocation is stored into any other allocation sinking
-  // candidate and put it on worklist so that we conservatively collect all
-  // exits for that candidate as well because they potentially might see
-  // this object.
-  for (Value* use = alloc->input_use_list();
-       use != NULL;
-       use = use->next_use()) {
-    Definition* obj = StoreInto(use);
-    if ((obj != NULL) && (obj != alloc)) {
-      AddInstruction(&worklist_, obj);
-    }
-  }
-}
-
-
-void AllocationSinking::ExitsCollector::CollectTransitively(Definition* alloc) {
-  exits_.TruncateTo(0);
-  worklist_.TruncateTo(0);
-
-  worklist_.Add(alloc);
-
-  // Note: worklist potentially will grow while we are iterating over it.
-  // We are not removing allocations from the worklist not to waste space on
-  // the side maintaining BitVector of already processed allocations: worklist
-  // is expected to be very small thus linear search in it is just as effecient
-  // as a bitvector.
-  for (intptr_t i = 0; i < worklist_.length(); i++) {
-    Collect(worklist_[i]);
-  }
-}
-
-
-void AllocationSinking::InsertMaterializations(Definition* alloc) {
-  // Collect all fields that are written for this instance.
-  ZoneGrowableArray<const Object*>* slots =
-      new(Z) ZoneGrowableArray<const Object*>(5);
-
-  for (Value* use = alloc->input_use_list();
-       use != NULL;
-       use = use->next_use()) {
-    StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
-    if ((store != NULL) && (store->instance()->definition() == alloc)) {
-      if (!store->field().IsNull()) {
-        AddSlot(slots, store->field());
-      } else {
-        AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(store->offset_in_bytes())));
-      }
-    }
-  }
-
-  if (alloc->ArgumentCount() > 0) {
-    AllocateObjectInstr* alloc_object = alloc->AsAllocateObject();
-    ASSERT(alloc_object->ArgumentCount() == 1);
-    intptr_t type_args_offset =
-        alloc_object->cls().type_arguments_field_offset();
-    AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(type_args_offset)));
-  }
-
-  // Collect all instructions that mention this object in the environment.
-  exits_collector_.CollectTransitively(alloc);
-
-  // Insert materializations at environment uses.
-  for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) {
-    CreateMaterializationAt(
-        exits_collector_.exits()[i], alloc, *slots);
-  }
-}
-
-
-}  // namespace dart
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
deleted file mode 100644
index 9d500aa..0000000
--- a/runtime/vm/flow_graph_optimizer.h
+++ /dev/null
@@ -1,456 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef VM_FLOW_GRAPH_OPTIMIZER_H_
-#define VM_FLOW_GRAPH_OPTIMIZER_H_
-
-#include "vm/intermediate_language.h"
-#include "vm/flow_graph.h"
-
-namespace dart {
-
-class CSEInstructionMap;
-template <typename T> class GrowableArray;
-class ParsedFunction;
-
-class FlowGraphOptimizer : public FlowGraphVisitor {
- public:
-  FlowGraphOptimizer(
-      FlowGraph* flow_graph,
-      bool use_speculative_inlining,
-      GrowableArray<intptr_t>* inlining_black_list)
-      : FlowGraphVisitor(flow_graph->reverse_postorder()),
-        flow_graph_(flow_graph),
-        use_speculative_inlining_(use_speculative_inlining),
-        inlining_black_list_(inlining_black_list) {
-    ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
-  }
-  virtual ~FlowGraphOptimizer() {}
-
-  FlowGraph* flow_graph() const { return flow_graph_; }
-
-  // Add ICData to InstanceCalls, so that optimizations can be run on them.
-  // TODO(srdjan): StaticCals as well?
-  void PopulateWithICData();
-
-  // Use ICData to optimize, replace or eliminate instructions.
-  void ApplyICData();
-
-  // Use propagated class ids to optimize, replace or eliminate instructions.
-  void ApplyClassIds();
-
-  // 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.
-  // Merge instructions (only per basic-block).
-  void TryOptimizePatterns();
-
-  // Returns true if any instructions were canonicalized away.
-  bool Canonicalize();
-
-  void EliminateDeadPhis();
-
-  void SelectRepresentations();
-
-  void WidenSmiToInt32();
-
-  void InferIntRanges();
-
-  void SelectIntegerInstructions();
-
-  void AnalyzeTryCatch();
-
-  bool TryInlineRecognizedMethod(intptr_t receiver_cid,
-                                 const Function& target,
-                                 Instruction* call,
-                                 Definition* receiver,
-                                 intptr_t token_pos,
-                                 const ICData& ic_data,
-                                 TargetEntryInstr** entry,
-                                 Definition** last);
-
-  // Remove environments from the instructions which do not deoptimize.
-  void EliminateEnvironments();
-
-  virtual void VisitStaticCall(StaticCallInstr* instr);
-  virtual void VisitInstanceCall(InstanceCallInstr* instr);
-  virtual void VisitStoreInstanceField(StoreInstanceFieldInstr* instr);
-  virtual void VisitAllocateContext(AllocateContextInstr* instr);
-  virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr* instr);
-
-  void InsertBefore(Instruction* next,
-                    Instruction* instr,
-                    Environment* env,
-                    FlowGraph::UseKind use_kind) {
-    flow_graph_->InsertBefore(next, instr, env, use_kind);
-  }
-
- private:
-  // Attempt to build ICData for call using propagated class-ids.
-  bool TryCreateICData(InstanceCallInstr* call);
-  const ICData& TrySpecializeICData(const ICData& ic_data, intptr_t cid);
-
-  void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
-
-  bool TryReplaceWithIndexedOp(InstanceCallInstr* call);
-  bool InlineSetIndexed(MethodRecognizer::Kind kind,
-                        const Function& target,
-                        Instruction* call,
-                        Definition* receiver,
-                        intptr_t token_pos,
-                        const ICData& value_check,
-                        TargetEntryInstr** entry,
-                        Definition** last);
-  bool InlineGetIndexed(MethodRecognizer::Kind kind,
-                        Instruction* call,
-                        Definition* receiver,
-                        TargetEntryInstr** entry,
-                        Definition** last);
-  intptr_t PrepareInlineIndexedOp(Instruction* call,
-                                  intptr_t array_cid,
-                                  Definition** array,
-                                  Definition* index,
-                                  Instruction** cursor);
-
-
-  bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind);
-  bool TryReplaceWithUnaryOp(InstanceCallInstr* call, Token::Kind op_kind);
-
-  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 TryInlineInstanceSetter(InstanceCallInstr* call,
-                               const ICData& unary_ic_data,
-                               bool allow_check = true);
-
-  bool TryInlineInstanceMethod(InstanceCallInstr* call);
-  bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
-                                     MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat64x2Constructor(StaticCallInstr* call,
-                                     MethodRecognizer::Kind recognized_kind);
-  bool TryInlineInt32x4Constructor(StaticCallInstr* call,
-                                    MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat32x4Method(InstanceCallInstr* call,
-                                MethodRecognizer::Kind recognized_kind);
-  bool TryInlineFloat64x2Method(InstanceCallInstr* call,
-                                MethodRecognizer::Kind recognized_kind);
-  bool TryInlineInt32x4Method(InstanceCallInstr* call,
-                               MethodRecognizer::Kind recognized_kind);
-  void ReplaceWithInstanceOf(InstanceCallInstr* instr);
-  bool TypeCheckAsClassEquality(const AbstractType& type);
-  void ReplaceWithTypeCast(InstanceCallInstr* instr);
-
-  bool TryReplaceInstanceCallWithInline(InstanceCallInstr* call);
-
-  Definition* PrepareInlineStringIndexOp(Instruction* call,
-                                         intptr_t cid,
-                                         Definition* str,
-                                         Definition* index,
-                                         Instruction* cursor);
-
-  bool InlineStringCodeUnitAt(Instruction* call,
-                              intptr_t cid,
-                              TargetEntryInstr** entry,
-                              Definition** last);
-
-  bool InlineStringBaseCharAt(Instruction* call,
-                              intptr_t cid,
-                              TargetEntryInstr** entry,
-                              Definition** last);
-
-  bool InlineDoubleOp(Token::Kind op_kind,
-                      Instruction* call,
-                      TargetEntryInstr** entry,
-                      Definition** last);
-
-  bool InlineByteArrayBaseLoad(Instruction* call,
-                               Definition* receiver,
-                               intptr_t array_cid,
-                               intptr_t view_cid,
-                               const ICData& ic_data,
-                               TargetEntryInstr** entry,
-                               Definition** last);
-
-  bool InlineByteArrayBaseStore(const Function& target,
-                                Instruction* call,
-                                Definition* receiver,
-                                intptr_t array_cid,
-                                intptr_t view_cid,
-                                const ICData& ic_data,
-                                TargetEntryInstr** entry,
-                                Definition** last);
-
-  intptr_t PrepareInlineByteArrayBaseOp(Instruction* call,
-                                        intptr_t array_cid,
-                                        intptr_t view_cid,
-                                        Definition** array,
-                                        Definition* index,
-                                        Instruction** cursor);
-
-  // Insert a check of 'to_check' determined by 'unary_checks'.  If the
-  // check fails it will deoptimize to 'deopt_id' using the deoptimization
-  // environment 'deopt_environment'.  The check is inserted immediately
-  // before 'insert_before'.
-  void AddCheckClass(Definition* to_check,
-                     const ICData& unary_checks,
-                     intptr_t deopt_id,
-                     Environment* deopt_environment,
-                     Instruction* insert_before);
-  Instruction* GetCheckClass(Definition* to_check,
-                             const ICData& unary_checks,
-                             intptr_t deopt_id,
-                             intptr_t token_pos);
-
-  // Insert a Smi check if needed.
-  void AddCheckSmi(Definition* to_check,
-                   intptr_t deopt_id,
-                   Environment* deopt_environment,
-                   Instruction* insert_before);
-
-  // Add a class check for a call's first argument immediately before the
-  // call, using the call's IC data to determine the check, and the call's
-  // deopt ID and deoptimization environment if the check fails.
-  void AddReceiverCheck(InstanceCallInstr* call);
-
-  void ReplaceCall(Definition* call, Definition* replacement);
-
-  void InsertConversionsFor(Definition* def);
-
-  void ConvertUse(Value* use, Representation from);
-  void ConvertEnvironmentUse(Value* use, Representation from);
-
-  void InsertConversion(Representation from,
-                        Representation to,
-                        Value* use,
-                        bool is_environment_use);
-
-  bool InstanceCallNeedsClassCheck(InstanceCallInstr* call,
-                                   RawFunction::Kind kind) const;
-
-  bool InlineFloat32x4Getter(InstanceCallInstr* call,
-                             MethodRecognizer::Kind getter);
-  bool InlineFloat64x2Getter(InstanceCallInstr* call,
-                             MethodRecognizer::Kind getter);
-  bool InlineInt32x4Getter(InstanceCallInstr* call,
-                            MethodRecognizer::Kind getter);
-  bool InlineFloat32x4BinaryOp(InstanceCallInstr* call,
-                               Token::Kind op_kind);
-  bool InlineInt32x4BinaryOp(InstanceCallInstr* call,
-                              Token::Kind op_kind);
-  bool InlineFloat64x2BinaryOp(InstanceCallInstr* call,
-                               Token::Kind op_kind);
-  bool InlineImplicitInstanceGetter(InstanceCallInstr* call, bool allow_check);
-
-  RawBool* InstanceOfAsBool(const ICData& ic_data,
-                            const AbstractType& type,
-                            ZoneGrowableArray<intptr_t>* results) const;
-
-  void ReplaceWithMathCFunction(InstanceCallInstr* call,
-                                MethodRecognizer::Kind recognized_kind);
-
-  void OptimizeLeftShiftBitAndSmiOp(Definition* bit_and_instr,
-                                    Definition* left_instr,
-                                    Definition* right_instr);
-  void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
-  void TryMergeMathUnary(GrowableArray<MathUnaryInstr*>* merge_candidates);
-
-  void AppendLoadIndexedForMerged(Definition* instr, intptr_t ix, intptr_t cid);
-  void AppendExtractNthOutputForMerged(Definition* instr, intptr_t ix,
-                                       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(); }
-  Isolate* isolate() const { return flow_graph_->isolate(); }
-  Zone* zone() const { return flow_graph_->zone(); }
-
-  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);
-};
-
-
-// Loop invariant code motion.
-class LICM : public ValueObject {
- public:
-  explicit LICM(FlowGraph* flow_graph);
-
-  void Optimize();
-
-  void OptimisticallySpecializeSmiPhis();
-
- private:
-  FlowGraph* flow_graph() const { return flow_graph_; }
-
-  void Hoist(ForwardInstructionIterator* it,
-             BlockEntryInstr* pre_header,
-             Instruction* current);
-
-  void TrySpecializeSmiPhi(PhiInstr* phi,
-                           BlockEntryInstr* header,
-                           BlockEntryInstr* pre_header);
-
-  FlowGraph* const flow_graph_;
-};
-
-
-// A simple common subexpression elimination based
-// on the dominator tree.
-class DominatorBasedCSE : public AllStatic {
- public:
-  // Return true, if the optimization changed the flow graph.
-  // False, if nothing changed.
-  static bool Optimize(FlowGraph* graph);
-
- private:
-  static bool OptimizeRecursive(
-      FlowGraph* graph,
-      BlockEntryInstr* entry,
-      CSEInstructionMap* map);
-};
-
-
-class DeadStoreElimination : public AllStatic {
- public:
-  static void Optimize(FlowGraph* graph);
-};
-
-
-class DeadCodeElimination : public AllStatic {
- public:
-  static void EliminateDeadPhis(FlowGraph* graph);
-};
-
-
-// Rewrite branches to eliminate materialization of boolean values after
-// inlining, and to expose other optimizations (e.g., constant folding of
-// branches, unreachable code elimination).
-class BranchSimplifier : public AllStatic {
- public:
-  static void Simplify(FlowGraph* flow_graph);
-
-  // Replace a target entry instruction with a join entry instruction.  Does
-  // not update the original target's predecessors to point to the new block
-  // and does not replace the target in already computed block order lists.
-  static JoinEntryInstr* ToJoinEntry(Zone* zone,
-                                     TargetEntryInstr* target);
-
- private:
-  // Match an instance of the pattern to rewrite.  See the implementation
-  // for the patterns that are handled by this pass.
-  static bool Match(JoinEntryInstr* block);
-
-  // Duplicate a branch while replacing its comparison's left and right
-  // inputs.
-  static BranchInstr* CloneBranch(Zone* zone,
-                                  BranchInstr* branch,
-                                  Value* new_left,
-                                  Value* new_right);
-};
-
-
-// Rewrite diamond control flow patterns that materialize values to use more
-// efficient branchless code patterns if such are supported on the current
-// platform.
-class IfConverter : public AllStatic {
- public:
-  static void Simplify(FlowGraph* flow_graph);
-};
-
-
-class AllocationSinking : public ZoneAllocated {
- public:
-  explicit AllocationSinking(FlowGraph* flow_graph)
-      : flow_graph_(flow_graph),
-        candidates_(5),
-        materializations_(5) { }
-
-  const GrowableArray<Definition*>& candidates() const {
-    return candidates_;
-  }
-
-  // Find the materialization insterted for the given allocation
-  // at the given exit.
-  MaterializeObjectInstr* MaterializationFor(Definition* alloc,
-                                             Instruction* exit);
-
-  void Optimize();
-
-  void DetachMaterializations();
-
- private:
-  // Helper class to collect deoptimization exits that might need to
-  // rematerialize an object: that is either instructions that reference
-  // this object explicitly in their deoptimization environment or
-  // reference some other allocation sinking candidate that points to
-  // this object.
-  class ExitsCollector : public ValueObject {
-   public:
-    ExitsCollector() : exits_(10), worklist_(3) { }
-
-    const GrowableArray<Instruction*>& exits() const { return exits_; }
-
-    void CollectTransitively(Definition* alloc);
-
-   private:
-    // Collect immediate uses of this object in the environments.
-    // If this object is stored into other allocation sinking candidates
-    // put them onto worklist so that CollectTransitively will process them.
-    void Collect(Definition* alloc);
-
-    GrowableArray<Instruction*> exits_;
-    GrowableArray<Definition*> worklist_;
-  };
-
-  void CollectCandidates();
-
-  void NormalizeMaterializations();
-
-  void RemoveUnusedMaterializations();
-
-  void DiscoverFailedCandidates();
-
-  void InsertMaterializations(Definition* alloc);
-
-  void CreateMaterializationAt(
-      Instruction* exit,
-      Definition* alloc,
-      const ZoneGrowableArray<const Object*>& fields);
-
-  void EliminateAllocation(Definition* alloc);
-
-  Isolate* isolate() const { return flow_graph_->isolate(); }
-  Zone* zone() const { return flow_graph_->zone(); }
-
-  FlowGraph* flow_graph_;
-
-  GrowableArray<Definition*> candidates_;
-  GrowableArray<MaterializeObjectInstr*> materializations_;
-
-  ExitsCollector exits_collector_;
-};
-
-
-// Optimize spill stores inside try-blocks by identifying values that always
-// contain a single known constant at catch block entry.
-class TryCatchAnalyzer : public AllStatic {
- public:
-  static void Optimize(FlowGraph* flow_graph);
-};
-
-}  // namespace dart
-
-#endif  // VM_FLOW_GRAPH_OPTIMIZER_H_
diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
index 16cf90c..18eaa36 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -5,7 +5,6 @@
 #include "vm/flow_graph_range_analysis.h"
 
 #include "vm/bit_vector.h"
-#include "vm/compiler.h"
 #include "vm/il_printer.h"
 
 namespace dart {
@@ -184,7 +183,7 @@
 
         InductionVariableInfo* info = DetectSimpleInductionVariable(current);
         if (info != NULL) {
-          if (FLAG_trace_range_analysis) {
+          if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
             THR_Print("Simple loop variable: %s bound <%s>\n",
                        current->ToCString(),
                        info->limit() != NULL ?
@@ -694,7 +693,7 @@
     }
 
     if (!range.Equals(defn->range())) {
-      if (FLAG_trace_range_analysis) {
+      if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
         THR_Print("%c [%" Pd "] %s:  %s => %s\n",
                   OpPrefix(op),
                   iteration,
@@ -997,7 +996,7 @@
         ConstructUpperBound(check->index()->definition(), check);
     if (upper_bound == UnwrapConstraint(check->index()->definition())) {
       // Unable to construct upper bound for the index.
-      if (FLAG_trace_range_analysis) {
+      if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
         THR_Print("Failed to construct upper bound for %s index\n",
                   check->ToCString());
       }
@@ -1008,7 +1007,7 @@
     // together. This will expose more redundancies when we are going to emit
     // upper bound through scheduler.
     if (!Simplify(&upper_bound, NULL)) {
-      if (FLAG_trace_range_analysis) {
+      if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
         THR_Print("Failed to simplify upper bound for %s index\n",
                   check->ToCString());
       }
@@ -1023,7 +1022,7 @@
     // range give up on generalization for simplicity.
     GrowableArray<Definition*> non_positive_symbols;
     if (!FindNonPositiveSymbols(&non_positive_symbols, upper_bound)) {
-      if (FLAG_trace_range_analysis) {
+      if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
         THR_Print("Failed to generalize %s index to %s"
                   " (can't ensure positivity)\n",
                   check->ToCString(),
@@ -1057,7 +1056,7 @@
     if (!RangeUtils::IsPositive(lower_bound->range())) {
       // Can't prove that lower bound is positive even with additional checks
       // against potentially non-positive symbols. Give up.
-      if (FLAG_trace_range_analysis) {
+      if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
         THR_Print("Failed to generalize %s index to %s"
                   " (lower bound is not positive)\n",
                   check->ToCString(),
@@ -1066,7 +1065,7 @@
       return;
     }
 
-    if (FLAG_trace_range_analysis) {
+    if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
       THR_Print("For %s computed index bounds [%s, %s]\n",
                 check->ToCString(),
                 IndexBoundToCString(lower_bound),
@@ -1534,7 +1533,7 @@
     // optimistic hoisting of checks possible)
     const bool try_generalization =
         function.allows_bounds_check_generalization() &&
-        !Compiler::always_optimize();
+        !FLAG_precompiled_mode;
 
     BoundsCheckGeneralizer generalizer(this, flow_graph_);
 
@@ -1673,7 +1672,7 @@
   FindUint32NarrowingDefinitions();
   Propagate();
   ReplaceInstructions();
-  if (FLAG_trace_integer_ir_selection) {
+  if (FLAG_support_il_printer && FLAG_trace_integer_ir_selection) {
     THR_Print("---- after integer ir selection -------\n");
     FlowGraphPrinter printer(*flow_graph_);
     printer.PrintBlocks();
@@ -1710,7 +1709,7 @@
       Definition* defn = current->AsDefinition();
       if ((defn != NULL) && defn->HasSSATemp()) {
         if (IsPotentialUint32Definition(defn)) {
-          if (FLAG_trace_integer_ir_selection) {
+          if (FLAG_support_il_printer && FLAG_trace_integer_ir_selection) {
            THR_Print("Adding %s\n", current->ToCString());
           }
           potential_uint32_defs_.Add(defn);
@@ -1751,7 +1750,7 @@
   for (intptr_t i = 0; i < potential_uint32_defs_.length(); i++) {
     Definition* defn = potential_uint32_defs_[i];
     if (IsUint32NarrowingDefinition(defn)) {
-      if (FLAG_trace_integer_ir_selection) {
+      if (FLAG_support_il_printer && FLAG_trace_integer_ir_selection) {
         THR_Print("Adding %s\n", defn->ToCString());
       }
       selected_uint32_defs_->Add(defn->ssa_temp_index());
@@ -1826,7 +1825,7 @@
         continue;
       }
       if (CanBecomeUint32(defn)) {
-        if (FLAG_trace_integer_ir_selection) {
+        if (FLAG_support_il_printer && FLAG_trace_integer_ir_selection) {
           THR_Print("Adding %s\n", defn->ToCString());
         }
         // Found a new candidate.
@@ -1894,7 +1893,7 @@
     }
     Definition* replacement = ConstructReplacementFor(defn);
     ASSERT(replacement != NULL);
-    if (FLAG_trace_integer_ir_selection) {
+    if (FLAG_support_il_printer && FLAG_trace_integer_ir_selection) {
       THR_Print("Replacing %s with %s\n", defn->ToCString(),
                                           replacement->ToCString());
     }
diff --git a/runtime/vm/flow_graph_range_analysis_test.cc b/runtime/vm/flow_graph_range_analysis_test.cc
index 308b1ce..8f91943 100644
--- a/runtime/vm/flow_graph_range_analysis_test.cc
+++ b/runtime/vm/flow_graph_range_analysis_test.cc
@@ -7,7 +7,6 @@
 
 namespace dart {
 
-
 TEST_CASE(RangeTests) {
   Range* zero = new Range(
       RangeBoundary::FromConstant(0),
@@ -43,9 +42,13 @@
     min = Clamp(min);                                                          \
     max = Clamp(max);                                                          \
     EXPECT(min.Equals(res_min));                                               \
-    if (!min.Equals(res_min)) OS::Print("%s\n", min.ToCString());              \
+    if (FLAG_support_il_printer && !min.Equals(res_min)) {                     \
+      OS::Print("%s\n", min.ToCString());                                      \
+    }                                                                          \
     EXPECT(max.Equals(res_max));                                               \
-    if (!max.Equals(res_max)) OS::Print("%s\n", max.ToCString());              \
+    if (FLAG_support_il_printer && !max.Equals(res_max)) {                     \
+      OS::Print("%s\n", max.ToCString());                                      \
+    }                                                                          \
   }
 
 #define NO_CLAMP(b) (b)
@@ -327,11 +330,11 @@
     EXPECT(right_range->max().ConstantValue() == r_max);                       \
     Range::Add(left_range, right_range, &min, &max, NULL);                     \
     EXPECT(min.Equals(result_min));                                            \
-    if (!min.Equals(result_min)) {                                             \
+    if (FLAG_support_il_printer && !min.Equals(result_min)) {                  \
       OS::Print("%s != %s\n", min.ToCString(), result_min.ToCString());        \
     }                                                                          \
     EXPECT(max.Equals(result_max));                                            \
-    if (!max.Equals(result_max)) {                                             \
+    if (FLAG_support_il_printer && !max.Equals(result_max)) {                  \
       OS::Print("%s != %s\n", max.ToCString(), result_max.ToCString());        \
     }                                                                          \
   }
@@ -422,11 +425,11 @@
     EXPECT(right_range->max().ConstantValue() == r_max);                       \
     Range::Sub(left_range, right_range, &min, &max, NULL);                     \
     EXPECT(min.Equals(result_min));                                            \
-    if (!min.Equals(result_min)) {                                             \
+    if (FLAG_support_il_printer && !min.Equals(result_min)) {                  \
       OS::Print("%s != %s\n", min.ToCString(), result_min.ToCString());        \
     }                                                                          \
     EXPECT(max.Equals(result_max));                                            \
-    if (!max.Equals(result_max)) {                                             \
+    if (FLAG_support_il_printer && !max.Equals(result_max)) {                  \
       OS::Print("%s != %s\n", max.ToCString(), result_max.ToCString());        \
     }                                                                          \
   }
@@ -485,11 +488,11 @@
     EXPECT(right_range->max().ConstantValue() == r_max);                       \
     Range::And(left_range, right_range, &min, &max);                           \
     EXPECT(min.Equals(result_min));                                            \
-    if (!min.Equals(result_min)) {                                             \
+    if (FLAG_support_il_printer && !min.Equals(result_min)) {                  \
       OS::Print("%s != %s\n", min.ToCString(), result_min.ToCString());        \
     }                                                                          \
     EXPECT(max.Equals(result_max));                                            \
-    if (!max.Equals(result_max)) {                                             \
+    if (FLAG_support_il_printer && !max.Equals(result_max)) {                  \
       OS::Print("%s != %s\n", max.ToCString(), result_max.ToCString());        \
     }                                                                          \
   }
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 7ea528a..df32f54 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -15,18 +15,17 @@
             "Trace flow graph type propagation");
 
 DECLARE_FLAG(bool, propagate_types);
-DECLARE_FLAG(bool, trace_cha);
-DECLARE_FLAG(bool, use_cha_deopt);
-DECLARE_FLAG(bool, fields_may_be_reset);
 
 
 void FlowGraphTypePropagator::Propagate(FlowGraph* flow_graph) {
+#ifndef PRODUCT
   Thread* thread = flow_graph->thread();
   Isolate* const isolate = flow_graph->isolate();
   TimelineStream* compiler_timeline = isolate->GetCompilerStream();
   TimelineDurationScope tds2(thread,
                              compiler_timeline,
                              "FlowGraphTypePropagator");
+#endif  // !PRODUCT
   FlowGraphTypePropagator propagator(flow_graph);
   propagator.Propagate();
 }
@@ -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++) {
@@ -80,13 +79,13 @@
   // definitions.
   while (!worklist_.is_empty()) {
     Definition* def = RemoveLastFromWorklist();
-    if (FLAG_trace_type_propagation) {
+    if (FLAG_support_il_printer && FLAG_trace_type_propagation) {
       THR_Print("recomputing type of v%" Pd ": %s\n",
                 def->ssa_temp_index(),
                 def->Type()->ToCString());
     }
     if (def->RecomputeType()) {
-      if (FLAG_trace_type_propagation) {
+      if (FLAG_support_il_printer && FLAG_trace_type_propagation) {
         THR_Print("  ... new type %s\n", def->Type()->ToCString());
       }
       for (Value::Iterator it(def->input_use_list());
@@ -128,7 +127,7 @@
 
   const intptr_t rollback_point = rollback_.length();
 
-  if (Isolate::Current()->flags().type_checks()) {
+  if (Isolate::Current()->type_checks()) {
     StrengthenAsserts(block);
   }
 
@@ -216,7 +215,7 @@
   CompileType* type = TypeOf(value->definition());
   value->SetReachingType(type);
 
-  if (FLAG_trace_type_propagation) {
+  if (FLAG_support_il_printer && FLAG_trace_type_propagation) {
     THR_Print("reaching type to v%" Pd " for v%" Pd " is %s\n",
               value->instruction()->IsDefinition() ?
                   value->instruction()->AsDefinition()->ssa_temp_index() : -1,
@@ -412,10 +411,11 @@
 
   const AbstractType* compile_type = ToAbstractType();
   const AbstractType* other_compile_type = other->ToAbstractType();
-  if (compile_type->IsMoreSpecificThan(*other_compile_type, NULL, Heap::kOld)) {
+  if (compile_type->IsMoreSpecificThan(
+          *other_compile_type, NULL, NULL, Heap::kOld)) {
     type_ = other_compile_type;
   } else if (other_compile_type->
-      IsMoreSpecificThan(*compile_type, NULL, Heap::kOld)) {
+      IsMoreSpecificThan(*compile_type, NULL, NULL, Heap::kOld)) {
   // Nothing to do.
   } else {
   // Can't unify.
@@ -489,15 +489,15 @@
       cid_ = kDynamicCid;
     } else if (type_->IsVoidType()) {
       cid_ = kNullCid;
+    } else if (type_->IsFunctionType() || type_->IsDartFunctionType()) {
+      cid_ = kClosureCid;
     } else if (type_->HasResolvedTypeClass()) {
       const Class& type_class = Class::Handle(type_->type_class());
       Thread* thread = Thread::Current();
       CHA* cha = thread->cha();
-      // Don't infer a cid from an abstract type for signature classes since
-      // there can be multiple compatible classes with different cids.
-      if (!type_class.IsSignatureClass() &&
-          !CHA::IsImplemented(type_class) &&
-          !CHA::HasSubclasses(type_class)) {
+      // Don't infer a cid from an abstract type since there can be multiple
+      // compatible classes with different cids.
+      if (!CHA::IsImplemented(type_class) && !CHA::HasSubclasses(type_class)) {
         if (type_class.IsPrivate()) {
           // Type of a private class cannot change through later loaded libs.
           cid_ = type_class.id();
@@ -618,7 +618,7 @@
     return false;
   }
 
-  *is_instance = compile_type.IsMoreSpecificThan(type, NULL, Heap::kOld);
+  *is_instance = compile_type.IsMoreSpecificThan(type, NULL, NULL, Heap::kOld);
   return *is_instance;
 }
 
@@ -633,7 +633,7 @@
     return IsNull();
   }
 
-  return ToAbstractType()->IsMoreSpecificThan(other, NULL, Heap::kOld);
+  return ToAbstractType()->IsMoreSpecificThan(other, NULL, NULL, Heap::kOld);
 }
 
 
@@ -655,7 +655,7 @@
 bool PhiInstr::RecomputeType() {
   CompileType result = CompileType::None();
   for (intptr_t i = 0; i < InputCount(); i++) {
-    if (FLAG_trace_type_propagation) {
+    if (FLAG_support_il_printer && FLAG_trace_type_propagation) {
       THR_Print("  phi %" Pd " input %" Pd ": v%" Pd " has reaching type %s\n",
                 ssa_temp_index(),
                 i,
@@ -890,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 =
@@ -905,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();
@@ -949,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());
   }
@@ -978,10 +978,11 @@
 
 CompileType AllocateObjectInstr::ComputeType() const {
   if (!closure_function().IsNull()) {
-    ASSERT(cls().raw() == closure_function().signature_class());
+    ASSERT(cls().id() == kClosureCid);
     return CompileType(CompileType::kNonNullable,
-                       cls().id(),
-                       &Type::ZoneHandle(cls().SignatureType()));
+                       kClosureCid,
+                       &FunctionType::ZoneHandle(
+                           closure_function().SignatureType()));
   }
   // TODO(vegorov): Incorporate type arguments into the returned type.
   return CompileType::FromCid(cls().id());
@@ -1007,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/gc_marker.cc b/runtime/vm/gc_marker.cc
index 1638b3d..c9ac9fa 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -485,7 +485,7 @@
   if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) {
     (isolate->gc_prologue_callback())();
   }
-  isolate->thread_registry()->PrepareForGC();
+  isolate->PrepareForGC();
   // The store buffers will be rebuilt as part of marking, reset them now.
   isolate->store_buffer()->Reset();
 }
@@ -562,6 +562,9 @@
 
 
 void GCMarker::ProcessObjectIdTable(Isolate* isolate) {
+  if (!FLAG_support_service) {
+    return;
+  }
   ObjectIdRingClearPointerVisitor visitor(isolate);
   ObjectIdRing* ring = isolate->object_id_ring();
   ASSERT(ring != NULL);
@@ -710,7 +713,9 @@
       // All marking done; detach code, etc.
       FinalizeResultsFrom(&mark);
     } else {
-      ThreadBarrier barrier(num_tasks + 1);
+      ThreadBarrier barrier(num_tasks + 1,
+                            heap_->barrier(),
+                            heap_->barrier_done());
       // Used to coordinate draining among tasks; all start out as 'busy'.
       uintptr_t num_busy = num_tasks;
       // Phase 1: Iterate over roots and drain marking stack in tasks.
diff --git a/runtime/vm/gc_sweeper.cc b/runtime/vm/gc_sweeper.cc
index a192138..0dcf62f 100644
--- a/runtime/vm/gc_sweeper.cc
+++ b/runtime/vm/gc_sweeper.cc
@@ -9,8 +9,8 @@
 #include "vm/heap.h"
 #include "vm/lockers.h"
 #include "vm/pages.h"
+#include "vm/safepoint.h"
 #include "vm/thread_pool.h"
-#include "vm/thread_registry.h"
 
 namespace dart {
 
@@ -116,13 +116,14 @@
   virtual void Run() {
     bool result = Thread::EnterIsolateAsHelper(task_isolate_);
     ASSERT(result);
+    Thread* thread = Thread::Current();
     GCSweeper sweeper;
 
     HeapPage* page = first_;
     HeapPage* prev_page = NULL;
 
     while (page != NULL) {
-      task_isolate_->thread_registry()->CheckSafepoint();
+      thread->CheckForSafepoint();
       HeapPage* next_page = page->next();
       ASSERT(page->type() == HeapPage::kData);
       bool page_in_use = sweeper.SweepPage(page, freelist_, false);
diff --git a/runtime/vm/gdbjit_android.cc b/runtime/vm/gdbjit_android.cc
deleted file mode 100644
index 1141fbf..0000000
--- a/runtime/vm/gdbjit_android.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/globals.h"
-#if defined(TARGET_OS_ANDROID)
-
-#include <stdint.h>  // NOLINT
-#include <stdio.h>  // NOLINT
-#include <stdlib.h>  // NOLINT
-
-#include "vm/gdbjit_android.h"
-
-extern "C" {
-  typedef enum {
-    JIT_NOACTION = 0,
-    JIT_REGISTER_FN,
-    JIT_UNREGISTER_FN
-  } jit_actions_t;
-
-  struct jit_code_entry {
-    struct jit_code_entry* next_entry;
-    struct jit_code_entry* prev_entry;
-    const char* symfile_addr;
-    uint64_t symfile_size;
-  };
-
-  struct jit_descriptor {
-    uint32_t version;
-    /* This type should be jit_actions_t, but we use uint32_t
-       to be explicit about the bitwidth.  */
-    uint32_t action_flag;
-    struct jit_code_entry* relevant_entry;
-    struct jit_code_entry* first_entry;
-  };
-
-#ifndef GDB_JIT_SYMBOLS
-  /* GDB puts a breakpoint in this function.  */
-  void __attribute__((noinline)) __jit_debug_register_code() { }
-
-  /* Make sure to specify the version statically, because the
-     debugger may check the version before we can set it.  */
-  struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
-#endif
-
-  static struct jit_code_entry* first_dynamic_region = NULL;
-  static struct jit_code_entry* last_dynamic_region = NULL;
-
-  void addDynamicSection(const char* symfile_addr, uint64_t symfile_size) {
-    jit_code_entry* new_entry = reinterpret_cast<jit_code_entry*>(
-        malloc(sizeof(jit_code_entry)));
-    if (new_entry != NULL) {
-      new_entry->symfile_addr = symfile_addr;
-      new_entry->symfile_size = symfile_size;
-      new_entry->next_entry = NULL;
-      new_entry->prev_entry = last_dynamic_region;
-      if (first_dynamic_region == NULL) {
-        first_dynamic_region = new_entry;
-      } else {
-        last_dynamic_region->next_entry = new_entry;
-      }
-      last_dynamic_region = new_entry;
-    }
-    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
-    __jit_debug_descriptor.relevant_entry = new_entry;
-    __jit_debug_descriptor.first_entry = first_dynamic_region;
-    __jit_debug_register_code();
-  }
-
-  void deleteDynamicSections() {
-    struct jit_code_entry* iterator = last_dynamic_region;
-    while (iterator != NULL) {
-      __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
-      __jit_debug_descriptor.relevant_entry = iterator;
-      __jit_debug_descriptor.first_entry = first_dynamic_region;
-      __jit_debug_register_code();
-      iterator = iterator->prev_entry;
-    }
-    first_dynamic_region = NULL;
-    last_dynamic_region = NULL;
-  }
-};
-
-#endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/gdbjit_android.h b/runtime/vm/gdbjit_android.h
deleted file mode 100644
index f2cd1ba..0000000
--- a/runtime/vm/gdbjit_android.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef VM_GDBJIT_ANDROID_H_
-#define VM_GDBJIT_ANDROID_H_
-
-#include <stdint.h>
-
-extern "C" {
-  void addDynamicSection(const char* symfile_addr, uint64_t symfile_size);
-  void deleteDynamicSections();
-};
-
-#endif  // VM_GDBJIT_ANDROID_H_
diff --git a/runtime/vm/gdbjit_linux.cc b/runtime/vm/gdbjit_linux.cc
deleted file mode 100644
index 9e06b85..0000000
--- a/runtime/vm/gdbjit_linux.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/globals.h"
-#if defined(TARGET_OS_LINUX)
-
-#include <stdint.h>  // NOLINT
-#include <stdio.h>  // NOLINT
-#include <stdlib.h>  // NOLINT
-
-#include "vm/gdbjit_linux.h"
-
-extern "C" {
-  typedef enum {
-    JIT_NOACTION = 0,
-    JIT_REGISTER_FN,
-    JIT_UNREGISTER_FN
-  } jit_actions_t;
-
-  struct jit_code_entry {
-    struct jit_code_entry* next_entry;
-    struct jit_code_entry* prev_entry;
-    const char* symfile_addr;
-    uint64_t symfile_size;
-  };
-
-  struct jit_descriptor {
-    uint32_t version;
-    /* This type should be jit_actions_t, but we use uint32_t
-       to be explicit about the bitwidth.  */
-    uint32_t action_flag;
-    struct jit_code_entry* relevant_entry;
-    struct jit_code_entry* first_entry;
-  };
-
-#ifndef GDB_JIT_SYMBOLS
-  /* GDB puts a breakpoint in this function.  */
-  void __attribute__((noinline)) __jit_debug_register_code() { }
-
-  /* Make sure to specify the version statically, because the
-     debugger may check the version before we can set it.  */
-  struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
-#endif
-
-  static struct jit_code_entry* first_dynamic_region = NULL;
-  static struct jit_code_entry* last_dynamic_region = NULL;
-
-  void addDynamicSection(const char* symfile_addr, uint64_t symfile_size) {
-    jit_code_entry* new_entry = reinterpret_cast<jit_code_entry*>(
-        malloc(sizeof(jit_code_entry)));
-    if (new_entry != NULL) {
-      new_entry->symfile_addr = symfile_addr;
-      new_entry->symfile_size = symfile_size;
-      new_entry->next_entry = NULL;
-      new_entry->prev_entry = last_dynamic_region;
-      if (first_dynamic_region == NULL) {
-        first_dynamic_region = new_entry;
-      } else {
-        last_dynamic_region->next_entry = new_entry;
-      }
-      last_dynamic_region = new_entry;
-    }
-    __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
-    __jit_debug_descriptor.relevant_entry = new_entry;
-    __jit_debug_descriptor.first_entry = first_dynamic_region;
-    __jit_debug_register_code();
-  }
-
-  void deleteDynamicSections() {
-    struct jit_code_entry* iterator = last_dynamic_region;
-    while (iterator != NULL) {
-      __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
-      __jit_debug_descriptor.relevant_entry = iterator;
-      __jit_debug_descriptor.first_entry = first_dynamic_region;
-      __jit_debug_register_code();
-      iterator = iterator->prev_entry;
-    }
-    first_dynamic_region = NULL;
-    last_dynamic_region = NULL;
-  }
-};
-
-#endif  // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/gdbjit_linux.h b/runtime/vm/gdbjit_linux.h
deleted file mode 100644
index cf259f6..0000000
--- a/runtime/vm/gdbjit_linux.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef VM_GDBJIT_LINUX_H_
-#define VM_GDBJIT_LINUX_H_
-
-#include <stdint.h>
-
-extern "C" {
-  void addDynamicSection(const char* symfile_addr, uint64_t symfile_size);
-  void deleteDynamicSections();
-};
-
-#endif  // VM_GDBJIT_LINUX_H_
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index f5eef18..9fd69e2 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -15,7 +15,7 @@
 #undef PARITY_EVEN
 #undef PARITY_ODD
 #undef near
-#endif
+#endif  // defined(_WIN32)
 
 // The following #defines are invalidated.
 #undef OVERFLOW  // From math.h conflicts in constants_ia32.h
@@ -27,6 +27,11 @@
 const intptr_t kSmiMax = (static_cast<intptr_t>(1) << kSmiBits) - 1;
 const intptr_t kSmiMin =  -(static_cast<intptr_t>(1) << kSmiBits);
 
+// Hard coded from above but for 32-bit architectures.
+const intptr_t kSmiBits32 = kBitsPerInt32 - 2;
+const intptr_t kSmiMax32 = (static_cast<intptr_t>(1) << kSmiBits32) - 1;
+const intptr_t kSmiMin32 =  -(static_cast<intptr_t>(1) << kSmiBits32);
+
 #define kPosInfinity bit_cast<double>(DART_UINT64_C(0x7ff0000000000000))
 #define kNegInfinity bit_cast<double>(DART_UINT64_C(0xfff0000000000000))
 
diff --git a/runtime/vm/handles.cc b/runtime/vm/handles.cc
index 311bd98..bf2697a 100644
--- a/runtime/vm/handles.cc
+++ b/runtime/vm/handles.cc
@@ -18,12 +18,9 @@
 namespace dart {
 
 DEFINE_FLAG(bool, verify_handles, false, "Verify handles.");
-DEFINE_DEBUG_FLAG(bool, trace_handles,
-                  false, "Traces allocation of handles.");
 
 
 VMHandles::~VMHandles() {
-#ifdef DEBUG
     if (FLAG_trace_handles) {
       OS::PrintErr("***   Handle Counts for 0x(%" Px
                    "):Zone = %d,Scoped = %d\n",
@@ -32,7 +29,6 @@
       OS::PrintErr("*** Deleting VM handle block 0x%" Px "\n",
                    reinterpret_cast<intptr_t>(this));
     }
-#endif
 }
 
 
diff --git a/runtime/vm/handles.h b/runtime/vm/handles.h
index 5e07d6e..aab078c 100644
--- a/runtime/vm/handles.h
+++ b/runtime/vm/handles.h
@@ -61,7 +61,6 @@
 class Thread;
 
 DECLARE_FLAG(bool, verify_handles);
-DECLARE_DEBUG_FLAG(bool, trace_handles);
 
 class HandleVisitor {
  public:
@@ -257,12 +256,10 @@
   VMHandles() : Handles<kVMHandleSizeInWords,
                         kVMHandlesPerChunk,
                         kOffsetOfRawPtr>() {
-#ifdef DEBUG
     if (FLAG_trace_handles) {
       OS::PrintErr("*** Starting a new VM handle block 0x%" Px "\n",
                    reinterpret_cast<intptr_t>(this));
     }
-#endif
   }
   ~VMHandles();
 
diff --git a/runtime/vm/handles_impl.h b/runtime/vm/handles_impl.h
index ad005bb..635c2db 100644
--- a/runtime/vm/handles_impl.h
+++ b/runtime/vm/handles_impl.h
@@ -11,8 +11,6 @@
 
 namespace dart {
 
-DECLARE_DEBUG_FLAG(bool, trace_handles);
-
 template <int kHandleSizeInWords, int kHandlesPerChunk, int kOffsetOfRawPtr>
 void Handles<kHandleSizeInWords,
              kHandlesPerChunk,
@@ -176,13 +174,11 @@
 void Handles<kHandleSizeInWords,
              kHandlesPerChunk,
              kOffsetOfRawPtr>::SetupNextScopeBlock() {
-#if defined(DEBUG)
   if (FLAG_trace_handles) {
     OS::PrintErr("***   Handle Counts for (0x%" Px "):Zone = %d,Scoped = %d\n",
                  reinterpret_cast<intptr_t>(this),
                  CountZoneHandles(), CountScopedHandles());
   }
-#endif
   if (scoped_blocks_->next_block() == NULL) {
     scoped_blocks_->set_next_block(new HandlesBlock(NULL));
   }
@@ -231,13 +227,11 @@
 void Handles<kHandleSizeInWords,
              kHandlesPerChunk,
              kOffsetOfRawPtr>::SetupNextZoneBlock() {
-#if defined(DEBUG)
   if (FLAG_trace_handles) {
     OS::PrintErr("***   Handle Counts for (0x%" Px "):Zone = %d,Scoped = %d\n",
                  reinterpret_cast<intptr_t>(this),
                  CountZoneHandles(), CountScopedHandles());
   }
-#endif
   zone_blocks_ = new HandlesBlock(zone_blocks_);
   ASSERT(zone_blocks_ != NULL);
 }
diff --git a/runtime/vm/handles_test.cc b/runtime/vm/handles_test.cc
index b871f97..8a05fb7 100644
--- a/runtime/vm/handles_test.cc
+++ b/runtime/vm/handles_test.cc
@@ -12,9 +12,6 @@
 
 namespace dart {
 
-DECLARE_DEBUG_FLAG(bool, trace_handles);
-
-
 // Unit test for Zone handle allocation.
 TEST_CASE(AllocateZoneHandle) {
 #if defined(DEBUG)
diff --git a/runtime/vm/hash_table.h b/runtime/vm/hash_table.h
index 592cf07..c162232 100644
--- a/runtime/vm/hash_table.h
+++ b/runtime/vm/hash_table.h
@@ -99,7 +99,9 @@
         key_handle_(Object::Handle(zone_)),
         smi_handle_(Smi::Handle(zone_)),
         data_(&Array::Handle(zone_, data)),
-        released_data_(NULL) {}
+        released_data_(NULL) {
+    ASSERT(!data_->IsNull());
+  }
 
   // Returns the final table. The handle is cleared when this HashTable is
   // destroyed.
@@ -296,6 +298,7 @@
   }
 
   intptr_t GetSmiValueAt(intptr_t index) const {
+    ASSERT(!data_->IsNull());
     ASSERT(Object::Handle(zone(), data_->At(index)).IsSmi());
     return Smi::Value(Smi::RawCast(data_->At(index)));
   }
@@ -435,6 +438,13 @@
     return table.Release().raw();
   }
 
+  template<typename Table>
+  static RawArray* New(const Array& array) {
+    Table table(array.raw());
+    table.Initialize();
+    return table.Release().raw();
+  }
+
   // Clears 'to' and inserts all elements from 'from', in iteration order.
   // The tables must have the same user payload size.
   template<typename From, typename To>
@@ -682,7 +692,9 @@
 class UnorderedHashSet : public HashSet<UnorderedHashTable<KeyTraits, 0> > {
  public:
   typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet;
-  explicit UnorderedHashSet(RawArray* data) : BaseSet(data) {}
+  explicit UnorderedHashSet(RawArray* data) : BaseSet(data) {
+    ASSERT(data != Array::null());
+  }
   UnorderedHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {}
 };
 
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 10586bd..8950958 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -26,28 +26,13 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool, disable_alloc_stubs_after_gc, false, "Stress testing flag.");
-DEFINE_FLAG(bool, gc_at_alloc, false, "GC at every allocation.");
-DEFINE_FLAG(int, new_gen_ext_limit, 64,
-            "maximum total external size (MB) in new gen before triggering GC");
-DEFINE_FLAG(int, pretenure_interval, 10,
-            "Back off pretenuring after this many cycles.");
-DEFINE_FLAG(int, pretenure_threshold, 98,
-            "Trigger pretenuring when this many percent are promoted.");
-DEFINE_FLAG(bool, verbose_gc, false, "Enables verbose GC.");
-DEFINE_FLAG(int, verbose_gc_hdr, 40, "Print verbose GC header interval.");
-DEFINE_FLAG(bool, verify_after_gc, false,
-            "Enables heap verification after GC.");
-DEFINE_FLAG(bool, verify_before_gc, false,
-            "Enables heap verification before GC.");
-DEFINE_FLAG(bool, pretenure_all, false, "Global pretenuring (for testing).");
-
-
 Heap::Heap(Isolate* isolate,
            intptr_t max_new_gen_semi_words,
            intptr_t max_old_gen_words,
            intptr_t max_external_words)
     : isolate_(isolate),
+      barrier_(new Monitor()),
+      barrier_done_(new Monitor()),
       new_space_(this, max_new_gen_semi_words, kNewObjectAlignmentOffset),
       old_space_(this, max_old_gen_words, max_external_words),
       read_only_(false),
@@ -65,6 +50,9 @@
 
 
 Heap::~Heap() {
+  delete barrier_;
+  delete barrier_done_;
+
   for (int sel = 0;
        sel < kNumWeakSelectors;
        sel++) {
@@ -99,20 +87,20 @@
   if (addr != 0) {
     return addr;
   }
-  // If we are in the process of running a sweep wait for the sweeper to free
+  // If we are in the process of running a sweep, wait for the sweeper to free
   // memory.
+  Thread* thread = Thread::Current();
   {
     MonitorLocker ml(old_space_.tasks_lock());
     addr = old_space_.TryAllocate(size, type);
     while ((addr == 0) && (old_space_.tasks() > 0)) {
-      ml.Wait();
+      ml.WaitWithSafepointCheck(thread);
       addr = old_space_.TryAllocate(size, type);
     }
   }
   if (addr != 0) {
     return addr;
   }
-  Thread* thread = Thread::Current();
   if (thread->CanCollectGarbage()) {
     // All GC tasks finished without allocating successfully. Run a full GC.
     CollectAllGarbage();
@@ -125,7 +113,7 @@
       MonitorLocker ml(old_space_.tasks_lock());
       addr = old_space_.TryAllocate(size, type);
       while ((addr == 0) && (old_space_.tasks() > 0)) {
-        ml.Wait();
+        ml.WaitWithSafepointCheck(thread);
         addr = old_space_.TryAllocate(size, type);
       }
     }
@@ -142,7 +130,7 @@
     {
       MonitorLocker ml(old_space_.tasks_lock());
       while (old_space_.tasks() > 0) {
-        ml.Wait();
+        ml.WaitWithSafepointCheck(thread);
       }
     }
   }
@@ -314,13 +302,13 @@
 }
 
 
-bool Heap::BeginNewSpaceGC() {
+bool Heap::BeginNewSpaceGC(Thread* thread) {
   MonitorLocker ml(&gc_in_progress_monitor_);
   bool start_gc_on_thread = true;
   while (gc_new_space_in_progress_ ||
          gc_old_space_in_progress_) {
     start_gc_on_thread = !gc_new_space_in_progress_;
-    ml.Wait();
+    ml.WaitWithSafepointCheck(thread);
   }
   if (start_gc_on_thread) {
     gc_new_space_in_progress_ = true;
@@ -338,13 +326,13 @@
 }
 
 
-bool Heap::BeginOldSpaceGC() {
+bool Heap::BeginOldSpaceGC(Thread* thread) {
   MonitorLocker ml(&gc_in_progress_monitor_);
   bool start_gc_on_thread = true;
   while (gc_new_space_in_progress_ ||
          gc_old_space_in_progress_) {
     start_gc_on_thread = !gc_old_space_in_progress_;
-    ml.Wait();
+    ml.WaitWithSafepointCheck(thread);
   }
   if (start_gc_on_thread) {
     gc_old_space_in_progress_ = true;
@@ -375,13 +363,15 @@
 void Heap::CollectNewSpaceGarbage(Thread* thread,
                                   ApiCallbacks api_callbacks,
                                   GCReason reason) {
-  if (BeginNewSpaceGC()) {
+  if (BeginNewSpaceGC(thread)) {
     bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks);
     RecordBeforeGC(kNew, reason);
     VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
+#ifndef PRODUCT
     TimelineDurationScope tds(thread,
                               isolate()->GetGCStream(),
                               "CollectNewGeneration");
+#endif  // !PRODUCT
     UpdateClassHeapStatsBeforeGC(kNew);
     new_space_.Scavenge(invoke_api_callbacks);
     isolate()->class_table()->UpdatePromoted();
@@ -400,13 +390,15 @@
 void Heap::CollectOldSpaceGarbage(Thread* thread,
                                   ApiCallbacks api_callbacks,
                                   GCReason reason) {
-  if (BeginOldSpaceGC()) {
+  if (BeginOldSpaceGC(thread)) {
     bool invoke_api_callbacks = (api_callbacks == kInvokeApiCallbacks);
     RecordBeforeGC(kOld, reason);
     VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
+#ifndef PRODUCT
     TimelineDurationScope tds(thread,
                               isolate()->GetGCStream(),
                               "CollectOldGeneration");
+#endif  // !PRODUCT
     UpdateClassHeapStatsBeforeGC(kOld);
     old_space_.MarkSweep(invoke_api_callbacks);
     RecordAfterGC(kOld);
@@ -762,7 +754,7 @@
   stats_.after_.old_ = old_space_.GetCurrentUsage();
   ASSERT((space == kNew && gc_new_space_in_progress_) ||
          (space == kOld && gc_old_space_in_progress_));
-  if (Service::gc_stream.enabled()) {
+  if (FLAG_support_service && Service::gc_stream.enabled()) {
     ServiceEvent event(Isolate::Current(), ServiceEvent::kGC);
     event.set_gc_stats(&stats_);
     Service::HandleEvent(&event);
diff --git a/runtime/vm/heap.h b/runtime/vm/heap.h
index 4a8ae93..f116af55 100644
--- a/runtime/vm/heap.h
+++ b/runtime/vm/heap.h
@@ -24,11 +24,6 @@
 class ServiceEvent;
 class VirtualMemory;
 
-DECLARE_FLAG(bool, verbose_gc);
-DECLARE_FLAG(bool, verify_before_gc);
-DECLARE_FLAG(bool, verify_after_gc);
-DECLARE_FLAG(bool, gc_at_alloc);
-
 class Heap {
  public:
   enum Space {
@@ -249,10 +244,13 @@
 
   Isolate* isolate() const { return isolate_; }
 
+  Monitor* barrier() const { return barrier_; }
+  Monitor* barrier_done() const { return barrier_done_; }
+
   bool ShouldPretenure(intptr_t class_id) const;
 
-  void SetupInstructionsSnapshotPage(void* pointer, uword size) {
-    old_space_.SetupInstructionsSnapshotPage(pointer, size);
+  void SetupExternalPage(void* pointer, uword size, bool is_executable) {
+    old_space_.SetupExternalPage(pointer, size, is_executable);
   }
 
  private:
@@ -323,9 +321,9 @@
   void UpdatePretenurePolicy();
 
   // Updates gc in progress flags.
-  bool BeginNewSpaceGC();
+  bool BeginNewSpaceGC(Thread* thread);
   void EndNewSpaceGC();
-  bool BeginOldSpaceGC();
+  bool BeginOldSpaceGC(Thread* thread);
   void EndOldSpaceGC();
 
   // If this heap is non-empty, updates start and end to the smallest range that
@@ -334,6 +332,8 @@
   void GetMergedAddressRange(uword* start, uword* end) const;
 
   Isolate* isolate_;
+  Monitor* barrier_;
+  Monitor* barrier_done_;
 
   // The different spaces used for allocation.
   Scavenger new_space_;
diff --git a/runtime/vm/heap_test.cc b/runtime/vm/heap_test.cc
index f52a81c..c76297d 100644
--- a/runtime/vm/heap_test.cc
+++ b/runtime/vm/heap_test.cc
@@ -26,6 +26,7 @@
   EXPECT_VALID(result);
   EXPECT(!Dart_IsNull(result));
   EXPECT(Dart_IsList(result));
+  TransitionNativeToVM transition(thread);
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   heap->CollectGarbage(Heap::kOld);
@@ -45,6 +46,7 @@
   EXPECT_VALID(result);
   EXPECT(!Dart_IsNull(result));
   EXPECT(Dart_IsList(result));
+  TransitionNativeToVM transition(thread);
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   heap->CollectGarbage(Heap::kOld);
@@ -64,6 +66,7 @@
   EXPECT_VALID(result);
   EXPECT(!Dart_IsNull(result));
   EXPECT(Dart_IsList(result));
+  TransitionNativeToVM transition(thread);
   Isolate* isolate = Isolate::Current();
   Heap* heap = isolate->heap();
   heap->CollectGarbage(Heap::kOld);
@@ -115,6 +118,7 @@
   Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
   EXPECT_VALID(result);
   EXPECT(!Dart_IsNull(result));
+  TransitionNativeToVM transition(thread);
   Library& lib = Library::Handle();
   lib ^= Api::UnwrapHandle(h_lib);
   EXPECT(!lib.IsNull());
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 97de0b1..b3e48f1 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -11,6 +11,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 DEFINE_FLAG(bool, print_environments, false, "Print SSA environments.");
 DEFINE_FLAG(charp, print_flow_graph_filter, NULL,
     "Print only IR of functions with matching names");
@@ -145,7 +147,7 @@
 
 
 void FlowGraphPrinter::PrintTypeCheck(const ParsedFunction& parsed_function,
-                                      intptr_t token_pos,
+                                      TokenPosition token_pos,
                                       Value* value,
                                       const AbstractType& dst_type,
                                       const String& dst_name,
@@ -169,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();
@@ -445,6 +447,9 @@
     PushArgumentAt(i)->value()->PrintTo(f);
   }
   PrintICDataHelper(f, ic_data());
+  if (with_checks()) {
+    f->Print(" WITH CHECKS");
+  }
 }
 
 
@@ -563,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);
@@ -576,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());
@@ -924,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());
 }
 
 
@@ -1217,4 +1222,44 @@
   return Thread::Current()->zone()->MakeCopyOfString(buffer);
 }
 
+#else  // PRODUCT
+
+void FlowGraphPrinter::PrintOneInstruction(Instruction* instr,
+                                           bool print_locations) {
+  UNREACHABLE();
+}
+
+
+void FlowGraphPrinter::PrintTypeCheck(const ParsedFunction& parsed_function,
+                                      TokenPosition token_pos,
+                                      Value* value,
+                                      const AbstractType& dst_type,
+                                      const String& dst_name,
+                                      bool eliminated) {
+  UNREACHABLE();
+}
+
+
+void FlowGraphPrinter::PrintBlock(BlockEntryInstr* block,
+                                  bool print_locations) {
+  UNREACHABLE();
+}
+
+
+void FlowGraphPrinter::PrintGraph(const char* phase, FlowGraph* flow_graph) {
+  UNREACHABLE();
+}
+
+
+void FlowGraphPrinter::PrintICData(const ICData& ic_data) {
+  UNREACHABLE();
+}
+
+
+bool FlowGraphPrinter::ShouldPrint(const Function& function) {
+  return false;
+}
+
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/il_printer.h b/runtime/vm/il_printer.h
index c1d036f..bc19c75 100644
--- a/runtime/vm/il_printer.h
+++ b/runtime/vm/il_printer.h
@@ -48,7 +48,7 @@
   void PrintInstruction(Instruction* instr);
   static void PrintOneInstruction(Instruction* instr, bool print_locations);
   static void PrintTypeCheck(const ParsedFunction& parsed_function,
-                             intptr_t token_pos,
+                             TokenPosition token_pos,
                              Value* value,
                              const AbstractType& dst_type,
                              const String& dst_name,
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 15635bc..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,20 +29,22 @@
 
 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);
-DECLARE_FLAG(bool, trace_optimization);
-DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
+
+
+#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),
@@ -127,7 +128,7 @@
 CheckClassInstr::CheckClassInstr(Value* value,
                                  intptr_t deopt_id,
                                  const ICData& unary_checks,
-                                 intptr_t token_pos)
+                                 TokenPosition token_pos)
     : TemplateInstruction(deopt_id),
       unary_checks_(unary_checks),
       cids_(unary_checks.NumberOfChecks()),
@@ -414,19 +415,20 @@
 
 
 const Field& LoadStaticFieldInstr::StaticField() const {
-  Field& field = Field::Handle();
+  Field& field = Field::ZoneHandle();
   field ^= field_value()->BoundConstant().raw();
   return field;
 }
 
 
-ConstantInstr::ConstantInstr(const Object& value, intptr_t token_pos)
+ConstantInstr::ConstantInstr(const Object& value, TokenPosition token_pos)
     : value_(value),
       token_pos_(token_pos) {
   // Check that the value is not an incorrect Integer representation.
   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());
 }
 
 
@@ -1323,11 +1325,6 @@
 
 
 bool BinarySmiOpInstr::CanDeoptimize() const {
-  if (FLAG_throw_on_javascript_int_overflow && (Smi::kBits > 32)) {
-    // If Smi's are bigger than 32-bits, then the instruction could deoptimize
-    // if the result is too big.
-    return true;
-  }
   switch (op_kind()) {
     case Token::kBIT_AND:
     case Token::kBIT_OR:
@@ -2055,19 +2052,25 @@
     const TypeArguments& instantiator_type_args =
         TypeArguments::Cast(constant_type_args->value());
     Error& bound_error = Error::Handle();
-    const AbstractType& new_dst_type = AbstractType::Handle(
+    AbstractType& new_dst_type = AbstractType::Handle(
         dst_type().InstantiateFrom(
-            instantiator_type_args, &bound_error, NULL, Heap::kOld));
-    // If dst_type is instantiated to dynamic or Object, skip the test.
-    if (!new_dst_type.IsMalformedOrMalbounded() && bound_error.IsNull() &&
-        (new_dst_type.IsDynamicType() || new_dst_type.IsObjectType())) {
+            instantiator_type_args, &bound_error, NULL, NULL, Heap::kOld));
+    if (new_dst_type.IsMalformedOrMalbounded() || !bound_error.IsNull()) {
+      return this;
+    }
+    if (new_dst_type.IsTypeRef()) {
+      new_dst_type = TypeRef::Cast(new_dst_type).type();
+    }
+    new_dst_type = new_dst_type.Canonicalize();
+    set_dst_type(new_dst_type);
+
+    if (new_dst_type.IsDynamicType() ||
+        new_dst_type.IsObjectType() ||
+        (FLAG_eliminate_type_checks &&
+         value()->Type()->IsAssignableTo(new_dst_type))) {
       return value()->definition();
     }
-    set_dst_type(AbstractType::ZoneHandle(new_dst_type.Canonicalize()));
-    if (FLAG_eliminate_type_checks &&
-        value()->Type()->IsAssignableTo(dst_type())) {
-      return value()->definition();
-    }
+
     ConstantInstr* null_constant = flow_graph->constant_null();
     instantiator_type_arguments()->BindTo(null_constant);
   }
@@ -2076,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;
 }
 
 
@@ -2344,7 +2347,7 @@
 
 static bool MaybeNumber(CompileType* type) {
   ASSERT(Type::Handle(Type::Number()).IsMoreSpecificThan(
-         Type::Handle(Type::Number()), NULL, Heap::kOld));
+             Type::Handle(Type::Number()), NULL, NULL, Heap::kOld));
   return type->ToAbstractType()->IsDynamicType()
       || type->ToAbstractType()->IsObjectType()
       || type->ToAbstractType()->IsTypeParameter()
@@ -2734,7 +2737,7 @@
   if (!compiler->is_optimizing()) {
     compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
                                    GetDeoptId(),
-                                   Scanner::kNoSourcePos);
+                                   TokenPosition::kNoSource);
   }
   if (HasParallelMove()) {
     compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -2760,7 +2763,7 @@
     // code that matches backwards from the end of the pattern.
     compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
                                    GetDeoptId(),
-                                   Scanner::kNoSourcePos);
+                                   TokenPosition::kNoSource);
   }
   if (HasParallelMove()) {
     compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -2961,7 +2964,7 @@
 }
 
 
-StrictCompareInstr::StrictCompareInstr(intptr_t token_pos,
+StrictCompareInstr::StrictCompareInstr(TokenPosition token_pos,
                                        Token::Kind kind,
                                        Value* left,
                                        Value* right,
@@ -3519,7 +3522,7 @@
     ZoneGrowableArray<Value*>* inputs,
     intptr_t deopt_id,
     MethodRecognizer::Kind recognized_kind,
-    intptr_t token_pos)
+    TokenPosition token_pos)
     : PureDefinition(deopt_id),
       inputs_(inputs),
       recognized_kind_(recognized_kind),
@@ -3543,9 +3546,14 @@
       return 1;
     }
     case MethodRecognizer::kDoubleRound:
+    case MethodRecognizer::kMathAtan:
+    case MethodRecognizer::kMathTan:
+    case MethodRecognizer::kMathAcos:
+    case MethodRecognizer::kMathAsin:
       return 1;
     case MethodRecognizer::kDoubleMod:
     case MethodRecognizer::kMathDoublePow:
+    case MethodRecognizer::kMathAtan2:
       return 2;
     default:
       UNREACHABLE();
@@ -3565,6 +3573,10 @@
     reinterpret_cast<RuntimeFunction>(
         static_cast<BinaryMathCFunction>(&DartModulo)));
 
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAtan2, 2, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<BinaryMathCFunction>(&atan2_ieee)));
+
 DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcFloor, 1, true /* is_float */,
     reinterpret_cast<RuntimeFunction>(
         static_cast<UnaryMathCFunction>(&floor)));
@@ -3581,6 +3593,30 @@
     reinterpret_cast<RuntimeFunction>(
         static_cast<UnaryMathCFunction>(&round)));
 
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcCos, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&cos)));
+
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcSin, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&sin)));
+
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAsin, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&asin)));
+
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAcos, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&acos)));
+
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcTan, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&tan)));
+
+DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcAtan, 1, true /* is_float */,
+    reinterpret_cast<RuntimeFunction>(
+        static_cast<UnaryMathCFunction>(&atan)));
+
 
 const RuntimeEntry& InvokeMathCFunctionInstr::TargetFunction() const {
   switch (recognized_kind_) {
@@ -3596,6 +3632,16 @@
       return kLibcPowRuntimeEntry;
     case MethodRecognizer::kDoubleMod:
       return kDartModuloRuntimeEntry;
+    case MethodRecognizer::kMathTan:
+      return kLibcTanRuntimeEntry;
+    case MethodRecognizer::kMathAsin:
+      return kLibcAsinRuntimeEntry;
+    case MethodRecognizer::kMathAcos:
+      return kLibcAcosRuntimeEntry;
+    case MethodRecognizer::kMathAtan:
+      return kLibcAtanRuntimeEntry;
+    case MethodRecognizer::kMathAtan2:
+      return kLibcAtan2RuntimeEntry;
     default:
       UNREACHABLE();
   }
@@ -3603,15 +3649,6 @@
 }
 
 
-DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcCos, 1, true /* is_float */,
-    reinterpret_cast<RuntimeFunction>(
-        static_cast<UnaryMathCFunction>(&cos)));
-
-DEFINE_RAW_LEAF_RUNTIME_ENTRY(LibcSin, 1, true /* is_float */,
-    reinterpret_cast<RuntimeFunction>(
-        static_cast<UnaryMathCFunction>(&sin)));
-
-
 const RuntimeEntry& MathUnaryInstr::TargetFunction() const {
   switch (kind()) {
     case MathUnaryInstr::kSin:
@@ -3689,6 +3726,7 @@
     Report::MessageF(Report::kError,
                      Script::Handle(function().script()),
                      function().token_pos(),
+                     Report::AtLocation,
                      "native function '%s' (%" Pd " arguments) cannot be found",
                      native_name().ToCString(),
                      function().NumParameters());
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 0a40848..f424c99 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -13,11 +13,10 @@
 #include "vm/method_recognizer.h"
 #include "vm/object.h"
 #include "vm/parser.h"
+#include "vm/token_position.h"
 
 namespace dart {
 
-DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
-
 class BitVector;
 class BlockEntryInstr;
 class BoxIntegerInstr;
@@ -38,47 +37,6 @@
 class RangeBoundary;
 class UnboxIntegerInstr;
 
-// These token positions are used to classify instructions that can't be
-// directly tied to an actual source position.
-#define CLASSIFYING_TOKEN_POSITIONS(V)                                         \
-    V(Private, -2)                                                             \
-    V(Box, -3)                                                                 \
-    V(ParallelMove, -4)                                                        \
-    V(TempMove, -5)                                                            \
-    V(Constant, -6)                                                            \
-    V(PushArgument, -7)                                                        \
-    V(ControlFlow, -8)                                                         \
-    V(Context, -9)
-
-// COMPILE_ASSERT that all CLASSIFYING_TOKEN_POSITIONS are less than
-// Scanner::kNoSourcePos.
-#define SANITY_CHECK_VALUES(name, value)                                       \
-  COMPILE_ASSERT(value < Scanner::kNoSourcePos);
-  CLASSIFYING_TOKEN_POSITIONS(SANITY_CHECK_VALUES);
-#undef SANITY_CHECK_VALUES
-
-class ClassifyingTokenPositions : public AllStatic {
- public:
-#define DEFINE_VALUES(name, value)                                             \
-  static const intptr_t k##name = value;
-  CLASSIFYING_TOKEN_POSITIONS(DEFINE_VALUES);
-#undef DEFINE_VALUES
-
-  static const char* ToCString(intptr_t token_pos) {
-    ASSERT(token_pos < 0);
-    switch (token_pos) {
-      case Scanner::kNoSourcePos: return "NoSource";
-#define DEFINE_CASE(name, value)                                               \
-      case value: return #name;
-      CLASSIFYING_TOKEN_POSITIONS(DEFINE_CASE);
-#undef DEFINE_CASE
-      default:
-        UNIMPLEMENTED();
-        return NULL;
-    }
-  }
-};
-
 // CompileType describes type of the value produced by the definition.
 //
 // It captures the following properties:
@@ -639,6 +597,20 @@
   DECLARE_INSTRUCTION_NO_BACKEND(type)                                         \
   DECLARE_INSTRUCTION_BACKEND()                                                \
 
+#ifndef PRODUCT
+#define PRINT_TO_SUPPORT                                                       \
+    virtual void PrintTo(BufferFormatter* f) const;
+#else
+#define PRINT_TO_SUPPORT
+#endif  // !PRODUCT
+
+#ifndef PRODUCT
+#define PRINT_OPERANDS_TO_SUPPORT                                              \
+    virtual void PrintOperandsTo(BufferFormatter* f) const;
+#else
+#define PRINT_OPERANDS_TO_SUPPORT
+#endif  // !PRODUCT
+
 class Instruction : public ZoneAllocated {
  public:
 #define DECLARE_TAG(type) k##type,
@@ -668,7 +640,9 @@
   const ICData* GetICData(
       const ZoneGrowableArray<const ICData*>& ic_data_array) const;
 
-  virtual intptr_t token_pos() const { return Scanner::kNoSourcePos; }
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kNoSource;
+  }
 
   virtual intptr_t InputCount() const = 0;
   virtual Value* InputAt(intptr_t i) const = 0;
@@ -740,10 +714,22 @@
 
   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
   virtual void PrintTo(BufferFormatter* f) const;
   virtual void PrintOperandsTo(BufferFormatter* f) const;
+#endif
 
 #define DECLARE_INSTRUCTION_TYPE_CHECK(Name, Type)                             \
   bool Is##Name() { return (As##Name() != NULL); }                             \
@@ -1092,12 +1078,12 @@
 
   bool IsRedundant() const;
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
-  virtual intptr_t token_pos() const {
-    return ClassifyingTokenPositions::kParallelMove;
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kParallelMove;
   }
 
+  PRINT_TO_SUPPORT
+
  private:
   GrowableArray<MoveOperands*> moves_;   // Elements cannot be null.
 
@@ -1123,6 +1109,8 @@
 
   intptr_t block_id() const { return block_id_; }
 
+  // NOTE: These are SSA positions and not token positions. These are used by
+  // the register allocator.
   void set_start_pos(intptr_t pos) { start_pos_ = pos; }
   intptr_t start_pos() const { return start_pos_; }
   void  set_end_pos(intptr_t pos) { end_pos_ = pos; }
@@ -1230,8 +1218,8 @@
     return this;
   }
 
-  virtual intptr_t token_pos() const {
-    return ClassifyingTokenPositions::kControlFlow;
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kControlFlow;
   }
 
   // Helper to mutate the graph during inlining. This block should be
@@ -1411,7 +1399,7 @@
     return indirect_entries_;
   }
 
-  virtual void PrintTo(BufferFormatter* f) const;
+  PRINT_TO_SUPPORT
 
  private:
   virtual void ClearPredecessors() {}
@@ -1457,11 +1445,11 @@
   void InsertPhi(PhiInstr* phi);
   void RemovePhi(PhiInstr* phi);
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
   virtual EffectSet Effects() const { return EffectSet::None(); }
   virtual EffectSet Dependencies() const { return EffectSet::None(); }
 
+  PRINT_TO_SUPPORT
+
  private:
   // Classes that have access to predecessors_ when inlining.
   friend class BlockEntryInstr;
@@ -1528,7 +1516,7 @@
     return predecessor_;
   }
 
-  virtual void PrintTo(BufferFormatter* f) const;
+  PRINT_TO_SUPPORT
 
  private:
   friend class BlockEntryInstr;  // Access to predecessor_ when inlining.
@@ -1556,10 +1544,10 @@
 
   DECLARE_INSTRUCTION(IndirectEntry)
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
   intptr_t indirect_id() const { return indirect_id_; }
 
+  PRINT_TO_SUPPORT
+
  private:
   const intptr_t indirect_id_;
 };
@@ -1606,7 +1594,7 @@
     return &initial_definitions_;
   }
 
-  virtual void PrintTo(BufferFormatter* f) const;
+  PRINT_TO_SUPPORT
 
  private:
   friend class BlockEntryInstr;  // Access to predecessor_ when inlining.
@@ -1748,6 +1736,9 @@
     return false;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+  PRINT_TO_SUPPORT
+
   bool UpdateType(CompileType new_type) {
     if (type_ == NULL) {
       type_ = ZoneCompileType::Wrap(new_type);
@@ -1789,11 +1780,6 @@
   // NULL iterator.
   void ReplaceWith(Definition* other, ForwardInstructionIterator* iterator);
 
-  // Printing support. These functions are sometimes overridden for custom
-  // formatting. Otherwise, it prints in the format "opcode(op1, op2, op3)".
-  virtual void PrintTo(BufferFormatter* f) const;
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   // A value in the constant propagation lattice.
   //    - non-constant sentinel
   //    - a constant (any non-sentinel value)
@@ -1973,8 +1959,6 @@
 
   DECLARE_INSTRUCTION(Phi)
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
   virtual void InferRange(RangeAnalysis* analysis, Range* range);
 
   BitVector* reaching_defs() const {
@@ -1998,6 +1982,8 @@
     return loop_variable_info_;
   }
 
+  PRINT_TO_SUPPORT
+
  private:
   // Direct access to inputs_ in order to resize it due to unreachable
   // predecessors.
@@ -2048,12 +2034,12 @@
     return 0;
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual CompileType ComputeType() const;
 
   virtual bool MayThrow() const { return false; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
 
@@ -2081,12 +2067,13 @@
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
 
-  virtual intptr_t token_pos() const {
-    return ClassifyingTokenPositions::kPushArgument;
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kPushArgument;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr);
 };
@@ -2099,7 +2086,7 @@
 
 class ReturnInstr : public TemplateInstruction<1, NoThrow> {
  public:
-  ReturnInstr(intptr_t token_pos, Value* value)
+  ReturnInstr(TokenPosition token_pos, Value* value)
       : TemplateInstruction(Thread::Current()->GetNextDeoptId()),
         token_pos_(token_pos) {
     SetInputAt(0, value);
@@ -2107,7 +2094,7 @@
 
   DECLARE_INSTRUCTION(Return)
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   Value* value() const { return inputs_[0]; }
 
   virtual bool CanBecomeDeoptimizationTarget() const {
@@ -2121,7 +2108,7 @@
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(ReturnInstr);
 };
@@ -2129,7 +2116,7 @@
 
 class ThrowInstr : public TemplateInstruction<0, Throws> {
  public:
-  explicit ThrowInstr(intptr_t token_pos)
+  explicit ThrowInstr(TokenPosition token_pos)
       : TemplateInstruction(Thread::Current()->GetNextDeoptId()),
         token_pos_(token_pos) {
   }
@@ -2138,14 +2125,14 @@
 
   virtual intptr_t ArgumentCount() const { return 1; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   virtual bool CanDeoptimize() const { return true; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(ThrowInstr);
 };
@@ -2155,7 +2142,7 @@
  public:
   // 'catch_try_index' can be CatchClauseNode::kInvalidTryIndex if the
   // rethrow has been artifically generated by the parser.
-  ReThrowInstr(intptr_t token_pos, intptr_t catch_try_index)
+  ReThrowInstr(TokenPosition token_pos, intptr_t catch_try_index)
       : TemplateInstruction(Thread::Current()->GetNextDeoptId()),
         token_pos_(token_pos),
         catch_try_index_(catch_try_index) {
@@ -2165,7 +2152,7 @@
 
   virtual intptr_t ArgumentCount() const { return 2; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   intptr_t catch_try_index() const { return catch_try_index_; }
 
   virtual bool CanDeoptimize() const { return true; }
@@ -2173,7 +2160,7 @@
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const intptr_t catch_try_index_;
 
   DISALLOW_COPY_AND_ASSIGN(ReThrowInstr);
@@ -2259,12 +2246,12 @@
     return parallel_move_;
   }
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
-  virtual intptr_t token_pos() const {
-    return ClassifyingTokenPositions::kControlFlow;
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kControlFlow;
   }
 
+  PRINT_TO_SUPPORT
+
  private:
   BlockEntryInstr* block_;
   JoinEntryInstr* successor_;
@@ -2322,11 +2309,11 @@
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
   Value* offset() const { return inputs_[0]; }
   void ComputeOffsetTable();
 
+  PRINT_TO_SUPPORT
+
  private:
   GrowableArray<TargetEntryInstr*> successors_;
   TypedData& offsets_;
@@ -2338,7 +2325,7 @@
   Value* left() const { return inputs_[0]; }
   Value* right() const { return inputs_[1]; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   Token::Kind kind() const { return kind_; }
 
   virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right) = 0;
@@ -2373,7 +2360,7 @@
   DEFINE_INSTRUCTION_TYPE_CHECK(Comparison)
 
  protected:
-  ComparisonInstr(intptr_t token_pos,
+  ComparisonInstr(TokenPosition token_pos,
                   Token::Kind kind,
                   Value* left,
                   Value* right,
@@ -2389,7 +2376,7 @@
   }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   Token::Kind kind_;
   intptr_t operation_cid_;  // Set by optimizer.
 
@@ -2421,7 +2408,7 @@
 
   Value* InputAt(intptr_t i) const { return comparison()->InputAt(i); }
 
-  virtual intptr_t token_pos() const { return comparison_->token_pos(); }
+  virtual TokenPosition token_pos() const { return comparison_->token_pos(); }
 
   virtual bool CanDeoptimize() const {
     // Branches need a deoptimization info in checked mode if they
@@ -2453,8 +2440,6 @@
 
   virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
-  virtual void PrintTo(BufferFormatter* f) const;
-
   // Set compile type constrained by the comparison of this branch.
   // FlowGraphPropagator propagates it downwards into either true or false
   // successor.
@@ -2490,6 +2475,8 @@
   virtual intptr_t SuccessorCount() const;
   virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
 
+  PRINT_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     comparison()->RawSetInputAt(i, value);
@@ -2571,8 +2558,6 @@
     return false;
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   Value* value() const { return inputs_[0]; }
   Range* constraint() const { return constraint_; }
 
@@ -2588,6 +2573,8 @@
     return target_;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   Range* constraint_;
   TargetEntryInstr* target_;
@@ -2599,7 +2586,7 @@
 class ConstantInstr : public TemplateDefinition<0, NoThrow, Pure> {
  public:
   ConstantInstr(const Object& value,
-                intptr_t token_pos = ClassifyingTokenPositions::kConstant);
+                TokenPosition token_pos = TokenPosition::kConstant);
 
   DECLARE_INSTRUCTION(Constant)
   virtual CompileType ComputeType() const;
@@ -2608,19 +2595,19 @@
 
   const Object& value() const { return value_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual void InferRange(RangeAnalysis* analysis, Range* range);
 
   virtual bool AttributesEqual(Instruction* other) const;
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
+
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   const Object& value_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(ConstantInstr);
 };
@@ -2653,7 +2640,7 @@
 
 class AssertAssignableInstr : public TemplateDefinition<2, Throws, Pure> {
  public:
-  AssertAssignableInstr(intptr_t token_pos,
+  AssertAssignableInstr(TokenPosition token_pos,
                         Value* value,
                         Value* instantiator_type_arguments,
                         const AbstractType& dst_type,
@@ -2664,6 +2651,7 @@
         dst_type_(AbstractType::ZoneHandle(dst_type.raw())),
         dst_name_(dst_name) {
     ASSERT(!dst_type.IsNull());
+    ASSERT(!dst_type.IsTypeRef());
     ASSERT(!dst_name.IsNull());
     SetInputAt(0, value);
     SetInputAt(1, instantiator_type_arguments);
@@ -2676,15 +2664,14 @@
   Value* value() const { return inputs_[0]; }
   Value* instantiator_type_arguments() const { return inputs_[1]; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   const AbstractType& dst_type() const { return dst_type_; }
   void set_dst_type(const AbstractType& dst_type) {
+    ASSERT(!dst_type.IsTypeRef());
     dst_type_ = dst_type.raw();
   }
   const String& dst_name() const { return dst_name_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual bool CanBecomeDeoptimizationTarget() const {
@@ -2697,8 +2684,10 @@
 
   virtual bool AttributesEqual(Instruction* other) const;
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   AbstractType& dst_type_;
   const String& dst_name_;
 
@@ -2708,7 +2697,7 @@
 
 class AssertBooleanInstr : public TemplateDefinition<1, Throws, Pure> {
  public:
-  AssertBooleanInstr(intptr_t token_pos, Value* value)
+  AssertBooleanInstr(TokenPosition token_pos, Value* value)
       : TemplateDefinition(Thread::Current()->GetNextDeoptId()),
         token_pos_(token_pos) {
     SetInputAt(0, value);
@@ -2717,19 +2706,19 @@
   DECLARE_INSTRUCTION(AssertBoolean)
   virtual CompileType ComputeType() const;
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   Value* value() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(AssertBooleanInstr);
 };
@@ -2771,7 +2760,9 @@
   DECLARE_INSTRUCTION(ClosureCall)
 
   const Array& argument_names() const { return ast_node_.arguments()->names(); }
-  virtual intptr_t token_pos() const { return ast_node_.token_pos(); }
+  virtual TokenPosition token_pos() const {
+    return ast_node_.token_pos();
+  }
 
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
   virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
@@ -2781,12 +2772,12 @@
   // TODO(kmillikin): implement exact call counts for closure calls.
   virtual intptr_t CallCount() const { return 1; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual EffectSet Effects() const { return EffectSet::All(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const ClosureCallNode& ast_node_;
   ZoneGrowableArray<PushArgumentInstr*>* arguments_;
@@ -2797,7 +2788,7 @@
 
 class InstanceCallInstr : public TemplateDefinition<0, Throws> {
  public:
-  InstanceCallInstr(intptr_t token_pos,
+  InstanceCallInstr(TokenPosition token_pos,
                     const String& function_name,
                     Token::Kind token_kind,
                     ZoneGrowableArray<PushArgumentInstr*>* arguments,
@@ -2838,7 +2829,7 @@
   // ICData can be replaced by optimizer.
   void set_ic_data(const ICData* value) { ic_data_ = value; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   const String& function_name() const { return function_name_; }
   Token::Kind token_kind() const { return token_kind_; }
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
@@ -2848,8 +2839,6 @@
   const Array& argument_names() const { return argument_names_; }
   intptr_t checked_argument_count() const { return checked_argument_count_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual bool CanBecomeDeoptimizationTarget() const {
@@ -2860,13 +2849,15 @@
 
   virtual EffectSet Effects() const { return EffectSet::All(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  protected:
-  friend class FlowGraphOptimizer;
+  friend class JitOptimizer;
   void set_ic_data(ICData* value) { ic_data_ = value; }
 
  private:
   const ICData* ic_data_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const String& function_name_;
   const Token::Kind token_kind_;  // Binary op, unary op, kGET or kILLEGAL.
   ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
@@ -2892,7 +2883,9 @@
 
   InstanceCallInstr* instance_call() const { return instance_call_; }
   bool with_checks() const { return with_checks_; }
-  virtual intptr_t token_pos() const { return instance_call_->token_pos(); }
+  virtual TokenPosition token_pos() const {
+    return instance_call_->token_pos();
+  }
 
   virtual intptr_t ArgumentCount() const {
     return instance_call()->ArgumentCount();
@@ -2915,7 +2908,7 @@
 
   virtual EffectSet Effects() const { return EffectSet::All(); }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   InstanceCallInstr* instance_call_;
@@ -2928,7 +2921,7 @@
 
 class StrictCompareInstr : public ComparisonInstr {
  public:
-  StrictCompareInstr(intptr_t token_pos,
+  StrictCompareInstr(TokenPosition token_pos,
                      Token::Kind kind,
                      Value* left,
                      Value* right,
@@ -2940,8 +2933,6 @@
 
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Definition* Canonicalize(FlowGraph* flow_graph);
@@ -2957,6 +2948,8 @@
 
   bool AttributesEqual(Instruction* other) const;
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   // True if the comparison must check for double, Mint or Bigint and
   // use value comparison instead.
@@ -2970,7 +2963,10 @@
 // comparison pattern.
 class TestSmiInstr : public ComparisonInstr {
  public:
-  TestSmiInstr(intptr_t token_pos, Token::Kind kind, Value* left, Value* right)
+  TestSmiInstr(TokenPosition token_pos,
+               Token::Kind kind,
+               Value* left,
+               Value* right)
       : ComparisonInstr(token_pos, kind, left, right) {
     ASSERT(kind == Token::kEQ || kind == Token::kNE);
   }
@@ -3004,7 +3000,7 @@
 // TestCidInstr needs only one argument
 class TestCidsInstr : public ComparisonInstr {
  public:
-  TestCidsInstr(intptr_t token_pos,
+  TestCidsInstr(TokenPosition token_pos,
                 Token::Kind kind,
                 Value* value,
                 const ZoneGrowableArray<intptr_t>& cid_results,
@@ -3043,7 +3039,7 @@
   virtual Condition EmitComparisonCode(FlowGraphCompiler* compiler,
                                        BranchLabels labels);
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   const ZoneGrowableArray<intptr_t>& cid_results_;
@@ -3053,7 +3049,7 @@
 
 class EqualityCompareInstr : public ComparisonInstr {
  public:
-  EqualityCompareInstr(intptr_t token_pos,
+  EqualityCompareInstr(TokenPosition token_pos,
                        Token::Kind kind,
                        Value* left,
                        Value* right,
@@ -3070,8 +3066,6 @@
 
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual void EmitBranchCode(FlowGraphCompiler* compiler,
@@ -3087,6 +3081,8 @@
     return kTagged;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(EqualityCompareInstr);
 };
@@ -3094,7 +3090,7 @@
 
 class RelationalOpInstr : public ComparisonInstr {
  public:
-  RelationalOpInstr(intptr_t token_pos,
+  RelationalOpInstr(TokenPosition token_pos,
                     Token::Kind kind,
                     Value* left,
                     Value* right,
@@ -3111,8 +3107,6 @@
 
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual void EmitBranchCode(FlowGraphCompiler* compiler,
@@ -3128,6 +3122,8 @@
     return kTagged;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(RelationalOpInstr);
 };
@@ -3177,8 +3173,6 @@
     return comparison()->RequiredInputRepresentation(i);
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual CompileType ComputeType() const;
 
   virtual void InferRange(RangeAnalysis* analysis, Range* range);
@@ -3202,6 +3196,8 @@
 
   virtual bool MayThrow() const { return comparison()->MayThrow(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     comparison()->RawSetInputAt(i, value);
@@ -3217,7 +3213,7 @@
 
 class StaticCallInstr : public TemplateDefinition<0, Throws> {
  public:
-  StaticCallInstr(intptr_t token_pos,
+  StaticCallInstr(TokenPosition token_pos,
                   const Function& function,
                   const Array& argument_names,
                   ZoneGrowableArray<PushArgumentInstr*>* arguments,
@@ -3249,7 +3245,7 @@
   // Accessors forwarded to the AST node.
   const Function& function() const { return function_; }
   const Array& argument_names() const { return argument_names_; }
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   virtual intptr_t ArgumentCount() const { return arguments_->length(); }
   virtual PushArgumentInstr* PushArgumentAt(intptr_t index) const {
@@ -3260,8 +3256,6 @@
     return ic_data() == NULL ? 0 : ic_data()->AggregateCount();
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return true; }
 
   virtual bool CanBecomeDeoptimizationTarget() const {
@@ -3291,9 +3285,11 @@
   virtual AliasIdentity Identity() const { return identity_; }
   virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const ICData* ic_data_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const Function& function_;
   const Array& argument_names_;
   ZoneGrowableArray<PushArgumentInstr*>* arguments_;
@@ -3312,7 +3308,7 @@
 class LoadLocalInstr : public TemplateDefinition<0, NoThrow> {
  public:
   LoadLocalInstr(const LocalVariable& local,
-                 intptr_t token_pos = Scanner::kNoSourcePos)
+                 TokenPosition token_pos)
       : local_(local), is_last_(false), token_pos_(token_pos) { }
 
   DECLARE_INSTRUCTION(LoadLocal)
@@ -3320,8 +3316,6 @@
 
   const LocalVariable& local() const { return local_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const {
@@ -3332,12 +3326,14 @@
   void mark_last() { is_last_ = true; }
   bool is_last() const { return is_last_; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
+
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   const LocalVariable& local_;
   bool is_last_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadLocalInstr);
 };
@@ -3362,8 +3358,8 @@
     return EffectSet::None();
   }
 
-  virtual intptr_t token_pos() const {
-    return ClassifyingTokenPositions::kTempMove;
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kTempMove;
   }
 
  private:
@@ -3394,8 +3390,6 @@
 
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const {
@@ -3408,10 +3402,12 @@
     return false;
   }
 
-  virtual intptr_t token_pos() const {
-    return ClassifyingTokenPositions::kTempMove;
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kTempMove;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     value_ = value;
@@ -3428,7 +3424,7 @@
  public:
   StoreLocalInstr(const LocalVariable& local,
                   Value* value,
-                  intptr_t token_pos = Scanner::kNoSourcePos)
+                  TokenPosition token_pos)
       : local_(local), is_dead_(false), is_last_(false), token_pos_(token_pos) {
     SetInputAt(0, value);
   }
@@ -3439,8 +3435,6 @@
   const LocalVariable& local() const { return local_; }
   Value* value() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   void mark_dead() { is_dead_ = true; }
@@ -3454,13 +3448,15 @@
     return EffectSet::None();
   }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
+
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   const LocalVariable& local_;
   bool is_dead_;
   bool is_last_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(StoreLocalInstr);
 };
@@ -3475,7 +3471,9 @@
 
   DECLARE_INSTRUCTION(NativeCall)
 
-  virtual intptr_t token_pos() const { return ast_node_.token_pos(); }
+  virtual TokenPosition token_pos() const {
+    return ast_node_.token_pos();
+  }
 
   const Function& function() const { return ast_node_.function(); }
 
@@ -3495,14 +3493,14 @@
     return ast_node_.link_lazily();
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const { return EffectSet::All(); }
 
   void SetupNative();
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   void set_native_c_function(NativeFunction value) {
     native_c_function_ = value;
@@ -3520,7 +3518,7 @@
 
 class DebugStepCheckInstr : public TemplateInstruction<0, NoThrow> {
  public:
-  DebugStepCheckInstr(intptr_t token_pos,
+  DebugStepCheckInstr(TokenPosition token_pos,
                       RawPcDescriptors::Kind stub_kind)
       : token_pos_(token_pos),
         stub_kind_(stub_kind) {
@@ -3528,13 +3526,13 @@
 
   DECLARE_INSTRUCTION(DebugStepCheck)
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   virtual bool CanDeoptimize() const { return false; }
   virtual EffectSet Effects() const { return EffectSet::All(); }
   virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const RawPcDescriptors::Kind stub_kind_;
 
   DISALLOW_COPY_AND_ASSIGN(DebugStepCheckInstr);
@@ -3553,7 +3551,7 @@
                           Value* instance,
                           Value* value,
                           StoreBarrierType emit_store_barrier,
-                          intptr_t token_pos)
+                          TokenPosition token_pos)
       : field_(field),
         offset_in_bytes_(field.Offset()),
         emit_store_barrier_(emit_store_barrier),
@@ -3562,13 +3560,14 @@
         is_object_reference_initialization_(false) {
     SetInputAt(kInstancePos, instance);
     SetInputAt(kValuePos, value);
+    CheckField(field);
   }
 
   StoreInstanceFieldInstr(intptr_t offset_in_bytes,
                           Value* instance,
                           Value* value,
                           StoreBarrierType emit_store_barrier,
-                          intptr_t token_pos)
+                          TokenPosition token_pos)
       : field_(Field::ZoneHandle()),
         offset_in_bytes_(offset_in_bytes),
         emit_store_barrier_(emit_store_barrier),
@@ -3601,7 +3600,7 @@
   bool is_object_reference_initialization() const {
     return is_object_reference_initialization_;
   }
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   const Field& field() const { return field_; }
   intptr_t offset_in_bytes() const { return offset_in_bytes_; }
@@ -3611,8 +3610,6 @@
         && (emit_store_barrier_ == kEmitStoreBarrier);
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   // May require a deoptimization target for input conversions.
@@ -3631,8 +3628,10 @@
 
   virtual Representation RequiredInputRepresentation(intptr_t index) const;
 
+  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();
@@ -3644,7 +3643,7 @@
   const Field& field_;
   intptr_t offset_in_bytes_;
   const StoreBarrierType emit_store_barrier_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   // This may be the first store to an unboxed field.
   bool is_potential_unboxed_initialization_;
   // True if this store initializes an object reference field of an object that
@@ -3663,6 +3662,7 @@
     : TemplateInstruction(deopt_id),
       field_(field) {
     SetInputAt(0, value);
+    CheckField(field);
   }
 
   Value* value() const { return inputs_[0]; }
@@ -3675,7 +3675,7 @@
     return true;
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   const Field& field_;
@@ -3689,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)
 
@@ -3707,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)
 
@@ -3722,7 +3726,7 @@
 
 class LoadStaticFieldInstr : public TemplateDefinition<1, NoThrow> {
  public:
-  LoadStaticFieldInstr(Value* field_value, intptr_t token_pos)
+  LoadStaticFieldInstr(Value* field_value, TokenPosition token_pos)
       : token_pos_(token_pos) {
     ASSERT(field_value->BindsToConstant());
     SetInputAt(0, field_value);
@@ -3735,8 +3739,6 @@
 
   Value* field_value() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual bool AllowsCSE() const { return StaticField().is_final(); }
@@ -3744,10 +3746,12 @@
   virtual EffectSet Dependencies() const;
   virtual bool AttributesEqual(Instruction* other) const;
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
+
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldInstr);
 };
@@ -3757,11 +3761,12 @@
  public:
   StoreStaticFieldInstr(const Field& field,
                         Value* value,
-                        intptr_t token_pos = Scanner::kNoSourcePos)
+                        TokenPosition token_pos)
       : field_(field),
         token_pos_(token_pos) {
     ASSERT(field.IsZoneHandle());
     SetInputAt(kValuePos, value);
+    CheckField(field);
   }
 
   enum {
@@ -3773,8 +3778,6 @@
   const Field& field() const { return field_; }
   Value* value() const { return inputs_[kValuePos]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   // Currently CSE/LICM don't operate on any instructions that can be affected
@@ -3782,7 +3785,9 @@
   // are marked as having no side-effects.
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
+
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   bool CanValueBeSmi() const {
@@ -3793,7 +3798,7 @@
   }
 
   const Field& field_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(StoreStaticFieldInstr);
 };
@@ -3806,7 +3811,7 @@
                    intptr_t index_scale,
                    intptr_t class_id,
                    intptr_t deopt_id,
-                   intptr_t token_pos)
+                   TokenPosition token_pos)
       : TemplateDefinition(deopt_id),
         index_scale_(index_scale),
         class_id_(class_id),
@@ -3815,7 +3820,7 @@
     SetInputAt(1, index);
   }
 
-  intptr_t token_pos() const { return token_pos_; }
+  TokenPosition token_pos() const { return token_pos_; }
 
   DECLARE_INSTRUCTION(LoadIndexed)
   virtual CompileType ComputeType() const;
@@ -3848,7 +3853,7 @@
  private:
   const intptr_t index_scale_;
   const intptr_t class_id_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadIndexedInstr);
 };
@@ -3867,7 +3872,7 @@
                      Value* index,
                      intptr_t element_count,
                      intptr_t class_id,
-                     intptr_t token_pos)
+                     TokenPosition token_pos)
       : class_id_(class_id),
         token_pos_(token_pos),
         element_count_(element_count),
@@ -3878,7 +3883,7 @@
     SetInputAt(1, index);
   }
 
-  intptr_t token_pos() const { return token_pos_; }
+  TokenPosition token_pos() const { return token_pos_; }
 
   DECLARE_INSTRUCTION(LoadCodeUnits)
   virtual CompileType ComputeType() const;
@@ -3916,7 +3921,7 @@
 
  private:
   const intptr_t class_id_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const intptr_t element_count_;
   Representation representation_;
 
@@ -3979,7 +3984,7 @@
 
 class StringInterpolateInstr : public TemplateDefinition<1, Throws> {
  public:
-  StringInterpolateInstr(Value* value, intptr_t token_pos)
+  StringInterpolateInstr(Value* value, TokenPosition token_pos)
       : TemplateDefinition(Thread::Current()->GetNextDeoptId()),
         token_pos_(token_pos),
         function_(Function::ZoneHandle()) {
@@ -3987,7 +3992,7 @@
   }
 
   Value* value() const { return inputs_[0]; }
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   virtual CompileType ComputeType() const;
   // Issues a static call to Dart code which calls toString on objects.
@@ -4001,7 +4006,7 @@
   DECLARE_INSTRUCTION(StringInterpolate)
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   Function& function_;
 
   DISALLOW_COPY_AND_ASSIGN(StringInterpolateInstr);
@@ -4017,7 +4022,7 @@
                     intptr_t index_scale,
                     intptr_t class_id,
                     intptr_t deopt_id,
-                    intptr_t token_pos)
+                    TokenPosition token_pos)
       : TemplateDefinition(deopt_id),
         emit_store_barrier_(emit_store_barrier),
         index_scale_(index_scale),
@@ -4068,7 +4073,7 @@
   const StoreBarrierType emit_store_barrier_;
   const intptr_t index_scale_;
   const intptr_t class_id_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(StoreIndexedInstr);
 };
@@ -4099,7 +4104,7 @@
 
 class InstanceOfInstr : public TemplateDefinition<2, Throws> {
  public:
-  InstanceOfInstr(intptr_t token_pos,
+  InstanceOfInstr(TokenPosition token_pos,
                   Value* value,
                   Value* instantiator_type_arguments,
                   const AbstractType& type,
@@ -4122,16 +4127,16 @@
 
   bool negate_result() const { return negate_result_; }
   const AbstractType& type() const { return type_; }
-  virtual intptr_t token_pos() const { return token_pos_; }
-
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   virtual bool CanDeoptimize() const { return true; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   Value* value_;
   Value* type_arguments_;
   const AbstractType& type_;
@@ -4143,7 +4148,7 @@
 
 class AllocateObjectInstr : public TemplateDefinition<0, NoThrow> {
  public:
-  AllocateObjectInstr(intptr_t token_pos,
+  AllocateObjectInstr(TokenPosition token_pos,
                       const Class& cls,
                       ZoneGrowableArray<PushArgumentInstr*>* arguments)
       : token_pos_(token_pos),
@@ -4164,15 +4169,13 @@
   }
 
   const Class& cls() const { return cls_; }
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   const Function& closure_function() const { return closure_function_; }
   void set_closure_function(const Function& function) {
     closure_function_ ^= function.raw();
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
@@ -4180,8 +4183,10 @@
   virtual AliasIdentity Identity() const { return identity_; }
   virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const Class& cls_;
   ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
   AliasIdentity identity_;
@@ -4194,7 +4199,7 @@
 class AllocateUninitializedContextInstr
     : public TemplateDefinition<0, NoThrow> {
  public:
-  AllocateUninitializedContextInstr(intptr_t token_pos,
+  AllocateUninitializedContextInstr(TokenPosition token_pos,
                                     intptr_t num_context_variables)
       : token_pos_(token_pos),
         num_context_variables_(num_context_variables),
@@ -4203,11 +4208,9 @@
   DECLARE_INSTRUCTION(AllocateUninitializedContext)
   virtual CompileType ComputeType() const;
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   intptr_t num_context_variables() const { return num_context_variables_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
@@ -4215,8 +4218,10 @@
   virtual AliasIdentity Identity() const { return identity_; }
   virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const intptr_t num_context_variables_;
   AliasIdentity identity_;
 
@@ -4283,7 +4288,6 @@
   }
 
   DECLARE_INSTRUCTION(MaterializeObject)
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual intptr_t InputCount() const {
     return values_->length();
@@ -4319,6 +4323,8 @@
     visited_for_liveness_ = true;
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     (*values_)[i] = value;
@@ -4340,7 +4346,7 @@
 
 class CreateArrayInstr : public TemplateDefinition<2, Throws> {
  public:
-  CreateArrayInstr(intptr_t token_pos,
+  CreateArrayInstr(TokenPosition token_pos,
                    Value* element_type,
                    Value* num_elements)
       : TemplateDefinition(Thread::Current()->GetNextDeoptId()),
@@ -4358,7 +4364,7 @@
   DECLARE_INSTRUCTION(CreateArray)
   virtual CompileType ComputeType() const;
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   Value* element_type() const { return inputs_[kElementTypePos]; }
   Value* num_elements() const { return inputs_[kLengthPos]; }
 
@@ -4372,7 +4378,7 @@
   virtual void SetIdentity(AliasIdentity identity) { identity_ = identity; }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   AliasIdentity identity_;
 
   DISALLOW_COPY_AND_ASSIGN(CreateArrayInstr);
@@ -4450,7 +4456,7 @@
   LoadFieldInstr(Value* instance,
                  intptr_t offset_in_bytes,
                  const AbstractType& type,
-                 intptr_t token_pos)
+                 TokenPosition token_pos)
       : offset_in_bytes_(offset_in_bytes),
         type_(type),
         result_cid_(kDynamicCid),
@@ -4467,7 +4473,7 @@
   LoadFieldInstr(Value* instance,
                  const Field* field,
                  const AbstractType& type,
-                 intptr_t token_pos)
+                 TokenPosition token_pos)
       : offset_in_bytes_(field->Offset()),
         type_(type),
         result_cid_(kDynamicCid),
@@ -4488,7 +4494,7 @@
   const AbstractType& type() const { return type_; }
   void set_result_cid(intptr_t value) { result_cid_ = value; }
   intptr_t result_cid() const { return result_cid_; }
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   const Field* field() const { return field_; }
 
@@ -4509,8 +4515,6 @@
   DECLARE_INSTRUCTION(LoadField)
   virtual CompileType ComputeType() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual void InferRange(RangeAnalysis* analysis, Range* range);
@@ -4528,6 +4532,8 @@
   virtual EffectSet Dependencies() const;
   virtual bool AttributesEqual(Instruction* other) const;
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const intptr_t offset_in_bytes_;
   const AbstractType& type_;
@@ -4536,7 +4542,7 @@
 
   MethodRecognizer::Kind recognized_kind_;
   const Field* field_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadFieldInstr);
 };
@@ -4544,7 +4550,7 @@
 
 class InstantiateTypeInstr : public TemplateDefinition<1, Throws> {
  public:
-  InstantiateTypeInstr(intptr_t token_pos,
+  InstantiateTypeInstr(TokenPosition token_pos,
                        const AbstractType& type,
                        const Class& instantiator_class,
                        Value* instantiator)
@@ -4562,16 +4568,16 @@
   const AbstractType& type() const { return type_;
   }
   const Class& instantiator_class() const { return instantiator_class_; }
-  virtual intptr_t token_pos() const { return token_pos_; }
-
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   virtual bool CanDeoptimize() const { return true; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const AbstractType& type_;
   const Class& instantiator_class_;
 
@@ -4581,7 +4587,7 @@
 
 class InstantiateTypeArgumentsInstr : public TemplateDefinition<1, Throws> {
  public:
-  InstantiateTypeArgumentsInstr(intptr_t token_pos,
+  InstantiateTypeArgumentsInstr(TokenPosition token_pos,
                                 const TypeArguments& type_arguments,
                                 const Class& instantiator_class,
                                 Value* instantiator)
@@ -4600,9 +4606,7 @@
     return type_arguments_;
   }
   const Class& instantiator_class() const { return instantiator_class_; }
-  virtual intptr_t token_pos() const { return token_pos_; }
-
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   virtual bool CanDeoptimize() const { return true; }
 
@@ -4610,8 +4614,10 @@
 
   virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const TypeArguments& type_arguments_;
   const Class& instantiator_class_;
 
@@ -4621,7 +4627,7 @@
 
 class AllocateContextInstr : public TemplateDefinition<0, NoThrow> {
  public:
-  AllocateContextInstr(intptr_t token_pos,
+  AllocateContextInstr(TokenPosition token_pos,
                        intptr_t num_context_variables)
       : token_pos_(token_pos),
         num_context_variables_(num_context_variables) { }
@@ -4629,17 +4635,17 @@
   DECLARE_INSTRUCTION(AllocateContext)
   virtual CompileType ComputeType() const;
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   intptr_t num_context_variables() const { return num_context_variables_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const intptr_t num_context_variables_;
 
   DISALLOW_COPY_AND_ASSIGN(AllocateContextInstr);
@@ -4652,9 +4658,12 @@
       : TemplateInstruction(Thread::Current()->GetNextDeoptId()),
         field_(field) {
     SetInputAt(0, input);
+    CheckField(field);
   }
 
-  virtual intptr_t token_pos() const { return field_.token_pos(); }
+  virtual TokenPosition token_pos() const {
+    return field_.token_pos();
+  }
   const Field& field() const { return field_; }
 
   DECLARE_INSTRUCTION(InitStaticField)
@@ -4672,13 +4681,13 @@
 
 class CloneContextInstr : public TemplateDefinition<1, NoThrow> {
  public:
-  CloneContextInstr(intptr_t token_pos, Value* context_value)
+  CloneContextInstr(TokenPosition token_pos, Value* context_value)
       : TemplateDefinition(Thread::Current()->GetNextDeoptId()),
         token_pos_(token_pos) {
     SetInputAt(0, context_value);
   }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   Value* context_value() const { return inputs_[0]; }
 
   DECLARE_INSTRUCTION(CloneContext)
@@ -4689,7 +4698,7 @@
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(CloneContextInstr);
 };
@@ -4809,8 +4818,8 @@
 
   Definition* Canonicalize(FlowGraph* flow_graph);
 
-  virtual intptr_t token_pos() const {
-    return ClassifyingTokenPositions::kBox;
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kBox;
   }
 
  protected:
@@ -4935,8 +4944,8 @@
     return GetDeoptId();
   }
 
-  virtual intptr_t token_pos() const {
-    return ClassifyingTokenPositions::kBox;
+  virtual TokenPosition token_pos() const {
+    return TokenPosition::kBox;
   }
 
  protected:
@@ -4991,10 +5000,10 @@
 
   virtual Definition* Canonicalize(FlowGraph* flow_graph);
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   DEFINE_INSTRUCTION_TYPE_CHECK(UnboxInteger)
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   bool is_truncating_;
 
@@ -5099,8 +5108,6 @@
   MathUnaryKind kind() const { return kind_; }
   const RuntimeEntry& TargetFunction() const;
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5129,6 +5136,8 @@
 
   static const char* KindToCString(MathUnaryKind kind);
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MathUnaryKind kind_;
 
@@ -5255,7 +5264,7 @@
                       Value* left,
                       Value* right,
                       intptr_t deopt_id,
-                      intptr_t token_pos)
+                      TokenPosition token_pos)
       : TemplateDefinition(deopt_id),
         op_kind_(op_kind),
         token_pos_(token_pos) {
@@ -5268,9 +5277,7 @@
 
   Token::Kind op_kind() const { return op_kind_; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
-
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   virtual bool CanDeoptimize() const { return false; }
 
@@ -5289,6 +5296,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(BinaryDoubleOp)
   virtual CompileType ComputeType() const;
 
@@ -5300,7 +5309,7 @@
 
  private:
   const Token::Kind op_kind_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(BinaryDoubleOpInstr);
 };
@@ -5322,8 +5331,6 @@
 
   Token::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5348,6 +5355,8 @@
     return op_kind() == other->AsBinaryFloat32x4Op()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Token::Kind op_kind_;
 
@@ -5370,8 +5379,6 @@
 
   intptr_t mask() const { return mask_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5407,6 +5414,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Simd32x4Shuffle)
   virtual CompileType ComputeType() const;
 
@@ -5439,8 +5448,6 @@
 
   intptr_t mask() const { return mask_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5466,6 +5473,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Simd32x4ShuffleMix)
   virtual CompileType ComputeType() const;
 
@@ -5501,8 +5510,6 @@
   Value* value2() const { return inputs_[2]; }
   Value* value3() const { return inputs_[3]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5525,6 +5532,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4ConstructorInstr);
 };
@@ -5539,8 +5548,6 @@
 
   Value* value() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5563,6 +5570,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4SplatInstr);
 };
@@ -5605,8 +5614,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5631,6 +5638,8 @@
     return op_kind() == other->AsFloat32x4Comparison()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5654,8 +5663,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5680,6 +5687,8 @@
     return op_kind() == other->AsFloat32x4MinMax()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5703,8 +5712,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5732,6 +5739,8 @@
     return op_kind() == other->AsFloat32x4Scale()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5752,8 +5761,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5778,6 +5785,8 @@
     return op_kind() == other->AsFloat32x4Sqrt()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5800,8 +5809,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5826,6 +5833,8 @@
     return op_kind() == other->AsFloat32x4ZeroArg()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5849,8 +5858,6 @@
   Value* lower() const { return inputs_[1]; }
   Value* upper() const { return inputs_[2]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5873,6 +5880,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4ClampInstr);
 };
@@ -5895,8 +5904,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5924,6 +5931,8 @@
     return op_kind() == other->AsFloat32x4With()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -5947,8 +5956,6 @@
 
   intptr_t mask() const { return mask_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -5984,6 +5991,8 @@
            (mask() == other->AsSimd64x2Shuffle()->mask());
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
   const intptr_t mask_;
@@ -6001,8 +6010,6 @@
 
   Value* left() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6025,6 +6032,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4ToInt32x4Instr);
 };
@@ -6039,8 +6048,6 @@
 
   Value* left() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6063,6 +6070,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float32x4ToFloat64x2Instr);
 };
@@ -6077,8 +6086,6 @@
 
   Value* left() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6101,6 +6108,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float64x2ToFloat32x4Instr);
 };
@@ -6117,8 +6126,6 @@
   Value* value0() const { return inputs_[0]; }
   Value* value1() const { return inputs_[1]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6136,6 +6143,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Float64x2Constructor)
   virtual CompileType ComputeType() const;
 
@@ -6155,8 +6164,6 @@
 
   Value* value() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6179,6 +6186,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Float64x2SplatInstr);
 };
@@ -6218,8 +6227,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6241,6 +6248,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Float64x2ZeroArg)
   virtual CompileType ComputeType() const;
 
@@ -6271,8 +6280,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6298,6 +6305,8 @@
     return GetDeoptId();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
   DECLARE_INSTRUCTION(Float64x2OneArg)
   virtual CompileType ComputeType() const;
 
@@ -6331,8 +6340,6 @@
   Value* value2() const { return inputs_[2]; }
   Value* value3() const { return inputs_[3]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6355,6 +6362,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Int32x4ConstructorInstr);
 };
@@ -6380,8 +6389,6 @@
   Value* value2() const { return inputs_[2]; }
   Value* value3() const { return inputs_[3]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6404,6 +6411,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Int32x4BoolConstructorInstr);
 };
@@ -6422,8 +6431,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6448,6 +6455,8 @@
     return op_kind() == other->AsInt32x4GetFlag()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -6468,8 +6477,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6498,6 +6505,8 @@
     return other->AsSimd32x4GetSignMask()->op_kind() == op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -6521,8 +6530,6 @@
   Value* trueValue() const { return inputs_[1]; }
   Value* falseValue() const { return inputs_[2]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6548,6 +6555,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Int32x4SelectInstr);
 };
@@ -6569,8 +6578,6 @@
 
   MethodRecognizer::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6598,6 +6605,8 @@
     return op_kind() == other->AsInt32x4SetFlag()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const MethodRecognizer::Kind op_kind_;
 
@@ -6614,8 +6623,6 @@
 
   Value* left() const { return inputs_[0]; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6638,6 +6645,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   DISALLOW_COPY_AND_ASSIGN(Int32x4ToFloat32x4Instr);
 };
@@ -6659,8 +6668,6 @@
 
   Token::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual bool CanDeoptimize() const { return false; }
 
   virtual Representation representation() const {
@@ -6685,6 +6692,8 @@
     return op_kind() == other->AsBinaryInt32x4Op()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Token::Kind op_kind_;
 
@@ -6719,8 +6728,6 @@
     return kUnboxedFloat64x2;
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual intptr_t DeoptimizationTarget() const {
     // Direct access since this instruction cannot deoptimize, and the deopt-id
     // was inherited from another instruction that could deoptimize.
@@ -6734,6 +6741,8 @@
     return op_kind() == other->AsBinaryFloat64x2Op()->op_kind();
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Token::Kind op_kind_;
 
@@ -6771,7 +6780,7 @@
     return GetDeoptId();
   }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
   RawInteger* Evaluate(const Integer& value) const;
 
@@ -6838,7 +6847,7 @@
   }
 
   virtual bool CanDeoptimize() const {
-    return FLAG_throw_on_javascript_int_overflow;
+    return false;
   }
 
   virtual CompileType ComputeType() const;
@@ -6930,7 +6939,8 @@
 
   virtual intptr_t DeoptimizationTarget() const { return GetDeoptId(); }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+  PRINT_OPERANDS_TO_SUPPORT
 
   DEFINE_INSTRUCTION_TYPE_CHECK(BinaryIntegerOp)
 
@@ -7097,8 +7107,7 @@
   }
 
   virtual bool CanDeoptimize() const {
-    return FLAG_throw_on_javascript_int_overflow
-        || (can_overflow() && ((op_kind() == Token::kADD) ||
+    return (can_overflow() && ((op_kind() == Token::kADD) ||
                                (op_kind() == Token::kSUB)))
         || (op_kind() == Token::kMUL);  // Deopt if inputs are not int32.
   }
@@ -7133,8 +7142,7 @@
   }
 
   virtual bool CanDeoptimize() const {
-    return FLAG_throw_on_javascript_int_overflow
-        || has_shift_count_check()
+    return  has_shift_count_check()
         || (can_overflow() && (op_kind() == Token::kSHL));
   }
 
@@ -7173,8 +7181,6 @@
   Value* value() const { return inputs_[0]; }
   Token::Kind op_kind() const { return op_kind_; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   DECLARE_INSTRUCTION(UnaryDoubleOp)
   virtual CompileType ComputeType() const;
 
@@ -7197,6 +7203,8 @@
 
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Token::Kind op_kind_;
 
@@ -7206,13 +7214,13 @@
 
 class CheckStackOverflowInstr : public TemplateInstruction<0, NoThrow> {
  public:
-  CheckStackOverflowInstr(intptr_t token_pos, intptr_t loop_depth)
+  CheckStackOverflowInstr(TokenPosition token_pos, intptr_t loop_depth)
       : TemplateInstruction(Thread::Current()->GetNextDeoptId()),
         token_pos_(token_pos),
         loop_depth_(loop_depth) {
   }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
   bool in_loop() const { return loop_depth_ > 0; }
   intptr_t loop_depth() const { return loop_depth_; }
 
@@ -7222,10 +7230,10 @@
 
   virtual EffectSet Effects() const { return EffectSet::None(); }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const intptr_t loop_depth_;
 
   DISALLOW_COPY_AND_ASSIGN(CheckStackOverflowInstr);
@@ -7235,13 +7243,13 @@
 // TODO(vegorov): remove this instruction in favor of Int32ToDouble.
 class SmiToDoubleInstr : public TemplateDefinition<1, NoThrow, Pure> {
  public:
-  SmiToDoubleInstr(Value* value, intptr_t token_pos)
+  SmiToDoubleInstr(Value* value, TokenPosition token_pos)
       : token_pos_(token_pos) {
     SetInputAt(0, value);
   }
 
   Value* value() const { return inputs_[0]; }
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   DECLARE_INSTRUCTION(SmiToDouble)
   virtual CompileType ComputeType() const;
@@ -7255,7 +7263,7 @@
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(SmiToDoubleInstr);
 };
@@ -7502,7 +7510,7 @@
   InvokeMathCFunctionInstr(ZoneGrowableArray<Value*>* inputs,
                            intptr_t deopt_id,
                            MethodRecognizer::Kind recognized_kind,
-                           intptr_t token_pos);
+                           TokenPosition token_pos);
 
   static intptr_t ArgumentCountFor(MethodRecognizer::Kind recognized_kind_);
 
@@ -7510,11 +7518,10 @@
 
   MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   DECLARE_INSTRUCTION(InvokeMathCFunction)
   virtual CompileType ComputeType() const;
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const { return false; }
 
@@ -7548,6 +7555,8 @@
   static const intptr_t kObjectTempIndex = 1;
   static const intptr_t kDoubleTempIndex = 2;
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     (*inputs_)[i] = value;
@@ -7555,7 +7564,7 @@
 
   ZoneGrowableArray<Value*>* inputs_;
   const MethodRecognizer::Kind recognized_kind_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(InvokeMathCFunctionInstr);
 };
@@ -7579,7 +7588,6 @@
   DECLARE_INSTRUCTION(ExtractNthOutput)
 
   virtual CompileType ComputeType() const;
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
   virtual bool CanDeoptimize() const { return false; }
 
   intptr_t index() const { return index_; }
@@ -7605,6 +7613,8 @@
            (other_extract->index() == index());
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const intptr_t index_;
   const Representation definition_rep_;
@@ -7647,7 +7657,6 @@
   static intptr_t OutputIndexOf(Token::Kind token);
 
   virtual CompileType ComputeType() const;
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
 
   virtual bool CanDeoptimize() const {
     if (kind_ == kTruncDivMod) {
@@ -7701,6 +7710,8 @@
     return "";
   }
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   virtual void RawSetInputAt(intptr_t i, Value* value) {
     (*inputs_)[i] = value;
@@ -7716,13 +7727,13 @@
   CheckClassInstr(Value* value,
                   intptr_t deopt_id,
                   const ICData& unary_checks,
-                  intptr_t token_pos);
+                  TokenPosition token_pos);
 
   DECLARE_INSTRUCTION(CheckClass)
 
   virtual bool CanDeoptimize() const { return true; }
 
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   Value* value() const { return inputs_[0]; }
 
@@ -7732,8 +7743,6 @@
 
   virtual Instruction* Canonicalize(FlowGraph* flow_graph);
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   bool IsNullCheck() const {
     return  DeoptIfNull() || DeoptIfNotNull();
   }
@@ -7754,11 +7763,13 @@
 
   static bool IsImmutableClassId(intptr_t cid);
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const ICData& unary_checks_;
   GrowableArray<intptr_t> cids_;  // Sorted, lowest first.
   bool licm_hoisted_;
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
 
   DISALLOW_COPY_AND_ASSIGN(CheckClassInstr);
 };
@@ -7766,7 +7777,7 @@
 
 class CheckSmiInstr : public TemplateInstruction<1, NoThrow, Pure> {
  public:
-  CheckSmiInstr(Value* value, intptr_t deopt_id, intptr_t token_pos)
+  CheckSmiInstr(Value* value, intptr_t deopt_id, TokenPosition token_pos)
       : TemplateInstruction(deopt_id),
         token_pos_(token_pos),
         licm_hoisted_(false) {
@@ -7774,7 +7785,7 @@
   }
 
   Value* value() const { return inputs_[0]; }
-  virtual intptr_t token_pos() const { return token_pos_; }
+  virtual TokenPosition token_pos() const { return token_pos_; }
 
   DECLARE_INSTRUCTION(CheckSmi)
 
@@ -7787,7 +7798,7 @@
   void set_licm_hoisted(bool value) { licm_hoisted_ = value; }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   bool licm_hoisted_;
 
   DISALLOW_COPY_AND_ASSIGN(CheckSmiInstr);
@@ -7815,7 +7826,7 @@
   virtual EffectSet Effects() const { return EffectSet::None(); }
   virtual bool AttributesEqual(Instruction* other) const { return true; }
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
+  PRINT_OPERANDS_TO_SUPPORT
 
  private:
   intptr_t cid_;
@@ -7925,8 +7936,6 @@
 
   virtual void InferRange(RangeAnalysis* analysis, Range* range);
 
-  virtual void PrintOperandsTo(BufferFormatter* f) const;
-
   virtual CompileType ComputeType() const {
     // TODO(vegorov) use range information to improve type.
     return CompileType::Int();
@@ -7934,6 +7943,8 @@
 
   DECLARE_INSTRUCTION(UnboxedIntConverter);
 
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const Representation from_representation_;
   const Representation to_representation_;
@@ -8182,7 +8193,7 @@
 class FlowGraphVisitor : public ValueObject {
  public:
   explicit FlowGraphVisitor(const GrowableArray<BlockEntryInstr*>& block_order)
-      : block_order_(block_order), current_iterator_(NULL) { }
+      : current_iterator_(NULL), block_order_(block_order) { }
   virtual ~FlowGraphVisitor() { }
 
   ForwardInstructionIterator* current_iterator() const {
@@ -8203,10 +8214,10 @@
 #undef DECLARE_VISIT_INSTRUCTION
 
  protected:
-  const GrowableArray<BlockEntryInstr*>& block_order_;
   ForwardInstructionIterator* current_iterator_;
 
  private:
+  const GrowableArray<BlockEntryInstr*>& block_order_;
   DISALLOW_COPY_AND_ASSIGN(FlowGraphVisitor);
 };
 
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 9120195..df31e31 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -7,8 +7,8 @@
 
 #include "vm/intermediate_language.h"
 
-#include "vm/cpu.h"
 #include "vm/compiler.h"
+#include "vm/cpu.h"
 #include "vm/dart_entry.h"
 #include "vm/flow_graph.h"
 #include "vm/flow_graph_compiler.h"
@@ -22,14 +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, 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) {
@@ -369,7 +365,7 @@
 
 
 static void EmitAssertBoolean(Register reg,
-                              intptr_t token_pos,
+                              TokenPosition token_pos,
                               intptr_t deopt_id,
                               LocationSummary* locs,
                               FlowGraphCompiler* compiler) {
@@ -378,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);
   }
@@ -942,15 +938,13 @@
   // into the runtime system.
   uword entry;
   const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
-  const bool is_leaf_call =
-      (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
   const StubEntry* stub_entry;
   if (link_lazily()) {
     stub_entry = StubCode::CallBootstrapCFunction_entry();
     entry = NativeEntry::LinkNativeCallEntry();
   } else {
     entry = reinterpret_cast<uword>(native_c_function());
-    if (is_bootstrap_native() || is_leaf_call) {
+    if (is_bootstrap_native()) {
       stub_entry = StubCode::CallBootstrapCFunction_entry();
 #if defined(USING_SIMULATOR)
       entry = Simulator::RedirectExternalReference(
@@ -961,12 +955,6 @@
       // stub generates the redirection address when running under the simulator
       // and hence we do not change 'entry' here.
       stub_entry = StubCode::CallNativeCFunction_entry();
-#if defined(USING_SIMULATOR)
-      if (!function().IsNativeAutoSetupScope()) {
-        entry = Simulator::RedirectExternalReference(
-            entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
-      }
-#endif
     }
   }
   __ LoadImmediate(R1, argc_tag);
@@ -1591,6 +1579,10 @@
   const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
 
   if (field_cid == kDynamicCid) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1619,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(
@@ -1745,6 +1737,10 @@
 
 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   if (field().guarded_list_length() == Field::kNoFixedLength) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1762,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()));
@@ -1822,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(
@@ -1834,7 +1830,7 @@
     locs->live_registers()->Remove(Location::RegisterLocation(result_));
 
     compiler->SaveLiveRegisters(locs);
-    compiler->GenerateCall(Scanner::kNoSourcePos,  // No token position.
+    compiler->GenerateCall(TokenPosition::kNoSource,  // No token position.
                            stub_entry,
                            RawPcDescriptors::kOther,
                            locs);
@@ -2119,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);
@@ -2259,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()),
@@ -2377,7 +2373,7 @@
   ASSERT(locs()->in(kLengthPos).reg() == kLengthReg);
 
   if (compiler->is_optimizing() &&
-      !Compiler::always_optimize() &&
+      !FLAG_precompiled_mode &&
       num_elements()->BindsToConstant() &&
       num_elements()->BoundConstant().IsSmi()) {
     const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2481,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,
@@ -2882,10 +2878,15 @@
       const Register value = instruction_->locs()->temp(0).reg();
       __ Comment("CheckStackOverflowSlowPathOsr");
       __ Bind(osr_entry_label());
-      ASSERT(FLAG_allow_absolute_addresses);
-      __ LoadImmediate(IP, flags_address);
-      __ LoadImmediate(value, Isolate::kOsrRequest);
-      __ str(value, Address(IP));
+      if (FLAG_allow_absolute_addresses) {
+        __ LoadImmediate(IP, flags_address);
+        __ LoadImmediate(value, Isolate::kOsrRequest);
+        __ str(value, Address(IP));
+      } else {
+        __ LoadIsolate(IP);
+        __ LoadImmediate(value, Isolate::kOsrRequest);
+        __ str(value, Address(IP, Isolate::stack_overflow_flags_offset()));
+      }
     }
     __ Comment("CheckStackOverflowSlowPath");
     __ Bind(entry_label());
@@ -2905,7 +2906,7 @@
       // In unoptimized code, record loop stack checks as possible OSR entries.
       compiler->AddCurrentDescriptor(RawPcDescriptors::kOsrEntry,
                                      instruction_->deopt_id(),
-                                     0);  // No token position.
+                                     TokenPosition::kNoSource);
     }
     compiler->pending_deoptimization_env_ = NULL;
     compiler->RestoreLiveRegisters(instruction_->locs());
@@ -6068,27 +6069,6 @@
 }
 
 
-static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler,
-                                           Label* overflow,
-                                           Register result_lo,
-                                           Register result_hi) {
-  // Compare upper half.
-  Label check_lower;
-  __ CompareImmediate(result_hi, 0x00200000);
-  __ b(overflow, GT);
-  __ b(&check_lower, NE);
-
-  __ CompareImmediate(result_lo, 0);
-  __ b(overflow, HI);
-
-  __ Bind(&check_lower);
-  __ CompareImmediate(result_hi, -0x00200000);
-  __ b(overflow, LT);
-  // Anything in the lower part would make the number bigger than the lower
-  // bound, so we are done.
-}
-
-
 LocationSummary* BinaryMintOpInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 2;
@@ -6166,9 +6146,6 @@
     default:
       UNREACHABLE();
   }
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi);
-  }
 }
 
 
@@ -6314,10 +6291,6 @@
         UNREACHABLE();
     }
   }
-
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi);
-  }
 }
 
 
@@ -6344,17 +6317,8 @@
   PairLocation* out_pair = locs()->out(0).AsPairLocation();
   Register out_lo = out_pair->At(0).reg();
   Register out_hi = out_pair->At(1).reg();
-
-  Label* deopt = NULL;
-
-  if (FLAG_throw_on_javascript_int_overflow) {
-    deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp);
-  }
   __ mvn(out_lo, Operand(left_lo));
   __ mvn(out_hi, Operand(left_hi));
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptIntOverflowCheck(compiler, deopt, out_lo, out_hi);
-  }
 }
 
 
@@ -6651,7 +6615,7 @@
     // may be inserted before this instruction.
     compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
                                    GetDeoptId(),
-                                   Scanner::kNoSourcePos);
+                                   TokenPosition::kNoSource);
   }
   if (HasParallelMove()) {
     compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -6854,7 +6818,7 @@
   const Register result = locs()->out(0).reg();
   __ PushObject(Object::null_object());
   __ Push(typed_data);
-  compiler->GenerateRuntimeCall(Scanner::kNoSourcePos,  // No token position.
+  compiler->GenerateRuntimeCall(TokenPosition::kNoSource,
                                 deopt_id(),
                                 kGrowRegExpStackRuntimeEntry,
                                 1,
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 05ce132..79296b3 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -21,14 +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, 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) {
@@ -357,7 +353,7 @@
 
 
 static void EmitAssertBoolean(Register reg,
-                              intptr_t token_pos,
+                              TokenPosition token_pos,
                               intptr_t deopt_id,
                               LocationSummary* locs,
                               FlowGraphCompiler* compiler) {
@@ -366,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);
   }
@@ -796,15 +792,13 @@
   // into the runtime system.
   uword entry;
   const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
-  const bool is_leaf_call =
-      (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
   const StubEntry* stub_entry;
   if (link_lazily()) {
     stub_entry = StubCode::CallBootstrapCFunction_entry();
     entry = NativeEntry::LinkNativeCallEntry();
   } else {
     entry = reinterpret_cast<uword>(native_c_function());
-    if (is_bootstrap_native() || is_leaf_call) {
+    if (is_bootstrap_native()) {
       stub_entry = StubCode::CallBootstrapCFunction_entry();
 #if defined(USING_SIMULATOR)
       entry = Simulator::RedirectExternalReference(
@@ -815,12 +809,6 @@
       // stub generates the redirection address when running under the simulator
       // and hence we do not change 'entry' here.
       stub_entry = StubCode::CallNativeCFunction_entry();
-#if defined(USING_SIMULATOR)
-      if (!function().IsNativeAutoSetupScope()) {
-        entry = Simulator::RedirectExternalReference(
-            entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
-      }
-#endif
     }
   }
   __ LoadImmediate(R1, argc_tag);
@@ -1448,6 +1436,10 @@
   const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
 
   if (field_cid == kDynamicCid) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1476,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);
@@ -1599,6 +1591,10 @@
 
 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   if (field().guarded_list_length() == Field::kNoFixedLength) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1616,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,
@@ -1674,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(),
@@ -1686,7 +1682,7 @@
     locs->live_registers()->Remove(Location::RegisterLocation(result_));
 
     compiler->SaveLiveRegisters(locs);
-    compiler->GenerateCall(Scanner::kNoSourcePos,  // No token position.
+    compiler->GenerateCall(TokenPosition::kNoSource,  // No token position.
                            stub_entry,
                            RawPcDescriptors::kOther,
                            locs);
@@ -1842,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);
@@ -1980,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());
@@ -2100,7 +2096,7 @@
   ASSERT(locs()->in(kLengthPos).reg() == kLengthReg);
 
   if (compiler->is_optimizing() &&
-      !Compiler::always_optimize() &&
+      !FLAG_precompiled_mode &&
       num_elements()->BindsToConstant() &&
       num_elements()->BoundConstant().IsSmi()) {
     const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2192,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);
@@ -2592,10 +2588,15 @@
       const Register value = instruction_->locs()->temp(0).reg();
       __ Comment("CheckStackOverflowSlowPathOsr");
       __ Bind(osr_entry_label());
-      ASSERT(FLAG_allow_absolute_addresses);
-      __ LoadImmediate(TMP, flags_address);
-      __ LoadImmediate(value, Isolate::kOsrRequest);
-      __ str(value, Address(TMP));
+      if (FLAG_allow_absolute_addresses) {
+        __ LoadImmediate(TMP, flags_address);
+        __ LoadImmediate(value, Isolate::kOsrRequest);
+        __ str(value, Address(TMP));
+      } else {
+        __ LoadIsolate(TMP);
+        __ LoadImmediate(value, Isolate::kOsrRequest);
+        __ str(value, Address(TMP, Isolate::stack_overflow_flags_offset()));
+      }
     }
     __ Comment("CheckStackOverflowSlowPath");
     __ Bind(entry_label());
@@ -2615,7 +2616,7 @@
       // In unoptimized code, record loop stack checks as possible OSR entries.
       compiler->AddCurrentDescriptor(RawPcDescriptors::kOsrEntry,
                                      instruction_->deopt_id(),
-                                     0);  // No token position.
+                                     TokenPosition::kNoSource);
     }
     compiler->pending_deoptimization_env_ = NULL;
     compiler->RestoreLiveRegisters(instruction_->locs());
@@ -2666,20 +2667,6 @@
 }
 
 
-static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler,
-                                        Range* range,
-                                        Label* overflow,
-                                        Register result) {
-  if (!RangeUtils::IsWithin(range, -0x20000000000000LL, 0x20000000000000LL)) {
-    ASSERT(overflow != NULL);
-    __ LoadImmediate(TMP, 0x20000000000000LL);
-    __ add(TMP2, result, Operand(TMP));
-    __ cmp(TMP2, Operand(TMP, LSL, 1));
-    __ b(overflow, HI);
-  }
-}
-
-
 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
                              BinarySmiOpInstr* shift_left) {
   const LocationSummary& locs = *shift_left->locs();
@@ -2703,9 +2690,6 @@
     }
     // Shift for result now we know there is no overflow.
     __ LslImmediate(result, left, value);
-    if (FLAG_throw_on_javascript_int_overflow) {
-      EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result);
-    }
     return;
   }
 
@@ -2735,9 +2719,6 @@
       __ SmiUntag(TMP, right);
       __ lslv(result, left, TMP);
     }
-    if (FLAG_throw_on_javascript_int_overflow) {
-      EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result);
-    }
     return;
   }
 
@@ -2782,9 +2763,6 @@
     // Shift for result now we know there is no overflow.
     __ lslv(result, left, TMP);
   }
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result);
-  }
 }
 
 
@@ -2920,9 +2898,6 @@
         UNREACHABLE();
         break;
     }
-    if (FLAG_throw_on_javascript_int_overflow) {
-      EmitJavascriptOverflowCheck(compiler, range(), deopt, result);
-    }
     return;
   }
 
@@ -3065,9 +3040,6 @@
       UNREACHABLE();
       break;
   }
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), deopt, result);
-  }
 }
 
 
@@ -4526,9 +4498,6 @@
       Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp);
       __ subs(result, ZR, Operand(value));
       __ b(deopt, VS);
-      if (FLAG_throw_on_javascript_int_overflow) {
-        EmitJavascriptOverflowCheck(compiler, range(), deopt, value);
-      }
       break;
     }
     case Token::kBIT_NOT:
@@ -4644,9 +4613,6 @@
   __ CompareImmediate(result, 0xC000000000000000);
   __ b(&do_call, MI);
   __ SmiTag(result);
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), &do_call, result);
-  }
   __ b(&done);
   __ Bind(&do_call);
   __ Push(value_obj);
@@ -4694,9 +4660,6 @@
   __ CompareImmediate(result, 0xC000000000000000);
   __ b(deopt, MI);
   __ SmiTag(result);
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), deopt, result);
-  }
 }
 
 
@@ -5010,9 +4973,6 @@
     __ add(TMP, result_mod, Operand(right));
     __ csel(result_mod, TMP, TMP2, GE);
     __ Bind(&done);
-    // FLAG_throw_on_javascript_int_overflow: not needed.
-    // Note that the result of an integer division/modulo of two
-    // in-range arguments, cannot create out-of-range result.
     return;
   }
   if (kind() == MergedMathInstr::kSinCos) {
@@ -5414,7 +5374,7 @@
     // may be inserted before this instruction.
     compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
                                    GetDeoptId(),
-                                   Scanner::kNoSourcePos);
+                                   TokenPosition::kNoSource);
   }
   if (HasParallelMove()) {
     compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -5616,7 +5576,7 @@
   const Register result = locs()->out(0).reg();
   __ PushObject(Object::null_object());
   __ Push(typed_data);
-  compiler->GenerateRuntimeCall(Scanner::kNoSourcePos,  // No token position.
+  compiler->GenerateRuntimeCall(TokenPosition::kNoSource,
                                 deopt_id(),
                                 kGrowRegExpStackRuntimeEntry,
                                 1,
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 0c2f782..bebb561 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -7,6 +7,7 @@
 
 #include "vm/intermediate_language.h"
 
+#include "vm/compiler.h"
 #include "vm/dart_entry.h"
 #include "vm/flow_graph.h"
 #include "vm/flow_graph_compiler.h"
@@ -19,14 +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, throw_on_javascript_int_overflow);
-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) {
@@ -242,7 +239,7 @@
 
 
 static void EmitAssertBoolean(Register reg,
-                              intptr_t token_pos,
+                              TokenPosition token_pos,
                               intptr_t deopt_id,
                               LocationSummary* locs,
                               FlowGraphCompiler* compiler) {
@@ -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);
   }
@@ -440,27 +437,6 @@
 }
 
 
-static void EmitJavascriptIntOverflowCheck(FlowGraphCompiler* compiler,
-                                           Label* overflow,
-                                           Register result_lo,
-                                           Register result_hi) {
-  // Compare upper half.
-  Label check_lower;
-  __ cmpl(result_hi, Immediate(0x00200000));
-  __ j(GREATER, overflow);
-  __ j(NOT_EQUAL, &check_lower);
-
-  __ cmpl(result_lo, Immediate(0));
-  __ j(ABOVE, overflow);
-
-  __ Bind(&check_lower);
-  __ cmpl(result_hi, Immediate(-0x00200000));
-  __ j(LESS, overflow);
-  // Anything in the lower part would make the number bigger than the lower
-  // bound, so we are done.
-}
-
-
 static Condition TokenKindToMintCondition(Token::Kind kind) {
   switch (kind) {
     case Token::kEQ: return EQUAL;
@@ -820,8 +796,6 @@
   SetupNative();
   Register result = locs()->out(0).reg();
   const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
-  const bool is_leaf_call =
-      (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
 
   // Push the result place holder initialized to NULL.
   __ PushObject(Object::null_object());
@@ -839,7 +813,7 @@
     stub_entry = StubCode::CallBootstrapCFunction_entry();
     __ movl(ECX, Immediate(NativeEntry::LinkNativeCallEntry()));
   } else {
-    stub_entry = (is_bootstrap_native() || is_leaf_call) ?
+    stub_entry = (is_bootstrap_native()) ?
         StubCode::CallBootstrapCFunction_entry() :
         StubCode::CallNativeCFunction_entry();
     const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
@@ -1436,6 +1410,10 @@
   const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
 
   if (field_cid == kDynamicCid) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1464,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(
@@ -1591,6 +1569,10 @@
 
 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   if (field().guarded_list_length() == Field::kNoFixedLength) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1608,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()));
@@ -1663,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(
@@ -1675,7 +1657,7 @@
     locs->live_registers()->Remove(Location::RegisterLocation(result_));
 
     compiler->SaveLiveRegisters(locs);
-    compiler->GenerateCall(Scanner::kNoSourcePos,  // No token position.
+    compiler->GenerateCall(TokenPosition::kNoSource,
                            stub_entry,
                            RawPcDescriptors::kOther,
                            locs);
@@ -1848,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));
@@ -1994,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()),
@@ -2217,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());
@@ -2625,7 +2607,7 @@
       // In unoptimized code, record loop stack checks as possible OSR entries.
       compiler->AddCurrentDescriptor(RawPcDescriptors::kOsrEntry,
                                      instruction_->deopt_id(),
-                                     0);  // No token position.
+                                     TokenPosition::kNoSource);
     }
     compiler->pending_deoptimization_env_ = NULL;
     compiler->RestoreLiveRegisters(instruction_->locs());
@@ -6028,9 +6010,6 @@
     default:
       UNREACHABLE();
   }
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
-  }
 }
 
 
@@ -6230,9 +6209,6 @@
     }
     __ Bind(&done);
   }
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
-  }
 }
 
 
@@ -6245,9 +6221,6 @@
   summary->set_in(0, Location::Pair(Location::RequiresRegister(),
                                     Location::RequiresRegister()));
   summary->set_out(0, Location::SameAsFirstInput());
-  if (FLAG_throw_on_javascript_int_overflow) {
-    summary->set_temp(0, Location::RequiresRegister());
-  }
   return summary;
 }
 
@@ -6262,18 +6235,8 @@
   Register out_hi = out_pair->At(1).reg();
   ASSERT(out_lo == left_lo);
   ASSERT(out_hi == left_hi);
-
-  Label* deopt = NULL;
-  if (FLAG_throw_on_javascript_int_overflow) {
-    deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp);
-  }
-
   __ notl(left_lo);
   __ notl(left_hi);
-
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptIntOverflowCheck(compiler, deopt, left_lo, left_hi);
-  }
 }
 
 
@@ -6551,7 +6514,7 @@
     // may be inserted before this instruction.
     compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
                                    GetDeoptId(),
-                                   Scanner::kNoSourcePos);
+                                   TokenPosition::kNoSource);
   }
   if (HasParallelMove()) {
     compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -6862,7 +6825,7 @@
   const Register result = locs()->out(0).reg();
   __ PushObject(Object::null_object());
   __ pushl(typed_data);
-  compiler->GenerateRuntimeCall(Scanner::kNoSourcePos,  // No token position.
+  compiler->GenerateRuntimeCall(TokenPosition::kNoSource,
                                 deopt_id(),
                                 kGrowRegExpStackRuntimeEntry,
                                 1,
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index e403445..f4b8032 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -21,14 +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, 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) {
@@ -418,7 +414,7 @@
 
 
 static void EmitAssertBoolean(Register reg,
-                              intptr_t token_pos,
+                              TokenPosition token_pos,
                               intptr_t deopt_id,
                               LocationSummary* locs,
                               FlowGraphCompiler* compiler) {
@@ -427,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);
   }
 
@@ -993,15 +989,13 @@
   // into the runtime system.
   uword entry;
   const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
-  const bool is_leaf_call =
-      (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
   const StubEntry* stub_entry;
   if (link_lazily()) {
     stub_entry = StubCode::CallBootstrapCFunction_entry();
     entry = NativeEntry::LinkNativeCallEntry();
   } else {
     entry = reinterpret_cast<uword>(native_c_function());
-    if (is_bootstrap_native() || is_leaf_call) {
+    if (is_bootstrap_native()) {
       stub_entry = StubCode::CallBootstrapCFunction_entry();
 #if defined(USING_SIMULATOR)
       entry = Simulator::RedirectExternalReference(
@@ -1012,12 +1006,6 @@
       // stub generates the redirection address when running under the simulator
       // and hence we do not change 'entry' here.
       stub_entry = StubCode::CallNativeCFunction_entry();
-#if defined(USING_SIMULATOR)
-      if (!function().IsNativeAutoSetupScope()) {
-        entry = Simulator::RedirectExternalReference(
-            entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
-      }
-#endif
     }
   }
   __ LoadImmediate(A1, argc_tag);
@@ -1622,6 +1610,10 @@
   const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
 
   if (field_cid == kDynamicCid) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1650,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(
@@ -1776,6 +1768,10 @@
 
 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   if (field().guarded_list_length() == Field::kNoFixedLength) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1791,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()));
@@ -1848,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(
@@ -1859,7 +1855,7 @@
     locs->live_registers()->Remove(Location::RegisterLocation(result_));
 
     compiler->SaveLiveRegisters(locs);
-    compiler->GenerateCall(Scanner::kNoSourcePos,  // No token position.
+    compiler->GenerateCall(TokenPosition::kNoSource,  // No token position.
                            stub_entry,
                            RawPcDescriptors::kOther,
                            locs);
@@ -2006,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);
@@ -2112,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()),
@@ -2231,7 +2227,7 @@
 
   Label slow_path, done;
   if (compiler->is_optimizing() &&
-      !Compiler::always_optimize() &&
+      !FLAG_precompiled_mode &&
       num_elements()->BindsToConstant() &&
       num_elements()->BoundConstant().IsSmi()) {
     const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2322,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,
@@ -2710,10 +2706,15 @@
       Register value = instruction_->locs()->temp(0).reg();
       __ Comment("CheckStackOverflowSlowPathOsr");
       __ Bind(osr_entry_label());
-      ASSERT(FLAG_allow_absolute_addresses);
-      __ LoadImmediate(TMP, flags_address);
-      __ LoadImmediate(value, Isolate::kOsrRequest);
-      __ sw(value, Address(TMP));
+      if (FLAG_allow_absolute_addresses) {
+        __ LoadImmediate(TMP, flags_address);
+        __ LoadImmediate(value, Isolate::kOsrRequest);
+        __ sw(value, Address(TMP));
+      } else {
+        __ LoadIsolate(TMP);
+        __ LoadImmediate(value, Isolate::kOsrRequest);
+        __ sw(value, Address(TMP, Isolate::stack_overflow_flags_offset()));
+      }
     }
     __ Comment("CheckStackOverflowSlowPath");
     __ Bind(entry_label());
@@ -2733,7 +2734,7 @@
       // In unoptimized code, record loop stack checks as possible OSR entries.
       compiler->AddCurrentDescriptor(RawPcDescriptors::kOsrEntry,
                                      instruction_->deopt_id(),
-                                     0);  // No token position.
+                                     TokenPosition::kNoSource);
     }
     compiler->pending_deoptimization_env_ = NULL;
     compiler->RestoreLiveRegisters(instruction_->locs());
@@ -5389,7 +5390,7 @@
     // may be inserted before this instruction.
     compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
                                    GetDeoptId(),
-                                   Scanner::kNoSourcePos);
+                                   TokenPosition::kNoSource);
   }
   if (HasParallelMove()) {
     compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -5591,7 +5592,7 @@
   __ LoadObject(TMP, Object::null_object());
   __ sw(TMP, Address(SP, 1 * kWordSize));
   __ sw(typed_data, Address(SP, 0 * kWordSize));
-  compiler->GenerateRuntimeCall(Scanner::kNoSourcePos,  // No token position.
+  compiler->GenerateRuntimeCall(TokenPosition::kNoSource,
                                 deopt_id(),
                                 kGrowRegExpStackRuntimeEntry,
                                 1,
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 7ca52de..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, throw_on_javascript_int_overflow);
-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 RAX.
 LocationSummary* Instruction::MakeCallSummary(Zone* zone) {
@@ -329,7 +324,7 @@
 
 
 static void EmitAssertBoolean(Register reg,
-                              intptr_t token_pos,
+                              TokenPosition token_pos,
                               intptr_t deopt_id,
                               LocationSummary* locs,
                               FlowGraphCompiler* compiler) {
@@ -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);
   }
@@ -775,8 +770,6 @@
   SetupNative();
   Register result = locs()->out(0).reg();
   const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
-  const bool is_leaf_call =
-      (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
 
   // Push the result place holder initialized to NULL.
   __ PushObject(Object::null_object());
@@ -794,9 +787,9 @@
     ExternalLabel label(NativeEntry::LinkNativeCallEntry());
     __ LoadNativeEntry(RBX, &label, kPatchable);
   } else {
-    stub_entry = (is_bootstrap_native() || is_leaf_call)
-        ? StubCode::CallBootstrapCFunction_entry()
-        : StubCode::CallNativeCFunction_entry();
+    stub_entry = (is_bootstrap_native()) ?
+        StubCode::CallBootstrapCFunction_entry() :
+        StubCode::CallNativeCFunction_entry();
     const ExternalLabel label(reinterpret_cast<uword>(native_c_function()));
     __ LoadNativeEntry(RBX, &label, kNotPatchable);
   }
@@ -1459,6 +1452,10 @@
   const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
 
   if (field_cid == kDynamicCid) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1487,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(
@@ -1600,6 +1597,10 @@
 
 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   if (field().guarded_list_length() == Field::kNoFixedLength) {
+    if (Compiler::IsBackgroundCompilation()) {
+      // Field state changed while compiling.
+      Compiler::AbortBackgroundCompilation(deopt_id());
+    }
     ASSERT(!compiler->is_optimizing());
     return;  // Nothing to emit.
   }
@@ -1617,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()));
@@ -1673,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(),
@@ -1685,7 +1686,7 @@
     locs->live_registers()->Remove(Location::RegisterLocation(result_));
 
     compiler->SaveLiveRegisters(locs);
-    compiler->GenerateCall(Scanner::kNoSourcePos,  // No token position.
+    compiler->GenerateCall(TokenPosition::kNoSource,  // No token position.
                            stub_entry,
                            RawPcDescriptors::kOther,
                            locs);
@@ -1855,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));
@@ -1997,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()),
@@ -2115,7 +2116,7 @@
 
   Label slow_path, done;
   if (compiler->is_optimizing() &&
-      !Compiler::always_optimize() &&
+      !FLAG_precompiled_mode &&
       num_elements()->BindsToConstant() &&
       num_elements()->BoundConstant().IsSmi()) {
     const intptr_t length = Smi::Cast(num_elements()->BoundConstant()).Value();
@@ -2215,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));
@@ -2606,9 +2607,14 @@
       Register temp = instruction_->locs()->temp(0).reg();
       __ Comment("CheckStackOverflowSlowPathOsr");
       __ Bind(osr_entry_label());
-      ASSERT(FLAG_allow_absolute_addresses);
-      __ LoadImmediate(temp, Immediate(flags_address));
-      __ movq(Address(temp, 0), Immediate(Isolate::kOsrRequest));
+      if (FLAG_allow_absolute_addresses) {
+        __ LoadImmediate(temp, Immediate(flags_address));
+        __ movq(Address(temp, 0), Immediate(Isolate::kOsrRequest));
+      } else {
+        __ LoadIsolate(TMP);
+        __ movq(Address(TMP, Isolate::stack_overflow_flags_offset()),
+                Immediate(Isolate::kOsrRequest));
+      }
     }
     __ Comment("CheckStackOverflowSlowPath");
     __ Bind(entry_label());
@@ -2628,7 +2634,7 @@
       // In unoptimized code, record loop stack checks as possible OSR entries.
       compiler->AddCurrentDescriptor(RawPcDescriptors::kOsrEntry,
                                      instruction_->deopt_id(),
-                                     0);  // No token position.
+                                     TokenPosition::kNoSource);
     }
     compiler->pending_deoptimization_env_ = NULL;
     compiler->RestoreLiveRegisters(instruction_->locs());
@@ -2680,22 +2686,6 @@
 }
 
 
-static void EmitJavascriptOverflowCheck(FlowGraphCompiler* compiler,
-                                        Range* range,
-                                        Label* overflow,
-                                        Register result) {
-  if (!RangeUtils::IsWithin(range, -0x20000000000000LL, 0x20000000000000LL)) {
-    ASSERT(overflow != NULL);
-    // TODO(zra): This can be tightened to one compare/branch using:
-    // overflow = (result + 2^52) > 2^53 with an unsigned comparison.
-    __ CompareImmediate(result, Immediate(-0x20000000000000LL));
-    __ j(LESS, overflow);
-    __ CompareImmediate(result, Immediate(0x20000000000000LL));
-    __ j(GREATER, overflow);
-  }
-}
-
-
 static void EmitSmiShiftLeft(FlowGraphCompiler* compiler,
                              BinarySmiOpInstr* shift_left) {
   const LocationSummary& locs = *shift_left->locs();
@@ -2723,9 +2713,6 @@
     }
     // Shift for result now we know there is no overflow.
     __ shlq(left, Immediate(value));
-    if (FLAG_throw_on_javascript_int_overflow) {
-      EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result);
-    }
     return;
   }
 
@@ -2754,9 +2741,6 @@
       __ SmiUntag(right);
       __ shlq(left, right);
     }
-    if (FLAG_throw_on_javascript_int_overflow) {
-      EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result);
-    }
     return;
   }
 
@@ -2806,9 +2790,6 @@
     // Shift for result now we know there is no overflow.
     __ shlq(left, right);
   }
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, shift_left->range(), deopt, result);
-  }
 }
 
 
@@ -2989,9 +2970,6 @@
         UNREACHABLE();
         break;
     }
-    if (FLAG_throw_on_javascript_int_overflow) {
-      EmitJavascriptOverflowCheck(compiler, range(), deopt, result);
-    }
     return;
   }  // locs()->in(1).IsConstant().
 
@@ -3034,9 +3012,6 @@
         UNREACHABLE();
         break;
     }
-    if (FLAG_throw_on_javascript_int_overflow) {
-      EmitJavascriptOverflowCheck(compiler, range(), deopt, result);
-    }
     return;
   }  // locs()->in(1).IsStackSlot().
 
@@ -3233,9 +3208,6 @@
       UNREACHABLE();
       break;
   }
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), deopt, result);
-  }
 }
 
 
@@ -4725,9 +4697,6 @@
       Label* deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryOp);
       __ negq(value);
       __ j(OVERFLOW, deopt);
-      if (FLAG_throw_on_javascript_int_overflow) {
-        EmitJavascriptOverflowCheck(compiler, range(), deopt, value);
-      }
       break;
     }
     case Token::kBIT_NOT:
@@ -4931,9 +4900,6 @@
   __ shlq(temp, Immediate(1));
   __ j(OVERFLOW, &do_call, Assembler::kNearJump);
   __ SmiTag(result);
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), &do_call, result);
-  }
   __ jmp(&done);
   __ Bind(&do_call);
   ASSERT(instance_call()->HasICData());
@@ -4981,9 +4947,6 @@
   __ shlq(temp, Immediate(1));
   __ j(OVERFLOW, deopt);
   __ SmiTag(result);
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), deopt, result);
-  }
 }
 
 
@@ -5416,7 +5379,6 @@
 
     __ SmiTag(RAX);
     __ SmiTag(RDX);
-    // FLAG_throw_on_javascript_int_overflow: not needed.
     // Note that the result of an integer division/modulo of two
     // in-range arguments, cannot create out-of-range result.
     return;
@@ -5721,10 +5683,6 @@
   }
 
   EmitInt64Arithmetic(compiler, op_kind(), left, right, deopt);
-
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), deopt, out);
-  }
 }
 
 
@@ -5745,17 +5703,7 @@
   const Register left = locs()->in(0).reg();
   const Register out = locs()->out(0).reg();
   ASSERT(out == left);
-
-  Label* deopt = NULL;
-  if (FLAG_throw_on_javascript_int_overflow) {
-    deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnaryMintOp);
-  }
-
   __ notq(left);
-
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), deopt, out);
-  }
 }
 
 
@@ -5852,9 +5800,6 @@
         UNREACHABLE();
     }
   }
-  if (FLAG_throw_on_javascript_int_overflow) {
-    EmitJavascriptOverflowCheck(compiler, range(), deopt, out);
-  }
 }
 
 
@@ -6192,7 +6137,7 @@
     // may be inserted before this instruction.
     compiler->AddCurrentDescriptor(RawPcDescriptors::kDeopt,
                                    GetDeoptId(),
-                                   Scanner::kNoSourcePos);
+                                   TokenPosition::kNoSource);
   }
   if (HasParallelMove()) {
     compiler->parallel_move_resolver()->EmitNativeCode(parallel_move());
@@ -6444,7 +6389,7 @@
   const Register result = locs()->out(0).reg();
   __ PushObject(Object::null_object());
   __ pushq(typed_data);
-  compiler->GenerateRuntimeCall(Scanner::kNoSourcePos,  // No token position.
+  compiler->GenerateRuntimeCall(TokenPosition::kNoSource,
                                 deopt_id(),
                                 kGrowRegExpStackRuntimeEntry,
                                 1,
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index c3356b3..af15e7a 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -21,7 +21,6 @@
 namespace dart {
 
 DEFINE_FLAG(bool, intrinsify, true, "Instrinsify when possible");
-DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
 DECLARE_FLAG(bool, code_comments);
 DECLARE_FLAG(bool, print_flow_graph);
 DECLARE_FLAG(bool, print_flow_graph_optimized);
@@ -68,19 +67,19 @@
   ASSERT(!func.IsNull());                                                      \
   func.set_is_intrinsic(true);
 
-  // Set up all core lib functions that can be intrisified.
+  // Set up all core lib functions that can be intrinsified.
   lib = Library::CoreLibrary();
   ASSERT(!lib.IsNull());
   CORE_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
   CORE_INTEGER_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
   GRAPH_CORE_INTRINSICS_LIST(SETUP_FUNCTION);
 
-  // Set up all math lib functions that can be intrisified.
+  // Set up all math lib functions that can be intrinsified.
   lib = Library::MathLibrary();
   ASSERT(!lib.IsNull());
   MATH_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
 
-  // Set up all dart:typed_data lib functions that can be intrisified.
+  // Set up all dart:typed_data lib functions that can be intrinsified.
   lib = Library::TypedDataLibrary();
   ASSERT(!lib.IsNull());
   TYPED_DATA_LIB_INTRINSIC_LIST(SETUP_FUNCTION);
@@ -156,7 +155,8 @@
 #undef EMIT_CASE
   }
 
-  if (FLAG_print_flow_graph && FlowGraphPrinter::ShouldPrint(function)) {
+  if (FLAG_support_il_printer &&
+      FLAG_print_flow_graph && FlowGraphPrinter::ShouldPrint(function)) {
     THR_Print("Intrinsic graph before\n");
     FlowGraphPrinter printer(*graph);
     printer.PrintBlocks();
@@ -166,7 +166,8 @@
   FlowGraphAllocator allocator(*graph, true);  // Intrinsic mode.
   allocator.AllocateRegisters();
 
-  if (FLAG_print_flow_graph && FlowGraphPrinter::ShouldPrint(function)) {
+  if (FLAG_support_il_printer &&
+      FLAG_print_flow_graph && FlowGraphPrinter::ShouldPrint(function)) {
     THR_Print("Intrinsic graph after\n");
     FlowGraphPrinter printer(*graph);
     printer.PrintBlocks();
@@ -199,15 +200,10 @@
     default:
       break;
   }
-  // Integer intrinsics are in the core library, but we don't want to
-  // intrinsify when Smi > 32 bits if we are looking for javascript integer
-  // overflow.
-  if (!(FLAG_throw_on_javascript_int_overflow && (Smi::kBits >= 32))) {
-    switch (function.recognized_kind()) {
-      CORE_INTEGER_LIB_INTRINSIC_LIST(EMIT_CASE)
-      default:
-        break;
-    }
+  switch (function.recognized_kind()) {
+    CORE_INTEGER_LIB_INTRINSIC_LIST(EMIT_CASE)
+    default:
+      break;
   }
 #undef EMIT_INTRINSIC
 }
@@ -264,7 +260,7 @@
                          SPREG));
   }
 
-  intptr_t TokenPos() {
+  TokenPosition TokenPos() {
     return flow_graph_->function().token_pos();
   }
 
@@ -294,7 +290,7 @@
                              Definition* array,
                              Definition* index,
                              intptr_t length_offset) {
-  intptr_t token_pos = builder->TokenPos();
+  TokenPosition token_pos = builder->TokenPos();
   builder->AddInstruction(
       new CheckSmiInstr(new Value(index),
                         Thread::kNoDeoptId,
@@ -304,7 +300,7 @@
       new LoadFieldInstr(new Value(array),
                          length_offset,
                          Type::ZoneHandle(Type::SmiType()),
-                         Scanner::kNoSourcePos));
+                         TokenPosition::kNoSource));
   builder->AddInstruction(
       new CheckArrayBoundInstr(new Value(length),
                                new Value(index),
@@ -774,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 bb3121f..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;
@@ -1537,12 +1535,10 @@
   Label fall_through;
   __ ldr(R0, Address(SP, 0 * kWordSize));
   __ LoadClassIdMayBeSmi(R1, R0);
+  __ CompareImmediate(R1, kClosureCid);
+  __ b(&fall_through, EQ);  // Instance is a closure.
   __ LoadClassById(R2, R1);
-
   // R2: class of instance (R0).
-  __ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
-  __ CompareObject(R3, Object::null_object());
-  __ b(&fall_through, NE);
 
   __ ldrh(R3, FieldAddress(R2, Class::num_type_arguments_offset()));
   __ CompareImmediate(R3, 0);
diff --git a/runtime/vm/intrinsifier_arm64.cc b/runtime/vm/intrinsifier_arm64.cc
index 265d5d4..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;
@@ -1614,11 +1612,10 @@
   Label fall_through;
   __ ldr(R0, Address(SP, 0 * kWordSize));
   __ LoadClassIdMayBeSmi(R1, R0);
+  __ CompareImmediate(R1, kClosureCid);
+  __ b(&fall_through, EQ);  // Instance is a closure.
   __ LoadClassById(R2, R1);
   // R2: class of instance (R0).
-  __ ldr(R3, FieldAddress(R2, Class::signature_function_offset()));
-  __ CompareObject(R3, Object::null_object());
-  __ b(&fall_through, NE);
 
   __ ldr(R3, FieldAddress(R2, Class::num_type_arguments_offset()), kHalfword);
   __ CompareImmediate(R3, 0);
diff --git a/runtime/vm/intrinsifier_ia32.cc b/runtime/vm/intrinsifier_ia32.cc
index 61620c8..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.
@@ -1680,19 +1678,16 @@
   Label fall_through;
   __ movl(EAX, Address(ESP, + 1 * kWordSize));
   __ LoadClassIdMayBeSmi(EDI, EAX);
+  __ cmpl(EDI, Immediate(kClosureCid));
+  __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Instance is a closure.
   __ LoadClassById(EBX, EDI);
   // EBX: class of instance (EAX).
-  const Immediate& raw_null =
-      Immediate(reinterpret_cast<intptr_t>(Object::null()));
-  __ movl(EDI, FieldAddress(EBX, Class::signature_function_offset()));
-  __ cmpl(EDI, raw_null);
-  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
 
   __ movzxw(EDI, FieldAddress(EBX, Class::num_type_arguments_offset()));
   __ cmpl(EDI, Immediate(0));
   __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
   __ movl(EAX, FieldAddress(EBX, Class::canonical_types_offset()));
-  __ cmpl(EAX, raw_null);
+  __ CompareObject(EAX, Object::null_object());
   __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Not yet set.
   __ ret();
 
diff --git a/runtime/vm/intrinsifier_mips.cc b/runtime/vm/intrinsifier_mips.cc
index 2be1114..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()));
@@ -1646,12 +1644,10 @@
   Label fall_through;
   __ lw(T0, Address(SP, 0 * kWordSize));
   __ LoadClassIdMayBeSmi(T1, T0);
+  __ BranchEqual(T1, Immediate(kClosureCid), &fall_through);
   __ LoadClassById(T2, T1);
   // T2: class of instance (T0).
 
-  __ lw(T1, FieldAddress(T2, Class::signature_function_offset()));
-  __ BranchNotEqual(T1, Object::null_object(), &fall_through);
-
   __ lhu(T1, FieldAddress(T2, Class::num_type_arguments_offset()));
   __ BranchNotEqual(T1, Immediate(0), &fall_through);
 
diff --git a/runtime/vm/intrinsifier_x64.cc b/runtime/vm/intrinsifier_x64.cc
index e3f2ca4..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()));
@@ -1536,11 +1534,11 @@
   __ LoadClassIdMayBeSmi(RCX, RAX);
 
   // RCX: untagged cid of instance (RAX).
+  __ cmpq(RCX, Immediate(kClosureCid));
+  __ j(EQUAL, &fall_through, Assembler::kNearJump);  // Instance is a closure.
+
   __ LoadClassById(RDI, RCX);
   // RDI: class of instance (RAX).
-  __ movq(RCX, FieldAddress(RDI, Class::signature_function_offset()));
-  __ CompareObject(RCX, Object::null_object());
-  __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
 
   __ movzxw(RCX, FieldAddress(RDI, Class::num_type_arguments_offset()));
   __ cmpq(RCX, Immediate(0));
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 5c764df..3fc7780 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -18,6 +18,7 @@
 #include "vm/dart_entry.h"
 #include "vm/debugger.h"
 #include "vm/deopt_instructions.h"
+#include "vm/flags.h"
 #include "vm/heap.h"
 #include "vm/lockers.h"
 #include "vm/log.h"
@@ -29,6 +30,7 @@
 #include "vm/port.h"
 #include "vm/profiler.h"
 #include "vm/reusable_handles.h"
+#include "vm/safepoint.h"
 #include "vm/service.h"
 #include "vm/service_event.h"
 #include "vm/service_isolate.h"
@@ -51,6 +53,7 @@
 DECLARE_FLAG(bool, print_metrics);
 DECLARE_FLAG(bool, timing);
 DECLARE_FLAG(bool, trace_service);
+DECLARE_FLAG(bool, trace_service_verbose);
 
 DEFINE_FLAG(bool, trace_isolates, false,
             "Trace isolate creation and shut down.");
@@ -58,6 +61,9 @@
             "Pause isolates before starting.");
 DEFINE_FLAG(bool, pause_isolates_on_exit, false,
             "Pause isolates exiting.");
+DEFINE_FLAG(bool, pause_isolates_on_unhandled_exceptions, false,
+            "Pause isolates on unhandled exceptions.");
+
 DEFINE_FLAG(bool, break_at_isolate_spawn, false,
             "Insert a one-time breakpoint at the entrypoint for all spawned "
             "isolates");
@@ -71,16 +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;
@@ -95,6 +94,7 @@
 DEFINE_FLAG_HANDLER(CheckedModeHandler,
                     checked,
                     "Enable checked mode.");
+)
 
 
 // Quick access to the locally defined thread() and isolate() methods.
@@ -148,6 +148,17 @@
 }
 
 
+NoOOBMessageScope::NoOOBMessageScope(Thread* thread) : StackResource(thread) {
+  isolate()->DeferOOBMessageInterrupts();
+}
+
+
+NoOOBMessageScope::~NoOOBMessageScope() {
+  isolate()->RestoreOOBMessageInterrupts();
+}
+
+
+
 void Isolate::RegisterClass(const Class& cls) {
   class_table()->Register(cls);
 }
@@ -351,7 +362,7 @@
       if (!I->VerifyPauseCapability(obj)) return Error::null();
 
       // If we are already paused, don't pause again.
-      if (I->debugger()->PauseEvent() == NULL) {
+      if (FLAG_support_debugger && (I->debugger()->PauseEvent() == NULL)) {
         return I->debugger()->SignalIsolateInterrupted();
       }
       break;
@@ -439,9 +450,11 @@
   StackZone stack_zone(thread);
   Zone* zone = stack_zone.GetZone();
   HandleScope handle_scope(thread);
+#ifndef PRODUCT
   TimelineDurationScope tds(thread, I->GetIsolateStream(), "HandleMessage");
   tds.SetNumArguments(1);
   tds.CopyArgument(0, "isolateName", I->name());
+#endif
 
   // If the message is in band we lookup the handler to dispatch to.  If the
   // receive port was closed, we drop the message without deserializing it.
@@ -504,7 +517,11 @@
         if (oob_tag.IsSmi()) {
           switch (Smi::Cast(oob_tag).Value()) {
             case Message::kServiceOOBMsg: {
-              Service::HandleIsolateMessage(I, oob_msg);
+              if (FLAG_support_service) {
+                Service::HandleIsolateMessage(I, oob_msg);
+              } else {
+                UNREACHABLE();
+              }
               break;
             }
             case Message::kIsolateLibOOBMsg: {
@@ -566,7 +583,10 @@
 
 
 void IsolateMessageHandler::NotifyPauseOnStart() {
-  if (Service::debug_stream.enabled()) {
+  if (!FLAG_support_service) {
+    return;
+  }
+  if (Service::debug_stream.enabled() || FLAG_warn_on_pause_with_no_debugger) {
     StartIsolateScope start_isolate(I);
     StackZone zone(T);
     HandleScope handle_scope(T);
@@ -580,7 +600,10 @@
 
 
 void IsolateMessageHandler::NotifyPauseOnExit() {
-  if (Service::debug_stream.enabled()) {
+  if (!FLAG_support_service) {
+    return;
+  }
+  if (Service::debug_stream.enabled() || FLAG_warn_on_pause_with_no_debugger) {
     StartIsolateScope start_isolate(I);
     StackZone zone(T);
     HandleScope handle_scope(T);
@@ -605,9 +628,9 @@
 }
 
 
-static MessageHandler::MessageStatus StoreError(Isolate* isolate,
+static MessageHandler::MessageStatus StoreError(Thread* thread,
                                                 const Error& error) {
-  isolate->object_store()->set_sticky_error(error);
+  thread->set_sticky_error(error);
   if (error.IsUnwindError()) {
     const UnwindError& unwind = UnwindError::Cast(error);
     if (!unwind.is_user_initiated()) {
@@ -624,18 +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.
-      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());
@@ -662,14 +673,29 @@
   if (result.IsUnwindError()) {
     // When unwinding we don't notify error listeners and we ignore
     // whether errors are fatal for the current isolate.
-    return StoreError(I, result);
+    return StoreError(T, result);
   } else {
     bool has_listener = I->NotifyErrorListeners(exc_str, stacktrace_str);
     if (I->ErrorsFatal()) {
       if (has_listener) {
-        I->object_store()->clear_sticky_error();
+        T->clear_sticky_error();
       } else {
-        I->object_store()->set_sticky_error(result);
+        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;
     }
@@ -678,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();
@@ -711,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());
@@ -721,7 +742,7 @@
   ASSERT(Isolate::Current() == this);
   ASSERT(Thread::Current()->IsMutatorThread());
 }
-#endif  // defined(DEBUG)
+)
 
 #if defined(DEBUG)
 #define REUSABLE_HANDLE_SCOPE_INIT(object)                                     \
@@ -733,6 +754,8 @@
 #define REUSABLE_HANDLE_INITIALIZERS(object)                                   \
   object##_handle_(NULL),
 
+// TODO(srdjan): Some Isolate monitors can be shared. Replace their usage with
+// that shared monitor.
 Isolate::Isolate(const Dart_IsolateFlags& api_flags)
   :   stack_limit_(0),
       store_buffer_(new StoreBuffer()),
@@ -743,6 +766,7 @@
       class_table_(),
       single_step_(false),
       thread_registry_(new ThreadRegistry()),
+      safepoint_handler_(new SafepointHandler(this)),
       message_notify_callback_(NULL),
       name_(NULL),
       debugger_name_(NULL),
@@ -762,11 +786,14 @@
       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),
       stack_overflow_flags_(0),
       stack_overflow_count_(0),
       message_handler_(NULL),
@@ -783,7 +810,6 @@
       last_allocationprofile_accumulator_reset_timestamp_(0),
       last_allocationprofile_gc_timestamp_(0),
       object_id_ring_(NULL),
-      trace_buffer_(NULL),
       tag_table_(GrowableObjectArray::null()),
       deoptimized_code_array_(GrowableObjectArray::null()),
       background_compiler_(NULL),
@@ -797,9 +823,11 @@
       cha_invalidation_gen_(kInvalidGen),
       field_invalidation_gen_(kInvalidGen),
       prefix_invalidation_gen_(kInvalidGen),
+      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.
@@ -816,37 +844,41 @@
   delete heap_;
   delete object_store_;
   delete api_state_;
-  delete debugger_;
+  if (FLAG_support_debugger) {
+    delete debugger_;
+  }
 #if defined(USING_SIMULATOR)
   delete simulator_;
 #endif
   delete mutex_;
   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.
   delete spawn_state_;
-  delete object_id_ring_;
+  if (FLAG_support_service) {
+    delete object_id_ring_;
+  }
   object_id_ring_ = NULL;
   delete pause_loop_monitor_;
   pause_loop_monitor_ = NULL;
+  delete boxed_field_list_mutex_;
+  boxed_field_list_mutex_ = NULL;
   ASSERT(spawn_count_ == 0);
   delete spawn_count_monitor_;
   if (compiler_stats_ != NULL) {
     delete compiler_stats_;
     compiler_stats_ = NULL;
   }
+  delete safepoint_handler_;
   delete thread_registry_;
 }
 
 
-#if defined(DEBUG)
-bool Isolate::IsIsolateOf(Thread* thread) {
-  return this == thread->isolate();
-}
-#endif  // DEBUG
-
-
 void Isolate::InitOnce() {
   create_callback_ = NULL;
   isolates_list_monitor_ = new Monitor();
@@ -867,13 +899,10 @@
   ISOLATE_METRIC_LIST(ISOLATE_METRIC_INIT);
 #undef ISOLATE_METRIC_INIT
 
+#ifndef PRODUCT
   // Initialize Timeline streams.
-#define ISOLATE_TIMELINE_STREAM_INIT(name, enabled_by_default)                 \
-  result->stream_##name##_.Init(#name,                                         \
-                                enabled_by_default,                            \
-                                Timeline::Stream##name##EnabledFlag());
-  ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_INIT);
-#undef ISOLATE_TIMELINE_STREAM_INIT
+  Timeline::SetupIsolateStreams(result);
+#endif  // !PRODUCT
 
   Heap::Init(result,
              is_vm_isolate
@@ -912,8 +941,10 @@
   result->set_terminate_capability(result->random()->NextUInt64());
 
   result->BuildName(name_prefix);
-  result->debugger_ = new Debugger();
-  result->debugger_->Initialize(result);
+  if (FLAG_support_debugger) {
+    result->debugger_ = new Debugger();
+    result->debugger_->Initialize(result);
+  }
   if (FLAG_trace_isolates) {
     if (name_prefix == NULL || strcmp(name_prefix, "vm-isolate") != 0) {
       OS::Print("[+] Starting isolate:\n"
@@ -921,12 +952,16 @@
     }
   }
 
-  result->compiler_stats_ = new CompilerStats(result);
-  if (FLAG_compiler_benchmark) {
-    result->compiler_stats_->EnableBenchmark();
+  if (FLAG_support_compiler_stats) {
+    result->compiler_stats_ = new CompilerStats(result);
+    if (FLAG_compiler_benchmark) {
+      result->compiler_stats_->EnableBenchmark();
+    }
   }
 
-  ObjectIdRing::Init(result);
+  if (FLAG_support_service) {
+    ObjectIdRing::Init(result);
+  }
 
   // Add to isolate list. Shutdown and delete the isolate on failure.
   if (!AddIsolateToList(result)) {
@@ -973,11 +1008,29 @@
               snapshot.instructions_size());
   }
 #endif
-  heap_->SetupInstructionsSnapshotPage(snapshot.instructions_start(),
-                                       snapshot.instructions_size());
+  heap_->SetupExternalPage(snapshot.instructions_start(),
+                           snapshot.instructions_size(),
+                           /* is_executable = */ true);
 }
 
 
+void Isolate::SetupDataSnapshotPage(const uint8_t* data_snapshot_buffer) {
+  DataSnapshot snapshot(data_snapshot_buffer);
+#if defined(DEBUG)
+  if (FLAG_trace_isolates) {
+    OS::Print("Precompiled rodata are at [0x%" Px ", 0x%" Px ")\n",
+              reinterpret_cast<uword>(snapshot.data_start()),
+              reinterpret_cast<uword>(snapshot.data_start()) +
+              snapshot.data_size());
+  }
+#endif
+  heap_->SetupExternalPage(snapshot.data_start(),
+                           snapshot.data_size(),
+                           /* is_executable = */ false);
+}
+
+
+
 void Isolate::set_debugger_name(const char* name) {
   free(debugger_name_);
   debugger_name_ = strdup(name);
@@ -1028,16 +1081,6 @@
 }
 
 
-void Isolate::ScheduleInterrupts(uword interrupt_bits) {
-  MutexLocker ml(mutex_);
-  ASSERT((interrupt_bits & ~kInterruptsMask) == 0);  // Must fit in mask.
-  if (stack_limit_ == saved_stack_limit_) {
-    stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
-  }
-  stack_limit_ |= interrupt_bits;
-}
-
-
 void Isolate::DoneLoading() {
   GrowableObjectArray& libs = GrowableObjectArray::Handle(current_zone(),
       object_store()->libraries());
@@ -1067,23 +1110,28 @@
   // isolate on thread pool for execution.
   ASSERT(object_store()->root_library() != Library::null());
   set_is_runnable(true);
-  if (!ServiceIsolate::IsServiceIsolate(this)) {
-    message_handler()->set_pause_on_start(FLAG_pause_isolates_on_start);
-    message_handler()->set_pause_on_exit(FLAG_pause_isolates_on_exit);
+  if (FLAG_support_debugger && !ServiceIsolate::IsServiceIsolate(this)) {
+    if (FLAG_pause_isolates_on_unhandled_exceptions) {
+      debugger()->SetExceptionPauseInfo(kPauseOnUnhandledExceptions);
+    }
   }
   IsolateSpawnState* state = spawn_state();
   if (state != NULL) {
     ASSERT(this == state->isolate());
     Run();
   }
-  TimelineStream* stream = GetIsolateStream();
-  ASSERT(stream != NULL);
-  TimelineEvent* event = stream->StartEvent();
-  if (event != NULL) {
-    event->Instant("Runnable");
-    event->Complete();
+#ifndef PRODUCT
+  if (FLAG_support_timeline) {
+    TimelineStream* stream = GetIsolateStream();
+    ASSERT(stream != NULL);
+    TimelineEvent* event = stream->StartEvent();
+    if (event != NULL) {
+      event->Instant("Runnable");
+      event->Complete();
+    }
   }
-  if (Service::isolate_stream.enabled()) {
+#endif  // !PRODUCT
+  if (FLAG_support_service && Service::isolate_stream.enabled()) {
     ServiceEvent runnableEvent(this, ServiceEvent::kIsolateRunnable);
     Service::HandleEvent(&runnableEvent);
   }
@@ -1332,8 +1380,7 @@
     if (!ClassFinalizer::ProcessPendingClasses()) {
       // Error is in sticky error already.
 #if defined(DEBUG)
-      const Error& error =
-          Error::Handle(isolate->object_store()->sticky_error());
+      const Error& error = Error::Handle(thread->sticky_error());
       ASSERT(!error.IsUnwindError());
 #endif
       return MessageHandler::kError;
@@ -1343,7 +1390,7 @@
     result = state->ResolveFunction();
     bool is_spawn_uri = state->is_spawn_uri();
     if (result.IsError()) {
-      return StoreError(isolate, Error::Cast(result));
+      return StoreError(thread, Error::Cast(result));
     }
     ASSERT(result.IsFunction());
     Function& func = Function::Handle(thread->zone());
@@ -1355,7 +1402,7 @@
     // way to debug. Set the breakpoint on the static function instead
     // of its implicit closure function because that latter is merely
     // a dispatcher that is marked as undebuggable.
-    if (FLAG_break_at_isolate_spawn) {
+    if (FLAG_support_debugger && FLAG_break_at_isolate_spawn) {
       isolate->debugger()->OneTimeBreakAtEntry(func);
     }
 
@@ -1398,7 +1445,7 @@
 
     result = DartEntry::InvokeFunction(entry_point, args);
     if (result.IsError()) {
-      return StoreError(isolate, Error::Cast(result));
+      return StoreError(thread, Error::Cast(result));
     }
   }
   return MessageHandler::kOK;
@@ -1418,7 +1465,7 @@
     ASSERT(thread->isolate() == isolate);
     StackZone zone(thread);
     HandleScope handle_scope(thread);
-    const Error& error = Error::Handle(isolate->object_store()->sticky_error());
+    const Error& error = Error::Handle(thread->sticky_error());
     if (!error.IsNull() && !error.IsUnwindError()) {
       OS::PrintErr("in ShutdownIsolate: %s\n", error.ToErrorCString());
     }
@@ -1437,6 +1484,27 @@
 }
 
 
+void Isolate::ScheduleInterrupts(uword interrupt_bits) {
+  MutexLocker ml(mutex_);
+  ASSERT((interrupt_bits & ~kInterruptsMask) == 0);  // Must fit in mask.
+
+  // Check to see if any of the requested interrupts should be deferred.
+  uword defer_bits = interrupt_bits & deferred_interrupts_mask_;
+  if (defer_bits != 0) {
+    deferred_interrupts_ |= defer_bits;
+    interrupt_bits &= ~deferred_interrupts_mask_;
+    if (interrupt_bits == 0) {
+      return;
+    }
+  }
+
+  if (stack_limit_ == saved_stack_limit_) {
+    stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
+  }
+  stack_limit_ |= interrupt_bits;
+}
+
+
 uword Isolate::GetAndClearInterrupts() {
   MutexLocker ml(mutex_);
   if (stack_limit_ == saved_stack_limit_) {
@@ -1448,10 +1516,51 @@
 }
 
 
+void Isolate::DeferOOBMessageInterrupts() {
+  MutexLocker ml(mutex_);
+  ASSERT(deferred_interrupts_mask_ == 0);
+  deferred_interrupts_mask_ = kMessageInterrupt;
+
+  if (stack_limit_ != saved_stack_limit_) {
+    // Defer any interrupts which are currently pending.
+    deferred_interrupts_ = stack_limit_ & deferred_interrupts_mask_;
+
+    // Clear deferrable interrupts, if present.
+    stack_limit_ &= ~deferred_interrupts_mask_;
+
+    if ((stack_limit_ & kInterruptsMask) == 0) {
+      // No other pending interrupts.  Restore normal stack limit.
+      stack_limit_ = saved_stack_limit_;
+    }
+  }
+  if (FLAG_trace_service && FLAG_trace_service_verbose) {
+    OS::Print("[+%" Pd64 "ms] Isolate %s deferring OOB interrupts\n",
+              Dart::timestamp(), name());
+  }
+}
+
+
+void Isolate::RestoreOOBMessageInterrupts() {
+  MutexLocker ml(mutex_);
+  ASSERT(deferred_interrupts_mask_ == kMessageInterrupt);
+  deferred_interrupts_mask_ = 0;
+  if (deferred_interrupts_ != 0) {
+    if (stack_limit_ == saved_stack_limit_) {
+      stack_limit_ = (~static_cast<uword>(0)) & ~kInterruptsMask;
+    }
+    stack_limit_ |= deferred_interrupts_;
+    deferred_interrupts_ = 0;
+  }
+  if (FLAG_trace_service && FLAG_trace_service_verbose) {
+    OS::Print("[+%" Pd64 "ms] Isolate %s restoring OOB interrupts\n",
+              Dart::timestamp(), name());
+  }
+}
+
+
 RawError* Isolate::HandleInterrupts() {
   uword interrupt_bits = GetAndClearInterrupts();
   if ((interrupt_bits & kVMInterrupt) != 0) {
-    thread_registry()->CheckSafepoint();
     if (store_buffer()->Overflowed()) {
       if (FLAG_verbose_gc) {
         OS::PrintErr("Scavenge scheduled by store buffer overflow.\n");
@@ -1469,9 +1578,10 @@
         OS::Print("[!] Terminating isolate due to OOB message:\n"
                   "\tisolate:    %s\n", name());
       }
-      const Error& error = Error::Handle(object_store()->sticky_error());
+      Thread* thread = Thread::Current();
+      const Error& error = Error::Handle(thread->sticky_error());
       ASSERT(!error.IsNull() && error.IsUnwindError());
-      object_store()->clear_sticky_error();
+      thread->clear_sticky_error();
       return error.raw();
     }
   }
@@ -1502,7 +1612,7 @@
 // all closure functions becomes more difficult, especially when
 // the list/map changes while iterating over it.
 RawFunction* Isolate::LookupClosureFunction(const Function& parent,
-                                            intptr_t token_pos) const {
+                                            TokenPosition token_pos) const {
   const GrowableObjectArray& closures =
       GrowableObjectArray::Handle(object_store()->closure_functions());
   ASSERT(!closures.IsNull());
@@ -1568,7 +1678,7 @@
 
   // Notify exit listeners that this isolate is shutting down.
   if (object_store() != NULL) {
-    const Error& error = Error::Handle(object_store()->sticky_error());
+    const Error& error = Error::Handle(thread->sticky_error());
     if (error.IsNull() ||
         !error.IsUnwindError() ||
         UnwindError::Cast(error).is_user_initiated()) {
@@ -1577,7 +1687,10 @@
   }
 
   // Clean up debugger resources.
-  debugger()->Shutdown();
+  if (FLAG_support_debugger) {
+    debugger()->Shutdown();
+  }
+
 
   // Close all the ports owned by this isolate.
   PortMap::ClosePorts(message_handler());
@@ -1585,15 +1698,19 @@
   // Fail fast if anybody tries to post any more messsages to this isolate.
   delete message_handler();
   set_message_handler(NULL);
-
-  // Before analyzing the isolate's timeline blocks- reclaim all cached blocks.
-  Timeline::ReclaimCachedBlocksFromThreads();
+  if (FLAG_support_timeline) {
+    // Before analyzing the isolate's timeline blocks- reclaim all cached
+    // blocks.
+    Timeline::ReclaimCachedBlocksFromThreads();
+  }
 
   // Dump all timing data for the isolate.
-  if (FLAG_timing) {
+#ifndef PRODUCT
+  if (FLAG_support_timeline && FLAG_timing) {
     TimelinePauseTrace tpt;
     tpt.Print();
   }
+#endif  // !PRODUCT
 
   // Finalize any weak persistent handles with a non-null referent.
   FinalizeWeakPersistentHandlesVisitor visitor;
@@ -1651,7 +1768,7 @@
     }
 
     // Write compiler stats data if enabled.
-    if (FLAG_compiler_stats
+    if (FLAG_support_compiler_stats && FLAG_compiler_stats
         && !ServiceIsolate::IsServiceIsolateDescendant(this)
         && (this != Dart::vm_isolate())) {
       OS::Print("%s", compiler_stats()->PrintToZone());
@@ -1752,15 +1869,23 @@
   visitor->VisitPointer(
       reinterpret_cast<RawObject**>(&registered_service_extension_handlers_));
 
+  // 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_mutex_ lock has been taken.
+  visitor->VisitPointer(reinterpret_cast<RawObject**>(&boxed_field_list_));
+
   // Visit objects in the debugger.
-  debugger()->VisitObjectPointers(visitor);
+  if (FLAG_support_debugger) {
+    debugger()->VisitObjectPointers(visitor);
+  }
 
   // Visit objects that are being used for deoptimization.
   if (deopt_context() != NULL) {
     deopt_context()->VisitObjectPointers(visitor);
   }
 
-  // Visit objects in thread registry (e.g., Dart stack, handles in zones).
+  // Visit objects in all threads (e.g., Dart stack, handles in zones).
   thread_registry()->VisitObjectPointers(visitor, validate_frames);
 }
 
@@ -1772,6 +1897,11 @@
 }
 
 
+void Isolate::PrepareForGC() {
+  thread_registry()->PrepareForGC();
+}
+
+
 static const char* ExceptionPauseInfoToServiceEnum(Dart_ExceptionPauseInfo pi) {
   switch (pi) {
     case kPauseOnAllExceptions:
@@ -1788,6 +1918,9 @@
 
 
 void Isolate::PrintJSON(JSONStream* stream, bool ref) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject jsobj(stream);
   jsobj.AddProperty("type", (ref ? "@Isolate" : "Isolate"));
   jsobj.AddFixedServiceId("isolates/%" Pd64 "",
@@ -1809,33 +1942,36 @@
     heap()->PrintToJSONObject(Heap::kOld, &jsheap);
   }
 
+  jsobj.AddProperty("runnable", is_runnable());
   jsobj.AddProperty("livePorts", message_handler()->live_ports());
-  jsobj.AddProperty("pauseOnExit", message_handler()->pause_on_exit());
+  jsobj.AddProperty("pauseOnExit", message_handler()->should_pause_on_exit());
 
-  if (message_handler()->paused_on_start()) {
-    ASSERT(debugger()->PauseEvent() == NULL);
-    ServiceEvent pause_event(this, ServiceEvent::kPauseStart);
-    jsobj.AddProperty("pauseEvent", &pause_event);
-  } else if (message_handler()->paused_on_exit()) {
-    ASSERT(debugger()->PauseEvent() == NULL);
-    ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
-    jsobj.AddProperty("pauseEvent", &pause_event);
-  } else if (debugger()->PauseEvent() != NULL && !resume_request_) {
-    ServiceEvent pause_event(debugger()->PauseEvent());
-    jsobj.AddProperty("pauseEvent", &pause_event);
-  } else {
-    ServiceEvent pause_event(this, ServiceEvent::kResume);
+  if (debugger() != NULL) {
+    if (message_handler()->is_paused_on_start()) {
+      ASSERT(debugger()->PauseEvent() == NULL);
+      ServiceEvent pause_event(this, ServiceEvent::kPauseStart);
+      jsobj.AddProperty("pauseEvent", &pause_event);
+    } else if (message_handler()->is_paused_on_exit()) {
+      ASSERT(debugger()->PauseEvent() == NULL);
+      ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
+      jsobj.AddProperty("pauseEvent", &pause_event);
+    } else if (debugger()->PauseEvent() != NULL && !resume_request_) {
+      ServiceEvent pause_event(debugger()->PauseEvent());
+      jsobj.AddProperty("pauseEvent", &pause_event);
+    } else {
+      ServiceEvent pause_event(this, ServiceEvent::kResume);
 
-    // TODO(turnidge): Don't compute a full stack trace.
-    DebuggerStackTrace* stack = debugger()->StackTrace();
-    if (stack->Length() > 0) {
-      pause_event.set_top_frame(stack->FrameAt(0));
+      // TODO(turnidge): Don't compute a full stack trace.
+      DebuggerStackTrace* stack = debugger()->StackTrace();
+      if (stack->Length() > 0) {
+        pause_event.set_top_frame(stack->FrameAt(0));
+      }
+      jsobj.AddProperty("pauseEvent", &pause_event);
     }
-    jsobj.AddProperty("pauseEvent", &pause_event);
-  }
 
-  jsobj.AddProperty("exceptionPauseMode",
-      ExceptionPauseInfoToServiceEnum(debugger()->GetExceptionPauseInfo()));
+    jsobj.AddProperty("exceptionPauseMode",
+        ExceptionPauseInfoToServiceEnum(debugger()->GetExceptionPauseInfo()));
+  }
 
   const Library& lib =
       Library::Handle(object_store()->root_library());
@@ -1847,8 +1983,8 @@
     JSONObject tagCounters(&jsobj, "_tagCounters");
     vm_tag_counters()->PrintToJSONObject(&tagCounters);
   }
-  if (object_store()->sticky_error() != Object::null()) {
-    Error& error = Error::Handle(object_store()->sticky_error());
+  if (Thread::Current()->sticky_error() != Object::null()) {
+    Error& error = Error::Handle(Thread::Current()->sticky_error());
     ASSERT(!error.IsNull());
     jsobj.AddProperty("error", error, false);
   }
@@ -1866,14 +2002,17 @@
       lib_array.AddValue(lib);
     }
   }
-  {
-    JSONArray breakpoints(&jsobj, "breakpoints");
-    debugger()->PrintBreakpointsToJSONArray(&breakpoints);
-  }
 
-  {
-    JSONObject jssettings(&jsobj, "_debuggerSettings");
-    debugger()->PrintSettingsToJSONObject(&jssettings);
+  if (debugger() != NULL) {
+    {
+      JSONArray breakpoints(&jsobj, "breakpoints");
+      debugger()->PrintBreakpointsToJSONArray(&breakpoints);
+    }
+
+    {
+      JSONObject jssettings(&jsobj, "_debuggerSettings");
+      debugger()->PrintSettingsToJSONObject(&jssettings);
+    }
   }
 
   {
@@ -1945,7 +2084,38 @@
 }
 
 
+void Isolate::AddDeoptimizingBoxedField(const Field& field) {
+  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);
+  }
+  const GrowableObjectArray& array =
+      GrowableObjectArray::Handle(boxed_field_list_);
+  array.Add(field, Heap::kOld);
+}
+
+
+RawField* Isolate::GetDeoptimizingBoxedField() {
+  MutexLocker ml(boxed_field_list_mutex_);
+  if (boxed_field_list_ == GrowableObjectArray::null()) {
+    return Field::null();
+  }
+  const GrowableObjectArray& array =
+      GrowableObjectArray::Handle(boxed_field_list_);
+  if (array.Length() == 0) {
+    return Field::null();
+  }
+  return Field::RawCast(array.RemoveLast());
+}
+
+
 RawObject* Isolate::InvokePendingServiceExtensionCalls() {
+  if (!FLAG_support_service) {
+    return Object::null();
+  }
   GrowableObjectArray& calls =
       GrowableObjectArray::Handle(GetAndClearPendingServiceExtensionCalls());
   if (calls.IsNull()) {
@@ -1959,7 +2129,7 @@
   ASSERT(!run_extension.IsNull());
 
   const Array& arguments =
-      Array::Handle(Array::New(kPendingEntrySize, Heap::kNew));
+      Array::Handle(Array::New(kPendingEntrySize + 1, Heap::kNew));
   Object& result = Object::Handle();
   String& method_name = String::Handle();
   Instance& closure = Instance::Handle();
@@ -1986,8 +2156,19 @@
     arguments.SetAt(kPendingReplyPortIndex, reply_port);
     id ^= calls.At(i + kPendingIdIndex);
     arguments.SetAt(kPendingIdIndex, id);
+    arguments.SetAt(kPendingEntrySize, Bool::Get(FLAG_trace_service));
 
+    if (FLAG_trace_service) {
+      OS::Print(
+          "[+%" Pd64 "ms] Isolate %s invoking _runExtension for %s\n",
+          Dart::timestamp(), name(), method_name.ToCString());
+    }
     result = DartEntry::InvokeFunction(run_extension, arguments);
+    if (FLAG_trace_service) {
+      OS::Print(
+          "[+%" Pd64 "ms] Isolate %s : _runExtension complete for %s\n",
+          Dart::timestamp(), name(), method_name.ToCString());
+    }
     if (result.IsError()) {
       if (result.IsUnwindError()) {
         // Propagate the unwind error. Remaining service extension calls
@@ -2025,6 +2206,11 @@
                                          const Array& parameter_values,
                                          const Instance& reply_port,
                                          const Instance& id) {
+  if (FLAG_trace_service) {
+    OS::Print(
+        "[+%" Pd64 "ms] Isolate %s ENQUEUING request for extension %s\n",
+        Dart::timestamp(), name(), method_name.ToCString());
+  }
   GrowableObjectArray& calls =
       GrowableObjectArray::Handle(pending_service_extension_calls());
   if (calls.IsNull()) {
@@ -2053,6 +2239,9 @@
 // done atomically.
 void Isolate::RegisterServiceExtensionHandler(const String& name,
                                               const Instance& closure) {
+  if (!FLAG_support_service) {
+    return;
+  }
   GrowableObjectArray& handlers =
       GrowableObjectArray::Handle(registered_service_extension_handlers());
   if (handlers.IsNull()) {
@@ -2085,6 +2274,9 @@
 // to Dart code unless you can ensure that the operations will can be
 // done atomically.
 RawInstance* Isolate::LookupServiceExtensionHandler(const String& name) {
+  if (!FLAG_support_service) {
+    return Instance::null();
+  }
   const GrowableObjectArray& handlers =
       GrowableObjectArray::Handle(registered_service_extension_handlers());
   if (handlers.IsNull()) {
@@ -2130,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;
@@ -2151,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);
@@ -2329,6 +2523,89 @@
 }
 
 
+Monitor* Isolate::threads_lock() const {
+  return thread_registry_->threads_lock();
+}
+
+
+Thread* Isolate::ScheduleThread(bool is_mutator, bool bypass_safepoint) {
+  // Schedule the thread into the isolate by associating
+  // a 'Thread' structure with it (this is done while we are holding
+  // the thread registry lock).
+  Thread* thread = NULL;
+  OSThread* os_thread = OSThread::Current();
+  if (os_thread != NULL) {
+    // 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.
+    while (!bypass_safepoint && safepoint_handler()->safepoint_in_progress()) {
+      ml.Wait();
+    }
+
+    // Now get a free Thread structure.
+    thread = thread_registry()->GetFreeThreadLocked(this, is_mutator);
+    ASSERT(thread != NULL);
+
+    // Set up other values and set the TLS value.
+    thread->isolate_ = this;
+    ASSERT(heap() != NULL);
+    thread->heap_ = heap();
+    thread->set_os_thread(os_thread);
+    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;
+    }
+    Thread::SetCurrent(thread);
+    os_thread->EnableThreadInterrupts();
+  }
+  return thread;
+}
+
+
+void Isolate::UnscheduleThread(Thread* thread,
+                               bool is_mutator,
+                               bool bypass_safepoint) {
+  // Disassociate the 'Thread' structure and unschedule the thread
+  // from this isolate.
+  // 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();
+  }
+  OSThread* os_thread = thread->os_thread();
+  ASSERT(os_thread != NULL);
+  os_thread->DisableThreadInterrupts();
+  os_thread->set_thread(NULL);
+  OSThread::SetCurrent(os_thread);
+  if (is_mutator) {
+    mutator_thread_ = NULL;
+  }
+  thread->isolate_ = NULL;
+  thread->heap_ = NULL;
+  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);
+}
+
+
 static RawInstance* DeserializeObject(Thread* thread,
                                       uint8_t* obj_data,
                                       intptr_t obj_len) {
@@ -2385,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());
@@ -2405,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());
 }
 
 
@@ -2455,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 8e84d00..9d6aa28 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -19,7 +19,7 @@
 #include "vm/os_thread.h"
 #include "vm/timeline.h"
 #include "vm/timer.h"
-#include "vm/trace_buffer.h"
+#include "vm/token_position.h"
 
 namespace dart {
 
@@ -53,9 +53,11 @@
 class RawObject;
 class RawInteger;
 class RawError;
+class RawField;
 class RawFloat32x4;
 class RawInt32x4;
 class RawUserTag;
+class SafepointHandler;
 class SampleBuffer;
 class SendPort;
 class ServiceIdZone;
@@ -80,6 +82,16 @@
 };
 
 
+// Disallow OOB message handling within this scope.
+class NoOOBMessageScope : public StackResource {
+ public:
+  explicit NoOOBMessageScope(Thread* thread);
+  ~NoOOBMessageScope();
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NoOOBMessageScope);
+};
+
+
 class Isolate : public BaseIsolate {
  public:
   // Keep both these enums in sync with isolate_patch.dart.
@@ -126,9 +138,13 @@
   // Visits weak object pointers.
   void VisitWeakPersistentHandles(HandleVisitor* visitor);
 
+  // Prepares all threads in an isolate for Garbage Collection.
+  void PrepareForGC();
+
   StoreBuffer* store_buffer() { return store_buffer_; }
 
-  ThreadRegistry* thread_registry() { return thread_registry_; }
+  ThreadRegistry* thread_registry() const { return thread_registry_; }
+  SafepointHandler* safepoint_handler() const { return safepoint_handler_; }
 
   ClassTable* class_table() { return &class_table_; }
   static intptr_t class_table_offset() {
@@ -224,6 +240,8 @@
 
   void SetupInstructionsSnapshotPage(
       const uint8_t* instructions_snapshot_buffer);
+  void SetupDataSnapshotPage(
+      const uint8_t* instructions_snapshot_buffer);
 
   // Returns true if any of the interrupts specified by 'interrupt_bits' are
   // currently scheduled for this isolate, but leaves them unchanged.
@@ -259,6 +277,9 @@
   uword stack_overflow_flags_address() const {
     return reinterpret_cast<uword>(&stack_overflow_flags_);
   }
+  static intptr_t stack_overflow_flags_offset() {
+    return OFFSET_OF(Isolate, stack_overflow_flags_);
+  }
 
   int32_t IncrementAndGetStackOverflowCount() {
     return ++stack_overflow_count_;
@@ -297,8 +318,15 @@
   void set_spawn_state(IsolateSpawnState* value) { spawn_state_ = value; }
 
   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) {
+      return NULL;
+    }
     ASSERT(debugger_ != NULL);
     return debugger_;
   }
@@ -312,44 +340,8 @@
   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_; }
-
-  // Requests that the debugger resume execution.
-  void Resume() {
+  // Lets the embedder know that a service message resulted in a resume request.
+  void SetResumeRequest() {
     resume_request_ = true;
     set_last_resume_timestamp();
   }
@@ -469,13 +461,6 @@
     return object_id_ring_;
   }
 
-  void set_trace_buffer(TraceBuffer* buffer) {
-    trace_buffer_ = buffer;
-  }
-  TraceBuffer* trace_buffer() {
-    return trace_buffer_;
-  }
-
   DeoptContext* deopt_context() const { return deopt_context_; }
   void set_deopt_context(DeoptContext* value) {
     ASSERT(value == NULL || deopt_context_ == NULL);
@@ -549,10 +534,17 @@
   ISOLATE_METRIC_LIST(ISOLATE_METRIC_ACCESSOR);
 #undef ISOLATE_METRIC_ACCESSOR
 
+#ifndef PRODUCT
 #define ISOLATE_TIMELINE_STREAM_ACCESSOR(name, not_used)                       \
   TimelineStream* Get##name##Stream() { return &stream_##name##_; }
   ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_ACCESSOR)
 #undef ISOLATE_TIMELINE_STREAM_ACCESSOR
+#else
+#define ISOLATE_TIMELINE_STREAM_ACCESSOR(name, not_used)                       \
+  TimelineStream* Get##name##Stream() { return NULL; }
+  ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_ACCESSOR)
+#undef ISOLATE_TIMELINE_STREAM_ACCESSOR
+#endif  // !PRODUCT
 
   static intptr_t IsolateListLength();
 
@@ -617,6 +609,12 @@
   void ResetPrefixInvalidationGen() { prefix_invalidation_gen_ = kInvalidGen; }
   uint32_t prefix_invalidation_gen() const { return prefix_invalidation_gen_; }
 
+  // Used by background compiler which field became boxed and must trigger
+  // deoptimization in the mutator thread.
+  void AddDeoptimizingBoxedField(const Field& field);
+  // Returns Field::null() if none available in the list.
+  RawField* GetDeoptimizingBoxedField();
+
   RawObject* InvokePendingServiceExtensionCalls();
   void AppendServiceExtensionCall(const Instance& closure,
                            const String& method_name,
@@ -635,12 +633,29 @@
 
   void AddClosureFunction(const Function& function) const;
   RawFunction* LookupClosureFunction(const Function& parent,
-                                     intptr_t token_pos) const;
+                                     TokenPosition token_pos) const;
   intptr_t FindClosureIndex(const Function& needle) const;
   RawFunction* ClosureFunctionFromIndex(intptr_t idx) const;
 
   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);
 
@@ -650,6 +665,7 @@
  private:
   friend class Dart;  // Init, InitOnce, Shutdown.
   friend class IsolateKillerVisitor;  // Kill().
+  friend class NoOOBMessageScope;
 
   explicit Isolate(const Dart_IsolateFlags& api_flags);
 
@@ -676,6 +692,9 @@
     user_tag_ = tag;
   }
 
+  void DeferOOBMessageInterrupts();
+  void RestoreOOBMessageInterrupts();
+
   RawGrowableObjectArray* GetAndClearPendingServiceExtensionCalls();
   RawGrowableObjectArray* pending_service_extension_calls() const {
     return pending_service_extension_calls_;
@@ -687,17 +706,10 @@
   void set_registered_service_extension_handlers(
       const GrowableObjectArray& value);
 
-  void ClearMutatorThread() {
-    mutator_thread_ = NULL;
-  }
-  void MakeCurrentThreadMutator(Thread* thread) {
-    ASSERT(thread == Thread::Current());
-    DEBUG_ASSERT(IsIsolateOf(thread));
-    mutator_thread_ = thread;
-  }
-#if defined(DEBUG)
-  bool IsIsolateOf(Thread* thread);
-#endif  // DEBUG
+  Monitor* threads_lock() const;
+  Thread* ScheduleThread(bool is_mutator, bool bypass_safepoint = false);
+  void UnscheduleThread(
+      Thread* thread, bool is_mutator, bool bypass_safepoint = false);
 
   // DEPRECATED: Use Thread's methods instead. During migration, these default
   // to using the mutator thread (which must also be the current thread).
@@ -718,8 +730,10 @@
   RawCode* ic_miss_code_;
   ClassTable class_table_;
   bool single_step_;
+  bool skip_step_;  // skip the next single step.
 
   ThreadRegistry* thread_registry_;
+  SafepointHandler* safepoint_handler_;
   Dart_MessageNotifyCallback message_notify_callback_;
   char* name_;
   char* debugger_name_;
@@ -739,11 +753,14 @@
   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* 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_;
   uword stack_overflow_flags_;
   int32_t stack_overflow_count_;
   MessageHandler* message_handler_;
@@ -758,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_;
@@ -769,9 +794,6 @@
   // Ring buffer of objects assigned an id.
   ObjectIdRing* object_id_ring_;
 
-  // Trace buffer support.
-  TraceBuffer* trace_buffer_;
-
   VMTagCounters vm_tag_counters_;
   RawGrowableObjectArray* tag_table_;
 
@@ -818,6 +840,11 @@
   uint32_t field_invalidation_gen_;
   uint32_t prefix_invalidation_gen_;
 
+  // Protect access to boxed_field_list_.
+  Mutex* boxed_field_list_mutex_;
+  // List of fields that became boxed and that trigger deoptimization.
+  RawGrowableObjectArray* boxed_field_list_;
+
   // This guards spawn_count_. An isolate cannot complete shutdown and be
   // destroyed while there are child isolates in the midst of a spawn.
   Monitor* spawn_count_monitor_;
@@ -828,10 +855,12 @@
   ISOLATE_METRIC_LIST(ISOLATE_METRIC_VARIABLE);
 #undef ISOLATE_METRIC_VARIABLE
 
+#ifndef PRODUCT
 #define ISOLATE_TIMELINE_STREAM_VARIABLE(name, not_used)                       \
   TimelineStream stream_##name##_;
   ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_VARIABLE)
 #undef ISOLATE_TIMELINE_STREAM_VARIABLE
+#endif  // !PRODUCT
 
   static Dart_IsolateCreateCallback create_callback_;
   static Dart_IsolateShutdownCallback shutdown_callback_;
@@ -859,10 +888,12 @@
 #undef REUSABLE_FRIEND_DECLARATION
 
   friend class GCMarker;  // VisitObjectPointers
+  friend class SafepointHandler;
   friend class Scavenger;  // VisitObjectPointers
   friend class ServiceIsolate;
   friend class Thread;
   friend class Timeline;
+  friend class IsolateTestHelper;
 
   DISALLOW_COPY_AND_ASSIGN(Isolate);
 };
@@ -958,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);
@@ -989,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/isolate_test.cc b/runtime/vm/isolate_test.cc
index 4bf156d..6491c41 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -131,7 +131,9 @@
 // round update *before* the interrupt is set.
 TEST_CASE(StackLimitInterrupts) {
   Isolate* isolate = Thread::Current()->isolate();
-  ThreadBarrier barrier(InterruptChecker::kTaskCount + 1);
+  ThreadBarrier barrier(InterruptChecker::kTaskCount + 1,
+                        isolate->heap()->barrier(),
+                        isolate->heap()->barrier_done());
   // Start all tasks. They will busy-wait until interrupted in the first round.
   for (intptr_t task = 0; task < InterruptChecker::kTaskCount; task++) {
     Dart::thread_pool()->Run(new InterruptChecker(isolate, &barrier));
@@ -149,4 +151,103 @@
   barrier.Exit();
 }
 
+
+class IsolateTestHelper {
+ public:
+  static uword GetStackLimit(Isolate* isolate) {
+    return isolate->stack_limit_;
+  }
+  static uword GetSavedStackLimit(Isolate* isolate) {
+    return isolate->saved_stack_limit_;
+  }
+  static uword GetDeferredInterruptsMask(Isolate* isolate) {
+    return isolate->deferred_interrupts_mask_;
+  }
+  static uword GetDeferredInterrupts(Isolate* isolate) {
+    return isolate->deferred_interrupts_;
+  }
+};
+
+
+TEST_CASE(NoOOBMessageScope) {
+  // EXPECT_EQ is picky about type agreement for its arguments.
+  const uword kZero = 0;
+  const uword kMessageInterrupt = Isolate::kMessageInterrupt;
+  const uword kVMInterrupt = Isolate::kVMInterrupt;
+  uword stack_limit;
+  uword interrupt_bits;
+
+  // Initially no interrupts are scheduled or deferred.
+  Isolate* isolate = Thread::Current()->isolate();
+  EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate),
+            IsolateTestHelper::GetSavedStackLimit(isolate));
+  EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(isolate));
+  EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(isolate));
+
+  {
+    // Defer message interrupts.
+    NoOOBMessageScope no_msg_scope(Thread::Current());
+    EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate),
+              IsolateTestHelper::GetSavedStackLimit(isolate));
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterruptsMask(isolate));
+    EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(isolate));
+
+    // Schedule a message, it is deferred.
+    isolate->ScheduleInterrupts(Isolate::kMessageInterrupt);
+    EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate),
+              IsolateTestHelper::GetSavedStackLimit(isolate));
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterruptsMask(isolate));
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterrupts(isolate));
+
+    // Schedule a vm interrupt, it is not deferred.
+    isolate->ScheduleInterrupts(Isolate::kVMInterrupt);
+    stack_limit = IsolateTestHelper::GetStackLimit(isolate);
+    EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(isolate));
+    EXPECT((stack_limit & Isolate::kVMInterrupt) != 0);
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterruptsMask(isolate));
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterrupts(isolate));
+
+    // Clear the vm interrupt.  Message is still deferred.
+    interrupt_bits = isolate->GetAndClearInterrupts();
+    EXPECT_EQ(kVMInterrupt, interrupt_bits);
+    EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate),
+              IsolateTestHelper::GetSavedStackLimit(isolate));
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterruptsMask(isolate));
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterrupts(isolate));
+  }
+
+  // Restore message interrupts.  Message is now pending.
+  stack_limit = IsolateTestHelper::GetStackLimit(isolate);
+  EXPECT_NE(stack_limit, IsolateTestHelper::GetSavedStackLimit(isolate));
+  EXPECT((stack_limit & Isolate::kMessageInterrupt) != 0);
+  EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(isolate));
+  EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(isolate));
+
+  {
+    // Defer message interrupts, again.  The pending interrupt is deferred.
+    NoOOBMessageScope no_msg_scope(Thread::Current());
+    EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate),
+              IsolateTestHelper::GetSavedStackLimit(isolate));
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterruptsMask(isolate));
+    EXPECT_EQ(kMessageInterrupt,
+              IsolateTestHelper::GetDeferredInterrupts(isolate));
+  }
+
+  // Restore, then clear interrupts.  The world is as it was.
+  interrupt_bits = isolate->GetAndClearInterrupts();
+  EXPECT_EQ(kMessageInterrupt, interrupt_bits);
+  EXPECT_EQ(IsolateTestHelper::GetStackLimit(isolate),
+            IsolateTestHelper::GetSavedStackLimit(isolate));
+  EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterruptsMask(isolate));
+  EXPECT_EQ(kZero, IsolateTestHelper::GetDeferredInterrupts(isolate));
+}
+
 }  // namespace dart
diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc
new file mode 100644
index 0000000..f5f2211
--- /dev/null
+++ b/runtime/vm/jit_optimizer.cc
@@ -0,0 +1,3162 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/jit_optimizer.h"
+
+#include "vm/bit_vector.h"
+#include "vm/branch_optimizer.h"
+#include "vm/cha.h"
+#include "vm/compiler.h"
+#include "vm/cpu.h"
+#include "vm/dart_entry.h"
+#include "vm/exceptions.h"
+#include "vm/flow_graph_builder.h"
+#include "vm/flow_graph_compiler.h"
+#include "vm/flow_graph_inliner.h"
+#include "vm/flow_graph_range_analysis.h"
+#include "vm/hash_map.h"
+#include "vm/il_printer.h"
+#include "vm/intermediate_language.h"
+#include "vm/object_store.h"
+#include "vm/parser.h"
+#include "vm/resolver.h"
+#include "vm/scopes.h"
+#include "vm/stack_frame.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+// Quick access to the current isolate and zone.
+#define I (isolate())
+#define Z (zone())
+
+static bool ShouldInlineSimd() {
+  return FlowGraphCompiler::SupportsUnboxedSimd128();
+}
+
+
+static bool CanUnboxDouble() {
+  return FlowGraphCompiler::SupportsUnboxedDoubles();
+}
+
+
+static bool CanConvertUnboxedMintToDouble() {
+  return FlowGraphCompiler::CanConvertUnboxedMintToDouble();
+}
+
+
+// Optimize instance calls using ICData.
+void JitOptimizer::ApplyICData() {
+  VisitBlocks();
+}
+
+
+// Optimize instance calls using cid.  This is called after optimizer
+// converted instance calls to instructions. Any remaining
+// instance calls are either megamorphic calls, cannot be optimized or
+// 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 JitOptimizer::ApplyClassIds() {
+  ASSERT(current_iterator_ == NULL);
+  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    ForwardInstructionIterator it(block_it.Current());
+    current_iterator_ = &it;
+    for (; !it.Done(); it.Advance()) {
+      Instruction* instr = it.Current();
+      if (instr->IsInstanceCall()) {
+        InstanceCallInstr* call = instr->AsInstanceCall();
+        if (call->HasICData()) {
+          if (TryCreateICData(call)) {
+            VisitInstanceCall(call);
+          }
+        }
+      } else if (instr->IsPolymorphicInstanceCall()) {
+        SpecializePolymorphicInstanceCall(instr->AsPolymorphicInstanceCall());
+      }
+    }
+    current_iterator_ = NULL;
+  }
+}
+
+
+// TODO(srdjan): Test/support other number types as well.
+static bool IsNumberCid(intptr_t cid) {
+  return (cid == kSmiCid) || (cid == kDoubleCid);
+}
+
+
+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
+    // to megamorphic call.
+    return false;
+  }
+  GrowableArray<intptr_t> class_ids(call->ic_data()->NumArgsTested());
+  ASSERT(call->ic_data()->NumArgsTested() <= call->ArgumentCount());
+  for (intptr_t i = 0; i < call->ic_data()->NumArgsTested(); i++) {
+    class_ids.Add(call->PushArgumentAt(i)->value()->Type()->ToCid());
+  }
+
+  const Token::Kind op_kind = call->token_kind();
+  if (Token::IsRelationalOperator(op_kind) ||
+      Token::IsEqualityOperator(op_kind) ||
+      Token::IsBinaryOperator(op_kind)) {
+    // Guess cid: if one of the inputs is a number assume that the other
+    // is a number of same type.
+    if (FLAG_guess_icdata_cid) {
+      const intptr_t cid_0 = class_ids[0];
+      const intptr_t cid_1 = class_ids[1];
+      if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) {
+        class_ids[0] = cid_1;
+      } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) {
+        class_ids[1] = cid_0;
+      }
+    }
+  }
+
+  bool all_cids_known = true;
+  for (intptr_t i = 0; i < class_ids.length(); i++) {
+    if (class_ids[i] == kDynamicCid) {
+      // Not all cid-s known.
+      all_cids_known = false;
+      break;
+    }
+  }
+
+  if (all_cids_known) {
+    const Class& receiver_class = Class::Handle(Z,
+        isolate()->class_table()->At(class_ids[0]));
+    if (!receiver_class.is_finalized()) {
+      // Do not eagerly finalize classes. ResolveDynamicForReceiverClass can
+      // cause class finalization, since callee's receiver class may not be
+      // finalized yet.
+      return false;
+    }
+    const Array& args_desc_array = Array::Handle(Z,
+        ArgumentsDescriptor::New(call->ArgumentCount(),
+                                 call->argument_names()));
+    ArgumentsDescriptor args_desc(args_desc_array);
+    const Function& function = Function::Handle(Z,
+        Resolver::ResolveDynamicForReceiverClass(
+            receiver_class,
+            call->function_name(),
+            args_desc,
+            false /* allow add */));
+    if (function.IsNull()) {
+      return false;
+    }
+
+    // Create new ICData, do not modify the one attached to the instruction
+    // since it is attached to the assembly instruction itself.
+    // TODO(srdjan): Prevent modification of ICData object that is
+    // referenced in assembly code.
+    const ICData& ic_data = ICData::ZoneHandle(Z,
+        ICData::NewFrom(*call->ic_data(), class_ids.length()));
+    if (class_ids.length() > 1) {
+      ic_data.AddCheck(class_ids, function);
+    } else {
+      ASSERT(class_ids.length() == 1);
+      ic_data.AddReceiverCheck(class_ids[0], function);
+    }
+    call->set_ic_data(&ic_data);
+    return true;
+  }
+
+  // Check if getter or setter in function's class and class is currently leaf.
+  if (FLAG_guess_icdata_cid &&
+      ((call->token_kind() == Token::kGET) ||
+          (call->token_kind() == Token::kSET))) {
+    const Class& owner_class = Class::Handle(Z, function().Owner());
+    if (!owner_class.is_abstract() &&
+        !CHA::HasSubclasses(owner_class) &&
+        !CHA::IsImplemented(owner_class)) {
+      const Array& args_desc_array = Array::Handle(Z,
+          ArgumentsDescriptor::New(call->ArgumentCount(),
+                                   call->argument_names()));
+      ArgumentsDescriptor args_desc(args_desc_array);
+      const Function& function = Function::Handle(Z,
+          Resolver::ResolveDynamicForReceiverClass(owner_class,
+                                                   call->function_name(),
+                                                   args_desc,
+                                                   false /* allow_add */));
+      if (!function.IsNull()) {
+        const ICData& ic_data = ICData::ZoneHandle(Z,
+            ICData::NewFrom(*call->ic_data(), class_ids.length()));
+        ic_data.AddReceiverCheck(owner_class.id(), function);
+        call->set_ic_data(&ic_data);
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+
+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)) {
+    return ic_data;  // Nothing to do
+  }
+
+  const Function& function =
+      Function::Handle(Z, ic_data.GetTargetForReceiverClassId(cid));
+  // TODO(fschneider): Try looking up the function on the class if it is
+  // not found in the ICData.
+  if (!function.IsNull()) {
+    const ICData& new_ic_data = ICData::ZoneHandle(Z, ICData::New(
+        Function::Handle(Z, ic_data.Owner()),
+        String::Handle(Z, ic_data.target_name()),
+        Object::empty_array(),  // Dummy argument descriptor.
+        ic_data.deopt_id(),
+        ic_data.NumArgsTested()));
+    new_ic_data.SetDeoptReasons(ic_data.DeoptReasons());
+    new_ic_data.AddReceiverCheck(cid, function);
+    return new_ic_data;
+  }
+
+  return ic_data;
+}
+
+
+void JitOptimizer::SpecializePolymorphicInstanceCall(
+    PolymorphicInstanceCallInstr* call) {
+  if (!FLAG_polymorphic_with_deopt) {
+    // Specialization adds receiver checks which can lead to deoptimization.
+    return;
+  }
+  if (!call->with_checks()) {
+    return;  // Already specialized.
+  }
+
+  const intptr_t receiver_cid =
+      call->PushArgumentAt(0)->value()->Type()->ToCid();
+  if (receiver_cid == kDynamicCid) {
+    return;  // No information about receiver was infered.
+  }
+
+  const ICData& ic_data = TrySpecializeICData(call->ic_data(), receiver_cid);
+  if (ic_data.raw() == call->ic_data().raw()) {
+    // No specialization.
+    return;
+  }
+
+  const bool with_checks = false;
+  PolymorphicInstanceCallInstr* specialized =
+      new(Z) PolymorphicInstanceCallInstr(call->instance_call(),
+                                          ic_data,
+                                          with_checks);
+  call->ReplaceWith(specialized, current_iterator());
+}
+
+
+static BinarySmiOpInstr* AsSmiShiftLeftInstruction(Definition* d) {
+  BinarySmiOpInstr* instr = d->AsBinarySmiOp();
+  if ((instr != NULL) && (instr->op_kind() == Token::kSHL)) {
+    return instr;
+  }
+  return NULL;
+}
+
+
+static bool IsPositiveOrZeroSmiConst(Definition* d) {
+  ConstantInstr* const_instr = d->AsConstant();
+  if ((const_instr != NULL) && (const_instr->value().IsSmi())) {
+    return Smi::Cast(const_instr->value()).Value() >= 0;
+  }
+  return false;
+}
+
+
+void JitOptimizer::OptimizeLeftShiftBitAndSmiOp(
+    Definition* bit_and_instr,
+    Definition* left_instr,
+    Definition* right_instr) {
+  ASSERT(bit_and_instr != NULL);
+  ASSERT((left_instr != NULL) && (right_instr != NULL));
+
+  // Check for pattern, smi_shift_left must be single-use.
+  bool is_positive_or_zero = IsPositiveOrZeroSmiConst(left_instr);
+  if (!is_positive_or_zero) {
+    is_positive_or_zero = IsPositiveOrZeroSmiConst(right_instr);
+  }
+  if (!is_positive_or_zero) return;
+
+  BinarySmiOpInstr* smi_shift_left = NULL;
+  if (bit_and_instr->InputAt(0)->IsSingleUse()) {
+    smi_shift_left = AsSmiShiftLeftInstruction(left_instr);
+  }
+  if ((smi_shift_left == NULL) && (bit_and_instr->InputAt(1)->IsSingleUse())) {
+    smi_shift_left = AsSmiShiftLeftInstruction(right_instr);
+  }
+  if (smi_shift_left == NULL) return;
+
+  // Pattern recognized.
+  smi_shift_left->mark_truncating();
+  ASSERT(bit_and_instr->IsBinarySmiOp() || bit_and_instr->IsBinaryMintOp());
+  if (bit_and_instr->IsBinaryMintOp()) {
+    // Replace Mint op with Smi op.
+    BinarySmiOpInstr* smi_op = new(Z) BinarySmiOpInstr(
+        Token::kBIT_AND,
+        new(Z) Value(left_instr),
+        new(Z) Value(right_instr),
+        Thread::kNoDeoptId);  // BIT_AND cannot deoptimize.
+    bit_and_instr->ReplaceWith(smi_op, current_iterator());
+  }
+}
+
+
+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);
+  flow_graph()->InsertAfter(instr, extract, NULL, FlowGraph::kValue);
+}
+
+
+// Dart:
+//  var x = d % 10;
+//  var y = d ~/ 10;
+//  var z = x + y;
+//
+// IL:
+//  v4 <- %(v2, v3)
+//  v5 <- ~/(v2, v3)
+//  v6 <- +(v4, v5)
+//
+// IL optimized:
+//  v4 <- DIVMOD(v2, v3);
+//  v5 <- LoadIndexed(v4, 0); // ~/ result
+//  v6 <- LoadIndexed(v4, 1); // % result
+//  v7 <- +(v5, v6)
+// Because of the environment it is important that merged instruction replaces
+// first original instruction encountered.
+void JitOptimizer::TryMergeTruncDivMod(
+    GrowableArray<BinarySmiOpInstr*>* merge_candidates) {
+  if (merge_candidates->length() < 2) {
+    // Need at least a TRUNCDIV and a MOD.
+    return;
+  }
+  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
+    BinarySmiOpInstr* curr_instr = (*merge_candidates)[i];
+    if (curr_instr == NULL) {
+      // Instruction was merged already.
+      continue;
+    }
+    ASSERT((curr_instr->op_kind() == Token::kTRUNCDIV) ||
+           (curr_instr->op_kind() == Token::kMOD));
+    // Check if there is kMOD/kTRUNDIV binop with same inputs.
+    const intptr_t other_kind = (curr_instr->op_kind() == Token::kTRUNCDIV) ?
+        Token::kMOD : Token::kTRUNCDIV;
+    Definition* left_def = curr_instr->left()->definition();
+    Definition* right_def = curr_instr->right()->definition();
+    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
+      BinarySmiOpInstr* other_binop = (*merge_candidates)[k];
+      // 'other_binop' can be NULL if it was already merged.
+      if ((other_binop != NULL) &&
+          (other_binop->op_kind() == other_kind) &&
+          (other_binop->left()->definition() == left_def) &&
+          (other_binop->right()->definition() == right_def)) {
+        (*merge_candidates)[k] = NULL;  // Clear it.
+        ASSERT(curr_instr->HasUses());
+        AppendExtractNthOutputForMerged(
+            curr_instr,
+            MergedMathInstr::OutputIndexOf(curr_instr->op_kind()),
+            kTagged, kSmiCid);
+        ASSERT(other_binop->HasUses());
+        AppendExtractNthOutputForMerged(
+            other_binop,
+            MergedMathInstr::OutputIndexOf(other_binop->op_kind()),
+            kTagged, kSmiCid);
+
+        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(2);
+        args->Add(new(Z) Value(curr_instr->left()->definition()));
+        args->Add(new(Z) Value(curr_instr->right()->definition()));
+
+        // Replace with TruncDivMod.
+        MergedMathInstr* div_mod = new(Z) MergedMathInstr(
+            args,
+            curr_instr->deopt_id(),
+            MergedMathInstr::kTruncDivMod);
+        curr_instr->ReplaceWith(div_mod, current_iterator());
+        other_binop->ReplaceUsesWith(div_mod);
+        other_binop->RemoveFromGraph();
+        // Only one merge possible. Because canonicalization happens later,
+        // more candidates are possible.
+        // TODO(srdjan): Allow merging of trunc-div/mod into truncDivMod.
+        break;
+      }
+    }
+  }
+}
+
+
+// Tries to merge MathUnary operations, in this case sinus and cosinus.
+void JitOptimizer::TryMergeMathUnary(
+    GrowableArray<MathUnaryInstr*>* merge_candidates) {
+  if (!FlowGraphCompiler::SupportsSinCos() || !CanUnboxDouble() ||
+      !FLAG_merge_sin_cos) {
+    return;
+  }
+  if (merge_candidates->length() < 2) {
+    // Need at least a SIN and a COS.
+    return;
+  }
+  for (intptr_t i = 0; i < merge_candidates->length(); i++) {
+    MathUnaryInstr* curr_instr = (*merge_candidates)[i];
+    if (curr_instr == NULL) {
+      // Instruction was merged already.
+      continue;
+    }
+    const intptr_t kind = curr_instr->kind();
+    ASSERT((kind == MathUnaryInstr::kSin) ||
+           (kind == MathUnaryInstr::kCos));
+    // Check if there is sin/cos binop with same inputs.
+    const intptr_t other_kind = (kind == MathUnaryInstr::kSin) ?
+        MathUnaryInstr::kCos : MathUnaryInstr::kSin;
+    Definition* def = curr_instr->value()->definition();
+    for (intptr_t k = i + 1; k < merge_candidates->length(); k++) {
+      MathUnaryInstr* other_op = (*merge_candidates)[k];
+      // 'other_op' can be NULL if it was already merged.
+      if ((other_op != NULL) && (other_op->kind() == other_kind) &&
+          (other_op->value()->definition() == def)) {
+        (*merge_candidates)[k] = NULL;  // Clear it.
+        ASSERT(curr_instr->HasUses());
+        AppendExtractNthOutputForMerged(curr_instr,
+                                        MergedMathInstr::OutputIndexOf(kind),
+                                        kUnboxedDouble, kDoubleCid);
+        ASSERT(other_op->HasUses());
+        AppendExtractNthOutputForMerged(
+            other_op,
+            MergedMathInstr::OutputIndexOf(other_kind),
+            kUnboxedDouble, kDoubleCid);
+        ZoneGrowableArray<Value*>* args = new(Z) ZoneGrowableArray<Value*>(1);
+        args->Add(new(Z) Value(curr_instr->value()->definition()));
+        // Replace with SinCos.
+        MergedMathInstr* sin_cos =
+            new(Z) MergedMathInstr(args,
+                                   curr_instr->DeoptimizationTarget(),
+                                   MergedMathInstr::kSinCos);
+        curr_instr->ReplaceWith(sin_cos, current_iterator());
+        other_op->ReplaceUsesWith(sin_cos);
+        other_op->RemoveFromGraph();
+        // Only one merge possible. Because canonicalization happens later,
+        // more candidates are possible.
+        // TODO(srdjan): Allow merging of sin/cos into sincos.
+        break;
+      }
+    }
+  }
+}
+
+
+// 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 JitOptimizer::TryOptimizePatterns() {
+  if (!FLAG_truncating_left_shift) return;
+  ASSERT(current_iterator_ == NULL);
+  GrowableArray<BinarySmiOpInstr*> div_mod_merge;
+  GrowableArray<MathUnaryInstr*> sin_cos_merge;
+  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    // Merging only per basic-block.
+    div_mod_merge.Clear();
+    sin_cos_merge.Clear();
+    ForwardInstructionIterator it(block_it.Current());
+    current_iterator_ = &it;
+    for (; !it.Done(); it.Advance()) {
+      if (it.Current()->IsBinarySmiOp()) {
+        BinarySmiOpInstr* binop = it.Current()->AsBinarySmiOp();
+        if (binop->op_kind() == Token::kBIT_AND) {
+          OptimizeLeftShiftBitAndSmiOp(binop,
+                                       binop->left()->definition(),
+                                       binop->right()->definition());
+        } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
+                   (binop->op_kind() == Token::kMOD)) {
+          if (binop->HasUses()) {
+            div_mod_merge.Add(binop);
+          }
+        }
+      } else if (it.Current()->IsBinaryMintOp()) {
+        BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
+        if (mintop->op_kind() == Token::kBIT_AND) {
+          OptimizeLeftShiftBitAndSmiOp(mintop,
+                                       mintop->left()->definition(),
+                                       mintop->right()->definition());
+        }
+      } else if (it.Current()->IsMathUnary()) {
+        MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
+        if ((math_unary->kind() == MathUnaryInstr::kSin) ||
+            (math_unary->kind() == MathUnaryInstr::kCos)) {
+          if (math_unary->HasUses()) {
+            sin_cos_merge.Add(math_unary);
+          }
+        }
+      }
+    }
+    TryMergeTruncDivMod(&div_mod_merge);
+    TryMergeMathUnary(&sin_cos_merge);
+    current_iterator_ = NULL;
+  }
+}
+
+
+static bool ClassIdIsOneOf(intptr_t class_id,
+                           const GrowableArray<intptr_t>& class_ids) {
+  for (intptr_t i = 0; i < class_ids.length(); i++) {
+    ASSERT(class_ids[i] != kIllegalCid);
+    if (class_ids[i] == class_id) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// Returns true if ICData tests two arguments and all ICData cids are in the
+// required sets 'receiver_class_ids' or 'argument_class_ids', respectively.
+static bool ICDataHasOnlyReceiverArgumentClassIds(
+    const ICData& ic_data,
+    const GrowableArray<intptr_t>& receiver_class_ids,
+    const GrowableArray<intptr_t>& argument_class_ids) {
+  if (ic_data.NumArgsTested() != 2) {
+    return false;
+  }
+  const intptr_t len = ic_data.NumberOfChecks();
+  GrowableArray<intptr_t> class_ids;
+  for (intptr_t i = 0; i < len; i++) {
+    if (ic_data.IsUsedAt(i)) {
+      ic_data.GetClassIdsAt(i, &class_ids);
+      ASSERT(class_ids.length() == 2);
+      if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
+          !ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+
+static bool ICDataHasReceiverArgumentClassIds(const ICData& ic_data,
+                                              intptr_t receiver_class_id,
+                                              intptr_t argument_class_id) {
+  if (ic_data.NumArgsTested() != 2) {
+    return false;
+  }
+  const intptr_t len = ic_data.NumberOfChecks();
+  for (intptr_t i = 0; i < len; i++) {
+    if (ic_data.IsUsedAt(i)) {
+      GrowableArray<intptr_t> class_ids;
+      ic_data.GetClassIdsAt(i, &class_ids);
+      ASSERT(class_ids.length() == 2);
+      if ((class_ids[0] == receiver_class_id) &&
+          (class_ids[1] == argument_class_id)) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+static bool HasOnlyOneSmi(const ICData& ic_data) {
+  return (ic_data.NumberOfUsedChecks() == 1)
+      && ic_data.HasReceiverClassId(kSmiCid);
+}
+
+
+static bool HasOnlySmiOrMint(const ICData& ic_data) {
+  if (ic_data.NumberOfUsedChecks() == 1) {
+    return ic_data.HasReceiverClassId(kSmiCid)
+        || ic_data.HasReceiverClassId(kMintCid);
+  }
+  return (ic_data.NumberOfUsedChecks() == 2)
+      && ic_data.HasReceiverClassId(kSmiCid)
+      && ic_data.HasReceiverClassId(kMintCid);
+}
+
+
+static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid) {
+  if (ic_data.NumberOfUsedChecks() != 1) {
+    return false;
+  }
+  GrowableArray<intptr_t> first;
+  GrowableArray<intptr_t> second;
+  ic_data.GetUsedCidsForTwoArgs(&first, &second);
+  return (first[0] == cid) && (second[0] == cid);
+}
+
+// Returns false if the ICData contains anything other than the 4 combinations
+// of Mint and Smi for the receiver and argument classes.
+static bool HasTwoMintOrSmi(const ICData& ic_data) {
+  GrowableArray<intptr_t> first;
+  GrowableArray<intptr_t> second;
+  ic_data.GetUsedCidsForTwoArgs(&first, &second);
+  for (intptr_t i = 0; i < first.length(); i++) {
+    if ((first[i] != kSmiCid) && (first[i] != kMintCid)) {
+      return false;
+    }
+    if ((second[i] != kSmiCid) && (second[i] != kMintCid)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+// Returns false if the ICData contains anything other than the 4 combinations
+// of Double and Smi for the receiver and argument classes.
+static bool HasTwoDoubleOrSmi(const ICData& ic_data) {
+  GrowableArray<intptr_t> class_ids(2);
+  class_ids.Add(kSmiCid);
+  class_ids.Add(kDoubleCid);
+  return ICDataHasOnlyReceiverArgumentClassIds(ic_data, class_ids, class_ids);
+}
+
+
+static bool HasOnlyOneDouble(const ICData& ic_data) {
+  return (ic_data.NumberOfUsedChecks() == 1)
+      && ic_data.HasReceiverClassId(kDoubleCid);
+}
+
+
+static bool ShouldSpecializeForDouble(const ICData& ic_data) {
+  // Don't specialize for double if we can't unbox them.
+  if (!CanUnboxDouble()) {
+    return false;
+  }
+
+  // Unboxed double operation can't handle case of two smis.
+  if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+    return false;
+  }
+
+  // Check that it have seen only smis and doubles.
+  return HasTwoDoubleOrSmi(ic_data);
+}
+
+
+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);
+    push->ReplaceUsesWith(push->value()->definition());
+    push->RemoveFromGraph();
+  }
+  call->ReplaceWith(replacement, current_iterator());
+}
+
+
+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),
+                                      deopt_id,
+                                      insert_before->token_pos()),
+                 deopt_environment,
+                 FlowGraph::kEffect);
+  }
+}
+
+
+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),
+                                deopt_id,
+                                token_pos);
+  }
+  return new(Z) CheckClassInstr(
+      new(Z) Value(to_check), deopt_id, unary_checks, token_pos);
+}
+
+
+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());
+  InsertBefore(insert_before, check, deopt_environment, FlowGraph::kEffect);
+}
+
+
+void JitOptimizer::AddReceiverCheck(InstanceCallInstr* call) {
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks()),
+                call->deopt_id(),
+                call->env(),
+                call);
+}
+
+
+static bool ArgIsAlways(intptr_t cid,
+                        const ICData& ic_data,
+                        intptr_t arg_number) {
+  ASSERT(ic_data.NumArgsTested() > arg_number);
+  if (ic_data.NumberOfUsedChecks() == 0) {
+    return false;
+  }
+  const intptr_t num_checks = ic_data.NumberOfChecks();
+  for (intptr_t i = 0; i < num_checks; i++) {
+    if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+bool JitOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) {
+  // Check for monomorphic IC data.
+  if (!call->HasICData()) return false;
+  const ICData& ic_data =
+      ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks());
+  if (ic_data.NumberOfChecks() != 1) {
+    return false;
+  }
+  return TryReplaceInstanceCallWithInline(call);
+}
+
+
+// Return true if d is a string of length one (a constant or result from
+// from string-from-char-code instruction.
+static bool IsLengthOneString(Definition* d) {
+  if (d->IsConstant()) {
+    const Object& obj = d->AsConstant()->value();
+    if (obj.IsString()) {
+      return String::Cast(obj).Length() == 1;
+    } else {
+      return false;
+    }
+  } else {
+    return d->IsStringFromCharCode();
+  }
+}
+
+
+// Returns true if the string comparison was converted into char-code
+// 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 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.
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  Value* left_val = NULL;
+  Definition* to_remove_left = NULL;
+  if (IsLengthOneString(right)) {
+    // Swap, since we know that both arguments are strings
+    Definition* temp = left;
+    left = right;
+    right = temp;
+  }
+  if (IsLengthOneString(left)) {
+    // Optimize if left is a string with length one (either constant or
+    // result of string-from-char-code.
+    if (left->IsConstant()) {
+      ConstantInstr* left_const = left->AsConstant();
+      const String& str = String::Cast(left_const->value());
+      ASSERT(str.Length() == 1);
+      ConstantInstr* char_code_left = flow_graph()->GetConstant(
+          Smi::ZoneHandle(Z, Smi::New(static_cast<intptr_t>(str.CharAt(0)))));
+      left_val = new(Z) Value(char_code_left);
+    } else if (left->IsStringFromCharCode()) {
+      // Use input of string-from-charcode as left value.
+      StringFromCharCodeInstr* instr = left->AsStringFromCharCode();
+      left_val = new(Z) Value(instr->char_code()->definition());
+      to_remove_left = instr;
+    } else {
+      // IsLengthOneString(left) should have been false.
+      UNREACHABLE();
+    }
+
+    Definition* to_remove_right = NULL;
+    Value* right_val = NULL;
+    if (right->IsStringFromCharCode()) {
+      // Skip string-from-char-code, and use its input as right value.
+      StringFromCharCodeInstr* right_instr = right->AsStringFromCharCode();
+      right_val = new(Z) Value(right_instr->char_code()->definition());
+      to_remove_right = right_instr;
+    } else {
+      const ICData& unary_checks_1 =
+          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
+      AddCheckClass(right,
+                    unary_checks_1,
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      // String-to-char-code instructions returns -1 (illegal charcode) if
+      // string is not of length one.
+      StringToCharCodeInstr* char_code_right =
+          new(Z) StringToCharCodeInstr(new(Z) Value(right), kOneByteStringCid);
+      InsertBefore(call, char_code_right, call->env(), FlowGraph::kValue);
+      right_val = new(Z) Value(char_code_right);
+    }
+
+    // Comparing char-codes instead of strings.
+    EqualityCompareInstr* comp =
+        new(Z) EqualityCompareInstr(call->token_pos(),
+                                    op_kind,
+                                    left_val,
+                                    right_val,
+                                    kSmiCid,
+                                    call->deopt_id());
+    ReplaceCall(call, comp);
+
+    // Remove dead instructions.
+    if ((to_remove_left != NULL) &&
+        (to_remove_left->input_use_list() == NULL)) {
+      to_remove_left->ReplaceUsesWith(flow_graph()->constant_null());
+      to_remove_left->RemoveFromGraph();
+    }
+    if ((to_remove_right != NULL) &&
+        (to_remove_right->input_use_list() == NULL)) {
+      to_remove_right->ReplaceUsesWith(flow_graph()->constant_null());
+      to_remove_right->RemoveFromGraph();
+    }
+    return true;
+  }
+  return false;
+}
+
+
+static bool SmiFitsInDouble() { return kSmiBits < 53; }
+
+bool JitOptimizer::TryReplaceWithEqualityOp(InstanceCallInstr* call,
+                                            Token::Kind op_kind) {
+  const ICData& ic_data = *call->ic_data();
+  ASSERT(ic_data.NumArgsTested() == 2);
+
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+
+  intptr_t cid = kIllegalCid;
+  if (HasOnlyTwoOf(ic_data, kOneByteStringCid)) {
+    if (TryStringLengthOneEquality(call, op_kind)) {
+      return true;
+    } else {
+      return false;
+    }
+  } else if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(left),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(right),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    cid = kSmiCid;
+  } else if (HasTwoMintOrSmi(ic_data) &&
+             FlowGraphCompiler::SupportsUnboxedMints()) {
+    cid = kMintCid;
+  } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
+    // Use double comparison.
+    if (SmiFitsInDouble()) {
+      cid = kDoubleCid;
+    } else {
+      if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+        // We cannot use double comparison on two smis. Need polymorphic
+        // call.
+        return false;
+      } else {
+        InsertBefore(call,
+                     new(Z) CheckEitherNonSmiInstr(
+                         new(Z) Value(left),
+                         new(Z) Value(right),
+                         call->deopt_id()),
+                     call->env(),
+                     FlowGraph::kEffect);
+        cid = kDoubleCid;
+      }
+    }
+  } else {
+    // Check if ICDData contains checks with Smi/Null combinations. In that case
+    // we can still emit the optimized Smi equality operation but need to add
+    // checks for null or Smi.
+    GrowableArray<intptr_t> smi_or_null(2);
+    smi_or_null.Add(kSmiCid);
+    smi_or_null.Add(kNullCid);
+    if (ICDataHasOnlyReceiverArgumentClassIds(ic_data,
+                                              smi_or_null,
+                                              smi_or_null)) {
+      const ICData& unary_checks_0 =
+          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
+      AddCheckClass(left,
+                    unary_checks_0,
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+
+      const ICData& unary_checks_1 =
+          ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecksForArgNr(1));
+      AddCheckClass(right,
+                    unary_checks_1,
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      cid = kSmiCid;
+    } else {
+      // Shortcut for equality with null.
+      ConstantInstr* right_const = right->AsConstant();
+      ConstantInstr* left_const = left->AsConstant();
+      if ((right_const != NULL && right_const->value().IsNull()) ||
+          (left_const != NULL && left_const->value().IsNull())) {
+        StrictCompareInstr* comp =
+            new(Z) StrictCompareInstr(call->token_pos(),
+                                      Token::kEQ_STRICT,
+                                      new(Z) Value(left),
+                                      new(Z) Value(right),
+                                      false);  // No number check.
+        ReplaceCall(call, comp);
+        return true;
+      }
+      return false;
+    }
+  }
+  ASSERT(cid != kIllegalCid);
+  EqualityCompareInstr* comp = new(Z) EqualityCompareInstr(call->token_pos(),
+                                                           op_kind,
+                                                           new(Z) Value(left),
+                                                           new(Z) Value(right),
+                                                           cid,
+                                                           call->deopt_id());
+  ReplaceCall(call, comp);
+  return true;
+}
+
+
+bool JitOptimizer::TryReplaceWithRelationalOp(InstanceCallInstr* call,
+                                              Token::Kind op_kind) {
+  const ICData& ic_data = *call->ic_data();
+  ASSERT(ic_data.NumArgsTested() == 2);
+
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+
+  intptr_t cid = kIllegalCid;
+  if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(left),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(right),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    cid = kSmiCid;
+  } else if (HasTwoMintOrSmi(ic_data) &&
+             FlowGraphCompiler::SupportsUnboxedMints()) {
+    cid = kMintCid;
+  } else if (HasTwoDoubleOrSmi(ic_data) && CanUnboxDouble()) {
+    // Use double comparison.
+    if (SmiFitsInDouble()) {
+      cid = kDoubleCid;
+    } else {
+      if (ICDataHasReceiverArgumentClassIds(ic_data, kSmiCid, kSmiCid)) {
+        // We cannot use double comparison on two smis. Need polymorphic
+        // call.
+        return false;
+      } else {
+        InsertBefore(call,
+                     new(Z) CheckEitherNonSmiInstr(
+                         new(Z) Value(left),
+                         new(Z) Value(right),
+                         call->deopt_id()),
+                     call->env(),
+                     FlowGraph::kEffect);
+        cid = kDoubleCid;
+      }
+    }
+  } else {
+    return false;
+  }
+  ASSERT(cid != kIllegalCid);
+  RelationalOpInstr* comp = new(Z) RelationalOpInstr(call->token_pos(),
+                                                     op_kind,
+                                                     new(Z) Value(left),
+                                                     new(Z) Value(right),
+                                                     cid,
+                                                     call->deopt_id());
+  ReplaceCall(call, comp);
+  return true;
+}
+
+
+bool JitOptimizer::TryReplaceWithBinaryOp(InstanceCallInstr* call,
+                                          Token::Kind op_kind) {
+  intptr_t operands_type = kIllegalCid;
+  ASSERT(call->HasICData());
+  const ICData& ic_data = *call->ic_data();
+  switch (op_kind) {
+    case Token::kADD:
+    case Token::kSUB:
+    case Token::kMUL:
+      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+        // Don't generate smi code if the IC data is marked because
+        // of an overflow.
+        operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
+            ? kMintCid
+            : kSmiCid;
+      } else if (HasTwoMintOrSmi(ic_data) &&
+                 FlowGraphCompiler::SupportsUnboxedMints()) {
+        // Don't generate mint code if the IC data is marked because of an
+        // overflow.
+        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) return false;
+        operands_type = kMintCid;
+      } else if (ShouldSpecializeForDouble(ic_data)) {
+        operands_type = kDoubleCid;
+      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
+        operands_type = kFloat32x4Cid;
+      } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+        ASSERT(op_kind != Token::kMUL);  // Int32x4 doesn't have a multiply op.
+        operands_type = kInt32x4Cid;
+      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
+        operands_type = kFloat64x2Cid;
+      } else {
+        return false;
+      }
+      break;
+    case Token::kDIV:
+      if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
+      if (ShouldSpecializeForDouble(ic_data) ||
+          HasOnlyTwoOf(ic_data, kSmiCid)) {
+        operands_type = kDoubleCid;
+      } else if (HasOnlyTwoOf(ic_data, kFloat32x4Cid)) {
+        operands_type = kFloat32x4Cid;
+      } else if (HasOnlyTwoOf(ic_data, kFloat64x2Cid)) {
+        operands_type = kFloat64x2Cid;
+      } else {
+        return false;
+      }
+      break;
+    case Token::kBIT_AND:
+    case Token::kBIT_OR:
+    case Token::kBIT_XOR:
+      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+        operands_type = kSmiCid;
+      } else if (HasTwoMintOrSmi(ic_data)) {
+        operands_type = kMintCid;
+      } else if (HasOnlyTwoOf(ic_data, kInt32x4Cid)) {
+        operands_type = kInt32x4Cid;
+      } else {
+        return false;
+      }
+      break;
+    case Token::kSHR:
+    case Token::kSHL:
+      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+        // Left shift may overflow from smi into mint or big ints.
+        // Don't generate smi code if the IC data is marked because
+        // of an overflow.
+        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
+          return false;
+        }
+        operands_type = ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)
+            ? kMintCid
+            : kSmiCid;
+      } else if (HasTwoMintOrSmi(ic_data) &&
+                 HasOnlyOneSmi(ICData::Handle(Z,
+                     ic_data.AsUnaryClassChecksForArgNr(1)))) {
+        // Don't generate mint code if the IC data is marked because of an
+        // overflow.
+        if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
+          return false;
+        }
+        // Check for smi/mint << smi or smi/mint >> smi.
+        operands_type = kMintCid;
+      } else {
+        return false;
+      }
+      break;
+    case Token::kMOD:
+    case Token::kTRUNCDIV:
+      if (!FlowGraphCompiler::SupportsHardwareDivision()) return false;
+      if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+        if (ic_data.HasDeoptReason(ICData::kDeoptBinarySmiOp)) {
+          return false;
+        }
+        operands_type = kSmiCid;
+      } else {
+        return false;
+      }
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  if (operands_type == kDoubleCid) {
+    if (!CanUnboxDouble()) {
+      return false;
+    }
+    // Check that either left or right are not a smi.  Result of a
+    // binary operation with two smis is a smi not a double, except '/' which
+    // returns a double for two smis.
+    if (op_kind != Token::kDIV) {
+      InsertBefore(call,
+                   new(Z) CheckEitherNonSmiInstr(
+                       new(Z) Value(left),
+                       new(Z) Value(right),
+                       call->deopt_id()),
+                   call->env(),
+                   FlowGraph::kEffect);
+    }
+
+    BinaryDoubleOpInstr* double_bin_op =
+        new(Z) BinaryDoubleOpInstr(op_kind,
+                                   new(Z) Value(left),
+                                   new(Z) Value(right),
+                                   call->deopt_id(), call->token_pos());
+    ReplaceCall(call, double_bin_op);
+  } else if (operands_type == kMintCid) {
+    if (!FlowGraphCompiler::SupportsUnboxedMints()) return false;
+    if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
+      ShiftMintOpInstr* shift_op =
+          new(Z) ShiftMintOpInstr(
+              op_kind, new(Z) Value(left), new(Z) Value(right),
+              call->deopt_id());
+      ReplaceCall(call, shift_op);
+    } else {
+      BinaryMintOpInstr* bin_op =
+          new(Z) BinaryMintOpInstr(
+              op_kind, new(Z) Value(left), new(Z) Value(right),
+              call->deopt_id());
+      ReplaceCall(call, bin_op);
+    }
+  } else if (operands_type == kFloat32x4Cid) {
+    return InlineFloat32x4BinaryOp(call, op_kind);
+  } else if (operands_type == kInt32x4Cid) {
+    return InlineInt32x4BinaryOp(call, op_kind);
+  } else if (operands_type == kFloat64x2Cid) {
+    return InlineFloat64x2BinaryOp(call, op_kind);
+  } else if (op_kind == Token::kMOD) {
+    ASSERT(operands_type == kSmiCid);
+    if (right->IsConstant()) {
+      const Object& obj = right->AsConstant()->value();
+      if (obj.IsSmi() && Utils::IsPowerOfTwo(Smi::Cast(obj).Value())) {
+        // Insert smi check and attach a copy of the original environment
+        // because the smi operation can still deoptimize.
+        InsertBefore(call,
+                     new(Z) CheckSmiInstr(new(Z) Value(left),
+                                          call->deopt_id(),
+                                          call->token_pos()),
+                     call->env(),
+                     FlowGraph::kEffect);
+        ConstantInstr* constant =
+            flow_graph()->GetConstant(Smi::Handle(Z,
+                Smi::New(Smi::Cast(obj).Value() - 1)));
+        BinarySmiOpInstr* bin_op =
+            new(Z) BinarySmiOpInstr(Token::kBIT_AND,
+                                    new(Z) Value(left),
+                                    new(Z) Value(constant),
+                                    call->deopt_id());
+        ReplaceCall(call, bin_op);
+        return true;
+      }
+    }
+    // Insert two smi checks and attach a copy of the original
+    // environment because the smi operation can still deoptimize.
+    AddCheckSmi(left, call->deopt_id(), call->env(), call);
+    AddCheckSmi(right, call->deopt_id(), call->env(), call);
+    BinarySmiOpInstr* bin_op =
+        new(Z) BinarySmiOpInstr(op_kind,
+                                new(Z) Value(left),
+                                new(Z) Value(right),
+                                call->deopt_id());
+    ReplaceCall(call, bin_op);
+  } else {
+    ASSERT(operands_type == kSmiCid);
+    // Insert two smi checks and attach a copy of the original
+    // environment because the smi operation can still deoptimize.
+    AddCheckSmi(left, call->deopt_id(), call->env(), call);
+    AddCheckSmi(right, call->deopt_id(), call->env(), call);
+    if (left->IsConstant() &&
+        ((op_kind == Token::kADD) || (op_kind == Token::kMUL))) {
+      // Constant should be on the right side.
+      Definition* temp = left;
+      left = right;
+      right = temp;
+    }
+    BinarySmiOpInstr* bin_op =
+        new(Z) BinarySmiOpInstr(
+            op_kind,
+            new(Z) Value(left),
+            new(Z) Value(right),
+            call->deopt_id());
+    ReplaceCall(call, bin_op);
+  }
+  return true;
+}
+
+
+bool JitOptimizer::TryReplaceWithUnaryOp(InstanceCallInstr* call,
+                                         Token::Kind op_kind) {
+  ASSERT(call->ArgumentCount() == 1);
+  Definition* input = call->ArgumentAt(0);
+  Definition* unary_op = NULL;
+  if (HasOnlyOneSmi(*call->ic_data())) {
+    InsertBefore(call,
+                 new(Z) CheckSmiInstr(new(Z) Value(input),
+                                      call->deopt_id(),
+                                      call->token_pos()),
+                 call->env(),
+                 FlowGraph::kEffect);
+    unary_op = new(Z) UnarySmiOpInstr(
+        op_kind, new(Z) Value(input), call->deopt_id());
+  } else if ((op_kind == Token::kBIT_NOT) &&
+             HasOnlySmiOrMint(*call->ic_data()) &&
+             FlowGraphCompiler::SupportsUnboxedMints()) {
+    unary_op = new(Z) UnaryMintOpInstr(
+        op_kind, new(Z) Value(input), call->deopt_id());
+  } else if (HasOnlyOneDouble(*call->ic_data()) &&
+             (op_kind == Token::kNEGATE) &&
+             CanUnboxDouble()) {
+    AddReceiverCheck(call);
+    unary_op = new(Z) UnaryDoubleOpInstr(
+        Token::kNEGATE, new(Z) Value(input), call->deopt_id());
+  } else {
+    return false;
+  }
+  ASSERT(unary_op != NULL);
+  ReplaceCall(call, unary_op);
+  return true;
+}
+
+
+// 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()) {
+      if (Compiler::IsBackgroundCompilation() ||
+          FLAG_force_clone_compiler_objects) {
+        return field.CloneFromOriginal();
+      } else {
+        return field.raw();
+      }
+    }
+    cls = cls.SuperClass();
+  }
+  return Field::null();
+}
+
+
+// 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 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
+    // may later add overriding methods.
+    return true;
+  }
+  Definition* callee_receiver = call->ArgumentAt(0);
+  ASSERT(callee_receiver != NULL);
+  const Function& function = flow_graph_->function();
+  if (function.IsDynamicFunction() &&
+      callee_receiver->IsParameter() &&
+      (callee_receiver->AsParameter()->index() == 0)) {
+    const String& name = (kind == RawFunction::kMethodExtractor)
+        ? String::Handle(Z, Field::NameFromGetter(call->function_name()))
+        : call->function_name();
+    const Class& cls = Class::Handle(Z, function.Owner());
+    if (!thread()->cha()->HasOverride(cls, name)) {
+      if (FLAG_trace_cha) {
+        THR_Print("  **(CHA) Instance call needs no check, "
+            "no overrides of '%s' '%s'\n",
+            name.ToCString(), cls.ToCString());
+      }
+      thread()->cha()->AddToLeafClasses(cls);
+      return false;
+    }
+  }
+  return true;
+}
+
+
+bool JitOptimizer::InlineImplicitInstanceGetter(InstanceCallInstr* call) {
+  ASSERT(call->HasICData());
+  const ICData& ic_data = *call->ic_data();
+  ASSERT(ic_data.HasOneTarget());
+  GrowableArray<intptr_t> class_ids;
+  ic_data.GetClassIdsAt(0, &class_ids);
+  ASSERT(class_ids.length() == 1);
+  // Inline implicit instance getter.
+  const String& field_name =
+      String::Handle(Z, Field::NameFromGetter(call->function_name()));
+  const Field& field =
+      Field::ZoneHandle(Z, GetField(class_ids[0], field_name));
+  ASSERT(!field.IsNull());
+
+  if (InstanceCallNeedsClassCheck(call, RawFunction::kImplicitGetter)) {
+    AddReceiverCheck(call);
+  }
+  LoadFieldInstr* load = new(Z) LoadFieldInstr(
+      new(Z) Value(call->ArgumentAt(0)),
+      &field,
+      AbstractType::ZoneHandle(Z, field.type()),
+      call->token_pos());
+  load->set_is_immutable(field.is_final());
+  if (field.guarded_cid() != kIllegalCid) {
+    if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) {
+      load->set_result_cid(field.guarded_cid());
+    }
+    flow_graph()->parsed_function().AddToGuardedFields(&field);
+  }
+
+  // Discard the environment from the original instruction because the load
+  // can't deoptimize.
+  call->RemoveEnvironment();
+  ReplaceCall(call, load);
+
+  if (load->result_cid() != kDynamicCid) {
+    // Reset value types if guarded_cid was used.
+    for (Value::Iterator it(load->input_use_list());
+         !it.Done();
+         it.Advance()) {
+      it.Current()->SetReachingType(NULL);
+    }
+  }
+  return true;
+}
+
+
+bool JitOptimizer::InlineFloat32x4Getter(InstanceCallInstr* call,
+                                         MethodRecognizer::Kind getter) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  intptr_t mask = 0;
+  if ((getter == MethodRecognizer::kFloat32x4Shuffle) ||
+      (getter == MethodRecognizer::kFloat32x4ShuffleMix)) {
+    // Extract shuffle mask.
+    Definition* mask_definition = NULL;
+    if (getter == MethodRecognizer::kFloat32x4Shuffle) {
+      ASSERT(call->ArgumentCount() == 2);
+      mask_definition = call->ArgumentAt(1);
+    } else {
+      ASSERT(getter == MethodRecognizer::kFloat32x4ShuffleMix);
+      ASSERT(call->ArgumentCount() == 3);
+      mask_definition = call->ArgumentAt(2);
+    }
+    if (!mask_definition->IsConstant()) {
+      return false;
+    }
+    ASSERT(mask_definition->IsConstant());
+    ConstantInstr* constant_instruction = mask_definition->AsConstant();
+    const Object& constant_mask = constant_instruction->value();
+    if (!constant_mask.IsSmi()) {
+      return false;
+    }
+    ASSERT(constant_mask.IsSmi());
+    mask = Smi::Cast(constant_mask).Value();
+    if ((mask < 0) || (mask > 255)) {
+      // Not a valid mask.
+      return false;
+    }
+  }
+  if (getter == MethodRecognizer::kFloat32x4GetSignMask) {
+    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else if (getter == MethodRecognizer::kFloat32x4ShuffleMix) {
+    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        new(Z) Value(call->ArgumentAt(1)),
+        mask,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else {
+    ASSERT((getter == MethodRecognizer::kFloat32x4Shuffle)  ||
+           (getter == MethodRecognizer::kFloat32x4ShuffleX) ||
+           (getter == MethodRecognizer::kFloat32x4ShuffleY) ||
+           (getter == MethodRecognizer::kFloat32x4ShuffleZ) ||
+           (getter == MethodRecognizer::kFloat32x4ShuffleW));
+    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        mask,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  }
+  UNREACHABLE();
+  return false;
+}
+
+
+bool JitOptimizer::InlineFloat64x2Getter(InstanceCallInstr* call,
+                                         MethodRecognizer::Kind getter) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  if ((getter == MethodRecognizer::kFloat64x2GetX) ||
+      (getter == MethodRecognizer::kFloat64x2GetY)) {
+    Simd64x2ShuffleInstr* instr = new(Z) Simd64x2ShuffleInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        0,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  }
+  UNREACHABLE();
+  return false;
+}
+
+
+bool JitOptimizer::InlineInt32x4Getter(InstanceCallInstr* call,
+                                       MethodRecognizer::Kind getter) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  AddCheckClass(call->ArgumentAt(0),
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  intptr_t mask = 0;
+  if ((getter == MethodRecognizer::kInt32x4Shuffle) ||
+      (getter == MethodRecognizer::kInt32x4ShuffleMix)) {
+    // Extract shuffle mask.
+    Definition* mask_definition = NULL;
+    if (getter == MethodRecognizer::kInt32x4Shuffle) {
+      ASSERT(call->ArgumentCount() == 2);
+      mask_definition = call->ArgumentAt(1);
+    } else {
+      ASSERT(getter == MethodRecognizer::kInt32x4ShuffleMix);
+      ASSERT(call->ArgumentCount() == 3);
+      mask_definition = call->ArgumentAt(2);
+    }
+    if (!mask_definition->IsConstant()) {
+      return false;
+    }
+    ASSERT(mask_definition->IsConstant());
+    ConstantInstr* constant_instruction = mask_definition->AsConstant();
+    const Object& constant_mask = constant_instruction->value();
+    if (!constant_mask.IsSmi()) {
+      return false;
+    }
+    ASSERT(constant_mask.IsSmi());
+    mask = Smi::Cast(constant_mask).Value();
+    if ((mask < 0) || (mask > 255)) {
+      // Not a valid mask.
+      return false;
+    }
+  }
+  if (getter == MethodRecognizer::kInt32x4GetSignMask) {
+    Simd32x4GetSignMaskInstr* instr = new(Z) Simd32x4GetSignMaskInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else if (getter == MethodRecognizer::kInt32x4ShuffleMix) {
+    Simd32x4ShuffleMixInstr* instr = new(Z) Simd32x4ShuffleMixInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        new(Z) Value(call->ArgumentAt(1)),
+        mask,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else if (getter == MethodRecognizer::kInt32x4Shuffle) {
+    Simd32x4ShuffleInstr* instr = new(Z) Simd32x4ShuffleInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        mask,
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  } else {
+    Int32x4GetFlagInstr* instr = new(Z) Int32x4GetFlagInstr(
+        getter,
+        new(Z) Value(call->ArgumentAt(0)),
+        call->deopt_id());
+    ReplaceCall(call, instr);
+    return true;
+  }
+}
+
+
+bool JitOptimizer::InlineFloat32x4BinaryOp(InstanceCallInstr* call,
+                                           Token::Kind op_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  // Type check left.
+  AddCheckClass(left,
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Type check right.
+  AddCheckClass(right,
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(1)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Replace call.
+  BinaryFloat32x4OpInstr* float32x4_bin_op =
+      new(Z) BinaryFloat32x4OpInstr(
+          op_kind, new(Z) Value(left), new(Z) Value(right),
+          call->deopt_id());
+  ReplaceCall(call, float32x4_bin_op);
+
+  return true;
+}
+
+
+bool JitOptimizer::InlineInt32x4BinaryOp(InstanceCallInstr* call,
+                                         Token::Kind op_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  // Type check left.
+  AddCheckClass(left,
+                ICData::ZoneHandle(
+                    Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Type check right.
+  AddCheckClass(right,
+                ICData::ZoneHandle(Z,
+                    call->ic_data()->AsUnaryClassChecksForArgNr(1)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Replace call.
+  BinaryInt32x4OpInstr* int32x4_bin_op =
+      new(Z) BinaryInt32x4OpInstr(
+          op_kind, new(Z) Value(left), new(Z) Value(right),
+          call->deopt_id());
+  ReplaceCall(call, int32x4_bin_op);
+  return true;
+}
+
+
+bool JitOptimizer::InlineFloat64x2BinaryOp(InstanceCallInstr* call,
+                                           Token::Kind op_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->ArgumentCount() == 2);
+  Definition* left = call->ArgumentAt(0);
+  Definition* right = call->ArgumentAt(1);
+  // Type check left.
+  AddCheckClass(left,
+                ICData::ZoneHandle(
+                    call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Type check right.
+  AddCheckClass(right,
+                ICData::ZoneHandle(
+                    call->ic_data()->AsUnaryClassChecksForArgNr(1)),
+                call->deopt_id(),
+                call->env(),
+                call);
+  // Replace call.
+  BinaryFloat64x2OpInstr* float64x2_bin_op =
+      new(Z) BinaryFloat64x2OpInstr(
+          op_kind, new(Z) Value(left), new(Z) Value(right),
+          call->deopt_id());
+  ReplaceCall(call, float64x2_bin_op);
+  return true;
+}
+
+
+// Only unique implicit instance getters can be currently handled.
+bool JitOptimizer::TryInlineInstanceGetter(InstanceCallInstr* call) {
+  ASSERT(call->HasICData());
+  const ICData& ic_data = *call->ic_data();
+  if (ic_data.NumberOfUsedChecks() == 0) {
+    // No type feedback collected.
+    return false;
+  }
+
+  if (!ic_data.HasOneTarget()) {
+    // Polymorphic sites are inlined like normal methods by conventional
+    // inlining in FlowGraphInliner.
+    return false;
+  }
+
+  const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0));
+  if (target.kind() != RawFunction::kImplicitGetter) {
+    // Non-implicit getters are inlined like normal methods by conventional
+    // inlining in FlowGraphInliner.
+    return false;
+  }
+  return InlineImplicitInstanceGetter(call);
+}
+
+
+bool JitOptimizer::TryReplaceInstanceCallWithInline(
+    InstanceCallInstr* call) {
+  Function& target = Function::Handle(Z);
+  GrowableArray<intptr_t> class_ids;
+  call->ic_data()->GetCheckAt(0, &class_ids, &target);
+  const intptr_t receiver_cid = class_ids[0];
+
+  TargetEntryInstr* entry;
+  Definition* last;
+  if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_,
+                                                   receiver_cid,
+                                                   target,
+                                                   call,
+                                                   call->ArgumentAt(0),
+                                                   call->token_pos(),
+                                                   *call->ic_data(),
+                                                   &entry, &last)) {
+    return false;
+  }
+
+  // Insert receiver class check.
+  AddReceiverCheck(call);
+  // Remove the original push arguments.
+  for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+    PushArgumentInstr* push = call->PushArgumentAt(i);
+    push->ReplaceUsesWith(push->value()->definition());
+    push->RemoveFromGraph();
+  }
+  // Replace all uses of this definition with the result.
+  call->ReplaceUsesWith(last);
+  // Finally insert the sequence other definition in place of this one in the
+  // graph.
+  call->previous()->LinkTo(entry->next());
+  entry->UnuseAllInputs();  // Entry block is not in the graph.
+  last->LinkTo(call);
+  // Remove through the iterator.
+  ASSERT(current_iterator()->Current() == call);
+  current_iterator()->RemoveCurrentFromGraph();
+  call->set_previous(NULL);
+  call->set_next(NULL);
+  return true;
+}
+
+
+void JitOptimizer::ReplaceWithMathCFunction(
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  AddReceiverCheck(call);
+  ZoneGrowableArray<Value*>* args =
+      new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
+  for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
+    args->Add(new(Z) Value(call->ArgumentAt(i)));
+  }
+  InvokeMathCFunctionInstr* invoke =
+      new(Z) InvokeMathCFunctionInstr(args,
+                                      call->deopt_id(),
+                                      recognized_kind,
+                                      call->token_pos());
+  ReplaceCall(call, invoke);
+}
+
+
+static bool IsSupportedByteArrayViewCid(intptr_t cid) {
+  switch (cid) {
+    case kTypedDataInt8ArrayCid:
+    case kTypedDataUint8ArrayCid:
+    case kExternalTypedDataUint8ArrayCid:
+    case kTypedDataUint8ClampedArrayCid:
+    case kExternalTypedDataUint8ClampedArrayCid:
+    case kTypedDataInt16ArrayCid:
+    case kTypedDataUint16ArrayCid:
+    case kTypedDataInt32ArrayCid:
+    case kTypedDataUint32ArrayCid:
+    case kTypedDataFloat32ArrayCid:
+    case kTypedDataFloat64ArrayCid:
+    case kTypedDataFloat32x4ArrayCid:
+    case kTypedDataInt32x4ArrayCid:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+// Inline only simple, frequently called core library methods.
+bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
+  ASSERT(call->HasICData());
+  const ICData& ic_data = *call->ic_data();
+  if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
+    // No type feedback collected or multiple targets found.
+    return false;
+  }
+
+  Function& target = Function::Handle(Z);
+  GrowableArray<intptr_t> class_ids;
+  ic_data.GetCheckAt(0, &class_ids, &target);
+  MethodRecognizer::Kind recognized_kind =
+      MethodRecognizer::RecognizeKind(target);
+
+  if ((recognized_kind == MethodRecognizer::kGrowableArraySetData) &&
+      (ic_data.NumberOfChecks() == 1) &&
+      (class_ids[0] == kGrowableObjectArrayCid)) {
+    // This is an internal method, no need to check argument types.
+    Definition* array = call->ArgumentAt(0);
+    Definition* value = call->ArgumentAt(1);
+    StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
+        GrowableObjectArray::data_offset(),
+        new(Z) Value(array),
+        new(Z) Value(value),
+        kEmitStoreBarrier,
+        call->token_pos());
+    ReplaceCall(call, store);
+    return true;
+  }
+
+  if ((recognized_kind == MethodRecognizer::kGrowableArraySetLength) &&
+      (ic_data.NumberOfChecks() == 1) &&
+      (class_ids[0] == kGrowableObjectArrayCid)) {
+    // This is an internal method, no need to check argument types nor
+    // range.
+    Definition* array = call->ArgumentAt(0);
+    Definition* value = call->ArgumentAt(1);
+    StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
+        GrowableObjectArray::length_offset(),
+        new(Z) Value(array),
+        new(Z) Value(value),
+        kNoStoreBarrier,
+        call->token_pos());
+    ReplaceCall(call, store);
+    return true;
+  }
+
+  if (((recognized_kind == MethodRecognizer::kStringBaseCodeUnitAt) ||
+       (recognized_kind == MethodRecognizer::kStringBaseCharAt)) &&
+      (ic_data.NumberOfChecks() == 1) &&
+      ((class_ids[0] == kOneByteStringCid) ||
+       (class_ids[0] == kTwoByteStringCid))) {
+    return TryReplaceInstanceCallWithInline(call);
+  }
+
+  if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) {
+    if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
+      // This is an internal method, no need to check argument types nor
+      // range.
+      Definition* str = call->ArgumentAt(0);
+      Definition* index = call->ArgumentAt(1);
+      Definition* value = call->ArgumentAt(2);
+      StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr(
+          new(Z) Value(str),
+          new(Z) Value(index),
+          new(Z) Value(value),
+          kNoStoreBarrier,
+          1,  // Index scale
+          kOneByteStringCid,
+          call->deopt_id(),
+          call->token_pos());
+      ReplaceCall(call, store_op);
+      return true;
+    }
+    return false;
+  }
+
+  if (CanUnboxDouble() &&
+      (recognized_kind == MethodRecognizer::kIntegerToDouble) &&
+      (ic_data.NumberOfChecks() == 1)) {
+    if (class_ids[0] == kSmiCid) {
+      AddReceiverCheck(call);
+      ReplaceCall(call,
+                  new(Z) SmiToDoubleInstr(
+                      new(Z) Value(call->ArgumentAt(0)),
+                      call->token_pos()));
+      return true;
+    } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) {
+      AddReceiverCheck(call);
+      ReplaceCall(call,
+                  new(Z) MintToDoubleInstr(new(Z) Value(call->ArgumentAt(0)),
+                                           call->deopt_id()));
+      return true;
+    }
+  }
+
+  if (class_ids[0] == kDoubleCid) {
+    if (!CanUnboxDouble()) {
+      return false;
+    }
+    switch (recognized_kind) {
+      case MethodRecognizer::kDoubleToInteger: {
+        AddReceiverCheck(call);
+        ASSERT(call->HasICData());
+        const ICData& ic_data = *call->ic_data();
+        Definition* input = call->ArgumentAt(0);
+        Definition* d2i_instr = NULL;
+        if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) {
+          // Do not repeatedly deoptimize because result didn't fit into Smi.
+          d2i_instr =  new(Z) DoubleToIntegerInstr(
+              new(Z) Value(input), call);
+        } else {
+          // Optimistically assume result fits into Smi.
+          d2i_instr = new(Z) DoubleToSmiInstr(
+              new(Z) Value(input), call->deopt_id());
+        }
+        ReplaceCall(call, d2i_instr);
+        return true;
+      }
+      case MethodRecognizer::kDoubleMod:
+      case MethodRecognizer::kDoubleRound:
+        ReplaceWithMathCFunction(call, recognized_kind);
+        return true;
+      case MethodRecognizer::kDoubleTruncate:
+      case MethodRecognizer::kDoubleFloor:
+      case MethodRecognizer::kDoubleCeil:
+        if (!TargetCPUFeatures::double_truncate_round_supported()) {
+          ReplaceWithMathCFunction(call, recognized_kind);
+        } else {
+          AddReceiverCheck(call);
+          DoubleToDoubleInstr* d2d_instr =
+              new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)),
+                                         recognized_kind, call->deopt_id());
+          ReplaceCall(call, d2d_instr);
+        }
+        return true;
+      case MethodRecognizer::kDoubleAdd:
+      case MethodRecognizer::kDoubleSub:
+      case MethodRecognizer::kDoubleMul:
+      case MethodRecognizer::kDoubleDiv:
+        return TryReplaceInstanceCallWithInline(call);
+      default:
+        // Unsupported method.
+        return false;
+    }
+  }
+
+  if (IsSupportedByteArrayViewCid(class_ids[0]) &&
+      (ic_data.NumberOfChecks() == 1)) {
+    return TryReplaceInstanceCallWithInline(call);
+  }
+
+  if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
+    return TryInlineFloat32x4Method(call, recognized_kind);
+  }
+
+  if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
+    return TryInlineInt32x4Method(call, recognized_kind);
+  }
+
+  if ((class_ids[0] == kFloat64x2Cid) && (ic_data.NumberOfChecks() == 1)) {
+    return TryInlineFloat64x2Method(call, recognized_kind);
+  }
+
+  if (recognized_kind == MethodRecognizer::kIntegerLeftShiftWithMask32) {
+    ASSERT(call->ArgumentCount() == 3);
+    ASSERT(ic_data.NumArgsTested() == 2);
+    Definition* value = call->ArgumentAt(0);
+    Definition* count = call->ArgumentAt(1);
+    Definition* int32_mask = call->ArgumentAt(2);
+    if (HasOnlyTwoOf(ic_data, kSmiCid)) {
+      if (ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
+        return false;
+      }
+      // We cannot overflow. The input value must be a Smi
+      AddCheckSmi(value, call->deopt_id(), call->env(), call);
+      AddCheckSmi(count, call->deopt_id(), call->env(), call);
+      ASSERT(int32_mask->IsConstant());
+      const Integer& mask_literal = Integer::Cast(
+          int32_mask->AsConstant()->value());
+      const int64_t mask_value = mask_literal.AsInt64Value();
+      ASSERT(mask_value >= 0);
+      if (mask_value > Smi::kMaxValue) {
+        // The result will not be Smi.
+        return false;
+      }
+      BinarySmiOpInstr* left_shift =
+          new(Z) BinarySmiOpInstr(Token::kSHL,
+                                  new(Z) Value(value),
+                                  new(Z) Value(count),
+                                  call->deopt_id());
+      left_shift->mark_truncating();
+      if ((kBitsPerWord == 32) && (mask_value == 0xffffffffLL)) {
+        // No BIT_AND operation needed.
+        ReplaceCall(call, left_shift);
+      } else {
+        InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
+        BinarySmiOpInstr* bit_and =
+            new(Z) BinarySmiOpInstr(Token::kBIT_AND,
+                                    new(Z) Value(left_shift),
+                                    new(Z) Value(int32_mask),
+                                    call->deopt_id());
+        ReplaceCall(call, bit_and);
+      }
+      return true;
+    }
+
+    if (HasTwoMintOrSmi(ic_data) &&
+        HasOnlyOneSmi(ICData::Handle(Z,
+                                     ic_data.AsUnaryClassChecksForArgNr(1)))) {
+      if (!FlowGraphCompiler::SupportsUnboxedMints() ||
+          ic_data.HasDeoptReason(ICData::kDeoptBinaryMintOp)) {
+        return false;
+      }
+      ShiftMintOpInstr* left_shift =
+          new(Z) ShiftMintOpInstr(Token::kSHL,
+                                  new(Z) Value(value),
+                                  new(Z) Value(count),
+                                  call->deopt_id());
+      InsertBefore(call, left_shift, call->env(), FlowGraph::kValue);
+      BinaryMintOpInstr* bit_and =
+          new(Z) BinaryMintOpInstr(Token::kBIT_AND,
+                                   new(Z) Value(left_shift),
+                                   new(Z) Value(int32_mask),
+                                   call->deopt_id());
+      ReplaceCall(call, bit_and);
+      return true;
+    }
+  }
+  return false;
+}
+
+
+bool JitOptimizer::TryInlineFloat32x4Constructor(
+    StaticCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  if (recognized_kind == MethodRecognizer::kFloat32x4Zero) {
+    Float32x4ZeroInstr* zero = new(Z) Float32x4ZeroInstr();
+    ReplaceCall(call, zero);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kFloat32x4Splat) {
+    Float32x4SplatInstr* splat =
+        new(Z) Float32x4SplatInstr(
+            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
+    ReplaceCall(call, splat);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kFloat32x4Constructor) {
+    Float32x4ConstructorInstr* con =
+        new(Z) Float32x4ConstructorInstr(
+            new(Z) Value(call->ArgumentAt(1)),
+            new(Z) Value(call->ArgumentAt(2)),
+            new(Z) Value(call->ArgumentAt(3)),
+            new(Z) Value(call->ArgumentAt(4)),
+            call->deopt_id());
+    ReplaceCall(call, con);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kFloat32x4FromInt32x4Bits) {
+    Int32x4ToFloat32x4Instr* cast =
+        new(Z) Int32x4ToFloat32x4Instr(
+            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
+    ReplaceCall(call, cast);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kFloat32x4FromFloat64x2) {
+    Float64x2ToFloat32x4Instr* cast =
+        new(Z) Float64x2ToFloat32x4Instr(
+            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
+    ReplaceCall(call, cast);
+    return true;
+  }
+  return false;
+}
+
+
+bool JitOptimizer::TryInlineFloat64x2Constructor(
+    StaticCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  if (recognized_kind == MethodRecognizer::kFloat64x2Zero) {
+    Float64x2ZeroInstr* zero = new(Z) Float64x2ZeroInstr();
+    ReplaceCall(call, zero);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kFloat64x2Splat) {
+    Float64x2SplatInstr* splat =
+        new(Z) Float64x2SplatInstr(
+            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
+    ReplaceCall(call, splat);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kFloat64x2Constructor) {
+    Float64x2ConstructorInstr* con =
+        new(Z) Float64x2ConstructorInstr(
+            new(Z) Value(call->ArgumentAt(1)),
+            new(Z) Value(call->ArgumentAt(2)),
+            call->deopt_id());
+    ReplaceCall(call, con);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kFloat64x2FromFloat32x4) {
+    Float32x4ToFloat64x2Instr* cast =
+        new(Z) Float32x4ToFloat64x2Instr(
+            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
+    ReplaceCall(call, cast);
+    return true;
+  }
+  return false;
+}
+
+
+bool JitOptimizer::TryInlineInt32x4Constructor(
+    StaticCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  if (recognized_kind == MethodRecognizer::kInt32x4BoolConstructor) {
+    Int32x4BoolConstructorInstr* con =
+        new(Z) Int32x4BoolConstructorInstr(
+            new(Z) Value(call->ArgumentAt(1)),
+            new(Z) Value(call->ArgumentAt(2)),
+            new(Z) Value(call->ArgumentAt(3)),
+            new(Z) Value(call->ArgumentAt(4)),
+            call->deopt_id());
+    ReplaceCall(call, con);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kInt32x4FromFloat32x4Bits) {
+    Float32x4ToInt32x4Instr* cast =
+        new(Z) Float32x4ToInt32x4Instr(
+            new(Z) Value(call->ArgumentAt(1)), call->deopt_id());
+    ReplaceCall(call, cast);
+    return true;
+  } else if (recognized_kind == MethodRecognizer::kInt32x4Constructor) {
+    Int32x4ConstructorInstr* con =
+        new(Z) Int32x4ConstructorInstr(
+            new(Z) Value(call->ArgumentAt(1)),
+            new(Z) Value(call->ArgumentAt(2)),
+            new(Z) Value(call->ArgumentAt(3)),
+            new(Z) Value(call->ArgumentAt(4)),
+            call->deopt_id());
+    ReplaceCall(call, con);
+    return true;
+  }
+  return false;
+}
+
+
+bool JitOptimizer::TryInlineFloat32x4Method(
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->HasICData());
+  switch (recognized_kind) {
+    case MethodRecognizer::kFloat32x4ShuffleX:
+    case MethodRecognizer::kFloat32x4ShuffleY:
+    case MethodRecognizer::kFloat32x4ShuffleZ:
+    case MethodRecognizer::kFloat32x4ShuffleW:
+    case MethodRecognizer::kFloat32x4GetSignMask:
+      ASSERT(call->ic_data()->HasReceiverClassId(kFloat32x4Cid));
+      ASSERT(call->ic_data()->HasOneTarget());
+      return InlineFloat32x4Getter(call, recognized_kind);
+
+    case MethodRecognizer::kFloat32x4Equal:
+    case MethodRecognizer::kFloat32x4GreaterThan:
+    case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
+    case MethodRecognizer::kFloat32x4LessThan:
+    case MethodRecognizer::kFloat32x4LessThanOrEqual:
+    case MethodRecognizer::kFloat32x4NotEqual: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      // Replace call.
+      Float32x4ComparisonInstr* cmp =
+          new(Z) Float32x4ComparisonInstr(recognized_kind,
+                                          new(Z) Value(left),
+                                          new(Z) Value(right),
+                                          call->deopt_id());
+      ReplaceCall(call, cmp);
+      return true;
+    }
+    case MethodRecognizer::kFloat32x4Min:
+    case MethodRecognizer::kFloat32x4Max: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Float32x4MinMaxInstr* minmax =
+          new(Z) Float32x4MinMaxInstr(
+              recognized_kind,
+              new(Z) Value(left),
+              new(Z) Value(right),
+              call->deopt_id());
+      ReplaceCall(call, minmax);
+      return true;
+    }
+    case MethodRecognizer::kFloat32x4Scale: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      // Left and right values are swapped when handed to the instruction,
+      // this is done so that the double value is loaded into the output
+      // register and can be destroyed.
+      Float32x4ScaleInstr* scale =
+          new(Z) Float32x4ScaleInstr(recognized_kind,
+                                     new(Z) Value(right),
+                                     new(Z) Value(left),
+                                     call->deopt_id());
+      ReplaceCall(call, scale);
+      return true;
+    }
+    case MethodRecognizer::kFloat32x4Sqrt:
+    case MethodRecognizer::kFloat32x4ReciprocalSqrt:
+    case MethodRecognizer::kFloat32x4Reciprocal: {
+      Definition* left = call->ArgumentAt(0);
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Float32x4SqrtInstr* sqrt =
+          new(Z) Float32x4SqrtInstr(recognized_kind,
+                                    new(Z) Value(left),
+                                    call->deopt_id());
+      ReplaceCall(call, sqrt);
+      return true;
+    }
+    case MethodRecognizer::kFloat32x4WithX:
+    case MethodRecognizer::kFloat32x4WithY:
+    case MethodRecognizer::kFloat32x4WithZ:
+    case MethodRecognizer::kFloat32x4WithW: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Float32x4WithInstr* with = new(Z) Float32x4WithInstr(recognized_kind,
+                                                           new(Z) Value(left),
+                                                           new(Z) Value(right),
+                                                           call->deopt_id());
+      ReplaceCall(call, with);
+      return true;
+    }
+    case MethodRecognizer::kFloat32x4Absolute:
+    case MethodRecognizer::kFloat32x4Negate: {
+      Definition* left = call->ArgumentAt(0);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Float32x4ZeroArgInstr* zeroArg =
+          new(Z) Float32x4ZeroArgInstr(
+              recognized_kind, new(Z) Value(left), call->deopt_id());
+      ReplaceCall(call, zeroArg);
+      return true;
+    }
+    case MethodRecognizer::kFloat32x4Clamp: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* lower = call->ArgumentAt(1);
+      Definition* upper = call->ArgumentAt(2);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Float32x4ClampInstr* clamp = new(Z) Float32x4ClampInstr(
+          new(Z) Value(left),
+          new(Z) Value(lower),
+          new(Z) Value(upper),
+          call->deopt_id());
+      ReplaceCall(call, clamp);
+      return true;
+    }
+    case MethodRecognizer::kFloat32x4ShuffleMix:
+    case MethodRecognizer::kFloat32x4Shuffle: {
+      return InlineFloat32x4Getter(call, recognized_kind);
+    }
+    default:
+      return false;
+  }
+}
+
+
+bool JitOptimizer::TryInlineFloat64x2Method(
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->HasICData());
+  switch (recognized_kind) {
+    case MethodRecognizer::kFloat64x2GetX:
+    case MethodRecognizer::kFloat64x2GetY:
+      ASSERT(call->ic_data()->HasReceiverClassId(kFloat64x2Cid));
+      ASSERT(call->ic_data()->HasOneTarget());
+      return InlineFloat64x2Getter(call, recognized_kind);
+    case MethodRecognizer::kFloat64x2Negate:
+    case MethodRecognizer::kFloat64x2Abs:
+    case MethodRecognizer::kFloat64x2Sqrt:
+    case MethodRecognizer::kFloat64x2GetSignMask: {
+      Definition* left = call->ArgumentAt(0);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Float64x2ZeroArgInstr* zeroArg =
+          new(Z) Float64x2ZeroArgInstr(
+              recognized_kind, new(Z) Value(left), call->deopt_id());
+      ReplaceCall(call, zeroArg);
+      return true;
+    }
+    case MethodRecognizer::kFloat64x2Scale:
+    case MethodRecognizer::kFloat64x2WithX:
+    case MethodRecognizer::kFloat64x2WithY:
+    case MethodRecognizer::kFloat64x2Min:
+    case MethodRecognizer::kFloat64x2Max: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* right = call->ArgumentAt(1);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Float64x2OneArgInstr* zeroArg =
+          new(Z) Float64x2OneArgInstr(recognized_kind,
+                                      new(Z) Value(left),
+                                      new(Z) Value(right),
+                                      call->deopt_id());
+      ReplaceCall(call, zeroArg);
+      return true;
+    }
+    default:
+      return false;
+  }
+}
+
+
+bool JitOptimizer::TryInlineInt32x4Method(
+    InstanceCallInstr* call,
+    MethodRecognizer::Kind recognized_kind) {
+  if (!ShouldInlineSimd()) {
+    return false;
+  }
+  ASSERT(call->HasICData());
+  switch (recognized_kind) {
+    case MethodRecognizer::kInt32x4ShuffleMix:
+    case MethodRecognizer::kInt32x4Shuffle:
+    case MethodRecognizer::kInt32x4GetFlagX:
+    case MethodRecognizer::kInt32x4GetFlagY:
+    case MethodRecognizer::kInt32x4GetFlagZ:
+    case MethodRecognizer::kInt32x4GetFlagW:
+    case MethodRecognizer::kInt32x4GetSignMask:
+      ASSERT(call->ic_data()->HasReceiverClassId(kInt32x4Cid));
+      ASSERT(call->ic_data()->HasOneTarget());
+      return InlineInt32x4Getter(call, recognized_kind);
+
+    case MethodRecognizer::kInt32x4Select: {
+      Definition* mask = call->ArgumentAt(0);
+      Definition* trueValue = call->ArgumentAt(1);
+      Definition* falseValue = call->ArgumentAt(2);
+      // Type check left.
+      AddCheckClass(mask,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Int32x4SelectInstr* select = new(Z) Int32x4SelectInstr(
+          new(Z) Value(mask),
+          new(Z) Value(trueValue),
+          new(Z) Value(falseValue),
+          call->deopt_id());
+      ReplaceCall(call, select);
+      return true;
+    }
+    case MethodRecognizer::kInt32x4WithFlagX:
+    case MethodRecognizer::kInt32x4WithFlagY:
+    case MethodRecognizer::kInt32x4WithFlagZ:
+    case MethodRecognizer::kInt32x4WithFlagW: {
+      Definition* left = call->ArgumentAt(0);
+      Definition* flag = call->ArgumentAt(1);
+      // Type check left.
+      AddCheckClass(left,
+                    ICData::ZoneHandle(
+                        Z, call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+                    call->deopt_id(),
+                    call->env(),
+                    call);
+      Int32x4SetFlagInstr* setFlag = new(Z) Int32x4SetFlagInstr(
+          recognized_kind,
+          new(Z) Value(left),
+          new(Z) Value(flag),
+          call->deopt_id());
+      ReplaceCall(call, setFlag);
+      return true;
+    }
+    default:
+      return false;
+  }
+}
+
+
+// If type tests specified by 'ic_data' do not depend on type arguments,
+// return mapping cid->result in 'results' (i : cid; i + 1: result).
+// If all tests yield the same result, return it otherwise return Bool::null.
+// If no mapping is possible, 'results' is empty.
+// An instance-of test returning all same results can be converted to a class
+// check.
+RawBool* JitOptimizer::InstanceOfAsBool(
+    const ICData& ic_data,
+    const AbstractType& type,
+    ZoneGrowableArray<intptr_t>* results) const {
+  ASSERT(results->is_empty());
+  ASSERT(ic_data.NumArgsTested() == 1);  // Unary checks only.
+  if (type.IsFunctionType() || type.IsDartFunctionType() ||
+      !type.IsInstantiated() || type.IsMalformedOrMalbounded()) {
+    return Bool::null();
+  }
+  const Class& type_class = Class::Handle(Z, type.type_class());
+  const intptr_t num_type_args = type_class.NumTypeArguments();
+  if (num_type_args > 0) {
+    // Only raw types can be directly compared, thus disregarding type
+    // arguments.
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::Handle(Z, type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
+    if (!is_raw_type) {
+      // Unknown result.
+      return Bool::null();
+    }
+  }
+
+  const ClassTable& class_table = *isolate()->class_table();
+  Bool& prev = Bool::Handle(Z);
+  Class& cls = Class::Handle(Z);
+
+  bool results_differ = false;
+  for (int i = 0; i < ic_data.NumberOfChecks(); i++) {
+    cls = class_table.At(ic_data.GetReceiverClassIdAt(i));
+    if (cls.NumTypeArguments() > 0) {
+      return Bool::null();
+    }
+    const bool is_subtype = cls.IsSubtypeOf(
+        TypeArguments::Handle(Z),
+        type_class,
+        TypeArguments::Handle(Z),
+        NULL,
+        NULL,
+        Heap::kOld);
+    results->Add(cls.id());
+    results->Add(is_subtype);
+    if (prev.IsNull()) {
+      prev = Bool::Get(is_subtype).raw();
+    } else {
+      if (is_subtype != prev.value()) {
+        results_differ = true;
+      }
+    }
+  }
+  return results_differ ?  Bool::null() : prev.raw();
+}
+
+
+// Returns true if checking against this type is a direct class id comparison.
+bool JitOptimizer::TypeCheckAsClassEquality(const AbstractType& type) {
+  ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded());
+  // Requires CHA.
+  if (!type.IsInstantiated()) return false;
+  // Function types have different type checking rules.
+  if (type.IsFunctionType()) return false;
+  const Class& type_class = Class::Handle(type.type_class());
+  // Could be an interface check?
+  if (CHA::IsImplemented(type_class)) return false;
+  // Check if there are subclasses.
+  if (CHA::HasSubclasses(type_class)) {
+    return false;
+  }
+
+  // Private classes cannot be subclassed by later loaded libs.
+  if (!type_class.IsPrivate()) {
+    if (FLAG_use_cha_deopt || isolate()->all_classes_finalized()) {
+      if (FLAG_trace_cha) {
+        THR_Print("  **(CHA) Typecheck as class equality since no "
+            "subclasses: %s\n",
+            type_class.ToCString());
+      }
+      if (FLAG_use_cha_deopt) {
+        thread()->cha()->AddToLeafClasses(type_class);
+      }
+    } else {
+      return false;
+    }
+  }
+  const intptr_t num_type_args = type_class.NumTypeArguments();
+  if (num_type_args > 0) {
+    // Only raw types can be directly compared, thus disregarding type
+    // arguments.
+    const intptr_t num_type_params = type_class.NumTypeParameters();
+    const intptr_t from_index = num_type_args - num_type_params;
+    const TypeArguments& type_arguments =
+        TypeArguments::Handle(type.arguments());
+    const bool is_raw_type = type_arguments.IsNull() ||
+        type_arguments.IsRaw(from_index, num_type_params);
+    return is_raw_type;
+  }
+  return true;
+}
+
+
+static bool CidTestResultsContains(const ZoneGrowableArray<intptr_t>& results,
+                                   intptr_t test_cid) {
+  for (intptr_t i = 0; i < results.length(); i += 2) {
+    if (results[i] == test_cid) return true;
+  }
+  return false;
+}
+
+
+static void TryAddTest(ZoneGrowableArray<intptr_t>* results,
+                       intptr_t test_cid,
+                       bool result) {
+  if (!CidTestResultsContains(*results, test_cid)) {
+    results->Add(test_cid);
+    results->Add(result);
+  }
+}
+
+
+// Tries to add cid tests to 'results' so that no deoptimization is
+// necessary.
+// TODO(srdjan): Do also for other than 'int' type.
+static bool TryExpandTestCidsResult(ZoneGrowableArray<intptr_t>* results,
+                                    const AbstractType& type) {
+  ASSERT(results->length() >= 2);  // At least on eentry.
+  const ClassTable& class_table = *Isolate::Current()->class_table();
+  if ((*results)[0] != kSmiCid) {
+    const Class& cls = Class::Handle(class_table.At(kSmiCid));
+    const Class& type_class = Class::Handle(type.type_class());
+    const bool smi_is_subtype = cls.IsSubtypeOf(TypeArguments::Handle(),
+                                                type_class,
+                                                TypeArguments::Handle(),
+                                                NULL,
+                                                NULL,
+                                                Heap::kOld);
+    results->Add((*results)[results->length() - 2]);
+    results->Add((*results)[results->length() - 2]);
+    for (intptr_t i = results->length() - 3; i > 1; --i) {
+      (*results)[i] = (*results)[i - 2];
+    }
+    (*results)[0] = kSmiCid;
+    (*results)[1] = smi_is_subtype;
+  }
+
+  ASSERT(type.IsInstantiated() && !type.IsMalformedOrMalbounded());
+  ASSERT(results->length() >= 2);
+  if (type.IsIntType()) {
+    ASSERT((*results)[0] == kSmiCid);
+    TryAddTest(results, kMintCid, true);
+    TryAddTest(results, kBigintCid, true);
+    // Cannot deoptimize since all tests returning true have been added.
+    return false;
+  }
+
+  return true;  // May deoptimize since we have not identified all 'true' tests.
+}
+
+
+// TODO(srdjan): Use ICData to check if always true or false.
+void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
+  ASSERT(Token::IsTypeTestOperator(call->token_kind()));
+  Definition* left = call->ArgumentAt(0);
+  Definition* type_args = NULL;
+  AbstractType& type = AbstractType::ZoneHandle(Z);
+  bool negate = false;
+  if (call->ArgumentCount() == 2) {
+    type_args = flow_graph()->constant_null();
+    if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) {
+      type = Type::Number();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfInt()).raw()) {
+      type = Type::IntType();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfSmi()).raw()) {
+      type = Type::SmiType();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfDouble()).raw()) {
+      type = Type::Double();
+    } else if (call->function_name().raw() ==
+        Library::PrivateCoreLibName(Symbols::_instanceOfString()).raw()) {
+      type = Type::StringType();
+    } else {
+      UNIMPLEMENTED();
+    }
+    negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition()
+        ->AsConstant()->value()).value();
+  } else {
+    type_args = call->ArgumentAt(1);
+    type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw();
+    negate = Bool::Cast(call->ArgumentAt(3)->OriginalDefinition()
+        ->AsConstant()->value()).value();
+  }
+  const ICData& unary_checks =
+      ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
+  if ((unary_checks.NumberOfChecks() > 0) &&
+      (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
+    ZoneGrowableArray<intptr_t>* results =
+        new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
+    Bool& as_bool =
+        Bool::ZoneHandle(Z, InstanceOfAsBool(unary_checks, type, results));
+    if (as_bool.IsNull()) {
+      if (results->length() == unary_checks.NumberOfChecks() * 2) {
+        const bool can_deopt = TryExpandTestCidsResult(results, type);
+        TestCidsInstr* test_cids = new(Z) TestCidsInstr(
+            call->token_pos(),
+            negate ? Token::kISNOT : Token::kIS,
+            new(Z) Value(left),
+            *results,
+            can_deopt ? call->deopt_id() : Thread::kNoDeoptId);
+        // Remove type.
+        ReplaceCall(call, test_cids);
+        return;
+      }
+    } else {
+      // TODO(srdjan): Use TestCidsInstr also for this case.
+      // One result only.
+      AddReceiverCheck(call);
+      if (negate) {
+        as_bool = Bool::Get(!as_bool.value()).raw();
+      }
+      ConstantInstr* bool_const = flow_graph()->GetConstant(as_bool);
+      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+        PushArgumentInstr* push = call->PushArgumentAt(i);
+        push->ReplaceUsesWith(push->value()->definition());
+        push->RemoveFromGraph();
+      }
+      call->ReplaceUsesWith(bool_const);
+      ASSERT(current_iterator()->Current() == call);
+      current_iterator()->RemoveCurrentFromGraph();
+      return;
+    }
+  }
+
+  if (TypeCheckAsClassEquality(type)) {
+    LoadClassIdInstr* left_cid = new(Z) LoadClassIdInstr(new(Z) Value(left));
+    InsertBefore(call,
+                 left_cid,
+                 NULL,
+                 FlowGraph::kValue);
+    const intptr_t type_cid = Class::Handle(Z, type.type_class()).id();
+    ConstantInstr* cid =
+        flow_graph()->GetConstant(Smi::Handle(Z, Smi::New(type_cid)));
+
+    StrictCompareInstr* check_cid =
+        new(Z) StrictCompareInstr(
+            call->token_pos(),
+            negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
+            new(Z) Value(left_cid),
+            new(Z) Value(cid),
+            false);  // No number check.
+    ReplaceCall(call, check_cid);
+    return;
+  }
+
+  InstanceOfInstr* instance_of =
+      new(Z) InstanceOfInstr(call->token_pos(),
+                             new(Z) Value(left),
+                             new(Z) Value(type_args),
+                             type,
+                             negate,
+                             call->deopt_id());
+  ReplaceCall(call, instance_of);
+}
+
+
+// TODO(srdjan): Apply optimizations as in ReplaceWithInstanceOf (TestCids).
+void JitOptimizer::ReplaceWithTypeCast(InstanceCallInstr* call) {
+  ASSERT(Token::IsTypeCastOperator(call->token_kind()));
+  Definition* left = call->ArgumentAt(0);
+  Definition* type_args = call->ArgumentAt(1);
+  const AbstractType& type =
+      AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value());
+  ASSERT(!type.IsMalformedOrMalbounded());
+  const ICData& unary_checks =
+      ICData::ZoneHandle(Z, call->ic_data()->AsUnaryClassChecks());
+  if ((unary_checks.NumberOfChecks() > 0) &&
+      (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks)) {
+    ZoneGrowableArray<intptr_t>* results =
+        new(Z) ZoneGrowableArray<intptr_t>(unary_checks.NumberOfChecks() * 2);
+    const Bool& as_bool = Bool::ZoneHandle(Z,
+        InstanceOfAsBool(unary_checks, type, results));
+    if (as_bool.raw() == Bool::True().raw()) {
+      AddReceiverCheck(call);
+      // Remove the original push arguments.
+      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+        PushArgumentInstr* push = call->PushArgumentAt(i);
+        push->ReplaceUsesWith(push->value()->definition());
+        push->RemoveFromGraph();
+      }
+      // Remove call, replace it with 'left'.
+      call->ReplaceUsesWith(left);
+      ASSERT(current_iterator()->Current() == call);
+      current_iterator()->RemoveCurrentFromGraph();
+      return;
+    }
+  }
+  const String& dst_name = String::ZoneHandle(Z,
+      Symbols::New(Exceptions::kCastErrorDstName));
+  AssertAssignableInstr* assert_as =
+      new(Z) AssertAssignableInstr(call->token_pos(),
+                                   new(Z) Value(left),
+                                   new(Z) Value(type_args),
+                                   type,
+                                   dst_name,
+                                   call->deopt_id());
+  ReplaceCall(call, assert_as);
+}
+
+
+// Tries to optimize instance call by replacing it with a faster instruction
+// (e.g, binary op, field load, ..).
+void JitOptimizer::VisitInstanceCall(InstanceCallInstr* instr) {
+  if (!instr->HasICData() || (instr->ic_data()->NumberOfUsedChecks() == 0)) {
+    return;
+  }
+  const Token::Kind op_kind = instr->token_kind();
+
+  // Type test is special as it always gets converted into inlined code.
+  if (Token::IsTypeTestOperator(op_kind)) {
+    ReplaceWithInstanceOf(instr);
+    return;
+  }
+
+  if (Token::IsTypeCastOperator(op_kind)) {
+    ReplaceWithTypeCast(instr);
+    return;
+  }
+
+  const ICData& unary_checks =
+      ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks());
+
+  const intptr_t max_checks = (op_kind == Token::kEQ)
+      ? FLAG_max_equality_polymorphic_checks
+      : FLAG_max_polymorphic_checks;
+  if ((unary_checks.NumberOfChecks() > max_checks) &&
+      InstanceCallNeedsClassCheck(instr, RawFunction::kRegularFunction)) {
+    // Too many checks, it will be megamorphic which needs unary checks.
+    instr->set_ic_data(&unary_checks);
+    return;
+  }
+
+  if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) {
+    return;
+  }
+  if ((op_kind == Token::kINDEX) && 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;
+  }
+  if ((op_kind == Token::kGET) && TryInlineInstanceGetter(instr)) {
+    return;
+  }
+  if ((op_kind == Token::kSET) &&
+      TryInlineInstanceSetter(instr, unary_checks)) {
+    return;
+  }
+  if (TryInlineInstanceMethod(instr)) {
+    return;
+  }
+
+  bool has_one_target = 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,
+                                              /* call_with_checks = */ false);
+      instr->ReplaceWith(call, current_iterator());
+      return;
+    }
+  }
+
+  if (unary_checks.NumberOfChecks() <= FLAG_max_polymorphic_checks) {
+    bool call_with_checks;
+    if (has_one_target && FLAG_polymorphic_with_deopt) {
+      // Type propagation has not run yet, we cannot eliminate the check.
+      AddReceiverCheck(instr);
+      // Call can still deoptimize, do not detach environment from instr.
+      call_with_checks = false;
+    } else {
+      call_with_checks = true;
+    }
+    PolymorphicInstanceCallInstr* call =
+        new(Z) PolymorphicInstanceCallInstr(instr, unary_checks,
+                                            call_with_checks);
+    instr->ReplaceWith(call, current_iterator());
+  }
+}
+
+
+void JitOptimizer::VisitStaticCall(StaticCallInstr* call) {
+  if (!CanUnboxDouble()) {
+    return;
+  }
+  MethodRecognizer::Kind recognized_kind =
+      MethodRecognizer::RecognizeKind(call->function());
+  MathUnaryInstr::MathUnaryKind unary_kind;
+  switch (recognized_kind) {
+    case MethodRecognizer::kMathSqrt:
+      unary_kind = MathUnaryInstr::kSqrt;
+      break;
+    case MethodRecognizer::kMathSin:
+      unary_kind = MathUnaryInstr::kSin;
+      break;
+    case MethodRecognizer::kMathCos:
+      unary_kind = MathUnaryInstr::kCos;
+      break;
+    default:
+      unary_kind = MathUnaryInstr::kIllegal;
+      break;
+  }
+  if (unary_kind != MathUnaryInstr::kIllegal) {
+    MathUnaryInstr* math_unary =
+        new(Z) MathUnaryInstr(unary_kind,
+                              new(Z) Value(call->ArgumentAt(0)),
+                              call->deopt_id());
+    ReplaceCall(call, math_unary);
+    return;
+  }
+  switch (recognized_kind) {
+    case MethodRecognizer::kFloat32x4Zero:
+    case MethodRecognizer::kFloat32x4Splat:
+    case MethodRecognizer::kFloat32x4Constructor:
+    case MethodRecognizer::kFloat32x4FromFloat64x2:
+      TryInlineFloat32x4Constructor(call, recognized_kind);
+      break;
+    case MethodRecognizer::kFloat64x2Constructor:
+    case MethodRecognizer::kFloat64x2Zero:
+    case MethodRecognizer::kFloat64x2Splat:
+    case MethodRecognizer::kFloat64x2FromFloat32x4:
+      TryInlineFloat64x2Constructor(call, recognized_kind);
+      break;
+    case MethodRecognizer::kInt32x4BoolConstructor:
+    case MethodRecognizer::kInt32x4Constructor:
+      TryInlineInt32x4Constructor(call, recognized_kind);
+      break;
+    case MethodRecognizer::kObjectConstructor: {
+      // Remove the original push arguments.
+      for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
+        PushArgumentInstr* push = call->PushArgumentAt(i);
+        push->ReplaceUsesWith(push->value()->definition());
+        push->RemoveFromGraph();
+      }
+      // Manually replace call with global null constant. ReplaceCall can't
+      // be used for definitions that are already in the graph.
+      call->ReplaceUsesWith(flow_graph_->constant_null());
+      ASSERT(current_iterator()->Current() == call);
+      current_iterator()->RemoveCurrentFromGraph();
+      break;
+    }
+    case MethodRecognizer::kMathMin:
+    case MethodRecognizer::kMathMax: {
+      // We can handle only monomorphic min/max call sites with both arguments
+      // being either doubles or smis.
+      if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
+        const ICData& ic_data = *call->ic_data();
+        intptr_t result_cid = kIllegalCid;
+        if (ICDataHasReceiverArgumentClassIds(ic_data,
+                                              kDoubleCid, kDoubleCid)) {
+          result_cid = kDoubleCid;
+        } else if (ICDataHasReceiverArgumentClassIds(ic_data,
+                                                     kSmiCid, kSmiCid)) {
+          result_cid = kSmiCid;
+        }
+        if (result_cid != kIllegalCid) {
+          MathMinMaxInstr* min_max = new(Z) MathMinMaxInstr(
+              recognized_kind,
+              new(Z) Value(call->ArgumentAt(0)),
+              new(Z) Value(call->ArgumentAt(1)),
+              call->deopt_id(),
+              result_cid);
+          const ICData& unary_checks =
+              ICData::ZoneHandle(Z, ic_data.AsUnaryClassChecks());
+          AddCheckClass(min_max->left()->definition(),
+                        unary_checks,
+                        call->deopt_id(),
+                        call->env(),
+                        call);
+          AddCheckClass(min_max->right()->definition(),
+                        unary_checks,
+                        call->deopt_id(),
+                        call->env(),
+                        call);
+          ReplaceCall(call, min_max);
+        }
+      }
+      break;
+    }
+    case MethodRecognizer::kMathDoublePow:
+    case MethodRecognizer::kMathTan:
+    case MethodRecognizer::kMathAsin:
+    case MethodRecognizer::kMathAcos:
+    case MethodRecognizer::kMathAtan:
+    case MethodRecognizer::kMathAtan2: {
+      // InvokeMathCFunctionInstr requires unboxed doubles. UnboxDouble
+      // instructions contain type checks and conversions to double.
+      ZoneGrowableArray<Value*>* args =
+          new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount());
+      for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
+        args->Add(new(Z) Value(call->ArgumentAt(i)));
+      }
+      InvokeMathCFunctionInstr* invoke =
+          new(Z) InvokeMathCFunctionInstr(args,
+                                          call->deopt_id(),
+                                          recognized_kind,
+                                          call->token_pos());
+      ReplaceCall(call, invoke);
+      break;
+    }
+    case MethodRecognizer::kDoubleFromInteger: {
+      if (call->HasICData() && (call->ic_data()->NumberOfChecks() == 1)) {
+        const ICData& ic_data = *call->ic_data();
+        if (CanUnboxDouble()) {
+          if (ArgIsAlways(kSmiCid, ic_data, 1)) {
+            Definition* arg = call->ArgumentAt(1);
+            AddCheckSmi(arg, call->deopt_id(), call->env(), call);
+            ReplaceCall(call,
+                        new(Z) SmiToDoubleInstr(new(Z) Value(arg),
+                                                call->token_pos()));
+          } else if (ArgIsAlways(kMintCid, ic_data, 1) &&
+                     CanConvertUnboxedMintToDouble()) {
+            Definition* arg = call->ArgumentAt(1);
+            ReplaceCall(call,
+                        new(Z) MintToDoubleInstr(new(Z) Value(arg),
+                                                 call->deopt_id()));
+          }
+        }
+      }
+      break;
+    }
+    default: {
+      if (call->function().IsFactory()) {
+        const Class& function_class =
+            Class::Handle(Z, call->function().Owner());
+        if ((function_class.library() == Library::CoreLibrary()) ||
+            (function_class.library() == Library::TypedDataLibrary())) {
+          intptr_t cid = FactoryRecognizer::ResultCid(call->function());
+          switch (cid) {
+            case kArrayCid: {
+              Value* type = new(Z) Value(call->ArgumentAt(0));
+              Value* num_elements = new(Z) Value(call->ArgumentAt(1));
+              if (num_elements->BindsToConstant() &&
+                  num_elements->BoundConstant().IsSmi()) {
+                intptr_t length =
+                    Smi::Cast(num_elements->BoundConstant()).Value();
+                if (length >= 0 && length <= Array::kMaxElements) {
+                  CreateArrayInstr* create_array =
+                      new(Z) CreateArrayInstr(
+                          call->token_pos(), type, num_elements);
+                  ReplaceCall(call, create_array);
+                }
+              }
+            }
+            default:
+              break;
+          }
+        }
+      }
+    }
+  }
+}
+
+
+void JitOptimizer::VisitStoreInstanceField(
+    StoreInstanceFieldInstr* instr) {
+  if (instr->IsUnboxedStore()) {
+    ASSERT(instr->is_potential_unboxed_initialization_);
+    // Determine if this field should be unboxed based on the usage of getter
+    // and setter functions: The heuristic requires that the setter has a
+    // 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().Original());
+    const String& field_name = String::Handle(Z, field.name());
+    const Class& owner = Class::Handle(Z, field.Owner());
+    const Function& getter =
+        Function::Handle(Z, owner.LookupGetterFunction(field_name));
+    const Function& setter =
+        Function::Handle(Z, owner.LookupSetterFunction(field_name));
+    bool unboxed_field = false;
+    if (!getter.IsNull() && !setter.IsNull()) {
+      if (field.is_double_initialized()) {
+        unboxed_field = true;
+      } else if ((setter.usage_counter() > 0) &&
+                 ((FLAG_getter_setter_ratio * setter.usage_counter()) >=
+                   getter.usage_counter())) {
+        unboxed_field = true;
+      }
+    }
+    if (!unboxed_field) {
+      // TODO(srdjan): Instead of aborting pass this field to the mutator thread
+      // so that it can:
+      // - set it to unboxed
+      // - deoptimize dependent code.
+      if (Compiler::IsBackgroundCompilation()) {
+        isolate()->AddDeoptimizingBoxedField(field);
+        Compiler::AbortBackgroundCompilation(Thread::kNoDeoptId);
+        UNREACHABLE();
+      }
+      if (FLAG_trace_optimization || FLAG_trace_field_guards) {
+        THR_Print("Disabling unboxing of %s\n", field.ToCString());
+        if (!setter.IsNull()) {
+          OS::Print("  setter usage count: %" Pd "\n", setter.usage_counter());
+        }
+        if (!getter.IsNull()) {
+          OS::Print("  getter usage count: %" Pd "\n", getter.usage_counter());
+        }
+      }
+      field.set_is_unboxing_candidate(false);
+      field.DeoptimizeDependentCode();
+    } else {
+      flow_graph()->parsed_function().AddToGuardedFields(&field);
+    }
+  }
+}
+
+
+void JitOptimizer::VisitAllocateContext(AllocateContextInstr* instr) {
+  // Replace generic allocation with a sequence of inlined allocation and
+  // explicit initalizing stores.
+  AllocateUninitializedContextInstr* replacement =
+      new AllocateUninitializedContextInstr(instr->token_pos(),
+                                            instr->num_context_variables());
+  instr->ReplaceWith(replacement, current_iterator());
+
+  StoreInstanceFieldInstr* store =
+      new(Z) StoreInstanceFieldInstr(Context::parent_offset(),
+                                     new Value(replacement),
+                                     new Value(flow_graph_->constant_null()),
+                                     kNoStoreBarrier,
+                                     instr->token_pos());
+  // Storing into uninitialized memory; remember to prevent dead store
+  // elimination and ensure proper GC barrier.
+  store->set_is_object_reference_initialization(true);
+  flow_graph_->InsertAfter(replacement, store, NULL, FlowGraph::kEffect);
+  Definition* cursor = store;
+  for (intptr_t i = 0; i < instr->num_context_variables(); ++i) {
+    store =
+        new(Z) StoreInstanceFieldInstr(Context::variable_offset(i),
+                                       new Value(replacement),
+                                       new Value(flow_graph_->constant_null()),
+                                       kNoStoreBarrier,
+                                       instr->token_pos());
+    // Storing into uninitialized memory; remember to prevent dead store
+    // elimination and ensure proper GC barrier.
+    store->set_is_object_reference_initialization(true);
+    flow_graph_->InsertAfter(cursor, store, NULL, FlowGraph::kEffect);
+    cursor = store;
+  }
+}
+
+
+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())
+    instr->set_representation(kUnboxedMint);
+#endif
+}
+
+
+bool JitOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
+                                           const ICData& unary_ic_data) {
+  ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
+      (unary_ic_data.NumArgsTested() == 1));
+  if (I->type_checks()) {
+    // Checked mode setters are inlined like normal methods by conventional
+    // inlining.
+    return false;
+  }
+
+  ASSERT(instr->HasICData());
+  if (unary_ic_data.NumberOfChecks() == 0) {
+    // No type feedback collected.
+    return false;
+  }
+  if (!unary_ic_data.HasOneTarget()) {
+    // Polymorphic sites are inlined like normal method calls by conventional
+    // inlining.
+    return false;
+  }
+  Function& target = Function::Handle(Z);
+  intptr_t class_id;
+  unary_ic_data.GetOneClassCheckAt(0, &class_id, &target);
+  if (target.kind() != RawFunction::kImplicitSetter) {
+    // Non-implicit setter are inlined like normal method calls.
+    return false;
+  }
+  // Inline implicit instance setter.
+  const String& field_name =
+      String::Handle(Z, Field::NameFromSetter(instr->function_name()));
+  const Field& field =
+      Field::ZoneHandle(Z, GetField(class_id, field_name));
+  ASSERT(!field.IsNull());
+
+  if (InstanceCallNeedsClassCheck(instr, RawFunction::kImplicitSetter)) {
+    AddReceiverCheck(instr);
+  }
+  if (field.guarded_cid() != kDynamicCid) {
+    InsertBefore(instr,
+                 new(Z) GuardFieldClassInstr(
+                     new(Z) Value(instr->ArgumentAt(1)),
+                      field,
+                      instr->deopt_id()),
+                 instr->env(),
+                 FlowGraph::kEffect);
+  }
+
+  if (field.needs_length_check()) {
+    InsertBefore(instr,
+                 new(Z) GuardFieldLengthInstr(
+                     new(Z) Value(instr->ArgumentAt(1)),
+                      field,
+                      instr->deopt_id()),
+                 instr->env(),
+                 FlowGraph::kEffect);
+  }
+
+  // Field guard was detached.
+  StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr(
+      field,
+      new(Z) Value(instr->ArgumentAt(0)),
+      new(Z) Value(instr->ArgumentAt(1)),
+      kEmitStoreBarrier,
+      instr->token_pos());
+
+  if (store->IsUnboxedStore()) {
+    flow_graph()->parsed_function().AddToGuardedFields(&field);
+  }
+
+  // Discard the environment from the original instruction because the store
+  // can't deoptimize.
+  instr->RemoveEnvironment();
+  ReplaceCall(instr, store);
+  return true;
+}
+
+
+}  // namespace dart
diff --git a/runtime/vm/jit_optimizer.h b/runtime/vm/jit_optimizer.h
new file mode 100644
index 0000000..ebddc78
--- /dev/null
+++ b/runtime/vm/jit_optimizer.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_JIT_OPTIMIZER_H_
+#define VM_JIT_OPTIMIZER_H_
+
+#include "vm/intermediate_language.h"
+#include "vm/flow_graph.h"
+
+namespace dart {
+
+class CSEInstructionMap;
+template <typename T> class GrowableArray;
+class ParsedFunction;
+
+class JitOptimizer : public FlowGraphVisitor {
+ public:
+  explicit JitOptimizer(FlowGraph* flow_graph)
+      : FlowGraphVisitor(flow_graph->reverse_postorder()),
+        flow_graph_(flow_graph) { }
+
+  virtual ~JitOptimizer() {}
+
+  FlowGraph* flow_graph() const { return flow_graph_; }
+
+  // Use ICData to optimize, replace or eliminate instructions.
+  void ApplyICData();
+
+  // Use propagated class ids to optimize, replace or eliminate instructions.
+  void ApplyClassIds();
+
+  // 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.
+  // Merge instructions (only per basic-block).
+  void TryOptimizePatterns();
+
+  virtual void VisitStaticCall(StaticCallInstr* instr);
+  virtual void VisitInstanceCall(InstanceCallInstr* instr);
+  virtual void VisitStoreInstanceField(StoreInstanceFieldInstr* instr);
+  virtual void VisitAllocateContext(AllocateContextInstr* instr);
+  virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr* instr);
+
+  void InsertBefore(Instruction* next,
+                    Instruction* instr,
+                    Environment* env,
+                    FlowGraph::UseKind use_kind) {
+    flow_graph_->InsertBefore(next, instr, env, use_kind);
+  }
+
+ private:
+  // Attempt to build ICData for call using propagated class-ids.
+  bool TryCreateICData(InstanceCallInstr* call);
+  const ICData& TrySpecializeICData(const ICData& ic_data, intptr_t cid);
+
+  void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
+
+  bool TryReplaceWithIndexedOp(InstanceCallInstr* call);
+
+
+  bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind);
+  bool TryReplaceWithUnaryOp(InstanceCallInstr* call, Token::Kind op_kind);
+
+  bool TryReplaceWithEqualityOp(InstanceCallInstr* call, Token::Kind op_kind);
+  bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
+
+  bool TryInlineInstanceGetter(InstanceCallInstr* call);
+  bool TryInlineInstanceSetter(InstanceCallInstr* call,
+                               const ICData& unary_ic_data);
+
+  bool TryInlineInstanceMethod(InstanceCallInstr* call);
+  bool TryInlineFloat32x4Constructor(StaticCallInstr* call,
+                                     MethodRecognizer::Kind recognized_kind);
+  bool TryInlineFloat64x2Constructor(StaticCallInstr* call,
+                                     MethodRecognizer::Kind recognized_kind);
+  bool TryInlineInt32x4Constructor(StaticCallInstr* call,
+                                    MethodRecognizer::Kind recognized_kind);
+  bool TryInlineFloat32x4Method(InstanceCallInstr* call,
+                                MethodRecognizer::Kind recognized_kind);
+  bool TryInlineFloat64x2Method(InstanceCallInstr* call,
+                                MethodRecognizer::Kind recognized_kind);
+  bool TryInlineInt32x4Method(InstanceCallInstr* call,
+                               MethodRecognizer::Kind recognized_kind);
+  void ReplaceWithInstanceOf(InstanceCallInstr* instr);
+  bool TypeCheckAsClassEquality(const AbstractType& type);
+  void ReplaceWithTypeCast(InstanceCallInstr* instr);
+
+  bool TryReplaceInstanceCallWithInline(InstanceCallInstr* call);
+
+  // Insert a check of 'to_check' determined by 'unary_checks'.  If the
+  // check fails it will deoptimize to 'deopt_id' using the deoptimization
+  // environment 'deopt_environment'.  The check is inserted immediately
+  // before 'insert_before'.
+  void AddCheckClass(Definition* to_check,
+                     const ICData& unary_checks,
+                     intptr_t deopt_id,
+                     Environment* deopt_environment,
+                     Instruction* insert_before);
+  Instruction* GetCheckClass(Definition* to_check,
+                             const ICData& unary_checks,
+                             intptr_t deopt_id,
+                             TokenPosition token_pos);
+
+  // Insert a Smi check if needed.
+  void AddCheckSmi(Definition* to_check,
+                   intptr_t deopt_id,
+                   Environment* deopt_environment,
+                   Instruction* insert_before);
+
+  // Add a class check for a call's first argument immediately before the
+  // call, using the call's IC data to determine the check, and the call's
+  // deopt ID and deoptimization environment if the check fails.
+  void AddReceiverCheck(InstanceCallInstr* call);
+
+  void ReplaceCall(Definition* call, Definition* replacement);
+
+
+  bool InstanceCallNeedsClassCheck(InstanceCallInstr* call,
+                                   RawFunction::Kind kind) const;
+
+  bool InlineFloat32x4Getter(InstanceCallInstr* call,
+                             MethodRecognizer::Kind getter);
+  bool InlineFloat64x2Getter(InstanceCallInstr* call,
+                             MethodRecognizer::Kind getter);
+  bool InlineInt32x4Getter(InstanceCallInstr* call,
+                            MethodRecognizer::Kind getter);
+  bool InlineFloat32x4BinaryOp(InstanceCallInstr* call,
+                               Token::Kind op_kind);
+  bool InlineInt32x4BinaryOp(InstanceCallInstr* call,
+                              Token::Kind op_kind);
+  bool InlineFloat64x2BinaryOp(InstanceCallInstr* call,
+                               Token::Kind op_kind);
+  bool InlineImplicitInstanceGetter(InstanceCallInstr* call);
+
+  RawBool* InstanceOfAsBool(const ICData& ic_data,
+                            const AbstractType& type,
+                            ZoneGrowableArray<intptr_t>* results) const;
+
+  void ReplaceWithMathCFunction(InstanceCallInstr* call,
+                                MethodRecognizer::Kind recognized_kind);
+
+  void OptimizeLeftShiftBitAndSmiOp(Definition* bit_and_instr,
+                                    Definition* left_instr,
+                                    Definition* right_instr);
+  void TryMergeTruncDivMod(GrowableArray<BinarySmiOpInstr*>* merge_candidates);
+  void TryMergeMathUnary(GrowableArray<MathUnaryInstr*>* merge_candidates);
+
+  void AppendExtractNthOutputForMerged(Definition* instr, intptr_t ix,
+                                       Representation rep, intptr_t cid);
+  bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
+
+  RawField* GetField(intptr_t class_id, const String& field_name);
+
+  Thread* thread() const { return flow_graph_->thread(); }
+  Isolate* isolate() const { return flow_graph_->isolate(); }
+  Zone* zone() const { return flow_graph_->zone(); }
+
+  const Function& function() const { return flow_graph_->function(); }
+
+  FlowGraph* flow_graph_;
+
+  DISALLOW_COPY_AND_ASSIGN(JitOptimizer);
+};
+
+
+}  // namespace dart
+
+#endif  // VM_JIT_OPTIMIZER_H_
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index 4851875..94928ab 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -18,6 +18,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 DECLARE_FLAG(bool, trace_service);
 
 JSONStream::JSONStream(intptr_t buf_size)
@@ -77,9 +79,9 @@
     Isolate* isolate = Isolate::Current();
     ASSERT(isolate != NULL);
     const char* isolate_name = isolate->name();
-    OS::Print("Isolate %s processing service request %s\n",
-              isolate_name, method_);
     setup_time_micros_ = OS::GetCurrentTimeMicros();
+    OS::Print("[+%" Pd64 "ms] Isolate %s processing service request %s\n",
+              Dart::timestamp(), isolate_name, method_);
   }
   buffer_.Printf("{\"jsonrpc\":\"2.0\", \"result\":");
 }
@@ -170,10 +172,6 @@
   Dart_Port port = reply_port();
   ASSERT(port != ILLEGAL_PORT);
   set_reply_port(ILLEGAL_PORT);  // Prevent double replies.
-  int64_t process_delta_micros = 0;
-  if (FLAG_trace_service) {
-    process_delta_micros = OS::GetCurrentTimeMicros() - setup_time_micros_;
-  }
   ASSERT(seq_ != NULL);
   if (seq_->IsString()) {
     const String& str = String::Cast(*seq_);
@@ -204,12 +202,15 @@
     Isolate* isolate = Isolate::Current();
     ASSERT(isolate != NULL);
     const char* isolate_name = isolate->name();
+    int64_t total_time = OS::GetCurrentTimeMicros() - setup_time_micros_;
     if (result) {
-      OS::Print("Isolate %s processed service request %s in %" Pd64" us.\n",
-                isolate_name, method_, process_delta_micros);
+      OS::Print("[+%" Pd64 "ms] Isolate %s processed service request %s "
+                "(%" Pd64 "us)\n",
+                Dart::timestamp(), isolate_name, method_, total_time);
     } else {
-      OS::Print("Isolate %s FAILED to post response for service request %s.\n",
-                isolate_name, method_);
+      OS::Print("[+%" Pd64 "ms] Isolate %s processed service request %s "
+                "(%" Pd64 "us) FAILED\n",
+                Dart::timestamp(), isolate_name, method_, total_time);
     }
   }
 }
@@ -396,10 +397,12 @@
 }
 
 
-bool JSONStream::PrintValueStr(const String& s, intptr_t limit) {
+bool JSONStream::PrintValueStr(const String& s,
+                               intptr_t offset,
+                               intptr_t count) {
   PrintCommaIfNeeded();
   buffer_.AddChar('"');
-  bool did_truncate = AddDartString(s, limit);
+  bool did_truncate = AddDartString(s, offset, count);
   buffer_.AddChar('"');
   return did_truncate;
 }
@@ -442,6 +445,12 @@
 }
 
 
+void JSONStream::PrintValue(TokenPosition tp) {
+  PrintCommaIfNeeded();
+  PrintValue(tp.value());
+}
+
+
 void JSONStream::PrintValue(const ServiceEvent* event) {
   PrintCommaIfNeeded();
   event->PrintJSON(this);
@@ -534,9 +543,10 @@
 
 bool JSONStream::PrintPropertyStr(const char* name,
                                   const String& s,
-                                  intptr_t limit) {
+                                  intptr_t offset,
+                                  intptr_t count) {
   PrintPropertyName(name);
-  return PrintValueStr(s, limit);
+  return PrintValueStr(s, offset, count);
 }
 
 
@@ -558,6 +568,12 @@
 }
 
 
+void JSONStream::PrintProperty(const char* name, TokenPosition tp) {
+  PrintPropertyName(name);
+  PrintValue(tp);
+}
+
+
 void JSONStream::PrintProperty(const char* name, Metric* metric) {
   PrintPropertyName(name);
   PrintValue(metric);
@@ -702,23 +718,24 @@
 }
 
 
-bool JSONStream::AddDartString(const String& s, intptr_t limit) {
-  bool did_truncate = false;
+bool JSONStream::AddDartString(const String& s,
+                               intptr_t offset,
+                               intptr_t count) {
   intptr_t length = s.Length();
-  if (limit == -1) {
-    limit = length;
+  ASSERT(offset >= 0);
+  if (offset > length) {
+    offset = length;
   }
-  if (length <= limit) {
-    limit = length;
-  } else {
-    did_truncate = true;
+  if (!Utils::RangeCheck(offset, count, length)) {
+    count = length - offset;
   }
-
-  for (intptr_t i = 0; i < limit; i++) {
+  intptr_t limit = offset + count;
+  for (intptr_t i = offset; i < limit; i++) {
     intptr_t code_unit = s.CharAt(i);
     buffer_.EscapeAndAddCodeUnit(code_unit);
   }
-  return did_truncate;
+  // Return value indicates whether the string is truncated.
+  return (offset > 0) || (limit < length);
 }
 
 
@@ -749,13 +766,13 @@
 
 
 void JSONObject::AddLocation(const Script& script,
-                             intptr_t token_pos,
-                             intptr_t end_token_pos) const {
+                             TokenPosition token_pos,
+                             TokenPosition end_token_pos) const {
   JSONObject location(this, "location");
   location.AddProperty("type", "SourceLocation");
   location.AddProperty("script", script);
   location.AddProperty("tokenPos", token_pos);
-  if (end_token_pos >= 0) {
+  if (end_token_pos.IsReal()) {
     location.AddProperty("endTokenPos", end_token_pos);
   }
 }
@@ -767,7 +784,7 @@
   Zone* zone = Thread::Current()->zone();
   Library& library = Library::Handle(zone);
   Script& script = Script::Handle(zone);
-  intptr_t token_pos;
+  TokenPosition token_pos = TokenPosition::kNoSource;
   bpt_loc->GetCodeLocation(&library, &script, &token_pos);
   AddLocation(script, token_pos);
 }
@@ -780,7 +797,7 @@
   Zone* zone = Thread::Current()->zone();
   Library& library = Library::Handle(zone);
   Script& script = Script::Handle(zone);
-  intptr_t token_pos;
+  TokenPosition token_pos = TokenPosition::kNoSource;
   bpt_loc->GetCodeLocation(&library, &script, &token_pos);
 
   JSONObject location(this, "location");
@@ -841,4 +858,6 @@
   free(p);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 95d2041..8c145681 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -9,6 +9,7 @@
 #include "platform/text_buffer.h"
 #include "vm/allocation.h"
 #include "vm/service.h"
+#include "vm/token_position.h"
 
 
 namespace dart {
@@ -155,11 +156,12 @@
   void PrintfValue(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
   void PrintValue(const Object& o, bool ref = true);
   void PrintValue(Breakpoint* bpt);
+  void PrintValue(TokenPosition tp);
   void PrintValue(const ServiceEvent* event);
   void PrintValue(Metric* metric);
   void PrintValue(MessageQueue* queue);
   void PrintValue(Isolate* isolate, bool ref = true);
-  bool PrintValueStr(const String& s, intptr_t limit);
+  bool PrintValueStr(const String& s, intptr_t offset, intptr_t count);
   void PrintValue(TimelineEvent* timeline_event);
   void PrintValueVM(bool ref = true);
 
@@ -174,7 +176,8 @@
                            const uint8_t* bytes,
                            intptr_t length);
   void PrintProperty(const char* name, const char* s);
-  bool PrintPropertyStr(const char* name, const String& s, intptr_t limit);
+  bool PrintPropertyStr(const char* name, const String& s,
+                        intptr_t offset, intptr_t count);
   void PrintPropertyNoEscape(const char* name, const char* s);
   void PrintfProperty(const char* name, const char* format, ...)
   PRINTF_ATTRIBUTE(3, 4);
@@ -182,6 +185,7 @@
 
   void PrintProperty(const char* name, const ServiceEvent* event);
   void PrintProperty(const char* name, Breakpoint* bpt);
+  void PrintProperty(const char* name, TokenPosition tp);
   void PrintProperty(const char* name, Metric* metric);
   void PrintProperty(const char* name, MessageQueue* queue);
   void PrintProperty(const char* name, Isolate* isolate);
@@ -191,7 +195,7 @@
   void PrintCommaIfNeeded();
   bool NeedComma();
 
-  bool AddDartString(const String& s, intptr_t limit);
+  bool AddDartString(const String& s, intptr_t offset, intptr_t count);
   void AddEscapedUTF8String(const char* s);
   void AddEscapedUTF8String(const char* s, intptr_t len);
 
@@ -240,9 +244,10 @@
 
   void AddFixedServiceId(const char* format, ...) const PRINTF_ATTRIBUTE(2, 3);
 
-  void AddLocation(const Script& script,
-                   intptr_t token_pos,
-                   intptr_t end_token_pos = -1) const;
+  void AddLocation(
+      const Script& script,
+      TokenPosition token_pos,
+      TokenPosition end_token_pos = TokenPosition::kNoSource) const;
 
   void AddLocation(const BreakpointLocation* bpt_loc) const;
 
@@ -276,8 +281,9 @@
   }
   bool AddPropertyStr(const char* name,
                       const String& s,
-                      intptr_t limit = -1) const {
-    return stream_->PrintPropertyStr(name, s, limit);
+                      intptr_t offset = 0,
+                      intptr_t count = -1) const {
+    return stream_->PrintPropertyStr(name, s, offset, count);
   }
   void AddPropertyNoEscape(const char* name, const char* s) const {
     stream_->PrintPropertyNoEscape(name, s);
@@ -291,6 +297,9 @@
   void AddProperty(const char* name, Breakpoint* bpt) const {
     stream_->PrintProperty(name, bpt);
   }
+  void AddProperty(const char* name, TokenPosition tp) const {
+    stream_->PrintProperty(name, tp);
+  }
   void AddProperty(const char* name, Metric* metric) const {
     stream_->PrintProperty(name, metric);
   }
@@ -355,6 +364,9 @@
   void AddValue(Breakpoint* bpt) const {
     stream_->PrintValue(bpt);
   }
+  void AddValue(TokenPosition tp) const {
+    stream_->PrintValue(tp);
+  }
   void AddValue(const ServiceEvent* event) const {
     stream_->PrintValue(event);
   }
diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc
index 245bdd6..7c5b49f 100644
--- a/runtime/vm/json_test.cc
+++ b/runtime/vm/json_test.cc
@@ -10,6 +10,7 @@
 
 namespace dart {
 
+#ifndef PRODUCT
 
 TEST_CASE(JSON_TextBuffer) {
   TextBuffer w(5);  // Small enough to make buffer grow at least once.
@@ -236,9 +237,22 @@
     JSONStream js;
     {
       JSONObject jsobj(&js);
-      jsobj.AddPropertyStr("ascci", obj);;
+      EXPECT(!jsobj.AddPropertyStr("ascii", obj));
     }
-    EXPECT_STREQ("{\"ascci\":\"Hello, World!\"}", js.ToCString());
+    EXPECT_STREQ("{\"ascii\":\"Hello, World!\"}", js.ToCString());
+  }
+
+  {
+    result = Dart_GetField(lib, NewString("ascii"));
+    EXPECT_VALID(result);
+    obj ^= Api::UnwrapHandle(result);
+
+    JSONStream js;
+    {
+      JSONObject jsobj(&js);
+      EXPECT(jsobj.AddPropertyStr("subrange", obj, 1, 4));
+    }
+    EXPECT_STREQ("{\"subrange\":\"ello\"}", js.ToCString());
   }
 
   {
@@ -249,7 +263,7 @@
     JSONStream js;
     {
       JSONObject jsobj(&js);
-      jsobj.AddPropertyStr("unicode", obj);
+      EXPECT(!jsobj.AddPropertyStr("unicode", obj));
     }
     EXPECT_STREQ("{\"unicode\":\"\\u00CE\\u00F1\\u0163\\u00E9r\\u00F1\\u00E5"
                  "\\u0163\\u00EE\\u00F6\\u00F1\\u00E5\\u013C\\u00EE\\u017E"
@@ -264,7 +278,7 @@
     JSONStream js;
     {
       JSONObject jsobj(&js);
-      jsobj.AddPropertyStr("surrogates", obj);
+      EXPECT(!jsobj.AddPropertyStr("surrogates", obj));
     }
     EXPECT_STREQ("{\"surrogates\":\"\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E"
                  "\\uD834\\uDD1E\\uD834\\uDD1E\"}", js.ToCString());
@@ -278,7 +292,7 @@
     JSONStream js;
     {
       JSONObject jsobj(&js);
-      jsobj.AddPropertyStr("nullInMiddle", obj);
+      EXPECT(!jsobj.AddPropertyStr("nullInMiddle", obj));
     }
     EXPECT_STREQ("{\"nullInMiddle\":\"This has\\u0000 four words.\"}",
                  js.ToCString());
@@ -301,4 +315,6 @@
   EXPECT(!js.ParamIs("dog", "banana"));
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index de4f773..8a9499e 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -195,6 +195,9 @@
 
 
 void Location::PrintTo(BufferFormatter* f) const {
+  if (!FLAG_support_il_printer) {
+    return;
+  }
   if (kind() == kStackSlot) {
     f->Print("S%+" Pd "", stack_index());
   } else if (kind() == kDoubleStackSlot) {
@@ -297,6 +300,9 @@
 
 
 void LocationSummary::PrintTo(BufferFormatter* f) const {
+  if (!FLAG_support_il_printer) {
+    return;
+  }
   if (input_count() > 0) {
     f->Print(" (");
     for (intptr_t i = 0; i < input_count(); i++) {
diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h
index 047b663..963c4b4 100644
--- a/runtime/vm/locations.h
+++ b/runtime/vm/locations.h
@@ -387,19 +387,20 @@
     return PayloadField::decode(value_);
   }
 
-  typedef BitField<Kind, 0, kBitsForKind> KindField;
-  typedef BitField<uword, kBitsForKind, kBitsForPayload> PayloadField;
+  class KindField : public BitField<uword, Kind, 0, kBitsForKind> {};
+  class PayloadField :
+      public BitField<uword, uword, kBitsForKind, kBitsForPayload> {};
 
   // Layout for kUnallocated locations payload.
-  typedef BitField<Policy, 0, 3> PolicyField;
+  typedef BitField<uword, Policy, 0, 3> PolicyField;
 
   // Layout for stack slots.
   static const intptr_t kBitsForBaseReg = 5;
   static const intptr_t kBitsForStackIndex = kBitsForPayload - kBitsForBaseReg;
-  typedef BitField<Register, 0, kBitsForBaseReg> StackSlotBaseField;
-  typedef BitField<intptr_t,
-                   kBitsForBaseReg,
-                   kBitsForStackIndex> StackIndexField;
+  class StackSlotBaseField :
+      public BitField<uword, Register, 0, kBitsForBaseReg> {};
+  class StackIndexField :
+      public BitField<uword, intptr_t, kBitsForBaseReg, kBitsForStackIndex> {};
   COMPILE_ASSERT(1 << kBitsForBaseReg >= kNumberOfCpuRegisters);
 
   static const intptr_t kStackIndexBias =
diff --git a/runtime/vm/lockers.cc b/runtime/vm/lockers.cc
new file mode 100644
index 0000000..2efe245
--- /dev/null
+++ b/runtime/vm/lockers.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/assert.h"
+#include "vm/lockers.h"
+#include "vm/safepoint.h"
+
+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());
+  thread->set_execution_state(Thread::kThreadInBlockedState);
+  thread->EnterSafepoint();
+  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);
+  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.
+    monitor_->Exit();
+    SafepointHandler* handler = thread->isolate()->safepoint_handler();
+    handler->ExitSafepointUsingLock(thread);
+    monitor_->Enter();
+  }
+  thread->set_execution_state(Thread::kThreadInVM);
+  return result;
+}
+
+
+SafepointMutexLocker::SafepointMutexLocker(Mutex* mutex) : mutex_(mutex) {
+  ASSERT(mutex != NULL);
+  if (!mutex_->TryLock()) {
+    // 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();
+    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);
+    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.
+      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);
+  }
+}
+
+}  // namespace dart
diff --git a/runtime/vm/lockers.h b/runtime/vm/lockers.h
index f3f5540..a0b1a17 100644
--- a/runtime/vm/lockers.h
+++ b/runtime/vm/lockers.h
@@ -13,43 +13,165 @@
 
 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) {
     return monitor_->Wait(millis);
   }
 
+  Monitor::WaitResult WaitWithSafepointCheck(
+      Thread* thread, int64_t millis = Monitor::kNoTimeout);
+
   Monitor::WaitResult WaitMicros(int64_t micros = Monitor::kNoTimeout) {
     return monitor_->WaitMicros(micros);
   }
@@ -64,10 +186,75 @@
 
  private:
   Monitor* const monitor_;
+  bool no_safepoint_scope_;
 
   DISALLOW_COPY_AND_ASSIGN(MonitorLocker);
 };
 
+/*
+ * 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);
+  virtual ~SafepointMutexLocker() {
+    mutex_->Unlock();
+  }
+
+ private:
+  Mutex* const mutex_;
+
+  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/log.cc b/runtime/vm/log.cc
index d576beb..91be51d 100644
--- a/runtime/vm/log.cc
+++ b/runtime/vm/log.cc
@@ -13,7 +13,8 @@
 
 DEFINE_FLAG(charp, isolate_log_filter, NULL,
             "Log isolates whose name include the filter. "
-            "Default: service isolate log messages are suppressed.");
+            "Default: service isolate log messages are suppressed "
+            "(specify 'vm-service' to log them).");
 
 Log::Log(LogPrinter printer)
     : printer_(printer),
@@ -140,16 +141,26 @@
 
 
 void Log::TerminateString() {
+  if (this == NoOpLog()) {
+    return;
+  }
   buffer_.Add('\0');
 }
 
 
 void Log::EnableManualFlush() {
+  if (this == NoOpLog()) {
+    return;
+  }
   manual_flush_++;
 }
 
 
 void Log::DisableManualFlush() {
+  if (this == NoOpLog()) {
+    return;
+  }
+
   manual_flush_--;
   ASSERT(manual_flush_ >= 0);
   if (manual_flush_ == 0) {
diff --git a/runtime/vm/longjump.cc b/runtime/vm/longjump.cc
index 5820a47..13e0133 100644
--- a/runtime/vm/longjump.cc
+++ b/runtime/vm/longjump.cc
@@ -29,7 +29,10 @@
   uword jumpbuf_addr = Isolate::GetCurrentStackPointer();
 #if defined(USING_SIMULATOR)
   Simulator* sim = Simulator::Current();
-  uword top_exit_frame_info = sim->top_exit_frame_info();
+  // When using simulator, only mutator thread should refer to Simulator
+  // since there can be only one per isolate.
+  uword top_exit_frame_info = thread->IsMutatorThread() ?
+      sim->top_exit_frame_info() : 0;
 #else
   uword top_exit_frame_info = thread->top_exit_frame_info();
 #endif
@@ -49,7 +52,6 @@
   ASSERT(IsSafeToJump());
 
   Thread* thread = Thread::Current();
-  Isolate* isolate = thread->isolate();
 
 #if defined(DEBUG)
 #define CHECK_REUSABLE_HANDLE(name)                                            \
@@ -59,7 +61,7 @@
 #endif  // defined(DEBUG)
 
   // Remember the error in the sticky error of this isolate.
-  isolate->object_store()->set_sticky_error(error);
+  thread->set_sticky_error(error);
 
   // Destruct all the active StackResource objects.
   StackResource::UnwindAbove(thread, top_);
diff --git a/runtime/vm/megamorphic_cache_table.cc b/runtime/vm/megamorphic_cache_table.cc
index 7f4bbec..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());
 
@@ -71,7 +71,8 @@
                                      false,  // Not external.
                                      false,  // Not native.
                                      cls,
-                                     0));  // No token position.
+                                     TokenPosition::kNoSource));
+  function.set_result_type(Type::Handle(Type::DynamicType()));
   function.set_is_debuggable(false);
   function.set_is_visible(false);
   function.AttachCode(code);
diff --git a/runtime/vm/message.cc b/runtime/vm/message.cc
index 54f40b4..035428d 100644
--- a/runtime/vm/message.cc
+++ b/runtime/vm/message.cc
@@ -181,6 +181,9 @@
 
 
 void MessageQueue::PrintJSON(JSONStream* stream) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONArray messages(stream);
 
   Object& msg_handler = Object::Handle();
@@ -203,9 +206,9 @@
     // TODO(johnmccutchan): Move port -> handler map out of Dart and into the
     // VM, that way we can lookup the handler without invoking Dart code.
     msg_handler = DartLibraryCalls::LookupHandler(current->dest_port());
-    if (msg_handler.IsInstance() && Instance::Cast(msg_handler).IsClosure()) {
+    if (msg_handler.IsClosure()) {
       // Grab function from closure.
-      msg_handler = Closure::function(Instance::Cast(msg_handler));
+      msg_handler = Closure::Cast(msg_handler).function();
     }
     if (msg_handler.IsFunction()) {
       const Function& function = Function::Cast(msg_handler);
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index 30194cd..c1a9980 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -61,10 +61,10 @@
       oob_message_handling_allowed_(true),
       live_ports_(0),
       paused_(0),
-      pause_on_start_(false),
-      pause_on_exit_(false),
-      paused_on_start_(false),
-      paused_on_exit_(false),
+      should_pause_on_start_(false),
+      should_pause_on_exit_(false),
+      is_paused_on_start_(false),
+      is_paused_on_exit_(false),
       paused_timestamp_(-1),
       pool_(NULL),
       task_(NULL),
@@ -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,19 @@
 #if defined(DEBUG)
   CheckAccess();
 #endif
-  return HandleMessages(true, false);
+  return HandleMessages(&ml, true, false);
+}
+
+
+MessageHandler::MessageStatus MessageHandler::HandleAllMessages() {
+  // We can only call HandleAllMessages when this handler is not
+  // assigned to a thread pool.
+  MonitorLocker ml(&monitor_);
+  ASSERT(pool_ == NULL);
+#if defined(DEBUG)
+  CheckAccess();
+#endif
+  return HandleMessages(&ml, true, true);
 }
 
 
@@ -266,7 +279,31 @@
 #if defined(DEBUG)
   CheckAccess();
 #endif
-  return HandleMessages(false, false);
+  return HandleMessages(&ml, false, false);
+}
+
+
+bool MessageHandler::ShouldPauseOnStart(MessageStatus status) const {
+  Isolate* owning_isolate = isolate();
+  if (owning_isolate == NULL) {
+    return false;
+  }
+  // If we are restarting or shutting down, we do not want to honor
+  // should_pause_on_start or should_pause_on_exit.
+  return (status != MessageHandler::kRestart &&
+          status != MessageHandler::kShutdown) &&
+         should_pause_on_start() && owning_isolate->is_runnable();
+}
+
+
+bool MessageHandler::ShouldPauseOnExit(MessageStatus status) const {
+  Isolate* owning_isolate = isolate();
+  if (owning_isolate == NULL) {
+    return false;
+  }
+  return (status != MessageHandler::kRestart &&
+          status != MessageHandler::kShutdown) &&
+         should_pause_on_exit() && owning_isolate->is_runnable();
 }
 
 
@@ -276,14 +313,6 @@
 }
 
 
-static bool ShouldPause(MessageHandler::MessageStatus status) {
-  // If we are restarting or shutting down, we do not want to honor
-  // pause_on_start or pause_on_exit.
-  return (status != MessageHandler::kRestart &&
-          status != MessageHandler::kShutdown);
-}
-
-
 void MessageHandler::TaskCallback() {
   ASSERT(Isolate::Current() == NULL);
   MessageStatus status = kOK;
@@ -294,28 +323,19 @@
     // all pending OOB messages, or we may miss a request for vm
     // shutdown.
     MonitorLocker ml(&monitor_);
-    if (pause_on_start()) {
-      if (!paused_on_start_) {
-        // Temporarily release the monitor when calling out to
-        // NotifyPauseOnStart.  This avoids a dead lock that can occur
-        // when this message handler tries to post a message while a
-        // message is being posted to it.
-        paused_on_start_ = true;
-        paused_timestamp_ = OS::GetCurrentTimeMillis();
-        monitor_.Exit();
-        NotifyPauseOnStart();
-        monitor_.Enter();
+    if (ShouldPauseOnStart(kOK)) {
+      if (!is_paused_on_start()) {
+        PausedOnStartLocked(true);
       }
       // More messages may have come in before we (re)acquired the monitor.
-      status = HandleMessages(false, false);
-      if (ShouldPause(status) && pause_on_start()) {
+      status = HandleMessages(&ml, false, false);
+      if (ShouldPauseOnStart(status)) {
         // Still paused.
         ASSERT(oob_queue_->IsEmpty());
         task_ = NULL;  // No task in queue.
         return;
       } else {
-        paused_on_start_ = false;
-        paused_timestamp_ = -1;
+        PausedOnStartLocked(false);
       }
     }
 
@@ -326,55 +346,44 @@
         // 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);
       }
     }
 
     // The isolate exits when it encounters an error or when it no
     // longer has live ports.
     if (status != kOK || !HasLivePorts()) {
-      if (ShouldPause(status) && pause_on_exit()) {
-        if (!paused_on_exit_) {
+      if (ShouldPauseOnExit(status)) {
+        if (!is_paused_on_exit()) {
           if (FLAG_trace_service_pause_events) {
             OS::PrintErr("Isolate %s paused before exiting. "
                          "Use the Observatory to release it.\n", name());
           }
-          // Temporarily release the monitor when calling out to
-          // NotifyPauseOnExit.  This avoids a dead lock that can
-          // occur when this message handler tries to post a message
-          // while a message is being posted to it.
-          paused_on_exit_ = true;
-          paused_timestamp_ = OS::GetCurrentTimeMillis();
-          monitor_.Exit();
-          NotifyPauseOnExit();
-          monitor_.Enter();
-
+          PausedOnExitLocked(true);
           // More messages may have come in while we released the monitor.
-          HandleMessages(false, false);
+          status = HandleMessages(&ml, false, false);
         }
-        if (ShouldPause(status) && pause_on_exit()) {
+        if (ShouldPauseOnExit(status)) {
           // Still paused.
           ASSERT(oob_queue_->IsEmpty());
           task_ = NULL;  // No task in queue.
           return;
         } else {
-          paused_on_exit_ = false;
-          paused_timestamp_ = -1;
+          PausedOnExitLocked(false);
         }
       }
       if (FLAG_trace_isolates) {
         if (status != kOK && isolate() != NULL) {
-          const Error& error =
-              Error::Handle(isolate()->object_store()->sticky_error());
+          const Error& error = Error::Handle(thread()->sticky_error());
           OS::Print("[-] Stopping message handler (%s):\n"
                     "\thandler:    %s\n"
                     "\terror:    %s\n",
@@ -443,6 +452,74 @@
 }
 
 
+void MessageHandler::PausedOnStart(bool paused) {
+  MonitorLocker ml(&monitor_);
+  PausedOnStartLocked(paused);
+}
+
+
+void MessageHandler::PausedOnStartLocked(bool paused) {
+  if (paused) {
+    ASSERT(!is_paused_on_start_);
+    is_paused_on_start_ = true;
+    paused_timestamp_ = OS::GetCurrentTimeMillis();
+  } else {
+    ASSERT(is_paused_on_start_);
+    is_paused_on_start_ = false;
+    paused_timestamp_ = -1;
+  }
+  if (is_paused_on_start_) {
+    // Temporarily release the monitor when calling out to
+    // NotifyPauseOnStart.  This avoids a dead lock that can occur
+    // when this message handler tries to post a message while a
+    // message is being posted to it.
+    monitor_.Exit();
+    NotifyPauseOnStart();
+    monitor_.Enter();
+  } else {
+    // Resumed. Clear the resume request of the owning isolate.
+    Isolate* owning_isolate = isolate();
+    if (owning_isolate != NULL) {
+      owning_isolate->GetAndClearResumeRequest();
+    }
+  }
+}
+
+
+void MessageHandler::PausedOnExit(bool paused) {
+  MonitorLocker ml(&monitor_);
+  PausedOnExitLocked(paused);
+}
+
+
+void MessageHandler::PausedOnExitLocked(bool paused) {
+  if (paused) {
+    ASSERT(!is_paused_on_exit_);
+    is_paused_on_exit_ = true;
+    paused_timestamp_ = OS::GetCurrentTimeMillis();
+  } else {
+    ASSERT(is_paused_on_exit_);
+    is_paused_on_exit_ = false;
+    paused_timestamp_ = -1;
+  }
+  if (is_paused_on_exit_) {
+    // Temporarily release the monitor when calling out to
+    // NotifyPauseOnExit.  This avoids a dead lock that can
+    // occur when this message handler tries to post a message
+    // while a message is being posted to it.
+    monitor_.Exit();
+    NotifyPauseOnExit();
+    monitor_.Enter();
+  } else {
+    // Resumed. Clear the resume request of the owning isolate.
+    Isolate* owning_isolate = isolate();
+    if (owning_isolate != NULL) {
+      owning_isolate->GetAndClearResumeRequest();
+    }
+  }
+}
+
+
 MessageHandler::AcquiredQueues::AcquiredQueues()
     : handler_(NULL) {
 }
diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h
index f4d907c..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:
@@ -56,6 +59,13 @@
   // Returns true on success.
   MessageStatus HandleNextMessage();
 
+  // Handles all messages for this message handler.  Should only
+  // be used when not running the handler on the thread pool (via Run
+  // or RunBlocking).
+  //
+  // Returns true on success.
+  MessageStatus HandleAllMessages();
+
   // Handles any OOB messages for this message handler.  Can be used
   // even if the message handler is running on the thread pool.
   //
@@ -78,30 +88,30 @@
   void increment_paused() { paused_++; }
   void decrement_paused() { ASSERT(paused_ > 0); paused_--; }
 
-  bool pause_on_start() const {
-    return pause_on_start_;
+  bool ShouldPauseOnStart(MessageStatus status) const;
+  bool should_pause_on_start() const {
+    return should_pause_on_start_;
   }
 
-  void set_pause_on_start(bool pause_on_start) {
-    pause_on_start_ = pause_on_start;
+  void set_should_pause_on_start(bool should_pause_on_start) {
+    should_pause_on_start_ = should_pause_on_start;
   }
 
-  bool paused_on_start() const {
-    // If pause_on_start_ is still set, tell the user we are paused,
-    // even if we haven't hit the pause point yet.
-    return paused_on_start_;
+  bool is_paused_on_start() const {
+    return is_paused_on_start_;
   }
 
-  bool pause_on_exit() const {
-    return pause_on_exit_;
+  bool ShouldPauseOnExit(MessageStatus status) const;
+  bool should_pause_on_exit() const {
+    return should_pause_on_exit_;
   }
 
-  void set_pause_on_exit(bool pause_on_exit) {
-    pause_on_exit_ = pause_on_exit;
+  void set_should_pause_on_exit(bool should_pause_on_exit) {
+    should_pause_on_exit_ = should_pause_on_exit;
   }
 
-  bool paused_on_exit() const {
-    return paused_on_exit_;
+  bool is_paused_on_exit() const {
+    return is_paused_on_exit_;
   }
 
   // Timestamp of the paused on start or paused on exit.
@@ -109,6 +119,9 @@
     return paused_timestamp_;
   }
 
+  void PausedOnStart(bool paused);
+  void PausedOnExit(bool paused);
+
   class AcquiredQueues : public ValueObject {
    public:
     AcquiredQueues();
@@ -203,6 +216,11 @@
   // Called by MessageHandlerTask to process our task queue.
   void TaskCallback();
 
+  // NOTE: These two functions release and reacquire the monitor, you may
+  // need to call HandleMessages to ensure all pending messages are handled.
+  void PausedOnStartLocked(bool paused);
+  void PausedOnExitLocked(bool paused);
+
   // Dequeue the next message.  Prefer messages from the oob_queue_ to
   // messages from the queue_.
   Message* DequeueMessage(Message::Priority min_priority);
@@ -210,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.
@@ -221,10 +240,10 @@
   bool oob_message_handling_allowed_;
   intptr_t live_ports_;  // The number of open ports, including control ports.
   intptr_t paused_;  // The number of pause messages received.
-  bool pause_on_start_;
-  bool pause_on_exit_;
-  bool paused_on_start_;
-  bool paused_on_exit_;
+  bool should_pause_on_start_;
+  bool should_pause_on_exit_;
+  bool is_paused_on_start_;
+  bool is_paused_on_exit_;
   int64_t paused_timestamp_;
   ThreadPool* pool_;
   ThreadPool::Task* task_;
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index c878847..87a524e 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -13,305 +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(::, 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)                                                   \
@@ -331,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;
@@ -513,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/metrics.cc b/runtime/vm/metrics.cc
index 0e15c0f..cb6c205 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -80,6 +80,9 @@
 
 
 void Metric::PrintJSON(JSONStream* stream) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject obj(stream);
   obj.AddProperty("type", "Counter");
   obj.AddProperty("name", name_);
diff --git a/runtime/vm/metrics_test.cc b/runtime/vm/metrics_test.cc
index cb204b9..1e99b2d 100644
--- a/runtime/vm/metrics_test.cc
+++ b/runtime/vm/metrics_test.cc
@@ -13,6 +13,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 UNIT_TEST_CASE(Metric_Simple) {
   Dart_CreateIsolate(
       NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
@@ -69,4 +71,6 @@
   Dart_ShutdownIsolate();
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index 4d0a348..ddc649b 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -334,18 +334,8 @@
   String& name = String::Handle(Z);
   while (it.HasNext()) {
     cls = it.GetNextClass();
-    if (cls.IsSignatureClass()) {
-      if (!cls.IsCanonicalSignatureClass()) {
-        // This is a typedef.  Add it to the list of class names.
-        name = cls.UserVisibleName();
-        names.Add(name);
-      } else {
-        // Skip canonical signature classes.  These are not named.
-      }
-    } else {
-      name = cls.UserVisibleName();
-      names.Add(name);
-    }
+    name = cls.UserVisibleName();
+    names.Add(name);
   }
   return Api::NewHandle(T, Array::MakeArray(names));
 }
@@ -362,7 +352,7 @@
 
   ASSERT(ClassFinalizer::AllClassesFinalized());
 
-  RawFunction* rf = Closure::function(closure_obj);
+  RawFunction* rf = Closure::Cast(closure_obj).function();
   return Api::NewHandle(T, rf);
 }
 
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 8a546e4..1bc5d4c 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -28,12 +28,13 @@
       : saved_isolate_(current_isolate) {
     if (current_isolate != NULL) {
       ASSERT(current_isolate == Isolate::Current());
-      Thread::ExitIsolate();
+      Dart_ExitIsolate();
     }
   }
   ~IsolateSaver() {
     if (saved_isolate_ != NULL) {
-      Thread::EnterIsolate(saved_isolate_);
+      Dart_Isolate I = reinterpret_cast<Dart_Isolate>(saved_isolate_);
+      Dart_EnterIsolate(I);
     }
   }
  private:
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index 3fb2f74..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);
 
@@ -62,11 +61,15 @@
 
 #endif
 
+#ifndef PRODUCT
 #define TRACE_NATIVE_CALL(format, name)                                        \
   if (FLAG_trace_natives) {                                                    \
     OS::Print("Calling native: " format "\n", name);                           \
   }
-
+#else
+#define TRACE_NATIVE_CALL(format, name)                                        \
+  do { } while (0)
+#endif
 
 // Class NativeArguments is used to access arguments passed in from
 // generated dart code to a runtime function or a dart library native
@@ -96,6 +99,10 @@
     return *arg_ptr;
   }
 
+  bool IsNativeAutoSetupScope() const {
+    return AutoSetupScopeBits::decode(argc_tag_);
+  }
+
   int NativeArgCount() const {
     int function_bits = FunctionBits::decode(argc_tag_);
     return ArgCount() - NumHiddenArgs(function_bits);
@@ -107,7 +114,7 @@
       // Retrieve the receiver from the context.
       const Object& closure = Object::Handle(ArgAt(0));
       const Context& context =
-          Context::Handle(Closure::context(Instance::Cast(closure)));
+          Context::Handle(Closure::Cast(closure).context());
       return context.At(0);
     }
     return ArgAt(NumHiddenArgs(function_bits));
@@ -127,6 +134,10 @@
     *retval_ = value.raw();
   }
 
+  RawObject* ReturnValue() const {
+    return *retval_;
+  }
+
   static intptr_t thread_offset() {
     return OFFSET_OF(NativeArguments, thread_);
   }
@@ -185,9 +196,11 @@
     kFunctionSize = 2,
     kAutoSetupScopeBit = 26,
   };
-  class ArgcBits : public BitField<int, kArgcBit, kArgcSize> {};
-  class FunctionBits : public BitField<int, kFunctionBit, kFunctionSize> {};
-  class AutoSetupScopeBits : public BitField<int, kAutoSetupScopeBit, 1> {};
+  class ArgcBits : public BitField<intptr_t, int32_t, kArgcBit, kArgcSize> {};
+  class FunctionBits :
+      public BitField<intptr_t, int, kFunctionBit, kFunctionSize> {};
+  class AutoSetupScopeBits :
+      public BitField<intptr_t, int, kAutoSetupScopeBit, 1> {};
   friend class Api;
   friend class BootstrapNatives;
   friend class Simulator;
@@ -222,7 +235,7 @@
   }
 
   Thread* thread_;  // Current thread pointer.
-  int argc_tag_;  // Encodes argument count and invoked native call type.
+  intptr_t argc_tag_;  // Encodes argument count and invoked native call type.
   RawObject*(*argv_)[];  // Pointer to an array of arguments to runtime call.
   RawObject** retval_;  // Pointer to the return value area.
 };
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index 92a99e8..a5c79d3 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -12,6 +12,7 @@
 #include "vm/dart_api_state.h"
 #include "vm/object_store.h"
 #include "vm/reusable_handles.h"
+#include "vm/safepoint.h"
 #include "vm/stack_frame.h"
 #include "vm/symbols.h"
 #include "vm/tags.h"
@@ -23,6 +24,13 @@
             "Trace invocation of natives (debug mode only)");
 
 
+void DartNativeThrowArgumentException(const Instance& instance) {
+  const Array& __args__ = Array::Handle(Array::New(1));
+  __args__.SetAt(0, instance);
+  Exceptions::ThrowByType(Exceptions::kArgument, __args__);
+}
+
+
 NativeFunction NativeEntry::ResolveNative(const Library& library,
                                           const String& function_name,
                                           int number_of_arguments,
@@ -33,12 +41,16 @@
     // class belongs in.
     return NULL;
   }
-  Dart_EnterScope();  // Enter a new Dart API scope as we invoke API entries.
-  Dart_NativeEntryResolver resolver = library.native_entry_resolver();
-  Dart_NativeFunction native_function =
-      resolver(Api::NewHandle(Thread::Current(), function_name.raw()),
-               number_of_arguments, auto_setup_scope);
-  Dart_ExitScope();  // Exit the Dart API scope.
+  Dart_NativeFunction native_function = NULL;
+  {
+    Thread* T = Thread::Current();
+    TransitionVMToNative transition(T);
+    Dart_EnterScope();  // Enter a new Dart API scope as we invoke API entries.
+    Dart_NativeEntryResolver resolver = library.native_entry_resolver();
+    native_function = resolver(Api::NewHandle(T, function_name.raw()),
+                               number_of_arguments, auto_setup_scope);
+    Dart_ExitScope();  // Exit the Dart API scope.
+  }
   return reinterpret_cast<NativeFunction>(native_function);
 }
 
@@ -86,46 +98,82 @@
 }
 
 
+bool NativeEntry::ReturnValueIsError(NativeArguments* arguments) {
+  RawObject* retval = arguments->ReturnValue();
+  return (retval->IsHeapObject() &&
+          RawObject::IsErrorClassId(retval->GetClassId()));
+}
+
+
+void NativeEntry::PropagateErrors(NativeArguments* arguments) {
+  Thread* thread = arguments->thread();
+  thread->UnwindScopes(thread->top_exit_frame_info());
+
+  // The thread->zone() is different here than before we unwound.
+  const Object& error =
+      Object::Handle(thread->zone(), arguments->ReturnValue());
+  Exceptions::PropagateError(Error::Cast(error));
+  UNREACHABLE();
+}
+
+
 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. */
   MSAN_UNPOISON(arguments, sizeof(*arguments));
   Thread* thread = arguments->thread();
-  Isolate* isolate = thread->isolate();
-
-  ApiState* state = isolate->api_state();
-  ASSERT(state != NULL);
-  ApiLocalScope* current_top_scope = thread->api_top_scope();
-  ApiLocalScope* scope = thread->api_reusable_scope();
-  TRACE_NATIVE_CALL("0x%" Px "", reinterpret_cast<uintptr_t>(func));
-  if (scope == NULL) {
-    scope = new ApiLocalScope(current_top_scope,
-                              thread->top_exit_frame_info());
-    ASSERT(scope != NULL);
+  if (!arguments->IsNativeAutoSetupScope()) {
+    TransitionGeneratedToNative transition(thread);
+    func(args);
+    if (ReturnValueIsError(arguments)) {
+      PropagateErrors(arguments);
+    }
   } else {
-    scope->Reinit(thread,
-                  current_top_scope,
-                  thread->top_exit_frame_info());
-    thread->set_api_reusable_scope(NULL);
-  }
-  thread->set_api_top_scope(scope);  // New scope is now the top scope.
+    Isolate* isolate = thread->isolate();
+    ApiState* state = isolate->api_state();
+    ASSERT(state != NULL);
+    ApiLocalScope* current_top_scope = thread->api_top_scope();
+    ApiLocalScope* scope = thread->api_reusable_scope();
+    TRACE_NATIVE_CALL("0x%" Px "", reinterpret_cast<uintptr_t>(func));
+    TransitionGeneratedToNative transition(thread);
+    if (scope == NULL) {
+      scope = new ApiLocalScope(current_top_scope,
+                                thread->top_exit_frame_info());
+      ASSERT(scope != NULL);
+    } else {
+      scope->Reinit(thread,
+                    current_top_scope,
+                    thread->top_exit_frame_info());
+      thread->set_api_reusable_scope(NULL);
+    }
+    thread->set_api_top_scope(scope);  // New scope is now the top scope.
 
-  func(args);
+    func(args);
+    if (ReturnValueIsError(arguments)) {
+      PropagateErrors(arguments);
+    }
 
-  ASSERT(current_top_scope == scope->previous());
-  thread->set_api_top_scope(current_top_scope);  // Reset top scope to previous.
-  if (thread->api_reusable_scope() == NULL) {
-    scope->Reset(thread);  // Reset the old scope which we just exited.
-    thread->set_api_reusable_scope(scope);
-  } else {
-    ASSERT(thread->api_reusable_scope() != scope);
-    delete scope;
+    ASSERT(current_top_scope == scope->previous());
+    thread->set_api_top_scope(current_top_scope);  // Reset top scope to prev.
+    if (thread->api_reusable_scope() == NULL) {
+      scope->Reset(thread);  // Reset the old scope which we just exited.
+      thread->set_api_reusable_scope(scope);
+    } else {
+      ASSERT(thread->api_reusable_scope() != scope);
+      delete scope;
+    }
+    DEOPTIMIZE_ALOT;
+    VERIFY_ON_TRANSITION;
   }
-  DEOPTIMIZE_ALOT;
-  VERIFY_ON_TRANSITION;
 }
 
 
@@ -168,11 +216,9 @@
 
   NativeFunction target_function = NULL;
   bool call_through_wrapper = false;
-#ifdef USING_SIMULATOR
-  bool is_native_auto_setup_scope = false;
-#endif
 
   {
+    TransitionGeneratedToVM transition(arguments->thread());
     StackZone zone(arguments->thread());
 
     DartFrameIterator iterator;
@@ -180,9 +226,6 @@
 
     const Code& code = Code::Handle(caller_frame->LookupDartCode());
     const Function& func = Function::Handle(code.function());
-#ifdef USING_SIMULATOR
-    is_native_auto_setup_scope = func.IsNativeAutoSetupScope();
-#endif
 
     if (FLAG_trace_natives) {
       OS::Print("Resolving native target for %s\n", func.ToCString());
@@ -216,19 +259,14 @@
     }
 #endif
 
-    const intptr_t argc_tag = NativeArguments::ComputeArgcTag(func);
-    const bool is_leaf_call =
-        (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0;
-
-    call_through_wrapper = !is_bootstrap_native && !is_leaf_call;
-
+    call_through_wrapper = !is_bootstrap_native;
     const Code& trampoline = Code::Handle(call_through_wrapper ?
         StubCode::CallNativeCFunction_entry()->code() :
         StubCode::CallBootstrapCFunction_entry()->code());
 
     NativeFunction patch_target_function = target_function;
 #if defined(USING_SIMULATOR)
-    if (!call_through_wrapper || !is_native_auto_setup_scope) {
+    if (!call_through_wrapper) {
       patch_target_function = reinterpret_cast<NativeFunction>(
           Simulator::RedirectExternalReference(
               reinterpret_cast<uword>(patch_target_function),
@@ -240,17 +278,18 @@
         caller_frame->pc(), code, patch_target_function, trampoline);
 
     if (FLAG_trace_natives) {
-      OS::Print("    -> %p (%s, %s)\n",
+      OS::Print("    -> %p (%s)\n",
                 target_function,
-                is_bootstrap_native ? "bootstrap" : "non-bootstrap",
-                is_leaf_call ? "leaf" : "non-leaf");
+                is_bootstrap_native ? "bootstrap" : "non-bootstrap");
     }
   }
   VERIFY_ON_TRANSITION;
 
   // 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 25dee39..9557073 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -54,6 +54,7 @@
       Thread* thread = arguments->thread();                                    \
       ASSERT(thread == Thread::Current());                                     \
       Isolate* isolate = thread->isolate();                                    \
+      TransitionGeneratedToVM transition(thread);                              \
       StackZone zone(thread);                                                  \
       SET_NATIVE_RETVAL(arguments,                                             \
                         DN_Helper##name(isolate,                               \
@@ -70,15 +71,16 @@
                                     NativeArguments* arguments)
 
 
+// Helper that throws an argument exception.
+void DartNativeThrowArgumentException(const Instance& instance);
+
 // Natives should throw an exception if an illegal argument or null is passed.
 // type name = value.
 #define GET_NON_NULL_NATIVE_ARGUMENT(type, name, value)                        \
   const Instance& __##name##_instance__ =                                      \
       Instance::CheckedHandle(zone, value);                                    \
   if (!__##name##_instance__.Is##type()) {                                     \
-    const Array& __args__ = Array::Handle(Array::New(1));                      \
-    __args__.SetAt(0, __##name##_instance__);                                  \
-    Exceptions::ThrowByType(Exceptions::kArgument, __args__);                  \
+    DartNativeThrowArgumentException(__##name##_instance__);                   \
   }                                                                            \
   const type& name = type::Cast(__##name##_instance__);
 
@@ -91,9 +93,7 @@
   type& name = type::Handle(zone);                                             \
   if (!__##name##_instance__.IsNull()) {                                       \
     if (!__##name##_instance__.Is##type()) {                                   \
-      const Array& __args__ = Array::Handle(Array::New(1));                    \
-      __args__.SetAt(0, __##name##_instance__);                                \
-      Exceptions::ThrowByType(Exceptions::kArgument, __args__);                \
+      DartNativeThrowArgumentException(__##name##_instance__);                 \
     }                                                                          \
   }                                                                            \
   name ^= value;
@@ -120,6 +120,13 @@
 
   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);
 };
 
 }  // namespace dart
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 730d560..300070b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -29,8 +29,8 @@
 #include "vm/intrinsifier.h"
 #include "vm/object_store.h"
 #include "vm/parser.h"
+#include "vm/precompiler.h"
 #include "vm/profiler.h"
-#include "vm/report.h"
 #include "vm/reusable_handles.h"
 #include "vm/runtime_entry.h"
 #include "vm/scopes.h"
@@ -55,18 +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, throw_on_javascript_int_overflow, false,
-    "Throw an exception when the result of an integer calculation will not "
-    "fit into a javascript integer.");
-DEFINE_FLAG(bool, trace_cha, false, "Trace CHA operations");
-DEFINE_FLAG(bool, use_field_guards, true, "Guard field cids.");
 DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache");
-DEFINE_FLAG(bool, trace_field_guards, false, "Trace changes in field's cids.");
 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, show_invisible_frames);
 DECLARE_FLAG(bool, trace_deoptimization);
 DECLARE_FLAG(bool, trace_deoptimization_verbose);
@@ -115,6 +108,7 @@
 LanguageError* Object::snapshot_writer_error_ = NULL;
 LanguageError* Object::branch_offset_error_ = NULL;
 LanguageError* Object::speculative_inlining_error_ = NULL;
+LanguageError* Object::background_compilation_error_ = NULL;
 Array* Object::vm_isolate_snapshot_object_table_ = NULL;
 Type* Object::dynamic_type_ = NULL;
 Type* Object::void_type_ = NULL;
@@ -141,6 +135,8 @@
 RawClass* Object::instructions_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::object_pool_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+RawClass* Object::code_source_map_class_ =
+    reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::stackmap_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::var_descriptors_class_ =
     reinterpret_cast<RawClass*>(RAW_NULL);
@@ -217,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()));
@@ -267,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.
@@ -315,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.
@@ -363,6 +365,8 @@
   }
 
   return result.raw();
+)
+  return name.raw();  // In PRODUCT, return argument unchanged.
 }
 
 
@@ -489,6 +493,7 @@
   snapshot_writer_error_ = LanguageError::ReadOnlyHandle();
   branch_offset_error_ = LanguageError::ReadOnlyHandle();
   speculative_inlining_error_ = LanguageError::ReadOnlyHandle();
+  background_compilation_error_ = LanguageError::ReadOnlyHandle();
   vm_isolate_snapshot_object_table_ = Array::ReadOnlyHandle();
   dynamic_type_ = Type::ReadOnlyHandle();
   void_type_ = Type::ReadOnlyHandle();
@@ -613,6 +618,9 @@
   cls = Class::New<PcDescriptors>();
   pc_descriptors_class_ = cls.raw();
 
+  cls = Class::New<CodeSourceMap>();
+  code_source_map_class_ = cls.raw();
+
   cls = Class::New<Stackmap>();
   stackmap_class_ = cls.raw();
 
@@ -836,6 +844,17 @@
   *speculative_inlining_error_ = LanguageError::New(error_str,
                                                     Report::kBailout,
                                                     Heap::kOld);
+  error_str = String::New("Background Compilation Failed", Heap::kOld);
+  *background_compilation_error_ = LanguageError::New(error_str,
+                                                      Report::kBailout,
+                                                      Heap::kOld);
+
+  // Some thread fields need to be reinitialized as null constants have not been
+  // initialized until now.
+  Thread* thr = Thread::Current();
+  ASSERT(thr != NULL);
+  thr->clear_sticky_error();
+  thr->clear_pending_functions();
 
   ASSERT(!null_object_->IsSmi());
   ASSERT(!null_array_->IsSmi());
@@ -877,6 +896,8 @@
   ASSERT(branch_offset_error_->IsLanguageError());
   ASSERT(!speculative_inlining_error_->IsSmi());
   ASSERT(speculative_inlining_error_->IsLanguageError());
+  ASSERT(!background_compilation_error_->IsSmi());
+  ASSERT(background_compilation_error_->IsLanguageError());
   ASSERT(!vm_isolate_snapshot_object_table_->IsSmi());
   ASSERT(vm_isolate_snapshot_object_table_->IsArray());
 }
@@ -893,9 +914,12 @@
     if (!obj->IsFreeListElement()) {
       ASSERT(obj->IsVMHeapObject());
       if (obj->IsMarked()) {
-        // Precompiled instructions are loaded pre-marked.
+        // Precompiled objects are loaded pre-marked.
         ASSERT(Dart::IsRunningPrecompiledCode());
-        ASSERT(obj->IsInstructions());
+        ASSERT(obj->IsInstructions() ||
+               obj->IsPcDescriptors() ||
+               obj->IsStackmap() ||
+               obj->IsOneByteString());
       } else {
         obj->SetMarkBitUnsynchronized();
       }
@@ -945,6 +969,7 @@
   SET_CLASS_NAME(code, Code);
   SET_CLASS_NAME(instructions, Instructions);
   SET_CLASS_NAME(object_pool, ObjectPool);
+  SET_CLASS_NAME(code_source_map, CodeSourceMap);
   SET_CLASS_NAME(pc_descriptors, PcDescriptors);
   SET_CLASS_NAME(stackmap, Stackmap);
   SET_CLASS_NAME(var_descriptors, LocalVarDescriptors);
@@ -1077,9 +1102,11 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   ASSERT(isolate == thread->isolate());
+NOT_IN_PRODUCT(
   TimelineDurationScope tds(thread,
                             isolate->GetIsolateStream(),
                             "Object::Init");
+)
 
 #if defined(DART_NO_SNAPSHOT)
   // Object::Init version when we are running in a version of dart that does
@@ -1122,6 +1149,8 @@
 
   // Setup type class early in the process.
   const Class& type_cls = Class::Handle(zone, Class::New<Type>());
+  const Class& function_type_cls = Class::Handle(zone,
+                                                 Class::New<FunctionType>());
   const Class& type_ref_cls = Class::Handle(zone, Class::New<TypeRef>());
   const Class& type_parameter_cls = Class::Handle(zone,
                                                   Class::New<TypeParameter>());
@@ -1176,7 +1205,7 @@
   // could expect. Use with caution.
   type ^= Type::New(Object::Handle(zone, cls.raw()),
                     TypeArguments::Handle(zone),
-                    Scanner::kNoSourcePos);
+                    TokenPosition::kNoSource);
   type.SetIsFinalized();
   type ^= type.Canonicalize();
   object_store->set_array_type(type);
@@ -1284,6 +1313,9 @@
   RegisterPrivateClass(type_cls, Symbols::Type(), core_lib);
   pending_classes.Add(type_cls);
 
+  RegisterPrivateClass(function_type_cls, Symbols::FunctionType(), core_lib);
+  pending_classes.Add(function_type_cls);
+
   RegisterPrivateClass(type_ref_cls, Symbols::TypeRef(), core_lib);
   pending_classes.Add(type_ref_cls);
 
@@ -1321,15 +1353,14 @@
   RegisterPrivateClass(cls, Symbols::_Double(), core_lib);
   pending_classes.Add(cls);
 
-  // Abstract super class for all signature classes.
-  cls = Class::New<Instance>(kIllegalCid);
-  cls.set_num_type_arguments(0);
+  // Class that represents the Dart class _Closure and C++ class Closure.
+  cls = Class::New<Closure>();
+  cls.set_type_arguments_field_offset(Closure::type_arguments_offset());
+  cls.set_num_type_arguments(0);  // Although a closure has type_arguments_.
   cls.set_num_own_type_arguments(0);
-  cls.set_is_prefinalized();
-  RegisterPrivateClass(cls, Symbols::FunctionImpl(), core_lib);
+  RegisterPrivateClass(cls, Symbols::_Closure(), core_lib);
   pending_classes.Add(cls);
-  type = Type::NewNonParameterizedType(cls);
-  object_store->set_function_impl_type(type);
+  object_store->set_closure_class(cls);
 
   cls = Class::New<WeakProperty>();
   object_store->set_weak_property_class(cls);
@@ -1337,6 +1368,7 @@
 
   // Pre-register the mirrors library so we can place the vm class
   // MirrorReference there rather than the core library.
+NOT_IN_PRODUCT(
   lib = Library::LookupLibrary(Symbols::DartMirrors());
   if (lib.IsNull()) {
     lib = Library::NewLibraryHelper(Symbols::DartMirrors(), true);
@@ -1349,6 +1381,7 @@
 
   cls = Class::New<MirrorReference>();
   RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
+)
 
   // Pre-register the collection library so we can place the vm class
   // LinkedHashMap there rather than the core library.
@@ -1575,7 +1608,7 @@
 #define ADD_SET_FIELD(clazz)                                                   \
   field_name = Symbols::New("cid"#clazz);                                      \
   field = Field::New(field_name, true, false, true, false, cls,                \
-      Type::Handle(Type::IntType()), 0);                                       \
+      Type::Handle(Type::IntType()), TokenPosition::kMinSource);             \
   value = Smi::New(k##clazz##Cid);                                             \
   field.SetStaticValue(value, true);                                           \
   cls.AddField(field);                                                         \
@@ -1606,6 +1639,7 @@
 
   cls = Class::New<LibraryPrefix>();
   cls = Class::New<Type>();
+  cls = Class::New<FunctionType>();
   cls = Class::New<TypeRef>();
   cls = Class::New<TypeParameter>();
   cls = Class::New<BoundedType>();
@@ -1660,6 +1694,9 @@
   cls = Class::New<Double>();
   object_store->set_double_class(cls);
 
+  cls = Class::New<Closure>();
+  object_store->set_closure_class(cls);
+
   cls = Class::New<Bigint>();
   object_store->set_bigint_class(cls);
 
@@ -1704,72 +1741,22 @@
 }
 
 
+#if defined(DEBUG)
+bool Object:: InVMHeap() const {
+  if (FLAG_verify_handles && raw()->IsVMHeapObject()) {
+    Heap* vm_isolate_heap = Dart::vm_isolate()->heap();
+    ASSERT(vm_isolate_heap->Contains(RawObject::ToAddr(raw())));
+  }
+  return raw()->IsVMHeapObject();
+}
+#endif  // DEBUG
+
+
 void Object::Print() const {
   THR_Print("%s\n", ToCString());
 }
 
 
-static void AddNameProperties(JSONObject* jsobj,
-                              const String& name,
-                              const String& vm_name) {
-  jsobj->AddProperty("name", name.ToCString());
-  if (!name.Equals(vm_name)) {
-    jsobj->AddProperty("_vmName", vm_name.ToCString());
-  }
-}
-
-
-void Object::AddCommonObjectProperties(JSONObject* jsobj,
-                                       const char* protocol_type,
-                                       bool ref) const {
-  const char* vm_type = JSONType();
-  bool same_type = (strcmp(protocol_type, vm_type) == 0);
-  if (ref) {
-    jsobj->AddPropertyF("type", "@%s", protocol_type);
-  } else {
-    jsobj->AddProperty("type", protocol_type);
-  }
-  if (!same_type) {
-    jsobj->AddProperty("_vmType", vm_type);
-  }
-  if (!ref || IsInstance() || IsNull()) {
-    // TODO(turnidge): Provide the type arguments here too?
-    const Class& cls = Class::Handle(this->clazz());
-    jsobj->AddProperty("class", cls);
-  }
-  if (!ref) {
-    if (raw()->IsHeapObject()) {
-      jsobj->AddProperty("size", raw()->Size());
-    } else {
-      jsobj->AddProperty("size", (intptr_t)0);
-    }
-  }
-}
-
-
-void Object::PrintJSON(JSONStream* stream, bool ref) const {
-  if (IsNull()) {
-    JSONObject jsobj(stream);
-    AddCommonObjectProperties(&jsobj, "Instance", ref);
-    jsobj.AddProperty("kind", "Null");
-    jsobj.AddFixedServiceId("objects/null");
-    jsobj.AddProperty("valueAsString", "null");
-  } else {
-    PrintJSONImpl(stream, ref);
-  }
-}
-
-
-void Object::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Object", ref);
-  jsobj.AddServiceId(*this);
-  if (ref) {
-    return;
-  }
-}
-
-
 RawString* Object::DictionaryName() const {
   return String::null();
 }
@@ -1849,7 +1836,7 @@
     class_table->UpdateAllocatedOld(cls_id, size);
   }
   const Class& cls = Class::Handle(class_table->At(cls_id));
-  if (cls.TraceAllocation(isolate)) {
+  if (FLAG_profiler && cls.TraceAllocation(isolate)) {
     Profiler::SampleAllocation(thread, cls_id);
   }
   NoSafepointScope no_safepoint;
@@ -1936,14 +1923,17 @@
 }
 
 
-RawString* Class::PrettyName() const {
-  return GeneratePrettyName();
+RawString* Class::ScrubbedName() const {
+  return String::ScrubName(String::Handle(Name()));
 }
 
 
 RawString* Class::UserVisibleName() const {
+NOT_IN_PRODUCT(
   ASSERT(raw_ptr()->user_name_ != String::null());
   return raw_ptr()->user_name_;
+)
+  return GenerateUserVisibleName();  // No caching in PRODUCT, regenerate.
 }
 
 
@@ -1953,41 +1943,11 @@
 }
 
 
-RawType* Class::SignatureType() const {
-  ASSERT(IsSignatureClass());
-  Zone* zone = Thread::Current()->zone();
-  const Function& function = Function::Handle(zone, signature_function());
-  ASSERT(!function.IsNull());
-  if (function.signature_class() != raw()) {
-    // This class is a function type alias. Return the canonical signature type.
-    const Class& canonical_signature_class =
-        Class::Handle(zone, function.signature_class());
-    return canonical_signature_class.SignatureType();
-  }
-  const Type& signature_type = Type::Handle(zone, CanonicalType());
-  if (!signature_type.IsNull()) {
-    return signature_type.raw();
-  }
-  // A signature class extends class Instance and is parameterized in the same
-  // way as the owner class of its non-static signature function.
-  // It is not type parameterized if its signature function is static.
-  // See Class::NewSignatureClass() for the setup of its type parameters.
-  // During type finalization, the type arguments of the super class of the
-  // owner class of its signature function will be prepended to the type
-  // argument vector. Therefore, we only need to set the type arguments
-  // matching the type parameters here.
-  const TypeArguments& signature_type_arguments =
-      TypeArguments::Handle(zone, type_parameters());
-  // Return the still unfinalized signature type.
-  return Type::New(*this, signature_type_arguments, token_pos());
-}
-
-
 RawAbstractType* Class::RareType() const {
   const Type& type = Type::Handle(Type::New(
       *this,
       Object::null_type_arguments(),
-      Scanner::kNoSourcePos));
+      TokenPosition::kNoSource));
   return ClassFinalizer::FinalizeType(*this,
                                       type,
                                       ClassFinalizer::kCanonicalize);
@@ -1999,7 +1959,7 @@
   const Type& type = Type::Handle(Type::New(
       *this,
       args,
-      Scanner::kNoSourcePos));
+      TokenPosition::kNoSource));
   return ClassFinalizer::FinalizeType(*this,
                                       type,
                                       ClassFinalizer::kCanonicalize);
@@ -2037,7 +1997,7 @@
   result.set_num_type_arguments(0);
   result.set_num_own_type_arguments(0);
   result.set_num_native_fields(0);
-  result.set_token_pos(Scanner::kNoSourcePos);
+  result.set_token_pos(TokenPosition::kNoSource);
   result.InitEmptyFields();
   Isolate::Current()->RegisterClass(result);
   return result.raw();
@@ -2049,6 +2009,7 @@
   Report::MessageF(Report::kError,
                    Script::Handle(cls.script()),
                    cls.token_pos(),
+                   Report::AtLocation,
                    "too many type parameters declared in class '%s' or in its "
                    "super classes",
                    String::Handle(cls.Name()).ToCString());
@@ -2167,6 +2128,7 @@
 
 
 void Class::SetFunctions(const Array& value) const {
+  ASSERT(Thread::Current()->IsMutatorThread());
   ASSERT(!value.IsNull());
   StorePointer(&raw_ptr()->functions_, value.raw());
   const intptr_t len = value.Length();
@@ -2180,11 +2142,14 @@
       set.Insert(func);
     }
     StorePointer(&raw_ptr()->functions_hash_table_, set.Release().raw());
+  } else {
+    StorePointer(&raw_ptr()->functions_hash_table_, Array::null());
   }
 }
 
 
 void Class::AddFunction(const Function& function) const {
+  ASSERT(Thread::Current()->IsMutatorThread());
   const Array& arr = Array::Handle(functions());
   const Array& new_arr =
       Array::Handle(Array::Grow(arr, arr.Length() + 1, Heap::kOld));
@@ -2204,6 +2169,7 @@
 
 
 void Class::RemoveFunction(const Function& function) const {
+  ASSERT(Thread::Current()->IsMutatorThread());
   const Array& arr = Array::Handle(functions());
   StorePointer(&raw_ptr()->functions_, Object::empty_array().raw());
   StorePointer(&raw_ptr()->functions_hash_table_, Array::null());
@@ -2457,14 +2423,6 @@
   cls = raw();
   intptr_t num_type_args = 0;
   do {
-    if (cls.IsSignatureClass()) {
-      Function& signature_fun = Function::Handle(zone);
-      signature_fun ^= cls.signature_function();
-      if (!signature_fun.is_static() &&
-          !signature_fun.HasInstantiatedSignature()) {
-        cls = signature_fun.Owner();
-      }
-    }
     // Calling NumOwnTypeArguments() on a mixin application class will setup the
     // type parameters if not already done.
     num_type_args += cls.NumOwnTypeArguments();
@@ -2474,8 +2432,12 @@
       break;
     }
     sup_type = cls.super_type();
-    ClassFinalizer::ResolveTypeClass(cls, sup_type);
+    // A BoundedType, TypeRef, or FunctionType can appear as type argument of
+    // sup_type, but not as sup_type itself.
+    ASSERT(sup_type.IsType());
+    sup_type = ClassFinalizer::ResolveTypeClass(cls, Type::Cast(sup_type));
     cls = sup_type.type_class();
+    ASSERT(!cls.IsTypedefClass());
   } while (true);
   set_num_type_arguments(num_type_args);
   return num_type_args;
@@ -2527,6 +2489,7 @@
 
 
 void Class::CalculateFieldOffsets() const {
+  ASSERT(id() != kClosureCid);  // Class _Closure is prefinalized.
   Array& flds = Array::Handle(fields());
   const Class& super = Class::Handle(SuperClass());
   intptr_t offset = 0;
@@ -2637,7 +2600,7 @@
                     false,  // Not external.
                     false,  // Not native.
                     *this,
-                    0));    // token_pos
+                    TokenPosition::kMinSource));
   ArgumentsDescriptor desc(args_desc);
   invocation.set_num_fixed_parameters(desc.PositionalCount());
   invocation.SetNumOptionalParameters(desc.NamedCount(),
@@ -2694,7 +2657,7 @@
                   false,  // Not external.
                   false,  // Not native.
                   owner,
-                  0));    // token_pos
+                  TokenPosition::kMethodExtractor));
 
   // Initialize signature: receiver is a single fixed parameter.
   const intptr_t kNumParameters = 1;
@@ -2740,9 +2703,7 @@
 
 void Class::Finalize() const {
   ASSERT(Thread::Current()->IsMutatorThread());
-  // Even if all regular classes are prefinalized (precompilation), signature
-  // classes may be added later when we encounter local functions.
-  ASSERT(IsSignatureClass() || !Isolate::Current()->all_classes_finalized());
+  ASSERT(!Isolate::Current()->all_classes_finalized());
   ASSERT(!is_finalized());
   // Prefinalized classes have a VM internal representation and no Dart fields.
   // Their instance size  is precomputed and field offsets are known.
@@ -2797,8 +2758,7 @@
 #if defined(DEBUG)
 static bool IsMutatorOrAtSafepoint() {
   Thread* thread = Thread::Current();
-  return thread->IsMutatorThread() ||
-         thread->isolate()->thread_registry()->AtSafepoint();
+  return thread->IsMutatorThread() || thread->IsAtSafepoint();
 }
 #endif
 
@@ -2898,6 +2858,7 @@
           *error,  // No previous error.
           Script::Handle(patch.script()),
           func.token_pos(),
+          Report::AtLocation,
           Report::kError,
           Heap::kNew,
           "signature mismatch: '%s'", member_name.ToCString());
@@ -2943,6 +2904,7 @@
           *error,  // No previous error.
           Script::Handle(patch.script()),
           field.token_pos(),
+          Report::AtLocation,
           Report::kError,
           Heap::kNew,
           "duplicate field: %s", member_name.ToCString());
@@ -3055,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.
@@ -3107,7 +3070,7 @@
   result.set_num_type_arguments(kUnknownNumTypeArguments);
   result.set_num_own_type_arguments(kUnknownNumTypeArguments);
   result.set_num_native_fields(0);
-  result.set_token_pos(Scanner::kNoSourcePos);
+  result.set_token_pos(TokenPosition::kNoSource);
   result.InitEmptyFields();
   Isolate::Current()->RegisterClass(result);
   return result.raw();
@@ -3116,7 +3079,7 @@
 
 RawClass* Class::New(const String& name,
                      const Script& script,
-                     intptr_t token_pos) {
+                     TokenPosition token_pos) {
   Class& result = Class::Handle(New<Instance>(kIllegalCid));
   result.set_name(name);
   result.set_script(script);
@@ -3125,79 +3088,12 @@
 }
 
 
-RawClass* Class::NewSignatureClass(const String& name,
-                                   const Function& signature_function,
-                                   const Script& script,
-                                   intptr_t token_pos) {
-  const Class& result = Class::Handle(New(name, script, token_pos));
-  // Instances of a signature class can only be closures.
-  result.set_instance_size(Closure::InstanceSize());
-  result.set_next_field_offset(Closure::NextFieldOffset());
-  // Signature classes extend the _FunctionImpl class.
-  result.set_super_type(Type::Handle(
-      Isolate::Current()->object_store()->function_impl_type()));
-  result.set_is_synthesized_class();
-  result.set_type_arguments_field_offset(Closure::type_arguments_offset());
-  if (!signature_function.IsNull()) {
-    result.PatchSignatureFunction(signature_function);
-  }
-  return result.raw();
-}
-
-
-void Class::PatchSignatureFunction(const Function& signature_function) const {
-  ASSERT(!signature_function.IsNull());
-  set_signature_function(signature_function);
-  const Class& owner_class = Class::Handle(signature_function.Owner());
-  ASSERT(!owner_class.IsNull());
-  // A signature class extends class Instance and is either not parameterized or
-  // parameterized with exactly the same list of type parameters as the owner
-  // class of its function.
-  // In case of a function type alias, the function owner is the alias class,
-  // which is also the signature class. The signature class is therefore
-  // parameterized according to the alias class declaration, even if the
-  // function type is not generic.
-  // Otherwise, if the function is static or if its signature type is
-  // non-generic, i.e. it does not depend on any type parameter of the owner
-  // class, then the signature class is not parameterized, although the owner
-  // class may be.
-  if (owner_class.raw() == raw()) {
-    // This signature class is an alias, which cannot be the canonical
-    // signature class for this signature function.
-    ASSERT(!IsCanonicalSignatureClass());
-    // Do not modify the declared type parameters of the alias, even if unused.
-  } else {
-    // Copy the type parameters only for an instance function type that is not
-    // instantiated, i.e. that depends on the type parameters of the owner
-    // class.
-    // TODO(regis): Verify that it is not a problem for the copied type
-    // parameters to refer to the owner class rather than to the signature
-    // class. In other words, uninstantiated function types should only get
-    // instantiated by the owner class as instantiator and never by the
-    // signature class itself.
-    TypeArguments& type_parameters = TypeArguments::Handle();
-    if (!signature_function.is_static() &&
-        (owner_class.NumTypeParameters() > 0) &&
-        !signature_function.HasInstantiatedSignature()) {
-      type_parameters = owner_class.type_parameters();
-    }
-    set_type_parameters(type_parameters);
-    if (signature_function.signature_class() == Object::null()) {
-      // Make this signature class the canonical signature class.
-      signature_function.set_signature_class(*this);
-      ASSERT(IsCanonicalSignatureClass());
-    }
-  }
-  set_is_prefinalized();
-}
-
-
 RawClass* Class::NewNativeWrapper(const Library& library,
                                   const String& name,
                                   int field_count) {
   Class& cls = Class::Handle(library.LookupClass(name));
   if (cls.IsNull()) {
-    cls = New(name, Script::Handle(), Scanner::kNoSourcePos);
+    cls = New(name, Script::Handle(), TokenPosition::kNoSource);
     cls.SetFields(Object::empty_array());
     cls.SetFunctions(Object::empty_array());
     // Set super class to Object.
@@ -3271,8 +3167,10 @@
 
 
 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(
   if (raw_ptr()->user_name_ == String::null()) {
     // TODO(johnmccutchan): Eagerly set user name for VM isolate classes,
     // lazily set user name for the other classes.
@@ -3280,28 +3178,22 @@
     const String& user_name = String::Handle(GenerateUserVisibleName());
     set_user_name(user_name);
   }
+)
 }
 
 
+NOT_IN_PRODUCT(
 void Class::set_user_name(const String& value) const {
   StorePointer(&raw_ptr()->user_name_, value.raw());
 }
-
-
-RawString* Class::GeneratePrettyName() const {
-  if (!IsCanonicalSignatureClass()) {
-    const String& name = String::Handle(Name());
-    return String::IdentifierPrettyName(name);
-  } else {
-    return Name();
-  }
-}
+)
 
 
 RawString* Class::GenerateUserVisibleName() const {
   if (FLAG_show_internal_names) {
     return Name();
   }
+NOT_IN_PRODUCT(
   switch (id()) {
     case kNullCid:
       return Symbols::Null().raw();
@@ -3343,6 +3235,8 @@
       return Symbols::Instructions().raw();
     case kObjectPoolCid:
       return Symbols::ObjectPool().raw();
+    case kCodeSourceMapCid:
+      return Symbols::CodeSourceMap().raw();
     case kPcDescriptorsCid:
       return Symbols::PcDescriptors().raw();
     case kStackmapCid:
@@ -3431,15 +3325,10 @@
     case kTypedDataFloat64ArrayCid:
     case kExternalTypedDataFloat64ArrayCid:
       return Symbols::Float64List().raw();
-    default:
-      if (!IsCanonicalSignatureClass()) {
-        const String& name = String::Handle(Name());
-        return String::IdentifierPrettyName(name);
-      } else {
-        return Name();
-      }
   }
-  UNREACHABLE();
+)
+  const String& name = String::Handle(Name());
+  return String::ScrubName(name);
 }
 
 
@@ -3448,22 +3337,23 @@
 }
 
 
-void Class::set_token_pos(intptr_t token_pos) const {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+void Class::set_token_pos(TokenPosition token_pos) const {
+  ASSERT(!token_pos.IsClassifying());
   StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
 }
 
 
-intptr_t Class::ComputeEndTokenPos() const {
+TokenPosition Class::ComputeEndTokenPos() const {
   // Return the begin token for synthetic classes.
-  if (IsSignatureClass() || IsMixinApplication() || IsTopLevel()) {
+  if (IsMixinApplication() || IsTopLevel()) {
     return token_pos();
   }
   const Script& scr = Script::Handle(script());
   ASSERT(!scr.IsNull());
   const TokenStream& tkns = TokenStream::Handle(scr.tokens());
-  TokenStream::Iterator tkit(
-      tkns, token_pos(), TokenStream::Iterator::kNoNewlines);
+  TokenStream::Iterator tkit(tkns,
+                             token_pos(),
+                             TokenStream::Iterator::kNoNewlines);
   intptr_t level = 0;
   while (tkit.CurrentTokenKind() != Token::kEOS) {
     if (tkit.CurrentTokenKind() == Token::kLBRACE) {
@@ -3476,7 +3366,7 @@
     tkit.Advance();
   }
   UNREACHABLE();
-  return 0;
+  return TokenPosition::kNoSource;
 }
 
 
@@ -3617,6 +3507,11 @@
 }
 
 
+void Class::ClearDirectSubclasses() const {
+  StorePointer(&raw_ptr()->direct_subclasses_, GrowableObjectArray::null());
+}
+
+
 RawArray* Class::constants() const {
   return raw_ptr()->constants_;
 }
@@ -3639,7 +3534,7 @@
 
 
 RawType* Class::CanonicalType() const {
-  if (!IsGeneric()) {
+  if (!IsGeneric() && !IsClosureClass()) {
     return reinterpret_cast<RawType*>(raw_ptr()->canonical_types_);
   }
   Array& types = Array::Handle();
@@ -3653,7 +3548,7 @@
 
 void Class::SetCanonicalType(const Type& type) const {
   ASSERT(type.IsCanonical());
-  if (!IsGeneric()) {
+  if (!IsGeneric() && !IsClosureClass()) {
     ASSERT((canonical_types() == Object::null()) ||
            (canonical_types() == type.raw()));  // Set during own finalization.
     set_canonical_types(type);
@@ -3663,11 +3558,13 @@
     ASSERT(!types.IsNull() && (types.Length() > 1));
     ASSERT((types.At(0) == Object::null()) || (types.At(0) == type.raw()));
     types.SetAt(0, type);
+    // Makes sure that 'canonical_types' has not changed.
+    ASSERT(types.raw() == canonical_types());
   }
 }
 
 
-intptr_t Class::FindCanonicalTypeIndex(const Type& needle) const {
+intptr_t Class::FindCanonicalTypeIndex(const AbstractType& needle) const {
   Thread* thread = Thread::Current();
   if (EnsureIsFinalized(thread) != Error::null()) {
     return -1;
@@ -3697,8 +3594,8 @@
 }
 
 
-RawType* Class::CanonicalTypeFromIndex(intptr_t idx) const {
-  Type& type = Type::Handle();
+RawAbstractType* Class::CanonicalTypeFromIndex(intptr_t idx) const {
+  AbstractType& type = AbstractType::Handle();
   if (idx == 0) {
     type = CanonicalType();
     if (!type.IsNull()) {
@@ -3745,12 +3642,6 @@
 }
 
 
-bool Class::IsCanonicalSignatureClass() const {
-  const Function& function = Function::Handle(signature_function());
-  return (!function.IsNull() && (function.signature_class() == raw()));
-}
-
-
 // If test_kind == kIsSubtypeOf, checks if type S is a subtype of type T.
 // If test_kind == kIsMoreSpecificThan, checks if S is more specific than T.
 // Type S is specified by this class parameterized with 'type_arguments', and
@@ -3763,6 +3654,7 @@
                                  const Class& other,
                                  const TypeArguments& other_type_arguments,
                                  Error* bound_error,
+                                 TrailPtr bound_trail,
                                  Heap::Space space) {
   // Use the thsi object as if it was the receiver of this method, but instead
   // of recursing reset it to the super class and loop.
@@ -3821,47 +3713,23 @@
                                      from_index,
                                      num_type_params,
                                      bound_error,
+                                     bound_trail,
                                      space);
     }
-    const bool other_is_function_class = other.IsFunctionClass();
-    if (other.IsSignatureClass() || other_is_function_class) {
-      const Function& other_fun = Function::Handle(zone,
-                                                   other.signature_function());
-      if (thsi.IsSignatureClass()) {
-        if (other_is_function_class) {
-          return true;
-        }
-        // Check for two function types.
-        const Function& fun =
-            Function::Handle(zone, thsi.signature_function());
-        return fun.TypeTest(test_kind,
-                            type_arguments,
-                            other_fun,
-                            other_type_arguments,
-                            bound_error,
-                            space);
-      }
-      // Check if type S has a call() method of function type T.
-      Function& function =
-          Function::Handle(zone, thsi.LookupDynamicFunction(Symbols::Call()));
+    if (other.IsFunctionClass()) {
+      // Check if type S has a call() method.
+      Function& function = Function::Handle(zone,
+          thsi.LookupDynamicFunctionAllowAbstract(Symbols::Call()));
       if (function.IsNull()) {
         // Walk up the super_class chain.
         Class& cls = Class::Handle(zone, thsi.SuperClass());
         while (!cls.IsNull() && function.IsNull()) {
-          function = cls.LookupDynamicFunction(Symbols::Call());
+          function = cls.LookupDynamicFunctionAllowAbstract(Symbols::Call());
           cls = cls.SuperClass();
         }
       }
       if (!function.IsNull()) {
-        if (other_is_function_class ||
-            function.TypeTest(test_kind,
-                              type_arguments,
-                              other_fun,
-                              other_type_arguments,
-                              bound_error,
-                              space)) {
-              return true;
-            }
+        return true;
       }
     }
     // Check for 'direct super type' specified in the implements clause
@@ -3906,7 +3774,11 @@
         // The index of the type parameters is adjusted upon finalization.
         error = Error::null();
         interface_args =
-            interface_args.InstantiateFrom(type_arguments, &error, NULL, space);
+            interface_args.InstantiateFrom(type_arguments,
+                                           &error,
+                                           NULL,
+                                           bound_trail,
+                                           space);
         if (!error.IsNull()) {
           // Return the first bound error to the caller if it requests it.
           if ((bound_error != NULL) && bound_error->IsNull()) {
@@ -3920,6 +3792,7 @@
                                    other,
                                    other_type_arguments,
                                    bound_error,
+                                   bound_trail,
                                    space)) {
         return true;
       }
@@ -3946,6 +3819,7 @@
                      const Class& other,
                      const TypeArguments& other_type_arguments,
                      Error* bound_error,
+                     TrailPtr bound_trail,
                      Heap::Space space) const {
   return TypeTestNonRecursive(*this,
                               test_kind,
@@ -3953,6 +3827,7 @@
                               other,
                               other_type_arguments,
                               bound_error,
+                              bound_trail,
                               space);
 }
 
@@ -3972,6 +3847,12 @@
 }
 
 
+RawFunction* Class::LookupDynamicFunctionAllowAbstract(
+    const String& name) const {
+  return LookupFunction(name, kInstanceAllowAbstract);
+}
+
+
 RawFunction* Class::LookupDynamicFunctionAllowPrivate(
     const String& name) const {
   return LookupFunctionAllowPrivate(name, kInstance);
@@ -4044,8 +3925,8 @@
 
 
 RawFunction* Class::CheckFunctionType(const Function& func, MemberKind kind) {
-  if (kind == kInstance) {
-    if (func.IsDynamicFunction()) {
+  if ((kind == kInstance) || (kind == kInstanceAllowAbstract)) {
+    if (func.IsDynamicFunction(kind == kInstanceAllowAbstract)) {
       return func.raw();
     }
   } else if (kind == kStatic) {
@@ -4082,13 +3963,18 @@
   const intptr_t len = funcs.Length();
   Function& function = thread->FunctionHandle();
   if (len >= kFunctionLookupHashTreshold) {
-    ClassFunctionsSet set(raw_ptr()->functions_hash_table_);
-    REUSABLE_STRING_HANDLESCOPE(thread);
-    function ^= set.GetOrNull(FunctionName(name, &(thread->StringHandle())));
-    // No mutations.
-    ASSERT(set.Release().raw() == raw_ptr()->functions_hash_table_);
-    return function.IsNull() ? Function::null()
-                             : CheckFunctionType(function, kind);
+    // Cache functions hash table to allow multi threaded access.
+    const Array& hash_table = Array::Handle(thread->zone(),
+                                            raw_ptr()->functions_hash_table_);
+    if (!hash_table.IsNull()) {
+      ClassFunctionsSet set(hash_table.raw());
+      REUSABLE_STRING_HANDLESCOPE(thread);
+      function ^= set.GetOrNull(FunctionName(name, &(thread->StringHandle())));
+      // No mutations.
+      ASSERT(set.Release().raw() == hash_table.raw());
+      return function.IsNull() ? Function::null()
+                               : CheckFunctionType(function, kind);
+    }
   }
   if (name.IsSymbol()) {
     // Quick Symbol compare.
@@ -4243,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();
@@ -4253,100 +4217,6 @@
 }
 
 
-void Class::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Isolate* isolate = Isolate::Current();
-  JSONObject jsobj(stream);
-  if ((raw() == Class::null()) || (id() == kFreeListElement)) {
-    // TODO(turnidge): This is weird and needs to be changed.
-    jsobj.AddProperty("type", "null");
-    return;
-  }
-  AddCommonObjectProperties(&jsobj, "Class", ref);
-  jsobj.AddFixedServiceId("classes/%" Pd "", id());
-  const String& user_name = String::Handle(PrettyName());
-  const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  if (ref) {
-    return;
-  }
-
-  const Error& err = Error::Handle(EnsureIsFinalized(Thread::Current()));
-  if (!err.IsNull()) {
-    jsobj.AddProperty("error", err);
-  }
-  jsobj.AddProperty("abstract", is_abstract());
-  jsobj.AddProperty("const", is_const());
-  jsobj.AddProperty("_finalized", is_finalized());
-  jsobj.AddProperty("_implemented", is_implemented());
-  jsobj.AddProperty("_patch", is_patch());
-  jsobj.AddProperty("_traceAllocations", TraceAllocation(isolate));
-  const Class& superClass = Class::Handle(SuperClass());
-  if (!superClass.IsNull()) {
-    jsobj.AddProperty("super", superClass);
-  }
-  jsobj.AddProperty("library", Object::Handle(library()));
-  const Script& script = Script::Handle(this->script());
-  if (!script.IsNull()) {
-    jsobj.AddLocation(script, token_pos(), ComputeEndTokenPos());
-  }
-  {
-    JSONArray interfaces_array(&jsobj, "interfaces");
-    const Array& interface_array = Array::Handle(interfaces());
-    Type& interface_type = Type::Handle();
-    if (!interface_array.IsNull()) {
-      for (intptr_t i = 0; i < interface_array.Length(); ++i) {
-        interface_type ^= interface_array.At(i);
-        interfaces_array.AddValue(interface_type);
-      }
-    }
-  }
-  {
-    JSONArray fields_array(&jsobj, "fields");
-    const Array& field_array = Array::Handle(fields());
-    Field& field = Field::Handle();
-    if (!field_array.IsNull()) {
-      for (intptr_t i = 0; i < field_array.Length(); ++i) {
-        field ^= field_array.At(i);
-        fields_array.AddValue(field);
-      }
-    }
-  }
-  {
-    JSONArray functions_array(&jsobj, "functions");
-    const Array& function_array = Array::Handle(functions());
-    Function& function = Function::Handle();
-    if (!function_array.IsNull()) {
-      for (intptr_t i = 0; i < function_array.Length(); i++) {
-        function ^= function_array.At(i);
-        functions_array.AddValue(function);
-      }
-    }
-  }
-  {
-    JSONArray subclasses_array(&jsobj, "subclasses");
-    const GrowableObjectArray& subclasses =
-        GrowableObjectArray::Handle(direct_subclasses());
-    if (!subclasses.IsNull()) {
-      Class& subclass = Class::Handle();
-      for (intptr_t i = 0; i < subclasses.Length(); ++i) {
-        // TODO(turnidge): Use the Type directly once regis has added
-        // types to the vmservice.
-        subclass ^= subclasses.At(i);
-        subclasses_array.AddValue(subclass);
-      }
-    }
-  }
-  {
-    ClassTable* class_table = Isolate::Current()->class_table();
-    const ClassHeapStats* stats = class_table->StatsWithUpdatedSize(id());
-    if (stats != NULL) {
-      JSONObject allocation_stats(&jsobj, "_allocationStats");
-      stats->PrintToJSONObject(*this, &allocation_stats);
-    }
-  }
-}
-
-
 void Class::InsertCanonicalConstant(intptr_t index,
                                     const Instance& constant) const {
   // The constant needs to be added to the list. Grow the list if it is full.
@@ -4366,7 +4236,7 @@
 
 RawUnresolvedClass* UnresolvedClass::New(const LibraryPrefix& library_prefix,
                                          const String& ident,
-                                         intptr_t token_pos) {
+                                         TokenPosition token_pos) {
   const UnresolvedClass& type = UnresolvedClass::Handle(UnresolvedClass::New());
   type.set_library_prefix(library_prefix);
   type.set_ident(ident);
@@ -4384,8 +4254,8 @@
 }
 
 
-void UnresolvedClass::set_token_pos(intptr_t token_pos) const {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+void UnresolvedClass::set_token_pos(TokenPosition token_pos) const {
+  ASSERT(!token_pos.IsClassifying());
   StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
 }
 
@@ -4425,11 +4295,6 @@
 }
 
 
-void UnresolvedClass::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 static uint32_t CombineHashes(uint32_t hash, uint32_t other_hash) {
   hash += other_hash;
   hash += hash << 10;
@@ -4561,6 +4426,7 @@
                              intptr_t from_index,
                              intptr_t len,
                              Error* bound_error,
+                             TrailPtr bound_trail,
                              Heap::Space space) const {
   ASSERT(Length() >= (from_index + len));
   ASSERT(!other.IsNull());
@@ -4572,7 +4438,11 @@
     ASSERT(!type.IsNull());
     other_type = other.TypeAt(from_index + i);
     ASSERT(!other_type.IsNull());
-    if (!type.TypeTest(test_kind, other_type, bound_error, space)) {
+    if (!type.TypeTest(test_kind,
+                       other_type,
+                       bound_error,
+                       bound_trail,
+                       space)) {
       return false;
     }
   }
@@ -4580,52 +4450,6 @@
 }
 
 
-void TypeArguments::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  // The index in the canonical_type_arguments table cannot be used as part of
-  // the object id (as in typearguments/id), because the indices are not
-  // preserved when the table grows and the entries get rehashed. Use the ring.
-  Isolate* isolate = Isolate::Current();
-  ObjectStore* object_store = isolate->object_store();
-  const Array& table = Array::Handle(object_store->canonical_type_arguments());
-  ASSERT(table.Length() > 0);
-  AddCommonObjectProperties(&jsobj, "TypeArguments", ref);
-  jsobj.AddServiceId(*this);
-  const String& user_name = String::Handle(PrettyName());
-  const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  if (ref) {
-    return;
-  }
-  {
-    JSONArray jsarr(&jsobj, "types");
-    AbstractType& type_arg = AbstractType::Handle();
-    for (intptr_t i = 0; i < Length(); i++) {
-      type_arg = TypeAt(i);
-      jsarr.AddValue(type_arg);
-    }
-  }
-  if (!IsInstantiated()) {
-    JSONArray jsarr(&jsobj, "_instantiations");
-    Array& prior_instantiations = Array::Handle(instantiations());
-    ASSERT(prior_instantiations.Length() > 0);  // Always at least a sentinel.
-    TypeArguments& type_args = TypeArguments::Handle();
-    intptr_t i = 0;
-    while (true) {
-      if (prior_instantiations.At(i) == Smi::New(StubCode::kNoInstantiator)) {
-        break;
-      }
-      JSONObject instantiation(&jsarr);
-      type_args ^= prior_instantiations.At(i);
-      instantiation.AddProperty("instantiator", type_args, true);
-      type_args ^= prior_instantiations.At(i + 1);
-      instantiation.AddProperty("instantiated", type_args, true);
-      i += 2;
-    }
-  }
-}
-
-
 bool TypeArguments::HasInstantiations() const {
   const Array& prior_instantiations = Array::Handle(instantiations());
   ASSERT(prior_instantiations.Length() > 0);  // Always at least a sentinel.
@@ -4668,6 +4492,7 @@
 
 void TypeArguments::SetTypeAt(intptr_t index,
                                 const AbstractType& value) const {
+  ASSERT(!IsCanonical());
   StorePointer(TypeAddr(index), value.raw());
 }
 
@@ -4845,7 +4670,8 @@
 RawTypeArguments* TypeArguments::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail,
+    TrailPtr instantiation_trail,
+    TrailPtr bound_trail,
     Heap::Space space) const {
   ASSERT(!IsInstantiated());
   if (!instantiator_type_arguments.IsNull() &&
@@ -4868,7 +4694,8 @@
     if (!type.IsNull() && !type.IsInstantiated()) {
       type = type.InstantiateFrom(instantiator_type_arguments,
                                   bound_error,
-                                  trail,
+                                  instantiation_trail,
+                                  bound_trail,
                                   space);
     }
     instantiated_array.SetTypeAt(i, type);
@@ -4901,7 +4728,8 @@
   }
   // Cache lookup failed. Instantiate the type arguments.
   TypeArguments& result = TypeArguments::Handle();
-  result = InstantiateFrom(instantiator_type_arguments, bound_error);
+  result = InstantiateFrom(
+      instantiator_type_arguments, bound_error, NULL, NULL, Heap::kOld);
   if ((bound_error != NULL) && !bound_error->IsNull()) {
     return result.raw();
   }
@@ -5132,6 +4960,11 @@
     for (intptr_t i = 0; i < num_types; i++) {
       type_arg = TypeAt(i);
       type_arg = type_arg.Canonicalize(trail);
+      if (IsCanonical()) {
+        // Canonicalizing this type_arg canonicalized this type.
+        ASSERT(IsRecursive());
+        return this->raw();
+      }
       SetTypeAt(i, type_arg);
     }
     // Canonicalization of a recursive type may change its hash.
@@ -5168,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";
@@ -5192,11 +5041,6 @@
 }
 
 
-void PatchClass::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 RawPatchClass* PatchClass::New(const Class& patched_class,
                                const Class& origin_class) {
   const PatchClass& result = PatchClass::Handle(PatchClass::New());
@@ -5242,6 +5086,9 @@
 
 
 bool Function::HasBreakpoint() const {
+  if (!FLAG_support_debugger) {
+    return false;
+  }
   Thread* thread = Thread::Current();
   return thread->isolate()->debugger()->HasBreakpoint(*this, thread->zone());
 }
@@ -5249,7 +5096,7 @@
 
 void Function::InstallOptimizedCode(const Code& code, bool is_osr) const {
   DEBUG_ASSERT(IsMutatorOrAtSafepoint());
-  // We may not have previous code if 'always_optimize' is set.
+  // We may not have previous code if FLAG_precompile is set.
   if (!is_osr && HasCode()) {
     Code::Handle(CurrentCode()).DisableDartCode();
   }
@@ -5378,7 +5225,7 @@
 
 
 void Function::set_eval_script(const Script& script) const {
-  ASSERT(token_pos() == 0);
+  ASSERT(token_pos() == TokenPosition::kMinSource);
   ASSERT(raw_ptr()->data_ == Object::null());
   set_data(script);
 }
@@ -5493,33 +5340,67 @@
 }
 
 
-RawClass* Function::signature_class() const {
+RawFunctionType* Function::SignatureType() const {
+  FunctionType& type = FunctionType::Handle();
+  const Object& obj = Object::Handle(raw_ptr()->data_);
   if (IsSignatureFunction()) {
-    const Object& obj = Object::Handle(raw_ptr()->data_);
-    ASSERT(obj.IsNull() || obj.IsClass());
-    return (obj.IsNull()) ? Class::null() : Class::Cast(obj).raw();
-  }
-  if (IsClosureFunction()) {
-    const Object& obj = Object::Handle(raw_ptr()->data_);
+    ASSERT(obj.IsNull() || obj.IsFunctionType());
+    type = obj.IsNull() ? FunctionType::null() : FunctionType::Cast(obj).raw();
+  } else {
+    ASSERT(IsClosureFunction());
     ASSERT(!obj.IsNull());
-    return ClosureData::Cast(obj).signature_class();
+    type = ClosureData::Cast(obj).signature_type();
   }
-  return Class::null();
+  if (type.IsNull()) {
+    // A function type is parameterized in the same way as the owner class of
+    // its non-static signature function.
+    // It is not type parameterized if its signature function is static.
+    // During type finalization, the type arguments of the super class of the
+    // owner class of its signature function will be prepended to the type
+    // argument vector. Therefore, we only need to set the type arguments
+    // matching the type parameters here.
+    // In case of a function type alias, the function owner is the alias class,
+    // i.e. the typedef. The signature type is therefore parameterized according
+    // to the alias class declaration, even if the function type is not generic.
+    // Otherwise, if the function is static or if its signature type is
+    // non-generic, i.e. it does not depend on any type parameter of the owner
+    // class, then the signature type is not parameterized, although the owner
+    // class may be. In this case, the scope class of the function type is reset
+    // to _Closure class as well as the owner of the signature function.
+    Class& scope_class = Class::Handle(Owner());
+    if (!scope_class.IsTypedefClass() &&
+        (is_static() ||
+         !scope_class.IsGeneric() ||
+         HasInstantiatedSignature())) {
+      scope_class = Isolate::Current()->object_store()->closure_class();
+      if (IsSignatureFunction()) {
+        set_owner(scope_class);
+        set_token_pos(TokenPosition::kNoSource);
+      }
+    }
+    const TypeArguments& signature_type_arguments =
+        TypeArguments::Handle(scope_class.type_parameters());
+    // Return the still unfinalized signature type.
+    type = FunctionType::New(scope_class,
+                             signature_type_arguments,
+                             *this,
+                             token_pos());
+
+    SetSignatureType(type);
+  }
+  return type.raw();
 }
 
 
-void Function::set_signature_class(const Class& value) const {
+void Function::SetSignatureType(const FunctionType& value) const {
   if (IsSignatureFunction()) {
     set_data(value);
-    return;
-  }
-  if (IsClosureFunction()) {
+  } else {
+    ASSERT(IsClosureFunction());
     const Object& obj = Object::Handle(raw_ptr()->data_);
     ASSERT(!obj.IsNull());
-    ClosureData::Cast(obj).set_signature_class(value);
-    return;
+    ClosureData::Cast(obj).set_signature_type(value);
   }
-  UNREACHABLE();
 }
 
 
@@ -5640,7 +5521,7 @@
 
 // This field is heavily overloaded:
 //   eval function:           Script expression source
-//   signature function:      Class signature class
+//   signature function:      Function type
 //   method extractor:        Function extracted closure function
 //   noSuchMethod dispatcher: Array arguments descriptor
 //   invoke-field dispatcher: Array arguments descriptor
@@ -5786,8 +5667,8 @@
 }
 
 
-void Function::set_token_pos(intptr_t token_pos) const {
-  ASSERT(token_pos >= 0);
+void Function::set_token_pos(TokenPosition token_pos) const {
+  ASSERT(!token_pos.IsClassifying() || IsMethodExtractor());
   StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
 }
 
@@ -5831,8 +5712,9 @@
     // Native methods don't need to be optimized.
     return false;
   }
+  const intptr_t function_length = end_token_pos().Pos() - token_pos().Pos();
   if (is_optimizable() && (script() != Script::null()) &&
-      ((end_token_pos() - token_pos()) < FLAG_huge_method_cutoff_in_tokens)) {
+      (function_length < FLAG_huge_method_cutoff_in_tokens)) {
     // Additional check needed for implicit getters.
     return (unoptimized_code() == Object::null()) ||
         (Code::Handle(unoptimized_code()).Size() <
@@ -5867,7 +5749,8 @@
   Thread* thread = Thread::Current();
   return is_inlinable() &&
          !is_generated_body() &&
-         !thread->isolate()->debugger()->HasBreakpoint(*this, thread->zone());
+         (!FLAG_support_debugger ||
+          !thread->isolate()->debugger()->HasBreakpoint(*this, thread->zone()));
 }
 
 
@@ -6156,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.
@@ -6169,6 +6052,7 @@
         *bound_error,  // A bound error if non null.
         Script::Handle(other.script()),
         other.token_pos(),
+        Report::AtLocation,
         Report::kError,
         Heap::kNew,
         "signature type '%s' of function '%s' is not a subtype of signature "
@@ -6209,10 +6093,12 @@
   AbstractType& other_param_type =
       AbstractType::Handle(other.ParameterTypeAt(other_parameter_position));
   if (!other_param_type.IsInstantiated()) {
-    other_param_type = other_param_type.InstantiateFrom(other_type_arguments,
-                                                        bound_error,
-                                                        NULL,  // trail
-                                                        space);
+    other_param_type =
+        other_param_type.InstantiateFrom(other_type_arguments,
+                                         bound_error,
+                                         NULL,  // instantiation_trail
+                                         NULL,  // bound_trail
+                                         space);
     ASSERT((bound_error == NULL) || bound_error->IsNull());
   }
   if (other_param_type.IsDynamicType()) {
@@ -6221,21 +6107,25 @@
   AbstractType& param_type =
       AbstractType::Handle(ParameterTypeAt(parameter_position));
   if (!param_type.IsInstantiated()) {
-    param_type = param_type.InstantiateFrom(
-        type_arguments, bound_error, NULL /*trail*/, space);
+    param_type = param_type.InstantiateFrom(type_arguments,
+                                            bound_error,
+                                            NULL,  // instantiation_trail
+                                            NULL,  // bound_trail
+                                            space);
     ASSERT((bound_error == NULL) || bound_error->IsNull());
   }
   if (param_type.IsDynamicType()) {
     return test_kind == kIsSubtypeOf;
   }
   if (test_kind == kIsSubtypeOf) {
-    if (!param_type.IsSubtypeOf(other_param_type, bound_error, space) &&
-        !other_param_type.IsSubtypeOf(param_type, bound_error, space)) {
+    if (!param_type.IsSubtypeOf(other_param_type, bound_error, NULL, space) &&
+        !other_param_type.IsSubtypeOf(param_type, bound_error, NULL, space)) {
       return false;
     }
   } else {
     ASSERT(test_kind == kIsMoreSpecificThan);
-    if (!param_type.IsMoreSpecificThan(other_param_type, bound_error, space)) {
+    if (!param_type.IsMoreSpecificThan(
+            other_param_type, bound_error, NULL, space)) {
       return false;
     }
   }
@@ -6273,26 +6163,29 @@
   AbstractType& other_res_type = AbstractType::Handle(other.result_type());
   if (!other_res_type.IsInstantiated()) {
     other_res_type = other_res_type.InstantiateFrom(other_type_arguments,
-                                                    bound_error);
+                                                    bound_error,
+                                                    NULL, NULL, space);
     ASSERT((bound_error == NULL) || bound_error->IsNull());
   }
   if (!other_res_type.IsDynamicType() && !other_res_type.IsVoidType()) {
     AbstractType& res_type = AbstractType::Handle(result_type());
     if (!res_type.IsInstantiated()) {
-      res_type = res_type.InstantiateFrom(type_arguments, bound_error);
+      res_type = res_type.InstantiateFrom(type_arguments, bound_error,
+                                          NULL, NULL, space);
       ASSERT((bound_error == NULL) || bound_error->IsNull());
     }
     if (res_type.IsVoidType()) {
       return false;
     }
     if (test_kind == kIsSubtypeOf) {
-      if (!res_type.IsSubtypeOf(other_res_type, bound_error) &&
-          !other_res_type.IsSubtypeOf(res_type, bound_error)) {
+      if (!res_type.IsSubtypeOf(other_res_type, bound_error, NULL, space) &&
+          !other_res_type.IsSubtypeOf(res_type, bound_error, NULL, space)) {
         return false;
       }
     } else {
       ASSERT(test_kind == kIsMoreSpecificThan);
-      if (!res_type.IsMoreSpecificThan(other_res_type, bound_error)) {
+      if (!res_type.IsMoreSpecificThan(other_res_type, bound_error,
+                                       NULL, space)) {
         return false;
       }
     }
@@ -6405,7 +6298,7 @@
                            bool is_external,
                            bool is_native,
                            const Object& owner,
-                           intptr_t token_pos) {
+                           TokenPosition token_pos) {
   ASSERT(!owner.IsNull());
   const Function& result = Function::Handle(Function::New());
   result.set_parameter_types(Object::empty_array());
@@ -6485,7 +6378,7 @@
 
 RawFunction* Function::NewClosureFunction(const String& name,
                                           const Function& parent,
-                                          intptr_t token_pos) {
+                                          TokenPosition token_pos) {
   ASSERT(!parent.IsNull());
   // Use the owner defining the parent function and not the class containing it.
   const Object& parent_owner = Object::Handle(parent.raw_ptr()->owner_);
@@ -6505,6 +6398,25 @@
 }
 
 
+RawFunction* Function::NewSignatureFunction(const Class& owner,
+                                            TokenPosition token_pos) {
+  const Function& result = Function::Handle(Function::New(
+      Symbols::AnonymousSignature(),
+      RawFunction::kSignatureFunction,
+      /* is_static = */ false,
+      /* is_const = */ false,
+      /* is_abstract = */ false,
+      /* is_external = */ false,
+      /* is_native = */ false,
+      owner,  // Same as function type scope class.
+      token_pos));
+  result.set_is_reflectable(false);
+  result.set_is_visible(false);
+  result.set_is_debuggable(false);
+  return result.raw();
+}
+
+
 RawFunction* Function::NewEvalFunction(const Class& owner,
                                        const Script& script,
                                        bool is_static) {
@@ -6517,7 +6429,7 @@
                     /* is_external = */ false,
                     /* is_native = */ false,
                     owner,
-                    /* token_pos = */ 0));
+                    TokenPosition::kMinSource));
   ASSERT(!script.IsNull());
   result.set_is_debuggable(false);
   result.set_is_visible(true);
@@ -6583,35 +6495,12 @@
     param_name = ParameterNameAt(has_receiver - kClosure + i);
     closure_function.SetParameterNameAt(i, param_name);
   }
-
-  // Lookup or create a new signature class for the closure function in the
-  // library of the owner class.
-  const Class& owner_class = Class::Handle(Owner());
-  ASSERT(!owner_class.IsNull() && (Owner() == closure_function.Owner()));
-  const Library& library = Library::Handle(owner_class.library());
-  ASSERT(!library.IsNull());
-  const String& signature = String::Handle(closure_function.Signature());
-  Class& signature_class = Class::ZoneHandle(
-      library.LookupLocalClass(signature));
-  if (signature_class.IsNull()) {
-    const Script& script = Script::Handle(this->script());
-    signature_class = Class::NewSignatureClass(signature,
-                                               closure_function,
-                                               script,
-                                               closure_function.token_pos());
-    library.AddClass(signature_class);
-  } else {
-    closure_function.set_signature_class(signature_class);
-  }
-  // Finalize types in signature class here, so that the
-  // signature type is not computed twice.
-  ClassFinalizer::FinalizeTypesInClass(signature_class);
-  const Type& signature_type = Type::Handle(signature_class.SignatureType());
+  const FunctionType& signature_type =
+      FunctionType::Handle(closure_function.SignatureType());
   if (!signature_type.IsFinalized()) {
     ClassFinalizer::FinalizeType(
-        signature_class, signature_type, ClassFinalizer::kCanonicalize);
+        Class::Handle(Owner()), signature_type, ClassFinalizer::kCanonicalize);
   }
-  ASSERT(closure_function.signature_class() == signature_class.raw());
   set_implicit_closure_function(closure_function);
   ASSERT(closure_function.IsImplicitClosureFunction());
   return closure_function.raw();
@@ -6662,8 +6551,11 @@
   while (i < num_fixed_params) {
     param_type = ParameterTypeAt(i);
     ASSERT(!param_type.IsNull());
-    if (instantiate && !param_type.IsInstantiated()) {
-      param_type = param_type.InstantiateFrom(instantiator, NULL);
+    if (instantiate &&
+        param_type.IsFinalized() &&
+        !param_type.IsInstantiated()) {
+      param_type = param_type.InstantiateFrom(instantiator, NULL,
+                                              NULL, NULL, Heap::kNew);
     }
     name = param_type.BuildName(name_visibility);
     pieces->Add(name);
@@ -6687,8 +6579,11 @@
         pieces->Add(Symbols::ColonSpace());
       }
       param_type = ParameterTypeAt(i);
-      if (instantiate && !param_type.IsInstantiated()) {
-        param_type = param_type.InstantiateFrom(instantiator, NULL);
+      if (instantiate &&
+          param_type.IsFinalized() &&
+          !param_type.IsInstantiated()) {
+        param_type = param_type.InstantiateFrom(instantiator, NULL,
+                                                NULL, NULL, Heap::kNew);
       }
       ASSERT(!param_type.IsNull());
       name = param_type.BuildName(name_visibility);
@@ -6716,9 +6611,6 @@
         Context::Handle(zone, object_store->empty_context());
     Instance& closure =
         Instance::Handle(zone, Closure::New(*this, context, Heap::kOld));
-    const char* error_str = NULL;
-    closure ^= closure.CheckAndCanonicalize(&error_str);
-    ASSERT(!closure.IsNull());
     set_implicit_static_closure(closure);
   }
   return implicit_static_closure();
@@ -6727,11 +6619,12 @@
 
 RawInstance* Function::ImplicitInstanceClosure(const Instance& receiver) const {
   ASSERT(IsImplicitClosureFunction());
-  const Class& cls = Class::Handle(signature_class());
+  const FunctionType& signature_type = FunctionType::Handle(SignatureType());
+  const Class& cls = Class::Handle(signature_type.type_class());
   const Context& context = Context::Handle(Context::New(1));
   context.SetAt(0, receiver);
   const Instance& result = Instance::Handle(Closure::New(*this, context));
-  if (cls.NumTypeArguments() > 0) {
+  if (cls.IsGeneric()) {
     const TypeArguments& type_arguments =
         TypeArguments::Handle(receiver.GetTypeArguments());
     result.SetTypeArguments(type_arguments);
@@ -6748,18 +6641,17 @@
   GrowableHandlePtrArray<const String> pieces(zone, 4);
   String& name = String::Handle(zone);
   if (!instantiate && !is_static() && (name_visibility == kInternalName)) {
-    // Prefix the signature with its signature class and type parameters, if any
+    // Prefix the signature with its scope class and type parameters, if any
     // (e.g. "Map<K, V>(K) => bool"). In case of a function type alias, the
-    // signature class name is the alias name.
+    // scope class name is the alias name.
     // The signature of static functions cannot be type parameterized.
-    const Class& function_class = Class::Handle(zone, Owner());
-    ASSERT(!function_class.IsNull());
-    const TypeArguments& type_parameters = TypeArguments::Handle(
-        zone, function_class.type_parameters());
-    if (!type_parameters.IsNull()) {
-      const String& function_class_name =
-          String::Handle(zone, function_class.Name());
-      pieces.Add(function_class_name);
+    const Class& scope_class = Class::Handle(zone, Owner());
+    ASSERT(!scope_class.IsNull());
+    if (scope_class.IsGeneric()) {
+      const TypeArguments& type_parameters = TypeArguments::Handle(
+          zone, scope_class.type_parameters());
+      const String& scope_class_name = String::Handle(zone, scope_class.Name());
+      pieces.Add(scope_class_name);
       const intptr_t num_type_parameters = type_parameters.Length();
       pieces.Add(Symbols::LAngleBracket());
       TypeParameter& type_parameter = TypeParameter::Handle(zone);
@@ -6788,8 +6680,9 @@
                            &pieces);
   pieces.Add(Symbols::RParenArrow());
   AbstractType& res_type = AbstractType::Handle(zone, result_type());
-  if (instantiate && !res_type.IsInstantiated()) {
-    res_type = res_type.InstantiateFrom(instantiator, NULL);
+  if (instantiate && res_type.IsFinalized() && !res_type.IsInstantiated()) {
+    res_type = res_type.InstantiateFrom(instantiator, NULL,
+                                        NULL, NULL, Heap::kNew);
   }
   name = res_type.BuildName(name_visibility);
   pieces.Add(name);
@@ -6834,7 +6727,7 @@
 
 
 RawScript* Function::script() const {
-  if (token_pos() == 0) {
+  if (token_pos() == TokenPosition::kMinSource) {
     // Testing for position 0 is an optimization that relies on temporary
     // eval functions having token position 0.
     const Script& script = Script::Handle(eval_script());
@@ -6859,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();
 }
 
 
@@ -6937,7 +6798,7 @@
   if (!func_script.HasSource()) {
     // When source is not available, avoid printing the whole token stream and
     // doing expensive position calculations.
-    return stream.GenerateSource(token_pos(), end_token_pos() + 1);
+    return stream.GenerateSource(token_pos(), end_token_pos().Next());
   }
 
   const TokenStream::Iterator tkit(stream, end_token_pos());
@@ -6970,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();
@@ -7021,11 +6880,15 @@
 
 void Function::RestoreICDataMap(
     ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data,
-    bool clone_descriptors) const {
+    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());
   if (saved_ic_data.IsNull()) {
+    // Could happen with deferred loading.
     return;
   }
   const intptr_t saved_length = saved_ic_data.Length();
@@ -7040,9 +6903,9 @@
     for (intptr_t i = 1; i < saved_length; i++) {
       ICData& ic_data = ICData::ZoneHandle(zone);
       ic_data ^= saved_ic_data.At(i);
-      if (clone_descriptors) {
-        ICData& original_ic_data = ICData::Handle(zone, ic_data.raw());
-        ic_data = ICData::CloneDescriptor(ic_data);
+      if (clone_ic_data) {
+        const ICData& original_ic_data = ICData::Handle(zone, ic_data.raw());
+        ic_data = ICData::Clone(ic_data);
         ic_data.SetOriginal(original_ic_data);
       }
       (*deopt_id_to_ic_data)[ic_data.deopt_id()] = &ic_data;
@@ -7151,109 +7014,6 @@
 }
 
 
-static void AddFunctionServiceId(const JSONObject& jsobj,
-                                 const Function& f,
-                                 const Class& cls) {
-  // Special kinds of functions use indices in their respective lists.
-  intptr_t id = -1;
-  const char* selector = NULL;
-  if (f.IsNonImplicitClosureFunction()) {
-    id = Isolate::Current()->FindClosureIndex(f);
-    selector = "closures";
-  } else if (f.IsImplicitClosureFunction()) {
-    id = cls.FindImplicitClosureFunctionIndex(f);
-    selector = "implicit_closures";
-  } else if (f.IsNoSuchMethodDispatcher() || f.IsInvokeFieldDispatcher()) {
-    id = cls.FindInvocationDispatcherFunctionIndex(f);
-    selector = "dispatchers";
-  }
-  if (id != -1) {
-    ASSERT(selector != NULL);
-    jsobj.AddFixedServiceId("classes/%" Pd "/%s/%" Pd "",
-                            cls.id(), selector, id);
-    return;
-  }
-  // Regular functions known to their owner use their name (percent-encoded).
-  String& name = String::Handle(f.name());
-  if (cls.LookupFunction(name) == f.raw()) {
-    name = String::EncodeIRI(name);
-    jsobj.AddFixedServiceId("classes/%" Pd "/functions/%s",
-                            cls.id(), name.ToCString());
-    return;
-  }
-  // Oddball functions (not known to their owner) fall back to use the object
-  // id ring. Current known examples are signature functions of closures
-  // and stubs like 'megamorphic_miss'.
-  jsobj.AddServiceId(f);
-}
-
-
-void Function::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Class& cls = Class::Handle(Owner());
-  ASSERT(!cls.IsNull());
-  Error& err = Error::Handle();
-  err ^= cls.EnsureIsFinalized(Thread::Current());
-  ASSERT(err.IsNull());
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Function", ref);
-  AddFunctionServiceId(jsobj, *this, cls);
-  const String& user_name = String::Handle(PrettyName());
-  const String& vm_name = String::Handle(name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  const Function& parent = Function::Handle(parent_function());
-  if (!parent.IsNull()) {
-    jsobj.AddProperty("owner", parent);
-  } else if (cls.IsTopLevel()) {
-    const Library& library = Library::Handle(cls.library());
-    jsobj.AddProperty("owner", library);
-  } else {
-    jsobj.AddProperty("owner", cls);
-  }
-
-  const char* kind_string = Function::KindToCString(kind());
-  jsobj.AddProperty("_kind", kind_string);
-  jsobj.AddProperty("static", is_static());
-  jsobj.AddProperty("const", is_const());
-  jsobj.AddProperty("_intrinsic", is_intrinsic());
-  jsobj.AddProperty("_native", is_native());
-  if (ref) {
-    return;
-  }
-  Code& code = Code::Handle(CurrentCode());
-  if (!code.IsNull()) {
-    jsobj.AddProperty("code", code);
-  }
-  Array& ics = Array::Handle(ic_data_array());
-  if (!ics.IsNull()) {
-    jsobj.AddProperty("_icDataArray", ics);
-  }
-  jsobj.AddProperty("_optimizable", is_optimizable());
-  jsobj.AddProperty("_inlinable", is_inlinable());
-  jsobj.AddProperty("_recognized", IsRecognized());
-  code = unoptimized_code();
-  if (!code.IsNull()) {
-    jsobj.AddProperty("_unoptimizedCode", code);
-  }
-  jsobj.AddProperty("_usageCounter", usage_counter());
-  jsobj.AddProperty("_optimizedCallSiteCount", optimized_call_site_count());
-  jsobj.AddProperty("_deoptimizations",
-                    static_cast<intptr_t>(deoptimization_counter()));
-  if ((kind() == RawFunction::kImplicitGetter) ||
-      (kind() == RawFunction::kImplicitSetter) ||
-      (kind() == RawFunction::kImplicitStaticFinalGetter)) {
-    const Field& field = Field::Handle(LookupImplicitGetterSetterField());
-    if (!field.IsNull()) {
-      jsobj.AddProperty("_field", field);
-    }
-  }
-
-  const Script& script = Script::Handle(this->script());
-  if (!script.IsNull()) {
-    jsobj.AddLocation(script, token_pos(), end_token_pos());
-  }
-}
-
-
 void ClosureData::set_context_scope(const ContextScope& value) const {
   StorePointer(&raw_ptr()->context_scope_, value.raw());
 }
@@ -7271,8 +7031,8 @@
 }
 
 
-void ClosureData::set_signature_class(const Class& value) const {
-  StorePointer(&raw_ptr()->signature_class_, value.raw());
+void ClosureData::set_signature_type(const FunctionType& value) const {
+  StorePointer(&raw_ptr()->signature_type_, value.raw());
 }
 
 
@@ -7290,11 +7050,6 @@
 }
 
 
-void ClosureData::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 void RedirectionData::set_type(const Type& value) const {
   ASSERT(!value.IsNull());
   StorePointer(&raw_ptr()->type_, value.raw());
@@ -7325,8 +7080,28 @@
 }
 
 
-void RedirectionData::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
+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()));
 }
 
 
@@ -7384,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();
   }
@@ -7398,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();
   }
@@ -7408,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();
   }
@@ -7421,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());
@@ -7444,7 +7239,7 @@
                      bool is_reflectable,
                      const Class& owner,
                      const AbstractType& type,
-                     intptr_t token_pos) {
+                     TokenPosition token_pos) {
   ASSERT(!owner.IsNull());
   const Field& result = Field::Handle(Field::New());
   result.set_name(name);
@@ -7478,7 +7273,7 @@
                              bool is_final,
                              bool is_const,
                              const Object& owner,
-                             intptr_t token_pos) {
+                             TokenPosition token_pos) {
   ASSERT(!owner.IsNull());
   const Field& result = Field::Handle(Field::New());
   result.set_name(name);
@@ -7507,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);
@@ -7524,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()));
 }
 
 
@@ -7542,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));
 }
 
@@ -7554,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);
@@ -7568,77 +7374,19 @@
   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);
 }
 
 
-void Field::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  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& vm_name = String::Handle(name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  if (cls.IsTopLevel()) {
-    const Library& library = Library::Handle(cls.library());
-    jsobj.AddProperty("owner", library);
-  } else {
-    jsobj.AddProperty("owner", cls);
-  }
-
-  AbstractType& declared_type = AbstractType::Handle(type());
-  jsobj.AddProperty("declaredType", declared_type);
-  jsobj.AddProperty("static", is_static());
-  jsobj.AddProperty("final", is_final());
-  jsobj.AddProperty("const", is_const());
-  if (ref) {
-    return;
-  }
-  if (is_static()) {
-    const Instance& valueObj = Instance::Handle(StaticValue());
-    jsobj.AddProperty("staticValue", valueObj);
-  }
-
-  jsobj.AddProperty("_guardNullable", is_nullable());
-  if (guarded_cid() == kIllegalCid) {
-    jsobj.AddProperty("_guardClass", "unknown");
-  } else if (guarded_cid() == kDynamicCid) {
-    jsobj.AddProperty("_guardClass", "dynamic");
-  } else {
-    ClassTable* table = Isolate::Current()->class_table();
-    ASSERT(table->IsValidIndex(guarded_cid()));
-    cls ^= table->At(guarded_cid());
-    jsobj.AddProperty("_guardClass", cls);
-  }
-  if (guarded_list_length() == kUnknownFixedLength) {
-    jsobj.AddProperty("_guardLength", "unknown");
-  } else if (guarded_list_length() == kNoFixedLength) {
-    jsobj.AddProperty("_guardLength", "variable");
-  } else {
-    jsobj.AddProperty("_guardLength", guarded_list_length());
-  }
-  const Class& origin_cls = Class::Handle(origin());
-  const Script& script = Script::Handle(origin_cls.script());
-  if (!script.IsNull()) {
-    jsobj.AddLocation(script, token_pos());
-  }
-}
-
-
 // Build a closure object that gets (or sets) the contents of a static
 // field f and cache the closure in a newly created static field
 // 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);
@@ -7708,6 +7456,7 @@
 
 
 void Field::set_dependent_code(const Array& array) const {
+  ASSERT(IsOriginal());
   StorePointer(&raw_ptr()->dependent_code_, array.raw());
 }
 
@@ -7751,6 +7500,7 @@
 
 
 void Field::RegisterDependentCode(const Code& code) const {
+  ASSERT(IsOriginal());
   DEBUG_ASSERT(IsMutatorOrAtSafepoint());
   ASSERT(code.is_optimized());
   FieldDependentArray a(*this);
@@ -7759,6 +7509,7 @@
 
 
 void Field::DeoptimizeDependentCode() const {
+  ASSERT(IsOriginal());
   ASSERT(Thread::Current()->IsMutatorThread());
   FieldDependentArray a(*this);
   a.DisableCode();
@@ -7773,6 +7524,7 @@
 
 
 void Field::SetPrecompiledInitializer(const Function& initializer) const {
+  ASSERT(IsOriginal());
   StorePointer(&raw_ptr()->initializer_.precompiled_, initializer.raw());
 }
 
@@ -7784,16 +7536,19 @@
 
 
 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());
-    Object& value = Object::Handle(Compiler::EvaluateStaticInitializer(*this));
+    const Object& value =
+        Object::Handle(Compiler::EvaluateStaticInitializer(*this));
     if (value.IsError()) {
       SetStaticValue(Object::null_instance());
       Exceptions::PropagateError(Error::Cast(value));
@@ -7890,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());
@@ -7902,6 +7658,7 @@
 
 
 bool Field::UpdateGuardedCidAndLength(const Object& value) const {
+  ASSERT(IsOriginal());
   const intptr_t cid = value.GetClassId();
 
   if (guarded_cid() == kIllegalCid) {
@@ -7969,6 +7726,7 @@
 
 
 void Field::RecordStore(const Object& value) const {
+  ASSERT(IsOriginal());
   if (!FLAG_use_field_guards) {
     return;
   }
@@ -8034,11 +7792,6 @@
 }
 
 
-void LiteralToken::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 RawGrowableObjectArray* TokenStream::TokenObjects() const {
   return raw_ptr()->token_objects_;
 }
@@ -8077,11 +7830,12 @@
 }
 
 RawString* TokenStream::GenerateSource() const {
-  return GenerateSource(0, kMaxElements);
+  return GenerateSource(TokenPosition::kMinSource,
+                        TokenPosition::kMaxSource);
 }
 
-RawString* TokenStream::GenerateSource(intptr_t start_pos,
-                                       intptr_t end_pos) const {
+RawString* TokenStream::GenerateSource(TokenPosition start_pos,
+                                       TokenPosition end_pos) const {
   Iterator iterator(*this, start_pos, Iterator::kAllTokens);
   const ExternalTypedData& data = ExternalTypedData::Handle(GetStream());
   const GrowableObjectArray& literals =
@@ -8232,6 +7986,16 @@
       separator = NULL;
     } else if ((curr == Token::kSEMICOLON) && (next != Token::kNEWLINE)) {
       separator = &Symbols::Blank();
+    } else if ((curr == Token::kIS) && (next == Token::kNOT)) {
+      separator = NULL;
+    } else if ((prev == Token::kIS) && (curr == Token::kNOT)) {
+      separator = &Symbols::Blank();
+    } else if ((curr == Token::kIDENT) &&
+               ((next == Token::kINCR) || (next == Token::kDECR))) {
+      separator = NULL;
+    } else if (((curr == Token::kINCR) || (curr == Token::kDECR)) &&
+               (next == Token::kIDENT)) {
+      separator = NULL;
     }
 
     // Add the separator.
@@ -8255,14 +8019,15 @@
 }
 
 
-intptr_t TokenStream::ComputeSourcePosition(intptr_t tok_pos) const {
-  Iterator iterator(*this, 0, Iterator::kAllTokens);
-  intptr_t src_pos = 0;
+TokenPosition TokenStream::ComputeSourcePosition(
+    TokenPosition tok_pos) const {
+  Iterator iterator(*this, TokenPosition::kMinSource, Iterator::kAllTokens);
+  TokenPosition src_pos = TokenPosition::kMinSource;
   Token::Kind kind = iterator.CurrentTokenKind();
-  while (iterator.CurrentPosition() < tok_pos && kind != Token::kEOS) {
+  while ((iterator.CurrentPosition() < tok_pos) && (kind != Token::kEOS)) {
     iterator.Advance();
     kind = iterator.CurrentTokenKind();
-    src_pos += 1;
+    src_pos.Next();
   }
   return src_pos;
 }
@@ -8297,7 +8062,7 @@
 
 
 // CompressedTokenMap maps String and LiteralToken keys to Smi values.
-// It also supports lookup by Scanner::TokenDescriptor.
+// It also supports lookup by TokenDescriptor.
 class CompressedTokenTraits {
  public:
   static bool IsMatch(const Scanner::TokenDescriptor& descriptor,
@@ -8517,25 +8282,8 @@
 }
 
 
-void TokenStream::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Object", ref);
-  // TODO(johnmccutchan): Generate a stable id. TokenStreams hang off
-  // a Script object but do not have a back reference to generate a stable id.
-  jsobj.AddServiceId(*this);
-  if (ref) {
-    return;
-  }
-  const String& private_key = String::Handle(PrivateKey());
-  jsobj.AddProperty("privateKey", private_key);
-  // TODO(johnmccutchan): Add support for printing LiteralTokens and add
-  // them to members array.
-  JSONArray members(&jsobj, "members");
-}
-
-
 TokenStream::Iterator::Iterator(const TokenStream& tokens,
-                                intptr_t token_pos,
+                                TokenPosition token_pos,
                                 Iterator::StreamType stream_type)
     : tokens_(TokenStream::Handle(tokens.raw())),
       data_(ExternalTypedData::Handle(tokens.GetStream())),
@@ -8543,23 +8291,26 @@
       token_objects_(Array::Handle(
           GrowableObjectArray::Handle(tokens.TokenObjects()).data())),
       obj_(Object::Handle()),
-      cur_token_pos_(token_pos),
+      cur_token_pos_(token_pos.Pos()),
       cur_token_kind_(Token::kILLEGAL),
       cur_token_obj_index_(-1),
       stream_type_(stream_type) {
-  SetCurrentPosition(token_pos);
+  ASSERT(token_pos != TokenPosition::kNoSource);
+  if (token_pos.IsReal()) {
+    SetCurrentPosition(token_pos);
+  }
 }
 
 
 void TokenStream::Iterator::SetStream(const TokenStream& tokens,
-                                      intptr_t token_pos) {
+                                      TokenPosition token_pos) {
   tokens_ = tokens.raw();
   data_ = tokens.GetStream();
   stream_.SetStream(reinterpret_cast<uint8_t*>(data_.DataAddr(0)),
                     data_.Length());
   token_objects_ = GrowableObjectArray::Handle(tokens.TokenObjects()).data();
   obj_ = Object::null();
-  cur_token_pos_ = token_pos;
+  cur_token_pos_ = token_pos.Pos();
   cur_token_kind_ = Token::kILLEGAL;
   cur_token_obj_index_ = -1;
   SetCurrentPosition(token_pos);
@@ -8601,13 +8352,13 @@
 }
 
 
-intptr_t TokenStream::Iterator::CurrentPosition() const {
-  return cur_token_pos_;
+TokenPosition TokenStream::Iterator::CurrentPosition() const {
+  return TokenPosition(cur_token_pos_);
 }
 
 
-void TokenStream::Iterator::SetCurrentPosition(intptr_t value) {
-  stream_.SetPosition(value);
+void TokenStream::Iterator::SetCurrentPosition(TokenPosition token_pos) {
+  stream_.SetPosition(token_pos.value());
   Advance();
 }
 
@@ -8705,7 +8456,9 @@
   Smi& value = Smi::Handle(zone);
   String& tokenValue = String::Handle(zone);
   ASSERT(!tkns.IsNull());
-  TokenStream::Iterator tkit(tkns, 0, TokenStream::Iterator::kAllTokens);
+  TokenStream::Iterator tkit(tkns,
+                             TokenPosition::kMinSource,
+                             TokenStream::Iterator::kAllTokens);
   int current_line = -1;
   Scanner s(source, key);
   s.Scan();
@@ -8760,7 +8513,7 @@
     // TODO(hausner): Could optimize here by not reporting tokens
     // that will never be a location used by the debugger, e.g.
     // braces, semicolons, most keywords etc.
-    value = Smi::New(tkit.CurrentPosition());
+    value = Smi::New(tkit.CurrentPosition().Pos());
     info.Add(value);
     int column = s.current_token().position.column;
     // On the first line of the script we must add the column offset.
@@ -8847,7 +8600,7 @@
 }
 
 
-void Script::GetTokenLocation(intptr_t token_pos,
+void Script::GetTokenLocation(TokenPosition token_pos,
                               intptr_t* line,
                               intptr_t* column,
                               intptr_t* token_len) const {
@@ -8865,10 +8618,12 @@
     return;
   }
   if (column == NULL) {
-    TokenStream::Iterator tkit(tkns, 0, TokenStream::Iterator::kAllTokens);
+    TokenStream::Iterator tkit(tkns,
+                               TokenPosition::kMinSource,
+                               TokenStream::Iterator::kAllTokens);
     intptr_t cur_line = line_offset() + 1;
-    while (tkit.CurrentPosition() < token_pos &&
-           tkit.CurrentTokenKind() != Token::kEOS) {
+    while ((tkit.CurrentPosition() < token_pos) &&
+           (tkit.CurrentTokenKind() != Token::kEOS)) {
       if (tkit.CurrentTokenKind() == Token::kNEWLINE) {
         cur_line++;
       }
@@ -8877,7 +8632,7 @@
     *line = cur_line;
   } else {
     const String& src = String::Handle(Source());
-    intptr_t src_pos = tkns.ComputeSourcePosition(token_pos);
+    TokenPosition src_pos = tkns.ComputeSourcePosition(token_pos);
     Scanner scanner(src, Symbols::Empty());
     scanner.ScanTo(src_pos);
     intptr_t relative_line = scanner.CurrentPosition().line;
@@ -8899,16 +8654,18 @@
 
 
 void Script::TokenRangeAtLine(intptr_t line_number,
-                              intptr_t* first_token_index,
-                              intptr_t* last_token_index) const {
+                              TokenPosition* first_token_index,
+                              TokenPosition* last_token_index) const {
   ASSERT(first_token_index != NULL && last_token_index != NULL);
   ASSERT(line_number > 0);
-  *first_token_index = -1;
-  *last_token_index = -1;
+  *first_token_index = TokenPosition::kNoSource;
+  *last_token_index = TokenPosition::kNoSource;
   const TokenStream& tkns = TokenStream::Handle(tokens());
   line_number -= line_offset();
   if (line_number < 1) line_number = 1;
-  TokenStream::Iterator tkit(tkns, 0, TokenStream::Iterator::kAllTokens);
+  TokenStream::Iterator tkit(tkns,
+                             TokenPosition::kMinSource,
+                             TokenStream::Iterator::kAllTokens);
   // Scan through the token stream to the required line.
   intptr_t cur_line = 1;
   while (cur_line < line_number && tkit.CurrentTokenKind() != Token::kEOS) {
@@ -8936,7 +8693,7 @@
   *first_token_index = tkit.CurrentPosition();
   // We cannot do "CurrentPosition() - 1" for the last token, because we do not
   // know whether the previous token is a simple one or not.
-  intptr_t end_pos = *first_token_index;
+  TokenPosition end_pos = *first_token_index;
   while (tkit.CurrentTokenKind() != Token::kNEWLINE &&
          tkit.CurrentTokenKind() != Token::kEOS) {
     end_pos = tkit.CurrentPosition();
@@ -9083,68 +8840,6 @@
 }
 
 
-// See also Dart_ScriptGetTokenInfo.
-void Script::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Script", ref);
-  const String& uri = String::Handle(url());
-  ASSERT(!uri.IsNull());
-  const String& encoded_uri = String::Handle(String::EncodeIRI(uri));
-  ASSERT(!encoded_uri.IsNull());
-  const Library& lib = Library::Handle(FindLibrary());
-  if (kind() == RawScript::kEvaluateTag) {
-    jsobj.AddServiceId(*this);
-  } else {
-    ASSERT(!lib.IsNull());
-    jsobj.AddFixedServiceId("libraries/%" Pd "/scripts/%s",
-        lib.index(), encoded_uri.ToCString());
-  }
-  jsobj.AddPropertyStr("uri", uri);
-  jsobj.AddProperty("_kind", GetKindAsCString());
-  if (ref) {
-    return;
-  }
-  if (!lib.IsNull()) {
-    jsobj.AddProperty("library", lib);
-  }
-  const String& source = String::Handle(Source());
-  jsobj.AddProperty("lineOffset", line_offset());
-  jsobj.AddProperty("columnOffset", col_offset());
-  if (!source.IsNull()) {
-    jsobj.AddPropertyStr("source", source);
-  }
-
-  // Print the line number table
-  if (!source.IsNull()) {
-    JSONArray tokenPosTable(&jsobj, "tokenPosTable");
-
-    const GrowableObjectArray& lineNumberArray =
-        GrowableObjectArray::Handle(GenerateLineNumberArray());
-    Object& value = Object::Handle();
-    intptr_t pos = 0;
-
-    // Skip leading null.
-    ASSERT(lineNumberArray.Length() > 0);
-    value = lineNumberArray.At(pos);
-    ASSERT(value.IsNull());
-    pos++;
-
-    while (pos < lineNumberArray.Length()) {
-      JSONArray lineInfo(&tokenPosTable);
-      while (pos < lineNumberArray.Length()) {
-        value = lineNumberArray.At(pos);
-        pos++;
-        if (value.IsNull()) {
-          break;
-        }
-        const Smi& smi = Smi::Cast(value);
-        lineInfo.AddValue(smi.Value());
-      }
-    }
-  }
-}
-
-
 DictionaryIterator::DictionaryIterator(const Library& library)
     : array_(Array::Handle(library.dictionary())),
       // Last element in array is a Smi indicating the number of entries used.
@@ -9239,7 +8934,8 @@
   const String& url = String::Handle(lib.url());
   Report::MessageF(Report::kError,
                    Script::Handle(lib.LookupScript(url)),
-                   Scanner::kNoSourcePos,
+                   TokenPosition::kNoSource,
+                   Report::AtLocation,
                    "too many imports in library '%s'",
                    url.ToCString());
   UNREACHABLE();
@@ -9392,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());
@@ -9407,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);
 }
 
@@ -9425,7 +9121,7 @@
 
 void Library::AddMetadata(const Object& owner,
                           const String& name,
-                          intptr_t token_pos) const {
+                          TokenPosition token_pos) const {
   const String& metaname = String::Handle(Symbols::New(name));
   const Field& field = Field::Handle(
       Field::NewTopLevel(metaname,
@@ -9444,7 +9140,7 @@
 
 void Library::AddClassMetadata(const Class& cls,
                                const Object& tl_owner,
-                               intptr_t token_pos) const {
+                               TokenPosition token_pos) const {
   // We use the toplevel class as the owner of a class's metadata field because
   // a class's metadata is in scope of the library, not the class.
   AddMetadata(tl_owner,
@@ -9454,7 +9150,7 @@
 
 
 void Library::AddFieldMetadata(const Field& field,
-                               intptr_t token_pos) const {
+                               TokenPosition token_pos) const {
   AddMetadata(Object::Handle(field.RawOwner()),
               String::Handle(MakeFieldMetaName(field)),
               token_pos);
@@ -9462,7 +9158,7 @@
 
 
 void Library::AddFunctionMetadata(const Function& func,
-                                  intptr_t token_pos) const {
+                                  TokenPosition token_pos) const {
   AddMetadata(Object::Handle(func.RawOwner()),
               String::Handle(MakeFunctionMetaName(func)),
               token_pos);
@@ -9470,7 +9166,7 @@
 
 
 void Library::AddTypeParameterMetadata(const TypeParameter& param,
-                                       intptr_t token_pos) const {
+                                       TokenPosition token_pos) const {
   AddMetadata(Class::Handle(param.parameterized_class()),
               String::Handle(MakeTypeParameterMetaName(param)),
               token_pos);
@@ -9478,7 +9174,7 @@
 
 
 void Library::AddLibraryMetadata(const Object& tl_owner,
-                                 intptr_t token_pos) const {
+                                 TokenPosition token_pos) const {
   AddMetadata(tl_owner, Symbols::TopLevel(), token_pos);
 }
 
@@ -9746,7 +9442,7 @@
   while (!entry.IsNull()) {
     entry_name = entry.DictionaryName();
     ASSERT(!entry_name.IsNull());
-     if (entry_name.Equals(name)) {
+    if (entry_name.Equals(name)) {
       return entry.raw();
     }
     *index = (*index + 1) % dict_size;
@@ -9768,6 +9464,51 @@
 }
 
 
+bool Library::RemoveObject(const Object& obj, const String& name) const {
+  Object& entry = Object::Handle();
+
+  intptr_t index;
+  entry = LookupEntry(name, &index);
+  if (entry.raw() != obj.raw()) {
+    return false;
+  }
+
+  const Array& dict = Array::Handle(dictionary());
+  dict.SetAt(index, Object::null_object());
+  intptr_t dict_size = dict.Length() - 1;
+
+  // Fix any downstream collisions.
+  String& key = String::Handle();
+  for (;;) {
+    index = (index + 1) % dict_size;
+    entry = dict.At(index);
+
+    if (entry.IsNull()) break;
+
+    key = entry.DictionaryName();
+    intptr_t new_index = key.Hash() % dict_size;
+    while ((dict.At(new_index) != entry.raw()) &&
+           (dict.At(new_index) != Object::null())) {
+      new_index = (new_index + 1) % dict_size;
+    }
+
+    if (index != new_index) {
+      ASSERT(dict.At(new_index) == Object::null());
+      dict.SetAt(new_index, entry);
+      dict.SetAt(index, Object::null_object());
+    }
+  }
+
+  // Update used count.
+  intptr_t used_elements = Smi::Value(Smi::RawCast(dict.At(dict_size))) - 1;
+  dict.SetAt(dict_size, Smi::Handle(Smi::New(used_elements)));
+
+  InvalidateResolvedNamesCache();
+
+  return true;
+}
+
+
 void Library::AddClass(const Class& cls) const {
   const String& class_name = String::Handle(cls.Name());
   AddObject(cls, class_name);
@@ -9812,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;
       }
@@ -10114,6 +9855,12 @@
 }
 
 
+void Library::DropDependencies() const {
+  StorePointer(&raw_ptr()->imports_, Array::null());
+  StorePointer(&raw_ptr()->exports_, Array::null());
+}
+
+
 void Library::AddImport(const Namespace& ns) const {
   Array& imports = Array::Handle(this->imports());
   intptr_t capacity = imports.Length();
@@ -10155,9 +9902,17 @@
 }
 
 
-void Library::InitResolvedNamesCache(intptr_t size) const {
-  const Array& cache = Array::Handle(HashTables::New<ResolvedNamesMap>(size));
-  StorePointer(&raw_ptr()->resolved_names_, cache.raw());
+void Library::InitResolvedNamesCache(intptr_t size,
+                                     SnapshotReader* reader) const {
+  if (reader == NULL) {
+    StorePointer(&raw_ptr()->resolved_names_,
+                 HashTables::New<ResolvedNamesMap>(size));
+  } else {
+    intptr_t len = ResolvedNamesMap::ArrayLengthForNumOccupied(size);
+    *reader->ArrayHandle() ^= reader->NewArray(len);
+    StorePointer(&raw_ptr()->resolved_names_,
+                 HashTables::New<ResolvedNamesMap>(*reader->ArrayHandle()));
+  }
 }
 
 
@@ -10300,9 +10055,17 @@
   String& lib_url = String::Handle(zone, String::null());
   GrowableObjectArray& libs = GrowableObjectArray::Handle(
       zone, isolate->object_store()->libraries());
-  for (int i = 0; i < libs.Length(); i++) {
+
+  // Make sure the URL string has an associated hash code
+  // to speed up the repeated equality checks.
+  url.Hash();
+
+  intptr_t len = libs.Length();
+  for (intptr_t i = 0; i < len; i++) {
     lib ^= libs.At(i);
     lib_url ^= lib.url();
+
+    ASSERT(url.HasHash() && lib_url.HasHash());
     if (lib_url.Equals(url)) {
       return lib.raw();
     }
@@ -10409,6 +10172,7 @@
 
 void Library::Register() const {
   ASSERT(Library::LookupLibrary(String::Handle(url())) == Library::null());
+  ASSERT(String::Handle(url()).HasHash());
   ObjectStore* object_store = Isolate::Current()->object_store();
   GrowableObjectArray& libs =
       GrowableObjectArray::Handle(object_store->libraries());
@@ -10490,135 +10254,6 @@
 }
 
 
-void Library::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  intptr_t id = index();
-  ASSERT(id >= 0);
-  JSONObject jsobj(stream);
-  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& library_url = String::Handle(url());
-  jsobj.AddPropertyStr("uri", library_url);
-  if (ref) {
-    return;
-  }
-  jsobj.AddProperty("debuggable", IsDebuggable());
-  {
-    JSONArray jsarr(&jsobj, "classes");
-    ClassDictionaryIterator class_iter(*this);
-    Class& klass = Class::Handle();
-    while (class_iter.HasNext()) {
-      klass = class_iter.GetNextClass();
-      if (!klass.IsCanonicalSignatureClass() &&
-          !klass.IsMixinApplication()) {
-        jsarr.AddValue(klass);
-      }
-    }
-  }
-  {
-    JSONArray jsarr(&jsobj, "dependencies");
-
-    Array& ports = Array::Handle();
-    Namespace& ns = Namespace::Handle();
-    Library& target = Library::Handle();
-
-    // Unprefixed imports.
-    ports = imports();
-    for (intptr_t i = 0; i < ports.Length(); i++) {
-      ns ^= ports.At(i);
-      if (ns.IsNull()) continue;
-
-      JSONObject jsdep(&jsarr);
-      jsdep.AddProperty("isDeferred", false);
-      jsdep.AddProperty("isExport", false);
-      jsdep.AddProperty("isImport", true);
-      target = ns.library();
-      jsdep.AddProperty("target", target);
-    }
-
-    // Exports.
-    ports = exports();
-    for (intptr_t i = 0; i < ports.Length(); i++) {
-      ns ^= ports.At(i);
-      if (ns.IsNull()) continue;
-
-      JSONObject jsdep(&jsarr);
-      jsdep.AddProperty("isDeferred", false);
-      jsdep.AddProperty("isExport", true);
-      jsdep.AddProperty("isImport", false);
-      target = ns.library();
-      jsdep.AddProperty("target", target);
-    }
-
-    // Prefixed imports.
-    DictionaryIterator entries(*this);
-    Object& entry = Object::Handle();
-    LibraryPrefix& prefix = LibraryPrefix::Handle();
-    String& prefixName = String::Handle();
-    while (entries.HasNext()) {
-      entry = entries.GetNext();
-      if (entry.IsLibraryPrefix()) {
-        prefix ^= entry.raw();
-        ports = prefix.imports();
-        for (intptr_t i = 0; i < ports.Length(); i++) {
-          ns ^= ports.At(i);
-          if (ns.IsNull()) continue;
-
-          JSONObject jsdep(&jsarr);
-          jsdep.AddProperty("isDeferred", prefix.is_deferred_load());
-          jsdep.AddProperty("isExport", false);
-          jsdep.AddProperty("isImport", true);
-          prefixName = prefix.name();
-          ASSERT(!prefixName.IsNull());
-          jsdep.AddProperty("prefix", prefixName.ToCString());
-          target = ns.library();
-          jsdep.AddProperty("target", target);
-        }
-      }
-    }
-  }
-  {
-    JSONArray jsarr(&jsobj, "variables");
-    DictionaryIterator entries(*this);
-    Object& entry = Object::Handle();
-    while (entries.HasNext()) {
-      entry = entries.GetNext();
-      if (entry.IsField()) {
-        jsarr.AddValue(entry);
-      }
-    }
-  }
-  {
-    JSONArray jsarr(&jsobj, "functions");
-    DictionaryIterator entries(*this);
-    Object& entry = Object::Handle();
-    while (entries.HasNext()) {
-      entry = entries.GetNext();
-      if (entry.IsFunction()) {
-        const Function& func = Function::Cast(entry);
-        if (func.kind() == RawFunction::kRegularFunction ||
-            func.kind() == RawFunction::kGetterFunction ||
-            func.kind() == RawFunction::kSetterFunction) {
-          jsarr.AddValue(func);
-        }
-      }
-    }
-  }
-  {
-    JSONArray jsarr(&jsobj, "scripts");
-    Array& scripts = Array::Handle(LoadedScripts());
-    Script& script = Script::Handle();
-    for (intptr_t i = 0; i < scripts.Length(); i++) {
-      script ^= scripts.At(i);
-      jsarr.AddValue(script);
-    }
-  }
-}
-
-
 RawLibrary* LibraryPrefix::GetLibrary(int index) const {
   if ((index >= 0) || (index < num_imports())) {
     const Array& imports = Array::Handle(this->imports());
@@ -10758,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
@@ -10772,7 +10412,6 @@
   } else if (deferred_lib.LoadNotStarted()) {
     Thread* thread = Thread::Current();
     Isolate* isolate = thread->isolate();
-    Api::Scope api_scope(thread);
     Zone* zone = thread->zone();
     deferred_lib.SetLoadRequested();
     const GrowableObjectArray& pending_deferred_loads =
@@ -10781,9 +10420,13 @@
     pending_deferred_loads.Add(deferred_lib);
     const String& lib_url = String::Handle(zone, deferred_lib.url());
     Dart_LibraryTagHandler handler = isolate->library_tag_handler();
-    handler(Dart_kImportTag,
-            Api::NewHandle(thread, importer()),
-            Api::NewHandle(thread, lib_url.raw()));
+    {
+      TransitionVMToNative transition(thread);
+      Api::Scope api_scope(thread);
+      handler(Dart_kImportTag,
+              Api::NewHandle(thread, importer()),
+              Api::NewHandle(thread, lib_url.raw()));
+    }
   } else {
     // Another load request is in flight.
     ASSERT(deferred_lib.LoadRequested());
@@ -10842,7 +10485,9 @@
 
 void LibraryPrefix::RegisterDependentCode(const Code& code) const {
   ASSERT(is_deferred_load());
-  ASSERT(!is_loaded());
+  // In background compilation, a library can be loaded while we are compiling.
+  // The generated code will be rejected in that case,
+  ASSERT(!is_loaded() || Compiler::IsBackgroundCompilation());
   PrefixDependentArray a(*this);
   a.Register(code);
 }
@@ -10910,17 +10555,12 @@
 }
 
 
-void LibraryPrefix::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 void Namespace::set_metadata_field(const Field& value) const {
   StorePointer(&raw_ptr()->metadata_field_, value.raw());
 }
 
 
-void Namespace::AddMetadata(const Object& owner, intptr_t token_pos) {
+void Namespace::AddMetadata(const Object& owner, TokenPosition token_pos) {
   ASSERT(Field::Handle(metadata_field()).IsNull());
   Field& field = Field::Handle(Field::NewTopLevel(Symbols::TopLevel(),
                                           false,  // is_final
@@ -10960,11 +10600,6 @@
 }
 
 
-void Namespace::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 bool Namespace::HidesName(const String& name) const {
   // Quick check for common case with no combinators.
   if (hide_names() == show_names()) {
@@ -11146,7 +10781,7 @@
 }
 
 
-#if defined(DART_NO_SNAPSHOT)
+#if defined(DART_NO_SNAPSHOT) && !defined(PRODUCT)
 void Library::CheckFunctionFingerprints() {
   GrowableArray<Library*> all_libs;
   Function& func = Function::Handle();
@@ -11208,7 +10843,7 @@
     FATAL("Fingerprint mismatch.");
   }
 }
-#endif  // defined(DART_NO_SNAPSHOT).
+#endif  // defined(DART_NO_SNAPSHOT) && !defined(PRODUCT).
 
 
 RawInstructions* Instructions::New(intptr_t size) {
@@ -11236,25 +10871,15 @@
 }
 
 
-void Instructions::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Object", ref);
-  jsobj.AddServiceId(*this);
-  if (ref) {
-    return;
-  }
-}
-
-
-// Encode integer in SLEB128 format.
-void PcDescriptors::EncodeInteger(GrowableArray<uint8_t>* data,
-                                  intptr_t value) {
+// Encode integer |value| in SLEB128 format and store into |data|.
+static void EncodeSLEB128(GrowableArray<uint8_t>* data,
+                          intptr_t value) {
   bool is_last_part = false;
   while (!is_last_part) {
-    intptr_t part = value & 0x7f;
+    uint8_t part = value & 0x7f;
     value >>= 7;
     if ((value == 0 && (part & 0x40) == 0) ||
-        (value == -1 && (part & 0x40) != 0)) {
+        (value == static_cast<intptr_t>(-1) && (part & 0x40) != 0)) {
       is_last_part = true;
     } else {
       part |= 0x80;
@@ -11264,24 +10889,39 @@
 }
 
 
+// Decode integer in SLEB128 format from |data| and update |byte_index|.
+static intptr_t DecodeSLEB128(const uint8_t* data,
+                              const intptr_t data_length,
+                              intptr_t* byte_index) {
+  ASSERT(*byte_index < data_length);
+  uword shift = 0;
+  intptr_t value = 0;
+  uint8_t part = 0;
+  do {
+    part = data[(*byte_index)++];
+    value |= static_cast<intptr_t>(part & 0x7f) << shift;
+    shift += 7;
+  } while ((part & 0x80) != 0);
+
+  if ((shift < (sizeof(value) * 8)) && ((part & 0x40) != 0)) {
+    value |= static_cast<intptr_t>(-1) << shift;
+  }
+  return value;
+}
+
+
+// Encode integer in SLEB128 format.
+void PcDescriptors::EncodeInteger(GrowableArray<uint8_t>* data,
+                                  intptr_t value) {
+  return EncodeSLEB128(data, value);
+}
+
+
 // Decode SLEB128 encoded integer. Update byte_index to the next integer.
 intptr_t PcDescriptors::DecodeInteger(intptr_t* byte_index) const {
   NoSafepointScope no_safepoint;
   const uint8_t* data = raw_ptr()->data();
-  ASSERT(*byte_index < Length());
-  uword shift = 0;
-  intptr_t value = 0;
-  intptr_t part = 0;
-  do {
-    part = data[(*byte_index)++];
-    value |= (part & 0x7f) << shift;
-    shift += 7;
-  } while ((part & 0x80) != 0);
-
-  if (shift < sizeof(value) * 8 && (part & 0x40) != 0) {
-    value |= -(1 << shift);
-  }
-  return value;
+  return DecodeSLEB128(data, Length(), byte_index);
 }
 
 
@@ -11328,48 +10968,8 @@
 }
 
 
-void ObjectPool::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Object", ref);
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("length", Length());
-  if (ref) {
-    return;
-  }
-
-  {
-    JSONArray jsarr(&jsobj, "_entries");
-    uword imm;
-    Object& obj = Object::Handle();
-    for (intptr_t i = 0; i < Length(); i++) {
-      JSONObject jsentry(stream);
-      jsentry.AddProperty("offset", OffsetFromIndex(i));
-      switch (InfoAt(i)) {
-      case ObjectPool::kTaggedObject:
-        obj = ObjectAt(i);
-        jsentry.AddProperty("kind", "Object");
-        jsentry.AddProperty("value", obj);
-        break;
-      case ObjectPool::kImmediate:
-        imm = RawValueAt(i);
-        jsentry.AddProperty("kind", "Immediate");
-        jsentry.AddProperty64("value", imm);
-        break;
-      case ObjectPool::kNativeEntry:
-        imm = RawValueAt(i);
-        jsentry.AddProperty("kind", "NativeEntry");
-        jsentry.AddProperty64("value", imm);
-        break;
-      default:
-        UNREACHABLE();
-      }
-    }
-  }
-}
-
-
 void ObjectPool::DebugPrint() const {
-  THR_Print("Object Pool: {\n");
+  THR_Print("Object Pool: 0x%" Px "{\n", reinterpret_cast<uword>(raw()));
   for (intptr_t i = 0; i < Length(); i++) {
     intptr_t offset = OffsetFromIndex(i);
     THR_Print("  %" Pd " PP+0x%" Px ": ", i, offset);
@@ -11474,7 +11074,7 @@
 const char* PcDescriptors::ToCString() const {
   // "*" in a printf format specifier tells it to read the field width from
   // the printf argument list.
-#define FORMAT "%#-*" Px "\t%s\t%" Pd "\t\t%" Pd "\t%" Pd "\n"
+#define FORMAT "%#-*" Px "\t%s\t%" Pd "\t\t%s\t%" Pd "\n"
   if (Length() == 0) {
     return "empty PcDescriptors\n";
   }
@@ -11489,7 +11089,7 @@
                          iter.PcOffset(),
                          KindAsStr(iter.Kind()),
                          iter.DeoptId(),
-                         iter.TokenPos(),
+                         iter.TokenPos().ToCString(),
                          iter.TryIndex());
     }
   }
@@ -11503,7 +11103,7 @@
                          iter.PcOffset(),
                          KindAsStr(iter.Kind()),
                          iter.DeoptId(),
-                         iter.TokenPos(),
+                         iter.TokenPos().ToCString(),
                          iter.TryIndex());
   }
   return buffer;
@@ -11511,34 +11111,6 @@
 }
 
 
-void PcDescriptors::PrintToJSONObject(JSONObject* jsobj, bool ref) const {
-  AddCommonObjectProperties(jsobj, "Object", ref);
-  // TODO(johnmccutchan): Generate a stable id. PcDescriptors hang off a Code
-  // object but do not have a back reference to generate an ID.
-  jsobj->AddServiceId(*this);
-  if (ref) {
-    return;
-  }
-  JSONArray members(jsobj, "members");
-  Iterator iter(*this, RawPcDescriptors::kAnyKind);
-  while (iter.MoveNext()) {
-    JSONObject descriptor(&members);
-    descriptor.AddPropertyF("pcOffset", "%" Px "", iter.PcOffset());
-    descriptor.AddProperty("kind", KindAsStr(iter.Kind()));
-    descriptor.AddProperty("deoptId", iter.DeoptId());
-    // TODO(turnidge): Use AddLocation instead.
-    descriptor.AddProperty("tokenPos", iter.TokenPos());
-    descriptor.AddProperty("tryIndex", iter.TryIndex());
-  }
-}
-
-
-void PcDescriptors::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintToJSONObject(&jsobj, ref);
-}
-
-
 // Verify assumptions (in debug mode only).
 // - No two deopt descriptors have the same deoptimization id.
 // - No two ic-call descriptors have the same deoptimization id (type feedback).
@@ -11583,6 +11155,190 @@
 }
 
 
+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_;
+}
+
+
+void CodeSourceMap::SetLength(intptr_t value) const {
+  StoreNonPointer(&raw_ptr()->length_, value);
+}
+
+
+void CodeSourceMap::CopyData(GrowableArray<uint8_t>* delta_encoded_data) {
+  NoSafepointScope no_safepoint;
+  uint8_t* data = UnsafeMutableNonPointer(&raw_ptr()->data()[0]);
+  for (intptr_t i = 0; i < delta_encoded_data->length(); ++i) {
+    data[i] = (*delta_encoded_data)[i];
+  }
+}
+
+
+RawCodeSourceMap* CodeSourceMap::New(GrowableArray<uint8_t>* data) {
+  ASSERT(Object::code_source_map_class() != Class::null());
+  Thread* thread = Thread::Current();
+  CodeSourceMap& result = CodeSourceMap::Handle(thread->zone());
+  {
+    uword size = CodeSourceMap::InstanceSize(data->length());
+    RawObject* raw = Object::Allocate(CodeSourceMap::kClassId,
+                                      size,
+                                      Heap::kOld);
+    NoSafepointScope no_safepoint;
+    result ^= raw;
+    result.SetLength(data->length());
+    result.CopyData(data);
+  }
+  return result.raw();
+}
+
+
+RawCodeSourceMap* CodeSourceMap::New(intptr_t length) {
+  ASSERT(Object::code_source_map_class() != Class::null());
+  Thread* thread = Thread::Current();
+  CodeSourceMap& result = CodeSourceMap::Handle(thread->zone());
+  {
+    uword size = CodeSourceMap::InstanceSize(length);
+    RawObject* raw = Object::Allocate(CodeSourceMap::kClassId,
+                                      size,
+                                      Heap::kOld);
+    NoSafepointScope no_safepoint;
+    result ^= raw;
+    result.SetLength(length);
+  }
+  return result.raw();
+}
+
+
+const char* CodeSourceMap::ToCString() const {
+  // "*" in a printf format specifier tells it to read the field width from
+  // the printf argument list.
+#define FORMAT "%#-*" Px "\t%s\n"
+  if (Length() == 0) {
+    return "empty CodeSourceMap\n";
+  }
+  // 4 bits per hex digit.
+  const int addr_width = kBitsPerWord / 4;
+  // First compute the buffer size required.
+  intptr_t len = 1;  // Trailing '\0'.
+  {
+    Iterator iter(*this);
+    while (iter.MoveNext()) {
+      len += OS::SNPrint(NULL, 0, FORMAT, addr_width,
+                         iter.PcOffset(),
+                         iter.TokenPos().ToCString());
+    }
+  }
+  // Allocate the buffer.
+  char* buffer = Thread::Current()->zone()->Alloc<char>(len);
+  // Layout the fields in the buffer.
+  intptr_t index = 0;
+  Iterator iter(*this);
+  while (iter.MoveNext()) {
+    index += OS::SNPrint((buffer + index), (len - index), FORMAT, addr_width,
+                         iter.PcOffset(),
+                         iter.TokenPos().ToCString());
+  }
+  return buffer;
+#undef FORMAT
+}
+
+
+// Encode integer in SLEB128 format.
+void CodeSourceMap::EncodeInteger(GrowableArray<uint8_t>* data,
+                                  intptr_t value) {
+  return EncodeSLEB128(data, value);
+}
+
+
+// Decode SLEB128 encoded integer. Update byte_index to the next integer.
+intptr_t CodeSourceMap::DecodeInteger(intptr_t* byte_index) const {
+  NoSafepointScope no_safepoint;
+  const uint8_t* data = raw_ptr()->data();
+  return DecodeSLEB128(data, Length(), byte_index);
+}
+
+
 bool Stackmap::GetBit(intptr_t bit_index) const {
   ASSERT(InRange(bit_index));
   int byte_index = bit_index >> kBitsPerByteLog2;
@@ -11708,11 +11464,6 @@
 }
 
 
-void Stackmap::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 RawString* LocalVarDescriptors::GetName(intptr_t var_index) const {
   ASSERT(var_index < Length());
   ASSERT(Object::Handle(*raw()->nameAddrAt(var_index)).IsString());
@@ -11751,8 +11502,8 @@
                        LocalVarDescriptors::KindToCString(kind),
                        index,
                        info.scope_id,
-                       info.begin_pos,
-                       info.end_pos);
+                       static_cast<int>(info.begin_pos.Pos()),
+                       static_cast<int>(info.end_pos.Pos()));
   } else if (kind == RawLocalVarDescriptors::kContextVar) {
     return OS::SNPrint(buffer, len,
                        "%2" Pd " %-13s level=%-3d index=%-3d"
@@ -11761,8 +11512,8 @@
                        LocalVarDescriptors::KindToCString(kind),
                        info.scope_id,
                        index,
-                       info.begin_pos,
-                       info.end_pos,
+                       static_cast<int>(info.begin_pos.Pos()),
+                       static_cast<int>(info.end_pos.Pos()),
                        var_name.ToCString());
   } else {
     return OS::SNPrint(buffer, len,
@@ -11772,8 +11523,8 @@
                        LocalVarDescriptors::KindToCString(kind),
                        info.scope_id,
                        index,
-                       info.begin_pos,
-                       info.end_pos,
+                       static_cast<int>(info.begin_pos.Pos()),
+                       static_cast<int>(info.end_pos.Pos()),
                        var_name.ToCString());
   }
 }
@@ -11809,33 +11560,6 @@
 }
 
 
-void LocalVarDescriptors::PrintJSONImpl(JSONStream* stream,
-                                        bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Object", ref);
-  // TODO(johnmccutchan): Generate a stable id. LocalVarDescriptors hang off
-  // a Code object but do not have a back reference to generate an ID.
-  jsobj.AddServiceId(*this);
-  if (ref) {
-    return;
-  }
-  JSONArray members(&jsobj, "members");
-  String& var_name = String::Handle();
-  for (intptr_t i = 0; i < Length(); i++) {
-    RawLocalVarDescriptors::VarInfo info;
-    var_name = GetName(i);
-    GetInfo(i, &info);
-    JSONObject var(&members);
-    var.AddProperty("name", var_name.ToCString());
-    var.AddProperty("index", static_cast<intptr_t>(info.index()));
-    var.AddProperty("beginPos", static_cast<intptr_t>(info.begin_pos));
-    var.AddProperty("endPos", static_cast<intptr_t>(info.end_pos));
-    var.AddProperty("scopeId", static_cast<intptr_t>(info.scope_id));
-    var.AddProperty("kind", KindToCString(info.kind()));
-  }
-}
-
-
 const char* LocalVarDescriptors::KindToCString(
     RawLocalVarDescriptors::VarInfoKind kind) {
   switch (kind) {
@@ -12065,12 +11789,6 @@
 }
 
 
-void ExceptionHandlers::PrintJSONImpl(JSONStream* stream,
-                                      bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 intptr_t DeoptInfo::FrameSize(const TypedData& packed) {
   NoSafepointScope no_safepoint;
   typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader;
@@ -12222,7 +11940,6 @@
 
 
 void ICData::set_owner(const Function& value) const {
-  ASSERT(!value.IsNull());
   StorePointer(&raw_ptr()->owner_, reinterpret_cast<RawObject*>(value.raw()));
 }
 
@@ -12286,35 +12003,6 @@
 }
 
 
-bool ICData::IssuedJSWarning() const {
-  return IssuedJSWarningBit::decode(raw_ptr()->state_bits_);
-}
-
-
-void ICData::SetIssuedJSWarning() const {
-  StoreNonPointer(&raw_ptr()->state_bits_,
-                  IssuedJSWarningBit::update(true, raw_ptr()->state_bits_));
-}
-
-
-bool ICData::MayCheckForJSWarning() const {
-  const String& name = String::Handle(target_name());
-  // Warning issued from native code.
-  // Calling sequence is decoded to obtain ic data in order to check if a
-  // warning has already been issued.
-  if (name.Equals(Library::PrivateCoreLibName(Symbols::_instanceOf())) ||
-      name.Equals(Library::PrivateCoreLibName(Symbols::_as()))) {
-    return true;
-  }
-  // Warning issued in ic miss handler.
-  // No decoding necessary, so allow optimization if warning already issued.
-  if (name.Equals(Symbols::toString()) && !IssuedJSWarning()) {
-    return true;
-  }
-  return false;
-}
-
-
 void ICData::set_state_bits(uint32_t bits) const {
   StoreNonPointer(&raw_ptr()->state_bits_, bits);
 }
@@ -12873,7 +12561,7 @@
 }
 
 
-RawICData* ICData::CloneDescriptor(const ICData& from) {
+RawICData* ICData::Clone(const ICData& from) {
   Zone* zone = Thread::Current()->zone();
   const ICData& result = ICData::Handle(ICData::NewDescriptor(
       zone,
@@ -12882,94 +12570,23 @@
       Array::Handle(zone, from.arguments_descriptor()),
       from.deopt_id(),
       from.NumArgsTested()));
-  // Preserve entry array.
-  result.set_ic_data_array(Array::Handle(zone, from.ic_data()));
+  // Clone entry array.
+  const Array& from_array = Array::Handle(zone, from.ic_data());
+  const intptr_t len = from_array.Length();
+  const Array& cloned_array =
+      Array::Handle(zone, Array::New(len, Heap::kOld));
+  Object& obj = Object::Handle(zone);
+  for (intptr_t i = 0; i < len; i++) {
+    obj = from_array.At(i);
+    cloned_array.SetAt(i, obj);
+  }
+  result.set_ic_data_array(cloned_array);
   // Copy deoptimization reasons.
   result.SetDeoptReasons(from.DeoptReasons());
   return result.raw();
 }
 
 
-void ICData::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Object", ref);
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("_owner", Object::Handle(Owner()));
-  jsobj.AddProperty("_selector", String::Handle(target_name()).ToCString());
-  if (ref) {
-    return;
-  }
-  jsobj.AddProperty("_argumentsDescriptor",
-                    Object::Handle(arguments_descriptor()));
-  jsobj.AddProperty("_entries", Object::Handle(ic_data()));
-}
-
-
-void ICData::PrintToJSONArray(const JSONArray& jsarray,
-                              intptr_t token_pos,
-                              bool is_static_call) const {
-  Isolate* isolate = Isolate::Current();
-  Class& cls = Class::Handle();
-  Function& func = Function::Handle();
-
-  JSONObject jsobj(&jsarray);
-  jsobj.AddProperty("name", String::Handle(target_name()).ToCString());
-  jsobj.AddProperty("tokenPos", token_pos);
-  // TODO(rmacnak): Figure out how to stringify DeoptReasons().
-  // jsobj.AddProperty("deoptReasons", ...);
-
-  JSONArray cache_entries(&jsobj, "cacheEntries");
-  for (intptr_t i = 0; i < NumberOfChecks(); i++) {
-    func = GetTargetAt(i);
-    if (is_static_call) {
-      cls ^= func.Owner();
-    } else {
-      intptr_t cid = GetReceiverClassIdAt(i);
-      cls ^= isolate->class_table()->At(cid);
-    }
-    intptr_t count = GetCountAt(i);
-    JSONObject cache_entry(&cache_entries);
-    if (cls.IsTopLevel()) {
-      cache_entry.AddProperty("receiverContainer",
-                              Library::Handle(cls.library()));
-    } else {
-      cache_entry.AddProperty("receiverContainer", cls);
-    }
-    cache_entry.AddProperty("count", count);
-    cache_entry.AddProperty("target", func);
-  }
-}
-
-
-void ICData::PrintToJSONArrayNew(const JSONArray& jsarray,
-                                 intptr_t token_pos,
-                                 bool is_static_call) const {
-  Isolate* isolate = Isolate::Current();
-  Class& cls = Class::Handle();
-  Function& func = Function::Handle();
-
-  JSONObject jsobj(&jsarray);
-  jsobj.AddProperty("name", String::Handle(target_name()).ToCString());
-  jsobj.AddProperty("tokenPos", token_pos);
-  // TODO(rmacnak): Figure out how to stringify DeoptReasons().
-  // jsobj.AddProperty("deoptReasons", ...);
-
-  JSONArray cache_entries(&jsobj, "cacheEntries");
-  for (intptr_t i = 0; i < NumberOfChecks(); i++) {
-    JSONObject cache_entry(&cache_entries);
-    func = GetTargetAt(i);
-    intptr_t count = GetCountAt(i);
-    if (!is_static_call) {
-      intptr_t cid = GetReceiverClassIdAt(i);
-      cls ^= isolate->class_table()->At(cid);
-      cache_entry.AddProperty("receiver", cls);
-    }
-    cache_entry.AddProperty("target", func);
-    cache_entry.AddProperty("count", count);
-  }
-}
-
-
 static Token::Kind RecognizeArithmeticOp(const String& name) {
   ASSERT(name.IsSymbol());
   if (name.raw() == Symbols::Plus().raw()) {
@@ -13171,6 +12788,9 @@
 
 
 bool Code::HasBreakpoint() const {
+  if (!FLAG_support_debugger) {
+    return false;
+  }
   return Isolate::Current()->debugger()->HasBreakpoint(*this);
 }
 
@@ -13282,6 +12902,9 @@
 
 
 void Code::Disassemble(DisassemblyFormatter* formatter) const {
+  if (!FLAG_support_disassembler) {
+    return;
+  }
   const Instructions& instr = Instructions::Handle(instructions());
   uword start = instr.EntryPoint();
   if (formatter == NULL) {
@@ -13369,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()) {
@@ -13451,11 +13097,13 @@
   CPU::FlushICache(instrs.EntryPoint(), instrs.size());
 
   code.set_compile_timestamp(OS::GetCurrentMonotonicMicros());
+#ifndef PRODUCT
   CodeObservers::NotifyAll(name,
                            instrs.EntryPoint(),
                            assembler->prologue_offset(),
                            instrs.size(),
                            optimized);
+#endif
   {
     NoSafepointScope no_safepoint;
     const ZoneGrowableArray<intptr_t>& pointer_offsets =
@@ -13512,13 +13160,14 @@
                             bool optimized) {
   // Calling ToLibNamePrefixedQualifiedCString is very expensive,
   // try to avoid it.
+#ifndef PRODUCT
   if (CodeObservers::AreActive()) {
     return FinalizeCode(function.ToLibNamePrefixedQualifiedCString(),
                         assembler,
                         optimized);
-  } else {
-    return FinalizeCode("", assembler, optimized);
   }
+#endif  // !PRODUCT
+  return FinalizeCode("", assembler, optimized);
 }
 
 
@@ -13570,7 +13219,7 @@
 }
 
 
-intptr_t Code::GetTokenIndexOfPC(uword pc) const {
+TokenPosition Code::GetTokenIndexOfPC(uword pc) const {
   uword pc_offset = pc - EntryPoint();
   const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
@@ -13579,7 +13228,7 @@
       return iter.TokenPos();
     }
   }
-  return -1;
+  return TokenPosition::kNoSource;
 }
 
 
@@ -13623,7 +13272,6 @@
 }
 
 
-// Called by disassembler.
 RawString* Code::Name() const {
   const Object& obj = Object::Handle(owner());
   if (obj.IsNull()) {
@@ -13635,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();
 }
 
 
@@ -13717,106 +13352,6 @@
 }
 
 
-void Code::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Code", ref);
-  jsobj.AddFixedServiceId("code/%" Px64"-%" Px "",
-                          compile_timestamp(),
-                          EntryPoint());
-  const String& user_name = String::Handle(PrettyName());
-  const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  const bool is_stub = IsStubCode() || IsAllocationStubCode();
-  if (is_stub) {
-    jsobj.AddProperty("kind", "Stub");
-  } else {
-    jsobj.AddProperty("kind", "Dart");
-  }
-  jsobj.AddProperty("_optimized", is_optimized());
-  const Object& obj = Object::Handle(owner());
-  if (obj.IsFunction()) {
-    const Function& func = Function::Cast(obj);
-    jsobj.AddProperty("_intrinsic", func.is_intrinsic());
-    jsobj.AddProperty("_native", func.is_native());
-  } else {
-    jsobj.AddProperty("_intrinsic", false);
-    jsobj.AddProperty("_native", false);
-  }
-  if (ref) {
-    return;
-  }
-  if (obj.IsFunction()) {
-    jsobj.AddProperty("function", obj);
-  } else {
-    // Generate a fake function reference.
-    JSONObject func(&jsobj, "function");
-    func.AddProperty("type", "@Function");
-    func.AddProperty("_kind", "Stub");
-    func.AddProperty("name", user_name.ToCString());
-    AddNameProperties(&func, user_name, vm_name);
-  }
-  jsobj.AddPropertyF("_startAddress", "%" Px "", EntryPoint());
-  jsobj.AddPropertyF("_endAddress", "%" Px "", EntryPoint() + Size());
-  jsobj.AddProperty("_alive", is_alive());
-  const ObjectPool& object_pool = ObjectPool::Handle(GetObjectPool());
-  jsobj.AddProperty("_objectPool", object_pool);
-  {
-    JSONArray jsarr(&jsobj, "_disassembly");
-    if (is_alive()) {
-      // Only disassemble alive code objects.
-      DisassembleToJSONStream formatter(jsarr);
-      Disassemble(&formatter);
-    }
-  }
-  const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
-  if (!descriptors.IsNull()) {
-    JSONObject desc(&jsobj, "_descriptors");
-    descriptors.PrintToJSONObject(&desc, false);
-  }
-  const Array& inlined_function_table = Array::Handle(GetInlinedIdToFunction());
-  if (!inlined_function_table.IsNull() &&
-      (inlined_function_table.Length() > 0)) {
-    JSONArray inlined_functions(&jsobj, "_inlinedFunctions");
-    Function& function = Function::Handle();
-    for (intptr_t i = 0; i < inlined_function_table.Length(); i++) {
-      function ^= inlined_function_table.At(i);
-      ASSERT(!function.IsNull());
-      inlined_functions.AddValue(function);
-    }
-  }
-  const Array& intervals = Array::Handle(GetInlinedIntervals());
-  if (!intervals.IsNull() && (intervals.Length() > 0)) {
-    Smi& start = Smi::Handle();
-    Smi& end = Smi::Handle();
-    Smi& temp_smi = Smi::Handle();
-    JSONArray inline_intervals(&jsobj, "_inlinedIntervals");
-    for (intptr_t i = 0; i < intervals.Length() - Code::kInlIntNumEntries;
-         i += Code::kInlIntNumEntries) {
-      start ^= intervals.At(i + Code::kInlIntStart);
-      if (start.IsNull()) {
-        continue;
-      }
-      end ^= intervals.At(i + Code::kInlIntNumEntries + Code::kInlIntStart);
-
-      // Format: [start, end, inline functions...]
-      JSONArray inline_interval(&inline_intervals);
-      inline_interval.AddValue(start.Value());
-      inline_interval.AddValue(end.Value());
-
-      temp_smi ^= intervals.At(i + Code::kInlIntInliningId);
-      intptr_t inlining_id = temp_smi.Value();
-      ASSERT(inlining_id >= 0);
-      intptr_t caller_id = GetCallerId(inlining_id);
-      while (inlining_id >= 0) {
-        inline_interval.AddValue(inlining_id);
-        inlining_id = caller_id;
-        caller_id = GetCallerId(inlining_id);
-      }
-    }
-  }
-}
-
-
 uword Code::GetLazyDeoptPc() const {
   return (lazy_deopt_pc_offset() != kInvalidPc)
       ? EntryPoint() + lazy_deopt_pc_offset() : 0;
@@ -13945,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());
@@ -14027,34 +13569,6 @@
 }
 
 
-void Context::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  // TODO(turnidge): Should the user level type for Context be Context
-  // or Object?
-  AddCommonObjectProperties(&jsobj, "Context", ref);
-  jsobj.AddServiceId(*this);
-
-  jsobj.AddProperty("length", num_variables());
-
-  if (ref) {
-    return;
-  }
-
-  const Context& parent_context = Context::Handle(parent());
-  if (!parent_context.IsNull()) {
-    jsobj.AddProperty("parent", parent_context);
-  }
-
-  JSONArray jsarr(&jsobj, "variables");
-  Object& var = Object::Handle();
-  for (intptr_t index = 0; index < num_variables(); index++) {
-    var = At(index);
-    JSONObject jselement(&jsarr);
-    jselement.AddProperty("value", var);
-  }
-}
-
-
 RawContextScope* ContextScope::New(intptr_t num_variables, bool is_implicit) {
   ASSERT(Object::context_scope_class() != Class::null());
   if (num_variables < 0 || num_variables > kMaxElements) {
@@ -14077,15 +13591,15 @@
 }
 
 
-intptr_t ContextScope::TokenIndexAt(intptr_t scope_index) const {
-  return Smi::Value(VariableDescAddr(scope_index)->token_pos);
+TokenPosition ContextScope::TokenIndexAt(intptr_t scope_index) const {
+  return TokenPosition(Smi::Value(VariableDescAddr(scope_index)->token_pos));
 }
 
 
 void ContextScope::SetTokenIndexAt(intptr_t scope_index,
-                                   intptr_t token_pos) const {
+                                   TokenPosition token_pos) const {
   StoreSmi(&VariableDescAddr(scope_index)->token_pos,
-           Smi::New(token_pos));
+           Smi::New(token_pos.value()));
 }
 
 
@@ -14176,23 +13690,18 @@
   for (int i = 0; i < num_variables(); i++) {
     name = NameAt(i);
     const char* cname = name.ToCString();
-    intptr_t pos = TokenIndexAt(i);
+    TokenPosition pos = TokenIndexAt(i);
     intptr_t idx = ContextIndexAt(i);
     intptr_t lvl = ContextLevelAt(i);
     char* chars = OS::SCreate(Thread::Current()->zone(),
-        "%s\nvar %s  token-pos %" Pd "  ctx lvl %" Pd "  index %" Pd "",
-        prev_cstr, cname, pos, lvl, idx);
+        "%s\nvar %s  token-pos %s  ctx lvl %" Pd "  index %" Pd "",
+        prev_cstr, cname, pos.ToCString(), lvl, idx);
     prev_cstr = chars;
   }
   return prev_cstr;
 }
 
 
-void ContextScope::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 RawArray* MegamorphicCache::buckets() const {
   return raw_ptr()->buckets_;
 }
@@ -14333,21 +13842,6 @@
 }
 
 
-void MegamorphicCache::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Object", ref);
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("_selector", String::Handle(target_name()).ToCString());
-  if (ref) {
-    return;
-  }
-  jsobj.AddProperty("_buckets", Object::Handle(buckets()));
-  jsobj.AddProperty("_mask", mask());
-  jsobj.AddProperty("_argumentsDescriptor",
-                    Object::Handle(arguments_descriptor()));
-}
-
-
 RawSubtypeTestCache* SubtypeTestCache::New() {
   ASSERT(Object::subtypetestcache_class() != Class::null());
   SubtypeTestCache& result = SubtypeTestCache::Handle();
@@ -14379,7 +13873,7 @@
 
 
 void SubtypeTestCache::AddCheck(
-    intptr_t instance_class_id,
+    const Object& instance_class_id_or_function,
     const TypeArguments& instance_type_arguments,
     const TypeArguments& instantiator_type_arguments,
     const Bool& test_result) const {
@@ -14389,24 +13883,24 @@
   data = Array::Grow(data, new_len);
   set_cache(data);
   intptr_t data_pos = old_num * kTestEntryLength;
-  data.SetAt(data_pos + kInstanceClassId,
-      Smi::Handle(Smi::New(instance_class_id)));
+  data.SetAt(data_pos + kInstanceClassIdOrFunction,
+             instance_class_id_or_function);
   data.SetAt(data_pos + kInstanceTypeArguments, instance_type_arguments);
   data.SetAt(data_pos + kInstantiatorTypeArguments,
-      instantiator_type_arguments);
+             instantiator_type_arguments);
   data.SetAt(data_pos + kTestResult, test_result);
 }
 
 
 void SubtypeTestCache::GetCheck(intptr_t ix,
-                                intptr_t* instance_class_id,
+                                Object* instance_class_id_or_function,
                                 TypeArguments* instance_type_arguments,
                                 TypeArguments* instantiator_type_arguments,
                                 Bool* test_result) const {
   Array& data = Array::Handle(cache());
   intptr_t data_pos = ix * kTestEntryLength;
-  *instance_class_id =
-      Smi::Value(Smi::RawCast(data.At(data_pos + kInstanceClassId)));
+  *instance_class_id_or_function =
+      data.At(data_pos + kInstanceClassIdOrFunction);
   *instance_type_arguments ^= data.At(data_pos + kInstanceTypeArguments);
   *instantiator_type_arguments ^=
       data.At(data_pos + kInstantiatorTypeArguments);
@@ -14419,11 +13913,6 @@
 }
 
 
-void SubtypeTestCache::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
-
 const char* Error::ToErrorCString() const {
   UNREACHABLE();
   return "Internal Error";
@@ -14437,11 +13926,6 @@
 }
 
 
-void Error::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  UNREACHABLE();
-}
-
-
 RawApiError* ApiError::New() {
   ASSERT(Object::api_error_class() != Class::null());
   RawObject* raw = Object::Allocate(ApiError::kClassId,
@@ -14482,15 +13966,6 @@
 }
 
 
-void ApiError::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Error", ref);
-  jsobj.AddProperty("kind", "InternalError");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("message", ToErrorCString());
-}
-
-
 RawLanguageError* LanguageError::New() {
   ASSERT(Object::language_error_class() != Class::null());
   RawObject* raw = Object::Allocate(LanguageError::kClassId,
@@ -14502,7 +13977,8 @@
 
 RawLanguageError* LanguageError::NewFormattedV(const Error& prev_error,
                                                const Script& script,
-                                               intptr_t token_pos,
+                                               TokenPosition token_pos,
+                                               bool report_after_token,
                                                Report::Kind kind,
                                                Heap::Space space,
                                                const char* format,
@@ -14519,6 +13995,7 @@
   result.set_previous_error(prev_error);
   result.set_script(script);
   result.set_token_pos(token_pos);
+  result.set_report_after_token(report_after_token);
   result.set_kind(kind);
   result.set_message(String::Handle(
       String::NewFormattedV(format, args, space)));
@@ -14528,14 +14005,16 @@
 
 RawLanguageError* LanguageError::NewFormatted(const Error& prev_error,
                                               const Script& script,
-                                              intptr_t token_pos,
+                                              TokenPosition token_pos,
+                                              bool report_after_token,
                                               Report::Kind kind,
                                               Heap::Space space,
                                               const char* format, ...) {
   va_list args;
   va_start(args, format);
   RawLanguageError* result = LanguageError::NewFormattedV(
-      prev_error, script, token_pos, kind, space, format, args);
+      prev_error, script, token_pos, report_after_token,
+      kind, space, format, args);
   NoSafepointScope no_safepoint;
   va_end(args);
   return result;
@@ -14570,12 +14049,17 @@
 }
 
 
-void LanguageError::set_token_pos(intptr_t token_pos) const {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+void LanguageError::set_token_pos(TokenPosition token_pos) const {
+  ASSERT(!token_pos.IsClassifying());
   StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
 }
 
 
+void LanguageError::set_report_after_token(bool value) {
+  StoreNonPointer(&raw_ptr()->report_after_token_, value);
+}
+
+
 void LanguageError::set_kind(uint8_t value) const {
   StoreNonPointer(&raw_ptr()->kind_, value);
 }
@@ -14599,6 +14083,7 @@
       Report::PrependSnippet(kind(),
                              Script::Handle(script()),
                              token_pos(),
+                             report_after_token(),
                              String::Handle(message())));
   // Prepend previous error message.
   const Error& prev_error = Error::Handle(previous_error());
@@ -14622,15 +14107,6 @@
 }
 
 
-void LanguageError::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Error", ref);
-  jsobj.AddProperty("kind", "LanguageError");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("message", ToErrorCString());
-}
-
-
 RawUnhandledException* UnhandledException::New(const Instance& exception,
                                                const Instance& stacktrace,
                                                Heap::Space space) {
@@ -14711,25 +14187,6 @@
 }
 
 
-
-void UnhandledException::PrintJSONImpl(JSONStream* stream,
-                                       bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Error", ref);
-  jsobj.AddProperty("kind", "UnhandledException");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("message", ToErrorCString());
-  if (ref) {
-    return;
-  }
-  Instance& instance = Instance::Handle();
-  instance = exception();
-  jsobj.AddProperty("exception", instance);
-  instance = stacktrace();
-  jsobj.AddProperty("stacktrace", instance);
-}
-
-
 RawUnwindError* UnwindError::New(const String& message, Heap::Space space) {
   ASSERT(Object::unwind_error_class() != Class::null());
   UnwindError& result = UnwindError::Handle();
@@ -14773,17 +14230,6 @@
 }
 
 
-void UnwindError::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  AddCommonObjectProperties(&jsobj, "Error", ref);
-  jsobj.AddProperty("kind", "TerminationError");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("message", ToErrorCString());
-  jsobj.AddProperty("_is_user_initiated", is_user_initiated());
-  jsobj.AddProperty("_is_vm_restart", is_vm_restart());
-}
-
-
 RawObject* Instance::Evaluate(const String& expr,
                               const Array& param_names,
                               const Array& param_values) const {
@@ -14955,11 +14401,32 @@
 }
 
 
-RawType* Instance::GetType() const {
+RawAbstractType* Instance::GetType() const {
   if (IsNull()) {
     return Type::NullType();
   }
   const Class& cls = Class::Handle(clazz());
+  if (cls.IsClosureClass()) {
+    const Function& signature =
+        Function::Handle(Closure::Cast(*this).function());
+    FunctionType& type = FunctionType::Handle(signature.SignatureType());
+    if (type.scope_class() == cls.raw()) {
+      // Type is not parameterized.
+      if (!type.IsCanonical()) {
+        type ^= type.Canonicalize();
+        signature.SetSignatureType(type);
+      }
+      return type.raw();
+    }
+    const Class& scope_cls = Class::Handle(type.scope_class());
+    ASSERT(scope_cls.NumTypeArguments() > 0);
+    TypeArguments& type_arguments = TypeArguments::Handle(GetTypeArguments());
+    type = FunctionType::New(
+        scope_cls, type_arguments, signature, TokenPosition::kNoSource);
+    type.SetIsFinalized();
+    type ^= type.Canonicalize();
+    return type.raw();
+  }
   Type& type = Type::Handle();
   if (!cls.IsGeneric()) {
     type = cls.CanonicalType();
@@ -14969,7 +14436,7 @@
     if (cls.NumTypeArguments() > 0) {
       type_arguments = GetTypeArguments();
     }
-    type = Type::New(cls, type_arguments, Scanner::kNoSourcePos);
+    type = Type::New(cls, type_arguments, TokenPosition::kNoSource);
     type.SetIsFinalized();
     type ^= type.Canonicalize();
   }
@@ -15001,6 +14468,7 @@
                             Error* bound_error) const {
   ASSERT(other.IsFinalized());
   ASSERT(!other.IsDynamicType());
+  ASSERT(!other.IsTypeRef());  // Must be dereferenced at compile time.
   ASSERT(!other.IsMalformed());
   ASSERT(!other.IsMalbounded());
   if (other.IsVoidType()) {
@@ -15008,6 +14476,51 @@
   }
   Zone* zone = Thread::Current()->zone();
   const Class& cls = Class::Handle(zone, clazz());
+  if (cls.IsClosureClass()) {
+    if (other.IsObjectType() || other.IsDartFunctionType()) {
+      return true;
+    }
+    Function& other_signature = Function::Handle(zone);
+    TypeArguments& other_type_arguments = TypeArguments::Handle(zone);
+    // Note that we may encounter a bound error in checked mode.
+    if (!other.IsInstantiated()) {
+      AbstractType& instantiated_other = AbstractType::Handle(
+          zone, other.InstantiateFrom(other_instantiator, bound_error,
+                                      NULL, NULL, Heap::kOld));
+      if ((bound_error != NULL) && !bound_error->IsNull()) {
+        ASSERT(Isolate::Current()->type_checks());
+        return false;
+      }
+      if (instantiated_other.IsTypeRef()) {
+        instantiated_other = TypeRef::Cast(instantiated_other).type();
+      }
+      if (instantiated_other.IsDynamicType() ||
+          instantiated_other.IsObjectType() ||
+          instantiated_other.IsDartFunctionType()) {
+        return true;
+      }
+      if (!instantiated_other.IsFunctionType()) {
+        return false;
+      }
+      other_signature = FunctionType::Cast(instantiated_other).signature();
+      other_type_arguments = instantiated_other.arguments();
+    } else {
+      if (!other.IsFunctionType()) {
+        return false;
+      }
+      other_signature = FunctionType::Cast(other).signature();
+      other_type_arguments = other.arguments();
+    }
+    const Function& signature =
+        Function::Handle(zone, Closure::Cast(*this).function());
+    const TypeArguments& type_arguments =
+        TypeArguments::Handle(zone, GetTypeArguments());
+    return signature.IsSubtypeOf(type_arguments,
+                                 other_signature,
+                                 other_type_arguments,
+                                 bound_error,
+                                 Heap::kOld);
+  }
   TypeArguments& type_arguments = TypeArguments::Handle(zone);
   if (cls.NumTypeArguments() > 0) {
     type_arguments = GetTypeArguments();
@@ -15025,22 +14538,57 @@
   }
   Class& other_class = Class::Handle(zone);
   TypeArguments& other_type_arguments = TypeArguments::Handle(zone);
+  AbstractType& instantiated_other = AbstractType::Handle(zone, other.raw());
   // Note that we may encounter a bound error in checked mode.
   if (!other.IsInstantiated()) {
-    const AbstractType& instantiated_other = AbstractType::Handle(
-        zone, other.InstantiateFrom(other_instantiator, bound_error));
+    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;
     }
-    other_class = instantiated_other.type_class();
-    other_type_arguments = instantiated_other.arguments();
-  } else {
-    other_class = other.type_class();
-    other_type_arguments = other.arguments();
+    if (instantiated_other.IsTypeRef()) {
+      instantiated_other = TypeRef::Cast(instantiated_other).type();
+    }
+    if (instantiated_other.IsDynamicType()) {
+      return true;
+    }
   }
+  other_type_arguments = instantiated_other.arguments();
+  const bool other_is_dart_function = instantiated_other.IsDartFunctionType();
+  if (other_is_dart_function || instantiated_other.IsFunctionType()) {
+    // Check if this instance understands a call() method of a compatible type.
+    Function& call = Function::Handle(zone,
+        cls.LookupDynamicFunctionAllowAbstract(Symbols::Call()));
+    if (call.IsNull()) {
+      // Walk up the super_class chain.
+      Class& super_cls = Class::Handle(zone, cls.SuperClass());
+      while (!super_cls.IsNull() && call.IsNull()) {
+        call = super_cls.LookupDynamicFunctionAllowAbstract(Symbols::Call());
+        super_cls = super_cls.SuperClass();
+      }
+    }
+    if (!call.IsNull()) {
+      if (other_is_dart_function) {
+        return true;
+      }
+      const Function& other_signature = Function::Handle(
+          zone, FunctionType::Cast(instantiated_other).signature());
+      if (call.IsSubtypeOf(type_arguments,
+                           other_signature,
+                           other_type_arguments,
+                           bound_error,
+                           Heap::kOld)) {
+        return true;
+      }
+    }
+  }
+  if (!instantiated_other.IsType()) {
+    return false;
+  }
+  other_class = instantiated_other.type_class();
   return cls.IsSubtypeOf(type_arguments, other_class, other_type_arguments,
-                         bound_error, Heap::kOld);
+                         bound_error, NULL, Heap::kOld);
 }
 
 
@@ -15104,17 +14652,11 @@
 }
 
 
-bool Instance::IsClosure() const {
-  const Class& cls = Class::Handle(clazz());
-  return cls.IsSignatureClass();
-}
-
-
 bool Instance::IsCallable(Function* function) const {
   Class& cls = Class::Handle(clazz());
-  if (cls.IsSignatureClass()) {
+  if (cls.IsClosureClass()) {
     if (function != NULL) {
-      *function = Closure::function(*this);
+      *function = Closure::Cast(*this).function();
     }
     return true;
   }
@@ -15219,7 +14761,7 @@
     return "Instance";
   } else {
     if (IsClosure()) {
-      return Closure::ToCString(*this);
+      return Closure::Cast(*this).ToCString();
     }
     const Class& cls = Class::Handle(clazz());
     TypeArguments& type_arguments = TypeArguments::Handle();
@@ -15227,8 +14769,8 @@
     if (num_type_arguments > 0) {
       type_arguments = GetTypeArguments();
     }
-    const Type& type =
-        Type::Handle(Type::New(cls, type_arguments, Scanner::kNoSourcePos));
+    const Type& type = Type::Handle(
+        Type::New(cls, type_arguments, TokenPosition::kNoSource));
     const String& type_name = String::Handle(type.UserVisibleName());
     return OS::SCreate(Thread::Current()->zone(),
         "Instance of '%s'", type_name.ToCString());
@@ -15236,91 +14778,6 @@
 }
 
 
-void Instance::PrintSharedInstanceJSON(JSONObject* jsobj,
-                                       bool ref) const {
-  AddCommonObjectProperties(jsobj, "Instance", ref);
-  if (ref) {
-    return;
-  }
-
-  // Walk the superclass chain, adding all instance fields.
-  Class& cls = Class::Handle(this->clazz());
-  {
-    Instance& fieldValue = Instance::Handle();
-    JSONArray jsarr(jsobj, "fields");
-    while (!cls.IsNull()) {
-      const Array& field_array = Array::Handle(cls.fields());
-      Field& field = Field::Handle();
-      if (!field_array.IsNull()) {
-        for (intptr_t i = 0; i < field_array.Length(); i++) {
-          field ^= field_array.At(i);
-          if (!field.is_static()) {
-            fieldValue ^= GetField(field);
-            JSONObject jsfield(&jsarr);
-            jsfield.AddProperty("type", "BoundField");
-            jsfield.AddProperty("decl", field);
-            jsfield.AddProperty("value", fieldValue);
-          }
-        }
-      }
-      cls = cls.SuperClass();
-    }
-  }
-
-  if (NumNativeFields() > 0) {
-    JSONArray jsarr(jsobj, "_nativeFields");
-    for (intptr_t i = 0; i < NumNativeFields(); i++) {
-      intptr_t value = GetNativeField(i);
-      JSONObject jsfield(&jsarr);
-      jsfield.AddProperty("index", i);
-      jsfield.AddProperty("value", value);
-    }
-  }
-}
-
-
-void Instance::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-
-  // Handle certain special instance values.
-  if (raw() == Object::sentinel().raw()) {
-    jsobj.AddProperty("type", "Sentinel");
-    jsobj.AddProperty("kind", "NotInitialized");
-    jsobj.AddProperty("valueAsString", "<not initialized>");
-    return;
-  } else if (raw() == Object::transition_sentinel().raw()) {
-    jsobj.AddProperty("type", "Sentinel");
-    jsobj.AddProperty("kind", "BeingInitialized");
-    jsobj.AddProperty("valueAsString", "<being initialized>");
-    return;
-  }
-
-  PrintSharedInstanceJSON(&jsobj, ref);
-  if (IsClosure()) {
-    jsobj.AddProperty("kind", "Closure");
-  } else {
-    jsobj.AddProperty("kind", "PlainInstance");
-  }
-  jsobj.AddServiceId(*this);
-  if (IsClosure()) {
-    jsobj.AddProperty("closureFunction",
-                      Function::Handle(Closure::function(*this)));
-    jsobj.AddProperty("closureContext",
-                      Context::Handle(Closure::context(*this)));
-  }
-  if (ref) {
-    return;
-  }
-  if (IsClosure()) {
-    Debugger* debugger = Isolate::Current()->debugger();
-    Breakpoint* bpt = debugger->BreakpointAtActivation(*this);
-    if (bpt != NULL) {
-      jsobj.AddProperty("_activationBreakpoint", bpt);
-    }
-  }
-}
-
-
 bool AbstractType::IsResolved() const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -15328,6 +14785,12 @@
 }
 
 
+void AbstractType::SetIsResolved() const {
+  // AbstractType is an abstract class.
+  UNREACHABLE();
+}
+
+
 bool AbstractType::HasResolvedTypeClass() const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -15356,10 +14819,15 @@
 }
 
 
-intptr_t AbstractType::token_pos() const {
+void AbstractType::set_arguments(const TypeArguments& value) const {
   // AbstractType is an abstract class.
   UNREACHABLE();
-  return -1;
+}
+
+TokenPosition AbstractType::token_pos() const {
+  // AbstractType is an abstract class.
+  UNREACHABLE();
+  return TokenPosition::kNoSource;
 }
 
 
@@ -15377,6 +14845,12 @@
 }
 
 
+void AbstractType::SetIsFinalized() const {
+  // AbstractType is an abstract class.
+  UNREACHABLE();
+}
+
+
 bool AbstractType::IsBeingFinalized() const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -15384,6 +14858,12 @@
 }
 
 
+void AbstractType::SetIsBeingFinalized() const {
+  // AbstractType is an abstract class.
+  UNREACHABLE();
+}
+
+
 bool AbstractType::IsMalformed() const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -15435,7 +14915,8 @@
 RawAbstractType* AbstractType::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail,
+    TrailPtr instantiation_trail,
+    TrailPtr bound_trail,
     Heap::Space space) const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -15465,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();
@@ -15495,14 +14983,54 @@
 }
 
 
+bool AbstractType::TestAndAddToTrail(TrailPtr* trail) const {
+  if (*trail == NULL) {
+    *trail = new Trail(Thread::Current()->zone(), 4);
+  } else {
+    const intptr_t len = (*trail)->length();
+    for (intptr_t i = 0; i < len; i++) {
+      if ((*trail)->At(i).raw() == this->raw()) {
+        return true;
+      }
+    }
+  }
+  (*trail)->Add(*this);
+  return false;
+}
+
+
+bool AbstractType::TestAndAddBuddyToTrail(TrailPtr* trail,
+                                          const AbstractType& buddy) const {
+  if (*trail == NULL) {
+    *trail = new Trail(Thread::Current()->zone(), 4);
+  } else {
+    const intptr_t len = (*trail)->length();
+    ASSERT((len % 2) == 0);
+    const bool this_is_typeref = IsTypeRef();
+    const bool buddy_is_typeref = buddy.IsTypeRef();
+    ASSERT(this_is_typeref || buddy_is_typeref);
+    for (intptr_t i = 0; i < len; i += 2) {
+      if ((((*trail)->At(i).raw() == this->raw()) ||
+           (buddy_is_typeref && (*trail)->At(i).Equals(*this))) &&
+          (((*trail)->At(i + 1).raw() == buddy.raw()) ||
+           (this_is_typeref && (*trail)->At(i + 1).Equals(buddy)))) {
+        return true;
+      }
+    }
+  }
+  (*trail)->Add(*this);
+  (*trail)->Add(buddy);
+  return false;
+}
+
+
 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);
@@ -15538,8 +15066,30 @@
   String& class_name = String::Handle(zone);
   intptr_t first_type_param_index;
   intptr_t num_type_params;  // Number of type parameters to print.
-  if (HasResolvedTypeClass()) {
-    const Class& cls = Class::Handle(zone, type_class());
+  Class& cls = Class::Handle(zone);
+  if (IsFunctionType()) {
+    cls = type_class();
+    const Function& signature_function = Function::Handle(
+        zone, FunctionType::Cast(*this).signature());
+    if (!cls.IsTypedefClass() ||
+        (cls.signature_function() != signature_function.raw())) {
+      if (!IsFinalized() || IsBeingFinalized() || IsMalformed()) {
+        return signature_function.UserVisibleSignature();
+      }
+      return signature_function.InstantiatedSignatureFrom(args,
+                                                          name_visibility);
+    }
+    class_name = cls.Name();  // Typedef name.
+    // We may be reporting an error about a malformed function type. In that
+    // case, avoid instantiating the signature, since it may cause divergence.
+    if (!IsFinalized() || IsBeingFinalized() || IsMalformed()) {
+      return class_name.raw();
+    }
+    // Print the name of a typedef as a regular, possibly parameterized, class.
+  } else if (HasResolvedTypeClass()) {
+    cls = type_class();
+  }
+  if (!cls.IsNull()) {
     if (IsResolved() || !cls.IsMixinApplication()) {
       // Do not print the full vector, but only the declared type parameters.
       num_type_params = cls.NumTypeParameters();
@@ -15550,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.
@@ -15577,29 +15125,8 @@
         first_type_param_index = num_args - num_type_params;
       }
     }
-    if (cls.IsSignatureClass()) {
-      // We may be reporting an error about a malformed function type. In that
-      // case, avoid instantiating the signature, since it may cause divergence.
-      if (!IsFinalized() || IsBeingFinalized() || IsMalformed()) {
-        return class_name.raw();
-      }
-      // To avoid divergence, print the name of a typedef (non-canonical
-      // signature class) as a regular, possibly parameterized, class.
-      if (cls.IsCanonicalSignatureClass()) {
-        const Function& signature_function = Function::Handle(
-            zone, cls.signature_function());
-        // Signature classes have no super type, however, they take as many
-        // type arguments as the owner class of their signature function (if it
-        // is non static and generic, see Class::NumTypeArguments()). Therefore,
-        // first_type_param_index may be greater than 0 here.
-        return signature_function.InstantiatedSignatureFrom(args,
-                                                            name_visibility);
-      }
-    }
   } else {
-    const UnresolvedClass& cls =
-        UnresolvedClass::Handle(zone, unresolved_class());
-    class_name = cls.Name();
+    class_name = UnresolvedClass::Handle(zone, unresolved_class()).Name();
     num_type_params = num_args;
     first_type_param_index = 0;
   }
@@ -15622,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();
@@ -15691,7 +15241,7 @@
 }
 
 
-bool AbstractType::IsFunctionType() const {
+bool AbstractType::IsDartFunctionType() const {
   return HasResolvedTypeClass() &&
       (type_class() == Type::Handle(Type::Function()).type_class());
 }
@@ -15700,6 +15250,7 @@
 bool AbstractType::TypeTest(TypeTestKind test_kind,
                             const AbstractType& other,
                             Error* bound_error,
+                            TrailPtr bound_trail,
                             Heap::Space space) const {
   ASSERT(IsFinalized());
   ASSERT(other.IsFinalized());
@@ -15716,19 +15267,22 @@
   // 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();
     }
     return false;
   }
+  if (other.IsObjectType() || other.IsDynamicType()) {
+    return true;
+  }
   if (IsBoundedType() || other.IsBoundedType()) {
     if (Equals(other)) {
       return true;
@@ -15740,6 +15294,7 @@
     }
     return false;  // TODO(regis): We should return "maybe after instantiation".
   }
+  Zone* zone = Thread::Current()->zone();
   // Type parameters cannot be handled by Class::TypeTest().
   // When comparing two uninstantiated function types, one returning type
   // parameter K, the other returning type parameter V, we cannot assume that K
@@ -15748,7 +15303,7 @@
   // The same rule applies when checking the upper bound of a still
   // uninstantiated type at compile time. Returning false will defer the test
   // to run time.
-  // There are however some cases can be decided at compile time.
+  // There are however some cases that can be decided at compile time.
   // For example, with class A<K, V extends K>, new A<T, T> called from within
   // a class B<T> will never require a run time bound check, even if T is
   // uninstantiated at compile time.
@@ -15760,13 +15315,15 @@
         return true;
       }
     }
-    const AbstractType& bound = AbstractType::Handle(type_param.bound());
+    const AbstractType& bound = AbstractType::Handle(zone, type_param.bound());
     // We may be checking bounds at finalization time and can encounter
     // a still unfinalized bound. Finalizing the bound here may lead to cycles.
     if (!bound.IsFinalized()) {
       return false;    // TODO(regis): Return "maybe after instantiation".
     }
-    if (bound.IsMoreSpecificThan(other, bound_error)) {
+    // The current bound_trail cannot be used, because operands are swapped and
+    // the test is different anyway (more specific vs. subtype).
+    if (bound.IsMoreSpecificThan(other, bound_error, NULL, space)) {
       return true;
     }
     return false;  // TODO(regis): We should return "maybe after instantiation".
@@ -15774,13 +15331,60 @@
   if (other.IsTypeParameter()) {
     return false;  // TODO(regis): We should return "maybe after instantiation".
   }
-  const Class& cls = Class::Handle(type_class());
-  return cls.TypeTest(test_kind,
-                      TypeArguments::Handle(arguments()),
-                      Class::Handle(other.type_class()),
-                      TypeArguments::Handle(other.arguments()),
-                      bound_error,
-                      space);
+  const Class& type_cls = Class::Handle(zone, type_class());
+  // Function types cannot be handled by Class::TypeTest().
+  const bool other_is_dart_function_type = other.IsDartFunctionType();
+  if (other_is_dart_function_type || other.IsFunctionType()) {
+    if (IsFunctionType()) {
+      if (other_is_dart_function_type) {
+        return true;
+      }
+      const Function& other_fun =
+          Function::Handle(zone, FunctionType::Cast(other).signature());
+      // Check for two function types.
+      const Function& fun =
+          Function::Handle(zone, FunctionType::Cast(*this).signature());
+      return fun.TypeTest(test_kind,
+                          TypeArguments::Handle(zone, arguments()),
+                          other_fun,
+                          TypeArguments::Handle(zone, other.arguments()),
+                          bound_error,
+                          space);
+    }
+    // Check if type S has a call() method of function type T.
+    Function& function = Function::Handle(zone,
+        type_cls.LookupDynamicFunctionAllowAbstract(Symbols::Call()));
+    if (function.IsNull()) {
+      // Walk up the super_class chain.
+      Class& cls = Class::Handle(zone, type_cls.SuperClass());
+      while (!cls.IsNull() && function.IsNull()) {
+        function = cls.LookupDynamicFunctionAllowAbstract(Symbols::Call());
+        cls = cls.SuperClass();
+      }
+    }
+    if (!function.IsNull()) {
+      if (other_is_dart_function_type ||
+          function.TypeTest(test_kind,
+                            TypeArguments::Handle(zone, arguments()),
+                            Function::Handle(
+                                zone, FunctionType::Cast(other).signature()),
+                            TypeArguments::Handle(zone, other.arguments()),
+                            bound_error,
+                            space)) {
+        return true;
+      }
+    }
+  }
+  if (IsFunctionType()) {
+    return false;
+  }
+  return type_cls.TypeTest(test_kind,
+                           TypeArguments::Handle(zone, arguments()),
+                           Class::Handle(zone, other.type_class()),
+                           TypeArguments::Handle(zone, other.arguments()),
+                           bound_error,
+                           bound_trail,
+                           space);
 }
 
 
@@ -15798,11 +15402,6 @@
 }
 
 
-void AbstractType::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  UNREACHABLE();
-}
-
-
 RawType* Type::NullType() {
   return Isolate::Current()->object_store()->null_type();
 }
@@ -15890,7 +15489,7 @@
     const TypeArguments& no_type_arguments = TypeArguments::Handle();
     type ^= Type::New(Object::Handle(type_class.raw()),
                       no_type_arguments,
-                      Scanner::kNoSourcePos);
+                      TokenPosition::kNoSource);
     type.SetIsFinalized();
     type ^= type.Canonicalize();
   }
@@ -15910,14 +15509,7 @@
 }
 
 
-void Type::ResetIsFinalized() const {
-  ASSERT(IsFinalized());
-  set_type_state(RawType::kBeingFinalized);
-  SetIsFinalized();
-}
-
-
-void Type::set_is_being_finalized() const {
+void Type::SetIsBeingFinalized() const {
   ASSERT(IsResolved() && !IsFinalized() && !IsBeingFinalized());
   set_type_state(RawType::kBeingFinalized);
 }
@@ -15933,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()) {
@@ -15953,7 +15545,7 @@
     return true;
   }
   ASSERT(type_error.kind() == Report::kMalboundedType);
-  return Isolate::Current()->flags().type_checks();
+  return Isolate::Current()->type_checks();
 }
 
 
@@ -15962,8 +15554,10 @@
 }
 
 
-void Type::set_is_resolved() const {
+void Type::SetIsResolved() const {
   ASSERT(!IsResolved());
+  // A Typedef is a FunctionType, not a type.
+  ASSERT(!Class::Handle(type_class()).IsTypedefClass());
   set_type_state(RawType::kResolved);
 }
 
@@ -16001,11 +15595,6 @@
 }
 
 
-RawTypeArguments* Type::arguments() const {
-  return raw_ptr()->arguments_;
-}
-
-
 bool Type::IsInstantiated(TrailPtr trail) const {
   if (raw_ptr()->type_state_ == RawType::kFinalizedInstantiated) {
     return true;
@@ -16021,7 +15610,6 @@
   intptr_t len = num_type_args;  // Check the full vector of type args.
   ASSERT(num_type_args > 0);
   // This type is not instantiated if it refers to type parameters.
-  // This IsInstantiated() call may be invoked on an unresolved signature type.
   // Although this type may still be unresolved, the type parameters it may
   // refer to are resolved by definition. We can therefore return the correct
   // result even for an unresolved type. We just need to look at all type
@@ -16040,7 +15628,8 @@
 RawAbstractType* Type::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail,
+    TrailPtr instantiation_trail,
+    TrailPtr bound_trail,
     Heap::Space space) const {
   Zone* zone = Thread::Current()->zone();
   ASSERT(IsFinalized() || IsBeingFinalized());
@@ -16054,35 +15643,25 @@
   if (arguments() == instantiator_type_arguments.raw()) {
     return raw();
   }
-  // If this type is recursive, we may already be instantiating it.
-  Type& instantiated_type = Type::Handle(zone);
-  instantiated_type ^= OnlyBuddyInTrail(trail);
-  if (!instantiated_type.IsNull()) {
-    ASSERT(IsRecursive());
-    return instantiated_type.raw();
-  }
   // Note that the type class has to be resolved at this time, but not
   // necessarily finalized yet. We may be checking bounds at compile time or
   // finalizing the type argument vector of a recursive type.
   const Class& cls = Class::Handle(zone, type_class());
-
-  // This uninstantiated type is not modified, as it can be instantiated
-  // with different instantiators. Allocate a new instantiated version of it.
-  instantiated_type = Type::New(cls, TypeArguments::Handle(zone), token_pos());
   TypeArguments& type_arguments = TypeArguments::Handle(zone, arguments());
   ASSERT(type_arguments.Length() == cls.NumTypeArguments());
-  if (type_arguments.IsRecursive()) {
-    AddOnlyBuddyToTrail(&trail, instantiated_type);
-  }
   type_arguments = type_arguments.InstantiateFrom(instantiator_type_arguments,
                                                   bound_error,
-                                                  trail,
+                                                  instantiation_trail,
+                                                  bound_trail,
                                                   space);
-  instantiated_type.set_arguments(type_arguments);
+  // This uninstantiated type is not modified, as it can be instantiated
+  // with different instantiators. Allocate a new instantiated version of it.
+  const Type& instantiated_type =
+      Type::Handle(zone, Type::New(cls, type_arguments, token_pos(), space));
   if (IsFinalized()) {
     instantiated_type.SetIsFinalized();
   } else {
-    instantiated_type.set_is_resolved();
+    instantiated_type.SetIsResolved();
   }
   // Canonicalization is not part of instantiation.
   return instantiated_type.raw();
@@ -16184,9 +15763,9 @@
   ASSERT(!IsBeingFinalized());  // Cloning must occur prior to finalization.
   TypeArguments& type_args = TypeArguments::Handle(arguments());
   type_args = type_args.CloneUnfinalized();
-  const Class& type_cls = Class::Handle(type_class());
-  const Type& clone = Type::Handle(Type::New(type_cls, type_args, token_pos()));
-  clone.set_is_resolved();
+  const Type& clone = Type::Handle(
+      Type::New(Class::Handle(type_class()), type_args, token_pos()));
+  clone.SetIsResolved();
   return clone.raw();
 }
 
@@ -16228,25 +15807,36 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
-  Type& type = Type::Handle(zone);
+  AbstractType& type = Type::Handle(zone);
   const Class& cls = Class::Handle(zone, type_class());
+  ASSERT(!cls.IsTypedefClass());  // This type should be a FunctionType.
   if (cls.raw() == Object::dynamic_class() && (isolate != Dart::vm_isolate())) {
     return Object::dynamic_type().raw();
   }
   // Fast canonical lookup/registry for simple types.
-  if (!cls.IsGeneric()) {
+  if (!cls.IsGeneric() && !cls.IsClosureClass()) {
     type = cls.CanonicalType();
     if (type.IsNull()) {
       ASSERT(!cls.raw()->IsVMHeapObject() || (isolate == Dart::vm_isolate()));
       // Canonicalize the type arguments of the supertype, if any.
       TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
       type_args = type_args.Canonicalize(trail);
+      if (IsCanonical()) {
+        // Canonicalizing type_args canonicalized this type.
+        ASSERT(IsRecursive());
+        return this->raw();
+      }
       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));
@@ -16285,74 +15875,34 @@
   // vector may be longer than necessary. This is not an issue.
   ASSERT(type_args.IsNull() || (type_args.Length() >= cls.NumTypeArguments()));
   type_args = type_args.Canonicalize(trail);
+  if (IsCanonical()) {
+    // Canonicalizing type_args canonicalized this type as a side effect.
+    ASSERT(IsRecursive());
+    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);
-  if ((index == 1) && cls.IsCanonicalSignatureClass()) {
-    canonical_types.SetAt(0, *this);  // Also set canonical signature type at 0.
-#ifdef DEBUG
-    // Verify that the first canonical type is the signature type by checking
-    // that the type argument vector of the canonical type ends with the
-    // uninstantiated type parameters of the signature class. Note that these
-    // type parameters may be bounded if the super class of the owner class
-    // declares bounds.
-    // The signature type is finalized during class finalization, before the
-    // optimizer may canonicalize instantiated function types of the same
-    // signature class.
-    // Although the signature class extends class Instance, the type arguments
-    // of the super class of the owner class of its signature function will be
-    // prepended to the type argument vector during class finalization.
-    const TypeArguments& type_params =
-        TypeArguments::Handle(zone, cls.type_parameters());
-    const intptr_t num_type_params = cls.NumTypeParameters();
-    const intptr_t num_type_args = cls.NumTypeArguments();
-    AbstractType& type_arg = AbstractType::Handle(zone);
-    TypeParameter& type_param = TypeParameter::Handle(zone);
-    for (intptr_t i = 0; i < num_type_params; i++) {
-      type_arg = type_args.TypeAt(num_type_args - num_type_params + i);
-      while (type_arg.IsBoundedType()) {
-        type_arg = BoundedType::Cast(type_arg).type();
-      }
-      type_param ^= type_params.TypeAt(i);
-      ASSERT(type_arg.Equals(type_param));
-    }
-#endif
-  }
-  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);
 }
 
 
@@ -16373,6 +15923,7 @@
 
 
 void Type::set_arguments(const TypeArguments& value) const {
+  ASSERT(!IsCanonical());
   StorePointer(&raw_ptr()->arguments_, value.raw());
 }
 
@@ -16387,7 +15938,7 @@
 
 RawType* Type::New(const Object& clazz,
                    const TypeArguments& arguments,
-                   intptr_t token_pos,
+                   TokenPosition token_pos,
                    Heap::Space space) {
   const Type& result = Type::Handle(Type::New(space));
   result.set_type_class(clazz);
@@ -16398,8 +15949,8 @@
 }
 
 
-void Type::set_token_pos(intptr_t token_pos) const {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+void Type::set_token_pos(TokenPosition token_pos) const {
+  ASSERT(!token_pos.IsClassifying());
   StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
 }
 
@@ -16438,30 +15989,508 @@
 }
 
 
-void Type::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Type");
-  if (IsCanonical()) {
-    const Class& type_cls = Class::Handle(type_class());
-    intptr_t id = type_cls.FindCanonicalTypeIndex(*this);
-    ASSERT(id >= 0);
-    intptr_t cid = type_cls.id();
-    jsobj.AddFixedServiceId("classes/%" Pd "/types/%" Pd "", cid, id);
-    jsobj.AddProperty("typeClass", type_cls);
+void FunctionType::SetIsFinalized() const {
+  ASSERT(!IsFinalized());
+  if (IsInstantiated()) {
+    set_type_state(RawFunctionType::kFinalizedInstantiated);
   } else {
-    jsobj.AddServiceId(*this);
+    set_type_state(RawFunctionType::kFinalizedUninstantiated);
   }
-  const String& user_name = String::Handle(PrettyName());
-  const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  if (ref) {
-    return;
+}
+
+
+void FunctionType::ResetIsFinalized() const {
+  ASSERT(IsFinalized());
+  set_type_state(RawFunctionType::kBeingFinalized);
+  SetIsFinalized();
+}
+
+
+void FunctionType::SetIsBeingFinalized() const {
+  ASSERT(IsResolved() && !IsFinalized() && !IsBeingFinalized());
+  set_type_state(RawFunctionType::kBeingFinalized);
+}
+
+
+bool FunctionType::IsMalformed() const {
+  if (raw_ptr()->error_ == LanguageError::null()) {
+    return false;
   }
-  const TypeArguments& typeArgs = TypeArguments::Handle(arguments());
-  if (!typeArgs.IsNull()) {
-    jsobj.AddProperty("typeArguments", typeArgs);
+  const LanguageError& type_error = LanguageError::Handle(error());
+  return type_error.kind() == Report::kMalformedType;
+}
+
+
+bool FunctionType::IsMalbounded() const {
+  if (!Isolate::Current()->type_checks()) {
+    return false;
   }
+  if (raw_ptr()->error_ == LanguageError::null()) {
+    return false;
+  }
+  const LanguageError& type_error = LanguageError::Handle(error());
+  return type_error.kind() == Report::kMalboundedType;
+}
+
+
+bool FunctionType::IsMalformedOrMalbounded() const {
+  if (raw_ptr()->error_ == LanguageError::null()) {
+    return false;
+  }
+  const LanguageError& type_error = LanguageError::Handle(error());
+  if (type_error.kind() == Report::kMalformedType) {
+    return true;
+  }
+  ASSERT(type_error.kind() == Report::kMalboundedType);
+  return Isolate::Current()->type_checks();
+}
+
+
+void FunctionType::set_error(const LanguageError& value) const {
+  StorePointer(&raw_ptr()->error_, value.raw());
+}
+
+
+void FunctionType::SetIsResolved() const {
+  ASSERT(!IsResolved());
+  set_type_state(RawFunctionType::kResolved);
+}
+
+
+bool FunctionType::IsInstantiated(TrailPtr trail) const {
+  if (raw_ptr()->type_state_ == RawFunctionType::kFinalizedInstantiated) {
+    return true;
+  }
+  if (raw_ptr()->type_state_ == RawFunctionType::kFinalizedUninstantiated) {
+    return false;
+  }
+  if (arguments() == TypeArguments::null()) {
+    return true;
+  }
+  const Class& scope_cls = Class::Handle(scope_class());
+  if (!scope_cls.IsGeneric()) {
+    ASSERT(scope_cls.IsClosureClass() || scope_cls.IsTypedefClass());
+    ASSERT(arguments() == TypeArguments::null());
+    return true;
+  }
+  const TypeArguments& type_arguments = TypeArguments::Handle(arguments());
+  const intptr_t num_type_args = scope_cls.NumTypeArguments();
+  const intptr_t num_type_params = scope_cls.NumTypeParameters();
+  // The vector may be longer than necessary. An empty vector is handled above.
+  ASSERT(type_arguments.Length() >= num_type_args);
+  return
+      (num_type_params == 0) ||
+      type_arguments.IsSubvectorInstantiated(num_type_args - num_type_params,
+                                             num_type_params);
+}
+
+
+RawAbstractType* FunctionType::InstantiateFrom(
+    const TypeArguments& instantiator_type_arguments,
+    Error* bound_error,
+    TrailPtr instantiation_trail,
+    TrailPtr bound_trail,
+    Heap::Space space) const {
+  Zone* zone = Thread::Current()->zone();
+  ASSERT(IsFinalized() || IsBeingFinalized());
+  ASSERT(!IsInstantiated());
+  ASSERT(!IsMalformed());  // FunctionType cannot be malformed.
+  // Instantiating this type with its own type arguments as instantiator can
+  // occur during finalization and bounds checking. Return the type unchanged.
+  if (arguments() == instantiator_type_arguments.raw()) {
+    return raw();
+  }
+  // Note that the scope class has to be resolved at this time, but not
+  // necessarily finalized yet. We may be checking bounds at compile time or
+  // finalizing the type argument vector of a recursive type.
+  const Class& cls = Class::Handle(zone, scope_class());
+  TypeArguments& type_arguments = TypeArguments::Handle(zone, arguments());
+  ASSERT(type_arguments.Length() == cls.NumTypeArguments());
+  type_arguments = type_arguments.InstantiateFrom(instantiator_type_arguments,
+                                                  bound_error,
+                                                  instantiation_trail,
+                                                  bound_trail,
+                                                  space);
+  // This uninstantiated type is not modified, as it can be instantiated
+  // with different instantiators. Allocate a new instantiated version of it.
+  const FunctionType& instantiated_type = FunctionType::Handle(zone,
+      FunctionType::New(cls,
+                        type_arguments,
+                        Function::Handle(zone, signature()),
+                        token_pos(),
+                        space));
+  if (IsFinalized()) {
+    instantiated_type.SetIsFinalized();
+  } else {
+    instantiated_type.SetIsResolved();
+  }
+  // Canonicalization is not part of instantiation.
+  return instantiated_type.raw();
+}
+
+
+bool FunctionType::IsEquivalent(const Instance& other, TrailPtr trail) const {
+  ASSERT(!IsNull());
+  if (raw() == other.raw()) {
+    return true;
+  }
+  if (!other.IsFunctionType()) {
+    return false;
+  }
+  const FunctionType& other_type = FunctionType::Cast(other);
+  ASSERT(IsResolved() && other_type.IsResolved());
+  if (IsMalformed() || other_type.IsMalformed()) {
+    return false;
+  }
+  if (scope_class() != other_type.scope_class()) {
+    return false;
+  }
+  if ((arguments() == other_type.arguments()) &&
+      (signature() == other_type.signature())) {
+    return true;
+  }
+  if (!IsFinalized() || !other_type.IsFinalized()) {
+    return false;
+  }
+
+  // We do not instantiate the types of the signature. This happens on demand
+  // at runtime during a type test.
+  // Therefore, equal function types must have equal type arguments.
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+  const TypeArguments& other_type_args = TypeArguments::Handle(
+      zone, other_type.arguments());
+  if (!type_args.Equals(other_type_args)) {
+    return false;
+  }
+
+  // Type arguments are equal.
+  // Equal function types must have equal signature types and equal optional
+  // named arguments.
+  if (signature() == other_type.signature()) {
+    return true;
+  }
+  const Function& sig_fun = Function::Handle(zone, signature());
+  const Function& other_sig_fun = Function::Handle(
+      zone, other_type.signature());
+
+  // Compare number of function parameters.
+  const intptr_t num_fixed_params = sig_fun.num_fixed_parameters();
+  const intptr_t other_num_fixed_params = other_sig_fun.num_fixed_parameters();
+  if (num_fixed_params != other_num_fixed_params) {
+    return false;
+  }
+  const intptr_t num_opt_pos_params = sig_fun.NumOptionalPositionalParameters();
+  const intptr_t other_num_opt_pos_params =
+      other_sig_fun.NumOptionalPositionalParameters();
+  if (num_opt_pos_params != other_num_opt_pos_params) {
+    return false;
+  }
+  const intptr_t num_opt_named_params = sig_fun.NumOptionalNamedParameters();
+  const intptr_t other_num_opt_named_params =
+      other_sig_fun.NumOptionalNamedParameters();
+  if (num_opt_named_params != other_num_opt_named_params) {
+    return false;
+  }
+  const intptr_t num_ignored_params = sig_fun.NumImplicitParameters();
+  const intptr_t other_num_ignored_params =
+      other_sig_fun.NumImplicitParameters();
+  if (num_ignored_params != other_num_ignored_params) {
+    return false;
+  }
+  AbstractType& param_type = Type::Handle(zone);
+  AbstractType& other_param_type = Type::Handle(zone);
+  // Check the result type.
+  param_type = sig_fun.result_type();
+  other_param_type = other_sig_fun.result_type();
+  if (!param_type.Equals(other_param_type)) {
+    return false;
+  }
+  // Check the types of all parameters.
+  const intptr_t num_params = sig_fun.NumParameters();
+  ASSERT(other_sig_fun.NumParameters() == num_params);
+  for (intptr_t i = 0; i < num_params; i++) {
+    param_type = sig_fun.ParameterTypeAt(i);
+    other_param_type = other_sig_fun.ParameterTypeAt(i);
+    if (!param_type.Equals(other_param_type)) {
+      return false;
+    }
+  }
+  // Check the names and types of optional named parameters.
+  if (num_opt_named_params == 0) {
+    return true;
+  }
+  for (intptr_t i = num_fixed_params; i < num_params; i++) {
+    if (sig_fun.ParameterNameAt(i) != other_sig_fun.ParameterNameAt(i)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+bool FunctionType::IsRecursive() const {
+  return TypeArguments::Handle(arguments()).IsRecursive();
+}
+
+
+RawAbstractType* FunctionType::CloneUnfinalized() const {
+  ASSERT(IsResolved());
+  if (IsFinalized()) {
+    return raw();
+  }
+  ASSERT(!IsMalformed());  // Malformed types are finalized.
+  ASSERT(!IsBeingFinalized());  // Cloning must occur prior to finalization.
+  TypeArguments& type_args = TypeArguments::Handle(arguments());
+  type_args = type_args.CloneUnfinalized();
+  const FunctionType& clone = FunctionType::Handle(
+      FunctionType::New(Class::Handle(scope_class()),
+                        type_args,
+                        Function::Handle(signature()),
+                        token_pos()));
+  clone.SetIsResolved();
+  return clone.raw();
+}
+
+
+RawAbstractType* FunctionType::CloneUninstantiated(const Class& new_owner,
+                                                   TrailPtr trail) const {
+  ASSERT(IsFinalized());
+  ASSERT(!IsMalformed());
+  if (IsInstantiated()) {
+    return raw();
+  }
+  // We may recursively encounter a type already being cloned, because we clone
+  // the upper bounds of its uninstantiated type arguments in the same pass.
+  FunctionType& clone = FunctionType::Handle();
+  clone ^= OnlyBuddyInTrail(trail);
+  if (!clone.IsNull()) {
+    return clone.raw();
+  }
+  clone = FunctionType::New(Class::Handle(scope_class()),
+                            TypeArguments::Handle(),
+                            Function::Handle(signature()),
+                            token_pos());
+  TypeArguments& type_args = TypeArguments::Handle(arguments());
+  // Upper bounds of uninstantiated type arguments may form a cycle.
+  if (type_args.IsRecursive() || !type_args.IsInstantiated()) {
+    AddOnlyBuddyToTrail(&trail, clone);
+  }
+  type_args = type_args.CloneUninstantiated(new_owner, trail);
+  clone.set_arguments(type_args);
+  clone.SetIsFinalized();
+  return clone.raw();
+}
+
+
+RawAbstractType* FunctionType::Canonicalize(TrailPtr trail) const {
+  ASSERT(IsFinalized());
+  if (IsCanonical() || IsMalformed()) {
+    ASSERT(IsMalformed() || TypeArguments::Handle(arguments()).IsOld());
+    return this->raw();
+  }
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  AbstractType& type = Type::Handle(zone);
+  const Class& scope_cls = Class::Handle(zone, type_class());
+  Array& canonical_types = Array::Handle(zone);
+  canonical_types ^= scope_cls.canonical_types();
+  if (canonical_types.IsNull()) {
+    canonical_types = empty_array().raw();
+  }
+  intptr_t length = canonical_types.Length();
+  // Linear search to see whether this type is already present in the
+  // list of canonicalized types.
+  // TODO(asiva): Try to re-factor this lookup code to make sharing
+  // easy between the 4 versions of this loop.
+  intptr_t index = 1;  // Slot 0 is reserved for CanonicalType().
+  while (index < length) {
+    type ^= canonical_types.At(index);
+    if (type.IsNull()) {
+      break;
+    }
+    ASSERT(type.IsFinalized());
+    if (this->Equals(type)) {
+      ASSERT(type.IsCanonical());
+      return type.raw();
+    }
+    index++;
+  }
+  // The type was not found in the table. It is not canonical yet.
+
+  // Canonicalize the type arguments.
+  TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+  // In case the type is first canonicalized at runtime, its type argument
+  // vector may be longer than necessary. This is not an issue.
+  ASSERT(type_args.IsNull() ||
+         (type_args.Length() >= scope_cls.NumTypeArguments()));
+  type_args = type_args.Canonicalize(trail);
+  if (IsCanonical()) {
+    // Canonicalizing type_args canonicalized this type as a side effect.
+    ASSERT(IsRecursive());
+    // Cycles via typedefs are detected and disallowed, but a function type can
+    // be recursive due to a cycle in its type arguments.
+    return this->raw();
+  }
+  set_arguments(type_args);
+
+  // Replace the actual function by a signature function.
+  const Function& fun = Function::Handle(zone, signature());
+  if (!fun.IsSignatureFunction()) {
+    Function& sig_fun = Function::Handle(zone,
+        Function::NewSignatureFunction(scope_cls, TokenPosition::kNoSource));
+    type = fun.result_type();
+    type = type.Canonicalize(trail);
+    sig_fun.set_result_type(type);
+    const intptr_t num_params = fun.NumParameters();
+    sig_fun.set_num_fixed_parameters(fun.num_fixed_parameters());
+    sig_fun.SetNumOptionalParameters(fun.NumOptionalParameters(),
+                                     fun.HasOptionalPositionalParameters());
+    sig_fun.set_parameter_types(Array::Handle(Array::New(num_params,
+                                                         Heap::kOld)));
+    for (intptr_t i = 0; i < num_params; i++) {
+      type = fun.ParameterTypeAt(i);
+      type = type.Canonicalize(trail);
+      sig_fun.SetParameterTypeAt(i, type);
+    }
+    sig_fun.set_parameter_names(Array::Handle(zone, fun.parameter_names()));
+    set_signature(sig_fun);
+  }
+  ASSERT(type_args.IsNull() || type_args.IsOld());
+
+  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);
+}
+
+
+intptr_t FunctionType::Hash() const {
+  ASSERT(IsFinalized());
+  uint32_t result = 1;
+  if (IsMalformed()) return result;
+  result = CombineHashes(result, Class::Handle(scope_class()).id());
+  result = CombineHashes(result, TypeArguments::Handle(arguments()).Hash());
+  const Function& sig_fun = Function::Handle(signature());
+  AbstractType& type = AbstractType::Handle(sig_fun.result_type());
+  result = CombineHashes(result, type.Hash());
+  result = CombineHashes(result, sig_fun.NumOptionalPositionalParameters());
+  const intptr_t num_params = sig_fun.NumParameters();
+  for (intptr_t i = 0; i < num_params; i++) {
+    type = sig_fun.ParameterTypeAt(i);
+    result = CombineHashes(result, type.Hash());
+  }
+  if (sig_fun.NumOptionalNamedParameters() > 0) {
+    String& param_name = String::Handle();
+    for (intptr_t i = sig_fun.num_fixed_parameters(); i < num_params; i++) {
+      param_name = sig_fun.ParameterNameAt(i);
+      result = CombineHashes(result, param_name.Hash());
+    }
+  }
+  return FinalizeHash(result);
+}
+
+
+void FunctionType::set_scope_class(const Class& value) const {
+  ASSERT(!value.IsNull());
+  StorePointer(&raw_ptr()->scope_class_, value.raw());
+}
+
+
+void FunctionType::set_arguments(const TypeArguments& value) const {
+  ASSERT(!IsCanonical());
+  StorePointer(&raw_ptr()->arguments_, value.raw());
+}
+
+
+void FunctionType::set_signature(const Function& value) const {
+  StorePointer(&raw_ptr()->signature_, value.raw());
+}
+
+
+RawFunctionType* FunctionType::New(Heap::Space space) {
+  RawObject* raw = Object::Allocate(FunctionType::kClassId,
+                                    FunctionType::InstanceSize(),
+                                    space);
+  return reinterpret_cast<RawFunctionType*>(raw);
+}
+
+
+RawFunctionType* FunctionType::New(const Class& clazz,
+                                   const TypeArguments& arguments,
+                                   const Function& signature,
+                                   TokenPosition token_pos,
+                                   Heap::Space space) {
+  const FunctionType& result = FunctionType::Handle(FunctionType::New(space));
+  result.set_scope_class(clazz);
+  result.set_arguments(arguments);
+  result.set_signature(signature);
+  result.set_token_pos(token_pos);
+  result.StoreNonPointer(&result.raw_ptr()->type_state_,
+                         RawFunctionType::kAllocated);
+  return result.raw();
+}
+
+
+void FunctionType::set_token_pos(TokenPosition token_pos) const {
+  ASSERT(!token_pos.IsClassifying());
+  StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
+}
+
+
+void FunctionType::set_type_state(int8_t state) const {
+  ASSERT((state >= RawFunctionType::kAllocated) &&
+         (state <= RawFunctionType::kFinalizedUninstantiated));
+  StoreNonPointer(&raw_ptr()->type_state_, state);
+}
+
+
+const char* FunctionType::ToCString() const {
+  const char* unresolved = IsResolved() ? "" : "Unresolved ";
+  const Class& scope_cls = Class::Handle(scope_class());
+  const TypeArguments& type_arguments = TypeArguments::Handle(arguments());
+  const Function& signature_function = Function::Handle(signature());
+  const String& signature_string = IsFinalized() ?
+      String::Handle(
+          signature_function.InstantiatedSignatureFrom(type_arguments,
+                                                       kInternalName)) :
+      String::Handle(signature_function.Signature());
+  if (scope_cls.IsClosureClass()) {
+    ASSERT(arguments() == TypeArguments::null());
+    return OS::SCreate(
+        Thread::Current()->zone(),
+        "%sFunctionType: %s", unresolved, signature_string.ToCString());
+  }
+  const char* class_name = String::Handle(scope_cls.Name()).ToCString();
+  const char* args_cstr =
+      type_arguments.IsNull() ? "null" : type_arguments.ToCString();
+  return OS::SCreate(
+      Thread::Current()->zone(),
+      "%s FunctionType: %s (scope_cls: %s, args: %s)",
+      unresolved,
+      signature_string.ToCString(),
+      class_name,
+      args_cstr);
 }
 
 
@@ -16490,21 +16519,28 @@
 RawTypeRef* TypeRef::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail,
+    TrailPtr instantiation_trail,
+    TrailPtr bound_trail,
     Heap::Space space) const {
   TypeRef& instantiated_type_ref = TypeRef::Handle();
-  instantiated_type_ref ^= OnlyBuddyInTrail(trail);
+  instantiated_type_ref ^= OnlyBuddyInTrail(instantiation_trail);
   if (!instantiated_type_ref.IsNull()) {
     return instantiated_type_ref.raw();
   }
+  instantiated_type_ref = TypeRef::New();
+  AddOnlyBuddyToTrail(&instantiation_trail, instantiated_type_ref);
+
   AbstractType& ref_type = AbstractType::Handle(type());
   ASSERT(!ref_type.IsTypeRef());
   AbstractType& instantiated_ref_type = AbstractType::Handle();
   instantiated_ref_type = ref_type.InstantiateFrom(
-      instantiator_type_arguments, bound_error, trail, space);
+      instantiator_type_arguments,
+      bound_error,
+      instantiation_trail,
+      bound_trail,
+      space);
   ASSERT(!instantiated_ref_type.IsTypeRef());
-  instantiated_type_ref = TypeRef::New(instantiated_ref_type);
-  AddOnlyBuddyToTrail(&trail, instantiated_type_ref);
+  instantiated_type_ref.set_type(instantiated_ref_type);
   return instantiated_type_ref.raw();
 }
 
@@ -16516,19 +16552,20 @@
   if (!cloned_type_ref.IsNull()) {
     return cloned_type_ref.raw();
   }
+  cloned_type_ref = TypeRef::New();
+  AddOnlyBuddyToTrail(&trail, cloned_type_ref);
   AbstractType& ref_type = AbstractType::Handle(type());
   ASSERT(!ref_type.IsTypeRef());
   AbstractType& cloned_ref_type = AbstractType::Handle();
   cloned_ref_type = ref_type.CloneUninstantiated(new_owner, trail);
   ASSERT(!cloned_ref_type.IsTypeRef());
-  cloned_type_ref = TypeRef::New(cloned_ref_type);
-  AddOnlyBuddyToTrail(&trail, cloned_type_ref);
+  cloned_type_ref.set_type(cloned_ref_type);
   return cloned_type_ref.raw();
 }
 
 
 void TypeRef::set_type(const AbstractType& value) const {
-  ASSERT(value.HasResolvedTypeClass());
+  ASSERT(value.IsFunctionType() || value.HasResolvedTypeClass());
   ASSERT(!value.IsTypeRef());
   StorePointer(&raw_ptr()->type_, value.raw());
 }
@@ -16551,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 =
@@ -16559,42 +16601,6 @@
 }
 
 
-bool TypeRef::TestAndAddToTrail(TrailPtr* trail) const {
-  if (*trail == NULL) {
-    *trail = new Trail(Thread::Current()->zone(), 4);
-  } else {
-    const intptr_t len = (*trail)->length();
-    for (intptr_t i = 0; i < len; i++) {
-      if ((*trail)->At(i).raw() == this->raw()) {
-        return true;
-      }
-    }
-  }
-  (*trail)->Add(*this);
-  return false;
-}
-
-
-bool TypeRef::TestAndAddBuddyToTrail(TrailPtr* trail,
-                                     const AbstractType& buddy) const {
-  if (*trail == NULL) {
-    *trail = new Trail(Thread::Current()->zone(), 4);
-  } else {
-    const intptr_t len = (*trail)->length();
-    ASSERT((len % 2) == 0);
-    for (intptr_t i = 0; i < len; i += 2) {
-      if (((*trail)->At(i).raw() == this->raw()) &&
-          ((*trail)->At(i + 1).raw() == buddy.raw())) {
-        return true;
-      }
-    }
-  }
-  (*trail)->Add(*this);
-  (*trail)->Add(buddy);
-  return false;
-}
-
-
 RawTypeRef* TypeRef::New() {
   RawObject* raw = Object::Allocate(TypeRef::kClassId,
                                     TypeRef::InstanceSize(),
@@ -16625,22 +16631,7 @@
 }
 
 
-void TypeRef::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "TypeRef");
-  jsobj.AddServiceId(*this);
-  const String& user_name = String::Handle(PrettyName());
-  const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  if (ref) {
-    return;
-  }
-  jsobj.AddProperty("targetType", AbstractType::Handle(type()));
-}
-
-
-void TypeParameter::set_is_finalized() const {
+void TypeParameter::SetIsFinalized() const {
   ASSERT(!IsFinalized());
   set_type_state(RawTypeParameter::kFinalizedUninstantiated);
 }
@@ -16698,7 +16689,8 @@
 RawAbstractType* TypeParameter::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail,
+    TrailPtr instantiation_trail,
+    TrailPtr bound_trail,
     Heap::Space space) const {
   ASSERT(IsFinalized());
   if (instantiator_type_arguments.IsNull()) {
@@ -16710,6 +16702,12 @@
   // type arguments are canonicalized at type finalization time. It would be too
   // early to canonicalize the returned type argument here, since instantiation
   // not only happens at run time, but also during type finalization.
+
+  // If the instantiated type parameter type_arg is a BoundedType, it means that
+  // it is still uninstantiated and that we are instantiating at finalization
+  // time (i.e. compile time).
+  // Indeed, the instantiator (type arguments of an instance) is always
+  // instantiated at run time and any bounds were checked during allocation.
   return type_arg.raw();
 }
 
@@ -16717,12 +16715,21 @@
 bool TypeParameter::CheckBound(const AbstractType& bounded_type,
                                const AbstractType& upper_bound,
                                Error* bound_error,
+                               TrailPtr bound_trail,
                                Heap::Space space) const {
   ASSERT((bound_error != NULL) && bound_error->IsNull());
   ASSERT(bounded_type.IsFinalized());
   ASSERT(upper_bound.IsFinalized());
   ASSERT(!bounded_type.IsMalformed());
-  if (bounded_type.IsSubtypeOf(upper_bound, bound_error, space)) {
+  if (bounded_type.IsTypeRef() || upper_bound.IsTypeRef()) {
+    // Shortcut the bound check if the pair <bounded_type, upper_bound> is
+    // already in the trail.
+    if (bounded_type.TestAndAddBuddyToTrail(&bound_trail, upper_bound)) {
+      return true;
+    }
+  }
+
+  if (bounded_type.IsSubtypeOf(upper_bound, bound_error, bound_trail, space)) {
     return true;
   }
   // Set bound_error if the caller is interested and if this is the first error.
@@ -16747,6 +16754,7 @@
           *bound_error,
           script,
           token_pos(),
+          Report::AtLocation,
           Report::kMalboundedType,
           Heap::kNew,
           "type parameter '%s' of class '%s' must extend bound '%s', "
@@ -16778,22 +16786,44 @@
 RawAbstractType* TypeParameter::CloneUninstantiated(
     const Class& new_owner, TrailPtr trail) const {
   ASSERT(IsFinalized());
-  AbstractType& upper_bound = AbstractType::Handle(bound());
-  upper_bound = upper_bound.CloneUninstantiated(new_owner, trail);
+  TypeParameter& clone = TypeParameter::Handle();
+  clone ^= OnlyBuddyInTrail(trail);
+  if (!clone.IsNull()) {
+    return clone.raw();
+  }
   const Class& old_owner = Class::Handle(parameterized_class());
   const intptr_t new_index = index() +
       new_owner.NumTypeArguments() - old_owner.NumTypeArguments();
-  const TypeParameter& clone = TypeParameter::Handle(
-      TypeParameter::New(new_owner,
-                         new_index,
-                         String::Handle(name()),
-                         upper_bound,
-                         token_pos()));
-  clone.set_is_finalized();
+  AbstractType& upper_bound = AbstractType::Handle(bound());
+  clone = TypeParameter::New(new_owner,
+                             new_index,
+                             String::Handle(name()),
+                             upper_bound,  // Not cloned yet.
+                             token_pos());
+  clone.SetIsFinalized();
+  AddOnlyBuddyToTrail(&trail, clone);
+  upper_bound = upper_bound.CloneUninstantiated(new_owner, trail);
+  clone.set_bound(upper_bound);
   return clone.raw();
 }
 
 
+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();
@@ -16816,7 +16846,7 @@
                                      intptr_t index,
                                      const String& name,
                                      const AbstractType& bound,
-                                     intptr_t token_pos) {
+                                     TokenPosition token_pos) {
   const TypeParameter& result = TypeParameter::Handle(TypeParameter::New());
   result.set_parameterized_class(parameterized_class);
   result.set_index(index);
@@ -16829,8 +16859,8 @@
 }
 
 
-void TypeParameter::set_token_pos(intptr_t token_pos) const {
-  ASSERT(Scanner::ValidSourcePosition(token_pos));
+void TypeParameter::set_token_pos(TokenPosition token_pos) const {
+  ASSERT(!token_pos.IsClassifying());
   StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
 }
 
@@ -16860,25 +16890,6 @@
 }
 
 
-void TypeParameter::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "TypeParameter");
-  jsobj.AddServiceId(*this);
-  const String& user_name = String::Handle(PrettyName());
-  const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  const Class& param_cls = Class::Handle(parameterized_class());
-  jsobj.AddProperty("parameterizedClass", param_cls);
-  if (ref) {
-    return;
-  }
-  jsobj.AddProperty("parameterIndex", index());
-  const AbstractType& upper_bound = AbstractType::Handle(bound());
-  jsobj.AddProperty("bound", upper_bound);
-}
-
-
 bool BoundedType::IsMalformed() const {
   return AbstractType::Handle(type()).IsMalformed();
 }
@@ -16963,53 +16974,75 @@
 RawAbstractType* BoundedType::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     Error* bound_error,
-    TrailPtr trail,
+    TrailPtr instantiation_trail,
+    TrailPtr bound_trail,
     Heap::Space space) const {
   ASSERT(IsFinalized());
   AbstractType& bounded_type = AbstractType::Handle(type());
   ASSERT(bounded_type.IsFinalized());
+  AbstractType& instantiated_bounded_type =
+      AbstractType::Handle(bounded_type.raw());
   if (!bounded_type.IsInstantiated()) {
-    bounded_type = bounded_type.InstantiateFrom(instantiator_type_arguments,
-                                                bound_error,
-                                                trail,
-                                                space);
-    // In case types of instantiator_type_arguments are not finalized, then
-    // the instantiated bounded_type is not finalized either.
+    instantiated_bounded_type =
+        bounded_type.InstantiateFrom(instantiator_type_arguments,
+                                     bound_error,
+                                     instantiation_trail,
+                                     bound_trail,
+                                     space);
+    // In case types of instantiator_type_arguments are not finalized
+    // (or instantiated), then the instantiated_bounded_type is not finalized
+    // (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());
     ASSERT(!upper_bound.IsObjectType() && !upper_bound.IsDynamicType());
-    const TypeParameter& type_param = TypeParameter::Handle(type_parameter());
+    AbstractType& instantiated_upper_bound =
+        AbstractType::Handle(upper_bound.raw());
     if (!upper_bound.IsInstantiated()) {
-      upper_bound = upper_bound.InstantiateFrom(instantiator_type_arguments,
-                                                bound_error,
-                                                trail,
-                                                space);
-      // Instantiated upper_bound may not be finalized. See comment above.
+      instantiated_upper_bound =
+          upper_bound.InstantiateFrom(instantiator_type_arguments,
+                                      bound_error,
+                                      instantiation_trail,
+                                      bound_trail,
+                                      space);
+      // The instantiated_upper_bound may not be finalized or instantiated.
+      // See comment above.
     }
     if (bound_error->IsNull()) {
-      if (bounded_type.IsBeingFinalized() ||
-          upper_bound.IsBeingFinalized() ||
-          (!type_param.CheckBound(bounded_type, upper_bound, bound_error) &&
+      // Shortcut the F-bounded case where we have reached a fixpoint.
+      if (instantiated_bounded_type.Equals(bounded_type) &&
+          instantiated_upper_bound.Equals(upper_bound)) {
+        return bounded_type.raw();
+      }
+      const TypeParameter& type_param = TypeParameter::Handle(type_parameter());
+      if (instantiated_bounded_type.IsBeingFinalized() ||
+          instantiated_upper_bound.IsBeingFinalized() ||
+          (!type_param.CheckBound(instantiated_bounded_type,
+                                  instantiated_upper_bound,
+                                  bound_error,
+                                  bound_trail,
+                                  space) &&
            bound_error->IsNull())) {
         // We cannot determine yet whether the bounded_type is below the
         // upper_bound, because one or both of them is still being finalized or
         // uninstantiated.
-        ASSERT(bounded_type.IsBeingFinalized() ||
-               upper_bound.IsBeingFinalized() ||
-               !bounded_type.IsInstantiated() ||
-               !upper_bound.IsInstantiated());
+        ASSERT(instantiated_bounded_type.IsBeingFinalized() ||
+               instantiated_upper_bound.IsBeingFinalized() ||
+               !instantiated_bounded_type.IsInstantiated() ||
+               !instantiated_upper_bound.IsInstantiated());
         // Postpone bound check by returning a new BoundedType with unfinalized
         // or partially instantiated bounded_type and upper_bound, but keeping
         // type_param.
-        bounded_type = BoundedType::New(bounded_type, upper_bound, type_param);
+        instantiated_bounded_type = BoundedType::New(instantiated_bounded_type,
+                                                     instantiated_upper_bound,
+                                                     type_param);
       }
     }
   }
-  return bounded_type.raw();
+  return instantiated_bounded_type.raw();
 }
 
 
@@ -17043,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
@@ -17091,23 +17130,7 @@
 }
 
 
-void BoundedType::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "BoundedType");
-  jsobj.AddServiceId(*this);
-  const String& user_name = String::Handle(PrettyName());
-  const String& vm_name = String::Handle(Name());
-  AddNameProperties(&jsobj, user_name, vm_name);
-  if (ref) {
-    return;
-  }
-  jsobj.AddProperty("targetType", AbstractType::Handle(type()));
-  jsobj.AddProperty("bound", AbstractType::Handle(bound()));
-}
-
-
-intptr_t MixinAppType::token_pos() const {
+TokenPosition MixinAppType::token_pos() const {
   return AbstractType::Handle(MixinTypeAt(0)).token_pos();
 }
 
@@ -17136,11 +17159,6 @@
 }
 
 
-void MixinAppType::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  UNREACHABLE();
-}
-
-
 RawAbstractType* MixinAppType::MixinTypeAt(intptr_t depth) const {
   return AbstractType::RawCast(Array::Handle(mixin_types()).At(depth));
 }
@@ -17182,11 +17200,6 @@
 }
 
 
-void Number::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  UNREACHABLE();
-}
-
-
 const char* Integer::ToCString() const {
   // Integer is an interface. No instances of Integer should exist except null.
   ASSERT(IsNull());
@@ -17194,25 +17207,6 @@
 }
 
 
-void Integer::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Int");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("valueAsString", ToCString());
-}
-
-
-// Throw JavascriptIntegerOverflow exception.
-static void ThrowJavascriptIntegerOverflow(const Integer& i) {
-  const Array& exc_args = Array::Handle(Array::New(1));
-  const String& i_str = String::Handle(String::New(i.ToCString()));
-  exc_args.SetAt(0, i_str);
-  Exceptions::ThrowByType(Exceptions::kJavascriptIntegerOverflowError,
-      exc_args);
-}
-
-
 RawInteger* Integer::New(const String& str, Heap::Space space) {
   // We are not supposed to have integers represented as two byte strings.
   ASSERT(str.IsOneByteString());
@@ -17222,19 +17216,12 @@
         Bigint::NewFromCString(str.ToCString(), space));
     ASSERT(!big.FitsIntoSmi());
     ASSERT(!big.FitsIntoInt64());
-    if (FLAG_throw_on_javascript_int_overflow) {
-      ThrowJavascriptIntegerOverflow(big);
-    }
     return big.raw();
   }
   return Integer::New(value, space);
 }
 
 
-// This is called from LiteralToken::New() in the parser, so we can't
-// raise an exception for javascript overflow here. Instead we do it in
-// Parser::CurrentIntegerLiteral(), which is the point in the parser where
-// integer literals escape, so we can call Parser::ErrorMsg().
 RawInteger* Integer::NewCanonical(const String& str) {
   // We are not supposed to have integers represented as two byte strings.
   ASSERT(str.IsOneByteString());
@@ -17252,16 +17239,8 @@
 }
 
 
-RawInteger* Integer::New(int64_t value, Heap::Space space, const bool silent) {
+RawInteger* Integer::New(int64_t value, Heap::Space space) {
   const bool is_smi = Smi::IsValid(value);
-  if (!silent &&
-      FLAG_throw_on_javascript_int_overflow &&
-      !Utils::IsJavascriptInt64(value)) {
-    const Integer& i = is_smi ?
-        Integer::Handle(Smi::New(static_cast<intptr_t>(value))) :
-        Integer::Handle(Mint::New(value, space));
-    ThrowJavascriptIntegerOverflow(i);
-  }
   if (is_smi) {
     return Smi::New(static_cast<intptr_t>(value));
   }
@@ -17271,10 +17250,6 @@
 
 RawInteger* Integer::NewFromUint64(uint64_t value, Heap::Space space) {
   if (value > static_cast<uint64_t>(Mint::kMaxValue)) {
-    if (FLAG_throw_on_javascript_int_overflow) {
-      const Integer &i = Integer::Handle(Bigint::NewFromUint64(value, space));
-      ThrowJavascriptIntegerOverflow(i);
-    }
     return Bigint::NewFromUint64(value, space);
   } else {
     return Integer::New(value, space);
@@ -17338,31 +17313,7 @@
 }
 
 
-// Returns true if the signed Integer does not fit into a
-// Javascript integer.
-bool Integer::CheckJavascriptIntegerOverflow() const {
-  // Always overflow if the value doesn't fit into an int64_t.
-  int64_t value = 1ULL << 63;
-  if (IsSmi()) {
-    value = AsInt64Value();
-  } else if (IsMint()) {
-    Mint& mint = Mint::Handle();
-    mint ^= raw();
-    value = mint.value();
-  } else {
-    if (Bigint::Cast(*this).FitsIntoInt64()) {
-      value = AsInt64Value();
-    }
-  }
-  return !Utils::IsJavascriptInt64(value);
-}
-
-
 RawInteger* Integer::AsValidInteger() const {
-  if (FLAG_throw_on_javascript_int_overflow &&
-      CheckJavascriptIntegerOverflow()) {
-    ThrowJavascriptIntegerOverflow(*this);
-  }
   if (IsSmi()) return raw();
   if (IsMint()) {
     Mint& mint = Mint::Handle();
@@ -17376,7 +17327,9 @@
   if (Bigint::Cast(*this).FitsIntoInt64()) {
     const int64_t value = AsInt64Value();
     if (Smi::IsValid(value)) {
-      return Smi::New(value);
+      // This cast is safe because Smi::IsValid verifies that value will fit.
+      intptr_t val = static_cast<intptr_t>(value);
+      return Smi::New(val);
     }
     return Mint::New(value);
   }
@@ -17530,8 +17483,7 @@
 // TODO(srdjan): Clarify handling of negative right operand in a shift op.
 RawInteger* Smi::ShiftOp(Token::Kind kind,
                          const Smi& other,
-                         Heap::Space space,
-                         const bool silent) const {
+                         Heap::Space space) const {
   intptr_t result = 0;
   const intptr_t left_value = Value();
   const intptr_t right_value = other.Value();
@@ -17548,7 +17500,7 @@
             return Bigint::NewFromShiftedInt64(left_value, right_value, space);
           } else {
             int64_t left_64 = left_value;
-            return Integer::New(left_64 << right_value, space, silent);
+            return Integer::New(left_64 << right_value, space);
           }
         }
       }
@@ -17620,15 +17572,6 @@
 }
 
 
-void Smi::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Int");
-  jsobj.AddFixedServiceId("objects/int-%" Pd "", Value());
-  jsobj.AddPropertyF("valueAsString", "%" Pd "", Value());
-}
-
-
 RawClass* Smi::Class() {
   return Isolate::Current()->object_store()->smi_class();
 }
@@ -17746,11 +17689,6 @@
 }
 
 
-void Mint::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Integer::PrintJSONImpl(stream, ref);
-}
-
-
 void Double::set_value(double value) const {
   StoreNonPointer(&raw_ptr()->value_, value);
 }
@@ -17878,15 +17816,6 @@
 }
 
 
-void Double::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Double");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("valueAsString", ToCString());
-}
-
-
 bool Bigint::Neg() const {
   return Bool::Handle(neg()).value();
 }
@@ -18028,8 +17957,10 @@
     --used;
   }
   if (used > 0) {
-    if ((used & 1) != 0) {
-      // Set leading zero for 64-bit processing of digit pairs.
+    if (((used & 1) != 0) && (digits.GetUint32(used << 2) != 0)) {
+      // Set leading zero for 64-bit processing of digit pairs if not set.
+      // The check above ensures that we avoid a write access to a possibly
+      // reused digits array that could be marked read only.
       digits.SetUint32(used << 2, 0);
     }
     result.set_digits(digits);
@@ -18634,11 +18565,6 @@
 }
 
 
-void Bigint::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Integer::PrintJSONImpl(stream, ref);
-}
-
-
 // Synchronize with implementation in compiler (intrinsifier).
 class StringHasher : ValueObject {
  public:
@@ -18804,16 +18730,36 @@
     return true;
   }
 
-  if (!other.IsString() || other.IsNull()) {
+  if (!other.IsString()) {
     return false;
   }
 
   const String& other_string = String::Cast(other);
-  if (this->HasHash() && other_string.HasHash() &&
-      (this->Hash() != other_string.Hash())) {
-    return false;  // Both sides have a hash code and it does not match.
+  return Equals(other_string);
+}
+
+
+bool String::Equals(const String& str,
+                    intptr_t begin_index,
+                    intptr_t len) const {
+  ASSERT(begin_index >= 0);
+  ASSERT((begin_index == 0) || (begin_index < str.Length()));
+  ASSERT(len >= 0);
+  ASSERT(len <= str.Length());
+  if (len != this->Length()) {
+    return false;  // Lengths don't match.
   }
-  return Equals(other_string, 0, other_string.Length());
+
+  Scanner::CharAtFunc this_char_at_func = this->CharAtFunc();
+  Scanner::CharAtFunc str_char_at_func = str.CharAtFunc();
+  for (intptr_t i = 0; i < len; i++) {
+    if (this_char_at_func(*this, i) !=
+        str_char_at_func(str, begin_index + i)) {
+      return false;
+    }
+  }
+
+  return true;
 }
 
 
@@ -19469,32 +19415,6 @@
 }
 
 
-void String::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  if (raw() == Symbols::OptimizedOut().raw()) {
-    // TODO(turnidge): This is a hack.  The user could have this
-    // special string in their program.  Fixing this involves updating
-    // the debugging api a bit.
-    jsobj.AddProperty("type", "Sentinel");
-    jsobj.AddProperty("kind", "OptimizedOut");
-    jsobj.AddProperty("valueAsString", "<optimized out>");
-    return;
-  }
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "String");
-  jsobj.AddServiceId(*this);
-  if (ref) {
-    bool did_truncate = jsobj.AddPropertyStr("valueAsString", *this, 128);
-    if (did_truncate) {
-      jsobj.AddProperty("valueAsStringIsTruncated", did_truncate);
-    }
-  } else {
-    bool did_truncate = jsobj.AddPropertyStr("valueAsString", *this);
-    ASSERT(!did_truncate);
-  }
-}
-
-
 void String::ToUTF8(uint8_t* utf8_array, intptr_t array_len) const {
   ASSERT(array_len >= Utf8::Length(*this));
   Utf8::Encode(*this, reinterpret_cast<char*>(utf8_array), array_len);
@@ -20384,16 +20304,6 @@
 }
 
 
-void Bool::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  const char* str = ToCString();
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Bool");
-  jsobj.AddFixedServiceId("objects/bool-%s", str);
-  jsobj.AddPropertyF("valueAsString", "%s", str);
-}
-
-
 bool Array::CanonicalizeEquals(const Instance& other) const {
   if (this->raw() == other.raw()) {
     // Both handles point to the same raw instance.
@@ -20496,37 +20406,6 @@
 }
 
 
-void Array::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "List");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("length", Length());
-  if (ref) {
-    return;
-  }
-  intptr_t offset;
-  intptr_t count;
-  stream->ComputeOffsetAndCount(Length(), &offset, &count);
-  if (offset > 0) {
-    jsobj.AddProperty("offset", offset);
-  }
-  if (count < Length()) {
-    jsobj.AddProperty("count", count);
-  }
-  intptr_t limit = offset + count;
-  ASSERT(limit <= Length());
-  {
-    JSONArray jsarr(&jsobj, "elements");
-    Object& element = Object::Handle();
-    for (intptr_t index = offset; index < limit; index++) {
-      element = At(index);
-      jsarr.AddValue(element);
-    }
-  }
-}
-
-
 RawArray* Array::Grow(const Array& source,
                       intptr_t new_length,
                       Heap::Space space) {
@@ -20744,38 +20623,6 @@
 }
 
 
-void GrowableObjectArray::PrintJSONImpl(JSONStream* stream,
-                                        bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "List");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("length", Length());
-  if (ref) {
-    return;
-  }
-  intptr_t offset;
-  intptr_t count;
-  stream->ComputeOffsetAndCount(Length(), &offset, &count);
-  if (offset > 0) {
-    jsobj.AddProperty("offset", offset);
-  }
-  if (count < Length()) {
-    jsobj.AddProperty("count", count);
-  }
-  intptr_t limit = offset + count;
-  ASSERT(limit <= Length());
-  {
-    JSONArray jsarr(&jsobj, "elements");
-    Object& element = Object::Handle();
-    for (intptr_t index = offset; index < limit; index++) {
-      element = At(index);
-      jsarr.AddValue(element);
-    }
-  }
-}
-
-
 // Equivalent to Dart's operator "==" and hashCode.
 class DefaultHashTraits {
  public:
@@ -20862,45 +20709,6 @@
 }
 
 
-void LinkedHashMap::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Map");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("length", Length());
-  if (ref) {
-    return;
-  }
-  intptr_t offset;
-  intptr_t count;
-  stream->ComputeOffsetAndCount(Length(), &offset, &count);
-  if (offset > 0) {
-    jsobj.AddProperty("offset", offset);
-  }
-  if (count < Length()) {
-    jsobj.AddProperty("count", count);
-  }
-  intptr_t limit = offset + count;
-  ASSERT(limit <= Length());
-  {
-    JSONArray jsarr(&jsobj, "associations");
-    Object& object = Object::Handle();
-    LinkedHashMap::Iterator iterator(*this);
-    int i = 0;
-    while (iterator.MoveNext() && i < limit) {
-      if (i >= offset) {
-        JSONObject jsassoc(&jsarr);
-        object = iterator.CurrentKey();
-        jsassoc.AddProperty("key", object);
-        object = iterator.CurrentValue();
-        jsassoc.AddProperty("value", object);
-      }
-      i++;
-    }
-  }
-}
-
-
 RawFloat32x4* Float32x4::New(float v0, float v1, float v2, float v3,
                              Heap::Space space) {
   ASSERT(Isolate::Current()->object_store()->float32x4_class() !=
@@ -20997,15 +20805,6 @@
 }
 
 
-void Float32x4::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Float32x4");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("valueAsString", ToCString());
-}
-
-
 RawInt32x4* Int32x4::New(int32_t v0, int32_t v1, int32_t v2, int32_t v3,
                          Heap::Space space) {
   ASSERT(Isolate::Current()->object_store()->int32x4_class() !=
@@ -21102,15 +20901,6 @@
 }
 
 
-void Int32x4::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Int32x4");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("valueAsString", ToCString());
-}
-
-
 RawFloat64x2* Float64x2::New(double value0, double value1, Heap::Space space) {
   ASSERT(Isolate::Current()->object_store()->float64x2_class() !=
          Class::null());
@@ -21181,15 +20971,6 @@
 }
 
 
-void Float64x2::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "Float64x2");
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("valueAsString", ToCString());
-}
-
-
 const intptr_t TypedData::element_size_table[TypedData::kNumElementSizes] = {
   1,   // kTypedDataInt8ArrayCid.
   1,   // kTypedDataUint8ArrayCid.
@@ -21278,38 +21059,6 @@
 }
 
 
-void TypedData::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  const Class& cls = Class::Handle(clazz());
-  const String& kind = String::Handle(cls.UserVisibleName());
-  jsobj.AddProperty("kind", kind.ToCString());
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("length", Length());
-  if (ref) {
-    return;
-  }
-  intptr_t offset;
-  intptr_t count;
-  stream->ComputeOffsetAndCount(Length(), &offset, &count);
-  if (offset > 0) {
-    jsobj.AddProperty("offset", offset);
-  }
-  if (count < Length()) {
-    jsobj.AddProperty("count", count);
-  }
-  if (count == 0) {
-    jsobj.AddProperty("bytes", "");
-  } else {
-    NoSafepointScope no_safepoint;
-    jsobj.AddPropertyBase64("bytes",
-                            reinterpret_cast<const uint8_t*>(
-                                DataAddr(offset * ElementSizeInBytes())),
-                            count * ElementSizeInBytes());
-  }
-}
-
-
 FinalizablePersistentHandle* ExternalTypedData::AddFinalizer(
     void* peer, Dart_WeakPersistentHandleFinalizer callback) const {
   return dart::AddFinalizer(*this, peer, callback);
@@ -21339,39 +21088,6 @@
 }
 
 
-void ExternalTypedData::PrintJSONImpl(JSONStream* stream,
-                                      bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  const Class& cls = Class::Handle(clazz());
-  const String& kind = String::Handle(cls.UserVisibleName());
-  jsobj.AddProperty("kind", kind.ToCString());
-  jsobj.AddServiceId(*this);
-  jsobj.AddProperty("length", Length());
-  if (ref) {
-    return;
-  }
-  intptr_t offset;
-  intptr_t count;
-  stream->ComputeOffsetAndCount(Length(), &offset, &count);
-  if (offset > 0) {
-    jsobj.AddProperty("offset", offset);
-  }
-  if (count < Length()) {
-    jsobj.AddProperty("count", count);
-  }
-  if (count == 0) {
-    jsobj.AddProperty("bytes", "");
-  } else {
-    NoSafepointScope no_safepoint;
-    jsobj.AddPropertyBase64("bytes",
-                            reinterpret_cast<const uint8_t*>(
-                                DataAddr(offset * ElementSizeInBytes())),
-                            count * ElementSizeInBytes());
-  }
-}
-
-
 RawCapability* Capability::New(uint64_t id, Heap::Space space) {
   Capability& result = Capability::Handle();
   {
@@ -21391,11 +21107,6 @@
 }
 
 
-void Capability::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Instance::PrintJSONImpl(stream, ref);
-}
-
-
 RawReceivePort* ReceivePort::New(Dart_Port id,
                                  bool is_control_port,
                                  Heap::Space space) {
@@ -21428,11 +21139,6 @@
 }
 
 
-void ReceivePort::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Instance::PrintJSONImpl(stream, ref);
-}
-
-
 RawSendPort* SendPort::New(Dart_Port id, Heap::Space space) {
   return New(id, Isolate::Current()->origin_id(), space);
 }
@@ -21461,13 +21167,8 @@
 }
 
 
-void SendPort::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Instance::PrintJSONImpl(stream, ref);
-}
-
-
-const char* Closure::ToCString(const Instance& closure) {
-  const Function& fun = Function::Handle(Closure::function(closure));
+const char* Closure::ToCString() const {
+  const Function& fun = Function::Handle(function());
   const bool is_implicit_closure = fun.IsImplicitClosureFunction();
   const char* fun_sig = String::Handle(fun.UserVisibleSignature()).ToCString();
   const char* from = is_implicit_closure ? " from " : "";
@@ -21477,23 +21178,31 @@
 }
 
 
-RawInstance* Closure::New(const Function& function,
-                          const Context& context,
-                          Heap::Space space) {
-  const Class& cls = Class::Handle(function.signature_class());
-  ASSERT(cls.instance_size() == Closure::InstanceSize());
-  Instance& result = Instance::Handle();
+RawClosure* Closure::New(const Function& function,
+                         const Context& context,
+                         Heap::Space space) {
+  Closure& result = Closure::Handle();
   {
-    RawObject* raw = Object::Allocate(cls.id(), Closure::InstanceSize(), space);
+    RawObject* raw = Object::Allocate(Closure::kClassId,
+                                      Closure::InstanceSize(),
+                                      space);
     NoSafepointScope no_safepoint;
     result ^= raw;
+    result.StorePointer(&result.raw_ptr()->function_, function.raw());
+    result.StorePointer(&result.raw_ptr()->context_, context.raw());
   }
-  Closure::set_function(result, function);
-  Closure::set_context(result, context);
   return result.raw();
 }
 
 
+RawClosure* Closure::New() {
+  RawObject* raw = Object::Allocate(Closure::kClassId,
+                                    Closure::InstanceSize(),
+                                    Heap::kOld);
+  return reinterpret_cast<RawClosure*>(raw);
+}
+
+
 intptr_t Stacktrace::Length() const {
   const Array& code_array = Array::Handle(raw_ptr()->code_array_);
   return code_array.Length();
@@ -21576,30 +21285,20 @@
 }
 
 
-void Stacktrace::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "StackTrace");
-  jsobj.AddServiceId(*this);
-  intptr_t idx = 0;
-  jsobj.AddProperty("valueAsString", ToCStringInternal(&idx));
-}
-
-
 static intptr_t PrintOneStacktrace(Zone* zone,
                                    GrowableArray<char*>* frame_strings,
                                    uword pc,
                                    const Function& function,
                                    const Code& code,
                                    intptr_t frame_index) {
-  const intptr_t token_pos = code.GetTokenIndexOfPC(pc);
+  const TokenPosition token_pos = code.GetTokenIndexOfPC(pc);
   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());
   intptr_t line = -1;
   intptr_t column = -1;
-  if (token_pos >= 0) {
+  if (token_pos.IsReal()) {
     if (script.HasSource()) {
       script.GetTokenLocation(token_pos, &line, &column);
     } else {
@@ -21625,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();
@@ -21654,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())) {
@@ -21664,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 (Compiler::allow_recompilation()) {
-          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 {
@@ -21835,33 +21498,6 @@
 }
 
 
-void JSRegExp::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "RegExp");
-  jsobj.AddServiceId(*this);
-
-  jsobj.AddProperty("pattern", String::Handle(pattern()));
-
-  if (ref) {
-    return;
-  }
-
-  jsobj.AddProperty("isCaseSensitive", !is_ignore_case());
-  jsobj.AddProperty("isMultiLine", is_multi_line());
-
-  Function& func = Function::Handle();
-  func = function(kOneByteStringCid);
-  jsobj.AddProperty("_oneByteFunction", func);
-  func = function(kTwoByteStringCid);
-  jsobj.AddProperty("_twoByteFunction", func);
-  func = function(kExternalOneByteStringCid);
-  jsobj.AddProperty("_externalOneByteFunction", func);
-  func = function(kExternalTwoByteStringCid);
-  jsobj.AddProperty("_externalTwoByteFunction", func);
-}
-
-
 RawWeakProperty* WeakProperty::New(Heap::Space space) {
   ASSERT(Isolate::Current()->object_store()->weak_property_class()
          != Class::null());
@@ -21877,21 +21513,6 @@
 }
 
 
-void WeakProperty::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "WeakProperty");
-  jsobj.AddServiceId(*this);
-  if (ref) {
-    return;
-  }
-
-  const Object& key_handle = Object::Handle(key());
-  jsobj.AddProperty("propertyKey", key_handle);
-  const Object& value_handle = Object::Handle(value());
-  jsobj.AddProperty("propertyValue", value_handle);
-}
-
 RawAbstractType* MirrorReference::GetAbstractTypeReferent() const {
   ASSERT(Object::Handle(referent()).IsAbstractType());
   return AbstractType::Cast(Object::Handle(referent())).raw();
@@ -21948,21 +21569,6 @@
 }
 
 
-void MirrorReference::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  JSONObject jsobj(stream);
-  PrintSharedInstanceJSON(&jsobj, ref);
-  jsobj.AddProperty("kind", "MirrorReference");
-  jsobj.AddServiceId(*this);
-
-  if (ref) {
-    return;
-  }
-
-  const Object& referent_handle = Object::Handle(referent());
-  jsobj.AddProperty("mirrorReferent", referent_handle);
-}
-
-
 void UserTag::MakeActive() const {
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
@@ -22100,10 +21706,4 @@
   return tag_label.ToCString();
 }
 
-
-void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Instance::PrintJSONImpl(stream, ref);
-}
-
-
 }  // namespace dart
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index d67b06a..8fafabc 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -11,6 +11,7 @@
 #include "vm/json_stream.h"
 #include "vm/bitmap.h"
 #include "vm/dart.h"
+#include "vm/flags.h"
 #include "vm/globals.h"
 #include "vm/growable_array.h"
 #include "vm/handles.h"
@@ -23,6 +24,7 @@
 #include "vm/scanner.h"
 #include "vm/tags.h"
 #include "vm/thread.h"
+#include "vm/token_position.h"
 #include "vm/verified_memory.h"
 
 namespace dart {
@@ -136,15 +138,7 @@
     return reinterpret_cast<Raw##object*>(Object::null());                     \
   }                                                                            \
   virtual const char* ToCString() const;                                       \
-  /* Object is printed as JSON into stream. If ref is true only a header */    \
-  /* with an object id is printed. If ref is false the object is fully   */    \
-  /* printed.                                                            */    \
-  virtual const char* JSONType() const {                                       \
-    return ""#object;                                                          \
-  }                                                                            \
   static const ClassId kClassId = k##object##Cid;                              \
- protected:  /* NOLINT */                                                      \
-  virtual void PrintJSONImpl(JSONStream* stream, bool ref) const;              \
  private:  /* NOLINT */                                                        \
   /* Initialize the handle based on the raw_ptr in the presence of null. */    \
   static void initializeHandle(object* obj, RawObject* raw_ptr) {              \
@@ -168,6 +162,28 @@
   void operator=(const object& value);                                         \
   void operator=(const super& value);                                          \
 
+// Conditionally include object_service.cc functionality in the vtable to avoid
+// link errors like the following:
+//
+// object.o:(.rodata._ZTVN4....E[_ZTVN4...E]+0x278):
+// undefined reference to
+// `dart::Instance::PrintSharedInstanceJSON(dart::JSONObject*, bool) const'.
+//
+#ifndef PRODUCT
+#define OBJECT_SERVICE_SUPPORT(object)                                         \
+   protected:  /* NOLINT */                                                    \
+  /* Object is printed as JSON into stream. If ref is true only a header */    \
+  /* with an object id is printed. If ref is false the object is fully   */    \
+  /* printed.                                                            */    \
+    virtual void PrintJSONImpl(JSONStream* stream, bool ref) const;            \
+    virtual const char* JSONType() const {                                     \
+      return ""#object;                                                        \
+    }
+#else
+#define OBJECT_SERVICE_SUPPORT(object)                                         \
+   protected:  /* NOLINT */
+#endif  // !PRODUCT
+
 #define SNAPSHOT_READER_SUPPORT(object)                                        \
   static Raw##object* ReadFrom(SnapshotReader* reader,                         \
                                intptr_t object_id,                             \
@@ -188,6 +204,7 @@
  protected:  /* NOLINT */                                                      \
   object() : super() {}                                                        \
   BASE_OBJECT_IMPLEMENTATION(object, super)                                    \
+  OBJECT_SERVICE_SUPPORT(object)
 
 #define HEAP_OBJECT_IMPLEMENTATION(object, super)                              \
   OBJECT_IMPLEMENTATION(object, super);                                        \
@@ -213,6 +230,7 @@
  private:  /* NOLINT */                                                        \
   object() : super() {}                                                        \
   BASE_OBJECT_IMPLEMENTATION(object, super)                                    \
+  OBJECT_SERVICE_SUPPORT(object)                                               \
   const Raw##object* raw_ptr() const {                                         \
     ASSERT(raw() != null());                                                   \
     return raw()->ptr();                                                       \
@@ -279,11 +297,13 @@
     }
   }
 
+#ifndef PRODUCT
   void PrintJSON(JSONStream* stream, bool ref = true) const;
-
+  virtual void PrintJSONImpl(JSONStream* stream, bool ref) const;
   virtual const char* JSONType() const {
     return IsNull() ? "null" : "Object";
   }
+#endif
 
   // Returns the name that is used to identify an object in the
   // namespace dictionary.
@@ -294,15 +314,11 @@
 
   bool IsNew() const { return raw()->IsNewObject(); }
   bool IsOld() const { return raw()->IsOldObject(); }
-  bool InVMHeap() const {
 #if defined(DEBUG)
-    if (raw()->IsVMHeapObject()) {
-      Heap* vm_isolate_heap = Dart::vm_isolate()->heap();
-      ASSERT(vm_isolate_heap->Contains(RawObject::ToAddr(raw())));
-    }
-#endif
-    return raw()->IsVMHeapObject();
-  }
+  bool InVMHeap() const;
+#else
+  bool InVMHeap() const { return raw()->IsVMHeapObject(); }
+#endif  // DEBUG
 
   // Print the object on stdout for debugging.
   void Print() const;
@@ -473,6 +489,11 @@
     return *speculative_inlining_error_;
   }
 
+  static const LanguageError& background_compilation_error() {
+    ASSERT(background_compilation_error_ != NULL);
+    return *background_compilation_error_;
+  }
+
   static const Array& vm_isolate_snapshot_object_table() {
     ASSERT(vm_isolate_snapshot_object_table_ != NULL);
     return *vm_isolate_snapshot_object_table_;
@@ -507,6 +528,7 @@
   static RawClass* instructions_class() { return instructions_class_; }
   static RawClass* object_pool_class() { return object_pool_class_; }
   static RawClass* pc_descriptors_class() { return pc_descriptors_class_; }
+  static RawClass* code_source_map_class() { return code_source_map_class_; }
   static RawClass* stackmap_class() { return stackmap_class_; }
   static RawClass* var_descriptors_class() { return var_descriptors_class_; }
   static RawClass* exception_handlers_class() {
@@ -563,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.
     //
@@ -577,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.
     //
@@ -589,7 +611,7 @@
     //   get:foo@6be832b        -> foo
     //   _MyClass@6b3832b.      -> _MyClass
     //   _MyClass@6b3832b.named -> _MyClass.named
-    //   _OneByteString          -> String (remapped)
+    //   _OneByteString         -> String (remapped)
     kUserVisibleName
   };
 
@@ -706,8 +728,6 @@
                                  const char* protocol_type,
                                  bool ref) const;
 
-  virtual void PrintJSONImpl(JSONStream* stream, bool ref) const;
-
  private:
   static intptr_t NextFieldOffset() {
     // Indicates this class cannot be extended by dart code.
@@ -768,6 +788,7 @@
   static RawClass* instructions_class_;  // Class of the Instructions vm object.
   static RawClass* object_pool_class_;  // Class of the ObjectPool vm object.
   static RawClass* pc_descriptors_class_;  // Class of PcDescriptors vm object.
+  static RawClass* code_source_map_class_;  // Class of CodeSourceMap vm object.
   static RawClass* stackmap_class_;  // Class of Stackmap vm object.
   static RawClass* var_descriptors_class_;  // Class of LocalVarDescriptors.
   static RawClass* exception_handlers_class_;  // Class of ExceptionHandlers.
@@ -808,6 +829,7 @@
   static LanguageError* snapshot_writer_error_;
   static LanguageError* branch_offset_error_;
   static LanguageError* speculative_inlining_error_;
+  static LanguageError* background_compilation_error_;
   static Array* vm_isolate_snapshot_object_table_;
   static Type* dynamic_type_;
   static Type* void_type_;
@@ -881,6 +903,10 @@
 };
 
 
+typedef ZoneGrowableHandlePtrArray<const AbstractType> Trail;
+typedef ZoneGrowableHandlePtrArray<const AbstractType>* TrailPtr;
+
+
 class Class : public Object {
  public:
   intptr_t instance_size() const {
@@ -927,7 +953,7 @@
   }
 
   RawString* Name() const;
-  RawString* PrettyName() const;
+  RawString* ScrubbedName() const;
   RawString* UserVisibleName() const;
   bool IsInFullSnapshot() const;
 
@@ -936,31 +962,16 @@
   RawScript* script() const { return raw_ptr()->script_; }
   void set_script(const Script& value) const;
 
-  intptr_t token_pos() const { return raw_ptr()->token_pos_; }
-  void set_token_pos(intptr_t value) const;
+  TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
+  void set_token_pos(TokenPosition value) const;
 
-  intptr_t ComputeEndTokenPos() const;
+  TokenPosition ComputeEndTokenPos() const;
 
-  // This class represents the signature class of a closure function if
-  // signature_function() is not null.
-  // The associated function may be a closure function (with code) or a
-  // signature function (without code) solely describing the result type and
-  // parameter types of the signature.
+  // This class represents a typedef if the signature function is not null.
   RawFunction* signature_function() const {
     return raw_ptr()->signature_function_;
   }
-  static intptr_t signature_function_offset() {
-    return OFFSET_OF(RawClass, signature_function_);
-  }
-
-  // Return the signature type of this signature class.
-  // For example, if this class represents a signature of the form
-  // 'F<T, R>(T, [b: B, c: C]) => R', then its signature type is a parameterized
-  // type with this class as the type class and type parameters 'T' and 'R'
-  // as its type argument vector.
-  // SignatureType is used as the type of formal parameters representing a
-  // function.
-  RawType* SignatureType() const;
+  void set_signature_function(const Function& value) const;
 
   // Return the Type with type parameters declared by this class filled in with
   // dynamic and type parameters declared in superclasses filled in as declared
@@ -1004,6 +1015,7 @@
   // not overlapping with the type arguments of the super class of this class.
   intptr_t NumOwnTypeArguments() const;
 
+  // Return true if this class declares type parameters.
   bool IsGeneric() const;
 
   // If this class is parameterized, each instance has a type_arguments field.
@@ -1078,6 +1090,7 @@
     return raw_ptr()->direct_subclasses_;
   }
   void AddDirectSubclass(const Class& subclass) const;
+  void ClearDirectSubclasses() const;
 
   // Check if this class represents the class of null.
   bool IsNullClass() const { return id() == kNullCid; }
@@ -1094,33 +1107,36 @@
   // Check if this class represents the 'Function' class.
   bool IsFunctionClass() const;
 
-  // Check if this class represents a signature class.
-  bool IsSignatureClass() const {
+  // Check if this class represents the 'Closure' class.
+  bool IsClosureClass() const  { return id() == kClosureCid; }
+  static bool IsClosureClass(RawClass* cls) {
+    NoSafepointScope no_safepoint;
+    return cls->ptr()->id_ == kClosureCid;
+  }
+
+  // Check if this class represents a typedef class.
+  bool IsTypedefClass() const {
     return signature_function() != Object::null();
   }
-  static bool IsSignatureClass(RawClass* cls) {
-    return cls->ptr()->signature_function_ != Object::null();
-  }
+
   static bool IsInFullSnapshot(RawClass* cls) {
     NoSafepointScope no_safepoint;
     return cls->ptr()->library_->ptr()->is_in_fullsnapshot_;
   }
 
-  // Check if this class represents a canonical signature class, i.e. not an
-  // alias as defined in a typedef.
-  bool IsCanonicalSignatureClass() const;
-
   // Check the subtype relationship.
   bool IsSubtypeOf(const TypeArguments& type_arguments,
                    const Class& other,
                    const TypeArguments& other_type_arguments,
                    Error* bound_error,
-                   Heap::Space space = Heap::kNew) const {
+                   TrailPtr bound_trail,
+                   Heap::Space space) const {
     return TypeTest(kIsSubtypeOf,
                     type_arguments,
                     other,
                     other_type_arguments,
                     bound_error,
+                    bound_trail,
                     space);
   }
 
@@ -1129,12 +1145,14 @@
                           const Class& other,
                           const TypeArguments& other_type_arguments,
                           Error* bound_error,
-                          Heap::Space space = Heap::kNew) const {
+                          TrailPtr bound_trail,
+                          Heap::Space space) const {
     return TypeTest(kIsMoreSpecificThan,
                     type_arguments,
                     other,
                     other_type_arguments,
                     bound_error,
+                    bound_trail,
                     space);
   }
 
@@ -1165,6 +1183,7 @@
   RawFunction* ImplicitClosureFunctionFromIndex(intptr_t idx) const;
 
   RawFunction* LookupDynamicFunction(const String& name) const;
+  RawFunction* LookupDynamicFunctionAllowAbstract(const String& name) const;
   RawFunction* LookupDynamicFunctionAllowPrivate(const String& name) const;
   RawFunction* LookupStaticFunction(const String& name) const;
   RawFunction* LookupStaticFunctionAllowPrivate(const String& name) const;
@@ -1184,8 +1203,8 @@
 
   void InsertCanonicalConstant(intptr_t index, const Instance& constant) const;
 
-  intptr_t FindCanonicalTypeIndex(const Type& needle) const;
-  RawType* CanonicalTypeFromIndex(intptr_t idx) const;
+  intptr_t FindCanonicalTypeIndex(const AbstractType& needle) const;
+  RawAbstractType* CanonicalTypeFromIndex(intptr_t idx) const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawClass));
@@ -1317,7 +1336,7 @@
   // Allocate instance classes.
   static RawClass* New(const String& name,
                        const Script& script,
-                       intptr_t token_pos);
+                       TokenPosition token_pos);
   static RawClass* NewNativeWrapper(const Library& library,
                                     const String& name,
                                     int num_fields);
@@ -1334,21 +1353,6 @@
   // Allocate the raw ExternalTypedData classes.
   static RawClass* NewExternalTypedDataClass(intptr_t class_id);
 
-  // Allocate a class representing a function signature described by
-  // signature_function, which must be a closure function or a signature
-  // function.
-  // The class may be type parameterized unless the signature_function is in a
-  // static scope. In that case, the type parameters are copied from the owner
-  // class of signature_function.
-  // A null signature function may be passed in and patched later. See below.
-  static RawClass* NewSignatureClass(const String& name,
-                                     const Function& signature_function,
-                                     const Script& script,
-                                     intptr_t token_pos);
-
-  // Patch the signature function of a signature class allocated without it.
-  void PatchSignatureFunction(const Function& signature_function) const;
-
   // Register code that has used CHA for optimization.
   // TODO(srdjan): Also register kind of CHA optimization (e.g.: leaf class,
   // leaf method, ...).
@@ -1367,6 +1371,7 @@
     kAny = 0,
     kStatic,
     kInstance,
+    kInstanceAllowAbstract,
     kConstructor,
     kFactory,
   };
@@ -1387,30 +1392,33 @@
     kEnumBit = 13,
     kIsAllocatedBit = 15,
   };
-  class ConstBit : public BitField<bool, kConstBit, 1> {};
-  class ImplementedBit : public BitField<bool, kImplementedBit, 1> {};
-  class TypeFinalizedBit : public BitField<bool, kTypeFinalizedBit, 1> {};
-  class ClassFinalizedBits : public BitField<RawClass::ClassFinalizedState,
-      kClassFinalizedPos, kClassFinalizedSize> {};  // NOLINT
-  class AbstractBit : public BitField<bool, kAbstractBit, 1> {};
-  class PatchBit : public BitField<bool, kPatchBit, 1> {};
-  class SynthesizedClassBit : public BitField<bool, kSynthesizedClassBit, 1> {};
-  class MarkedForParsingBit : public BitField<bool, kMarkedForParsingBit, 1> {};
-  class MixinAppAliasBit : public BitField<bool, kMixinAppAliasBit, 1> {};
-  class MixinTypeAppliedBit : public BitField<bool, kMixinTypeAppliedBit, 1> {};
-  class FieldsMarkedNullableBit : public BitField<bool,
-      kFieldsMarkedNullableBit, 1> {};  // NOLINT
-  class CycleFreeBit : public BitField<bool, kCycleFreeBit, 1> {};
-  class EnumBit : public BitField<bool, kEnumBit, 1> {};
-  class IsAllocatedBit : public BitField<bool, kIsAllocatedBit, 1> {};
+  class ConstBit : public BitField<uint16_t, bool, kConstBit, 1> {};
+  class ImplementedBit : public BitField<uint16_t, bool, kImplementedBit, 1> {};
+  class TypeFinalizedBit :
+      public BitField<uint16_t, bool, kTypeFinalizedBit, 1> {};
+  class ClassFinalizedBits : public BitField<uint16_t,
+                                             RawClass::ClassFinalizedState,
+                                             kClassFinalizedPos,
+                                             kClassFinalizedSize> {};
+  class AbstractBit : public BitField<uint16_t, bool, kAbstractBit, 1> {};
+  class PatchBit : public BitField<uint16_t, bool, kPatchBit, 1> {};
+  class SynthesizedClassBit :
+      public BitField<uint16_t, bool, kSynthesizedClassBit, 1> {};
+  class MarkedForParsingBit :
+      public BitField<uint16_t, bool, kMarkedForParsingBit, 1> {};
+  class MixinAppAliasBit :
+      public BitField<uint16_t, bool, kMixinAppAliasBit, 1> {};
+  class MixinTypeAppliedBit :
+      public BitField<uint16_t, bool, kMixinTypeAppliedBit, 1> {};
+  class FieldsMarkedNullableBit :
+      public BitField<uint16_t, bool, kFieldsMarkedNullableBit, 1> {};
+  class CycleFreeBit : public BitField<uint16_t, bool, kCycleFreeBit, 1> {};
+  class EnumBit : public BitField<uint16_t, bool, kEnumBit, 1> {};
+  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_signature_function(const Function& value) const;
-  void set_signature_type(const AbstractType& value) const;
   void set_state_bits(intptr_t bits) const;
 
   void set_constants(const Array& value) const;
@@ -1467,6 +1475,7 @@
                 const Class& other,
                 const TypeArguments& other_type_arguments,
                 Error* bound_error,
+                TrailPtr bound_trail,
                 Heap::Space space) const;
 
   static bool TypeTestNonRecursive(
@@ -1476,13 +1485,24 @@
       const Class& other,
       const TypeArguments& other_type_arguments,
       Error* bound_error,
+      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;
   friend class Object;
   friend class Type;
+  friend class FunctionType;
   friend class Intrinsifier;
   friend class Precompiler;
 };
@@ -1496,7 +1516,7 @@
     return raw_ptr()->library_prefix_;
   }
   RawString* ident() const { return raw_ptr()->ident_; }
-  intptr_t token_pos() const { return raw_ptr()->token_pos_; }
+  TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
 
   RawString* Name() const;
 
@@ -1506,12 +1526,12 @@
 
   static RawUnresolvedClass* New(const LibraryPrefix& library_prefix,
                                  const String& ident,
-                                 intptr_t token_pos);
+                                 TokenPosition token_pos);
 
  private:
   void set_library_prefix(const LibraryPrefix& library_prefix) const;
   void set_ident(const String& ident) const;
-  void set_token_pos(intptr_t token_pos) const;
+  void set_token_pos(TokenPosition token_pos) const;
 
   static RawUnresolvedClass* New();
 
@@ -1520,9 +1540,6 @@
 };
 
 
-typedef ZoneGrowableHandlePtrArray<const AbstractType> Trail;
-typedef ZoneGrowableHandlePtrArray<const AbstractType>* TrailPtr;
-
 // A TypeArguments is an array of AbstractType.
 class TypeArguments : public Object {
  public:
@@ -1539,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 {
@@ -1571,8 +1582,10 @@
                    intptr_t from_index,
                    intptr_t len,
                    Error* bound_error,
-                   Heap::Space space = Heap::kNew) const {
-    return TypeTest(kIsSubtypeOf, other, from_index, len, bound_error, space);
+                   TrailPtr bound_trail,
+                   Heap::Space space) const {
+    return TypeTest(kIsSubtypeOf, other, from_index, len,
+                    bound_error, bound_trail, space);
   }
 
   // Check the 'more specific' relationship, considering only a subvector of
@@ -1581,9 +1594,10 @@
                           intptr_t from_index,
                           intptr_t len,
                           Error* bound_error,
-                          Heap::Space space = Heap::kNew) const {
-    return TypeTest(kIsMoreSpecificThan,
-        other, from_index, len, bound_error, space);
+                          TrailPtr bound_trail,
+                          Heap::Space space) const {
+    return TypeTest(kIsMoreSpecificThan, other, from_index, len,
+                    bound_error, bound_trail, space);
   }
 
   // Check if the vectors are equal (they may be null).
@@ -1631,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
@@ -1639,8 +1656,9 @@
   RawTypeArguments* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
-      Heap::Space space = Heap::kNew) const;
+      TrailPtr instantiation_trail,
+      TrailPtr bound_trail,
+      Heap::Space space) const;
 
   // Runtime instantiation with canonicalization. Not to be used during type
   // finalization at compile time.
@@ -1696,6 +1714,7 @@
                 intptr_t from_index,
                 intptr_t len,
                 Error* bound_error,
+                TrailPtr bound_trail,
                 Heap::Space space) const;
 
   // Return the internal or public name of a subvector of this type argument
@@ -1823,13 +1842,6 @@
   bool HasDeoptReason(ICData::DeoptReasonId reason) const;
   void AddDeoptReason(ICData::DeoptReasonId reason) const;
 
-  bool IssuedJSWarning() const;
-  void SetIssuedJSWarning() const;
-
-  // Return true if the target function of this IC data may check for (and
-  // possibly issue) a Javascript compatibility warning.
-  bool MayCheckForJSWarning() const;
-
   intptr_t NumberOfChecks() const;
 
   // Discounts any checks with usage of zero.
@@ -1930,11 +1942,8 @@
                         intptr_t num_args_tested);
   static RawICData* NewFrom(const ICData& from, intptr_t num_args_tested);
 
-  // Generates a new ICData with descriptor data copied (shallow clone).
-  // Entry array of the result is the same as in 'from'. Once entry array is
-  // created, it can only change the 'count', all other properties are invariant
-  // (target, cids, number of checks).
-  static RawICData* CloneDescriptor(const ICData& from);
+  // Generates a new ICData with descriptor and data array copied (deep clone).
+  static RawICData* Clone(const ICData& from);
 
   static intptr_t TestEntryLengthFor(intptr_t num_args);
 
@@ -2018,16 +2027,16 @@
     }
   }
 
-  // It is only meaningful to interptret range feedback stored in the ICData
+  // It is only meaningful to interpret range feedback stored in the ICData
   // when all checks are Mint or Smi.
   bool HasRangeFeedback() const;
   RangeFeedback DecodeRangeFeedbackAt(intptr_t idx) const;
 
   void PrintToJSONArray(const JSONArray& jsarray,
-                        intptr_t token_pos,
+                        TokenPosition token_pos,
                         bool is_static_call) const;
   void PrintToJSONArrayNew(const JSONArray& jsarray,
-                           intptr_t token_pos,
+                           TokenPosition token_pos,
                            bool is_static_call) const;
 
   // Initialize the preallocated empty ICData entry arrays.
@@ -2057,18 +2066,22 @@
     kNumArgsTestedSize = 2,
     kDeoptReasonPos = kNumArgsTestedPos + kNumArgsTestedSize,
     kDeoptReasonSize = kLastRecordedDeoptReason + 1,
-    kIssuedJSWarningBit = kDeoptReasonPos + kDeoptReasonSize,
-    kRangeFeedbackPos = kIssuedJSWarningBit + 1,
+    kRangeFeedbackPos = kDeoptReasonPos + kDeoptReasonSize,
     kRangeFeedbackSize = kBitsPerRangeFeedback * kRangeFeedbackSlots
   };
 
   class NumArgsTestedBits : public BitField<uint32_t,
-      kNumArgsTestedPos, kNumArgsTestedSize> {};  // NOLINT
+                                            uint32_t,
+                                            kNumArgsTestedPos,
+                                            kNumArgsTestedSize> {};
   class DeoptReasonBits : public BitField<uint32_t,
-      ICData::kDeoptReasonPos, ICData::kDeoptReasonSize> {};  // NOLINT
-  class IssuedJSWarningBit : public BitField<bool, kIssuedJSWarningBit, 1> {};
+                                          uint32_t,
+                                          ICData::kDeoptReasonPos,
+                                          ICData::kDeoptReasonSize> {};
   class RangeFeedbackBits : public BitField<uint32_t,
-      ICData::kRangeFeedbackPos, ICData::kRangeFeedbackSize> {};  // NOLINT
+                                            uint32_t,
+                                            ICData::kRangeFeedbackPos,
+                                            ICData::kRangeFeedbackSize> {};
 
 #if defined(DEBUG)
   // Used in asserts to verify that a check is not added twice.
@@ -2099,15 +2112,28 @@
 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;
 
+  // Return the type of this function's signature. It may not be canonical yet.
+  // For example, if this function has a signature of the form
+  // '(T, [b: B, c: C]) => R', where 'T' and 'R' are type parameters of the
+  // owner class of this function, then its signature type is a parameterized
+  // FunctionType with uninstantiated type arguments 'T' and 'R' as elements of
+  // its type argument vector.
+  RawFunctionType* SignatureType() const;
+
+  // Update the signature type (with a canonical version).
+  void SetSignatureType(const FunctionType& value) const;
+
   // Build a string of the form 'C<T, R>(T, {b: B, c: C}) => R' representing the
   // internal signature of the given function. In this example, T and R are
   // type parameters of class C, the owner of the function.
@@ -2116,17 +2142,12 @@
     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.
+  // type parameters of class C, the owner of the function, also called the
+  // scope class of the function type.
   // Implicit parameters are hidden, as well as the prefix denoting the
-  // signature class and its type parameters.
+  // scope class and its type parameters.
   RawString* UserVisibleSignature() const {
     const bool instantiate = false;
     return BuildSignature(
@@ -2219,10 +2240,6 @@
   // Enclosing function of this local function.
   RawFunction* parent_function() const;
 
-  // Signature class of this closure function or signature function.
-  RawClass* signature_class() const;
-  void set_signature_class(const Class& value) const;
-
   void set_extracted_method_closure(const Function& function) const;
   RawFunction* extracted_method_closure() const;
 
@@ -2284,8 +2301,8 @@
   bool IsFactory() const {
     return (kind() == RawFunction::kConstructor) && is_static();
   }
-  bool IsDynamicFunction() const {
-    if (is_static() || is_abstract()) {
+  bool IsDynamicFunction(bool allow_abstract = false) const {
+    if (is_static() || (!allow_abstract && is_abstract())) {
       return false;
     }
     switch (kind()) {
@@ -2331,11 +2348,11 @@
   }
   bool IsInFactoryScope() const;
 
-  intptr_t token_pos() const { return raw_ptr()->token_pos_; }
-  void set_token_pos(intptr_t value) const;
+  TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
+  void set_token_pos(TokenPosition value) const;
 
-  intptr_t end_token_pos() const { return raw_ptr()->end_token_pos_; }
-  void set_end_token_pos(intptr_t value) const {
+  TokenPosition end_token_pos() const { return raw_ptr()->end_token_pos_; }
+  void set_end_token_pos(TokenPosition value) const {
     StoreNonPointer(&raw_ptr()->end_token_pos_, value);
   }
 
@@ -2470,7 +2487,7 @@
                    const Function& other,
                    const TypeArguments& other_type_arguments,
                    Error* bound_error,
-                   Heap::Space space = Heap::kNew) const {
+                   Heap::Space space) const {
     return TypeTest(kIsSubtypeOf,
                     type_arguments,
                     other,
@@ -2485,7 +2502,7 @@
                           const Function& other,
                           const TypeArguments& other_type_arguments,
                           Error* bound_error,
-                   Heap::Space space = Heap::kNew) const {
+                          Heap::Space space) const {
     return TypeTest(kIsMoreSpecificThan,
                     type_arguments,
                     other,
@@ -2494,6 +2511,14 @@
                     space);
   }
 
+  // Check the subtype or 'more specific' relationship.
+  bool TypeTest(TypeTestKind test_kind,
+                const TypeArguments& type_arguments,
+                const Function& other,
+                const TypeArguments& other_type_arguments,
+                Error* bound_error,
+                Heap::Space space) const;
+
   // Returns true if this function represents an explicit getter function.
   bool IsGetterFunction() const {
     return kind() == RawFunction::kGetterFunction;
@@ -2538,7 +2563,7 @@
   bool IsImplicitStaticClosureFunction() const {
     return is_static() && IsImplicitClosureFunction();
   }
-  bool static IsImplicitStaticClosureFunction(RawFunction* func);
+  static bool IsImplicitStaticClosureFunction(RawFunction* func);
 
   // Returns true if this function represents an implicit instance closure
   // function.
@@ -2557,6 +2582,11 @@
   bool IsSignatureFunction() const {
     return kind() == RawFunction::kSignatureFunction;
   }
+  static bool IsSignatureFunction(RawFunction* function) {
+    NoSafepointScope no_safepoint;
+    return KindBits::decode(function->ptr()->kind_tag_) ==
+        RawFunction::kSignatureFunction;
+  }
 
   bool IsAsyncFunction() const {
     return modifier() == RawFunction::kAsync;
@@ -2610,15 +2640,17 @@
                           bool is_external,
                           bool is_native,
                           const Object& owner,
-                          intptr_t token_pos);
+                          TokenPosition token_pos);
 
-  // Allocates a new Function object representing a closure function, as well as
-  // a new associated Class object representing the signature class of the
-  // function.
-  // The function and the class share the same given name.
+  // Allocates a new Function object representing a closure function.
   static RawFunction* NewClosureFunction(const String& name,
                                          const Function& parent,
-                                         intptr_t token_pos);
+                                         TokenPosition token_pos);
+
+  // Allocates a new Function object representing a signature function.
+  // The owner is the scope class of the function type.
+  static RawFunction* NewSignatureFunction(const Class& owner,
+                                           TokenPosition token_pos);
 
   static RawFunction* NewEvalFunction(const Class& owner,
                                       const Script& script,
@@ -2642,11 +2674,10 @@
   void SaveICDataMap(
       const ZoneGrowableArray<const ICData*>& deopt_id_to_ic_data,
       const Array& edge_counters_array) const;
-  // Uses saved ICData to populate the table 'deopt_id_to_ic_data'. Clone
-  // descriptors if 'clone_descriptors' true.
-  void RestoreICDataMap(
-      ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data,
-      bool clone_descriptors) const;
+  // Uses 'ic_data_array' to populate the table 'deopt_id_to_ic_data'. Clone
+  // ic_data (array and descriptor) if 'clone_ic_data' is true.
+  void RestoreICDataMap(ZoneGrowableArray<const ICData*>* deopt_id_to_ic_data,
+                        bool clone_ic_data) const;
 
   RawArray* ic_data_array() const;
   void ClearICDataArray() const;
@@ -2735,18 +2766,19 @@
       (kBitsPerByte * sizeof(static_cast<RawFunction*>(0)->kind_tag_)));
 
   class KindBits :
-    public BitField<RawFunction::Kind, kKindTagPos, kKindTagSize> {};  // NOLINT
+    public BitField<uint32_t, RawFunction::Kind, kKindTagPos, kKindTagSize> {};
 
-  class RecognizedBits : public BitField<MethodRecognizer::Kind,
+  class RecognizedBits : public BitField<uint32_t,
+                                         MethodRecognizer::Kind,
                                          kRecognizedTagPos,
                                          kRecognizedTagSize> {};
-  class ModifierBits :
-    public BitField<RawFunction::AsyncModifier,
-                   kModifierPos,
-                   kModifierSize> {};  // NOLINT
+  class ModifierBits : public BitField<uint32_t,
+                                       RawFunction::AsyncModifier,
+                                       kModifierPos,
+                                       kModifierSize> {};
 
 #define DEFINE_BIT(name, _) \
-  class name##Bit : public BitField<bool, k##name##Bit, 1> {};
+  class name##Bit : public BitField<uint32_t, bool, k##name##Bit, 1> {};
 FOR_EACH_FUNCTION_KIND_BIT(DEFINE_BIT)
 #undef DEFINE_BIT
 
@@ -2766,6 +2798,8 @@
 
   static RawFunction* New();
 
+  RawString* QualifiedName(NameVisibility name_visibility) const;
+
   void BuildSignatureParameters(
       bool instantiate,
       NameVisibility name_visibility,
@@ -2775,14 +2809,6 @@
                             NameVisibility name_visibility,
                             const TypeArguments& instantiator) const;
 
-  // Check the subtype or 'more specific' relationship.
-  bool TypeTest(TypeTestKind test_kind,
-                const TypeArguments& type_arguments,
-                const Function& other,
-                const TypeArguments& other_type_arguments,
-                Error* bound_error,
-                Heap::Space space) const;
-
   // Checks the type of the formal parameter at the given position for
   // subtyping or 'more specific' relationship between the type of this function
   // and the type of the other function.
@@ -2819,9 +2845,9 @@
   RawFunction* parent_function() const { return raw_ptr()->parent_function_; }
   void set_parent_function(const Function& value) const;
 
-  // Signature class of this closure function or signature function.
-  RawClass* signature_class() const { return raw_ptr()->signature_class_; }
-  void set_signature_class(const Class& value) const;
+  // Signature type of this closure function.
+  RawFunctionType* signature_type() const { return raw_ptr()->signature_type_; }
+  void set_signature_type(const FunctionType& value) const;
 
   RawInstance* implicit_static_closure() const {
     return raw_ptr()->closure_;
@@ -2867,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_); }
@@ -2879,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 {
@@ -2888,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_));
   }
 
@@ -2899,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.
@@ -2919,17 +2960,20 @@
                        bool is_reflectable,
                        const Class& owner,
                        const AbstractType& type,
-                       intptr_t token_pos);
+                       TokenPosition token_pos);
 
   static RawField* NewTopLevel(const String& name,
                                bool is_final,
                                bool is_const,
                                const Object& owner,
-                               intptr_t token_pos);
+                               TokenPosition token_pos);
 
   // Allocate new field object, clone values from this field. The
   // owner of the clone is new_owner.
   RawField* Clone(const Class& new_owner) const;
+  // 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_);
@@ -2940,13 +2984,14 @@
 
   static intptr_t kind_bits_offset() { return OFFSET_OF(RawField, kind_bits_); }
 
-  intptr_t token_pos() const { return raw_ptr()->token_pos_; }
+  TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
 
   bool has_initializer() const {
     return HasInitializerBit::decode(raw_ptr()->kind_bits_);
   }
   // 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_));
@@ -2997,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_));
   }
 
@@ -3091,15 +3137,16 @@
     kReflectableBit,
     kDoubleInitializedBit,
   };
-  class ConstBit : public BitField<bool, kConstBit, 1> {};
-  class StaticBit : public BitField<bool, kStaticBit, 1> {};
-  class FinalBit : public BitField<bool, kFinalBit, 1> {};
-  class HasInitializerBit : public BitField<bool, kHasInitializerBit, 1> {};
-  class UnboxingCandidateBit : public BitField<bool,
-                                               kUnboxingCandidateBit, 1> {};
-  class ReflectableBit : public BitField<bool, kReflectableBit, 1> {};
-  class DoubleInitializedBit : public BitField<bool,
-                                               kDoubleInitializedBit, 1> {};
+  class ConstBit : public BitField<uint8_t, bool, kConstBit, 1> {};
+  class StaticBit : public BitField<uint8_t, bool, kStaticBit, 1> {};
+  class FinalBit : public BitField<uint8_t, bool, kFinalBit, 1> {};
+  class HasInitializerBit :
+      public BitField<uint8_t, bool, kHasInitializerBit, 1> {};
+  class UnboxingCandidateBit :
+      public BitField<uint8_t, bool, kUnboxingCandidateBit, 1> {};
+  class ReflectableBit : public BitField<uint8_t, bool, kReflectableBit, 1> {};
+  class DoubleInitializedBit :
+      public BitField<uint8_t, bool, kDoubleInitializedBit, 1> {};
 
   // Update guarded cid and guarded length for this field. Returns true, if
   // deoptimization of dependent code is required.
@@ -3118,11 +3165,11 @@
   void set_owner(const Object& value) const {
     StorePointer(&raw_ptr()->owner_, value.raw());
   }
-  void set_token_pos(intptr_t token_pos) const {
+  void set_token_pos(TokenPosition token_pos) const {
     StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
   }
-  void set_kind_bits(intptr_t value) const {
-    StoreNonPointer(&raw_ptr()->kind_bits_, static_cast<uint8_t>(value));
+  void set_kind_bits(uint8_t value) const {
+    StoreNonPointer(&raw_ptr()->kind_bits_, value);
   }
 
   static RawField* New();
@@ -3168,8 +3215,9 @@
   void SetStream(const ExternalTypedData& stream) const;
 
   RawString* GenerateSource() const;
-  RawString* GenerateSource(intptr_t start, intptr_t end) const;
-  intptr_t ComputeSourcePosition(intptr_t tok_pos) const;
+  RawString* GenerateSource(TokenPosition start,
+                            TokenPosition end) const;
+  TokenPosition ComputeSourcePosition(TokenPosition tok_pos) const;
 
   RawString* PrivateKey() const;
 
@@ -3198,10 +3246,10 @@
     };
 
     Iterator(const TokenStream& tokens,
-             intptr_t token_pos,
+             TokenPosition token_pos,
              Iterator::StreamType stream_type = kNoNewlines);
 
-    void SetStream(const TokenStream& tokens, intptr_t token_pos);
+    void SetStream(const TokenStream& tokens, TokenPosition token_pos);
     bool IsValid() const;
 
     inline Token::Kind CurrentTokenKind() const {
@@ -3210,8 +3258,8 @@
 
     Token::Kind LookaheadTokenKind(intptr_t num_tokens);
 
-    intptr_t CurrentPosition() const;
-    void SetCurrentPosition(intptr_t value);
+    TokenPosition CurrentPosition() const;
+    void SetCurrentPosition(TokenPosition token_pos);
 
     void Advance();
 
@@ -3281,7 +3329,7 @@
 
   void SetLocationOffset(intptr_t line_offset, intptr_t col_offset) const;
 
-  void GetTokenLocation(intptr_t token_pos,
+  void GetTokenLocation(TokenPosition token_pos,
                         intptr_t* line,
                         intptr_t* column,
                         intptr_t* token_len = NULL) const;
@@ -3291,8 +3339,8 @@
   // after, but not on given line, returns in *first_token_index the index of
   // the first token after the line, and a negative value in *last_token_index.
   void TokenRangeAtLine(intptr_t line_number,
-                        intptr_t* first_token_index,
-                        intptr_t* last_token_index) const;
+                        TokenPosition* first_token_index,
+                        TokenPosition* last_token_index) const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawScript));
@@ -3429,6 +3477,7 @@
   void AddClass(const Class& cls) const;
   void AddObject(const Object& obj, const String& name) const;
   void ReplaceObject(const Object& obj, const String& name) const;
+  bool RemoveObject(const Object& obj, const String& name) const;
   RawObject* LookupReExport(const String& name) const;
   RawObject* LookupObjectAllowPrivate(const String& name) const;
   RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
@@ -3460,12 +3509,14 @@
 
   void AddClassMetadata(const Class& cls,
                         const Object& tl_owner,
-                        intptr_t token_pos) const;
-  void AddFieldMetadata(const Field& field, intptr_t token_pos) const;
-  void AddFunctionMetadata(const Function& func, intptr_t token_pos) const;
-  void AddLibraryMetadata(const Object& tl_owner, intptr_t token_pos) const;
+                        TokenPosition token_pos) const;
+  void AddFieldMetadata(const Field& field, TokenPosition token_pos) const;
+  void AddFunctionMetadata(const Function& func,
+                           TokenPosition token_pos) const;
+  void AddLibraryMetadata(const Object& tl_owner,
+                          TokenPosition token_pos) const;
   void AddTypeParameterMetadata(const TypeParameter& param,
-                                intptr_t token_pos) const;
+                                TokenPosition token_pos) const;
   RawObject* GetMetadata(const Object& obj) const;
 
   RawClass* toplevel_class() const {
@@ -3486,6 +3537,8 @@
   RawLibrary* ImportLibraryAt(intptr_t index) const;
   bool ImportsCorelib() const;
 
+  void DropDependencies() const;
+
   // Resolving native methods for script loaded in the library.
   Dart_NativeEntryResolver native_entry_resolver() const {
     return raw_ptr()->native_entry_resolver_;
@@ -3601,7 +3654,8 @@
   void InitClassDictionary() const;
 
   RawArray* resolved_names() const { return raw_ptr()->resolved_names_; }
-  void InitResolvedNamesCache(intptr_t size) const;
+  void InitResolvedNamesCache(intptr_t size,
+                              SnapshotReader* reader = NULL) const;
   void GrowResolvedNamesCache() const;
   bool LookupResolvedNamesCache(const String& name, Object* obj) const;
   void AddToResolvedNamesCache(const String& name, const Object& obj) const;
@@ -3621,7 +3675,7 @@
   RawField* GetMetadataField(const String& metaname) const;
   void AddMetadata(const Object& owner,
                    const String& name,
-                   intptr_t token_pos) const;
+                   TokenPosition token_pos) const;
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(Library, Object);
 
@@ -3642,7 +3696,7 @@
   RawArray* show_names() const { return raw_ptr()->show_names_; }
   RawArray* hide_names() const { return raw_ptr()->hide_names_; }
 
-  void AddMetadata(const Object& owner, intptr_t token_pos);
+  void AddMetadata(const Object& owner, TokenPosition token_pos);
   RawObject* GetMetadata() const;
 
   static intptr_t InstanceSize() {
@@ -3813,6 +3867,14 @@
         entry_point - HeaderSize() + kHeapObjectTag);
   }
 
+  bool Equals(const Instructions& other) const {
+    if (size() != other.size()) {
+      return false;
+    }
+    NoSafepointScope no_safepoint;
+    return memcmp(raw_ptr(), other.raw_ptr(), InstanceSize(size())) == 0;
+  }
+
  private:
   void set_size(intptr_t size) const {
     StoreNonPointer(&raw_ptr()->size_, size);
@@ -3939,7 +4001,7 @@
 
     uword PcOffset() const { return cur_pc_offset_; }
     intptr_t DeoptId() const { return cur_deopt_id_; }
-    intptr_t TokenPos() const { return cur_token_pos_; }
+    TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); }
     intptr_t TryIndex() const { return cur_try_index_; }
     RawPcDescriptors::Kind Kind() const {
       return static_cast<RawPcDescriptors::Kind>(cur_kind_);
@@ -3986,6 +4048,89 @@
 };
 
 
+class CodeSourceMap : public Object {
+ public:
+  static const intptr_t kBytesPerElement = 1;
+  static const intptr_t kMaxElements = kMaxInt32 / kBytesPerElement;
+
+  static intptr_t InstanceSize() {
+    ASSERT(sizeof(RawCodeSourceMap) ==
+           OFFSET_OF_RETURNED_VALUE(RawCodeSourceMap, data));
+    return 0;
+  }
+  static intptr_t InstanceSize(intptr_t len) {
+    ASSERT(0 <= len && len <= kMaxElements);
+    return RoundedAllocationSize(sizeof(RawCodeSourceMap) + len);
+  }
+
+  static RawCodeSourceMap* New(GrowableArray<uint8_t>* delta_encoded_data);
+
+  void PrintToJSONObject(JSONObject* jsobj, bool ref) const;
+
+  // Encode integer in SLEB128 format.
+  static void EncodeInteger(GrowableArray<uint8_t>* data, intptr_t value);
+
+  // 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)
+        : code_source_map_(code_source_map),
+          byte_index_(0),
+          cur_pc_offset_(0),
+          cur_token_pos_(0) {
+    }
+
+    bool MoveNext() {
+      // Moves to the next record.
+      while (byte_index_ < code_source_map_.Length()) {
+        cur_pc_offset_ += code_source_map_.DecodeInteger(&byte_index_);
+        cur_token_pos_ += code_source_map_.DecodeInteger(&byte_index_);
+
+        return true;
+      }
+      return false;
+    }
+
+    uword PcOffset() const { return cur_pc_offset_; }
+    TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); }
+
+   private:
+    friend class CodeSourceMap;
+
+    const CodeSourceMap& code_source_map_;
+    intptr_t byte_index_;
+
+    intptr_t cur_pc_offset_;
+    intptr_t cur_token_pos_;
+  };
+
+ private:
+  static RawCodeSourceMap* New(intptr_t length);
+
+  intptr_t Length() const;
+  void SetLength(intptr_t value) const;
+  void CopyData(GrowableArray<uint8_t>* data);
+
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(CodeSourceMap, Object);
+  friend class Class;
+  friend class Object;
+};
+
+
 class Stackmap : public Object {
  public:
   static const intptr_t kNoMaximum = -1;
@@ -4216,6 +4361,15 @@
     StorePointer(&raw_ptr()->pc_descriptors_, descriptors.raw());
   }
 
+  RawCodeSourceMap* code_source_map() const {
+    return raw_ptr()->code_source_map_;
+  }
+
+  void set_code_source_map(const CodeSourceMap& code_source_map) const {
+    ASSERT(code_source_map.IsOld());
+    StorePointer(&raw_ptr()->code_source_map_, code_source_map.raw());
+  }
+
   // Array of DeoptInfo objects.
   RawArray* deopt_info_array() const {
     return raw_ptr()->deopt_info_array_;
@@ -4308,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;
 
@@ -4386,7 +4543,7 @@
     NoSafepointScope no_safepoint;
     return *PointerOffsetAddrAt(index);
   }
-  intptr_t GetTokenIndexOfPC(uword pc) const;
+  TokenPosition GetTokenIndexOfPC(uword pc) const;
 
   enum {
     kInvalidPc = -1
@@ -4399,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_;
@@ -4447,9 +4604,10 @@
     kPtrOffSize = 30,
   };
 
-  class OptimizedBit : public BitField<bool, kOptimizedBit, 1> {};
-  class AliveBit : public BitField<bool, kAliveBit, 1> {};
-  class PtrOffBits : public BitField<intptr_t, kPtrOffBit, kPtrOffSize> {};
+  class OptimizedBit : public BitField<int32_t, bool, kOptimizedBit, 1> {};
+  class AliveBit : public BitField<int32_t, bool, kAliveBit, 1> {};
+  class PtrOffBits :
+      public BitField<int32_t, intptr_t, kPtrOffBit, kPtrOffSize> {};
 
   class SlowFindRawCodeVisitor : public FindObjectVisitor {
    public:
@@ -4515,6 +4673,7 @@
   friend class Class;
   friend class SnapshotWriter;
   friend class CodePatcher;  // for set_instructions
+  friend class Precompiler;  // for set_instructions
   // So that the RawFunction pointer visitor can determine whether code the
   // function points to is optimized.
   friend class RawFunction;
@@ -4591,8 +4750,8 @@
  public:
   intptr_t num_variables() const { return raw_ptr()->num_variables_; }
 
-  intptr_t TokenIndexAt(intptr_t scope_index) const;
-  void SetTokenIndexAt(intptr_t scope_index, intptr_t token_pos) const;
+  TokenPosition TokenIndexAt(intptr_t scope_index) const;
+  void SetTokenIndexAt(intptr_t scope_index, TokenPosition token_pos) const;
 
   RawString* NameAt(intptr_t scope_index) const;
   void SetNameAt(intptr_t scope_index, const String& name) const;
@@ -4726,7 +4885,7 @@
 class SubtypeTestCache : public Object {
  public:
   enum Entries {
-    kInstanceClassId = 0,
+    kInstanceClassIdOrFunction = 0,
     kInstanceTypeArguments = 1,
     kInstantiatorTypeArguments = 2,
     kTestResult = 3,
@@ -4734,12 +4893,12 @@
   };
 
   intptr_t NumberOfChecks() const;
-  void AddCheck(intptr_t class_id,
+  void AddCheck(const Object& instance_class_id_or_function,
                 const TypeArguments& instance_type_arguments,
                 const TypeArguments& instantiator_type_arguments,
                 const Bool& test_result) const;
   void GetCheck(intptr_t ix,
-                intptr_t* class_id,
+                Object* instance_class_id_or_function,
                 TypeArguments* instance_type_arguments,
                 TypeArguments* instantiator_type_arguments,
                 Bool* test_result) const;
@@ -4816,15 +4975,17 @@
   // A null script means no source and a negative token_pos means no position.
   static RawLanguageError* NewFormatted(const Error& prev_error,
                                         const Script& script,
-                                        intptr_t token_pos,
+                                        TokenPosition token_pos,
+                                        bool report_after_token,
                                         Report::Kind kind,
                                         Heap::Space space,
                                         const char* format, ...)
-    PRINTF_ATTRIBUTE(6, 7);
+    PRINTF_ATTRIBUTE(7, 8);
 
   static RawLanguageError* NewFormattedV(const Error& prev_error,
                                          const Script& script,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
+                                         bool report_after_token,
                                          Report::Kind kind,
                                          Heap::Space space,
                                          const char* format, va_list args);
@@ -4844,8 +5005,11 @@
   RawScript* script() const { return raw_ptr()->script_; }
   void set_script(const Script& value) const;
 
-  intptr_t token_pos() const { return raw_ptr()->token_pos_; }
-  void set_token_pos(intptr_t value) const;
+  TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
+  void set_token_pos(TokenPosition value) const;
+
+  bool report_after_token() const { return raw_ptr()->report_after_token_; }
+  void set_report_after_token(bool value);
 
   void set_kind(uint8_t value) const;
 
@@ -4957,7 +5121,7 @@
     StorePointer(FieldAddr(field), value.raw());
   }
 
-  RawType* GetType() const;
+  RawAbstractType* GetType() const;
 
   virtual RawTypeArguments* GetTypeArguments() const;
   virtual void SetTypeArguments(const TypeArguments& value) const;
@@ -4984,9 +5148,6 @@
 
   void SetNativeField(int index, intptr_t value) const;
 
-  // Returns true if the instance is a closure object.
-  bool IsClosure() const;
-
   // If the instance is a callable object, i.e. a closure or the instance of a
   // class implementing a 'call' method, return true and set the function
   // (if not NULL) to call.
@@ -5015,7 +5176,9 @@
   static intptr_t ElementSizeFor(intptr_t cid);
 
  protected:
+#ifndef PRODUCT
   virtual void PrintSharedInstanceJSON(JSONObject* jsobj, bool ref) const;
+#endif
 
  private:
   RawObject** FieldAddrAtOffset(intptr_t offset) const {
@@ -5113,18 +5276,22 @@
 class AbstractType : public Instance {
  public:
   virtual bool IsFinalized() const;
+  virtual void SetIsFinalized() const;
   virtual bool IsBeingFinalized() const;
+  virtual void SetIsBeingFinalized() const;
   virtual bool IsMalformed() const;
   virtual bool IsMalbounded() const;
   virtual bool IsMalformedOrMalbounded() const;
   virtual RawLanguageError* error() const;
   virtual void set_error(const LanguageError& value) const;
   virtual bool IsResolved() const;
+  virtual void SetIsResolved() const;
   virtual bool HasResolvedTypeClass() const;
   virtual RawClass* type_class() const;
   virtual RawUnresolvedClass* unresolved_class() const;
   virtual RawTypeArguments* arguments() const;
-  virtual intptr_t token_pos() const;
+  virtual void set_arguments(const TypeArguments& value) const;
+  virtual TokenPosition token_pos() const;
   virtual bool IsInstantiated(TrailPtr trail = NULL) const;
   virtual bool CanonicalizeEquals(const Instance& other) const {
     return Equals(other);
@@ -5141,8 +5308,9 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
-      Heap::Space space = Heap::kNew) const;
+      TrailPtr instantiation_trail,
+      TrailPtr bound_trail,
+      Heap::Space space) const;
 
   // Return a clone of this unfinalized type or the type itself if it is
   // already finalized. Apply recursively to type arguments, i.e. finalized
@@ -5172,21 +5340,35 @@
   // the trail. The receiver may only be added once with its only buddy.
   void AddOnlyBuddyToTrail(TrailPtr* trail, const AbstractType& buddy) const;
 
+  // Return true if the receiver is contained in the trail.
+  // Otherwise, if the trail is null, allocate a trail, then add the receiver to
+  // the trail and return false.
+  bool TestAndAddToTrail(TrailPtr* trail) const;
+
+  // Return true if the pair <receiver, buddy> is contained in the trail.
+  // Otherwise, if the trail is null, allocate a trail, add the pair <receiver,
+  // buddy> to the trail and return false.
+  // The receiver may be added several times, each time with a different buddy.
+  bool TestAndAddBuddyToTrail(TrailPtr* trail, const AbstractType& buddy) const;
+
   // The name of this type, including the names of its type arguments, if any.
   virtual RawString* Name() const {
     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
@@ -5238,21 +5420,24 @@
   // Check if this type represents the 'String' type.
   bool IsStringType() const;
 
-  // Check if this type represents the 'Function' type.
-  bool IsFunctionType() const;
+  // Check if this type represents the Dart 'Function' type.
+  bool IsDartFunctionType() const;
 
   // Check the subtype relationship.
   bool IsSubtypeOf(const AbstractType& other,
                    Error* bound_error,
-                   Heap::Space space = Heap::kNew) const {
-    return TypeTest(kIsSubtypeOf, other, bound_error, space);
+                   TrailPtr bound_trail,
+                   Heap::Space space) const {
+    return TypeTest(kIsSubtypeOf, other, bound_error, bound_trail, space);
   }
 
   // Check the 'more specific' relationship.
   bool IsMoreSpecificThan(const AbstractType& other,
                           Error* bound_error,
-                          Heap::Space space = Heap::kNew) const {
-    return TypeTest(kIsMoreSpecificThan, other, bound_error, space);
+                          TrailPtr bound_trail,
+                          Heap::Space space) const {
+    return TypeTest(kIsMoreSpecificThan, other,
+                    bound_error, bound_trail, space);
   }
 
  private:
@@ -5260,6 +5445,7 @@
   bool TypeTest(TypeTestKind test_kind,
                 const AbstractType& other,
                 Error* bound_error,
+                TrailPtr bound_trail,
                 Heap::Space space) const;
 
   // Return the internal or public name of this type, including the names of its
@@ -5291,12 +5477,11 @@
         (raw_ptr()->type_state_ == RawType::kFinalizedInstantiated) ||
         (raw_ptr()->type_state_ == RawType::kFinalizedUninstantiated);
   }
-  void SetIsFinalized() const;
-  void ResetIsFinalized() const;  // Ignore current state and set again.
+  virtual void SetIsFinalized() const;
   virtual bool IsBeingFinalized() const {
     return raw_ptr()->type_state_ == RawType::kBeingFinalized;
   }
-  void set_is_being_finalized() const;
+  virtual void SetIsBeingFinalized() const;
   virtual bool IsMalformed() const;
   virtual bool IsMalbounded() const;
   virtual bool IsMalformedOrMalbounded() const;
@@ -5305,27 +5490,29 @@
   virtual bool IsResolved() const {
     return raw_ptr()->type_state_ >= RawType::kResolved;
   }
-  void set_is_resolved() const;
+  virtual void SetIsResolved() const;
   virtual bool HasResolvedTypeClass() const;  // Own type class resolved.
   virtual RawClass* type_class() const;
   void set_type_class(const Object& value) const;
   virtual RawUnresolvedClass* unresolved_class() const;
-  virtual RawTypeArguments* arguments() const;
-  void set_arguments(const TypeArguments& value) const;
-  virtual intptr_t token_pos() const { return raw_ptr()->token_pos_; }
+  virtual RawTypeArguments* arguments() const { return raw_ptr()->arguments_; }
+  virtual void set_arguments(const TypeArguments& value) const;
+  virtual TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
   virtual bool IsInstantiated(TrailPtr trail = NULL) const;
   virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
   virtual bool IsRecursive() const;
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
-      Heap::Space space = Heap::kNew) const;
+      TrailPtr instantiation_trail,
+      TrailPtr bound_trail,
+      Heap::Space space) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
       const Class& new_owner,
       TrailPtr trail = NULL) const;
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
@@ -5386,11 +5573,11 @@
 
   static RawType* New(const Object& clazz,
                       const TypeArguments& arguments,
-                      intptr_t token_pos,
+                      TokenPosition token_pos,
                       Heap::Space space = Heap::kOld);
 
  private:
-  void set_token_pos(intptr_t token_pos) const;
+  void set_token_pos(TokenPosition token_pos) const;
   void set_type_state(int8_t state) const;
 
   static RawType* New(Heap::Space space = Heap::kOld);
@@ -5401,6 +5588,106 @@
 };
 
 
+// TODO(regis): FunctionType is very similar to Type. Instead of a separate
+// class FunctionType, we could consider an object of class Type as representing
+// a function type if it has a non-null function (signature) field.
+// In order to save space, we could reuse the error_ field? A malformed or
+// malbounded function type would lose its function reference, but the error
+// string would contain relevant info.
+
+// A FunctionType describes the signature of a function, i.e. the result type
+// and formal parameter types of the function, as well as the names of optional
+// named formal parameters.
+// If these types refer to type parameters of a class in scope, the function
+// type is generic. A generic function type may be instantiated by a type
+// argument vector.
+// Therefore, a FunctionType consists of a scope class, a type argument vector,
+// and a signature.
+// The scope class is either a generic class (or generic typedef) declaring the
+// type parameters referred to by the signature, or class _Closure in the
+// non-generic case (including the non-generic typedef case).
+// The type arguments specify an instantiation of the generic signature (null in
+// the non-generic case).
+// The signature is a reference to an actual closure function (kClosureFunction)
+// or to a signature function (kSignatureFunction).
+// Since typedefs cannot refer to themselves, directly or indirectly, a
+// FunctionType cannot be recursive. Only individual formal parameter types can.
+class FunctionType : public AbstractType {
+ public:
+  virtual bool IsFinalized() const {
+    return
+        (raw_ptr()->type_state_ == RawFunctionType::kFinalizedInstantiated) ||
+        (raw_ptr()->type_state_ == RawFunctionType::kFinalizedUninstantiated);
+  }
+  virtual void SetIsFinalized() const;
+  void ResetIsFinalized() const;  // Ignore current state and set again.
+  virtual bool IsBeingFinalized() const {
+    return raw_ptr()->type_state_ == RawFunctionType::kBeingFinalized;
+  }
+  virtual void SetIsBeingFinalized() const;
+  virtual bool IsMalformed() const;
+  virtual bool IsMalbounded() const;
+  virtual bool IsMalformedOrMalbounded() const;
+  virtual RawLanguageError* error() const { return raw_ptr()->error_; }
+  virtual void set_error(const LanguageError& value) const;
+  virtual bool IsResolved() const {
+    return raw_ptr()->type_state_ >= RawFunctionType::kResolved;
+  }
+  virtual void SetIsResolved() const;
+  // The scope class of a FunctionType is always resolved. It has no actual
+  // type class. Returning false is important for the type testers to work, e.g.
+  // IsDynamicType(), IsBoolType(), etc...
+  virtual bool HasResolvedTypeClass() const { return false; }
+  // Return scope_class from virtual type_class() to factorize finalization
+  // with Type, also a parameterized type.
+  virtual RawClass* type_class() const { return scope_class(); }
+  RawClass* scope_class() const { return raw_ptr()->scope_class_; }
+  void set_scope_class(const Class& value) const;
+  virtual RawTypeArguments* arguments() const { return raw_ptr()->arguments_; }
+  virtual void set_arguments(const TypeArguments& value) const;
+  RawFunction* signature() const { return raw_ptr()->signature_; }
+  virtual TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
+  virtual bool IsInstantiated(TrailPtr trail = NULL) const;
+  virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
+  virtual bool IsRecursive() const;
+  virtual RawAbstractType* InstantiateFrom(
+      const TypeArguments& instantiator_type_arguments,
+      Error* malformed_error,
+      TrailPtr instantiation_trail,
+      TrailPtr bound_trail,
+      Heap::Space space) const;
+  virtual RawAbstractType* CloneUnfinalized() const;
+  virtual RawAbstractType* CloneUninstantiated(
+      const Class& new_owner,
+      TrailPtr trail = NULL) const;
+  virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+  virtual RawString* EnumerateURIs() const;
+
+  virtual intptr_t Hash() const;
+
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(RawFunctionType));
+  }
+
+  static RawFunctionType* New(const Class& scope_class,
+                              const TypeArguments& arguments,
+                              const Function& signature,
+                              TokenPosition token_pos,
+                              Heap::Space space = Heap::kOld);
+
+ private:
+  void set_signature(const Function& value) const;
+  void set_token_pos(TokenPosition token_pos) const;
+  void set_type_state(int8_t state) const;
+
+  static RawFunctionType* New(Heap::Space space = Heap::kOld);
+
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(FunctionType, AbstractType);
+  friend class Class;
+  friend class TypeArguments;
+};
+
+
 // A TypeRef is used to break cycles in the representation of recursive types.
 // Its only field is the recursive AbstractType it refers to.
 // Note that the cycle always involves type arguments.
@@ -5422,7 +5709,10 @@
     return AbstractType::Handle(type()).IsMalformedOrMalbounded();
   }
   virtual bool IsResolved() const { return true; }
-  virtual bool HasResolvedTypeClass() const { return true; }
+  virtual bool HasResolvedTypeClass() const {
+    // Returns false if the ref type is a function type.
+    return AbstractType::Handle(type()).HasResolvedTypeClass();
+  }
   RawAbstractType* type() const { return raw_ptr()->type_; }
   void set_type(const AbstractType& value) const;
   virtual RawClass* type_class() const {
@@ -5431,7 +5721,7 @@
   virtual RawTypeArguments* arguments() const {
     return AbstractType::Handle(type()).arguments();
   }
-  virtual intptr_t token_pos() const {
+  virtual TokenPosition token_pos() const {
     return AbstractType::Handle(type()).token_pos();
   }
   virtual bool IsInstantiated(TrailPtr trail = NULL) const;
@@ -5441,26 +5731,17 @@
   virtual RawTypeRef* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
-      Heap::Space space = Heap::kNew) const;
+      TrailPtr instantiation_trail,
+      TrailPtr bound_trail,
+      Heap::Space space) const;
   virtual RawTypeRef* CloneUninstantiated(
       const Class& new_owner,
       TrailPtr trail = NULL) const;
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
-  // Return true if the receiver is contained in the trail.
-  // Otherwise, if the trail is null, allocate a trail, then add the receiver to
-  // the trail and return false.
-  bool TestAndAddToTrail(TrailPtr* trail) const;
-
-  // Return true if the pair <receiver, buddy> is contained in the trail.
-  // Otherwise, if the trail is null, allocate a trail, add the pair <receiver,
-  // buddy> to the trail and return false.
-  // The receiver may be added several times, each time with a different buddy.
-  bool TestAndAddBuddyToTrail(TrailPtr* trail, const AbstractType& buddy) const;
-
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawTypeRef));
   }
@@ -5491,7 +5772,7 @@
     ASSERT(raw_ptr()->type_state_ != RawTypeParameter::kFinalizedInstantiated);
     return raw_ptr()->type_state_ == RawTypeParameter::kFinalizedUninstantiated;
   }
-  void set_is_finalized() const;
+  virtual void SetIsFinalized() const;
   virtual bool IsBeingFinalized() const { return false; }
   virtual bool IsMalformed() const { return false; }
   virtual bool IsMalbounded() const { return false; }
@@ -5513,8 +5794,9 @@
   bool CheckBound(const AbstractType& bounded_type,
                   const AbstractType& upper_bound,
                   Error* bound_error,
-                  Heap::Space space = Heap::kNew) const;
-  virtual intptr_t token_pos() const { return raw_ptr()->token_pos_; }
+                  TrailPtr bound_trail,
+                  Heap::Space space) const;
+  virtual TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
   virtual bool IsInstantiated(TrailPtr trail = NULL) const {
     return false;
   }
@@ -5523,14 +5805,16 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
-      Heap::Space space = Heap::kNew) const;
+      TrailPtr instantiation_trail,
+      TrailPtr bound_trail,
+      Heap::Space space) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
       const Class& new_owner, TrailPtr trail = NULL) const;
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const {
     return raw();
   }
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
@@ -5542,12 +5826,12 @@
                                intptr_t index,
                                const String& name,
                                const AbstractType& bound,
-                               intptr_t token_pos);
+                               TokenPosition token_pos);
 
  private:
   void set_parameterized_class(const Class& value) const;
   void set_name(const String& value) const;
-  void set_token_pos(intptr_t token_pos) const;
+  void set_token_pos(TokenPosition token_pos) const;
   void set_type_state(int8_t state) const;
 
   static RawTypeParameter* New();
@@ -5593,7 +5877,7 @@
   RawTypeParameter* type_parameter() const {
     return raw_ptr()->type_parameter_;
   }
-  virtual intptr_t token_pos() const {
+  virtual TokenPosition token_pos() const {
     return AbstractType::Handle(type()).token_pos();
   }
   virtual bool IsInstantiated(TrailPtr trail = NULL) const {
@@ -5608,14 +5892,16 @@
   virtual RawAbstractType* InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       Error* bound_error,
-      TrailPtr trail = NULL,
-      Heap::Space space = Heap::kNew) const;
+      TrailPtr instantiation_trail,
+      TrailPtr bound_trail,
+      Heap::Space space) const;
   virtual RawAbstractType* CloneUnfinalized() const;
   virtual RawAbstractType* CloneUninstantiated(
       const Class& new_owner, TrailPtr trail = NULL) const;
   virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const {
     return raw();
   }
+  virtual RawString* EnumerateURIs() const;
 
   virtual intptr_t Hash() const;
 
@@ -5657,7 +5943,7 @@
   virtual bool IsResolved() const { return false; }
   virtual bool HasResolvedTypeClass() const { return false; }
   virtual RawString* Name() const;
-  virtual intptr_t token_pos() const;
+  virtual TokenPosition token_pos() const;
 
   // Returns the mixin composition depth of this mixin application type.
   intptr_t Depth() const;
@@ -5698,6 +5984,7 @@
 
  private:
   OBJECT_IMPLEMENTATION(Number, Instance);
+
   friend class Class;
 };
 
@@ -5711,10 +5998,7 @@
   // Returns a canonical Integer object allocated in the old gen space.
   static RawInteger* NewCanonical(const String& str);
 
-  // Do not throw JavascriptIntegerOverflow if 'silent' is true.
-  static RawInteger* New(int64_t value,
-                         Heap::Space space = Heap::kNew,
-                         const bool silent = false);
+  static RawInteger* New(int64_t value, Heap::Space space = Heap::kNew);
 
   virtual bool OperatorEquals(const Instance& other) const {
     return Equals(other);
@@ -5752,9 +6036,6 @@
                     const Integer& other,
                     Heap::Space space = Heap::kNew) const;
 
-  // Returns true if the Integer does not fit in a Javascript integer.
-  bool CheckJavascriptIntegerOverflow() const;
-
  private:
   OBJECT_IMPLEMENTATION(Integer, Number);
   friend class Class;
@@ -5811,8 +6092,7 @@
 
   RawInteger* ShiftOp(Token::Kind kind,
                       const Smi& other,
-                      Heap::Space space = Heap::kNew,
-                      const bool silent = false) const;
+                      Heap::Space space = Heap::kNew) const;
 
   void operator=(RawSmi* value) {
     raw_ = value;
@@ -5839,7 +6119,7 @@
 
   Smi() : Integer() {}
   BASE_OBJECT_IMPLEMENTATION(Smi, Integer);
-
+  OBJECT_SERVICE_SUPPORT(Smi);
   friend class Api;  // For ValueFromRaw
   friend class Class;
   friend class Object;
@@ -6091,6 +6371,7 @@
     this->SetHash(result);
     return result;
   }
+
   bool HasHash() const {
     ASSERT(Smi::New(0) == NULL);
     return (raw_ptr()->hash_ != NULL);
@@ -6120,9 +6401,10 @@
   intptr_t CharSize() const;
 
   inline bool Equals(const String& str) const;
-  inline bool Equals(const String& str,
-                     intptr_t begin_index,  // begin index on 'str'.
-                     intptr_t len) const;  // len on 'str'.
+
+  bool Equals(const String& str,
+              intptr_t begin_index,  // begin index on 'str'.
+              intptr_t len) const;  // len on 'str'.
 
   // Compares to a '\0' terminated array of UTF-8 encoded characters.
   bool Equals(const char* cstr) const;
@@ -6283,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);
@@ -6341,6 +6623,7 @@
   friend class ExternalTwoByteString;
   // So that SkippedCodeFunctions can print a debug string from a NoHandleScope.
   friend class SkippedCodeFunctions;
+  friend class RawOneByteString;
 };
 
 
@@ -7667,86 +7950,45 @@
 };
 
 
-class Closure : public AllStatic {
+class Closure : public Instance {
  public:
-  static RawFunction* function(const Instance& closure) {
-    return *FunctionAddr(closure);
+  RawFunction* function() const { return raw_ptr()->function_; }
+  void set_function(const Function& function) const {
+    // TODO(regis): Only used from deferred_objects.cc. Remove once fixed.
+    StorePointer(&raw_ptr()->function_, function.raw());
   }
-  static intptr_t function_offset() {
-    return static_cast<intptr_t>(kFunctionOffset * kWordSize);
-  }
+  static intptr_t function_offset() { return OFFSET_OF(RawClosure, function_); }
 
-  static RawContext* context(const Instance& closure) {
-    return *ContextAddr(closure);
+  RawContext* context() const { return raw_ptr()->context_; }
+  void set_context(const Context& context) const {
+    // TODO(regis): Only used from deferred_objects.cc. Remove once fixed.
+    StorePointer(&raw_ptr()->context_, context.raw());
   }
-  static intptr_t context_offset() {
-    return static_cast<intptr_t>(kContextOffset * kWordSize);
-  }
+  static intptr_t context_offset() { return OFFSET_OF(RawClosure, context_); }
 
-  static RawTypeArguments* GetTypeArguments(const Instance& closure) {
-    return *TypeArgumentsAddr(closure);
-  }
-  static void SetTypeArguments(const Instance& closure,
-                               const TypeArguments& value) {
-    ASSERT(value.IsNull() || value.IsCanonical());
-    closure.StorePointer(TypeArgumentsAddr(closure), value.raw());
-  }
   static intptr_t type_arguments_offset() {
-    return static_cast<intptr_t>(kTypeArgumentsOffset * kWordSize);
+    return OFFSET_OF(RawClosure, type_arguments_);
   }
 
-  static const char* ToCString(const Instance& closure);
-
   static intptr_t InstanceSize() {
-    intptr_t size = sizeof(RawInstance) + (kNumFields * kWordSize);
-    ASSERT(size == Object::RoundedAllocationSize(size));
-    return size;
+    return RoundedAllocationSize(sizeof(RawClosure));
   }
 
-  static RawInstance* New(const Function& function,
-                          const Context& context,
-                          Heap::Space space = Heap::kNew);
+  // Returns true if all elements are OK for canonicalization.
+  virtual bool CheckAndCanonicalizeFields(const char** error_str) const {
+    // None of the fields of a closure are instances.
+    return true;
+  }
+
+  static RawClosure* New(const Function& function,
+                         const Context& context,
+                         Heap::Space space = Heap::kNew);
 
  private:
-  static const int kTypeArgumentsOffset = 1;
-  static const int kFunctionOffset = 2;
-  static const int kContextOffset = 3;
-  static const int kNumFields = 3;
+  static RawClosure* New();
 
-  static RawTypeArguments** TypeArgumentsAddr(const Instance& obj) {
-    ASSERT(obj.IsClosure());
-    return reinterpret_cast<RawTypeArguments**>(
-        reinterpret_cast<intptr_t>(obj.raw_ptr()) + type_arguments_offset());
-  }
-  static RawFunction** FunctionAddr(const Instance& obj) {
-    ASSERT(obj.IsClosure());
-    return reinterpret_cast<RawFunction**>(
-        reinterpret_cast<intptr_t>(obj.raw_ptr()) + function_offset());
-  }
-  static RawContext** ContextAddr(const Instance& obj) {
-    ASSERT(obj.IsClosure());
-    return reinterpret_cast<RawContext**>(
-        reinterpret_cast<intptr_t>(obj.raw_ptr()) + context_offset());
-  }
-  static void set_function(const Instance& closure,
-                           const Function& value) {
-    closure.StorePointer(FunctionAddr(closure), value.raw());
-  }
-  static void set_context(const Instance& closure,
-                          const Context& value) {
-    closure.StorePointer(ContextAddr(closure), value.raw());
-  }
-  static intptr_t NextFieldOffset() {
-    // Indicates this class cannot be extended by dart code.
-    return -kWordSize;
-  }
-  static RawFunction* GetFunction(RawObject* obj) {
-    return *(reinterpret_cast<RawFunction**>(
-        reinterpret_cast<intptr_t>(obj->ptr()) + function_offset()));
-  }
-
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(Closure, Instance);
   friend class Class;
-  friend class SnapshotWriter;
 };
 
 
@@ -7878,8 +8120,8 @@
     kFlagsSize = 4,
   };
 
-  class TypeBits : public BitField<RegExType, kTypePos, kTypeSize> {};
-  class FlagsBits : public BitField<intptr_t, kFlagsPos, kFlagsSize> {};
+  class TypeBits : public BitField<int8_t, RegExType, kTypePos, kTypeSize> {};
+  class FlagsBits : public BitField<int8_t, intptr_t, kFlagsPos, kFlagsSize> {};
 
   bool is_initialized() const { return (type() != kUnitialized); }
   bool is_simple() const { return (type() == kSimple); }
@@ -8198,29 +8440,16 @@
   if (str.IsNull()) {
     return false;
   }
+  if (IsCanonical() && str.IsCanonical()) {
+    return false;  // Two symbols that aren't identical aren't equal.
+  }
+  if (HasHash() && str.HasHash() && (Hash() != str.Hash())) {
+    return false;  // Both sides have hash codes and they do not match.
+  }
   return Equals(str, 0, str.Length());
 }
 
 
-bool String::Equals(const String& str,
-                    intptr_t begin_index,
-                    intptr_t len) const {
-  ASSERT(begin_index >= 0);
-  ASSERT((begin_index == 0) || (begin_index < str.Length()));
-  ASSERT(len >= 0);
-  ASSERT(len <= str.Length());
-  if (len != this->Length()) {
-    return false;  // Lengths don't match.
-  }
-  for (intptr_t i = 0; i < len; i++) {
-    if (this->CharAt(i) != str.CharAt(begin_index + i)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-
 intptr_t Library::UrlHash() const {
   intptr_t result = Smi::Value(url()->ptr()->hash_);
   ASSERT(result != 0);
diff --git a/runtime/vm/object_graph_test.cc b/runtime/vm/object_graph_test.cc
index 1afcc44..801d01c 100644
--- a/runtime/vm/object_graph_test.cc
+++ b/runtime/vm/object_graph_test.cc
@@ -38,7 +38,7 @@
 };
 
 
-TEST_CASE(ObjectGraph) {
+VM_TEST_CASE(ObjectGraph) {
   Isolate* isolate = thread->isolate();
   // Create a simple object graph with objects a, b, c, d:
   //  a+->b+->c
diff --git a/runtime/vm/object_id_ring.cc b/runtime/vm/object_id_ring.cc
index 9ae8b92..d01d8bd 100644
--- a/runtime/vm/object_id_ring.cc
+++ b/runtime/vm/object_id_ring.cc
@@ -9,6 +9,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 void ObjectIdRing::Init(Isolate* isolate, int32_t capacity) {
   ObjectIdRing* ring = new ObjectIdRing(isolate, capacity);
   isolate->set_object_id_ring(ring);
@@ -253,4 +255,6 @@
   return IsValidContiguous(id);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/object_id_ring_test.cc b/runtime/vm/object_id_ring_test.cc
index 27347ea..c85d44c 100644
--- a/runtime/vm/object_id_ring_test.cc
+++ b/runtime/vm/object_id_ring_test.cc
@@ -11,6 +11,7 @@
 
 namespace dart {
 
+#ifndef PRODUCT
 
 class ObjectIdRingTestHelper {
  public:
@@ -48,7 +49,7 @@
 
 
 // Test that serial number wrapping works.
-TEST_CASE(ObjectIdRingSerialWrapTest) {
+VM_TEST_CASE(ObjectIdRingSerialWrapTest) {
   Isolate* isolate = Isolate::Current();
   ObjectIdRing* ring = isolate->object_id_ring();
   ObjectIdRingTestHelper::SetCapacityAndMaxSerial(ring, 2, 4);
@@ -160,8 +161,11 @@
   EXPECT_NE(Object::null(), raw_obj2);
   EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj1));
   EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj2));
-  // Force a scavenge.
-  heap->CollectGarbage(Heap::kNew);
+  {
+    TransitionNativeToVM transition(thread);
+    // Force a scavenge.
+    heap->CollectGarbage(Heap::kNew);
+  }
   RawObject* raw_object_moved1 = ring->GetObjectForId(raw_obj_id1, &kind);
   EXPECT_EQ(ObjectIdRing::kValid, kind);
   RawObject* raw_object_moved2 = ring->GetObjectForId(raw_obj_id2, &kind);
@@ -187,7 +191,7 @@
 
 
 // Test that the ring table is updated with nulls when the old GC collects.
-TEST_CASE(ObjectIdRingOldGCTest) {
+VM_TEST_CASE(ObjectIdRingOldGCTest) {
   Isolate* isolate = thread->isolate();
   Heap* heap = isolate->heap();
   ObjectIdRing* ring = isolate->object_id_ring();
@@ -241,7 +245,7 @@
 
 // Test that the ring table correctly reports an entry as expired when it is
 // overridden by new entries.
-TEST_CASE(ObjectIdRingExpiredEntryTest) {
+VM_TEST_CASE(ObjectIdRingExpiredEntryTest) {
   Isolate* isolate = Isolate::Current();
   ObjectIdRing* ring = isolate->object_id_ring();
 
@@ -271,4 +275,6 @@
   EXPECT_EQ(Object::null(), obj_lookup);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
new file mode 100644
index 0000000..ba63134
--- /dev/null
+++ b/runtime/vm/object_service.cc
@@ -0,0 +1,1602 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/debugger.h"
+#include "vm/disassembler.h"
+#include "vm/object.h"
+#include "vm/object_store.h"
+#include "vm/stub_code.h"
+#include "vm/symbols.h"
+
+namespace dart {
+
+#ifndef PRODUCT
+
+static void AddNameProperties(JSONObject* jsobj,
+                              const String& name,
+                              const String& vm_name) {
+  jsobj->AddProperty("name", name.ToCString());
+  if (!name.Equals(vm_name)) {
+    jsobj->AddProperty("_vmName", vm_name.ToCString());
+  }
+}
+
+
+void Object::AddCommonObjectProperties(JSONObject* jsobj,
+                                       const char* protocol_type,
+                                       bool ref) const {
+  const char* vm_type = JSONType();
+  bool same_type = (strcmp(protocol_type, vm_type) == 0);
+  if (ref) {
+    jsobj->AddPropertyF("type", "@%s", protocol_type);
+  } else {
+    jsobj->AddProperty("type", protocol_type);
+  }
+  if (!same_type) {
+    jsobj->AddProperty("_vmType", vm_type);
+  }
+  if (!ref || IsInstance() || IsNull()) {
+    // TODO(turnidge): Provide the type arguments here too?
+    const Class& cls = Class::Handle(this->clazz());
+    jsobj->AddProperty("class", cls);
+  }
+  if (!ref) {
+    if (raw()->IsHeapObject()) {
+      jsobj->AddProperty("size", raw()->Size());
+    } else {
+      jsobj->AddProperty("size", (intptr_t)0);
+    }
+  }
+}
+
+
+void Object::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Object", ref);
+  jsobj.AddServiceId(*this);
+  if (ref) {
+    return;
+  }
+}
+
+
+void Object::PrintJSON(JSONStream* stream, bool ref) const {
+  if (IsNull()) {
+    JSONObject jsobj(stream);
+    AddCommonObjectProperties(&jsobj, "Instance", ref);
+    jsobj.AddProperty("kind", "Null");
+    jsobj.AddFixedServiceId("objects/null");
+    jsobj.AddProperty("valueAsString", "null");
+  } else {
+    PrintJSONImpl(stream, ref);
+  }
+}
+
+
+void Class::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Isolate* isolate = Isolate::Current();
+  JSONObject jsobj(stream);
+  if ((raw() == Class::null()) || (id() == kFreeListElement)) {
+    // TODO(turnidge): This is weird and needs to be changed.
+    jsobj.AddProperty("type", "null");
+    return;
+  }
+  AddCommonObjectProperties(&jsobj, "Class", ref);
+  jsobj.AddFixedServiceId("classes/%" Pd "", id());
+  const String& scrubbed_name = String::Handle(ScrubbedName());
+  const String& vm_name = String::Handle(Name());
+  AddNameProperties(&jsobj, scrubbed_name, vm_name);
+  if (ref) {
+    return;
+  }
+
+  const Error& err = Error::Handle(EnsureIsFinalized(Thread::Current()));
+  if (!err.IsNull()) {
+    jsobj.AddProperty("error", err);
+  }
+  jsobj.AddProperty("abstract", is_abstract());
+  jsobj.AddProperty("const", is_const());
+  jsobj.AddProperty("_finalized", is_finalized());
+  jsobj.AddProperty("_implemented", is_implemented());
+  jsobj.AddProperty("_patch", is_patch());
+  jsobj.AddProperty("_traceAllocations", TraceAllocation(isolate));
+  const Class& superClass = Class::Handle(SuperClass());
+  if (!superClass.IsNull()) {
+    jsobj.AddProperty("super", superClass);
+  }
+  jsobj.AddProperty("library", Object::Handle(library()));
+  const Script& script = Script::Handle(this->script());
+  if (!script.IsNull()) {
+    jsobj.AddLocation(script, token_pos(), ComputeEndTokenPos());
+  }
+  {
+    JSONArray interfaces_array(&jsobj, "interfaces");
+    const Array& interface_array = Array::Handle(interfaces());
+    Type& interface_type = Type::Handle();
+    if (!interface_array.IsNull()) {
+      for (intptr_t i = 0; i < interface_array.Length(); ++i) {
+        interface_type ^= interface_array.At(i);
+        interfaces_array.AddValue(interface_type);
+      }
+    }
+  }
+  {
+    JSONArray fields_array(&jsobj, "fields");
+    const Array& field_array = Array::Handle(fields());
+    Field& field = Field::Handle();
+    if (!field_array.IsNull()) {
+      for (intptr_t i = 0; i < field_array.Length(); ++i) {
+        field ^= field_array.At(i);
+        fields_array.AddValue(field);
+      }
+    }
+  }
+  {
+    JSONArray functions_array(&jsobj, "functions");
+    const Array& function_array = Array::Handle(functions());
+    Function& function = Function::Handle();
+    if (!function_array.IsNull()) {
+      for (intptr_t i = 0; i < function_array.Length(); i++) {
+        function ^= function_array.At(i);
+        functions_array.AddValue(function);
+      }
+    }
+  }
+  {
+    JSONArray subclasses_array(&jsobj, "subclasses");
+    const GrowableObjectArray& subclasses =
+        GrowableObjectArray::Handle(direct_subclasses());
+    if (!subclasses.IsNull()) {
+      Class& subclass = Class::Handle();
+      for (intptr_t i = 0; i < subclasses.Length(); ++i) {
+        // TODO(turnidge): Use the Type directly once regis has added
+        // types to the vmservice.
+        subclass ^= subclasses.At(i);
+        subclasses_array.AddValue(subclass);
+      }
+    }
+  }
+  {
+    ClassTable* class_table = Isolate::Current()->class_table();
+    const ClassHeapStats* stats = class_table->StatsWithUpdatedSize(id());
+    if (stats != NULL) {
+      JSONObject allocation_stats(&jsobj, "_allocationStats");
+      stats->PrintToJSONObject(*this, &allocation_stats);
+    }
+  }
+}
+
+
+void UnresolvedClass::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void TypeArguments::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  // The index in the canonical_type_arguments table cannot be used as part of
+  // the object id (as in typearguments/id), because the indices are not
+  // preserved when the table grows and the entries get rehashed. Use the ring.
+  Isolate* isolate = Isolate::Current();
+  ObjectStore* object_store = isolate->object_store();
+  const Array& table = Array::Handle(object_store->canonical_type_arguments());
+  ASSERT(table.Length() > 0);
+  AddCommonObjectProperties(&jsobj, "TypeArguments", ref);
+  jsobj.AddServiceId(*this);
+  const String& user_name = String::Handle(UserVisibleName());
+  const String& vm_name = String::Handle(Name());
+  AddNameProperties(&jsobj, user_name, vm_name);
+  if (ref) {
+    return;
+  }
+  {
+    JSONArray jsarr(&jsobj, "types");
+    AbstractType& type_arg = AbstractType::Handle();
+    for (intptr_t i = 0; i < Length(); i++) {
+      type_arg = TypeAt(i);
+      jsarr.AddValue(type_arg);
+    }
+  }
+  if (!IsInstantiated()) {
+    JSONArray jsarr(&jsobj, "_instantiations");
+    Array& prior_instantiations = Array::Handle(instantiations());
+    ASSERT(prior_instantiations.Length() > 0);  // Always at least a sentinel.
+    TypeArguments& type_args = TypeArguments::Handle();
+    intptr_t i = 0;
+    while (true) {
+      if (prior_instantiations.At(i) == Smi::New(StubCode::kNoInstantiator)) {
+        break;
+      }
+      JSONObject instantiation(&jsarr);
+      type_args ^= prior_instantiations.At(i);
+      instantiation.AddProperty("instantiator", type_args, true);
+      type_args ^= prior_instantiations.At(i + 1);
+      instantiation.AddProperty("instantiated", type_args, true);
+      i += 2;
+    }
+  }
+}
+
+
+void PatchClass::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+static void AddFunctionServiceId(const JSONObject& jsobj,
+                                 const Function& f,
+                                 const Class& cls) {
+  // Special kinds of functions use indices in their respective lists.
+  intptr_t id = -1;
+  const char* selector = NULL;
+  if (f.IsNonImplicitClosureFunction()) {
+    id = Isolate::Current()->FindClosureIndex(f);
+    selector = "closures";
+  } else if (f.IsImplicitClosureFunction()) {
+    id = cls.FindImplicitClosureFunctionIndex(f);
+    selector = "implicit_closures";
+  } else if (f.IsNoSuchMethodDispatcher() || f.IsInvokeFieldDispatcher()) {
+    id = cls.FindInvocationDispatcherFunctionIndex(f);
+    selector = "dispatchers";
+  }
+  if (id != -1) {
+    ASSERT(selector != NULL);
+    jsobj.AddFixedServiceId("classes/%" Pd "/%s/%" Pd "",
+                            cls.id(), selector, id);
+    return;
+  }
+  // Regular functions known to their owner use their name (percent-encoded).
+  String& name = String::Handle(f.name());
+  if (cls.LookupFunction(name) == f.raw()) {
+    name = String::EncodeIRI(name);
+    jsobj.AddFixedServiceId("classes/%" Pd "/functions/%s",
+                            cls.id(), name.ToCString());
+    return;
+  }
+  // Oddball functions (not known to their owner) fall back to use the object
+  // id ring. Current known examples are signature functions of closures
+  // and stubs like 'megamorphic_miss'.
+  jsobj.AddServiceId(f);
+}
+
+
+void Function::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Class& cls = Class::Handle(Owner());
+  ASSERT(!cls.IsNull());
+  Error& err = Error::Handle();
+  err ^= cls.EnsureIsFinalized(Thread::Current());
+  ASSERT(err.IsNull());
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Function", ref);
+  AddFunctionServiceId(jsobj, *this, cls);
+  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());
+  if (!parent.IsNull()) {
+    jsobj.AddProperty("owner", parent);
+  } else if (cls.IsTopLevel()) {
+    const Library& library = Library::Handle(cls.library());
+    jsobj.AddProperty("owner", library);
+  } else {
+    jsobj.AddProperty("owner", cls);
+  }
+
+  const char* kind_string = Function::KindToCString(kind());
+  jsobj.AddProperty("_kind", kind_string);
+  jsobj.AddProperty("static", is_static());
+  jsobj.AddProperty("const", is_const());
+  jsobj.AddProperty("_intrinsic", is_intrinsic());
+  jsobj.AddProperty("_native", is_native());
+  if (ref) {
+    return;
+  }
+  Code& code = Code::Handle(CurrentCode());
+  if (!code.IsNull()) {
+    jsobj.AddProperty("code", code);
+  }
+  Array& ics = Array::Handle(ic_data_array());
+  if (!ics.IsNull()) {
+    jsobj.AddProperty("_icDataArray", ics);
+  }
+  jsobj.AddProperty("_optimizable", is_optimizable());
+  jsobj.AddProperty("_inlinable", is_inlinable());
+  jsobj.AddProperty("_recognized", IsRecognized());
+  code = unoptimized_code();
+  if (!code.IsNull()) {
+    jsobj.AddProperty("_unoptimizedCode", code);
+  }
+  jsobj.AddProperty("_usageCounter", usage_counter());
+  jsobj.AddProperty("_optimizedCallSiteCount", optimized_call_site_count());
+  jsobj.AddProperty("_deoptimizations",
+                    static_cast<intptr_t>(deoptimization_counter()));
+  if ((kind() == RawFunction::kImplicitGetter) ||
+      (kind() == RawFunction::kImplicitSetter) ||
+      (kind() == RawFunction::kImplicitStaticFinalGetter)) {
+    const Field& field = Field::Handle(LookupImplicitGetterSetterField());
+    if (!field.IsNull()) {
+      jsobj.AddProperty("_field", field);
+    }
+  }
+
+  const Script& script = Script::Handle(this->script());
+  if (!script.IsNull()) {
+    jsobj.AddLocation(script, token_pos(), end_token_pos());
+  }
+}
+
+
+void RedirectionData::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void Field::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  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(UserVisibleName());
+  const String& vm_name = String::Handle(name());
+  AddNameProperties(&jsobj, user_name, vm_name);
+  if (cls.IsTopLevel()) {
+    const Library& library = Library::Handle(cls.library());
+    jsobj.AddProperty("owner", library);
+  } else {
+    jsobj.AddProperty("owner", cls);
+  }
+
+  AbstractType& declared_type = AbstractType::Handle(type());
+  jsobj.AddProperty("declaredType", declared_type);
+  jsobj.AddProperty("static", is_static());
+  jsobj.AddProperty("final", is_final());
+  jsobj.AddProperty("const", is_const());
+  if (ref) {
+    return;
+  }
+  if (is_static()) {
+    const Instance& valueObj = Instance::Handle(StaticValue());
+    jsobj.AddProperty("staticValue", valueObj);
+  }
+
+  jsobj.AddProperty("_guardNullable", is_nullable());
+  if (guarded_cid() == kIllegalCid) {
+    jsobj.AddProperty("_guardClass", "unknown");
+  } else if (guarded_cid() == kDynamicCid) {
+    jsobj.AddProperty("_guardClass", "dynamic");
+  } else {
+    ClassTable* table = Isolate::Current()->class_table();
+    ASSERT(table->IsValidIndex(guarded_cid()));
+    cls ^= table->At(guarded_cid());
+    jsobj.AddProperty("_guardClass", cls);
+  }
+  if (guarded_list_length() == kUnknownFixedLength) {
+    jsobj.AddProperty("_guardLength", "unknown");
+  } else if (guarded_list_length() == kNoFixedLength) {
+    jsobj.AddProperty("_guardLength", "variable");
+  } else {
+    jsobj.AddProperty("_guardLength", guarded_list_length());
+  }
+  const Class& origin_cls = Class::Handle(Origin());
+  const class Script& script = Script::Handle(origin_cls.script());
+  if (!script.IsNull()) {
+    jsobj.AddLocation(script, token_pos());
+  }
+}
+
+
+void LiteralToken::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void TokenStream::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Object", ref);
+  // TODO(johnmccutchan): Generate a stable id. TokenStreams hang off
+  // a Script object but do not have a back reference to generate a stable id.
+  jsobj.AddServiceId(*this);
+  if (ref) {
+    return;
+  }
+  const String& private_key = String::Handle(PrivateKey());
+  jsobj.AddProperty("privateKey", private_key);
+  // TODO(johnmccutchan): Add support for printing LiteralTokens and add
+  // them to members array.
+  JSONArray members(&jsobj, "members");
+}
+
+
+// See also Dart_ScriptGetTokenInfo.
+void Script::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Script", ref);
+  const String& uri = String::Handle(url());
+  ASSERT(!uri.IsNull());
+  const String& encoded_uri = String::Handle(String::EncodeIRI(uri));
+  ASSERT(!encoded_uri.IsNull());
+  const Library& lib = Library::Handle(FindLibrary());
+  if (kind() == RawScript::kEvaluateTag) {
+    jsobj.AddServiceId(*this);
+  } else {
+    ASSERT(!lib.IsNull());
+    jsobj.AddFixedServiceId("libraries/%" Pd "/scripts/%s",
+        lib.index(), encoded_uri.ToCString());
+  }
+  jsobj.AddPropertyStr("uri", uri);
+  jsobj.AddProperty("_kind", GetKindAsCString());
+  if (ref) {
+    return;
+  }
+  if (!lib.IsNull()) {
+    jsobj.AddProperty("library", lib);
+  }
+  const String& source = String::Handle(Source());
+  jsobj.AddProperty("lineOffset", line_offset());
+  jsobj.AddProperty("columnOffset", col_offset());
+  if (!source.IsNull()) {
+    jsobj.AddPropertyStr("source", source);
+  }
+
+  // Print the line number table
+  if (!source.IsNull()) {
+    JSONArray tokenPosTable(&jsobj, "tokenPosTable");
+
+    const GrowableObjectArray& lineNumberArray =
+        GrowableObjectArray::Handle(GenerateLineNumberArray());
+    Object& value = Object::Handle();
+    intptr_t pos = 0;
+
+    // Skip leading null.
+    ASSERT(lineNumberArray.Length() > 0);
+    value = lineNumberArray.At(pos);
+    ASSERT(value.IsNull());
+    pos++;
+
+    while (pos < lineNumberArray.Length()) {
+      JSONArray lineInfo(&tokenPosTable);
+      while (pos < lineNumberArray.Length()) {
+        value = lineNumberArray.At(pos);
+        pos++;
+        if (value.IsNull()) {
+          break;
+        }
+        const Smi& smi = Smi::Cast(value);
+        lineInfo.AddValue(smi.Value());
+      }
+    }
+  }
+}
+
+
+void Library::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  intptr_t id = index();
+  ASSERT(id >= 0);
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Library", ref);
+  jsobj.AddFixedServiceId("libraries/%" Pd "", id);
+  const String& vm_name = String::Handle(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) {
+    return;
+  }
+  jsobj.AddProperty("debuggable", IsDebuggable());
+  {
+    JSONArray jsarr(&jsobj, "classes");
+    ClassDictionaryIterator class_iter(*this);
+    Class& klass = Class::Handle();
+    while (class_iter.HasNext()) {
+      klass = class_iter.GetNextClass();
+      if (!klass.IsMixinApplication()) {
+        jsarr.AddValue(klass);
+      }
+    }
+  }
+  {
+    JSONArray jsarr(&jsobj, "dependencies");
+
+    Array& ports = Array::Handle();
+    Namespace& ns = Namespace::Handle();
+    Library& target = Library::Handle();
+
+    // Unprefixed imports.
+    ports = imports();
+    for (intptr_t i = 0; i < ports.Length(); i++) {
+      ns ^= ports.At(i);
+      if (ns.IsNull()) continue;
+
+      JSONObject jsdep(&jsarr);
+      jsdep.AddProperty("isDeferred", false);
+      jsdep.AddProperty("isExport", false);
+      jsdep.AddProperty("isImport", true);
+      target = ns.library();
+      jsdep.AddProperty("target", target);
+    }
+
+    // Exports.
+    ports = exports();
+    for (intptr_t i = 0; i < ports.Length(); i++) {
+      ns ^= ports.At(i);
+      if (ns.IsNull()) continue;
+
+      JSONObject jsdep(&jsarr);
+      jsdep.AddProperty("isDeferred", false);
+      jsdep.AddProperty("isExport", true);
+      jsdep.AddProperty("isImport", false);
+      target = ns.library();
+      jsdep.AddProperty("target", target);
+    }
+
+    // Prefixed imports.
+    DictionaryIterator entries(*this);
+    Object& entry = Object::Handle();
+    LibraryPrefix& prefix = LibraryPrefix::Handle();
+    String& prefixName = String::Handle();
+    while (entries.HasNext()) {
+      entry = entries.GetNext();
+      if (entry.IsLibraryPrefix()) {
+        prefix ^= entry.raw();
+        ports = prefix.imports();
+        for (intptr_t i = 0; i < ports.Length(); i++) {
+          ns ^= ports.At(i);
+          if (ns.IsNull()) continue;
+
+          JSONObject jsdep(&jsarr);
+          jsdep.AddProperty("isDeferred", prefix.is_deferred_load());
+          jsdep.AddProperty("isExport", false);
+          jsdep.AddProperty("isImport", true);
+          prefixName = prefix.name();
+          ASSERT(!prefixName.IsNull());
+          jsdep.AddProperty("prefix", prefixName.ToCString());
+          target = ns.library();
+          jsdep.AddProperty("target", target);
+        }
+      }
+    }
+  }
+  {
+    JSONArray jsarr(&jsobj, "variables");
+    DictionaryIterator entries(*this);
+    Object& entry = Object::Handle();
+    while (entries.HasNext()) {
+      entry = entries.GetNext();
+      if (entry.IsField()) {
+        jsarr.AddValue(entry);
+      }
+    }
+  }
+  {
+    JSONArray jsarr(&jsobj, "functions");
+    DictionaryIterator entries(*this);
+    Object& entry = Object::Handle();
+    while (entries.HasNext()) {
+      entry = entries.GetNext();
+      if (entry.IsFunction()) {
+        const Function& func = Function::Cast(entry);
+        if (func.kind() == RawFunction::kRegularFunction ||
+            func.kind() == RawFunction::kGetterFunction ||
+            func.kind() == RawFunction::kSetterFunction) {
+          jsarr.AddValue(func);
+        }
+      }
+    }
+  }
+  {
+    JSONArray jsarr(&jsobj, "scripts");
+    Array& scripts = Array::Handle(LoadedScripts());
+    Script& script = Script::Handle();
+    for (intptr_t i = 0; i < scripts.Length(); i++) {
+      script ^= scripts.At(i);
+      jsarr.AddValue(script);
+    }
+  }
+}
+
+
+void LibraryPrefix::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void Namespace::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void Instructions::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Object", ref);
+  jsobj.AddServiceId(*this);
+  if (ref) {
+    return;
+  }
+}
+
+
+void ObjectPool::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Object", ref);
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("length", Length());
+  if (ref) {
+    return;
+  }
+
+  {
+    JSONArray jsarr(&jsobj, "_entries");
+    uword imm;
+    Object& obj = Object::Handle();
+    for (intptr_t i = 0; i < Length(); i++) {
+      JSONObject jsentry(stream);
+      jsentry.AddProperty("offset", OffsetFromIndex(i));
+      switch (InfoAt(i)) {
+      case ObjectPool::kTaggedObject:
+        obj = ObjectAt(i);
+        jsentry.AddProperty("kind", "Object");
+        jsentry.AddProperty("value", obj);
+        break;
+      case ObjectPool::kImmediate:
+        imm = RawValueAt(i);
+        jsentry.AddProperty("kind", "Immediate");
+        jsentry.AddProperty64("value", imm);
+        break;
+      case ObjectPool::kNativeEntry:
+        imm = RawValueAt(i);
+        jsentry.AddProperty("kind", "NativeEntry");
+        jsentry.AddProperty64("value", imm);
+        break;
+      default:
+        UNREACHABLE();
+      }
+    }
+  }
+}
+
+
+void PcDescriptors::PrintToJSONObject(JSONObject* jsobj, bool ref) const {
+  AddCommonObjectProperties(jsobj, "Object", ref);
+  // TODO(johnmccutchan): Generate a stable id. PcDescriptors hang off a Code
+  // object but do not have a back reference to generate an ID.
+  jsobj->AddServiceId(*this);
+  if (ref) {
+    return;
+  }
+  JSONArray members(jsobj, "members");
+  Iterator iter(*this, RawPcDescriptors::kAnyKind);
+  while (iter.MoveNext()) {
+    JSONObject descriptor(&members);
+    descriptor.AddPropertyF("pcOffset", "%" Px "", iter.PcOffset());
+    descriptor.AddProperty("kind", KindAsStr(iter.Kind()));
+    descriptor.AddProperty("deoptId", iter.DeoptId());
+    // TODO(turnidge): Use AddLocation instead.
+    descriptor.AddProperty("tokenPos", iter.TokenPos());
+    descriptor.AddProperty("tryIndex", iter.TryIndex());
+  }
+}
+
+
+void PcDescriptors::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintToJSONObject(&jsobj, ref);
+}
+
+
+void CodeSourceMap::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void Stackmap::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void LocalVarDescriptors::PrintJSONImpl(JSONStream* stream,
+                                        bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Object", ref);
+  // TODO(johnmccutchan): Generate a stable id. LocalVarDescriptors hang off
+  // a Code object but do not have a back reference to generate an ID.
+  jsobj.AddServiceId(*this);
+  if (ref) {
+    return;
+  }
+  JSONArray members(&jsobj, "members");
+  String& var_name = String::Handle();
+  for (intptr_t i = 0; i < Length(); i++) {
+    RawLocalVarDescriptors::VarInfo info;
+    var_name = GetName(i);
+    GetInfo(i, &info);
+    JSONObject var(&members);
+    var.AddProperty("name", var_name.ToCString());
+    var.AddProperty("index", static_cast<intptr_t>(info.index()));
+    var.AddProperty("beginPos", info.begin_pos);
+    var.AddProperty("endPos", info.end_pos);
+    var.AddProperty("scopeId", static_cast<intptr_t>(info.scope_id));
+    var.AddProperty("kind", KindToCString(info.kind()));
+  }
+}
+
+
+void ExceptionHandlers::PrintJSONImpl(JSONStream* stream,
+                                      bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void ICData::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Object", ref);
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("_owner", Object::Handle(Owner()));
+  jsobj.AddProperty("_selector", String::Handle(target_name()).ToCString());
+  if (ref) {
+    return;
+  }
+  jsobj.AddProperty("_argumentsDescriptor",
+                    Object::Handle(arguments_descriptor()));
+  jsobj.AddProperty("_entries", Object::Handle(ic_data()));
+}
+
+
+void ICData::PrintToJSONArray(const JSONArray& jsarray,
+                              TokenPosition token_pos,
+                              bool is_static_call) const {
+  Isolate* isolate = Isolate::Current();
+  Class& cls = Class::Handle();
+  Function& func = Function::Handle();
+
+  JSONObject jsobj(&jsarray);
+  jsobj.AddProperty("name", String::Handle(target_name()).ToCString());
+  jsobj.AddProperty("tokenPos", token_pos);
+  // TODO(rmacnak): Figure out how to stringify DeoptReasons().
+  // jsobj.AddProperty("deoptReasons", ...);
+
+  JSONArray cache_entries(&jsobj, "cacheEntries");
+  for (intptr_t i = 0; i < NumberOfChecks(); i++) {
+    func = GetTargetAt(i);
+    if (is_static_call) {
+      cls ^= func.Owner();
+    } else {
+      intptr_t cid = GetReceiverClassIdAt(i);
+      cls ^= isolate->class_table()->At(cid);
+    }
+    intptr_t count = GetCountAt(i);
+    JSONObject cache_entry(&cache_entries);
+    if (cls.IsTopLevel()) {
+      cache_entry.AddProperty("receiverContainer",
+                              Library::Handle(cls.library()));
+    } else {
+      cache_entry.AddProperty("receiverContainer", cls);
+    }
+    cache_entry.AddProperty("count", count);
+    cache_entry.AddProperty("target", func);
+  }
+}
+
+
+void ICData::PrintToJSONArrayNew(const JSONArray& jsarray,
+                                 TokenPosition token_pos,
+                                 bool is_static_call) const {
+  Isolate* isolate = Isolate::Current();
+  Class& cls = Class::Handle();
+  Function& func = Function::Handle();
+
+  JSONObject jsobj(&jsarray);
+  jsobj.AddProperty("name", String::Handle(target_name()).ToCString());
+  jsobj.AddProperty("tokenPos", token_pos.value());
+  // TODO(rmacnak): Figure out how to stringify DeoptReasons().
+  // jsobj.AddProperty("deoptReasons", ...);
+
+  JSONArray cache_entries(&jsobj, "cacheEntries");
+  for (intptr_t i = 0; i < NumberOfChecks(); i++) {
+    JSONObject cache_entry(&cache_entries);
+    func = GetTargetAt(i);
+    intptr_t count = GetCountAt(i);
+    if (!is_static_call) {
+      intptr_t cid = GetReceiverClassIdAt(i);
+      cls ^= isolate->class_table()->At(cid);
+      cache_entry.AddProperty("receiver", cls);
+    }
+    cache_entry.AddProperty("target", func);
+    cache_entry.AddProperty("count", count);
+  }
+}
+
+
+void Code::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Code", ref);
+  jsobj.AddFixedServiceId("code/%" Px64"-%" Px "",
+                          compile_timestamp(),
+                          EntryPoint());
+  const String& qualified_name = String::Handle(QualifiedName());
+  const String& vm_name = String::Handle(Name());
+  AddNameProperties(&jsobj, qualified_name, vm_name);
+  const bool is_stub = IsStubCode() || IsAllocationStubCode();
+  if (is_stub) {
+    jsobj.AddProperty("kind", "Stub");
+  } else {
+    jsobj.AddProperty("kind", "Dart");
+  }
+  jsobj.AddProperty("_optimized", is_optimized());
+  const Object& obj = Object::Handle(owner());
+  if (obj.IsFunction()) {
+    const Function& func = Function::Cast(obj);
+    jsobj.AddProperty("_intrinsic", func.is_intrinsic());
+    jsobj.AddProperty("_native", func.is_native());
+  } else {
+    jsobj.AddProperty("_intrinsic", false);
+    jsobj.AddProperty("_native", false);
+  }
+  if (ref) {
+    return;
+  }
+  if (obj.IsFunction()) {
+    jsobj.AddProperty("function", obj);
+  } else {
+    // Generate a fake function reference.
+    JSONObject func(&jsobj, "function");
+    func.AddProperty("type", "@Function");
+    func.AddProperty("_kind", "Stub");
+    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());
+  jsobj.AddProperty("_alive", is_alive());
+  const ObjectPool& object_pool = ObjectPool::Handle(GetObjectPool());
+  jsobj.AddProperty("_objectPool", object_pool);
+  {
+    JSONArray jsarr(&jsobj, "_disassembly");
+    if (is_alive()) {
+      // Only disassemble alive code objects.
+      DisassembleToJSONStream formatter(jsarr);
+      Disassemble(&formatter);
+    }
+  }
+  const PcDescriptors& descriptors = PcDescriptors::Handle(pc_descriptors());
+  if (!descriptors.IsNull()) {
+    JSONObject desc(&jsobj, "_descriptors");
+    descriptors.PrintToJSONObject(&desc, false);
+  }
+  const Array& inlined_function_table = Array::Handle(GetInlinedIdToFunction());
+  if (!inlined_function_table.IsNull() &&
+      (inlined_function_table.Length() > 0)) {
+    JSONArray inlined_functions(&jsobj, "_inlinedFunctions");
+    Function& function = Function::Handle();
+    for (intptr_t i = 0; i < inlined_function_table.Length(); i++) {
+      function ^= inlined_function_table.At(i);
+      ASSERT(!function.IsNull());
+      inlined_functions.AddValue(function);
+    }
+  }
+  const Array& intervals = Array::Handle(GetInlinedIntervals());
+  if (!intervals.IsNull() && (intervals.Length() > 0)) {
+    Smi& start = Smi::Handle();
+    Smi& end = Smi::Handle();
+    Smi& temp_smi = Smi::Handle();
+    JSONArray inline_intervals(&jsobj, "_inlinedIntervals");
+    for (intptr_t i = 0; i < intervals.Length() - Code::kInlIntNumEntries;
+         i += Code::kInlIntNumEntries) {
+      start ^= intervals.At(i + Code::kInlIntStart);
+      if (start.IsNull()) {
+        continue;
+      }
+      end ^= intervals.At(i + Code::kInlIntNumEntries + Code::kInlIntStart);
+
+      // Format: [start, end, inline functions...]
+      JSONArray inline_interval(&inline_intervals);
+      inline_interval.AddValue(start.Value());
+      inline_interval.AddValue(end.Value());
+
+      temp_smi ^= intervals.At(i + Code::kInlIntInliningId);
+      intptr_t inlining_id = temp_smi.Value();
+      ASSERT(inlining_id >= 0);
+      intptr_t caller_id = GetCallerId(inlining_id);
+      while (inlining_id >= 0) {
+        inline_interval.AddValue(inlining_id);
+        inlining_id = caller_id;
+        caller_id = GetCallerId(inlining_id);
+      }
+    }
+  }
+}
+
+
+void Context::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  // TODO(turnidge): Should the user level type for Context be Context
+  // or Object?
+  AddCommonObjectProperties(&jsobj, "Context", ref);
+  jsobj.AddServiceId(*this);
+
+  jsobj.AddProperty("length", num_variables());
+
+  if (ref) {
+    return;
+  }
+
+  const Context& parent_context = Context::Handle(parent());
+  if (!parent_context.IsNull()) {
+    jsobj.AddProperty("parent", parent_context);
+  }
+
+  JSONArray jsarr(&jsobj, "variables");
+  Object& var = Object::Handle();
+  for (intptr_t index = 0; index < num_variables(); index++) {
+    var = At(index);
+    JSONObject jselement(&jsarr);
+    jselement.AddProperty("value", var);
+  }
+}
+
+
+void ContextScope::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void MegamorphicCache::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Object", ref);
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("_selector", String::Handle(target_name()).ToCString());
+  if (ref) {
+    return;
+  }
+  jsobj.AddProperty("_buckets", Object::Handle(buckets()));
+  jsobj.AddProperty("_mask", mask());
+  jsobj.AddProperty("_argumentsDescriptor",
+                    Object::Handle(arguments_descriptor()));
+}
+
+
+void SubtypeTestCache::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void Error::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  UNREACHABLE();
+}
+
+
+void ApiError::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Error", ref);
+  jsobj.AddProperty("kind", "InternalError");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("message", ToErrorCString());
+}
+
+
+void LanguageError::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Error", ref);
+  jsobj.AddProperty("kind", "LanguageError");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("message", ToErrorCString());
+}
+
+
+void UnhandledException::PrintJSONImpl(JSONStream* stream,
+                                       bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Error", ref);
+  jsobj.AddProperty("kind", "UnhandledException");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("message", ToErrorCString());
+  if (ref) {
+    return;
+  }
+  Instance& instance = Instance::Handle();
+  instance = exception();
+  jsobj.AddProperty("exception", instance);
+  instance = stacktrace();
+  jsobj.AddProperty("stacktrace", instance);
+}
+
+
+void UnwindError::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  AddCommonObjectProperties(&jsobj, "Error", ref);
+  jsobj.AddProperty("kind", "TerminationError");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("message", ToErrorCString());
+  jsobj.AddProperty("_is_user_initiated", is_user_initiated());
+  jsobj.AddProperty("_is_vm_restart", is_vm_restart());
+}
+
+
+void Instance::PrintSharedInstanceJSON(JSONObject* jsobj,
+                                       bool ref) const {
+  AddCommonObjectProperties(jsobj, "Instance", ref);
+  if (ref) {
+    return;
+  }
+
+  // Walk the superclass chain, adding all instance fields.
+  Class& cls = Class::Handle(this->clazz());
+  {
+    Instance& fieldValue = Instance::Handle();
+    JSONArray jsarr(jsobj, "fields");
+    while (!cls.IsNull()) {
+      const Array& field_array = Array::Handle(cls.fields());
+      Field& field = Field::Handle();
+      if (!field_array.IsNull()) {
+        for (intptr_t i = 0; i < field_array.Length(); i++) {
+          field ^= field_array.At(i);
+          if (!field.is_static()) {
+            fieldValue ^= GetField(field);
+            JSONObject jsfield(&jsarr);
+            jsfield.AddProperty("type", "BoundField");
+            jsfield.AddProperty("decl", field);
+            jsfield.AddProperty("value", fieldValue);
+          }
+        }
+      }
+      cls = cls.SuperClass();
+    }
+  }
+
+  if (NumNativeFields() > 0) {
+    JSONArray jsarr(jsobj, "_nativeFields");
+    for (intptr_t i = 0; i < NumNativeFields(); i++) {
+      intptr_t value = GetNativeField(i);
+      JSONObject jsfield(&jsarr);
+      jsfield.AddProperty("index", i);
+      jsfield.AddProperty("value", value);
+    }
+  }
+}
+
+
+void Instance::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+
+  // Handle certain special instance values.
+  if (raw() == Object::sentinel().raw()) {
+    jsobj.AddProperty("type", "Sentinel");
+    jsobj.AddProperty("kind", "NotInitialized");
+    jsobj.AddProperty("valueAsString", "<not initialized>");
+    return;
+  } else if (raw() == Object::transition_sentinel().raw()) {
+    jsobj.AddProperty("type", "Sentinel");
+    jsobj.AddProperty("kind", "BeingInitialized");
+    jsobj.AddProperty("valueAsString", "<being initialized>");
+    return;
+  }
+
+  PrintSharedInstanceJSON(&jsobj, ref);
+  if (IsClosure()) {
+    jsobj.AddProperty("kind", "Closure");
+  } else {
+    jsobj.AddProperty("kind", "PlainInstance");
+  }
+  jsobj.AddServiceId(*this);
+  if (IsClosure()) {
+    jsobj.AddProperty("closureFunction",
+                      Function::Handle(Closure::Cast(*this).function()));
+    jsobj.AddProperty("closureContext",
+                      Context::Handle(Closure::Cast(*this).context()));
+  }
+  if (ref) {
+    return;
+  }
+  if (IsClosure()) {
+    Debugger* debugger = Isolate::Current()->debugger();
+    Breakpoint* bpt = debugger->BreakpointAtActivation(*this);
+    if (bpt != NULL) {
+      jsobj.AddProperty("_activationBreakpoint", bpt);
+    }
+  }
+}
+
+
+void AbstractType::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  UNREACHABLE();
+}
+
+
+void Type::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Type");
+  if (IsCanonical()) {
+    const Class& type_cls = Class::Handle(type_class());
+    intptr_t id = type_cls.FindCanonicalTypeIndex(*this);
+    ASSERT(id >= 0);
+    intptr_t cid = type_cls.id();
+    jsobj.AddFixedServiceId("classes/%" Pd "/types/%" Pd "", cid, id);
+    jsobj.AddProperty("typeClass", type_cls);
+  } else {
+    jsobj.AddServiceId(*this);
+  }
+  const String& user_name = String::Handle(UserVisibleName());
+  const String& vm_name = String::Handle(Name());
+  AddNameProperties(&jsobj, user_name, vm_name);
+  if (ref) {
+    return;
+  }
+  const TypeArguments& typeArgs = TypeArguments::Handle(arguments());
+  if (!typeArgs.IsNull()) {
+    jsobj.AddProperty("typeArguments", typeArgs);
+  }
+}
+
+
+void FunctionType::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "FunctionType");
+  if (IsCanonical()) {
+    const Class& scope_cls = Class::Handle(scope_class());
+    intptr_t id = scope_cls.FindCanonicalTypeIndex(*this);
+    ASSERT(id >= 0);
+    intptr_t cid = scope_cls.id();
+    jsobj.AddFixedServiceId("classes/%" Pd "/types/%" Pd "", cid, id);
+    jsobj.AddProperty("scopeClass", scope_cls);
+  } else {
+    jsobj.AddServiceId(*this);
+  }
+  const String& user_name = String::Handle(UserVisibleName());
+  const String& vm_name = String::Handle(Name());
+  AddNameProperties(&jsobj, user_name, vm_name);
+  if (ref) {
+    return;
+  }
+  const TypeArguments& typeArgs = TypeArguments::Handle(arguments());
+  if (!typeArgs.IsNull()) {
+    jsobj.AddProperty("typeArguments", typeArgs);
+  }
+}
+
+
+void TypeRef::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "TypeRef");
+  jsobj.AddServiceId(*this);
+  const String& user_name = String::Handle(UserVisibleName());
+  const String& vm_name = String::Handle(Name());
+  AddNameProperties(&jsobj, user_name, vm_name);
+  if (ref) {
+    return;
+  }
+  jsobj.AddProperty("targetType", AbstractType::Handle(type()));
+}
+
+
+void TypeParameter::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "TypeParameter");
+  jsobj.AddServiceId(*this);
+  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());
+  jsobj.AddProperty("parameterizedClass", param_cls);
+  if (ref) {
+    return;
+  }
+  jsobj.AddProperty("parameterIndex", index());
+  const AbstractType& upper_bound = AbstractType::Handle(bound());
+  jsobj.AddProperty("bound", upper_bound);
+}
+
+
+void BoundedType::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "BoundedType");
+  jsobj.AddServiceId(*this);
+  const String& user_name = String::Handle(UserVisibleName());
+  const String& vm_name = String::Handle(Name());
+  AddNameProperties(&jsobj, user_name, vm_name);
+  if (ref) {
+    return;
+  }
+  jsobj.AddProperty("targetType", AbstractType::Handle(type()));
+  jsobj.AddProperty("bound", AbstractType::Handle(bound()));
+}
+
+
+void MixinAppType::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  UNREACHABLE();
+}
+
+
+void Number::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  UNREACHABLE();
+}
+
+
+void Integer::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Int");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("valueAsString", ToCString());
+}
+
+
+void Smi::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Int");
+  jsobj.AddFixedServiceId("objects/int-%" Pd "", Value());
+  jsobj.AddPropertyF("valueAsString", "%" Pd "", Value());
+}
+
+
+void Mint::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Integer::PrintJSONImpl(stream, ref);
+}
+
+
+void Double::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Double");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("valueAsString", ToCString());
+}
+
+
+void Bigint::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Integer::PrintJSONImpl(stream, ref);
+}
+
+
+void String::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  if (raw() == Symbols::OptimizedOut().raw()) {
+    // TODO(turnidge): This is a hack.  The user could have this
+    // special string in their program.  Fixing this involves updating
+    // the debugging api a bit.
+    jsobj.AddProperty("type", "Sentinel");
+    jsobj.AddProperty("kind", "OptimizedOut");
+    jsobj.AddProperty("valueAsString", "<optimized out>");
+    return;
+  }
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "String");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("length", Length());
+  if (ref) {
+    // String refs always truncate to a fixed count;
+    const intptr_t kFixedCount = 128;
+    if (jsobj.AddPropertyStr("valueAsString", *this, 0, kFixedCount)) {
+      jsobj.AddProperty("count", kFixedCount);
+      jsobj.AddProperty("valueAsStringIsTruncated", true);
+    }
+    return;
+  }
+
+  intptr_t offset;
+  intptr_t count;
+  stream->ComputeOffsetAndCount(Length(), &offset, &count);
+  if (offset > 0) {
+    jsobj.AddProperty("offset", offset);
+  }
+  if (count < Length()) {
+    jsobj.AddProperty("count", count);
+  }
+  jsobj.AddPropertyStr("valueAsString", *this, offset, count);
+}
+
+
+void Bool::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  const char* str = ToCString();
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Bool");
+  jsobj.AddFixedServiceId("objects/bool-%s", str);
+  jsobj.AddPropertyF("valueAsString", "%s", str);
+}
+
+
+void Array::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "List");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("length", Length());
+  if (ref) {
+    return;
+  }
+  intptr_t offset;
+  intptr_t count;
+  stream->ComputeOffsetAndCount(Length(), &offset, &count);
+  if (offset > 0) {
+    jsobj.AddProperty("offset", offset);
+  }
+  if (count < Length()) {
+    jsobj.AddProperty("count", count);
+  }
+  intptr_t limit = offset + count;
+  ASSERT(limit <= Length());
+  {
+    JSONArray jsarr(&jsobj, "elements");
+    Object& element = Object::Handle();
+    for (intptr_t index = offset; index < limit; index++) {
+      element = At(index);
+      jsarr.AddValue(element);
+    }
+  }
+}
+
+
+void GrowableObjectArray::PrintJSONImpl(JSONStream* stream,
+                                        bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "List");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("length", Length());
+  if (ref) {
+    return;
+  }
+  intptr_t offset;
+  intptr_t count;
+  stream->ComputeOffsetAndCount(Length(), &offset, &count);
+  if (offset > 0) {
+    jsobj.AddProperty("offset", offset);
+  }
+  if (count < Length()) {
+    jsobj.AddProperty("count", count);
+  }
+  intptr_t limit = offset + count;
+  ASSERT(limit <= Length());
+  {
+    JSONArray jsarr(&jsobj, "elements");
+    Object& element = Object::Handle();
+    for (intptr_t index = offset; index < limit; index++) {
+      element = At(index);
+      jsarr.AddValue(element);
+    }
+  }
+}
+
+
+void LinkedHashMap::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Map");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("length", Length());
+  if (ref) {
+    return;
+  }
+  intptr_t offset;
+  intptr_t count;
+  stream->ComputeOffsetAndCount(Length(), &offset, &count);
+  if (offset > 0) {
+    jsobj.AddProperty("offset", offset);
+  }
+  if (count < Length()) {
+    jsobj.AddProperty("count", count);
+  }
+  intptr_t limit = offset + count;
+  ASSERT(limit <= Length());
+  {
+    JSONArray jsarr(&jsobj, "associations");
+    Object& object = Object::Handle();
+    LinkedHashMap::Iterator iterator(*this);
+    int i = 0;
+    while (iterator.MoveNext() && i < limit) {
+      if (i >= offset) {
+        JSONObject jsassoc(&jsarr);
+        object = iterator.CurrentKey();
+        jsassoc.AddProperty("key", object);
+        object = iterator.CurrentValue();
+        jsassoc.AddProperty("value", object);
+      }
+      i++;
+    }
+  }
+}
+
+
+void Float32x4::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Float32x4");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("valueAsString", ToCString());
+}
+
+
+void Int32x4::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Int32x4");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("valueAsString", ToCString());
+}
+
+
+void Float64x2::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "Float64x2");
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("valueAsString", ToCString());
+}
+
+
+void TypedData::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  const Class& cls = Class::Handle(clazz());
+  const String& kind = String::Handle(cls.UserVisibleName());
+  jsobj.AddProperty("kind", kind.ToCString());
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("length", Length());
+  if (ref) {
+    return;
+  }
+  intptr_t offset;
+  intptr_t count;
+  stream->ComputeOffsetAndCount(Length(), &offset, &count);
+  if (offset > 0) {
+    jsobj.AddProperty("offset", offset);
+  }
+  if (count < Length()) {
+    jsobj.AddProperty("count", count);
+  }
+  if (count == 0) {
+    jsobj.AddProperty("bytes", "");
+  } else {
+    NoSafepointScope no_safepoint;
+    jsobj.AddPropertyBase64("bytes",
+                            reinterpret_cast<const uint8_t*>(
+                                DataAddr(offset * ElementSizeInBytes())),
+                            count * ElementSizeInBytes());
+  }
+}
+
+
+void ExternalTypedData::PrintJSONImpl(JSONStream* stream,
+                                      bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  const Class& cls = Class::Handle(clazz());
+  const String& kind = String::Handle(cls.UserVisibleName());
+  jsobj.AddProperty("kind", kind.ToCString());
+  jsobj.AddServiceId(*this);
+  jsobj.AddProperty("length", Length());
+  if (ref) {
+    return;
+  }
+  intptr_t offset;
+  intptr_t count;
+  stream->ComputeOffsetAndCount(Length(), &offset, &count);
+  if (offset > 0) {
+    jsobj.AddProperty("offset", offset);
+  }
+  if (count < Length()) {
+    jsobj.AddProperty("count", count);
+  }
+  if (count == 0) {
+    jsobj.AddProperty("bytes", "");
+  } else {
+    NoSafepointScope no_safepoint;
+    jsobj.AddPropertyBase64("bytes",
+                            reinterpret_cast<const uint8_t*>(
+                                DataAddr(offset * ElementSizeInBytes())),
+                            count * ElementSizeInBytes());
+  }
+}
+
+
+void Capability::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Instance::PrintJSONImpl(stream, ref);
+}
+
+
+void ReceivePort::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Instance::PrintJSONImpl(stream, ref);
+}
+
+
+void SendPort::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Instance::PrintJSONImpl(stream, ref);
+}
+
+
+void ClosureData::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
+
+void Closure::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Instance::PrintJSONImpl(stream, ref);
+}
+
+
+void Stacktrace::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "StackTrace");
+  jsobj.AddServiceId(*this);
+  intptr_t idx = 0;
+  jsobj.AddProperty("valueAsString", ToCStringInternal(&idx));
+}
+
+
+void JSRegExp::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "RegExp");
+  jsobj.AddServiceId(*this);
+
+  jsobj.AddProperty("pattern", String::Handle(pattern()));
+
+  if (ref) {
+    return;
+  }
+
+  jsobj.AddProperty("isCaseSensitive", !is_ignore_case());
+  jsobj.AddProperty("isMultiLine", is_multi_line());
+
+  Function& func = Function::Handle();
+  func = function(kOneByteStringCid);
+  jsobj.AddProperty("_oneByteFunction", func);
+  func = function(kTwoByteStringCid);
+  jsobj.AddProperty("_twoByteFunction", func);
+  func = function(kExternalOneByteStringCid);
+  jsobj.AddProperty("_externalOneByteFunction", func);
+  func = function(kExternalTwoByteStringCid);
+  jsobj.AddProperty("_externalTwoByteFunction", func);
+}
+
+
+void WeakProperty::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "WeakProperty");
+  jsobj.AddServiceId(*this);
+  if (ref) {
+    return;
+  }
+
+  const Object& key_handle = Object::Handle(key());
+  jsobj.AddProperty("propertyKey", key_handle);
+  const Object& value_handle = Object::Handle(value());
+  jsobj.AddProperty("propertyValue", value_handle);
+}
+
+
+void MirrorReference::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "MirrorReference");
+  jsobj.AddServiceId(*this);
+
+  if (ref) {
+    return;
+  }
+
+  const Object& referent_handle = Object::Handle(referent());
+  jsobj.AddProperty("mirrorReferent", referent_handle);
+}
+
+void UserTag::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Instance::PrintJSONImpl(stream, ref);
+}
+
+#endif
+
+}  // namespace dart
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 624e1fe..a0feb38 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -20,7 +20,7 @@
     null_class_(Class::null()),
     null_type_(Type::null()),
     function_type_(Type::null()),
-    function_impl_type_(Type::null()),
+    closure_class_(Class::null()),
     number_type_(Type::null()),
     int_type_(Type::null()),
     integer_implementation_class_(Class::null()),
@@ -79,7 +79,6 @@
     resume_capabilities_(GrowableObjectArray::null()),
     exit_listeners_(GrowableObjectArray::null()),
     error_listeners_(GrowableObjectArray::null()),
-    sticky_error_(Error::null()),
     empty_context_(Context::null()),
     stack_overflow_(Instance::null()),
     out_of_memory_(Instance::null()),
@@ -119,7 +118,7 @@
 }
 
 
-bool ObjectStore::PreallocateObjects() {
+RawError* ObjectStore::PreallocateObjects() {
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   Zone* zone = thread->zone();
@@ -127,7 +126,7 @@
   if (this->stack_overflow() != Instance::null()) {
     ASSERT(this->out_of_memory() != Instance::null());
     ASSERT(this->preallocated_stack_trace() != Stacktrace::null());
-    return true;
+    return Error::null();
   }
   ASSERT(this->stack_overflow() == Instance::null());
   ASSERT(this->out_of_memory() == Instance::null());
@@ -148,7 +147,7 @@
                                             Symbols::Dot(),
                                             Object::empty_array());
   if (result.IsError()) {
-    return false;
+    return Error::Cast(result).raw();
   }
   set_stack_overflow(Instance::Cast(result));
 
@@ -157,7 +156,7 @@
                                             Symbols::Dot(),
                                             Object::empty_array());
   if (result.IsError()) {
-    return false;
+    return Error::Cast(result).raw();
   }
   set_out_of_memory(Instance::Cast(result));
 
@@ -179,7 +178,7 @@
   stack_trace.set_expand_inlined(false);
   set_preallocated_stack_trace(stack_trace);
 
-  return true;
+  return Error::null();
 }
 
 
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index db57663..92be955 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -67,9 +67,9 @@
     function_type_ = value.raw();
   }
 
-  RawType* function_impl_type() const { return function_impl_type_; }
-  void set_function_impl_type(const Type& value) {
-    function_impl_type_ = value.raw();
+  RawClass* closure_class() const { return closure_class_; }
+  void set_closure_class(const Class& value) {
+    closure_class_ = value.raw();
   }
 
   RawType* number_type() const { return number_type_; }
@@ -365,15 +365,6 @@
     return error_listeners_;
   }
 
-  RawError* sticky_error() const { return sticky_error_; }
-  void set_sticky_error(const Error& value) {
-    // TODO(asiva): Move sticky_error_ into thread specific area.
-    ASSERT(Thread::Current()->IsMutatorThread());
-    ASSERT(!value.IsNull());
-    sticky_error_ = value.raw();
-  }
-  void clear_sticky_error() { sticky_error_ = Error::null(); }
-
   RawContext* empty_context() const { return empty_context_; }
   void set_empty_context(const Context& value) {
     empty_context_ = value.raw();
@@ -487,9 +478,9 @@
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
   // Called to initialize objects required by the vm but which invoke
-  // dart code.  If an error occurs then false is returned and error
-  // information is stored in sticky_error().
-  bool PreallocateObjects();
+  // dart code.  If an error occurs the error object is returned otherwise
+  // a null object is returned.
+  RawError* PreallocateObjects();
 
   void InitKnownObjects();
 
@@ -504,7 +495,7 @@
   RawClass* null_class_;
   RawType* null_type_;
   RawType* function_type_;
-  RawType* function_impl_type_;
+  RawClass* closure_class_;
   RawType* number_type_;
   RawType* int_type_;
   RawClass* integer_implementation_class_;
@@ -563,7 +554,6 @@
   RawGrowableObjectArray* resume_capabilities_;
   RawGrowableObjectArray* exit_listeners_;
   RawGrowableObjectArray* error_listeners_;
-  RawError* sticky_error_;
   RawContext* empty_context_;
   RawInstance* stack_overflow_;
   RawInstance* out_of_memory_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 422121e..e793b9b 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -29,13 +29,13 @@
 static RawClass* CreateDummyClass(const String& class_name,
                                   const Script& script) {
   const Class& cls = Class::Handle(
-      Class::New(class_name, script, Scanner::kNoSourcePos));
+      Class::New(class_name, script, TokenPosition::kNoSource));
   cls.set_is_synthesized_class();  // Dummy class for testing.
   return cls.raw();
 }
 
 
-TEST_CASE(Class) {
+VM_TEST_CASE(Class) {
   // Allocate the class first.
   const String& class_name = String::Handle(Symbols::New("MyClass"));
   const Script& script = Script::Handle();
@@ -68,12 +68,12 @@
   function_name = Symbols::New("foo");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      false, false, false, false, false, cls, 0);
+      false, false, false, false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(0, function);
   function_name = Symbols::New("bar");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      false, false, false, false, false, cls, 0);
+      false, false, false, false, false, cls, TokenPosition::kMinSource);
 
   const int kNumFixedParameters = 2;
   const int kNumOptionalParameters = 3;
@@ -86,24 +86,24 @@
   function_name = Symbols::New("baz");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      false, false, false, false, false, cls, 0);
+      false, false, false, false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(2, function);
 
   function_name = Symbols::New("Foo");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      true, false, false, false, false, cls, 0);
+      true, false, false, false, false, cls, TokenPosition::kMinSource);
 
   functions.SetAt(3, function);
   function_name = Symbols::New("Bar");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      true, false, false, false, false, cls, 0);
+      true, false, false, false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(4, function);
   function_name = Symbols::New("BaZ");
   function = Function::New(
       function_name, RawFunction::kRegularFunction,
-      true, false, false, false, false, cls, 0);
+      true, false, false, false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(5, function);
 
   // Setup the functions in the class.
@@ -143,7 +143,7 @@
 }
 
 
-TEST_CASE(TypeArguments) {
+VM_TEST_CASE(TypeArguments) {
   const Type& type1 = Type::Handle(Type::Double());
   const Type& type2 = Type::Handle(Type::StringType());
   const TypeArguments& type_arguments1 = TypeArguments::Handle(
@@ -165,7 +165,7 @@
 }
 
 
-TEST_CASE(TokenStream) {
+VM_TEST_CASE(TokenStream) {
   String& source = String::Handle(String::New("= ( 9 , ."));
   String& private_key = String::Handle(String::New(""));
   Scanner scanner(source, private_key);
@@ -174,7 +174,7 @@
   EXPECT_EQ(Token::kLPAREN, ts[1].kind);
   const TokenStream& token_stream = TokenStream::Handle(
       TokenStream::New(ts, private_key, false));
-  TokenStream::Iterator iterator(token_stream, 0);
+  TokenStream::Iterator iterator(token_stream, TokenPosition::kMinSource);
   // EXPECT_EQ(6, token_stream.Length());
   iterator.Advance();  // Advance to '(' token.
   EXPECT_EQ(Token::kLPAREN, iterator.CurrentTokenKind());
@@ -187,7 +187,7 @@
 }
 
 
-TEST_CASE(GenerateExactSource) {
+VM_TEST_CASE(GenerateExactSource) {
   // Verify the exact formatting of generated sources.
   const char* kScriptChars =
   "\n"
@@ -196,10 +196,16 @@
   "  static fly() { return 5; }\n"
   "  void catcher(x) {\n"
   "    try {\n"
-  "      if (x) {\n"
-  "        fly();\n"
+  "      if (x is! List) {\n"
+  "        for (int i = 0; i < x; i++) {\n"
+  "          fly();\n"
+  "          ++i;\n"
+  "        }\n"
   "      } else {\n"
-  "        !fly();\n"
+  "        for (int i = 0; i < x; i--) {\n"
+  "          !fly();\n"
+  "          --i;\n"
+  "        }\n"
   "      }\n"
   "    } on Blah catch (a) {\n"
   "      _print(17);\n"
@@ -241,7 +247,7 @@
   const Class& cls = Class::Handle(
       lib.LookupClass(String::Handle(String::New("A"))));
   EXPECT(!cls.IsNull());
-  const intptr_t end_token_pos = cls.ComputeEndTokenPos();
+  const TokenPosition end_token_pos = cls.ComputeEndTokenPos();
   const Script& scr = Script::Handle(cls.script());
   intptr_t line;
   intptr_t col;
@@ -250,7 +256,7 @@
 }
 
 
-TEST_CASE(InstanceClass) {
+VM_TEST_CASE(InstanceClass) {
   // Allocate the class first.
   String& class_name = String::Handle(Symbols::New("EmptyClass"));
   Script& script = Script::Handle();
@@ -282,7 +288,7 @@
   const String& field_name = String::Handle(Symbols::New("the_field"));
   const Field& field = Field::Handle(
       Field::New(field_name, false, false, false, true, one_field_class,
-                 Object::dynamic_type(), 0));
+                 Object::dynamic_type(), TokenPosition::kMinSource));
   one_fields.SetAt(0, field);
   one_field_class.SetFields(one_fields);
   one_field_class.Finalize();
@@ -296,7 +302,7 @@
 }
 
 
-TEST_CASE(Smi) {
+VM_TEST_CASE(Smi) {
   const Smi& smi = Smi::Handle(Smi::New(5));
   Object& smi_object = Object::Handle(smi.raw());
   EXPECT(smi.IsSmi());
@@ -358,7 +364,7 @@
 }
 
 
-TEST_CASE(StringCompareTo) {
+VM_TEST_CASE(StringCompareTo) {
   const String& abcd = String::Handle(String::New("abcd"));
   const String& abce = String::Handle(String::New("abce"));
   EXPECT_EQ(0, abcd.CompareTo(abcd));
@@ -402,7 +408,7 @@
 }
 
 
-TEST_CASE(StringEncodeIRI) {
+VM_TEST_CASE(StringEncodeIRI) {
   const char* kInput =
       "file:///usr/local/johnmccutchan/workspace/dart-repo/dart/test.dart";
   const char* kOutput =
@@ -415,7 +421,7 @@
 }
 
 
-TEST_CASE(StringDecodeIRI) {
+VM_TEST_CASE(StringDecodeIRI) {
   const char* kOutput =
       "file:///usr/local/johnmccutchan/workspace/dart-repo/dart/test.dart";
   const char* kInput =
@@ -428,7 +434,7 @@
 }
 
 
-TEST_CASE(StringDecodeIRIInvalid) {
+VM_TEST_CASE(StringDecodeIRIInvalid) {
   String& input = String::Handle();
   input = String::New("file%");
   String& decoded = String::Handle();
@@ -443,7 +449,7 @@
 }
 
 
-TEST_CASE(StringIRITwoByte) {
+VM_TEST_CASE(StringIRITwoByte) {
   const intptr_t kInputLen = 3;
   const uint16_t kInput[kInputLen] = { 'x', '/', 256 };
   const String& input = String::Handle(String::FromUTF16(kInput, kInputLen));
@@ -458,7 +464,7 @@
 }
 
 
-TEST_CASE(Mint) {
+VM_TEST_CASE(Mint) {
 // On 64-bit architectures a Smi is stored in a 64 bit word. A Midint cannot
 // be allocated if it does fit into a Smi.
 #if !defined(ARCH_IS_64_BIT)
@@ -532,7 +538,7 @@
 }
 
 
-TEST_CASE(Double) {
+VM_TEST_CASE(Double) {
   {
     const double dbl_const = 5.0;
     const Double& dbl = Double::Handle(Double::New(dbl_const));
@@ -616,7 +622,7 @@
 }
 
 
-TEST_CASE(Bigint) {
+VM_TEST_CASE(Bigint) {
   Bigint& b = Bigint::Handle();
   EXPECT(b.IsNull());
   const char* cstr = "18446744073709551615000";
@@ -655,7 +661,7 @@
 }
 
 
-TEST_CASE(Integer) {
+VM_TEST_CASE(Integer) {
   Integer& i = Integer::Handle();
   i = Integer::NewCanonical(String::Handle(String::New("12")));
   EXPECT(i.IsSmi());
@@ -672,7 +678,7 @@
 }
 
 
-TEST_CASE(String) {
+VM_TEST_CASE(String) {
   const char* kHello = "Hello World!";
   int32_t hello_len = strlen(kHello);
   const String& str = String::Handle(String::New(kHello));
@@ -819,7 +825,7 @@
 }
 
 
-TEST_CASE(StringFormat) {
+VM_TEST_CASE(StringFormat) {
   const char* hello_str = "Hello World!";
   const String& str =
       String::Handle(String::NewFormatted("Hello %s!", "World"));
@@ -832,7 +838,7 @@
 }
 
 
-TEST_CASE(StringConcat) {
+VM_TEST_CASE(StringConcat) {
   // Create strings from concatenated 1-byte empty strings.
   {
     const String& empty1 = String::Handle(String::New(""));
@@ -1366,7 +1372,7 @@
 }
 
 
-TEST_CASE(StringHashConcat) {
+VM_TEST_CASE(StringHashConcat) {
   EXPECT_EQ(String::Handle(String::New("onebyte")).Hash(),
             String::HashConcat(String::Handle(String::New("one")),
                                String::Handle(String::New("byte"))));
@@ -1382,7 +1388,7 @@
 }
 
 
-TEST_CASE(StringSubStringDifferentWidth) {
+VM_TEST_CASE(StringSubStringDifferentWidth) {
   // Create 1-byte substring from a 1-byte source string.
   const char* onechars =
       "\xC3\xB6\xC3\xB1\xC3\xA9";
@@ -1444,7 +1450,7 @@
 }
 
 
-TEST_CASE(StringFromUtf8Literal) {
+VM_TEST_CASE(StringFromUtf8Literal) {
   // Create a 1-byte string from a UTF-8 encoded string literal.
   {
     const char* src =
@@ -1612,7 +1618,7 @@
 }
 
 
-TEST_CASE(StringEqualsUtf8) {
+VM_TEST_CASE(StringEqualsUtf8) {
   const char* onesrc = "abc";
   const String& onestr = String::Handle(String::New(onesrc));
   EXPECT(onestr.IsOneByteString());
@@ -1643,7 +1649,7 @@
 }
 
 
-TEST_CASE(StringEqualsUTF32) {
+VM_TEST_CASE(StringEqualsUTF32) {
   const String& empty = String::Handle(String::New(""));
   const String& t_str = String::Handle(String::New("t"));
   const String& th_str = String::Handle(String::New("th"));
@@ -1660,7 +1666,7 @@
 }
 
 
-TEST_CASE(ExternalOneByteString) {
+VM_TEST_CASE(ExternalOneByteString) {
   uint8_t characters[] = { 0xF6, 0xF1, 0xE9 };
   intptr_t len = ARRAY_SIZE(characters);
 
@@ -1692,7 +1698,7 @@
 }
 
 
-TEST_CASE(EscapeSpecialCharactersOneByteString) {
+VM_TEST_CASE(EscapeSpecialCharactersOneByteString) {
   uint8_t characters[] =
       { 'a', '\n', '\f', '\b', '\t', '\v', '\r', '\\', '$', 'z' };
   intptr_t len = ARRAY_SIZE(characters);
@@ -1713,7 +1719,7 @@
 }
 
 
-TEST_CASE(EscapeSpecialCharactersExternalOneByteString) {
+VM_TEST_CASE(EscapeSpecialCharactersExternalOneByteString) {
   uint8_t characters[] =
       { 'a', '\n', '\f', '\b', '\t', '\v', '\r', '\\', '$', 'z' };
   intptr_t len = ARRAY_SIZE(characters);
@@ -1738,7 +1744,7 @@
   EXPECT_EQ(escaped_empty_str.Length(), 0);
 }
 
-TEST_CASE(EscapeSpecialCharactersTwoByteString) {
+VM_TEST_CASE(EscapeSpecialCharactersTwoByteString) {
   uint16_t characters[] =
       { 'a', '\n', '\f', '\b', '\t', '\v', '\r', '\\', '$', 'z' };
   intptr_t len = ARRAY_SIZE(characters);
@@ -1761,7 +1767,7 @@
 }
 
 
-TEST_CASE(EscapeSpecialCharactersExternalTwoByteString) {
+VM_TEST_CASE(EscapeSpecialCharactersExternalTwoByteString) {
   uint16_t characters[] =
       { 'a', '\n', '\f', '\b', '\t', '\v', '\r', '\\', '$', 'z' };
   intptr_t len = ARRAY_SIZE(characters);
@@ -1786,7 +1792,7 @@
 }
 
 
-TEST_CASE(ExternalTwoByteString) {
+VM_TEST_CASE(ExternalTwoByteString) {
   uint16_t characters[] = { 0x1E6B, 0x1E85, 0x1E53 };
   intptr_t len = ARRAY_SIZE(characters);
 
@@ -1819,7 +1825,7 @@
 }
 
 
-TEST_CASE(Symbol) {
+VM_TEST_CASE(Symbol) {
   const String& one = String::Handle(Symbols::New("Eins"));
   EXPECT(one.IsSymbol());
   const String& two = String::Handle(Symbols::New("Zwei"));
@@ -1881,7 +1887,7 @@
 }
 
 
-TEST_CASE(SymbolUnicode) {
+VM_TEST_CASE(SymbolUnicode) {
   uint16_t monkey_utf16[] = { 0xd83d, 0xdc35 };  // Unicode Monkey Face.
   String& monkey = String::Handle(Symbols::FromUTF16(monkey_utf16, 2));
   EXPECT(monkey.IsSymbol());
@@ -1903,13 +1909,13 @@
 }
 
 
-TEST_CASE(Bool) {
+VM_TEST_CASE(Bool) {
   EXPECT(Bool::True().value());
   EXPECT(!Bool::False().value());
 }
 
 
-TEST_CASE(Array) {
+VM_TEST_CASE(Array) {
   const int kArrayLen = 5;
   const Array& array = Array::Handle(Array::New(kArrayLen));
   EXPECT_EQ(kArrayLen, array.Length());
@@ -2056,7 +2062,7 @@
 }
 
 
-TEST_CASE(StringCodePointIterator) {
+VM_TEST_CASE(StringCodePointIterator) {
   const String& str0 = String::Handle(String::New(""));
   String::CodePointIterator it0(str0);
   EXPECT(!it0.Next());
@@ -2111,7 +2117,7 @@
 }
 
 
-TEST_CASE(StringCodePointIteratorRange) {
+VM_TEST_CASE(StringCodePointIteratorRange) {
   const String& str = String::Handle(String::New("foo bar baz"));
 
   String::CodePointIterator it0(str, 3, 0);
@@ -2128,7 +2134,7 @@
 }
 
 
-TEST_CASE(GrowableObjectArray) {
+VM_TEST_CASE(GrowableObjectArray) {
   const int kArrayLen = 5;
   Smi& value = Smi::Handle();
   Smi& expected_value = Smi::Handle();
@@ -2250,7 +2256,7 @@
 }
 
 
-TEST_CASE(InternalTypedData) {
+VM_TEST_CASE(InternalTypedData) {
   uint8_t data[] = { 253, 254, 255, 0, 1, 2, 3, 4 };
   intptr_t data_length = ARRAY_SIZE(data);
 
@@ -2306,7 +2312,7 @@
 }
 
 
-TEST_CASE(ExternalTypedData) {
+VM_TEST_CASE(ExternalTypedData) {
   uint8_t data[] = { 253, 254, 255, 0, 1, 2, 3, 4 };
   intptr_t data_length = ARRAY_SIZE(data);
 
@@ -2407,7 +2413,7 @@
 }
 
 
-TEST_CASE(EmbeddedScript) {
+VM_TEST_CASE(EmbeddedScript) {
   const char* url_chars = "builtin:test-case";
   const char* text =
       /* 1 */ "<!DOCTYPE html>\n"
@@ -2462,47 +2468,47 @@
 
   intptr_t line, col;
   intptr_t fast_line;
-  script.GetTokenLocation(0, &line, &col);
+  script.GetTokenLocation(TokenPosition(0), &line, &col);
   EXPECT_EQ(first_dart_line, line);
   EXPECT_EQ(col, col_offset + 1);
 
   // We allow asking for only the line number, which only scans the token stream
   // instead of rescanning the script.
-  script.GetTokenLocation(0, &fast_line, NULL);
+  script.GetTokenLocation(TokenPosition(0), &fast_line, NULL);
   EXPECT_EQ(line, fast_line);
 
-  script.GetTokenLocation(5, &line, &col);  // Token 'return'
+  script.GetTokenLocation(TokenPosition(5), &line, &col);  // Token 'return'
   EXPECT_EQ(4, line);  // 'return' is in line 4.
   EXPECT_EQ(5, col);   // Four spaces before 'return'.
 
   // We allow asking for only the line number, which only scans the token stream
   // instead of rescanning the script.
-  script.GetTokenLocation(5, &fast_line, NULL);
+  script.GetTokenLocation(TokenPosition(5), &fast_line, NULL);
   EXPECT_EQ(line, fast_line);
 
-  intptr_t first_idx, last_idx;
+  TokenPosition first_idx, last_idx;
   script.TokenRangeAtLine(3, &first_idx, &last_idx);
-  EXPECT_EQ(0, first_idx);  // Token 'main' is first token.
-  EXPECT_EQ(3, last_idx);   // Token { is last token.
+  EXPECT_EQ(0, first_idx.value());  // Token 'main' is first token.
+  EXPECT_EQ(3, last_idx.value());   // Token { is last token.
   script.TokenRangeAtLine(4, &first_idx, &last_idx);
-  EXPECT_EQ(5, first_idx);  // Token 'return' is first token.
-  EXPECT_EQ(7, last_idx);   // Token ; is last token.
+  EXPECT_EQ(5, first_idx.value());  // Token 'return' is first token.
+  EXPECT_EQ(7, last_idx.value());   // Token ; is last token.
   script.TokenRangeAtLine(5, &first_idx, &last_idx);
-  EXPECT_EQ(9, first_idx);  // Token } is first and only token.
-  EXPECT_EQ(9, last_idx);
+  EXPECT_EQ(9, first_idx.value());  // Token } is first and only token.
+  EXPECT_EQ(9, last_idx.value());
   script.TokenRangeAtLine(1, &first_idx, &last_idx);
-  EXPECT_EQ(0, first_idx);
-  EXPECT_EQ(3, last_idx);
+  EXPECT_EQ(0, first_idx.value());
+  EXPECT_EQ(3, last_idx.value());
   script.TokenRangeAtLine(6, &first_idx, &last_idx);
-  EXPECT_EQ(-1, first_idx);
-  EXPECT_EQ(-1, last_idx);
+  EXPECT_EQ(-1, first_idx.value());
+  EXPECT_EQ(-1, last_idx.value());
   script.TokenRangeAtLine(1000, &first_idx, &last_idx);
-  EXPECT_EQ(-1, first_idx);
-  EXPECT_EQ(-1, last_idx);
+  EXPECT_EQ(-1, first_idx.value());
+  EXPECT_EQ(-1, last_idx.value());
 }
 
 
-TEST_CASE(Context) {
+VM_TEST_CASE(Context) {
   const int kNumVariables = 5;
   const Context& parent_context = Context::Handle(Context::New(0));
   const Context& context = Context::Handle(Context::New(kNumVariables));
@@ -2525,7 +2531,7 @@
 }
 
 
-TEST_CASE(ContextScope) {
+VM_TEST_CASE(ContextScope) {
   const intptr_t parent_scope_function_level = 0;
   LocalScope* parent_scope =
       new LocalScope(NULL, parent_scope_function_level, 0);
@@ -2537,17 +2543,17 @@
   const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
   const String& a = String::ZoneHandle(Symbols::New("a"));
   LocalVariable* var_a =
-      new LocalVariable(Scanner::kNoSourcePos, a, dynamic_type);
+      new LocalVariable(TokenPosition::kNoSource, a, dynamic_type);
   parent_scope->AddVariable(var_a);
 
   const String& b = String::ZoneHandle(Symbols::New("b"));
   LocalVariable* var_b =
-      new LocalVariable(Scanner::kNoSourcePos, b, dynamic_type);
+      new LocalVariable(TokenPosition::kNoSource, b, dynamic_type);
   local_scope->AddVariable(var_b);
 
   const String& c = String::ZoneHandle(Symbols::New("c"));
   LocalVariable* var_c =
-      new LocalVariable(Scanner::kNoSourcePos, c, dynamic_type);
+      new LocalVariable(TokenPosition::kNoSource, c, dynamic_type);
   parent_scope->AddVariable(var_c);
 
   bool test_only = false;  // Please, insert alias.
@@ -2612,7 +2618,7 @@
 }
 
 
-TEST_CASE(Closure) {
+VM_TEST_CASE(Closure) {
   // Allocate the class first.
   const String& class_name = String::Handle(Symbols::New("MyClass"));
   const Script& script = Script::Handle();
@@ -2623,29 +2629,26 @@
   Function& parent = Function::Handle();
   const String& parent_name = String::Handle(Symbols::New("foo_papa"));
   parent = Function::New(parent_name, RawFunction::kRegularFunction,
-                         false, false, false, false, false, cls, 0);
+                         false, false, false, false, false, cls,
+                         TokenPosition::kMinSource);
   functions.SetAt(0, parent);
   cls.SetFunctions(functions);
 
   Function& function = Function::Handle();
   const String& function_name = String::Handle(Symbols::New("foo"));
-  function = Function::NewClosureFunction(function_name, parent, 0);
-  const Class& signature_class = Class::Handle(
-      Class::NewSignatureClass(function_name, function, script, 0));
-  const Instance& closure = Instance::Handle(Closure::New(function, context));
+  function = Function::NewClosureFunction(
+      function_name, parent, TokenPosition::kMinSource);
+  const Closure& closure = Closure::Handle(Closure::New(function, context));
   const Class& closure_class = Class::Handle(closure.clazz());
-  EXPECT(closure_class.IsSignatureClass());
-  EXPECT(closure_class.IsCanonicalSignatureClass());
-  EXPECT_EQ(closure_class.raw(), signature_class.raw());
-  const Function& signature_function =
-    Function::Handle(signature_class.signature_function());
-  EXPECT_EQ(signature_function.raw(), function.raw());
-  const Context& closure_context = Context::Handle(Closure::context(closure));
-  EXPECT_EQ(closure_context.raw(), closure_context.raw());
+  EXPECT_EQ(closure_class.id(), kClosureCid);
+  const Function& closure_function = Function::Handle(closure.function());
+  EXPECT_EQ(closure_function.raw(), function.raw());
+  const Context& closure_context = Context::Handle(closure.context());
+  EXPECT_EQ(closure_context.raw(), context.raw());
 }
 
 
-TEST_CASE(ObjectPrinting) {
+VM_TEST_CASE(ObjectPrinting) {
   // Simple Smis.
   EXPECT_STREQ("2", Smi::Handle(Smi::New(2)).ToCString());
   EXPECT_STREQ("-15", Smi::Handle(Smi::New(-15)).ToCString());
@@ -2664,7 +2667,7 @@
 }
 
 
-TEST_CASE(CheckedHandle) {
+VM_TEST_CASE(CheckedHandle) {
   // Ensure that null handles have the correct C++ vtable setup.
   const String& str1 = String::Handle();
   EXPECT(str1.IsString());
@@ -2697,12 +2700,13 @@
   owner_class.set_library(owner_library);
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   return Function::New(function_name, RawFunction::kRegularFunction,
-                       true, false, false, false, false, owner_class, 0);
+                       true, false, false, false, false, owner_class,
+                       TokenPosition::kMinSource);
 }
 
 
 // Test for Code and Instruction object creation.
-TEST_CASE(Code) {
+VM_TEST_CASE(Code) {
   extern void GenerateIncrement(Assembler* assembler);
   Assembler _assembler_;
   GenerateIncrement(&_assembler_);
@@ -2720,7 +2724,7 @@
 
 // Test for immutability of generated instructions. The test crashes with a
 // segmentation fault when writing into it.
-TEST_CASE(CodeImmutability) {
+VM_TEST_CASE(CodeImmutability) {
   extern void GenerateIncrement(Assembler* assembler);
   Assembler _assembler_;
   GenerateIncrement(&_assembler_);
@@ -2742,7 +2746,7 @@
 
 
 // Test for Embedded String object in the instructions.
-TEST_CASE(EmbedStringInCode) {
+VM_TEST_CASE(EmbedStringInCode) {
   extern void GenerateEmbedStringInCode(Assembler* assembler, const char* str);
   const char* kHello = "Hello World!";
   word expected_length = static_cast<word>(strlen(kHello));
@@ -2765,7 +2769,7 @@
 
 
 // Test for Embedded Smi object in the instructions.
-TEST_CASE(EmbedSmiInCode) {
+VM_TEST_CASE(EmbedSmiInCode) {
   extern void GenerateEmbedSmiInCode(Assembler* assembler, intptr_t value);
   const intptr_t kSmiTestValue = 5;
   Assembler _assembler_;
@@ -2782,7 +2786,7 @@
 
 #if defined(ARCH_IS_64_BIT)
 // Test for Embedded Smi object in the instructions.
-TEST_CASE(EmbedSmiIn64BitCode) {
+VM_TEST_CASE(EmbedSmiIn64BitCode) {
   extern void GenerateEmbedSmiInCode(Assembler* assembler, intptr_t value);
   const intptr_t kSmiTestValue = DART_INT64_C(5) << 32;
   Assembler _assembler_;
@@ -2798,7 +2802,7 @@
 #endif  // ARCH_IS_64_BIT
 
 
-TEST_CASE(ExceptionHandlers) {
+VM_TEST_CASE(ExceptionHandlers) {
   const int kNumEntries = 4;
   // Add an exception handler table to the code.
   ExceptionHandlers& exception_handlers = ExceptionHandlers::Handle();
@@ -2836,16 +2840,22 @@
 }
 
 
-TEST_CASE(PcDescriptors) {
+VM_TEST_CASE(PcDescriptors) {
   DescriptorList* builder = new DescriptorList(0);
 
   // kind, pc_offset, deopt_id, token_pos, try_index
-  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 1, 20, 1);
-  builder->AddDescriptor(RawPcDescriptors::kDeopt, 20, 2, 30, 0);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 30, 3, 40, 1);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 4, 40, 2);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 5, 80, 3);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 80, 6, 150, 3);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         10, 1, TokenPosition(20), 1);
+  builder->AddDescriptor(RawPcDescriptors::kDeopt,
+                         20, 2, TokenPosition(30), 0);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         30, 3, TokenPosition(40), 1);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         10, 4, TokenPosition(40), 2);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         10, 5, TokenPosition(80), 3);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         80, 6, TokenPosition(150), 3);
 
   PcDescriptors& descriptors = PcDescriptors::Handle();
   descriptors ^= builder->FinalizePcDescriptors(0);
@@ -2862,47 +2872,53 @@
   PcDescriptors::Iterator iter(pc_descs, RawPcDescriptors::kAnyKind);
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(20, iter.TokenPos());
+  EXPECT_EQ(20, iter.TokenPos().value());
   EXPECT_EQ(1, iter.TryIndex());
   EXPECT_EQ(static_cast<uword>(10), iter.PcOffset());
   EXPECT_EQ(1, iter.DeoptId());
   EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(30, iter.TokenPos());
+  EXPECT_EQ(30, iter.TokenPos().value());
   EXPECT_EQ(RawPcDescriptors::kDeopt, iter.Kind());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(40, iter.TokenPos());
+  EXPECT_EQ(40, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(40, iter.TokenPos());
+  EXPECT_EQ(40, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(80, iter.TokenPos());
+  EXPECT_EQ(80, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(150, iter.TokenPos());
+  EXPECT_EQ(150, iter.TokenPos().value());
 
   EXPECT_EQ(3, iter.TryIndex());
   EXPECT_EQ(static_cast<uword>(80), iter.PcOffset());
-  EXPECT_EQ(150, iter.TokenPos());
+  EXPECT_EQ(150, iter.TokenPos().value());
   EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
 
   EXPECT_EQ(false, iter.MoveNext());
 }
 
 
-TEST_CASE(PcDescriptorsLargeDeltas) {
+VM_TEST_CASE(PcDescriptorsLargeDeltas) {
   DescriptorList* builder = new DescriptorList(0);
 
   // kind, pc_offset, deopt_id, token_pos, try_index
-  builder->AddDescriptor(RawPcDescriptors::kOther, 100, 1, 200, 1);
-  builder->AddDescriptor(RawPcDescriptors::kDeopt, 200, 2, 300, 0);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 300, 3, 400, 1);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 100, 4, 0, 2);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 100, 5, 800, 3);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 800, 6, 150, 3);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         100, 1, TokenPosition(200), 1);
+  builder->AddDescriptor(RawPcDescriptors::kDeopt,
+                         200, 2, TokenPosition(300), 0);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         300, 3, TokenPosition(400), 1);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         100, 4, TokenPosition(0), 2);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         100, 5, TokenPosition(800), 3);
+  builder->AddDescriptor(RawPcDescriptors::kOther,
+                         800, 6, TokenPosition(150), 3);
 
   PcDescriptors& descriptors = PcDescriptors::Handle();
   descriptors ^= builder->FinalizePcDescriptors(0);
@@ -2919,31 +2935,31 @@
   PcDescriptors::Iterator iter(pc_descs, RawPcDescriptors::kAnyKind);
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(200, iter.TokenPos());
+  EXPECT_EQ(200, iter.TokenPos().value());
   EXPECT_EQ(1, iter.TryIndex());
   EXPECT_EQ(static_cast<uword>(100), iter.PcOffset());
   EXPECT_EQ(1, iter.DeoptId());
   EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(300, iter.TokenPos());
+  EXPECT_EQ(300, iter.TokenPos().value());
   EXPECT_EQ(RawPcDescriptors::kDeopt, iter.Kind());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(400, iter.TokenPos());
+  EXPECT_EQ(400, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(0, iter.TokenPos());
+  EXPECT_EQ(0, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(800, iter.TokenPos());
+  EXPECT_EQ(800, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
-  EXPECT_EQ(150, iter.TokenPos());
+  EXPECT_EQ(150, iter.TokenPos().value());
 
   EXPECT_EQ(3, iter.TryIndex());
   EXPECT_EQ(static_cast<uword>(800), iter.PcOffset());
-  EXPECT_EQ(150, iter.TokenPos());
+  EXPECT_EQ(150, iter.TokenPos().value());
   EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
 
   EXPECT_EQ(false, iter.MoveNext());
@@ -2963,12 +2979,12 @@
   const String& field_name = String::Handle(Symbols::New(name));
   const Field& field =
       Field::Handle(Field::New(field_name, true, false, false, true, cls,
-          Object::dynamic_type(), 0));
+          Object::dynamic_type(), TokenPosition::kMinSource));
   return field.raw();
 }
 
 
-TEST_CASE(ClassDictionaryIterator) {
+VM_TEST_CASE(ClassDictionaryIterator) {
   Class& ae66 = Class::ZoneHandle(CreateTestClass("Ae6/6"));
   Class& re44 = Class::ZoneHandle(CreateTestClass("Re4/4"));
   Field& ce68 = Field::ZoneHandle(CreateTestField("Ce6/8"));
@@ -3008,11 +3024,11 @@
                        is_external,
                        is_native,
                        cls,
-                       0);
+                       TokenPosition::kMinSource);
 }
 
 
-TEST_CASE(ICData) {
+VM_TEST_CASE(ICData) {
   Function& function = Function::Handle(GetDummyTarget("Bern"));
   const intptr_t id = 12;
   const intptr_t num_args_tested = 1;
@@ -3084,7 +3100,7 @@
 }
 
 
-TEST_CASE(SubtypeTestCache) {
+VM_TEST_CASE(SubtypeTestCache) {
   String& class_name = String::Handle(Symbols::New("EmptyClass"));
   Script& script = Script::Handle();
   const Class& empty_class =
@@ -3092,23 +3108,25 @@
   SubtypeTestCache& cache = SubtypeTestCache::Handle(SubtypeTestCache::New());
   EXPECT(!cache.IsNull());
   EXPECT_EQ(0, cache.NumberOfChecks());
+  const Object& class_id_or_fun = Object::Handle(Smi::New(empty_class.id()));
   const TypeArguments& targ_0 = TypeArguments::Handle(TypeArguments::New(2));
   const TypeArguments& targ_1 = TypeArguments::Handle(TypeArguments::New(3));
-  cache.AddCheck(empty_class.id(), targ_0, targ_1, Bool::True());
+  cache.AddCheck(class_id_or_fun, targ_0, targ_1, Bool::True());
   EXPECT_EQ(1, cache.NumberOfChecks());
-  intptr_t test_class_id = -1;
+  Object& test_class_id_or_fun = Object::Handle();
   TypeArguments& test_targ_0 = TypeArguments::Handle();
   TypeArguments& test_targ_1 = TypeArguments::Handle();
   Bool& test_result = Bool::Handle();
-  cache.GetCheck(0, &test_class_id, &test_targ_0, &test_targ_1, &test_result);
-  EXPECT_EQ(empty_class.id(), test_class_id);
+  cache.GetCheck(
+      0, &test_class_id_or_fun, &test_targ_0, &test_targ_1, &test_result);
+  EXPECT_EQ(class_id_or_fun.raw(), test_class_id_or_fun.raw());
   EXPECT_EQ(targ_0.raw(), test_targ_0.raw());
   EXPECT_EQ(targ_1.raw(), test_targ_1.raw());
   EXPECT_EQ(Bool::True().raw(), test_result.raw());
 }
 
 
-TEST_CASE(FieldTests) {
+VM_TEST_CASE(FieldTests) {
   const String& f = String::Handle(String::New("oneField"));
   const String& getter_f = String::Handle(Field::GetterName(f));
   const String& setter_f = String::Handle(Field::SetterName(f));
@@ -3131,7 +3149,7 @@
 bool EqualsIgnoringPrivate(const String& name, const String& private_name);
 
 
-TEST_CASE(EqualsIgnoringPrivate) {
+VM_TEST_CASE(EqualsIgnoringPrivate) {
   String& mangled_name = String::Handle();
   String& bare_name = String::Handle();
 
@@ -3264,7 +3282,7 @@
 }
 
 
-TEST_CASE(ArrayNew_Overflow_Crash) {
+VM_TEST_CASE(ArrayNew_Overflow_Crash) {
   Array::Handle(Array::New(Array::kMaxElements + 1));
 }
 
@@ -3330,7 +3348,7 @@
 }
 
 
-TEST_CASE(WeakProperty_PreserveCrossGen) {
+VM_TEST_CASE(WeakProperty_PreserveCrossGen) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
@@ -3442,7 +3460,7 @@
 }
 
 
-TEST_CASE(WeakProperty_PreserveRecurse) {
+VM_TEST_CASE(WeakProperty_PreserveRecurse) {
   // This used to end in an infinite recursion. Caused by scavenging the weak
   // property before scavenging the key.
   Isolate* isolate = Isolate::Current();
@@ -3465,7 +3483,7 @@
 }
 
 
-TEST_CASE(WeakProperty_PreserveOne_NewSpace) {
+VM_TEST_CASE(WeakProperty_PreserveOne_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   String& key = String::Handle();
@@ -3484,7 +3502,7 @@
 }
 
 
-TEST_CASE(WeakProperty_PreserveTwo_NewSpace) {
+VM_TEST_CASE(WeakProperty_PreserveTwo_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   String& key1 = String::Handle();
@@ -3513,7 +3531,7 @@
 }
 
 
-TEST_CASE(WeakProperty_PreserveTwoShared_NewSpace) {
+VM_TEST_CASE(WeakProperty_PreserveTwoShared_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
@@ -3540,7 +3558,7 @@
 }
 
 
-TEST_CASE(WeakProperty_PreserveOne_OldSpace) {
+VM_TEST_CASE(WeakProperty_PreserveOne_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   String& key = String::Handle();
@@ -3559,7 +3577,7 @@
 }
 
 
-TEST_CASE(WeakProperty_PreserveTwo_OldSpace) {
+VM_TEST_CASE(WeakProperty_PreserveTwo_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   String& key1 = String::Handle();
@@ -3588,7 +3606,7 @@
 }
 
 
-TEST_CASE(WeakProperty_PreserveTwoShared_OldSpace) {
+VM_TEST_CASE(WeakProperty_PreserveTwoShared_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
@@ -3615,7 +3633,7 @@
 }
 
 
-TEST_CASE(WeakProperty_ClearOne_NewSpace) {
+VM_TEST_CASE(WeakProperty_ClearOne_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
@@ -3636,7 +3654,7 @@
 }
 
 
-TEST_CASE(WeakProperty_ClearTwoShared_NewSpace) {
+VM_TEST_CASE(WeakProperty_ClearTwoShared_NewSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
@@ -3663,7 +3681,7 @@
 }
 
 
-TEST_CASE(WeakProperty_ClearOne_OldSpace) {
+VM_TEST_CASE(WeakProperty_ClearOne_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
@@ -3684,7 +3702,7 @@
 }
 
 
-TEST_CASE(WeakProperty_ClearTwoShared_OldSpace) {
+VM_TEST_CASE(WeakProperty_ClearTwoShared_OldSpace) {
   Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
@@ -3711,7 +3729,7 @@
 }
 
 
-TEST_CASE(MirrorReference) {
+VM_TEST_CASE(MirrorReference) {
   const MirrorReference& reference =
       MirrorReference::Handle(MirrorReference::New(Object::Handle()));
   Object& initial_referent = Object::Handle(reference.referent());
@@ -3769,7 +3787,7 @@
 }
 
 
-TEST_CASE(FindClosureIndex) {
+VM_TEST_CASE(FindClosureIndex) {
   // Allocate the class first.
   const String& class_name = String::Handle(Symbols::New("MyClass"));
   const Script& script = Script::Handle();
@@ -3780,13 +3798,15 @@
   Function& parent = Function::Handle();
   const String& parent_name = String::Handle(Symbols::New("foo_papa"));
   parent = Function::New(parent_name, RawFunction::kRegularFunction,
-                         false, false, false, false, false, cls, 0);
+                         false, false, false, false, false, cls,
+                         TokenPosition::kMinSource);
   functions.SetAt(0, parent);
   cls.SetFunctions(functions);
 
   Function& function = Function::Handle();
   const String& function_name = String::Handle(Symbols::New("foo"));
-  function = Function::NewClosureFunction(function_name, parent, 0);
+  function = Function::NewClosureFunction(function_name, parent,
+                                          TokenPosition::kMinSource);
   // Add closure function to class.
   iso->AddClosureFunction(function);
 
@@ -3805,7 +3825,7 @@
 }
 
 
-TEST_CASE(FindInvocationDispatcherFunctionIndex) {
+VM_TEST_CASE(FindInvocationDispatcherFunctionIndex) {
   const String& class_name = String::Handle(Symbols::New("MyClass"));
   const Script& script = Script::Handle();
   const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
@@ -3815,7 +3835,8 @@
   Function& parent = Function::Handle();
   const String& parent_name = String::Handle(Symbols::New("foo_papa"));
   parent = Function::New(parent_name, RawFunction::kRegularFunction,
-                         false, false, false, false, false, cls, 0);
+                         false, false, false, false, false, cls,
+                         TokenPosition::kMinSource);
   functions.SetAt(0, parent);
   cls.SetFunctions(functions);
   cls.Finalize();
@@ -4013,11 +4034,18 @@
   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());
 }
 
 
 TEST_CASE(FunctionWithBreakpointNotInlined) {
+  if (!FLAG_support_debugger) {
+    return;
+  }
   const char* kScriptChars =
       "class A {\n"
       "  a() {\n"
@@ -4056,7 +4084,7 @@
 }
 
 
-TEST_CASE(SpecialClassesHaveEmptyArrays) {
+VM_TEST_CASE(SpecialClassesHaveEmptyArrays) {
   ObjectStore* object_store = Isolate::Current()->object_store();
   Class& cls = Class::Handle();
   Object& array = Object::Handle();
@@ -4087,6 +4115,9 @@
 }
 
 
+#ifndef PRODUCT
+
+
 class ObjectAccumulator : public ObjectVisitor {
  public:
   explicit ObjectAccumulator(GrowableArray<Object*>* objects)
@@ -4111,7 +4142,7 @@
 };
 
 
-TEST_CASE(PrintJSON) {
+VM_TEST_CASE(PrintJSON) {
   Heap* heap = Isolate::Current()->heap();
   heap->CollectAllGarbage();
   GrowableArray<Object*> objects;
@@ -4125,7 +4156,7 @@
 }
 
 
-TEST_CASE(PrintJSONPrimitives) {
+VM_TEST_CASE(PrintJSONPrimitives) {
   char buffer[1024];
   Isolate* isolate = Isolate::Current();
 
@@ -4269,7 +4300,7 @@
         "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
         "\"name\":\"_OneByteString\",\"_vmName\":\"\"},"
         "\"kind\":\"String\","
-        "\"id\":\"\",\"valueAsString\":\"dw\"}",
+        "\"id\":\"\",\"length\":2,\"valueAsString\":\"dw\"}",
         buffer);
   }
   // Array reference
@@ -4415,6 +4446,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 TEST_CASE(InstanceEquality) {
   // Test that Instance::OperatorEquals can call a user-defined operator==.
   const char* kScript =
@@ -4590,7 +4624,7 @@
 }
 
 
-TEST_CASE(Symbols_FromConcatAll) {
+VM_TEST_CASE(Symbols_FromConcatAll) {
   {
     const String* data[3] = { &Symbols::FallThroughError(),
                               &Symbols::Dot(),
@@ -4662,7 +4696,7 @@
 };
 
 
-TEST_CASE(String_IdentifierPrettyName) {
+VM_TEST_CASE(String_ScrubName) {
   TestResult tests[] = {
     {"(dynamic, dynamic) => void", "(dynamic, dynamic) => void"},
     {"_List@915557746", "_List"},
@@ -4682,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_android.cc b/runtime/vm/os_android.cc
index 9dcd09e..5975735 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -21,9 +21,7 @@
 #include "platform/utils.h"
 #include "vm/code_observers.h"
 #include "vm/dart.h"
-#include "vm/debuginfo.h"
 #include "vm/isolate.h"
-#include "vm/vtune.h"
 #include "vm/zone.h"
 
 
@@ -31,12 +29,11 @@
 
 // Android CodeObservers.
 
-DEFINE_FLAG(bool, generate_gdb_symbols, false,
-    "Generate symbols of generated dart functions for debugging with GDB");
+#ifndef PRODUCT
+
 DEFINE_FLAG(bool, generate_perf_events_symbols, false,
     "Generate events symbols for profiling with perf");
 
-
 class PerfCodeObserver : public CodeObserver {
  public:
   PerfCodeObserver() : out_file_(NULL) {
@@ -83,41 +80,7 @@
   DISALLOW_COPY_AND_ASSIGN(PerfCodeObserver);
 };
 
-
-class GdbCodeObserver : public CodeObserver {
- public:
-  GdbCodeObserver() { }
-
-  virtual bool IsActive() const {
-    return FLAG_generate_gdb_symbols;
-  }
-
-  virtual void Notify(const char* name,
-                      uword base,
-                      uword prologue_offset,
-                      uword size,
-                      bool optimized) {
-    if (prologue_offset > 0) {
-      // In order to ensure that gdb sees the first instruction of a function
-      // as the prologue sequence we register two symbols for the cases when
-      // the prologue sequence is not the first instruction:
-      // <name>_entry is used for code preceding the prologue sequence.
-      // <name> for rest of the code (first instruction is prologue sequence).
-      char* pname = OS::SCreate(Thread::Current()->zone(),
-          "%s_%s", name, "entry");
-      DebugInfo::RegisterSection(pname, base, size);
-      DebugInfo::RegisterSection(name,
-                                 (base + prologue_offset),
-                                 (size - prologue_offset));
-    } else {
-      DebugInfo::RegisterSection(name, base, size);
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(GdbCodeObserver);
-};
-
+#endif  // !PRODUCT
 
 const char* OS::Name() {
   return "android";
@@ -427,15 +390,11 @@
 
 
 void OS::RegisterCodeObservers() {
+#ifndef PRODUCT
   if (FLAG_generate_perf_events_symbols) {
     CodeObservers::Register(new PerfCodeObserver);
   }
-  if (FLAG_generate_gdb_symbols) {
-    CodeObservers::Register(new GdbCodeObserver);
-  }
-#if defined(DART_VTUNE_SUPPORT)
-  CodeObservers::Register(new VTuneCodeObserver);
-#endif
+#endif  // !PRODUCT
 }
 
 
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index 244e9b7..d97a3a7 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -22,26 +22,21 @@
 #include "platform/utils.h"
 #include "vm/code_observers.h"
 #include "vm/dart.h"
-#include "vm/debuginfo.h"
+#include "vm/flags.h"
 #include "vm/isolate.h"
 #include "vm/lockers.h"
 #include "vm/os_thread.h"
-#include "vm/vtune.h"
 #include "vm/zone.h"
 
 
 namespace dart {
 
-// Linux CodeObservers.
+#ifndef PRODUCT
 
-DEFINE_FLAG(bool, generate_gdb_symbols, false,
-    "Generate symbols of generated dart functions for debugging with GDB");
 DEFINE_FLAG(bool, generate_perf_events_symbols, false,
     "Generate events symbols for profiling with perf");
-DEFINE_FLAG(bool, generate_perf_jitdump, false,
-    "Writes jitdump data for profiling with perf annotate");
 
-
+// Linux CodeObservers.
 class PerfCodeObserver : public CodeObserver {
  public:
   PerfCodeObserver() : out_file_(NULL) {
@@ -92,249 +87,7 @@
 };
 
 
-class GdbCodeObserver : public CodeObserver {
- public:
-  GdbCodeObserver() { }
-
-  virtual bool IsActive() const {
-    return FLAG_generate_gdb_symbols;
-  }
-
-  virtual void Notify(const char* name,
-                      uword base,
-                      uword prologue_offset,
-                      uword size,
-                      bool optimized) {
-    if (prologue_offset > 0) {
-      // In order to ensure that gdb sees the first instruction of a function
-      // as the prologue sequence we register two symbols for the cases when
-      // the prologue sequence is not the first instruction:
-      // <name>_entry is used for code preceding the prologue sequence.
-      // <name> for rest of the code (first instruction is prologue sequence).
-      char* pname = OS::SCreate(Thread::Current()->zone(),
-          "%s_%s", name, "entry");
-      DebugInfo::RegisterSection(pname, base, size);
-      DebugInfo::RegisterSection(name,
-                                 (base + prologue_offset),
-                                 (size - prologue_offset));
-    } else {
-      DebugInfo::RegisterSection(name, base, size);
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(GdbCodeObserver);
-};
-
-
-#define CLOCKFD 3
-#define FD_TO_CLOCKID(fd)       ((~(clockid_t) (fd) << 3) | CLOCKFD)  // NOLINT
-
-class JitdumpCodeObserver : public CodeObserver {
- public:
-  JitdumpCodeObserver() {
-    ASSERT(FLAG_generate_perf_jitdump);
-    out_file_ = NULL;
-    clock_fd_ = -1;
-    clock_id_ = kInvalidClockId;
-    code_sequence_ = 0;
-    Dart_FileOpenCallback file_open = Isolate::file_open_callback();
-    Dart_FileWriteCallback file_write = Isolate::file_write_callback();
-    Dart_FileCloseCallback file_close = Isolate::file_close_callback();
-    if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
-      return;
-    }
-    // The Jitdump code observer writes all jitted code into the file
-    // 'perf.jitdump' in the current working directory. We open the file once
-    // on initialization and close it when the VM is going down.
-    {
-      // Open the file.
-      const char* filename = "perf.jitdump";
-      out_file_ = (*file_open)(filename, true);
-      ASSERT(out_file_ != NULL);
-      // Write the jit dump header.
-      WriteHeader();
-    }
-    // perf uses an internal clock and because our output is merged with data
-    // collected by perf our timestamps must be consistent. Using
-    // the posix-clock-module (/dev/trace_clock) as our time source ensures
-    // we are consistent with the perf timestamps.
-    clock_id_ = kInvalidClockId;
-    clock_fd_ = open("/dev/trace_clock", O_RDONLY);
-    if (clock_fd_ >= 0) {
-      clock_id_ = FD_TO_CLOCKID(clock_fd_);
-    }
-  }
-
-  ~JitdumpCodeObserver() {
-    Dart_FileCloseCallback file_close = Isolate::file_close_callback();
-    if (file_close == NULL) {
-      return;
-    }
-    ASSERT(out_file_ != NULL);
-    (*file_close)(out_file_);
-    if (clock_fd_ >= 0) {
-      close(clock_fd_);
-    }
-  }
-
-  virtual bool IsActive() const {
-    return FLAG_generate_perf_jitdump && (out_file_ != NULL);
-  }
-
-  virtual void Notify(const char* name,
-                      uword base,
-                      uword prologue_offset,
-                      uword size,
-                      bool optimized) {
-    WriteCodeLoad(name, base, prologue_offset, size, optimized);
-  }
-
- private:
-  static const uint32_t kJitHeaderMagic = 0x4A695444;
-  static const uint32_t kJitHeaderMagicSw = 0x4454694A;
-  static const uint32_t kJitHeaderVersion = 0x1;
-  static const uint32_t kElfMachIA32 = 3;
-  static const uint32_t kElfMachX64 = 62;
-  static const uint32_t kElfMachARM = 40;
-  // TODO(zra): Find the right ARM64 constant.
-  static const uint32_t kElfMachARM64 = 40;
-  static const uint32_t kElfMachMIPS = 10;
-  static const int kInvalidClockId = -1;
-
-  struct jitheader {
-    uint32_t magic;   /* characters "jItD" */
-    uint32_t version; /* header version */
-    uint32_t total_size;  /* total size of header */
-    uint32_t elf_mach;  /* elf mach target */
-    uint32_t pad1;    /* reserved */
-    uint32_t pid;   /* JIT process id */
-    uint64_t timestamp; /* timestamp */
-  };
-
-  /* record prefix (mandatory in each record) */
-  struct jr_prefix {
-    uint32_t id;
-    uint32_t total_size;
-    uint64_t timestamp;
-  };
-
-  enum jit_record_type {
-    JIT_CODE_LOAD = 0,
-    /* JIT_CODE_MOVE = 1, */
-    /* JIT_CODE_DEBUG_INFO = 2, */
-    /* JIT_CODE_CLOSE = 3, */
-    JIT_CODE_MAX = 4,
-  };
-
-  struct jr_code_load {
-    struct jr_prefix prefix;
-    uint32_t pid;
-    uint32_t tid;
-    uint64_t vma;
-    uint64_t code_addr;
-    uint64_t code_size;
-    uint64_t code_index;
-  };
-
-  const char* GenerateCodeName(const char* name, bool optimized) {
-    const char* marker = optimized ? "*" : "";
-    return OS::SCreate(Thread::Current()->zone(), "%s%s", marker, name);
-  }
-
-  uint32_t GetElfMach() {
-#if defined(TARGET_ARCH_IA32)
-    return kElfMachIA32;
-#elif defined(TARGET_ARCH_X64)
-    return kElfMachX64;
-#elif defined(TARGET_ARCH_ARM)
-    return kElfMachARM;
-#elif defined(TARGET_ARCH_ARM64)
-    return kElfMachARM64;
-#elif defined(TARGET_ARCH_MIPS)
-    return kElfMachMIPS;
-#else
-#error Unknown architecture.
-#endif
-  }
-
-  pid_t gettid() {
-    // libc doesn't wrap the Linux-specific gettid system call.
-    // Note that this thread id is not the same as the posix thread id.
-    return syscall(SYS_gettid);
-  }
-
-  uint64_t GetKernelTimeNanos() {
-    if (clock_id_ != kInvalidClockId) {
-      struct timespec ts;
-      int r = clock_gettime(clock_id_, &ts);
-      ASSERT(r == 0);
-      uint64_t nanos = static_cast<uint64_t>(ts.tv_sec) *
-                       static_cast<uint64_t>(kNanosecondsPerSecond);
-      nanos += static_cast<uint64_t>(ts.tv_nsec);
-      return nanos;
-    } else {
-      return OS::GetCurrentTimeMicros() * kNanosecondsPerMicrosecond;
-    }
-  }
-
-  void WriteHeader() {
-    Dart_FileWriteCallback file_write = Isolate::file_write_callback();
-    ASSERT(file_write != NULL);
-    ASSERT(out_file_ != NULL);
-    jitheader header;
-    header.magic = kJitHeaderMagic;
-    header.version = kJitHeaderVersion;
-    header.total_size = sizeof(jitheader);
-    header.pad1 = 0x0;
-    header.elf_mach = GetElfMach();
-    header.pid = getpid();
-    header.timestamp = GetKernelTimeNanos();
-    {
-      MutexLocker ml(CodeObservers::mutex());
-      (*file_write)(&header, sizeof(header), out_file_);
-    }
-  }
-
-  void WriteCodeLoad(const char* name, uword base, uword prologue_offset,
-                     uword code_size, bool optimized) {
-    Dart_FileWriteCallback file_write = Isolate::file_write_callback();
-    ASSERT(file_write != NULL);
-    ASSERT(out_file_ != NULL);
-
-    const char* code_name = GenerateCodeName(name, optimized);
-    const intptr_t code_name_size = strlen(code_name) + 1;
-    uint8_t* code_pointer = reinterpret_cast<uint8_t*>(base);
-
-    jr_code_load code_load;
-    code_load.prefix.id = JIT_CODE_LOAD;
-    code_load.prefix.total_size =
-        sizeof(code_load) + code_name_size + code_size;
-    code_load.prefix.timestamp = GetKernelTimeNanos();
-    code_load.pid = getpid();
-    code_load.tid = gettid();
-    code_load.vma = 0x0;  //  Our addresses are absolute.
-    code_load.code_addr = base;
-    code_load.code_size = code_size;
-
-    {
-      MutexLocker ml(CodeObservers::mutex());
-      // Set this field under the index.
-      code_load.code_index = code_sequence_++;
-      // Write structures.
-      (*file_write)(&code_load, sizeof(code_load), out_file_);
-      (*file_write)(code_name, code_name_size, out_file_);
-      (*file_write)(code_pointer, code_size, out_file_);
-    }
-  }
-
-  void* out_file_;
-  int clock_fd_;
-  int clock_id_;
-  uint64_t code_sequence_;
-  DISALLOW_COPY_AND_ASSIGN(JitdumpCodeObserver);
-};
-
+#endif  // !PRODUCT
 
 const char* OS::Name() {
   return "linux";
@@ -617,18 +370,11 @@
 
 
 void OS::RegisterCodeObservers() {
+#ifndef PRODUCT
   if (FLAG_generate_perf_events_symbols) {
     CodeObservers::Register(new PerfCodeObserver);
   }
-  if (FLAG_generate_gdb_symbols) {
-    CodeObservers::Register(new GdbCodeObserver);
-  }
-  if (FLAG_generate_perf_jitdump) {
-    CodeObservers::Register(new JitdumpCodeObserver);
-  }
-#if defined(DART_VTUNE_SUPPORT)
-  CodeObservers::Register(new VTuneCodeObserver);
-#endif
+#endif  // !PRODUCT
 }
 
 
diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc
index 0dcd506..0303161 100644
--- a/runtime/vm/os_thread.cc
+++ b/runtime/vm/os_thread.cc
@@ -51,8 +51,10 @@
   RemoveThreadFromList(this);
   delete log_;
   log_ = NULL;
-  if (Timeline::recorder() != NULL) {
-    Timeline::recorder()->FinishBlock(timeline_block_);
+  if (FLAG_support_timeline) {
+    if (Timeline::recorder() != NULL) {
+      Timeline::recorder()->FinishBlock(timeline_block_);
+    }
   }
   timeline_block_ = NULL;
   delete timeline_block_lock_;
@@ -70,7 +72,7 @@
   ASSERT(OSThread::Current() == this);
   uintptr_t old =
       AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_);
-  if (old == 1) {
+  if (FLAG_profiler && (old == 1)) {
     // We just decremented from 1 to 0.
     // Make sure the thread interrupter is awake.
     ThreadInterrupter::WakeUp();
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 84f11b6a..2ca6a7c 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -237,9 +237,9 @@
   static OSThread* thread_list_head_;
   static bool creation_enabled_;
 
+  friend class Isolate;  // to access set_thread(Thread*).
   friend class OSThreadIterator;
   friend class ThreadInterrupterWin;
-  friend class ThreadRegistry;
 };
 
 
@@ -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/os_win.cc b/runtime/vm/os_win.cc
index 603ade6..2548a4c 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -14,7 +14,6 @@
 #include "platform/utils.h"
 #include "platform/assert.h"
 #include "vm/os_thread.h"
-#include "vm/vtune.h"
 #include "vm/zone.h"
 
 namespace dart {
@@ -365,9 +364,6 @@
 
 
 void OS::RegisterCodeObservers() {
-#if defined(DART_VTUNE_SUPPORT)
-  CodeObservers::Register(new VTuneCodeObserver);
-#endif
 }
 
 
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index 5d5df0e..177b091 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -11,7 +11,7 @@
 #include "vm/lockers.h"
 #include "vm/object.h"
 #include "vm/os_thread.h"
-#include "vm/thread_registry.h"
+#include "vm/safepoint.h"
 #include "vm/verified_memory.h"
 #include "vm/virtual_memory.h"
 
@@ -29,35 +29,30 @@
             "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) {
   ASSERT(memory != NULL);
   ASSERT(memory->size() > VirtualMemory::PageSize());
   bool is_executable = (type == kExecutable);
-  if (!memory->Commit(is_executable)) {
+  // Create the new page executable (RWX) only if we're not in W^X mode
+  bool create_executable = !FLAG_write_protect_code && is_executable;
+  if (!memory->Commit(create_executable)) {
     return NULL;
   }
   HeapPage* result = reinterpret_cast<HeapPage*>(memory->address());
   ASSERT(result != NULL);
   result->memory_ = memory;
   result->next_ = NULL;
-  result->executable_ = is_executable;
+  result->type_ = type;
   return result;
 }
 
@@ -130,7 +125,7 @@
 void HeapPage::WriteProtect(bool read_only) {
   VirtualMemory::Protection prot;
   if (read_only) {
-    if (executable_) {
+    if (type_ == kExecutable) {
       prot = VirtualMemory::kReadExecute;
     } else {
       prot = VirtualMemory::kReadOnly;
@@ -344,7 +339,8 @@
     // Start of the newly allocated page is the allocated object.
     result = page->object_start();
     // Note: usage_.capacity_in_words is increased by AllocatePage.
-    usage_.used_in_words += size >> kWordSizeLog2;
+    AtomicOperations::IncrementBy(&(usage_.used_in_words),
+                                  (size >> kWordSizeLog2));
     // Enqueue the remainder in the free list.
     uword free_start = result + size;
     intptr_t free_size = page->object_end() - free_start;
@@ -381,7 +377,8 @@
       result = TryAllocateInFreshPage(size, type, growth_policy, is_locked);
       // usage_ is updated by the call above.
     } else {
-      usage_.used_in_words += size >> kWordSizeLog2;
+      AtomicOperations::IncrementBy(&(usage_.used_in_words),
+                                    (size >> kWordSizeLog2));
     }
   } else {
     // Large page allocation.
@@ -400,21 +397,19 @@
       if (page != NULL) {
         result = page->object_start();
         // Note: usage_.capacity_in_words is increased by AllocateLargePage.
-        usage_.used_in_words += size >> kWordSizeLog2;
+        AtomicOperations::IncrementBy(&(usage_.used_in_words),
+                                      (size >> kWordSizeLog2));
       }
     }
   }
-  if (result != 0) {
 #ifdef DEBUG
+  if (result != 0) {
     // A successful allocation should increase usage_.
     ASSERT(usage_before.used_in_words < usage_.used_in_words);
-#endif
-  } else {
-#ifdef DEBUG
-    // A failed allocation should not change used_in_words.
-    ASSERT(usage_before.used_in_words == usage_.used_in_words);
-#endif
   }
+  // Note we cannot assert that a failed allocation should not change
+  // used_in_words as another thread could have changed used_in_words.
+#endif
   ASSERT((result & kObjectAlignmentMask) == kOldObjectAlignmentOffset);
   return result;
 }
@@ -432,14 +427,14 @@
 
 void PageSpace::AllocateExternal(intptr_t size) {
   intptr_t size_in_words = size >> kWordSizeLog2;
-  usage_.external_in_words += size_in_words;
+  AtomicOperations::IncrementBy(&(usage_.external_in_words), size_in_words);
   // TODO(koda): Control growth.
 }
 
 
 void PageSpace::FreeExternal(intptr_t size) {
   intptr_t size_in_words = size >> kWordSizeLog2;
-  usage_.external_in_words -= size_in_words;
+  AtomicOperations::DecrementBy(&(usage_.external_in_words), size_in_words);
 }
 
 
@@ -663,7 +658,9 @@
     AbandonBumpAllocation();
   }
   for (ExclusivePageIterator it(this); !it.Done(); it.Advance()) {
-    if ((it.page()->type() != HeapPage::kExecutable) || include_code_pages) {
+    HeapPage::PageType page_type = it.page()->type();
+    if ((page_type != HeapPage::kReadOnlyData) &&
+        ((page_type != HeapPage::kExecutable) || include_code_pages)) {
       it.page()->WriteProtect(read_only);
     }
   }
@@ -671,6 +668,9 @@
 
 
 void PageSpace::PrintToJSONObject(JSONObject* object) const {
+  if (!FLAG_support_service) {
+    return;
+  }
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
   JSONObject space(object, "old");
@@ -711,6 +711,9 @@
 
 void PageSpace::PrintHeapMapToJSONStream(
     Isolate* isolate, JSONStream* stream) const {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject heap_map(stream);
   heap_map.AddProperty("type", "HeapMap");
   heap_map.AddProperty("freeClassId",
@@ -791,6 +794,7 @@
 
 
 void PageSpace::MarkSweep(bool invoke_api_callbacks) {
+  Thread* thread = Thread::Current();
   Isolate* isolate = heap_->isolate();
   ASSERT(isolate == Isolate::Current());
 
@@ -798,114 +802,95 @@
   {
     MonitorLocker locker(tasks_lock());
     while (tasks() > 0) {
-      locker.Wait();
+      locker.WaitWithSafepointCheck(thread);
     }
     set_tasks(1);
   }
-  // Ensure that all threads for this isolate are at a safepoint (either stopped
-  // or in native code). If two threads are racing at this point, the loser
-  // will continue with its collection after waiting for the winner to complete.
-  // TODO(koda): Consider moving SafepointThreads into allocation failure/retry
-  // logic to avoid needless collections.
-  isolate->thread_registry()->SafepointThreads();
-
-  // Perform various cleanup that relies on no tasks interfering.
-  isolate->class_table()->FreeOldTables();
-
-  NoSafepointScope no_safepoints;
-
-  if (FLAG_print_free_list_before_gc) {
-    OS::Print("Data Freelist (before GC):\n");
-    freelist_[HeapPage::kData].Print();
-    OS::Print("Executable Freelist (before GC):\n");
-    freelist_[HeapPage::kExecutable].Print();
-  }
-
-  if (FLAG_verify_before_gc) {
-    OS::PrintErr("Verifying before marking...");
-    heap_->VerifyGC();
-    OS::PrintErr(" done.\n");
-  }
-
-  const int64_t start = OS::GetCurrentTimeMicros();
-
-  // Make code pages writable.
-  WriteProtectCode(false);
-
-  // Save old value before GCMarker visits the weak persistent handles.
-  SpaceUsage usage_before = GetCurrentUsage();
-
-  // Mark all reachable old-gen objects.
-  bool collect_code = FLAG_collect_code && ShouldCollectCode();
-  GCMarker marker(heap_);
-  marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code);
-  usage_.used_in_words = marker.marked_words();
-
-  int64_t mid1 = OS::GetCurrentTimeMicros();
-
-  // Abandon the remainder of the bump allocation block.
-  AbandonBumpAllocation();
-  // Reset the freelists and setup sweeping.
-  freelist_[HeapPage::kData].Reset();
-  freelist_[HeapPage::kExecutable].Reset();
-
-  int64_t mid2 = OS::GetCurrentTimeMicros();
-  int64_t mid3 = 0;
-
+  // Ensure that all threads for this isolate are at a safepoint (either
+  // stopped or in native code). We have guards around Newgen GC and oldgen GC
+  // to ensure that if two threads are racing to collect at the same time the
+  // loser skips collection and goes straight to allocation.
   {
+    SafepointOperationScope safepoint_scope(thread);
+
+    // Perform various cleanup that relies on no tasks interfering.
+    isolate->class_table()->FreeOldTables();
+
+    NoSafepointScope no_safepoints;
+
+    if (FLAG_print_free_list_before_gc) {
+      OS::Print("Data Freelist (before GC):\n");
+      freelist_[HeapPage::kData].Print();
+      OS::Print("Executable Freelist (before GC):\n");
+      freelist_[HeapPage::kExecutable].Print();
+    }
+
     if (FLAG_verify_before_gc) {
-      OS::PrintErr("Verifying before sweeping...");
-      heap_->VerifyGC(kAllowMarked);
+      OS::PrintErr("Verifying before marking...");
+      heap_->VerifyGC();
       OS::PrintErr(" done.\n");
     }
-    GCSweeper sweeper;
 
-    // During stop-the-world phases we should use bulk lock when adding elements
-    // to the free list.
-    MutexLocker mld(freelist_[HeapPage::kData].mutex());
-    MutexLocker mle(freelist_[HeapPage::kExecutable].mutex());
+    const int64_t start = OS::GetCurrentTimeMicros();
 
-    // Large and executable pages are always swept immediately.
-    HeapPage* prev_page = NULL;
-    HeapPage* page = large_pages_;
-    while (page != NULL) {
-      HeapPage* next_page = page->next();
-      const intptr_t words_to_end = sweeper.SweepLargePage(page);
-      if (words_to_end == 0) {
-        FreeLargePage(page, prev_page);
-      } else {
-        TruncateLargePage(page, words_to_end << kWordSizeLog2);
-        prev_page = page;
+    // Make code pages writable.
+    WriteProtectCode(false);
+
+    // Save old value before GCMarker visits the weak persistent handles.
+    SpaceUsage usage_before = GetCurrentUsage();
+
+    // Mark all reachable old-gen objects.
+    bool collect_code = FLAG_collect_code && ShouldCollectCode();
+    GCMarker marker(heap_);
+    marker.MarkObjects(isolate, this, invoke_api_callbacks, collect_code);
+    usage_.used_in_words = marker.marked_words();
+
+    int64_t mid1 = OS::GetCurrentTimeMicros();
+
+    // Abandon the remainder of the bump allocation block.
+    AbandonBumpAllocation();
+    // Reset the freelists and setup sweeping.
+    freelist_[HeapPage::kData].Reset();
+    freelist_[HeapPage::kExecutable].Reset();
+
+    int64_t mid2 = OS::GetCurrentTimeMicros();
+    int64_t mid3 = 0;
+
+    {
+      if (FLAG_verify_before_gc) {
+        OS::PrintErr("Verifying before sweeping...");
+        heap_->VerifyGC(kAllowMarked);
+        OS::PrintErr(" done.\n");
       }
-      // Advance to the next page.
-      page = next_page;
-    }
+      GCSweeper sweeper;
 
-    prev_page = NULL;
-    page = exec_pages_;
-    FreeList* freelist = &freelist_[HeapPage::kExecutable];
-    while (page != NULL) {
-      HeapPage* next_page = page->next();
-      bool page_in_use = sweeper.SweepPage(page, freelist, true);
-      if (page_in_use) {
-        prev_page = page;
-      } else {
-        FreePage(page, prev_page);
-      }
-      // Advance to the next page.
-      page = next_page;
-    }
+      // During stop-the-world phases we should use bulk lock when adding
+      // elements to the free list.
+      MutexLocker mld(freelist_[HeapPage::kData].mutex());
+      MutexLocker mle(freelist_[HeapPage::kExecutable].mutex());
 
-    mid3 = OS::GetCurrentTimeMicros();
-
-    if (!FLAG_concurrent_sweep) {
-      // Sweep all regular sized pages now.
-      prev_page = NULL;
-      page = pages_;
+      // Large and executable pages are always swept immediately.
+      HeapPage* prev_page = NULL;
+      HeapPage* page = large_pages_;
       while (page != NULL) {
         HeapPage* next_page = page->next();
-        bool page_in_use = sweeper.SweepPage(
-            page, &freelist_[page->type()], true);
+        const intptr_t words_to_end = sweeper.SweepLargePage(page);
+        if (words_to_end == 0) {
+          FreeLargePage(page, prev_page);
+        } else {
+          TruncateLargePage(page, words_to_end << kWordSizeLog2);
+          prev_page = page;
+        }
+        // Advance to the next page.
+        page = next_page;
+      }
+
+      prev_page = NULL;
+      page = exec_pages_;
+      FreeList* freelist = &freelist_[HeapPage::kExecutable];
+      while (page != NULL) {
+        HeapPage* next_page = page->next();
+        bool page_in_use = sweeper.SweepPage(page, freelist, true);
         if (page_in_use) {
           prev_page = page;
         } else {
@@ -914,47 +899,65 @@
         // Advance to the next page.
         page = next_page;
       }
-      if (FLAG_verify_after_gc) {
-        OS::PrintErr("Verifying after sweeping...");
-        heap_->VerifyGC(kForbidMarked);
-        OS::PrintErr(" done.\n");
+
+      mid3 = OS::GetCurrentTimeMicros();
+
+      if (!FLAG_concurrent_sweep) {
+        // Sweep all regular sized pages now.
+        prev_page = NULL;
+        page = pages_;
+        while (page != NULL) {
+          HeapPage* next_page = page->next();
+          bool page_in_use = sweeper.SweepPage(
+              page, &freelist_[page->type()], true);
+          if (page_in_use) {
+            prev_page = page;
+          } else {
+            FreePage(page, prev_page);
+          }
+          // Advance to the next page.
+          page = next_page;
+        }
+        if (FLAG_verify_after_gc) {
+          OS::PrintErr("Verifying after sweeping...");
+          heap_->VerifyGC(kForbidMarked);
+          OS::PrintErr(" done.\n");
+        }
+      } else {
+        // Start the concurrent sweeper task now.
+        GCSweeper::SweepConcurrent(
+            isolate, pages_, pages_tail_, &freelist_[HeapPage::kData]);
       }
-    } else {
-      // Start the concurrent sweeper task now.
-      GCSweeper::SweepConcurrent(
-          isolate, pages_, pages_tail_, &freelist_[HeapPage::kData]);
+    }
+
+    // Make code pages read-only.
+    WriteProtectCode(true);
+
+    int64_t end = OS::GetCurrentTimeMicros();
+
+    // Record signals for growth control. Include size of external allocations.
+    page_space_controller_.EvaluateGarbageCollection(usage_before,
+                                                     GetCurrentUsage(),
+                                                     start, end);
+
+    heap_->RecordTime(kMarkObjects, mid1 - start);
+    heap_->RecordTime(kResetFreeLists, mid2 - mid1);
+    heap_->RecordTime(kSweepPages, mid3 - mid2);
+    heap_->RecordTime(kSweepLargePages, end - mid3);
+
+    if (FLAG_print_free_list_after_gc) {
+      OS::Print("Data Freelist (after GC):\n");
+      freelist_[HeapPage::kData].Print();
+      OS::Print("Executable Freelist (after GC):\n");
+      freelist_[HeapPage::kExecutable].Print();
+    }
+
+    UpdateMaxUsed();
+    if (heap_ != NULL) {
+      heap_->UpdateGlobalMaxUsed();
     }
   }
 
-  // Make code pages read-only.
-  WriteProtectCode(true);
-
-  int64_t end = OS::GetCurrentTimeMicros();
-
-  // Record signals for growth control. Include size of external allocations.
-  page_space_controller_.EvaluateGarbageCollection(usage_before,
-                                                   GetCurrentUsage(),
-                                                   start, end);
-
-  heap_->RecordTime(kMarkObjects, mid1 - start);
-  heap_->RecordTime(kResetFreeLists, mid2 - mid1);
-  heap_->RecordTime(kSweepPages, mid3 - mid2);
-  heap_->RecordTime(kSweepLargePages, end - mid3);
-
-  if (FLAG_print_free_list_after_gc) {
-    OS::Print("Data Freelist (after GC):\n");
-    freelist_[HeapPage::kData].Print();
-    OS::Print("Executable Freelist (after GC):\n");
-    freelist_[HeapPage::kExecutable].Print();
-  }
-
-  UpdateMaxUsed();
-  if (heap_ != NULL) {
-    heap_->UpdateGlobalMaxUsed();
-  }
-
-  isolate->thread_registry()->ResumeAllThreads();
-
   // Done, reset the task count.
   {
     MonitorLocker ml(tasks_lock());
@@ -1005,7 +1008,8 @@
   ASSERT(remaining >= size);
   uword result = bump_top_;
   bump_top_ += size;
-  usage_.used_in_words += size >> kWordSizeLog2;
+  AtomicOperations::IncrementBy(&(usage_.used_in_words),
+                                (size >> kWordSizeLog2));
   // Note: Remaining block is unwalkable until MakeIterable is called.
 #ifdef DEBUG
   if (bump_top_ < bump_end_) {
@@ -1035,7 +1039,8 @@
   FreeList* freelist = &freelist_[HeapPage::kData];
   uword result = freelist->TryAllocateSmallLocked(size);
   if (result != 0) {
-    usage_.used_in_words += size >> kWordSizeLog2;
+    AtomicOperations::IncrementBy(&(usage_.used_in_words),
+                                  (size >> kWordSizeLog2));
     return result;
   }
   result = TryAllocateDataBumpLocked(size, growth_policy);
@@ -1061,7 +1066,9 @@
 }
 
 
-void PageSpace::SetupInstructionsSnapshotPage(void* pointer, uword size) {
+void PageSpace::SetupExternalPage(void* pointer,
+                                  uword size,
+                                  bool is_executable) {
   // Setup a HeapPage so precompiled Instructions can be traversed.
   // Instructions are contiguous at [pointer, pointer + size). HeapPage
   // expects to find objects at [memory->start() + ObjectStartOffset,
@@ -1070,23 +1077,31 @@
   pointer = reinterpret_cast<void*>(reinterpret_cast<uword>(pointer) - offset);
   size += offset;
 
-  ASSERT(Utils::IsAligned(pointer, OS::PreferredCodeAlignment()));
-
-  VirtualMemory* memory = VirtualMemory::ForInstructionsSnapshot(pointer, size);
+  VirtualMemory* memory = VirtualMemory::ForExternalPage(pointer, size);
   ASSERT(memory != NULL);
   HeapPage* page = reinterpret_cast<HeapPage*>(malloc(sizeof(HeapPage)));
   page->memory_ = memory;
   page->next_ = NULL;
   page->object_end_ = memory->end();
-  page->executable_ = true;
 
   MutexLocker ml(pages_lock_);
-  if (exec_pages_ == NULL) {
-    exec_pages_ = page;
+  HeapPage** first, **tail;
+  if (is_executable) {
+    ASSERT(Utils::IsAligned(pointer, OS::PreferredCodeAlignment()));
+    page->type_ = HeapPage::kExecutable;
+    first = &exec_pages_;
+    tail = &exec_pages_tail_;
   } else {
-    exec_pages_tail_->set_next(page);
+    page->type_ = HeapPage::kReadOnlyData;
+    first = &pages_;
+    tail = &pages_tail_;
   }
-  exec_pages_tail_ = page;
+  if (*first == NULL) {
+    *first = page;
+  } else {
+    (*tail)->set_next(page);
+  }
+  (*tail) = page;
 }
 
 
diff --git a/runtime/vm/pages.h b/runtime/vm/pages.h
index 17d1674..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);
@@ -31,6 +30,7 @@
   enum PageType {
     kData = 0,
     kExecutable,
+    kReadOnlyData,
     kNumPageTypes
   };
 
@@ -49,7 +49,7 @@
   }
 
   PageType type() const {
-    return executable_ ? kExecutable : kData;
+    return type_;
   }
 
   void VisitObjects(ObjectVisitor* visitor) const;
@@ -80,7 +80,7 @@
   VirtualMemory* memory_;
   HeapPage* next_;
   uword object_end_;
-  bool executable_;
+  PageType type_;
 
   friend class PageSpace;
 
@@ -346,7 +346,7 @@
   static intptr_t top_offset() { return OFFSET_OF(PageSpace, bump_top_); }
   static intptr_t end_offset() { return OFFSET_OF(PageSpace, bump_end_); }
 
-  void SetupInstructionsSnapshotPage(void* pointer, uword size);
+  void SetupExternalPage(void* pointer, uword size, bool is_executable);
 
  private:
   // Ids for time and data records in Heap::GCStats.
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 47cb001..78ca6a5 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -5,7 +5,7 @@
 #include "vm/parser.h"
 #include "vm/flags.h"
 
-#ifndef DART_PRECOMPILED
+#ifndef DART_PRECOMPILED_RUNTIME
 
 #include "lib/invocation_mirror.h"
 #include "platform/utils.h"
@@ -28,8 +28,8 @@
 #include "vm/object_store.h"
 #include "vm/os.h"
 #include "vm/regexp_assembler.h"
-#include "vm/report.h"
 #include "vm/resolver.h"
+#include "vm/safepoint.h"
 #include "vm/scanner.h"
 #include "vm/scopes.h"
 #include "vm/stack_frame.h"
@@ -41,13 +41,8 @@
 namespace dart {
 
 DEFINE_FLAG(bool, enable_debug_break, false, "Allow use of break \"message\".");
-DEFINE_FLAG(bool, enable_mirrors, true,
-    "Disable to make importing dart:mirrors an error.");
-DEFINE_FLAG(bool, load_deferred_eagerly, false,
-    "Load deferred libraries eagerly.");
 DEFINE_FLAG(bool, 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,
@@ -55,22 +50,21 @@
 DEFINE_FLAG(bool, await_is_keyword, false,
     "await and yield are treated as proper keywords in synchronous code.");
 
-DECLARE_FLAG(bool, lazy_dispatchers);
-DECLARE_FLAG(bool, load_deferred_eagerly);
 DECLARE_FLAG(bool, profile_vm);
-DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
-DECLARE_FLAG(bool, warn_on_javascript_compatibility);
+DECLARE_FLAG(bool, trace_service);
 
 // Quick access to the current thread, isolate and zone.
 #define T (thread())
 #define I (isolate())
 #define Z (zone())
 
+// Quick synthetic token position.
+#define ST(token_pos) ((token_pos).ToSynthetic())
 
 #if defined(DEBUG)
 class TraceParser : public ValueObject {
  public:
-  TraceParser(intptr_t token_pos,
+  TraceParser(TokenPosition token_pos,
               const Script& script,
               intptr_t* trace_indent,
               const char* msg) {
@@ -82,7 +76,7 @@
         script.GetTokenLocation(token_pos, &line, &column);
         PrintIndent();
         OS::Print("%s (line %" Pd ", col %" Pd ", token %" Pd ")\n",
-                  msg, line, column, token_pos);
+                  msg, line, column, token_pos.value());
       }
       (*indent_)++;
     }
@@ -125,6 +119,27 @@
 };
 
 
+class RecursionChecker : public ValueObject {
+ public:
+  explicit RecursionChecker(Parser* p) : parser_(p) {
+    parser_->recursion_counter_++;
+    // No need to check the stack unless the parser is in an unusually deep
+    // recurive state. Thus, we omit the more expensive stack checks in
+    // the common case.
+    const int kMaxUncheckedDepth = 100;  // Somewhat arbitrary.
+    if (parser_->recursion_counter_ > kMaxUncheckedDepth) {
+      parser_->CheckStack();
+    }
+  }
+  ~RecursionChecker() {
+    parser_->recursion_counter_--;
+  }
+
+ private:
+  Parser* parser_;
+};
+
+
 static RawTypeArguments* NewTypeArguments(
     const GrowableArray<AbstractType*>& objs) {
   const TypeArguments& a =
@@ -138,6 +153,20 @@
 }
 
 
+void ParsedFunction::AddToGuardedFields(const Field* field) const {
+  if ((field->guarded_cid() == kDynamicCid) ||
+      (field->guarded_cid() == kIllegalCid)) {
+    return;
+  }
+  for (intptr_t j = 0; j < guarded_fields_->length(); j++) {
+    if ((*guarded_fields_)[j]->raw() == field->raw()) {
+      return;
+    }
+  }
+  guarded_fields_->Add(&Field::ZoneHandle(Z, field->Original()));
+}
+
+
 LocalVariable* ParsedFunction::EnsureExpressionTemp() {
   if (!has_expression_temp_var()) {
     LocalVariable* temp =
@@ -239,8 +268,11 @@
 
 struct CatchParamDesc {
   CatchParamDesc()
-      : token_pos(Scanner::kNoSourcePos), type(NULL), name(NULL), var(NULL) { }
-  intptr_t token_pos;
+      : token_pos(TokenPosition::kNoSource),
+        type(NULL),
+        name(NULL),
+        var(NULL) { }
+  TokenPosition token_pos;
   const AbstractType* type;
   const String* name;
   LocalVariable* var;
@@ -326,7 +358,9 @@
 
 
 // For parsing a compilation unit.
-Parser::Parser(const Script& script, const Library& library, intptr_t token_pos)
+Parser::Parser(const Script& script,
+               const Library& library,
+               TokenPosition token_pos)
     : isolate_(Thread::Current()->isolate()),
       thread_(Thread::Current()),
       script_(Script::Handle(zone(), script.raw())),
@@ -347,7 +381,8 @@
       last_used_try_index_(0),
       unregister_pending_function_(false),
       async_temp_scope_(NULL),
-      trace_indent_(0) {
+      trace_indent_(0),
+      recursion_counter_(0) {
   ASSERT(tokens_iterator_.IsValid());
   ASSERT(!library.IsNull());
 }
@@ -356,12 +391,12 @@
 // For parsing a function.
 Parser::Parser(const Script& script,
                ParsedFunction* parsed_function,
-               intptr_t token_position)
+               TokenPosition token_pos)
     : isolate_(Thread::Current()->isolate()),
       thread_(Thread::Current()),
       script_(Script::Handle(zone(), script.raw())),
       tokens_iterator_(TokenStream::Handle(zone(), script.tokens()),
-                       token_position),
+                       token_pos),
       token_kind_(Token::kILLEGAL),
       current_block_(NULL),
       is_top_level_(false),
@@ -381,7 +416,8 @@
       last_used_try_index_(0),
       unregister_pending_function_(false),
       async_temp_scope_(NULL),
-      trace_indent_(0) {
+      trace_indent_(0),
+      recursion_counter_(0) {
   ASSERT(tokens_iterator_.IsValid());
   ASSERT(!current_function().IsNull());
   EnsureExpressionTemp();
@@ -392,6 +428,7 @@
   if (unregister_pending_function_) {
     const GrowableObjectArray& pending_functions =
         GrowableObjectArray::Handle(T->pending_functions());
+    ASSERT(!pending_functions.IsNull());
     ASSERT(pending_functions.Length() > 0);
     ASSERT(pending_functions.At(pending_functions.Length() - 1) ==
         current_function().raw());
@@ -410,7 +447,7 @@
 }
 
 
-void Parser::SetScript(const Script& script, intptr_t token_pos) {
+void Parser::SetScript(const Script& script, TokenPosition token_pos) {
   script_ = script.raw();
   tokens_iterator_.SetStream(
       TokenStream::Handle(Z, script.tokens()), token_pos);
@@ -446,9 +483,10 @@
 }
 
 
-void Parser::SetPosition(intptr_t position) {
+void Parser::SetPosition(TokenPosition position) {
   tokens_iterator_.SetCurrentPosition(position);
   token_kind_ = Token::kILLEGAL;
+  prev_token_pos_ = position;
 }
 
 
@@ -458,6 +496,7 @@
   ASSERT(thread->long_jump_base()->IsSafeToJump());
   CSTAT_TIMER_SCOPE(thread, parser_timer);
   VMTagScope tagScope(thread, VMTag::kCompileTopLevelTagId);
+#ifndef PRODUCT
   TimelineDurationScope tds(thread,
                             thread->isolate()->GetCompilerStream(),
                             "CompileTopLevel");
@@ -465,8 +504,9 @@
     tds.SetNumArguments(1);
     tds.CopyArgument(0, "script", String::Handle(script.url()).ToCString());
   }
+#endif
 
-  Parser parser(script, library, 0);
+  Parser parser(script, library, TokenPosition::kMinSource);
   parser.ParseTopLevel();
 }
 
@@ -503,14 +543,6 @@
   literal_token_ ^= tokens_iterator_.CurrentToken();
   ASSERT(literal_token_.kind() == Token::kINTEGER);
   RawInteger* ri = Integer::RawCast(literal_token_.value());
-  if (FLAG_throw_on_javascript_int_overflow) {
-    const Integer& i = Integer::Handle(Z, ri);
-    if (i.CheckJavascriptIntegerOverflow()) {
-      ReportError(TokenPos(),
-                  "Integer literal does not fit in a Javascript integer: %s.",
-                  i.ToCString());
-    }
-  }
   return ri;
 }
 
@@ -518,7 +550,7 @@
 struct ParamDesc {
   ParamDesc()
       : type(NULL),
-        name_pos(Scanner::kNoSourcePos),
+        name_pos(TokenPosition::kNoSource),
         name(NULL),
         default_value(NULL),
         metadata(NULL),
@@ -527,7 +559,7 @@
         is_field_initializer(false),
         has_explicit_type(false) { }
   const AbstractType* type;
-  intptr_t name_pos;
+  TokenPosition name_pos;
   const String* name;
   const Instance* default_value;  // NULL if not an optional parameter.
   const Object* metadata;  // NULL if no metadata or metadata not evaluated.
@@ -555,7 +587,7 @@
     this->parameters = new ZoneGrowableArray<ParamDesc>();
   }
 
-  void AddFinalParameter(intptr_t name_pos,
+  void AddFinalParameter(TokenPosition name_pos,
                          const String* name,
                          const AbstractType* type) {
     this->num_fixed_parameters++;
@@ -567,7 +599,8 @@
     this->parameters->Add(param);
   }
 
-  void AddReceiver(const AbstractType* receiver_type, intptr_t token_pos) {
+  void AddReceiver(const AbstractType* receiver_type,
+                   TokenPosition token_pos) {
     ASSERT(this->parameters->is_empty());
     AddFinalParameter(token_pos, &Symbols::This(), receiver_type);
   }
@@ -623,10 +656,10 @@
     has_factory = false;
     has_operator = false;
     has_native = false;
-    metadata_pos = Scanner::kNoSourcePos;
+    metadata_pos = TokenPosition::kNoSource;
     operator_token = Token::kILLEGAL;
     type = NULL;
-    name_pos = Scanner::kNoSourcePos;
+    name_pos = TokenPosition::kNoSource;
     name = NULL;
     redirect_name = NULL;
     dict_name = NULL;
@@ -676,11 +709,11 @@
   bool has_factory;
   bool has_operator;
   bool has_native;
-  intptr_t metadata_pos;
+  TokenPosition metadata_pos;
   Token::Kind operator_token;
   const AbstractType* type;
-  intptr_t name_pos;
-  intptr_t decl_begin_pos;
+  TokenPosition name_pos;
+  TokenPosition decl_begin_pos;
   String* name;
   // For constructors: NULL or name of redirected to constructor.
   String* redirect_name;
@@ -703,7 +736,7 @@
             const Class& cls,
             const String& cls_name,
             bool is_interface,
-            intptr_t token_pos)
+            TokenPosition token_pos)
       : zone_(zone),
         clazz_(cls),
         class_name_(cls_name),
@@ -746,7 +779,7 @@
     return false;
   }
 
-  intptr_t token_pos() const {
+  TokenPosition token_pos() const {
     return token_pos_;
   }
 
@@ -780,7 +813,7 @@
   Zone* zone_;
   const Class& clazz_;
   const String& class_name_;
-  intptr_t token_pos_;   // Token index of "class" keyword.
+  TokenPosition token_pos_;   // Token index of "class" keyword.
   GrowableArray<const Function*> functions_;
   GrowableArray<const Field*> fields_;
   GrowableArray<MemberDesc> members_;
@@ -821,6 +854,7 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   const int64_t num_tokes_before = STAT_VALUE(thread, num_tokens_consumed);
+#ifndef PRODUCT
   TimelineDurationScope tds(thread,
                             thread->isolate()->GetCompilerStream(),
                             "ParseClass");
@@ -828,6 +862,7 @@
     tds.SetNumArguments(1);
     tds.CopyArgument(0, "class", String::Handle(cls.Name()).ToCString());
   }
+#endif
   if (!cls.is_synthesized_class()) {
     ASSERT(thread->long_jump_base()->IsSafeToJump());
     CSTAT_TIMER_SCOPE(thread, parser_timer);
@@ -886,10 +921,9 @@
     return param_descriptor.raw();
   } else {
     Thread* thread = Thread::Current();
-    Isolate* isolate = thread->isolate();
     Error& error = Error::Handle();
-    error = isolate->object_store()->sticky_error();
-    isolate->object_store()->clear_sticky_error();
+    error = thread->sticky_error();
+    thread->clear_sticky_error();
     return error.raw();
   }
   UNREACHABLE();
@@ -920,7 +954,7 @@
     parser.ParseFormalParameterList(true, true, params);
     return true;
   } else {
-    Thread::Current()->isolate()->object_store()->clear_sticky_error();
+    Thread::Current()->clear_sticky_error();
     params->Clear();
     return false;
   }
@@ -937,18 +971,22 @@
   INC_STAT(thread, num_functions_parsed, 1);
   VMTagScope tagScope(thread, VMTag::kCompileParseFunctionTagId,
                       FLAG_profile_vm);
+#ifndef PRODUCT
   TimelineDurationScope tds(thread,
                             thread->isolate()->GetCompilerStream(),
                             "ParseFunction");
+#endif  // !PRODUCT
   ASSERT(thread->long_jump_base()->IsSafeToJump());
   ASSERT(parsed_function != NULL);
   const Function& func = parsed_function->function();
   const Script& script = Script::Handle(zone, func.script());
   Parser parser(script, parsed_function, func.token_pos());
+#ifndef PRODUCT
   if (tds.enabled()) {
     tds.SetNumArguments(1);
     tds.CopyArgument(0, "function", String::Handle(func.name()).ToCString());
   }
+#endif  // !PRODUCT
   SequenceNode* node_sequence = NULL;
   switch (func.kind()) {
     case RawFunction::kClosureFunction:
@@ -970,7 +1008,7 @@
       if (!func.IsImplicitConstructor()) {
         parser.SkipFunctionPreamble();
       }
-      node_sequence = parser.ParseFunc(func);
+      node_sequence = parser.ParseFunc(func, false);
       break;
     case RawFunction::kImplicitGetter:
       ASSERT(!func.is_static());
@@ -1040,9 +1078,9 @@
     Thread* thread = Thread::Current();
     StackZone stack_zone(thread);
     Zone* zone = stack_zone.GetZone();
-    const Class& owner_class = Class::Handle(zone, meta_data.owner());
-    const Script& script = Script::Handle(zone, meta_data.script());
-    const intptr_t token_pos = meta_data.token_pos();
+    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,
     // so we create a fake function to use as the current_function rather than
@@ -1068,12 +1106,11 @@
     return metadata;
   } else {
     Thread* thread = Thread::Current();
-    Isolate* isolate = thread->isolate();
     StackZone stack_zone(thread);
     Zone* zone = stack_zone.GetZone();
     Error& error = Error::Handle(zone);
-    error = isolate->object_store()->sticky_error();
-    isolate->object_store()->clear_sticky_error();
+    error = thread->sticky_error();
+    thread->clear_sticky_error();
     return error.raw();
   }
   UNREACHABLE();
@@ -1087,7 +1124,7 @@
       GrowableObjectArray::Handle(Z, GrowableObjectArray::New(Heap::kOld));
   while (CurrentToken() == Token::kAT) {
     ConsumeToken();
-    intptr_t expr_pos = TokenPos();
+    TokenPosition expr_pos = TokenPos();
     if (!IsIdentifier()) {
       ExpectIdentifier("identifier expected");
     }
@@ -1131,7 +1168,7 @@
                       "or constructor");
         }
         ConsumeToken();
-        const intptr_t ident_pos = TokenPos();
+        const TokenPosition ident_pos = TokenPos();
         String* ident = ExpectIdentifier("identifier expected");
         const Field& field = Field::Handle(Z, cls.LookupStaticField(*ident));
         if (field.IsNull()) {
@@ -1164,7 +1201,7 @@
   CheckToken(Token::kASSIGN, "field initialier expected");
   ConsumeToken();
   OpenFunctionBlock(parsed_function()->function());
-  intptr_t expr_pos = TokenPos();
+  TokenPosition expr_pos = TokenPos();
   AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
   ReturnNode* ret = new(Z) ReturnNode(expr_pos, expr);
   current_block_->statements->Add(ret);
@@ -1182,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,
@@ -1238,7 +1275,7 @@
   OpenFunctionBlock(func);
   AddFormalParamsToScope(&params, current_block_->scope);
 
-  intptr_t ident_pos = TokenPos();
+  TokenPosition ident_pos = TokenPos();
   const String& field_name = *ExpectIdentifier("field name expected");
   const Class& field_class = Class::Handle(Z, func.Owner());
   const Field& field =
@@ -1248,7 +1285,7 @@
   // Static final fields must have an initializer.
   ExpectToken(Token::kASSIGN);
 
-  const intptr_t expr_pos = TokenPos();
+  const TokenPosition expr_pos = TokenPos();
   if (field.is_const()) {
     // We don't want to use ParseConstExpr() here because we don't want
     // the constant folding code to create, compile and execute a code
@@ -1286,7 +1323,7 @@
   TRACE_PARSER("ParseInstanceGetter");
   ParamList params;
   // func.token_pos() points to the name of the field.
-  const intptr_t ident_pos = func.token_pos();
+  const TokenPosition ident_pos = func.token_pos();
   ASSERT(current_class().raw() == func.Owner());
   params.AddReceiver(ReceiverType(current_class()), ident_pos);
   ASSERT(func.num_fixed_parameters() == 1);  // receiver.
@@ -1311,7 +1348,7 @@
   LoadInstanceFieldNode* load_field =
       new LoadInstanceFieldNode(ident_pos, load_receiver, field);
 
-  ReturnNode* return_node = new ReturnNode(Scanner::kNoSourcePos, load_field);
+  ReturnNode* return_node = new ReturnNode(ST(ident_pos), load_field);
   current_block_->statements->Add(return_node);
   return CloseBlock();
 }
@@ -1325,7 +1362,7 @@
 SequenceNode* Parser::ParseInstanceSetter(const Function& func) {
   TRACE_PARSER("ParseInstanceSetter");
   // func.token_pos() points to the name of the field.
-  const intptr_t ident_pos = func.token_pos();
+  const TokenPosition ident_pos = func.token_pos();
   const String& field_name = *CurrentLiteral();
   const Class& field_class = Class::ZoneHandle(Z, func.Owner());
   const Field& field =
@@ -1355,14 +1392,14 @@
   StoreInstanceFieldNode* store_field =
       new StoreInstanceFieldNode(ident_pos, receiver, field, value);
   current_block_->statements->Add(store_field);
-  current_block_->statements->Add(new ReturnNode(Scanner::kNoSourcePos));
+  current_block_->statements->Add(new ReturnNode(ST(ident_pos)));
   return CloseBlock();
 }
 
 
 SequenceNode* Parser::ParseConstructorClosure(const Function& func) {
   TRACE_PARSER("ParseConstructorClosure");
-  const intptr_t token_pos = func.token_pos();
+  const TokenPosition token_pos = func.token_pos();
 
   Function& constructor = Function::ZoneHandle(Z);
   TypeArguments& type_args = TypeArguments::ZoneHandle(Z);
@@ -1416,7 +1453,7 @@
 
 SequenceNode* Parser::ParseImplicitClosure(const Function& func) {
   TRACE_PARSER("ParseImplicitClosure");
-  intptr_t token_pos = func.token_pos();
+  TokenPosition token_pos = func.token_pos();
 
   OpenFunctionBlock(func);
 
@@ -1428,7 +1465,7 @@
 
   const Function& parent = Function::ZoneHandle(func.parent_function());
   if (parent.IsImplicitSetterFunction()) {
-    const intptr_t ident_pos = func.token_pos();
+    const TokenPosition ident_pos = func.token_pos();
     ASSERT(IsIdentifier());
     const String& field_name = *CurrentLiteral();
     const Class& field_class = Class::ZoneHandle(Z, parent.Owner());
@@ -1482,8 +1519,8 @@
 
   ParamList params;
 
-  const intptr_t ident_pos = func.token_pos();
-  ASSERT(func.token_pos() == 0);
+  const TokenPosition ident_pos = func.token_pos();
+  ASSERT(func.token_pos() == TokenPosition::kMethodExtractor);
   ASSERT(current_class().raw() == func.Owner());
   params.AddReceiver(ReceiverType(current_class()), ident_pos);
   ASSERT(func.num_fixed_parameters() == 1);  // Receiver.
@@ -1503,7 +1540,7 @@
       load_receiver,
       NULL);
 
-  ReturnNode* return_node = new ReturnNode(Scanner::kNoSourcePos, closure);
+  ReturnNode* return_node = new ReturnNode(ident_pos, closure);
   current_block_->statements->Add(return_node);
   return CloseBlock();
 }
@@ -1513,7 +1550,7 @@
                                   const ArgumentsDescriptor& desc) {
   ParamList params;
   // Receiver first.
-  intptr_t token_pos = func.token_pos();
+  TokenPosition token_pos = func.token_pos();
   params.AddReceiver(ReceiverType(current_class()), token_pos);
   // Remaining positional parameters.
   intptr_t i = 1;
@@ -1553,8 +1590,8 @@
   TRACE_PARSER("ParseNoSuchMethodDispatcher");
   ASSERT(FLAG_lazy_dispatchers);
   ASSERT(func.IsNoSuchMethodDispatcher());
-  intptr_t token_pos = func.token_pos();
-  ASSERT(func.token_pos() == 0);
+  TokenPosition token_pos = func.token_pos();
+  ASSERT(func.token_pos() == TokenPosition::kMinSource);
   ASSERT(current_class().raw() == func.Owner());
 
   ArgumentsDescriptor desc(Array::Handle(Z, func.saved_args_desc()));
@@ -1608,8 +1645,8 @@
 SequenceNode* Parser::ParseInvokeFieldDispatcher(const Function& func) {
   TRACE_PARSER("ParseInvokeFieldDispatcher");
   ASSERT(func.IsInvokeFieldDispatcher());
-  intptr_t token_pos = func.token_pos();
-  ASSERT(func.token_pos() == 0);
+  TokenPosition token_pos = func.token_pos();
+  ASSERT(func.token_pos() == TokenPosition::kMinSource);
   ASSERT(current_class().raw() == func.Owner());
 
   const Array& args_desc = Array::Handle(Z, func.saved_args_desc());
@@ -1624,14 +1661,14 @@
   ArgumentListNode* no_args = new ArgumentListNode(token_pos);
   LoadLocalNode* receiver = new LoadLocalNode(token_pos, scope->VariableAt(0));
 
-  const Class& function_impl = Class::Handle(Type::Handle(
-      Isolate::Current()->object_store()->function_impl_type()).type_class());
+  const Class& closure_cls = Class::Handle(
+      Isolate::Current()->object_store()->closure_class());
 
   const Class& owner = Class::Handle(Z, func.Owner());
   ASSERT(!owner.IsNull());
   const String& name = String::Handle(Z, func.name());
   AstNode* function_object = NULL;
-  if (owner.raw() == function_impl.raw() && name.Equals(Symbols::Call())) {
+  if (owner.raw() == closure_cls.raw() && name.Equals(Symbols::Call())) {
     function_object = receiver;
   } else {
     const String& getter_name = String::ZoneHandle(Z,
@@ -1658,7 +1695,7 @@
   args->set_names(names);
 
   AstNode* result = NULL;
-  if (owner.raw() == function_impl.raw() && name.Equals(Symbols::Call())) {
+  if (owner.raw() == closure_cls.raw() && name.Equals(Symbols::Call())) {
     result = new ClosureCallNode(token_pos, function_object, args);
   } else {
     result = BuildClosureCall(token_pos, function_object, args);
@@ -1670,7 +1707,7 @@
 }
 
 
-AstNode* Parser::BuildClosureCall(intptr_t token_pos,
+AstNode* Parser::BuildClosureCall(TokenPosition token_pos,
                                   AstNode* closure,
                                   ArgumentListNode* arguments) {
   return new InstanceCallNode(token_pos,
@@ -1685,17 +1722,17 @@
   ASSERT((opening_token == Token::kLBRACE) ||
          (opening_token == Token::kLPAREN));
   GrowableArray<Token::Kind> token_stack(8);
-  GrowableArray<intptr_t> token_pos_stack(8);
+  GrowableArray<TokenPosition> token_pos_stack(8);
   // Adding the first opening brace here, because it will be consumed
   // in the loop right away.
   token_stack.Add(opening_token);
-  const intptr_t start_pos =  TokenPos();
-  intptr_t opening_pos = start_pos;
+  const TokenPosition start_pos =  TokenPos();
+  TokenPosition opening_pos = start_pos;
   token_pos_stack.Add(start_pos);
   bool is_match = true;
   bool unexpected_token_found = false;
   Token::Kind token = opening_token;
-  intptr_t token_pos;
+  TokenPosition token_pos;
   do {
     ConsumeToken();
     token = CurrentToken();
@@ -1735,7 +1772,8 @@
   if (!is_match) {
     const Error& error = Error::Handle(
         LanguageError::NewFormatted(Error::Handle(),
-            script_, opening_pos, Report::kWarning, Heap::kNew,
+            script_, opening_pos, Report::AtLocation,
+            Report::kWarning, Heap::kNew,
             "unbalanced '%s' opens here", Token::Str(opening_token)));
     ReportErrors(error, script_, token_pos,
                  "unbalanced '%s'", Token::Str(token));
@@ -1879,55 +1917,22 @@
       ParseFormalParameterList(no_explicit_default_values, false, &func_params);
 
       // In top-level and mixin functions, the source may be in a different
-      // script than the script of the current class.
-      Object& sig_func_owner = Object::Handle(Z, current_class().raw());
-      if (current_class().script() != script_.raw()) {
-        sig_func_owner = PatchClass::New(current_class(), script_);
-      }
-
-      // The field 'is_static' has no meaning for signature functions.
+      // script than the script of the current class. However, we never reparse
+      // signature functions (except typedef signature functions), therefore
+      // we do not need to keep the correct script via a patch class. Use the
+      // actual current class as owner of the signature function.
       const Function& signature_function = Function::Handle(Z,
-          Function::New(*parameter.name,
-                        RawFunction::kSignatureFunction,
-                        /* is_static = */ false,
-                        /* is_const = */ false,
-                        /* is_abstract = */ false,
-                        /* is_external = */ false,
-                        /* is_native = */ false,
-                        sig_func_owner,
-                        parameter.name_pos));
+          Function::NewSignatureFunction(current_class(),
+                                         TokenPosition::kNoSource));
       signature_function.set_result_type(result_type);
-      signature_function.set_is_debuggable(false);
       AddFormalParamsToFunction(&func_params, signature_function);
-      const String& signature =
-          String::Handle(Z, signature_function.Signature());
-      // Lookup the signature class, i.e. the class whose name is the signature.
-      // We only lookup in the current library, but not in its imports, and only
-      // create a new canonical signature class if it does not exist yet.
-      Class& signature_class =
-          Class::ZoneHandle(Z, library_.LookupLocalClass(signature));
-      if (signature_class.IsNull()) {
-        signature_class = Class::NewSignatureClass(signature,
-                                                   signature_function,
-                                                   script_,
-                                                   parameter.name_pos);
-        // Record the function signature class in the current library, unless
-        // we are currently skipping a formal parameter list, in which case
-        // the signature class could remain unfinalized.
-        if (!params->skipped) {
-          library_.AddClass(signature_class);
-        }
-      } else {
-        signature_function.set_signature_class(signature_class);
-      }
-      ASSERT(signature_function.signature_class() == signature_class.raw());
+      FunctionType& signature_type =
+          FunctionType::ZoneHandle(Z, signature_function.SignatureType());
       if (!is_top_level_) {
-        // Finalize types in signature class here, so that the
-        // signature type is not computed twice.
-        ClassFinalizer::FinalizeTypesInClass(signature_class);
+        signature_type ^= ClassFinalizer::FinalizeType(
+            current_class(), signature_type, ClassFinalizer::kCanonicalize);
+        signature_function.SetSignatureType(signature_type);
       }
-      const Type& signature_type =
-          Type::ZoneHandle(Z, signature_class.SignatureType());
       ASSERT(is_top_level_ || signature_type.IsFinalized());
       // A signature type itself cannot be malformed or malbounded, only its
       // signature function's result type or parameter types may be.
@@ -2059,7 +2064,7 @@
 // If it is not found, and resolve_getter is true, try to resolve a getter of
 // the same name. If it is still not found, return noSuchMethod and
 // set is_no_such_method to true..
-RawFunction* Parser::GetSuperFunction(intptr_t token_pos,
+RawFunction* Parser::GetSuperFunction(TokenPosition token_pos,
                                       const String& name,
                                       ArgumentListNode* arguments,
                                       bool resolve_getter,
@@ -2095,12 +2100,12 @@
 
 
 StaticCallNode* Parser::BuildInvocationMirrorAllocation(
-    intptr_t call_pos,
+    TokenPosition call_pos,
     const String& function_name,
     const ArgumentListNode& function_args,
     const LocalVariable* temp_for_last_arg,
     bool is_super_invocation) {
-  const intptr_t args_pos = function_args.token_pos();
+  const TokenPosition args_pos = function_args.token_pos();
   // Build arguments to the call to the static
   // InvocationMirror._allocateInvocationMirror method.
   ArgumentListNode* arguments = new ArgumentListNode(args_pos);
@@ -2144,13 +2149,13 @@
 
 
 ArgumentListNode* Parser::BuildNoSuchMethodArguments(
-    intptr_t call_pos,
+    TokenPosition call_pos,
     const String& function_name,
     const ArgumentListNode& function_args,
     const LocalVariable* temp_for_last_arg,
     bool is_super_invocation) {
   ASSERT(function_args.length() >= 1);  // The receiver is the first argument.
-  const intptr_t args_pos = function_args.token_pos();
+  const TokenPosition args_pos = function_args.token_pos();
   ArgumentListNode* arguments = new ArgumentListNode(args_pos);
   arguments->Add(function_args.NodeAt(0));
   // The second argument is the invocation mirror.
@@ -2166,7 +2171,7 @@
 AstNode* Parser::ParseSuperCall(const String& function_name) {
   TRACE_PARSER("ParseSuperCall");
   ASSERT(CurrentToken() == Token::kLPAREN);
-  const intptr_t supercall_pos = TokenPos();
+  const TokenPosition supercall_pos = TokenPos();
 
   // 'this' parameter is the first argument to super call.
   ArgumentListNode* arguments = new ArgumentListNode(supercall_pos);
@@ -2214,7 +2219,7 @@
 AstNode* Parser::BuildUnarySuperOperator(Token::Kind op, PrimaryNode* super) {
   ASSERT(super->IsSuper());
   AstNode* super_op = NULL;
-  const intptr_t super_pos = super->token_pos();
+  const TokenPosition super_pos = super->token_pos();
   if ((op == Token::kNEGATE) ||
       (op == Token::kBIT_NOT)) {
     // Resolve the operator function in the superclass.
@@ -2246,7 +2251,7 @@
 AstNode* Parser::ParseSuperOperator() {
   TRACE_PARSER("ParseSuperOperator");
   AstNode* super_op = NULL;
-  const intptr_t operator_pos = TokenPos();
+  const TokenPosition operator_pos = TokenPos();
 
   if (CurrentToken() == Token::kLBRACK) {
     ConsumeToken();
@@ -2303,7 +2308,7 @@
 
 
 ClosureNode* Parser::CreateImplicitClosureNode(const Function& func,
-                                               intptr_t token_pos,
+                                               TokenPosition token_pos,
                                                AstNode* receiver) {
   Function& implicit_closure_function =
       Function::ZoneHandle(Z, func.ImplicitClosureFunction());
@@ -2312,9 +2317,10 @@
     // parameterized class, make sure that the receiver is captured as
     // instantiator.
     if (current_block_->scope->function_level() > 0) {
-      const Class& signature_class = Class::Handle(Z,
-          implicit_closure_function.signature_class());
-      if (signature_class.NumTypeParameters() > 0) {
+      const FunctionType& signature_type = FunctionType::Handle(Z,
+          implicit_closure_function.SignatureType());
+      const Class& scope_class = Class::Handle(Z, signature_type.type_class());
+      if (scope_class.IsGeneric()) {
         CaptureInstantiator();
       }
     }
@@ -2324,7 +2330,7 @@
 
 
 AstNode* Parser::ParseSuperFieldAccess(const String& field_name,
-                                       intptr_t field_pos) {
+                                       TokenPosition field_pos) {
   TRACE_PARSER("ParseSuperFieldAccess");
   const Class& super_class = Class::ZoneHandle(Z, current_class().SuperClass());
   if (super_class.IsNull()) {
@@ -2371,7 +2377,7 @@
 
 StaticCallNode* Parser::GenerateSuperConstructorCall(
       const Class& cls,
-      intptr_t supercall_pos,
+      TokenPosition supercall_pos,
       LocalVariable* receiver,
       ArgumentListNode* forwarding_args) {
   const Class& super_class = Class::Handle(Z, cls.SuperClass());
@@ -2438,7 +2444,7 @@
                                               LocalVariable* receiver) {
   TRACE_PARSER("ParseSuperInitializer");
   ASSERT(CurrentToken() == Token::kSUPER);
-  const intptr_t supercall_pos = TokenPos();
+  const TokenPosition supercall_pos = TokenPos();
   ConsumeToken();
   const Class& super_class = Class::Handle(Z, cls.SuperClass());
   ASSERT(!super_class.IsNull());
@@ -2489,7 +2495,7 @@
                                   LocalVariable* receiver,
                                   GrowableArray<Field*>* initialized_fields) {
   TRACE_PARSER("ParseInitializer");
-  const intptr_t field_pos = TokenPos();
+  const TokenPosition field_pos = TokenPos();
   if (CurrentToken() == Token::kTHIS) {
     ConsumeToken();
     ExpectToken(Token::kPERIOD);
@@ -2543,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;
         }
@@ -2561,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 intptr_t saved_token_pos = TokenPos();
+  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());
 
@@ -2575,7 +2582,7 @@
   ConsumeToken();
   ExpectToken(Token::kASSIGN);
   AstNode* init_expr = NULL;
-  intptr_t expr_pos = TokenPos();
+  TokenPosition expr_pos = TokenPos();
   if (field.is_const()) {
     init_expr = ParseConstExpr();
   } else {
@@ -2602,7 +2609,7 @@
   TRACE_PARSER("ParseInitializedInstanceFields");
   const Array& fields = Array::Handle(Z, cls.fields());
   Field& f = Field::Handle(Z);
-  const intptr_t saved_pos = TokenPos();
+  const TokenPosition saved_pos = TokenPos();
   for (int i = 0; i < fields.Length(); i++) {
     f ^= fields.At(i);
     if (!f.is_static() && f.has_initializer()) {
@@ -2615,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());
@@ -2627,7 +2634,7 @@
           // expression must be a compile-time constant.
           init_expr = ParseConstExpr();
         } else {
-          intptr_t expr_pos = TokenPos();
+          TokenPosition expr_pos = TokenPos();
           init_expr = ParseExpr(kAllowConst, kConsumeCascades);
           if (init_expr->EvalConstExpr() != NULL) {
             Instance& expr_value = Instance::ZoneHandle(Z);
@@ -2656,7 +2663,7 @@
 
 
 AstNode* Parser::CheckDuplicateFieldInit(
-    intptr_t init_pos,
+    TokenPosition init_pos,
     GrowableArray<Field*>* initialized_fields,
     AstNode* instance,
     Field* field,
@@ -2829,7 +2836,7 @@
   TRACE_PARSER("ParseConstructorRedirection");
   ExpectToken(Token::kCOLON);
   ASSERT(CurrentToken() == Token::kTHIS);
-  const intptr_t call_pos = TokenPos();
+  const TokenPosition call_pos = TokenPos();
   ConsumeToken();
   String& ctor_name = String::Handle(Z, cls.Name());
   GrowableHandlePtrArray<const String> pieces(Z, 3);
@@ -2873,11 +2880,13 @@
 SequenceNode* Parser::MakeImplicitConstructor(const Function& func) {
   ASSERT(func.IsGenerativeConstructor());
   ASSERT(func.Owner() == current_class().raw());
-  const intptr_t ctor_pos = TokenPos();
+  const TokenPosition ctor_pos = TokenPos();
   OpenFunctionBlock(func);
 
   LocalVariable* receiver = new LocalVariable(
-      Scanner::kNoSourcePos, Symbols::This(), *ReceiverType(current_class()));
+      TokenPosition::kNoSource,
+      Symbols::This(),
+      *ReceiverType(current_class()));
   current_block_->scope->InsertParameterAt(0, receiver);
 
   // Parse expressions of instance fields that have an explicit
@@ -2920,20 +2929,20 @@
 
     // Prepare user-defined arguments to be forwarded to super call.
     // The first user-defined argument is at position 1.
-    forwarding_args = new ArgumentListNode(Scanner::kNoSourcePos);
+    forwarding_args = new ArgumentListNode(ST(ctor_pos));
     for (int i = 1; i < func.NumParameters(); i++) {
       LocalVariable* param = new LocalVariable(
-          Scanner::kNoSourcePos,
+          TokenPosition::kNoSource,
           String::ZoneHandle(Z, func.ParameterNameAt(i)),
           Object::dynamic_type());
       current_block_->scope->InsertParameterAt(i, param);
-      forwarding_args->Add(new LoadLocalNode(Scanner::kNoSourcePos, param));
+      forwarding_args->Add(new LoadLocalNode(ST(ctor_pos), param));
     }
   }
 
   AstNode* super_call = GenerateSuperConstructorCall(
       current_class(),
-      Scanner::kNoSourcePos,
+      ctor_pos,
       receiver,
       forwarding_args);
   if (super_call != NULL) {
@@ -2942,24 +2951,50 @@
   CheckFieldsInitialized(current_class());
 
   // Empty constructor body.
-  current_block_->statements->Add(new ReturnNode(Scanner::kNoSourcePos));
+  current_block_->statements->Add(new ReturnNode(ST(ctor_pos)));
   SequenceNode* statements = CloseBlock();
   return statements;
 }
 
 
+// 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());
+  ASSERT(!pending_functions.IsNull());
   for (int i = 0; i < pending_functions.Length(); i++) {
     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_);
-  pending_functions.Add(current_function());
+  pending_functions.Add(current_function(), Heap::kOld);
   unregister_pending_function_ = true;
 }
 
@@ -3142,7 +3177,7 @@
 // Parser is at the opening parenthesis of the formal parameter
 // declaration of the function or constructor.
 // Parse the formal parameters and code.
-SequenceNode* Parser::ParseFunc(const Function& func) {
+SequenceNode* Parser::ParseFunc(const Function& func, bool check_semicolon) {
   TRACE_PARSER("ParseFunc");
   Function& saved_innermost_function =
       Function::Handle(Z, innermost_function().raw());
@@ -3266,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.
@@ -3280,7 +3315,7 @@
     }
   }
 
-  const intptr_t modifier_pos = TokenPos();
+  const TokenPosition modifier_pos = TokenPos();
   RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
   if (!func.is_generated_body()) {
     // Don't add a modifier to the closure representing the body of
@@ -3319,7 +3354,7 @@
 
   BoolScope allow_await(&this->await_is_keyword_,
                         func.IsAsyncOrGenerator() || func.is_generated_body());
-  intptr_t end_token_pos = Scanner::kNoSourcePos;
+  TokenPosition end_token_pos = TokenPosition::kNoSource;
   if (CurrentToken() == Token::kLBRACE) {
     ConsumeToken();
     if (String::Handle(Z, func.name()).Equals(Symbols::EqualOperator())) {
@@ -3344,11 +3379,14 @@
         AddEqualityNullCheck();
       }
     }
-    const intptr_t expr_pos = TokenPos();
+    const TokenPosition expr_pos = TokenPos();
     AstNode* expr = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
     ASSERT(expr != NULL);
     current_block_->statements->Add(new ReturnNode(expr_pos, expr));
     end_token_pos = TokenPos();
+    if (check_semicolon) {
+      ExpectSemicolon();
+    }
   } else if (IsSymbol(Symbols::Native())) {
     if (String::Handle(Z, func.name()).Equals(
         Symbols::EqualOperator())) {
@@ -3409,24 +3447,24 @@
 
 void Parser::AddEqualityNullCheck() {
   AstNode* argument =
-      new LoadLocalNode(Scanner::kNoSourcePos,
+      new LoadLocalNode(TokenPosition::kNoSource,
                         current_block_->scope->parent()->VariableAt(1));
   LiteralNode* null_operand =
-      new LiteralNode(Scanner::kNoSourcePos, Instance::ZoneHandle(Z));
+      new LiteralNode(TokenPosition::kNoSource, Instance::ZoneHandle(Z));
   ComparisonNode* check_arg =
-      new ComparisonNode(Scanner::kNoSourcePos,
+      new ComparisonNode(TokenPosition::kNoSource,
                          Token::kEQ_STRICT,
                          argument,
                          null_operand);
   ComparisonNode* result =
-      new ComparisonNode(Scanner::kNoSourcePos,
+      new ComparisonNode(TokenPosition::kNoSource,
                          Token::kEQ_STRICT,
-                         LoadReceiver(Scanner::kNoSourcePos),
+                         LoadReceiver(TokenPosition::kNoSource),
                          null_operand);
-  SequenceNode* arg_is_null = new SequenceNode(Scanner::kNoSourcePos,
+  SequenceNode* arg_is_null = new SequenceNode(TokenPosition::kNoSource,
                                                current_block_->scope);
-  arg_is_null->Add(new ReturnNode(Scanner::kNoSourcePos, result));
-  IfNode* if_arg_null = new IfNode(Scanner::kNoSourcePos,
+  arg_is_null->Add(new ReturnNode(TokenPosition::kNoSource, result));
+  IfNode* if_arg_null = new IfNode(TokenPosition::kNoSource,
                                    check_arg,
                                    arg_is_null,
                                    NULL);
@@ -3538,7 +3576,7 @@
   // Parse the formal parameters.
   const bool are_implicitly_final = method->has_const;
   const bool allow_explicit_default_values = true;
-  const intptr_t formal_param_pos = TokenPos();
+  const TokenPosition formal_param_pos = TokenPos();
   method->params.Clear();
   // Static functions do not have a receiver.
   // The first parameter of a factory is the TypeArguments vector of
@@ -3612,7 +3650,7 @@
                   method->name->ToCString());
     }
     ConsumeToken();
-    const intptr_t type_pos = TokenPos();
+    const TokenPosition type_pos = TokenPos();
     is_redirecting = true;
     const bool consume_unresolved_prefix =
         (LookaheadToken(3) == Token::kLT) ||
@@ -3691,7 +3729,7 @@
                 method->name->ToCString());
   }
 
-  const intptr_t modifier_pos = TokenPos();
+  const TokenPosition modifier_pos = TokenPos();
   RawFunction::AsyncModifier async_modifier = ParseFunctionModifier();
   if ((method->IsFactoryOrConstructor() || method->IsSetter()) &&
       (async_modifier != RawFunction::kNoModifier)) {
@@ -3701,7 +3739,7 @@
                 method->name->ToCString());
   }
 
-  intptr_t method_end_pos = TokenPos();
+  TokenPosition method_end_pos = TokenPos();
   String* native_name = NULL;
   if ((CurrentToken() == Token::kLBRACE) ||
       (CurrentToken() == Token::kARROW)) {
@@ -3833,7 +3871,7 @@
   if (library_.is_dart_scheme() && library_.IsPrivate(*method->name)) {
     func.set_is_reflectable(false);
   }
-  if (FLAG_enable_mirrors && (method->metadata_pos >= 0)) {
+  if (FLAG_enable_mirrors && (method->metadata_pos.IsReal())) {
     library_.AddFunctionMetadata(func, method->metadata_pos);
   }
   if (method->has_native) {
@@ -3864,7 +3902,7 @@
          CurrentToken() == Token::kCOMMA ||
          CurrentToken() == Token::kASSIGN);
   ASSERT(field->type != NULL);
-  ASSERT(field->name_pos >= 0);
+  ASSERT(field->name_pos.IsReal());
   ASSERT(current_member_ == field);
   // All const fields are also final.
   ASSERT(!field->has_const || field->has_final);
@@ -3933,7 +3971,7 @@
     class_field.set_has_initializer(has_initializer);
     members->AddField(class_field);
     field->field_ = &class_field;
-    if (FLAG_enable_mirrors && (field->metadata_pos >= 0)) {
+    if (FLAG_enable_mirrors && (field->metadata_pos.IsReal())) {
       library_.AddFieldMetadata(class_field, field->metadata_pos);
     }
 
@@ -4080,7 +4118,7 @@
 
 
 void Parser::ParseClassMemberDefinition(ClassDesc* members,
-                                        intptr_t metadata_pos) {
+                                        TokenPosition metadata_pos) {
   TRACE_PARSER("ParseClassMemberDefinition");
   MemberDesc member;
   current_member_ = &member;
@@ -4114,7 +4152,8 @@
     member.has_var = true;
     // The member type is the 'dynamic' type.
     member.type = &Object::dynamic_type();
-  } else if (CurrentToken() == Token::kFACTORY) {
+  } else if ((CurrentToken() == Token::kFACTORY) &&
+      (LookaheadToken(1) != Token::kLPAREN)) {
     ConsumeToken();
     if (member.has_static) {
       ReportError("factory method cannot be explicitly marked static");
@@ -4290,12 +4329,12 @@
 
 void Parser::ParseEnumDeclaration(const GrowableObjectArray& pending_classes,
                                   const Object& tl_owner,
-                                  intptr_t metadata_pos) {
+                                  TokenPosition metadata_pos) {
   TRACE_PARSER("ParseEnumDeclaration");
-  const intptr_t declaration_pos = (metadata_pos >= 0) ? metadata_pos
-                                                       : TokenPos();
+  const TokenPosition declaration_pos =
+      (metadata_pos.IsReal()) ? metadata_pos : TokenPos();
   ConsumeToken();
-  const intptr_t name_pos = TokenPos();
+  const TokenPosition name_pos = TokenPos();
   String* enum_name =
       ExpectUserDefinedTypeIdentifier("enum type name expected");
   if (FLAG_trace_parser) {
@@ -4330,7 +4369,7 @@
   library_.AddClass(cls);
   cls.set_is_synthesized_class();
   cls.set_is_enum_class();
-  if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+  if (FLAG_enable_mirrors && (metadata_pos.IsReal())) {
     library_.AddClassMetadata(cls, tl_owner, metadata_pos);
   }
   cls.set_super_type(Type::Handle(Z, Type::ObjectType()));
@@ -4340,11 +4379,12 @@
 
 void Parser::ParseClassDeclaration(const GrowableObjectArray& pending_classes,
                                    const Object& tl_owner,
-                                   intptr_t metadata_pos) {
+                                   TokenPosition metadata_pos) {
   TRACE_PARSER("ParseClassDeclaration");
   bool is_patch = false;
   bool is_abstract = false;
-  intptr_t declaration_pos = (metadata_pos >= 0) ? metadata_pos : TokenPos();
+  TokenPosition declaration_pos =
+      metadata_pos.IsReal() ? metadata_pos : TokenPos();
   if (is_patch_source() &&
       (CurrentToken() == Token::kIDENT) &&
       CurrentLiteral()->Equals("patch")) {
@@ -4355,7 +4395,7 @@
     ConsumeToken();
   }
   ExpectToken(Token::kCLASS);
-  const intptr_t classname_pos = TokenPos();
+  const TokenPosition classname_pos = TokenPos();
   String& class_name = *ExpectUserDefinedTypeIdentifier("class name expected");
   if (FLAG_trace_parser) {
     OS::Print("TopLevel parsing class '%s'\n", class_name.ToCString());
@@ -4380,10 +4420,6 @@
       // Preserve and reuse the original type parameters and bounds since the
       // ones defined in the patch class will not be finalized.
       orig_type_parameters = cls.type_parameters();
-      // A patch class must be given the same name as the class it is patching,
-      // otherwise the generic signature classes it defines will not match the
-      // patched generic signature classes. Therefore, new signature classes
-      // will be introduced and the original ones will not get finalized.
       cls = Class::New(class_name, script_, declaration_pos);
       cls.set_library(library_);
     } else {
@@ -4453,7 +4489,7 @@
   if (is_abstract) {
     cls.set_is_abstract();
   }
-  if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+  if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
     library_.AddClassMetadata(cls, tl_owner, metadata_pos);
   }
 
@@ -4467,7 +4503,7 @@
   AbstractType& super_type = Type::Handle(Z);
   if ((CurrentToken() == Token::kEXTENDS) || is_mixin_declaration) {
     ConsumeToken();  // extends or =
-    const intptr_t type_pos = TokenPos();
+    const TokenPosition type_pos = TokenPos();
     super_type = ParseType(ClassFinalizer::kResolveTypeParameters);
     if (super_type.IsMalformedOrMalbounded()) {
       ReportError(Error::Handle(Z, super_type.error()));
@@ -4544,14 +4580,14 @@
     ConsumeToken();
   }
   ExpectToken(Token::kCLASS);
-  const intptr_t class_pos = TokenPos();
+  const TokenPosition class_pos = TokenPos();
   ClassDesc members(Z, cls, class_name, false, class_pos);
   while (CurrentToken() != Token::kLBRACE) {
     ConsumeToken();
   }
   ExpectToken(Token::kLBRACE);
   while (CurrentToken() != Token::kRBRACE) {
-    intptr_t metadata_pos = SkipMetadata();
+    TokenPosition metadata_pos = SkipMetadata();
     ParseClassMemberDefinition(&members, metadata_pos);
   }
   ExpectToken(Token::kRBRACE);
@@ -4596,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'.
@@ -4694,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);
@@ -4830,9 +4866,9 @@
 void Parser::ParseMixinAppAlias(
     const GrowableObjectArray& pending_classes,
     const Object& tl_owner,
-    intptr_t metadata_pos) {
+    TokenPosition metadata_pos) {
   TRACE_PARSER("ParseMixinAppAlias");
-  const intptr_t classname_pos = TokenPos();
+  const TokenPosition classname_pos = TokenPos();
   String& class_name = *ExpectUserDefinedTypeIdentifier("class name expected");
   if (FLAG_trace_parser) {
     OS::Print("toplevel parsing mixin application alias class '%s'\n",
@@ -4857,7 +4893,7 @@
     ConsumeToken();
   }
 
-  const intptr_t type_pos = TokenPos();
+  const TokenPosition type_pos = TokenPos();
   AbstractType& type =
       AbstractType::Handle(Z,
                            ParseType(ClassFinalizer::kResolveTypeParameters));
@@ -4882,7 +4918,7 @@
   }
   ExpectSemicolon();
   pending_classes.Add(mixin_application, Heap::kOld);
-  if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+  if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
     library_.AddClassMetadata(mixin_application, tl_owner, metadata_pos);
   }
 }
@@ -4896,7 +4932,7 @@
   if (IsIdentifier() && (LookaheadToken(1) == Token::kLPAREN)) {
     return true;
   }
-  const intptr_t saved_pos = TokenPos();
+  const TokenPosition saved_pos = TokenPos();
   bool is_alias_name = false;
   if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
     ConsumeToken();
@@ -4915,7 +4951,7 @@
   if (IsIdentifier() && (LookaheadToken(1) == Token::kASSIGN)) {
     return true;
   }
-  const intptr_t saved_pos = TokenPos();
+  const TokenPosition saved_pos = TokenPos();
   bool is_mixin_def = false;
   if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
     ConsumeToken();
@@ -4930,9 +4966,10 @@
 
 void Parser::ParseTypedef(const GrowableObjectArray& pending_classes,
                           const Object& tl_owner,
-                          intptr_t metadata_pos) {
+                          TokenPosition metadata_pos) {
   TRACE_PARSER("ParseTypedef");
-  intptr_t declaration_pos = (metadata_pos >= 0) ? metadata_pos : TokenPos();
+  TokenPosition declaration_pos =
+      metadata_pos.IsReal() ? metadata_pos : TokenPos();
   ExpectToken(Token::kTYPEDEF);
 
   if (IsMixinAppAlias()) {
@@ -4954,7 +4991,7 @@
     result_type = ParseType(ClassFinalizer::kDoNotResolve);
   }
 
-  const intptr_t alias_name_pos = TokenPos();
+  const TokenPosition alias_name_pos = TokenPos();
   const String* alias_name =
       ExpectUserDefinedTypeIdentifier("function alias name expected");
 
@@ -4967,15 +5004,15 @@
                 "'%s' is already defined", alias_name->ToCString());
   }
 
-  // Create the function type alias signature class. It will be linked to its
+  // Create the function type alias scope class. It will be linked to its
   // signature function after it has been parsed. The type parameters, in order
-  // to be properly finalized, need to be associated to this signature class as
+  // to be properly finalized, need to be associated to this scope class as
   // they are parsed.
   const Class& function_type_alias = Class::Handle(Z,
-      Class::NewSignatureClass(*alias_name,
-                               Function::Handle(Z),
-                               script_,
-                               declaration_pos));
+      Class::New(*alias_name, script_, declaration_pos));
+  function_type_alias.set_is_synthesized_class();
+  function_type_alias.set_is_abstract();
+  function_type_alias.set_is_prefinalized();
   library_.AddClass(function_type_alias);
   set_current_class(function_type_alias);
   // Parse the type parameters of the function type.
@@ -5000,55 +5037,24 @@
   const bool no_explicit_default_values = false;
   ParseFormalParameterList(no_explicit_default_values, false, &func_params);
   ExpectSemicolon();
-  // The field 'is_static' has no meaning for signature functions.
-  Function& signature_function = Function::Handle(Z,
-      Function::New(*alias_name,
-                    RawFunction::kSignatureFunction,
-                    /* is_static = */ false,
-                    /* is_const = */ false,
-                    /* is_abstract = */ false,
-                    /* is_external = */ false,
-                    /* is_native = */ false,
-                    function_type_alias,
-                    alias_name_pos));
+  Function& signature_function =
+      Function::Handle(Z, Function::NewSignatureFunction(function_type_alias,
+                                                         alias_name_pos));
   signature_function.set_result_type(result_type);
-  signature_function.set_is_debuggable(false);
   AddFormalParamsToFunction(&func_params, signature_function);
 
-  // Patch the signature function in the signature class.
-  function_type_alias.PatchSignatureFunction(signature_function);
+  // Set the signature function in the function type alias class.
+  function_type_alias.set_signature_function(signature_function);
 
-  const String& signature = String::Handle(Z,
-                                           signature_function.Signature());
   if (FLAG_trace_parser) {
     OS::Print("TopLevel parsing function type alias '%s'\n",
-              signature.ToCString());
+              String::Handle(Z, signature_function.Signature()).ToCString());
   }
-  // Lookup the signature class, i.e. the class whose name is the signature.
-  // We only lookup in the current library, but not in its imports, and only
-  // create a new canonical signature class if it does not exist yet.
-  Class& signature_class =
-      Class::ZoneHandle(Z, library_.LookupLocalClass(signature));
-  if (signature_class.IsNull()) {
-    signature_class = Class::NewSignatureClass(signature,
-                                               signature_function,
-                                               script_,
-                                               alias_name_pos);
-    // Record the function signature class in the current library.
-    library_.AddClass(signature_class);
-  } else {
-    // Forget the just created signature function and use the existing one.
-    signature_function = signature_class.signature_function();
-    function_type_alias.PatchSignatureFunction(signature_function);
-  }
-  ASSERT(signature_function.signature_class() == signature_class.raw());
-
   // The alias should not be marked as finalized yet, since it needs to be
   // checked in the class finalizer for illegal self references.
-  ASSERT(!function_type_alias.IsCanonicalSignatureClass());
   ASSERT(!function_type_alias.is_finalized());
   pending_classes.Add(function_type_alias, Heap::kOld);
-  if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+  if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
     library_.AddClassMetadata(function_type_alias,
                               tl_owner,
                               metadata_pos);
@@ -5071,11 +5077,11 @@
 }
 
 
-intptr_t Parser::SkipMetadata() {
+TokenPosition Parser::SkipMetadata() {
   if (CurrentToken() != Token::kAT) {
-    return Scanner::kNoSourcePos;
+    return TokenPosition::kNoSource;
   }
-  intptr_t metadata_pos = TokenPos();
+  TokenPosition metadata_pos = TokenPos();
   while (CurrentToken() == Token::kAT) {
     ConsumeToken();
     ExpectIdentifier("identifier expected");
@@ -5139,10 +5145,10 @@
     AbstractType& type_parameter_bound = Type::Handle(Z);
     do {
       ConsumeToken();
-      const intptr_t metadata_pos = SkipMetadata();
-      const intptr_t type_parameter_pos = TokenPos();
-      const intptr_t declaration_pos = (metadata_pos >= 0) ? metadata_pos
-                                                           : type_parameter_pos;
+      const TokenPosition metadata_pos = SkipMetadata();
+      const TokenPosition type_parameter_pos = TokenPos();
+      const TokenPosition declaration_pos =
+          metadata_pos.IsReal() ? metadata_pos : type_parameter_pos;
       String& type_parameter_name =
           *ExpectUserDefinedTypeIdentifier("type parameter expected");
       // Check for duplicate type parameters.
@@ -5171,7 +5177,7 @@
                                           declaration_pos);
       type_parameters_array.Add(
           &AbstractType::ZoneHandle(Z, type_parameter.raw()));
-      if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+      if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
         library_.AddTypeParameterMetadata(type_parameter, metadata_pos);
       }
       index++;
@@ -5246,7 +5252,7 @@
   // Now parse and add the new interfaces.
   do {
     ConsumeToken();
-    intptr_t interface_pos = TokenPos();
+    TokenPosition interface_pos = TokenPos();
     interface = ParseType(ClassFinalizer::kResolveTypeParameters);
     if (interface.IsTypeParameter()) {
       ReportError(interface_pos,
@@ -5288,7 +5294,7 @@
 
 void Parser::ParseTopLevelVariable(TopLevel* top_level,
                                    const Object& owner,
-                                   intptr_t metadata_pos) {
+                                   TokenPosition metadata_pos) {
   TRACE_PARSER("ParseTopLevelVariable");
   const bool is_const = (CurrentToken() == Token::kCONST);
   // Const fields are implicitly final.
@@ -5299,7 +5305,7 @@
   Field& field = Field::Handle(Z);
   Function& getter = Function::Handle(Z);
   while (true) {
-    const intptr_t name_pos = TokenPos();
+    const TokenPosition name_pos = TokenPos();
     String& var_name = *ExpectIdentifier("variable name expected");
 
     if (library_.LookupLocalObject(var_name) != Object::null()) {
@@ -5330,7 +5336,7 @@
     field.SetStaticValue(Object::null_instance(), true);
     top_level->AddField(field);
     library_.AddObject(field, var_name);
-    if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+    if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
       library_.AddFieldMetadata(field, metadata_pos);
     }
     if (CurrentToken() == Token::kASSIGN) {
@@ -5406,9 +5412,9 @@
 
 void Parser::ParseTopLevelFunction(TopLevel* top_level,
                                    const Object& owner,
-                                   intptr_t metadata_pos) {
+                                   TokenPosition metadata_pos) {
   TRACE_PARSER("ParseTopLevelFunction");
-  const intptr_t decl_begin_pos = TokenPos();
+  const TokenPosition decl_begin_pos = TokenPos();
   AbstractType& result_type = Type::Handle(Z, Type::DynamicType());
   const bool is_static = true;
   bool is_external = false;
@@ -5433,7 +5439,7 @@
       result_type = ParseType(ClassFinalizer::kResolveTypeParameters);
     }
   }
-  const intptr_t name_pos = TokenPos();
+  const TokenPosition name_pos = TokenPos();
   const String& func_name = *ExpectIdentifier("function name expected");
 
   bool found = library_.LookupLocalObject(func_name) != Object::null();
@@ -5452,15 +5458,15 @@
   // not need to check setters.
 
   CheckToken(Token::kLPAREN);
-  const intptr_t function_pos = TokenPos();
+  const TokenPosition function_pos = TokenPos();
   ParamList params;
   const bool allow_explicit_default_values = true;
   ParseFormalParameterList(allow_explicit_default_values, false, &params);
 
-  const intptr_t modifier_pos = TokenPos();
+  const TokenPosition modifier_pos = TokenPos();
   RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
 
-  intptr_t function_end_pos = function_pos;
+  TokenPosition function_end_pos = function_pos;
   bool is_native = false;
   String* native_name = NULL;
   if (is_external) {
@@ -5521,7 +5527,7 @@
     toplevel_cls.RemoveFunction(replaced_func);
     library_.ReplaceObject(func, func_name);
   }
-  if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+  if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
     library_.AddFunctionMetadata(func, metadata_pos);
   }
 }
@@ -5529,9 +5535,9 @@
 
 void Parser::ParseTopLevelAccessor(TopLevel* top_level,
                                    const Object& owner,
-                                   intptr_t metadata_pos) {
+                                   TokenPosition metadata_pos) {
   TRACE_PARSER("ParseTopLevelAccessor");
-  const intptr_t decl_begin_pos = TokenPos();
+  const TokenPosition decl_begin_pos = TokenPos();
   const bool is_static = true;
   bool is_external = false;
   bool is_patch = false;
@@ -5564,10 +5570,10 @@
       UnexpectedToken();
     }
   }
-  const intptr_t name_pos = TokenPos();
+  const TokenPosition name_pos = TokenPos();
   const String* field_name = ExpectIdentifier("accessor name expected");
 
-  const intptr_t accessor_pos = TokenPos();
+  const TokenPosition accessor_pos = TokenPos();
   ParamList params;
 
   if (!is_getter) {
@@ -5614,14 +5620,14 @@
                 field_name->ToCString());
   }
 
-  const intptr_t modifier_pos = TokenPos();
+  const TokenPosition modifier_pos = TokenPos();
   RawFunction::AsyncModifier func_modifier = ParseFunctionModifier();
   if (!is_getter && (func_modifier != RawFunction::kNoModifier)) {
     ReportError(modifier_pos,
                 "setter function cannot be async, async* or sync*");
   }
 
-  intptr_t accessor_end_pos = accessor_pos;
+  TokenPosition accessor_end_pos = accessor_pos;
   bool is_native = false;
   String* native_name = NULL;
   if (is_external) {
@@ -5686,14 +5692,14 @@
     toplevel_cls.RemoveFunction(replaced_func);
     library_.ReplaceObject(func, accessor_name);
   }
-  if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+  if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
     library_.AddFunctionMetadata(func, metadata_pos);
   }
 }
 
 
 RawObject* Parser::CallLibraryTagHandler(Dart_LibraryTag tag,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          const String& url) {
   Dart_LibraryTagHandler handler = I->library_tag_handler();
   if (handler == NULL) {
@@ -5708,24 +5714,28 @@
   // Block class finalization attempts when calling into the library
   // tag handler.
   I->BlockClassFinalization();
-  Api::Scope api_scope(T);
-  Dart_Handle result = handler(tag,
-                               Api::NewHandle(T, library_.raw()),
-                               Api::NewHandle(T, url.raw()));
+  Object& result = Object::Handle(Z);
+  {
+    TransitionVMToNative transition(T);
+    Api::Scope api_scope(T);
+    Dart_Handle retval = handler(tag,
+                                 Api::NewHandle(T, library_.raw()),
+                                 Api::NewHandle(T, url.raw()));
+    result = Api::UnwrapHandle(retval);
+  }
   I->UnblockClassFinalization();
-  if (Dart_IsError(result)) {
+  if (result.IsError()) {
     // In case of an error we append an explanatory error message to the
     // error obtained from the library tag handler.
-    Error& prev_error = Error::Handle(Z);
-    prev_error ^= Api::UnwrapHandle(result);
+    const Error& prev_error = Error::Cast(result);
     Report::LongJumpF(prev_error, script_, token_pos, "library handler failed");
   }
   if (tag == Dart_kCanonicalizeUrl) {
-    if (!Dart_IsString(result)) {
+    if (!result.IsString()) {
       ReportError(token_pos, "library handler failed URI canonicalization");
     }
   }
-  return Api::UnwrapHandle(result);
+  return result.raw();
 }
 
 
@@ -5764,11 +5774,11 @@
 
 
 void Parser::ParseLibraryImportExport(const Object& tl_owner,
-                                      intptr_t metadata_pos) {
+                                      TokenPosition metadata_pos) {
   bool is_import = (CurrentToken() == Token::kIMPORT);
   bool is_export = (CurrentToken() == Token::kEXPORT);
   ASSERT(is_import || is_export);
-  const intptr_t import_pos = TokenPos();
+  const TokenPosition import_pos = TokenPos();
   ConsumeToken();
   CheckToken(Token::kSTRING, "library url expected");
   AstNode* url_literal = ParseStringLiteral(false);
@@ -5812,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;
@@ -5832,7 +5842,7 @@
     CheckToken(Token::kAS, "'as' expected");
   }
   String& prefix = String::Handle(Z);
-  intptr_t prefix_pos = Scanner::kNoSourcePos;
+  TokenPosition prefix_pos = TokenPosition::kNoSource;
   if (is_import && (CurrentToken() == Token::kAS)) {
     ConsumeToken();
     prefix_pos = TokenPos();
@@ -5895,7 +5905,7 @@
 
   Namespace& ns = Namespace::Handle(Z,
       Namespace::New(library, show_names, hide_names));
-  if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+  if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
     ns.AddMetadata(tl_owner, metadata_pos);
   }
 
@@ -5945,7 +5955,7 @@
 
 
 void Parser::ParseLibraryPart() {
-  const intptr_t source_pos = TokenPos();
+  const TokenPosition source_pos = TokenPos();
   ConsumeToken();  // Consume "part".
   CheckToken(Token::kSTRING, "url expected");
   AstNode* url_literal = ParseStringLiteral(false);
@@ -5974,14 +5984,14 @@
   // declaration that follows the library definitions. Therefore, we
   // need to remember the position of the last token that was
   // successfully consumed.
-  intptr_t rewind_pos = TokenPos();
-  intptr_t metadata_pos = SkipMetadata();
+  TokenPosition rewind_pos = TokenPos();
+  TokenPosition metadata_pos = SkipMetadata();
   if (CurrentToken() == Token::kLIBRARY) {
     if (is_patch_source()) {
       ReportError("patch cannot override library name");
     }
     ParseLibraryName();
-    if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+    if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
       library_.AddLibraryMetadata(tl_owner, metadata_pos);
     }
     rewind_pos = TokenPos();
@@ -6038,7 +6048,7 @@
   ObjectStore* object_store = I->object_store();
   const GrowableObjectArray& pending_classes =
       GrowableObjectArray::Handle(Z, object_store->pending_classes());
-  SetPosition(0);
+  SetPosition(TokenPosition::kMinSource);
   is_top_level_ = true;
   TopLevel top_level(Z);
 
@@ -6063,7 +6073,7 @@
   const Class& cls = Class::Handle(Z);
   while (true) {
     set_current_class(cls);  // No current class.
-    intptr_t metadata_pos = SkipMetadata();
+    TokenPosition metadata_pos = SkipMetadata();
     if (CurrentToken() == Token::kCLASS) {
       ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
     } else if (CurrentToken() == Token::kENUM) {
@@ -6107,6 +6117,18 @@
 }
 
 
+void Parser::CheckStack() {
+  volatile uword c_stack_pos = Isolate::GetCurrentStackPointer();
+  volatile uword c_stack_base = OSThread::Current()->stack_base();
+  volatile uword c_stack_limit =
+      c_stack_base - OSThread::GetSpecifiedStackSize();
+  // Note: during early initialization the stack_base() can return 0.
+  if ((c_stack_base > 0) && (c_stack_pos < c_stack_limit)) {
+    ReportError("stack overflow while parsing");
+  }
+}
+
+
 void Parser::ChainNewBlock(LocalScope* outer_scope) {
   Block* block = new(Z) Block(
       current_block_,
@@ -6176,7 +6198,7 @@
   // We only get here when parsing an async generator body.
   ASSERT(innermost_function().IsAsyncGenClosure());
 
-  const intptr_t try_end_pos = innermost_function().end_token_pos();
+  const TokenPosition try_end_pos = innermost_function().end_token_pos();
 
   // The try-block (closure body code) has been parsed. We are now
   // generating the code for the catch block.
@@ -6188,10 +6210,10 @@
   // Add the exception and stack trace parameters to the scope.
   CatchParamDesc exception_param;
   CatchParamDesc stack_trace_param;
-  exception_param.token_pos = Scanner::kNoSourcePos;
+  exception_param.token_pos = TokenPosition::kNoSource;
   exception_param.type = &Object::dynamic_type();
   exception_param.name = &Symbols::ExceptionParameter();
-  stack_trace_param.token_pos = Scanner::kNoSourcePos;
+  stack_trace_param.token_pos = TokenPosition::kNoSource;
   stack_trace_param.type = &Object::dynamic_type();
   stack_trace_param.name = &Symbols::StackTraceParameter();
 
@@ -6211,9 +6233,9 @@
     // Generate code to load the exception object (:exception_var) into
     // the exception variable specified in this block.
     current_block_->statements->Add(new(Z) StoreLocalNode(
-        Scanner::kNoSourcePos,
+        TokenPosition::kNoSource,
         exception_param.var,
-        new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
+        new(Z) LoadLocalNode(TokenPosition::kNoSource, exception_var)));
   }
 
   LocalVariable* stack_trace_var =
@@ -6224,9 +6246,9 @@
     // to load the stack trace object (:stack_trace_var) into the stack
     // trace variable specified in this block.
     current_block_->statements->Add(new(Z) StoreLocalNode(
-        Scanner::kNoSourcePos,
+        TokenPosition::kNoSource,
         stack_trace_param.var,
-        new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
+        new(Z) LoadLocalNode(TokenPosition::kNoSource, stack_trace_var)));
   }
   LocalVariable* saved_exception_var = try_scope->LocalLookupVariable(
       Symbols::SavedExceptionVar());
@@ -6245,15 +6267,17 @@
       current_block_->scope->LookupVariable(Symbols::Controller(), false);
   ASSERT(controller != NULL);
   ArgumentListNode* args =
-      new(Z) ArgumentListNode(Scanner::kNoSourcePos);
-  args->Add(new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_param.var));
-  args->Add(new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_param.var));
+      new(Z) ArgumentListNode(TokenPosition::kNoSource);
+  args->Add(new(Z) LoadLocalNode(
+      TokenPosition::kNoSource, exception_param.var));
+  args->Add(new(Z) LoadLocalNode(
+      TokenPosition::kNoSource, stack_trace_param.var));
   current_block_->statements->Add(
       new(Z) InstanceCallNode(try_end_pos,
-          new(Z) LoadLocalNode(Scanner::kNoSourcePos, controller),
+          new(Z) LoadLocalNode(TokenPosition::kNoSource, controller),
           Symbols::AddError(),
           args));
-  ReturnNode* return_node = new(Z) ReturnNode(Scanner::kNoSourcePos);
+  ReturnNode* return_node = new(Z) ReturnNode(TokenPosition::kNoSource);
   AddNodeForFinallyInlining(return_node);
   current_block_->statements->Add(return_node);
   AstNode* catch_block = CloseBlock();
@@ -6278,10 +6302,10 @@
   do {
     OpenBlock();
     ArgumentListNode* no_args =
-        new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+        new(Z) ArgumentListNode(TokenPosition::kNoSource);
     current_block_->statements->Add(
         new(Z) InstanceCallNode(try_end_pos,
-            new(Z) LoadLocalNode(Scanner::kNoSourcePos, controller),
+            new(Z) LoadLocalNode(TokenPosition::kNoSource, controller),
             Symbols::Close(),
             no_args));
 
@@ -6289,7 +6313,7 @@
     AwaitMarkerNode* await_marker =
         new(Z) AwaitMarkerNode(async_temp_scope_,
                                current_block_->scope,
-                               Scanner::kNoSourcePos);
+                               TokenPosition::kNoSource);
     current_block_->statements->Add(await_marker);
     ReturnNode* continuation_ret = new(Z) ReturnNode(try_end_pos);
     continuation_ret->set_return_type(ReturnNode::kContinuationTarget);
@@ -6320,7 +6344,7 @@
   handler_types.Add(Object::dynamic_type());
 
   CatchClauseNode* catch_clause = new(Z) CatchClauseNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       catch_handler_list,
       Array::ZoneHandle(Z, Array::MakeArray(handler_types)),
       context_var,
@@ -6334,7 +6358,7 @@
   const intptr_t try_index = try_statement->try_index();
 
   AstNode* try_catch_node =
-      new(Z) TryCatchNode(Scanner::kNoSourcePos,
+      new(Z) TryCatchNode(TokenPosition::kNoSource,
                           body,
                           context_var,
                           catch_clause,
@@ -6359,10 +6383,10 @@
   OpenBlock();  // Catch block.
   CatchParamDesc exception_param;
   CatchParamDesc stack_trace_param;
-  exception_param.token_pos = Scanner::kNoSourcePos;
+  exception_param.token_pos = TokenPosition::kNoSource;
   exception_param.type = &Object::dynamic_type();
   exception_param.name = &Symbols::ExceptionParameter();
-  stack_trace_param.token_pos = Scanner::kNoSourcePos;
+  stack_trace_param.token_pos = TokenPosition::kNoSource;
   stack_trace_param.type = &Object::dynamic_type();
   stack_trace_param.name = &Symbols::StackTraceParameter();
 
@@ -6380,9 +6404,9 @@
     // the exception variable specified in this block.
     ASSERT(exception_var != NULL);
     current_block_->statements->Add(new(Z) StoreLocalNode(
-        Scanner::kNoSourcePos,
+        TokenPosition::kNoSource,
         exception_param.var,
-        new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
+        new(Z) LoadLocalNode(TokenPosition::kNoSource, exception_var)));
   }
 
   LocalVariable* stack_trace_var =
@@ -6393,9 +6417,9 @@
     // trace variable specified in this block.
     ASSERT(stack_trace_var != NULL);
     current_block_->statements->Add(new(Z) StoreLocalNode(
-        Scanner::kNoSourcePos,
+        TokenPosition::kNoSource,
         stack_trace_param.var,
-        new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
+        new(Z) LoadLocalNode(TokenPosition::kNoSource, stack_trace_var)));
   }
   LocalVariable* saved_exception_var = try_scope->LocalLookupVariable(
       Symbols::SavedExceptionVar());
@@ -6413,17 +6437,18 @@
       Symbols::AsyncCompleter(), false);
   ASSERT(async_completer != NULL);
   ArgumentListNode* completer_args =
-      new (Z) ArgumentListNode(Scanner::kNoSourcePos);
+      new (Z) ArgumentListNode(TokenPosition::kNoSource);
   completer_args->Add(
-      new (Z) LoadLocalNode(Scanner::kNoSourcePos, exception_param.var));
+      new (Z) LoadLocalNode(TokenPosition::kNoSource, exception_param.var));
   completer_args->Add(
-      new (Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_param.var));
+      new (Z) LoadLocalNode(TokenPosition::kNoSource,
+                            stack_trace_param.var));
   current_block_->statements->Add(new (Z) InstanceCallNode(
       TokenPos(),
-      new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_completer),
+      new (Z) LoadLocalNode(TokenPosition::kNoSource, async_completer),
       Symbols::CompleterCompleteError(),
       completer_args));
-  ReturnNode* return_node = new (Z) ReturnNode(Scanner::kNoSourcePos);
+  ReturnNode* return_node = new (Z) ReturnNode(TokenPosition::kNoSource);
   // Behavior like a continuation return, i.e,. don't call a completer.
   return_node->set_return_type(ReturnNode::kContinuation);
   current_block_->statements->Add(return_node);
@@ -6440,7 +6465,7 @@
   const intptr_t try_index = try_statement->try_index();
 
   CatchClauseNode* catch_clause = new (Z) CatchClauseNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       catch_handler_list,
       Array::ZoneHandle(Z, Array::MakeArray(handler_types)),
       context_var,
@@ -6451,7 +6476,7 @@
       CatchClauseNode::kInvalidTryIndex,
       true);
   AstNode* try_catch_node = new (Z) TryCatchNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       try_block,
       context_var,
       catch_clause,
@@ -6497,7 +6522,9 @@
   // Add implicit closure parameter if not already present.
   if (params->parameters->length() == 0) {
     params->AddFinalParameter(
-        0, &Symbols::ClosureParameter(), &Object::dynamic_type());
+        TokenPosition::kMinSource,
+        &Symbols::ClosureParameter(),
+        &Object::dynamic_type());
   }
   ParamDesc iterator_param;
   iterator_param.name = &Symbols::IteratorParameter();
@@ -6514,7 +6541,7 @@
 }
 
 
-RawFunction* Parser::OpenSyncGeneratorFunction(intptr_t func_pos) {
+RawFunction* Parser::OpenSyncGeneratorFunction(TokenPosition func_pos) {
   Function& body = Function::Handle(Z);
   String& body_closure_name = String::Handle(Z);
   bool is_new_closure = false;
@@ -6551,19 +6578,12 @@
     // Add the parameters to the newly created closure.
     AddFormalParamsToFunction(&closure_params, body);
 
-    // Create and set the signature class of the closure.
-    const String& sig = String::Handle(Z, body.Signature());
-    Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
-    if (sig_cls.IsNull()) {
-      sig_cls = Class::NewSignatureClass(sig, body, script_, body.token_pos());
-      library_.AddClass(sig_cls);
-    }
-    body.set_signature_class(sig_cls);
-    // Finalize types in signature class here, so that the
-    // signature type is not computed twice.
-    ClassFinalizer::FinalizeTypesInClass(sig_cls);
-    const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
-    ASSERT(sig_type.IsFinalized());
+    // Finalize function type.
+    FunctionType& signature_type =
+        FunctionType::Handle(Z, body.SignatureType());
+    signature_type ^= ClassFinalizer::FinalizeType(
+        current_class(), signature_type, ClassFinalizer::kCanonicalize);
+    body.SetSignatureType(signature_type);
     ASSERT(AbstractType::Handle(Z, body.result_type()).IsResolved());
     ASSERT(body.NumParameters() == closure_params.parameters->length());
   }
@@ -6588,10 +6608,10 @@
   // :await_jump_var = -1;
   LocalVariable* jump_var =
       current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
-  LiteralNode* init_value =
-      new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+  LiteralNode* init_value = new(Z) LiteralNode(TokenPosition::kNoSource,
+                                               Smi::ZoneHandle(Smi::New(-1)));
   current_block_->statements->Add(
-      new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+      new(Z) StoreLocalNode(TokenPosition::kNoSource, jump_var, init_value));
 
   // return new SyncIterable(body_closure);
   const Class& iterable_class =
@@ -6605,17 +6625,18 @@
   const String& closure_name = String::Handle(Z, closure.name());
   ASSERT(closure_name.IsSymbol());
 
-  ArgumentListNode* arguments = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+  ArgumentListNode* arguments =
+      new(Z) ArgumentListNode(TokenPosition::kNoSource);
   ClosureNode* closure_obj = new(Z) ClosureNode(
-      Scanner::kNoSourcePos, closure, NULL, closure_body->scope());
+      TokenPosition::kNoSource, closure, NULL, closure_body->scope());
   arguments->Add(closure_obj);
   ConstructorCallNode* new_iterable =
-      new(Z) ConstructorCallNode(Scanner::kNoSourcePos,
+      new(Z) ConstructorCallNode(TokenPosition::kNoSource,
           TypeArguments::ZoneHandle(Z),
           iterable_constructor,
           arguments);
   ReturnNode* return_node =
-      new (Z) ReturnNode(Scanner::kNoSourcePos, new_iterable);
+      new (Z) ReturnNode(TokenPosition::kNoSource, new_iterable);
   current_block_->statements->Add(return_node);
   return CloseBlock();
 }
@@ -6630,7 +6651,9 @@
   // Add implicit closure parameter if not yet present.
   if (params->parameters->length() == 0) {
     params->AddFinalParameter(
-        0, &Symbols::ClosureParameter(), &Object::dynamic_type());
+        TokenPosition::kMinSource,
+        &Symbols::ClosureParameter(),
+        &Object::dynamic_type());
   }
   ParamDesc result_param;
   result_param.name = &Symbols::AsyncOperationParam();
@@ -6652,7 +6675,7 @@
 }
 
 
-RawFunction* Parser::OpenAsyncFunction(intptr_t async_func_pos) {
+RawFunction* Parser::OpenAsyncFunction(TokenPosition async_func_pos) {
   TRACE_PARSER("OpenAsyncFunction");
   AddContinuationVariables();
   AddAsyncClosureVariables();
@@ -6688,20 +6711,12 @@
     // Add the parameters to the newly created closure.
     AddFormalParamsToFunction(&closure_params, closure);
 
-    // Create and set the signature class of the closure.
-    const String& sig = String::Handle(Z, closure.Signature());
-    Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
-    if (sig_cls.IsNull()) {
-      sig_cls =
-          Class::NewSignatureClass(sig, closure, script_, closure.token_pos());
-      library_.AddClass(sig_cls);
-    }
-    closure.set_signature_class(sig_cls);
-    // Finalize types in signature class here, so that the
-    // signature type is not computed twice.
-    ClassFinalizer::FinalizeTypesInClass(sig_cls);
-    const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
-    ASSERT(sig_type.IsFinalized());
+    // Finalize function type.
+    FunctionType& signature_type =
+        FunctionType::Handle(Z, closure.SignatureType());
+    signature_type ^= ClassFinalizer::FinalizeType(
+        current_class(), signature_type, ClassFinalizer::kCanonicalize);
+    closure.SetSignatureType(signature_type);
     ASSERT(AbstractType::Handle(Z, closure.result_type()).IsResolved());
     ASSERT(closure.NumParameters() == closure_params.parameters->length());
   }
@@ -6717,10 +6732,12 @@
   //   var :await_jump_var;
   //   var :await_ctx_var;
   LocalVariable* await_jump_var = new (Z) LocalVariable(
-      Scanner::kNoSourcePos, Symbols::AwaitJumpVar(), Object::dynamic_type());
+      TokenPosition::kNoSource,
+      Symbols::AwaitJumpVar(),
+      Object::dynamic_type());
   current_block_->scope->AddVariable(await_jump_var);
   LocalVariable* await_ctx_var = new (Z) LocalVariable(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       Symbols::AwaitContextVar(),
       Object::dynamic_type());
   current_block_->scope->AddVariable(await_ctx_var);
@@ -6734,20 +6751,22 @@
   //   var :async_catch_error_callback;
   //   var :async_completer;
   LocalVariable* async_op_var = new(Z) LocalVariable(
-      Scanner::kNoSourcePos, Symbols::AsyncOperation(), Object::dynamic_type());
+      TokenPosition::kNoSource,
+      Symbols::AsyncOperation(),
+      Object::dynamic_type());
   current_block_->scope->AddVariable(async_op_var);
   LocalVariable* async_then_callback_var = new(Z) LocalVariable(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       Symbols::AsyncThenCallback(),
       Object::dynamic_type());
   current_block_->scope->AddVariable(async_then_callback_var);
   LocalVariable* async_catch_error_callback_var = new(Z) LocalVariable(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       Symbols::AsyncCatchErrorCallback(),
       Object::dynamic_type());
   current_block_->scope->AddVariable(async_catch_error_callback_var);
   LocalVariable* async_completer = new(Z) LocalVariable(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       Symbols::AsyncCompleter(),
       Object::dynamic_type());
   current_block_->scope->AddVariable(async_completer);
@@ -6766,25 +6785,30 @@
   // These variables are used to store the async generator closure containing
   // the body of the async* function. They are used by the await operator.
   LocalVariable* controller_var = new(Z) LocalVariable(
-      Scanner::kNoSourcePos, Symbols::Controller(), Object::dynamic_type());
+      TokenPosition::kNoSource,
+      Symbols::Controller(),
+      Object::dynamic_type());
   current_block_->scope->AddVariable(controller_var);
   LocalVariable* async_op_var = new(Z) LocalVariable(
-      Scanner::kNoSourcePos, Symbols::AsyncOperation(), Object::dynamic_type());
+      TokenPosition::kNoSource,
+      Symbols::AsyncOperation(),
+      Object::dynamic_type());
   current_block_->scope->AddVariable(async_op_var);
   LocalVariable* async_then_callback_var = new(Z) LocalVariable(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       Symbols::AsyncThenCallback(),
       Object::dynamic_type());
   current_block_->scope->AddVariable(async_then_callback_var);
   LocalVariable* async_catch_error_callback_var = new(Z) LocalVariable(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       Symbols::AsyncCatchErrorCallback(),
       Object::dynamic_type());
   current_block_->scope->AddVariable(async_catch_error_callback_var);
 }
 
 
-RawFunction* Parser::OpenAsyncGeneratorFunction(intptr_t async_func_pos) {
+RawFunction* Parser::OpenAsyncGeneratorFunction(
+    TokenPosition async_func_pos) {
   TRACE_PARSER("OpenAsyncGeneratorFunction");
   AddContinuationVariables();
   AddAsyncGeneratorVariables();
@@ -6823,20 +6847,12 @@
     // Add the parameters to the newly created closure.
     AddFormalParamsToFunction(&closure_params, closure);
 
-    // Create and set the signature class of the closure.
-    const String& sig = String::Handle(Z, closure.Signature());
-    Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
-    if (sig_cls.IsNull()) {
-      sig_cls =
-          Class::NewSignatureClass(sig, closure, script_, closure.token_pos());
-      library_.AddClass(sig_cls);
-    }
-    closure.set_signature_class(sig_cls);
-    // Finalize types in signature class here, so that the
-    // signature type is not computed twice.
-    ClassFinalizer::FinalizeTypesInClass(sig_cls);
-    const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
-    ASSERT(sig_type.IsFinalized());
+    // Finalize function type.
+    FunctionType& signature_type =
+        FunctionType::Handle(Z, closure.SignatureType());
+    signature_type ^= ClassFinalizer::FinalizeType(
+        current_class(), signature_type, ClassFinalizer::kCanonicalize);
+    closure.SetSignatureType(signature_type);
     ASSERT(AbstractType::Handle(Z, closure.result_type()).IsResolved());
     ASSERT(closure.NumParameters() == closure_params.parameters->length());
   }
@@ -6903,19 +6919,19 @@
   // :await_jump_var = -1;
   LocalVariable* jump_var =
       current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
-  LiteralNode* init_value =
-      new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+  LiteralNode* init_value = new(Z) LiteralNode(TokenPosition::kNoSource,
+                                               Smi::ZoneHandle(Smi::New(-1)));
   current_block_->statements->Add(
-      new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+      new(Z) StoreLocalNode(TokenPosition::kNoSource, jump_var, init_value));
 
   // Add to AST:
   //   :async_op = <closure>;  (containing the original body)
   LocalVariable* async_op_var =
       current_block_->scope->LookupVariable(Symbols::AsyncOperation(), false);
   ClosureNode* closure_obj = new(Z) ClosureNode(
-      Scanner::kNoSourcePos, closure_func, NULL, closure_body->scope());
+      TokenPosition::kNoSource, closure_func, NULL, closure_body->scope());
   StoreLocalNode* store_async_op = new (Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       async_op_var,
       closure_obj);
 
@@ -6927,18 +6943,18 @@
           Symbols::AsyncThenWrapperHelper()));
   ASSERT(!async_then_wrapper_helper.IsNull());
   ArgumentListNode* async_then_wrapper_helper_args = new (Z) ArgumentListNode(
-      Scanner::kNoSourcePos);
+      TokenPosition::kNoSource);
   async_then_wrapper_helper_args->Add(
-      new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+      new (Z) LoadLocalNode(TokenPosition::kNoSource, async_op_var));
   StaticCallNode* then_wrapper_call = new (Z) StaticCallNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       async_then_wrapper_helper,
       async_then_wrapper_helper_args);
   LocalVariable* async_then_callback_var =
       current_block_->scope->LookupVariable(
           Symbols::AsyncThenCallback(), false);
   StoreLocalNode* store_async_then_callback = new (Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       async_then_callback_var,
       then_wrapper_call);
 
@@ -6951,43 +6967,45 @@
           Symbols::AsyncErrorWrapperHelper()));
   ASSERT(!async_error_wrapper_helper.IsNull());
   ArgumentListNode* async_error_wrapper_helper_args = new (Z) ArgumentListNode(
-      Scanner::kNoSourcePos);
+      TokenPosition::kNoSource);
   async_error_wrapper_helper_args->Add(
-      new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+      new (Z) LoadLocalNode(TokenPosition::kNoSource, async_op_var));
   StaticCallNode* error_wrapper_call = new (Z) StaticCallNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       async_error_wrapper_helper,
       async_error_wrapper_helper_args);
   LocalVariable* async_catch_error_callback_var =
       current_block_->scope->LookupVariable(
           Symbols::AsyncCatchErrorCallback(), false);
   StoreLocalNode* store_async_catch_error_callback = new (Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       async_catch_error_callback_var,
       error_wrapper_call);
 
   current_block_->statements->Add(store_async_catch_error_callback);
 
   // :controller = new _AsyncStarStreamController(body_closure);
-  ArgumentListNode* arguments = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
-  arguments->Add(new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+  ArgumentListNode* arguments =
+      new(Z) ArgumentListNode(TokenPosition::kNoSource);
+  arguments->Add(
+      new (Z) LoadLocalNode(TokenPosition::kNoSource, async_op_var));
   ConstructorCallNode* controller_constructor_call =
-      new(Z) ConstructorCallNode(Scanner::kNoSourcePos,
+      new(Z) ConstructorCallNode(TokenPosition::kNoSource,
                                  TypeArguments::ZoneHandle(Z),
                                  controller_constructor,
                                  arguments);
   LocalVariable* controller_var =
      current_block_->scope->LookupVariable(Symbols::Controller(), false);
   StoreLocalNode* store_controller =
-      new(Z) StoreLocalNode(Scanner::kNoSourcePos,
+      new(Z) StoreLocalNode(TokenPosition::kNoSource,
                             controller_var,
                             controller_constructor_call);
   current_block_->statements->Add(store_controller);
 
   // return :controller.stream;
-  ReturnNode* return_node = new(Z) ReturnNode(Scanner::kNoSourcePos,
-      new(Z) InstanceGetterNode(Scanner::kNoSourcePos,
-          new(Z) LoadLocalNode(Scanner::kNoSourcePos,
+  ReturnNode* return_node = new(Z) ReturnNode(TokenPosition::kNoSource,
+      new(Z) InstanceGetterNode(TokenPosition::kNoSource,
+          new(Z) LoadLocalNode(TokenPosition::kNoSource,
               controller_var),
               Symbols::Stream()));
   current_block_->statements->Add(return_node);
@@ -7013,7 +7031,8 @@
 
 
 // Add a return node to the sequence if necessary.
-void Parser::EnsureHasReturnStatement(SequenceNode* seq, intptr_t return_pos) {
+void Parser::EnsureHasReturnStatement(SequenceNode* seq,
+                                      TokenPosition return_pos) {
   if ((seq->length() == 0) ||
       !seq->NodeAt(seq->length() - 1)->IsReturnNode()) {
     const Function& func = innermost_function();
@@ -7081,17 +7100,18 @@
   LocalVariable* async_completer = current_block_->scope->LookupVariable(
       Symbols::AsyncCompleter(), false);
 
+  const TokenPosition token_pos = ST(closure_body->token_pos());
   // Add to AST:
   //   :async_completer = new Completer.sync();
   ArgumentListNode* empty_args =
-      new (Z) ArgumentListNode(Scanner::kNoSourcePos);
+      new (Z) ArgumentListNode(token_pos);
   ConstructorCallNode* completer_constructor_node = new (Z) ConstructorCallNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       TypeArguments::ZoneHandle(Z),
       completer_constructor,
       empty_args);
   StoreLocalNode* store_completer = new (Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       async_completer,
       completer_constructor_node);
   current_block_->statements->Add(store_completer);
@@ -7100,18 +7120,19 @@
   LocalVariable* jump_var =
       current_block_->scope->LookupVariable(Symbols::AwaitJumpVar(), false);
   LiteralNode* init_value =
-      new(Z) LiteralNode(Scanner::kNoSourcePos, Smi::ZoneHandle(Smi::New(-1)));
+      new(Z) LiteralNode(token_pos,
+                         Smi::ZoneHandle(Smi::New(-1)));
   current_block_->statements->Add(
-      new(Z) StoreLocalNode(Scanner::kNoSourcePos, jump_var, init_value));
+      new(Z) StoreLocalNode(token_pos, jump_var, init_value));
 
   // Add to AST:
   //   :async_op = <closure>;  (containing the original body)
   LocalVariable* async_op_var = current_block_->scope->LookupVariable(
       Symbols::AsyncOperation(), false);
   ClosureNode* cn = new(Z) ClosureNode(
-      Scanner::kNoSourcePos, closure, NULL, closure_body->scope());
+      token_pos, closure, NULL, closure_body->scope());
   StoreLocalNode* store_async_op = new (Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       async_op_var,
       cn);
   current_block_->statements->Add(store_async_op);
@@ -7123,18 +7144,18 @@
           Symbols::AsyncThenWrapperHelper()));
   ASSERT(!async_then_wrapper_helper.IsNull());
   ArgumentListNode* async_then_wrapper_helper_args = new (Z) ArgumentListNode(
-      Scanner::kNoSourcePos);
+      token_pos);
   async_then_wrapper_helper_args->Add(
-      new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+      new (Z) LoadLocalNode(token_pos, async_op_var));
   StaticCallNode* then_wrapper_call = new (Z) StaticCallNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       async_then_wrapper_helper,
       async_then_wrapper_helper_args);
   LocalVariable* async_then_callback_var =
       current_block_->scope->LookupVariable(
           Symbols::AsyncThenCallback(), false);
   StoreLocalNode* store_async_then_callback = new (Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       async_then_callback_var,
       then_wrapper_call);
 
@@ -7147,18 +7168,18 @@
           Symbols::AsyncErrorWrapperHelper()));
   ASSERT(!async_error_wrapper_helper.IsNull());
   ArgumentListNode* async_error_wrapper_helper_args = new (Z) ArgumentListNode(
-      Scanner::kNoSourcePos);
+      token_pos);
   async_error_wrapper_helper_args->Add(
-      new (Z) LoadLocalNode(Scanner::kNoSourcePos, async_op_var));
+      new (Z) LoadLocalNode(token_pos, async_op_var));
   StaticCallNode* error_wrapper_call = new (Z) StaticCallNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       async_error_wrapper_helper,
       async_error_wrapper_helper_args);
   LocalVariable* async_catch_error_callback_var =
       current_block_->scope->LookupVariable(
           Symbols::AsyncCatchErrorCallback(), false);
   StoreLocalNode* store_async_catch_error_callback = new (Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       async_catch_error_callback_var,
       error_wrapper_call);
 
@@ -7166,22 +7187,22 @@
 
   // Add to AST:
   //   new Future.microtask(:async_op);
-  ArgumentListNode* arguments = new (Z) ArgumentListNode(Scanner::kNoSourcePos);
+  ArgumentListNode* arguments = new (Z) ArgumentListNode(token_pos);
   arguments->Add(new (Z) LoadLocalNode(
-      Scanner::kNoSourcePos, async_op_var));
+      token_pos, async_op_var));
   ConstructorCallNode* future_node = new (Z) ConstructorCallNode(
-      Scanner::kNoSourcePos, TypeArguments::ZoneHandle(Z), constructor,
+      token_pos, TypeArguments::ZoneHandle(Z), constructor,
       arguments);
   current_block_->statements->Add(future_node);
 
   // Add to AST:
   //   return :async_completer.future;
   ReturnNode* return_node = new (Z) ReturnNode(
-      Scanner::kNoSourcePos,
+      token_pos,
       new (Z) InstanceGetterNode(
-          Scanner::kNoSourcePos,
+          token_pos,
           new (Z) LoadLocalNode(
-              Scanner::kNoSourcePos,
+              token_pos,
               async_completer),
           Symbols::CompleterFuture()));
   current_block_->statements->Add(return_node);
@@ -7231,7 +7252,8 @@
   if (!Utils::IsInt(16, params->num_fixed_parameters) ||
       !Utils::IsInt(16, params->num_optional_parameters)) {
     const Script& script = Script::Handle(Class::Handle(func.Owner()).script());
-    Report::MessageF(Report::kError, script, func.token_pos(),
+    Report::MessageF(Report::kError,
+                     script, func.token_pos(), Report::AtLocation,
                      "too many formal parameters");
   }
   func.set_num_fixed_parameters(params->num_fixed_parameters);
@@ -7324,7 +7346,7 @@
 }
 
 
-AstNode* Parser::LoadReceiver(intptr_t token_pos) {
+AstNode* Parser::LoadReceiver(TokenPosition token_pos) {
   // A nested function may access 'this', referring to the receiver of the
   // outermost enclosing function.
   const bool kTestOnly = false;
@@ -7336,7 +7358,7 @@
 }
 
 
-InstanceGetterNode* Parser::CallGetter(intptr_t token_pos,
+InstanceGetterNode* Parser::CallGetter(TokenPosition token_pos,
                                        AstNode* object,
                                        const String& name) {
   return new(Z) InstanceGetterNode(token_pos, object, name);
@@ -7350,10 +7372,10 @@
                                           SequenceNode** await_preamble) {
   TRACE_PARSER("ParseVariableDeclaration");
   ASSERT(IsIdentifier());
-  const intptr_t ident_pos = TokenPos();
+  const TokenPosition ident_pos = TokenPos();
   const String& ident = *CurrentLiteral();
   ConsumeToken();  // Variable identifier.
-  const intptr_t assign_pos = TokenPos();
+  const TokenPosition assign_pos = TokenPos();
   AstNode* initialization = NULL;
   LocalVariable* variable = NULL;
   if (CurrentToken() == Token::kASSIGN) {
@@ -7361,7 +7383,7 @@
     ConsumeToken();
     AstNode* expr = ParseAwaitableExpr(
         is_const, kConsumeCascades, await_preamble);
-    const intptr_t expr_end_pos = TokenPos();
+    const TokenPosition expr_end_pos = TokenPos();
     variable = new(Z) LocalVariable(
         expr_end_pos, ident, type);
     initialization = new(Z) StoreLocalNode(
@@ -7383,9 +7405,9 @@
   }
 
   ASSERT(current_block_ != NULL);
-  const intptr_t previous_pos =
+  const TokenPosition previous_pos =
       current_block_->scope->PreviousReferencePos(ident);
-  if (previous_pos >= 0) {
+  if (previous_pos.IsReal()) {
     ASSERT(!script_.IsNull());
     if (previous_pos > ident_pos) {
       ReportError(ident_pos,
@@ -7467,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");
@@ -7512,8 +7534,8 @@
 
   result_type = Type::DynamicType();
 
-  const intptr_t function_pos = TokenPos();
-  intptr_t metadata_pos = Scanner::kNoSourcePos;
+  const TokenPosition function_pos = TokenPos();
+  TokenPosition metadata_pos = TokenPosition::kNoSource;
   if (is_literal) {
     ASSERT(CurrentToken() == Token::kLPAREN);
     function_name = &Symbols::AnonymousClosure();
@@ -7526,16 +7548,16 @@
                (LookaheadToken(1) != Token::kLPAREN)) {
       result_type = ParseType(ClassFinalizer::kCanonicalize);
     }
-    const intptr_t name_pos = TokenPos();
+    const TokenPosition name_pos = TokenPos();
     variable_name = ExpectIdentifier("function name expected");
     function_name = variable_name;
 
     // Check that the function name has not been referenced
     // before this declaration.
     ASSERT(current_block_ != NULL);
-    const intptr_t previous_pos =
+    const TokenPosition previous_pos =
         current_block_->scope->PreviousReferencePos(*function_name);
-    if (previous_pos >= 0) {
+    if (previous_pos.IsReal()) {
       ASSERT(!script_.IsNull());
       intptr_t line_number;
       script_.GetTokenLocation(previous_pos, &line_number, NULL);
@@ -7553,7 +7575,6 @@
   // Note that we cannot share the same closure function between the closurized
   // and non-closurized versions of the same parent function.
   Function& function = Function::ZoneHandle(Z);
-  bool is_new_closure = false;
   // TODO(hausner): There could be two different closures at the given
   // function_pos, one enclosed in a closurized function and one enclosed in the
   // non-closurized version of this same function.
@@ -7562,12 +7583,11 @@
     // The function will be registered in the lookup table by the
     // EffectGraphVisitor::VisitClosureNode when the newly allocated closure
     // function has been properly setup.
-    is_new_closure = true;
     function = Function::NewClosureFunction(*function_name,
                                             innermost_function(),
                                             function_pos);
     function.set_result_type(result_type);
-    if (FLAG_enable_mirrors && (metadata_pos >= 0)) {
+    if (FLAG_enable_mirrors && metadata_pos.IsReal()) {
       library_.AddFunctionMetadata(function, metadata_pos);
     }
   }
@@ -7577,17 +7597,19 @@
   // passed as a function argument, or returned as a function result.
 
   LocalVariable* function_variable = NULL;
-  Type& function_type = Type::ZoneHandle(Z);
+  FunctionType& function_type = FunctionType::ZoneHandle(Z);
   if (variable_name != NULL) {
     // Since the function type depends on the signature of the closure function,
     // it cannot be determined before the formal parameter list of the closure
     // function is parsed. Therefore, we set the function type to a new
-    // parameterized type to be patched after the actual type is known.
-    // We temporarily use the class of the Function interface.
-    const Class& unknown_signature_class = Class::Handle(Z,
-        Type::Handle(Z, Type::Function()).type_class());
-    function_type = Type::New(unknown_signature_class,
-                              TypeArguments::Handle(Z), function_pos);
+    // function type to be patched after the actual type is known.
+    // We temporarily use the Closure class as scope class.
+    const Class& unknown_scope_class = Class::Handle(Z,
+        I->object_store()->closure_class());
+    function_type = FunctionType::New(unknown_scope_class,
+                                      TypeArguments::Handle(Z),
+                                      function,
+                                      function_pos);
     function_type.SetIsFinalized();  // No finalization needed.
 
     // Add the function variable to the scope before parsing the function in
@@ -7611,52 +7633,28 @@
   }
 
   // Parse the local function.
-  SequenceNode* statements = Parser::ParseFunc(function);
+  SequenceNode* statements = Parser::ParseFunc(function, !is_literal);
   INC_STAT(thread(), num_functions_parsed, 1);
 
   // Now that the local function has formal parameters, lookup the signature
-  // class in the current library (but not in its imports) and only create a new
-  // canonical signature class if it does not exist yet.
-  const String& signature = String::Handle(Z, function.Signature());
-  Class& signature_class = Class::ZoneHandle(Z);
-  if (!is_new_closure) {
-    signature_class = function.signature_class();
-  }
-  if (signature_class.IsNull()) {
-    signature_class = library_.LookupLocalClass(signature);
-  }
-  if (signature_class.IsNull()) {
-    // If we don't have a signature class yet, this must be a closure we
-    // have not parsed before.
-    ASSERT(is_new_closure);
-    signature_class = Class::NewSignatureClass(signature,
-                                               function,
-                                               script_,
-                                               function.token_pos());
-    // Record the function signature class in the current library.
-    library_.AddClass(signature_class);
-  } else if (is_new_closure) {
-    function.set_signature_class(signature_class);
-  }
-  ASSERT(function.signature_class() == signature_class.raw());
+  FunctionType& signature_type =
+      FunctionType::ZoneHandle(Z, function.SignatureType());
+  signature_type ^= ClassFinalizer::FinalizeType(
+      current_class(), signature_type, ClassFinalizer::kCanonicalize);
+  function.SetSignatureType(signature_type);
 
   // Local functions are registered in the enclosing class, but
   // ignored during class finalization. The enclosing class has
   // already been finalized.
   ASSERT(current_class().is_finalized());
+  ASSERT(signature_type.IsFinalized());
 
   // Make sure that the instantiator is captured.
-  if ((signature_class.NumTypeParameters() > 0) &&
-      (current_block_->scope->function_level() > 0)) {
+  if ((current_block_->scope->function_level() > 0) &&
+      Class::Handle(signature_type.type_class()).IsGeneric()) {
     CaptureInstantiator();
   }
 
-  // Finalize types in signature class here, so that the
-  // signature type is not computed twice.
-  ClassFinalizer::FinalizeTypesInClass(signature_class);
-  const Type& signature_type = Type::Handle(Z, signature_class.SignatureType());
-  ASSERT(signature_type.IsFinalized());
-
   // A signature type itself cannot be malformed or malbounded, only its
   // signature function's result type or parameter types may be.
   ASSERT(!signature_type.IsMalformed());
@@ -7664,9 +7662,11 @@
 
   if (variable_name != NULL) {
     // Patch the function type of the variable now that the signature is known.
-    function_type.set_type_class(signature_class);
+    function_type.set_scope_class(
+        Class::Handle(Z, signature_type.scope_class()));
     function_type.set_arguments(
         TypeArguments::Handle(Z, signature_type.arguments()));
+    ASSERT(function_type.signature() == function.raw());
 
     // The function type was initially marked as instantiated, but it may
     // actually be uninstantiated.
@@ -7863,7 +7863,7 @@
   }
   // Skip optional metadata.
   if (CurrentToken() == Token::kAT) {
-    const intptr_t saved_pos = TokenPos();
+    const TokenPosition saved_pos = TokenPos();
     SkipMetadata();
     const bool is_var_decl = IsVariableDeclaration();
     SetPosition(saved_pos);
@@ -7873,7 +7873,7 @@
     // Not a legal type identifier or const keyword or metadata.
     return false;
   }
-  const intptr_t saved_pos = TokenPos();
+  const TokenPosition saved_pos = TokenPos();
   bool is_var_decl = false;
   bool have_type = false;
   if (CurrentToken() == Token::kCONST) {
@@ -7886,7 +7886,7 @@
         (follower == Token::kPERIOD) ||  // Qualified class name of type.
         Token::IsIdentifier(follower)) {  // Variable name following a type.
       // We see the beginning of something that could be a type.
-      const intptr_t type_pos = TokenPos();
+      const TokenPosition type_pos = TokenPos();
       if (TryParseOptionalType()) {
         have_type = true;
       } else {
@@ -7910,7 +7910,7 @@
 // Look ahead to detect whether the next tokens should be parsed as
 // a function declaration. Token position remains unchanged.
 bool Parser::IsFunctionDeclaration() {
-  const intptr_t saved_pos = TokenPos();
+  const TokenPosition saved_pos = TokenPos();
   bool is_external = false;
   SkipMetadata();
   if (is_top_level_) {
@@ -7958,7 +7958,7 @@
 
 
 bool Parser::IsTopLevelAccessor() {
-  const intptr_t saved_pos = TokenPos();
+  const TokenPosition saved_pos = TokenPos();
   if (is_patch_source() && IsSymbol(Symbols::Patch())) {
     ConsumeToken();
   } else if (CurrentToken() == Token::kEXTERNAL) {
@@ -7985,7 +7985,7 @@
   if (CurrentToken() != Token::kLPAREN || !allow_function_literals_) {
     return false;
   }
-  const intptr_t saved_pos = TokenPos();
+  const TokenPosition saved_pos = TokenPos();
   bool is_function_literal = false;
   SkipToMatchingParenthesis();
   ParseFunctionModifier();
@@ -8002,7 +8002,7 @@
 // statement. Returns true if we recognize a for ( .. in expr)
 // statement.
 bool Parser::IsForInStatement() {
-  const intptr_t saved_pos = TokenPos();
+  const TokenPosition saved_pos = TokenPos();
   bool result = false;
   // Allow const modifier as well when recognizing a for-in statement
   // pattern. We will get an error later if the loop variable is
@@ -8052,8 +8052,9 @@
   TRACE_PARSER("ParseStatementSequence");
   const bool dead_code_allowed = true;
   bool abrupt_completing_seen = false;
+  RecursionChecker rc(this);
   while (CurrentToken() != Token::kRBRACE) {
-    const intptr_t statement_pos = TokenPos();
+    const TokenPosition statement_pos = TokenPos();
     AstNode* statement = ParseStatement();
     // Do not add statements with no effect (e.g., LoadLocalNode).
     if ((statement != NULL) && statement->IsLoadLocalNode()) {
@@ -8091,6 +8092,7 @@
     ParseStatementSequence();
     ExpectToken(Token::kRBRACE);
   } else {
+    RecursionChecker rc(this);
     AstNode* statement = ParseStatement();
     if (statement != NULL) {
       current_block_->statements->Add(statement);
@@ -8104,7 +8106,7 @@
 AstNode* Parser::ParseIfStatement(String* label_name) {
   TRACE_PARSER("ParseIfStatement");
   ASSERT(CurrentToken() == Token::kIF);
-  const intptr_t if_pos = TokenPos();
+  const TokenPosition if_pos = TokenPos();
   SourceLabel* label = NULL;
   if (label_name != NULL) {
     label = SourceLabel::New(if_pos, label_name, SourceLabel::kStatement);
@@ -8159,7 +8161,7 @@
   const Instance& first_value = values[0]->literal();
   for (intptr_t i = 0; i < num_expressions; i++) {
     const Instance& val = values[i]->literal();
-    const intptr_t val_pos = values[i]->token_pos();
+    const TokenPosition val_pos = values[i]->token_pos();
     if (first_value.IsInteger()) {
       if (!val.IsInteger()) {
         ReportError(val_pos, "expected case expression of type int");
@@ -8207,7 +8209,7 @@
                                   SourceLabel* case_label) {
   TRACE_PARSER("ParseCaseClause");
   bool default_seen = false;
-  const intptr_t case_pos = TokenPos();
+  const TokenPosition case_pos = TokenPos();
   // The case expressions node sequence does not own the enclosing scope.
   SequenceNode* case_expressions = new(Z) SequenceNode(case_pos, NULL);
   while (CurrentToken() == Token::kCASE || CurrentToken() == Token::kDEFAULT) {
@@ -8216,7 +8218,7 @@
         ReportError("default clause must be last case");
       }
       ConsumeToken();  // Keyword case.
-      const intptr_t expr_pos = TokenPos();
+      const TokenPosition expr_pos = TokenPos();
       AstNode* expr = ParseExpr(kRequireConst, kConsumeCascades);
       ASSERT(expr->IsLiteralNode());
       case_expr_values->Add(expr->AsLiteralNode());
@@ -8259,7 +8261,8 @@
       if (!abrupt_completing_seen) {
         ArgumentListNode* arguments = new(Z) ArgumentListNode(TokenPos());
         arguments->Add(new(Z) LiteralNode(
-            TokenPos(), Integer::ZoneHandle(Z, Integer::New(TokenPos()))));
+            TokenPos(),
+            Integer::ZoneHandle(Z, Integer::New(TokenPos().value()))));
         current_block_->statements->Add(
             MakeStaticCall(Symbols::FallThroughError(),
                            Library::PrivateCoreLibName(Symbols::ThrowNew()),
@@ -8283,12 +8286,12 @@
 AstNode* Parser::ParseSwitchStatement(String* label_name) {
   TRACE_PARSER("ParseSwitchStatement");
   ASSERT(CurrentToken() == Token::kSWITCH);
-  const intptr_t switch_pos = TokenPos();
+  const TokenPosition switch_pos = TokenPos();
   SourceLabel* label =
       SourceLabel::New(switch_pos, label_name, SourceLabel::kSwitch);
   ConsumeToken();
   ExpectToken(Token::kLPAREN);
-  const intptr_t expr_pos = TokenPos();
+  const TokenPosition expr_pos = TokenPos();
   AstNode* switch_expr = ParseAwaitableExpr(
       kAllowConst, kConsumeCascades, NULL);
   ExpectToken(Token::kRPAREN);
@@ -8322,7 +8325,7 @@
     if (IsIdentifier() && LookaheadToken(1) == Token::kCOLON) {
       // Case statements start with a label.
       String* label_name = CurrentLiteral();
-      const intptr_t label_pos = TokenPos();
+      const TokenPosition label_pos = TokenPos();
       ConsumeToken();  // Consume label identifier.
       ConsumeToken();  // Consume colon.
       case_label = current_block_->scope->LocalLookupLabel(*label_name);
@@ -8382,7 +8385,7 @@
 
 AstNode* Parser::ParseWhileStatement(String* label_name) {
   TRACE_PARSER("ParseWhileStatement");
-  const intptr_t while_pos = TokenPos();
+  const TokenPosition while_pos = TokenPos();
   SourceLabel* label =
       SourceLabel::New(while_pos, label_name, SourceLabel::kWhile);
   ConsumeToken();
@@ -8404,7 +8407,7 @@
 
 AstNode* Parser::ParseDoWhileStatement(String* label_name) {
   TRACE_PARSER("ParseDoWhileStatement");
-  const intptr_t do_pos = TokenPos();
+  const TokenPosition do_pos = TokenPos();
   SourceLabel* label =
       SourceLabel::New(do_pos, label_name, SourceLabel::kDoWhile);
   ConsumeToken();
@@ -8413,7 +8416,7 @@
   ExpectToken(Token::kWHILE);
   ExpectToken(Token::kLPAREN);
   SequenceNode* await_preamble = NULL;
-  intptr_t expr_pos = TokenPos();
+  TokenPosition expr_pos = TokenPos();
   AstNode* cond_expr =
       ParseAwaitableExpr(kAllowConst, kConsumeCascades, &await_preamble);
   if (await_preamble != NULL) {
@@ -8514,11 +8517,12 @@
   const Function& print_fn = Function::ZoneHandle(
       Z, lib.LookupFunctionAllowPrivate(Symbols::print()));
   ASSERT(!print_fn.IsNull());
-  ArgumentListNode* one_arg = new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+  ArgumentListNode* one_arg =
+      new(Z) ArgumentListNode(TokenPosition::kNoSource);
   String& msg = String::ZoneHandle(Symbols::NewFormatted("%s", str));
-  one_arg->Add(new(Z) LiteralNode(Scanner::kNoSourcePos, msg));
+  one_arg->Add(new(Z) LiteralNode(TokenPosition::kNoSource, msg));
   AstNode* print_call =
-      new(Z) StaticCallNode(Scanner::kNoSourcePos, print_fn, one_arg);
+      new(Z) StaticCallNode(TokenPosition::kNoSource, print_fn, one_arg);
   return print_call;
 }
 
@@ -8526,7 +8530,7 @@
 AstNode* Parser::ParseAwaitForStatement(String* label_name) {
   TRACE_PARSER("ParseAwaitForStatement");
   ASSERT(IsAwaitKeyword());
-  const intptr_t await_for_pos = TokenPos();
+  const TokenPosition await_for_pos = TokenPos();
   ConsumeToken();  // await.
   ASSERT(CurrentToken() == Token::kFOR);
   ConsumeToken();  // for.
@@ -8553,15 +8557,15 @@
     // 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);
   }
-  intptr_t loop_var_pos = TokenPos();
+  TokenPosition loop_var_pos = TokenPos();
   const String* loop_var_name = ExpectIdentifier("variable name expected");
 
   // Parse stream expression.
   ExpectToken(Token::kIN);
-  const intptr_t stream_expr_pos = TokenPos();
+  const TokenPosition stream_expr_pos = TokenPos();
   AstNode* stream_expr =
       ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
   ExpectToken(Token::kRPAREN);
@@ -8658,7 +8662,7 @@
   SourceLabel* label =
       SourceLabel::New(await_for_pos, label_name, SourceLabel::kFor);
   current_block_->scope->AddLabel(label);
-  const intptr_t loop_var_assignment_pos = TokenPos();
+  const TokenPosition loop_var_assignment_pos = TokenPos();
 
   AstNode* iterator_current = new(Z) InstanceGetterNode(
       loop_var_assignment_pos,
@@ -8723,9 +8727,9 @@
 
   if (outer_saved_try_ctx != NULL) {
     catch_block->Add(new (Z) StoreLocalNode(
-        Scanner::kNoSourcePos,
+        TokenPosition::kNoSource,
         outer_saved_try_ctx,
-        new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+        new (Z) LoadLocalNode(TokenPosition::kNoSource,
                               outer_async_saved_try_ctx)));
   }
 
@@ -8746,7 +8750,7 @@
       outer_try->try_index() : CatchClauseNode::kInvalidTryIndex;
 
   // The finally block contains a call to cancel the stream.
-  // :for-in-iter.cancel()
+  // :for-in-iter.cancel();
 
   // Inline the finally block to the exit points in the try block.
   intptr_t node_index = 0;
@@ -8756,18 +8760,30 @@
   }
   do {
     OpenBlock();
+
+    // Restore the saved try context of the enclosing try block if one
+    // exists.
+    if (outer_saved_try_ctx != NULL) {
+      current_block_->statements->Add(new (Z) StoreLocalNode(
+          TokenPosition::kNoSource,
+          outer_saved_try_ctx,
+          new (Z) LoadLocalNode(TokenPosition::kNoSource,
+                                outer_async_saved_try_ctx)));
+    }
+    // :for-in-iter.cancel();
     ArgumentListNode* no_args =
-        new(Z) ArgumentListNode(Scanner::kNoSourcePos);
+        new(Z) ArgumentListNode(TokenPosition::kNoSource);
     current_block_->statements->Add(
-        new(Z) InstanceCallNode(Scanner::kNoSourcePos,
-            new(Z) LoadLocalNode(Scanner::kNoSourcePos, iterator_var),
+        new(Z) InstanceCallNode(TokenPosition::kNoSource,
+            new(Z) LoadLocalNode(TokenPosition::kNoSource, iterator_var),
             Symbols::Cancel(),
             no_args));
     finally_clause = CloseBlock();
+
     AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
     if (node_to_inline != NULL) {
       InlinedFinallyNode* node =
-          new(Z) InlinedFinallyNode(Scanner::kNoSourcePos,
+          new(Z) InlinedFinallyNode(TokenPosition::kNoSource,
                                     finally_clause,
                                     context_var,
                                     outer_try_index);
@@ -8815,7 +8831,7 @@
 }
 
 
-AstNode* Parser::ParseForInStatement(intptr_t forin_pos,
+AstNode* Parser::ParseForInStatement(TokenPosition forin_pos,
                                      SourceLabel* label) {
   TRACE_PARSER("ParseForInStatement");
   bool loop_var_is_final = (CurrentToken() == Token::kFINAL);
@@ -8823,7 +8839,7 @@
     ReportError("Loop variable cannot be 'const'");
   }
   const String* loop_var_name = NULL;
-  intptr_t loop_var_pos = Scanner::kNoSourcePos;
+  TokenPosition loop_var_pos = TokenPosition::kNoSource;
   bool new_loop_var = false;
   AbstractType& loop_var_type =  AbstractType::ZoneHandle(Z);
   if (LookaheadToken(1) == Token::kIN) {
@@ -8835,12 +8851,12 @@
     // 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");
   }
   ExpectToken(Token::kIN);
-  const intptr_t collection_pos = TokenPos();
+  const TokenPosition collection_pos = TokenPos();
   AstNode* collection_expr =
       ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
   ExpectToken(Token::kRPAREN);
@@ -8879,7 +8895,7 @@
   // loop body.
   OpenLoopBlock();
   current_block_->scope->AddLabel(label);
-  const intptr_t loop_var_assignment_pos = TokenPos();
+  const TokenPosition loop_var_assignment_pos = TokenPos();
 
   AstNode* iterator_current = new(Z) InstanceGetterNode(
       loop_var_assignment_pos,
@@ -8937,7 +8953,7 @@
 
 AstNode* Parser::ParseForStatement(String* label_name) {
   TRACE_PARSER("ParseForStatement");
-  const intptr_t for_pos = TokenPos();
+  const TokenPosition for_pos = TokenPos();
   ConsumeToken();
   ExpectToken(Token::kLPAREN);
   SourceLabel* label = SourceLabel::New(for_pos, label_name, SourceLabel::kFor);
@@ -8948,7 +8964,7 @@
   // that we allocate a new context if the loop variable is captured.
   OpenLoopBlock();
   AstNode* initializer = NULL;
-  const intptr_t init_pos = TokenPos();
+  const TokenPosition init_pos = TokenPos();
   LocalScope* init_scope = current_block_->scope;
   if (CurrentToken() != Token::kSEMICOLON) {
     if (IsVariableDeclaration()) {
@@ -8966,7 +8982,7 @@
   }
   ExpectSemicolon();
   AstNode* increment = NULL;
-  const intptr_t incr_pos = TokenPos();
+  const TokenPosition incr_pos = TokenPos();
   if (CurrentToken() != Token::kRPAREN) {
     increment = ParseAwaitableExprList();
   }
@@ -9019,12 +9035,12 @@
 }
 
 
-AstNode* Parser::MakeAssertCall(intptr_t begin, intptr_t end) {
+AstNode* Parser::MakeAssertCall(TokenPosition begin, TokenPosition end) {
   ArgumentListNode* arguments = new(Z) ArgumentListNode(begin);
   arguments->Add(new(Z) LiteralNode(begin,
-      Integer::ZoneHandle(Z, Integer::New(begin))));
+      Integer::ZoneHandle(Z, Integer::New(begin.value()))));
   arguments->Add(new(Z) LiteralNode(end,
-      Integer::ZoneHandle(Z, Integer::New(end))));
+      Integer::ZoneHandle(Z, Integer::New(end.value()))));
   return MakeStaticCall(Symbols::AssertionError(),
                         Library::PrivateCoreLibName(Symbols::ThrowNew()),
                         arguments);
@@ -9036,7 +9052,7 @@
       (condition->IsStoreLocalNode() &&
        condition->AsStoreLocalNode()->value()->IsClosureNode())) {
     // Function literal in assert implies a call.
-    const intptr_t pos = condition->token_pos();
+    const TokenPosition pos = condition->token_pos();
     condition = BuildClosureCall(pos,
                                  condition,
                                  new(Z) ArgumentListNode(pos));
@@ -9053,14 +9069,14 @@
   TRACE_PARSER("ParseAssertStatement");
   ConsumeToken();  // Consume assert keyword.
   ExpectToken(Token::kLPAREN);
-  const intptr_t condition_pos = TokenPos();
-  if (!I->flags().asserts()) {
+  const TokenPosition condition_pos = TokenPos();
+  if (!I->asserts()) {
     SkipExpr();
     ExpectToken(Token::kRPAREN);
     return NULL;
   }
   AstNode* condition = ParseAwaitableExpr(kAllowConst, kConsumeCascades, NULL);
-  const intptr_t condition_end = TokenPos();
+  const TokenPosition condition_end = TokenPos();
   ExpectToken(Token::kRPAREN);
   condition = InsertClosureCallNodes(condition);
   condition = new(Z) UnaryOpNode(condition_pos, Token::kNOT, condition);
@@ -9124,16 +9140,16 @@
   ASSERT(saved_exception_var != NULL);
   ASSERT(exception_var != NULL);
   statements->Add(new(Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       saved_exception_var,
-      new(Z) LoadLocalNode(Scanner::kNoSourcePos, exception_var)));
+      new(Z) LoadLocalNode(TokenPosition::kNoSource, exception_var)));
 
   ASSERT(saved_stack_trace_var != NULL);
   ASSERT(stack_trace_var != NULL);
   statements->Add(new(Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       saved_stack_trace_var,
-      new(Z) LoadLocalNode(Scanner::kNoSourcePos, stack_trace_var)));
+      new(Z) LoadLocalNode(TokenPosition::kNoSource, stack_trace_var)));
 }
 
 
@@ -9154,7 +9170,7 @@
   if (try_stack_ != NULL) {
     try_stack_->enter_finally();
   }
-  // In case of async closures we need to restore the saved try index of an
+  // In case of async closures we need to restore the saved try context of an
   // outer try block (if it exists).  The current try block has already been
   // removed from the stack of try blocks.
   if (is_async) {
@@ -9168,9 +9184,9 @@
                                           try_stack_->try_index());
         current_block_->statements->Add(
             new (Z) StoreLocalNode(
-                Scanner::kNoSourcePos,
+                TokenPosition::kNoSource,
                 saved_try_ctx,
-                new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+                new (Z) LoadLocalNode(TokenPosition::kNoSource,
                                       async_saved_try_ctx)));
       }
     }
@@ -9254,7 +9270,7 @@
 
 
 SequenceNode* Parser::ParseCatchClauses(
-    intptr_t handler_pos,
+    TokenPosition handler_pos,
     bool is_async,
     LocalVariable* exception_var,
     LocalVariable* stack_trace_var,
@@ -9274,7 +9290,7 @@
     // Open a block that contains the if or an unconditional body.  It's
     // closed in the loop that builds the if-then-else nest.
     OpenBlock();
-    const intptr_t catch_pos = TokenPos();
+    const TokenPosition catch_pos = TokenPos();
     CatchParamDesc exception_param;
     CatchParamDesc stack_trace_param;
     if (IsSymbol(Symbols::On())) {
@@ -9441,9 +9457,9 @@
                                           try_block->try_index());
         async_code->Add(
             new (Z) StoreLocalNode(
-                Scanner::kNoSourcePos,
+                TokenPosition::kNoSource,
                 saved_try_ctx,
-                new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+                new (Z) LoadLocalNode(TokenPosition::kNoSource,
                                       async_saved_try_ctx)));
       }
     }
@@ -9470,16 +9486,16 @@
                            Symbols::AsyncSavedTryCtxVarPrefix().ToCString(),
                            last_used_try_index_ - 1));
   LocalVariable* async_saved_try_ctx = new (Z) LocalVariable(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       async_saved_try_ctx_name,
       Object::dynamic_type());
   ASSERT(async_temp_scope_ != NULL);
   async_temp_scope_->AddVariable(async_saved_try_ctx);
   ASSERT(saved_try_context != NULL);
   current_block_->statements->Add(new(Z) StoreLocalNode(
-      Scanner::kNoSourcePos,
+      TokenPosition::kNoSource,
       async_saved_try_ctx,
-      new(Z) LoadLocalNode(Scanner::kNoSourcePos, saved_try_context)));
+      new(Z) LoadLocalNode(TokenPosition::kNoSource, saved_try_context)));
 }
 
 
@@ -9558,7 +9574,7 @@
 AstNode* Parser::ParseTryStatement(String* label_name) {
   TRACE_PARSER("ParseTryStatement");
 
-  const intptr_t try_pos = TokenPos();
+  const TokenPosition try_pos = TokenPos();
   SourceLabel* try_label = NULL;
   if (label_name != NULL) {
     try_label = SourceLabel::New(try_pos, label_name, SourceLabel::kStatement);
@@ -9607,7 +9623,7 @@
 
   // Now parse the 'catch' blocks if any.
   try_stack_->enter_catch();
-  const intptr_t handler_pos = TokenPos();
+  const TokenPosition handler_pos = TokenPos();
   const GrowableObjectArray& handler_types =
       GrowableObjectArray::Handle(Z, GrowableObjectArray::New(Heap::kOld));
   bool needs_stack_trace = false;
@@ -9638,7 +9654,7 @@
     if (parse) {
       ConsumeToken();  // Consume the 'finally'.
     }
-    const intptr_t finally_pos = TokenPos();
+    const TokenPosition finally_pos = TokenPos();
     // Add the finally block to the exit points recorded so far.
     intptr_t node_index = 0;
     AstNode* node_to_inline = try_statement->GetNodeToInlineFinally(node_index);
@@ -9718,7 +9734,7 @@
   TRACE_PARSER("ParseJump");
   ASSERT(CurrentToken() == Token::kBREAK || CurrentToken() == Token::kCONTINUE);
   Token::Kind jump_kind = CurrentToken();
-  const intptr_t jump_pos = TokenPos();
+  const TokenPosition jump_pos = TokenPos();
   SourceLabel* target = NULL;
   ConsumeToken();
   if (IsIdentifier()) {
@@ -9783,7 +9799,7 @@
 
 AstNode* Parser::ParseYieldStatement() {
   bool is_yield_each = false;
-  const intptr_t yield_pos = TokenPos();
+  const TokenPosition yield_pos = TokenPos();
   ConsumeToken();  // yield reserved word.
   if (CurrentToken() == Token::kMUL) {
     is_yield_each = true;
@@ -9808,17 +9824,18 @@
     ASSERT(iterator_param != NULL);
     // Generate :iterator.current = expr;
     AstNode* iterator =
-        new(Z) LoadLocalNode(Scanner::kNoSourcePos, iterator_param);
+        new(Z) LoadLocalNode(TokenPosition::kNoSource, iterator_param);
     AstNode* store_current =
-        new(Z) InstanceSetterNode(Scanner::kNoSourcePos,
+        new(Z) InstanceSetterNode(TokenPosition::kNoSource,
                                   iterator,
-                                  String::ZoneHandle(Symbols::Current().raw()),
+                                  Library::PrivateCoreLibName(
+                                      Symbols::_current()),
                                   expr);
     yield->AddNode(store_current);
     if (is_yield_each) {
       // Generate :iterator.isYieldEach = true;
       AstNode* set_is_yield_each =
-          new(Z) InstanceSetterNode(Scanner::kNoSourcePos,
+          new(Z) InstanceSetterNode(TokenPosition::kNoSource,
               iterator,
               String::ZoneHandle(Symbols::IsYieldEach().raw()),
               new(Z) LiteralNode(TokenPos(), Bool::True()));
@@ -9827,7 +9844,7 @@
     AwaitMarkerNode* await_marker =
         new(Z) AwaitMarkerNode(async_temp_scope_,
                                current_block_->scope,
-                               Scanner::kNoSourcePos);
+                               TokenPosition::kNoSource);
     yield->AddNode(await_marker);
     // Return true to indicate that a value has been generated.
     ReturnNode* return_true = new(Z) ReturnNode(yield_pos,
@@ -9848,15 +9865,15 @@
                            &outer_async_saved_try_ctx);
     if (saved_try_ctx != NULL) {
       yield->AddNode(new (Z) StoreLocalNode(
-          Scanner::kNoSourcePos,
+          TokenPosition::kNoSource,
           saved_try_ctx,
-          new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+          new (Z) LoadLocalNode(TokenPosition::kNoSource,
                                 async_saved_try_ctx)));
       if (outer_saved_try_ctx != NULL) {
         yield->AddNode(new (Z) StoreLocalNode(
-            Scanner::kNoSourcePos,
+            TokenPosition::kNoSource,
             outer_saved_try_ctx,
-            new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+            new (Z) LoadLocalNode(TokenPosition::kNoSource,
                                   outer_async_saved_try_ctx)));
       }
     } else {
@@ -9874,7 +9891,7 @@
     add_args->Add(expr);
     AstNode* add_call =
         new(Z) InstanceCallNode(yield_pos,
-            new(Z) LoadLocalNode(Scanner::kNoSourcePos, controller_var),
+            new(Z) LoadLocalNode(TokenPosition::kNoSource, controller_var),
             is_yield_each ? Symbols::AddStream() : Symbols::add(),
             add_args);
 
@@ -9886,18 +9903,18 @@
     // restore saved_try_context
 
     SequenceNode* true_branch =
-        new(Z) SequenceNode(Scanner::kNoSourcePos, NULL);
+        new(Z) SequenceNode(TokenPosition::kNoSource, NULL);
     AstNode* return_from_generator = new(Z) ReturnNode(yield_pos);
     true_branch->Add(return_from_generator);
     AddNodeForFinallyInlining(return_from_generator);
     AstNode* if_is_cancelled =
-       new(Z) IfNode(Scanner::kNoSourcePos, add_call, true_branch, NULL);
+       new(Z) IfNode(TokenPosition::kNoSource, add_call, true_branch, NULL);
     yield->AddNode(if_is_cancelled);
 
     AwaitMarkerNode* await_marker =
         new(Z) AwaitMarkerNode(async_temp_scope_,
                                current_block_->scope,
-                               Scanner::kNoSourcePos);
+                               TokenPosition::kNoSource);
     yield->AddNode(await_marker);
     ReturnNode* continuation_return = new(Z) ReturnNode(yield_pos);
     continuation_return->set_return_type(ReturnNode::kContinuationTarget);
@@ -9916,15 +9933,15 @@
                            &outer_async_saved_try_ctx);
     if (saved_try_ctx != NULL) {
       yield->AddNode(new (Z) StoreLocalNode(
-          Scanner::kNoSourcePos,
+          TokenPosition::kNoSource,
           saved_try_ctx,
-          new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+          new (Z) LoadLocalNode(TokenPosition::kNoSource,
                                 async_saved_try_ctx)));
       if (outer_saved_try_ctx != NULL) {
         yield->AddNode(new (Z) StoreLocalNode(
-            Scanner::kNoSourcePos,
+            TokenPosition::kNoSource,
             outer_saved_try_ctx,
-            new (Z) LoadLocalNode(Scanner::kNoSourcePos,
+            new (Z) LoadLocalNode(TokenPosition::kNoSource,
                                   outer_async_saved_try_ctx)));
       }
     } else {
@@ -9938,19 +9955,19 @@
 AstNode* Parser::ParseStatement() {
   TRACE_PARSER("ParseStatement");
   AstNode* statement = NULL;
-  intptr_t label_pos = Scanner::kNoSourcePos;
+  TokenPosition label_pos = TokenPosition::kNoSource;
   String* label_name = NULL;
   if (IsIdentifier()) {
     if (LookaheadToken(1) == Token::kCOLON) {
       // Statement starts with a label.
       label_name = CurrentLiteral();
       label_pos = TokenPos();
-      ASSERT(label_pos >= 0);
+      ASSERT(label_pos.IsReal());
       ConsumeToken();  // Consume identifier.
       ConsumeToken();  // Consume colon.
     }
   }
-  const intptr_t statement_pos = TokenPos();
+  const TokenPosition statement_pos = TokenPos();
   const Token::Kind token = CurrentToken();
 
   if (token == Token::kWHILE) {
@@ -9966,10 +9983,10 @@
   } else if (token == Token::kTRY) {
     statement = ParseTryStatement(label_name);
   } else if (token == Token::kRETURN) {
-    const intptr_t return_pos = TokenPos();
+    const TokenPosition return_pos = TokenPos();
     ConsumeToken();
     if (CurrentToken() != Token::kSEMICOLON) {
-      const intptr_t expr_pos = TokenPos();
+      const TokenPosition expr_pos = TokenPos();
       if (current_function().IsGenerativeConstructor() &&
           (current_block_->scope->function_level() == 0)) {
         ReportError(expr_pos,
@@ -10085,7 +10102,7 @@
 
 
 void Parser::ReportErrors(const Error& prev_error,
-                          const Script& script, intptr_t token_pos,
+                          const Script& script, TokenPosition token_pos,
                           const char* format, ...) {
   va_list args;
   va_start(args, format);
@@ -10095,10 +10112,23 @@
 }
 
 
-void Parser::ReportError(intptr_t token_pos, const char* format, ...) const {
+void Parser::ReportError(TokenPosition token_pos,
+                         const char* format, ...) const {
   va_list args;
   va_start(args, format);
-  Report::MessageV(Report::kError, script_, token_pos, format, args);
+  Report::MessageV(Report::kError,
+                   script_, token_pos, Report::AtLocation, format, args);
+  va_end(args);
+  UNREACHABLE();
+}
+
+
+void Parser::ReportErrorBefore(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  Report::MessageV(Report::kError,
+                   script_, PrevTokenPos(), Report::AfterLocation,
+                   format, args);
   va_end(args);
   UNREACHABLE();
 }
@@ -10107,16 +10137,19 @@
 void Parser::ReportError(const char* format, ...) const {
   va_list args;
   va_start(args, format);
-  Report::MessageV(Report::kError, script_, TokenPos(), format, args);
+  Report::MessageV(Report::kError,
+                   script_, TokenPos(), Report::AtLocation, format, args);
   va_end(args);
   UNREACHABLE();
 }
 
 
-void Parser::ReportWarning(intptr_t token_pos, const char* format, ...) const {
+void Parser::ReportWarning(TokenPosition token_pos,
+                           const char* format, ...) const {
   va_list args;
   va_start(args, format);
-  Report::MessageV(Report::kWarning, script_, token_pos, format, args);
+  Report::MessageV(Report::kWarning,
+                   script_, token_pos, Report::AtLocation, format, args);
   va_end(args);
 }
 
@@ -10124,7 +10157,8 @@
 void Parser::ReportWarning(const char* format, ...) const {
   va_list args;
   va_start(args, format);
-  Report::MessageV(Report::kWarning, script_, TokenPos(), format, args);
+  Report::MessageV(Report::kWarning,
+                   script_, TokenPos(), Report::AtLocation, format, args);
   va_end(args);
 }
 
@@ -10150,7 +10184,7 @@
 
 void Parser::ExpectSemicolon() {
   if (CurrentToken() != Token::kSEMICOLON) {
-    ReportError("semicolon expected");
+    ReportErrorBefore("semicolon expected");
   }
   ConsumeToken();
 }
@@ -10211,7 +10245,7 @@
 }
 
 
-SequenceNode* Parser::NodeAsSequenceNode(intptr_t sequence_pos,
+SequenceNode* Parser::NodeAsSequenceNode(TokenPosition sequence_pos,
                                          AstNode* node,
                                          LocalScope* scope) {
   if ((node == NULL) || !node->IsSequenceNode()) {
@@ -10226,7 +10260,8 @@
 
 
 // Call _throwNewIfNotLoaded if prefix is not NULL, otherwise call _throwNew.
-AstNode* Parser::ThrowTypeError(intptr_t type_pos, const AbstractType& type,
+AstNode* Parser::ThrowTypeError(TokenPosition type_pos,
+                                const AbstractType& type,
                                 LibraryPrefix* prefix) {
   ArgumentListNode* arguments = new(Z) ArgumentListNode(type_pos);
 
@@ -10240,7 +10275,7 @@
   }
   // Location argument.
   arguments->Add(new(Z) LiteralNode(
-      type_pos, Integer::ZoneHandle(Z, Integer::New(type_pos))));
+      type_pos, Integer::ZoneHandle(Z, Integer::New(type_pos.value()))));
   // Src value argument.
   arguments->Add(new(Z) LiteralNode(type_pos, Object::null_instance()));
   // Dst type name argument.
@@ -10257,7 +10292,7 @@
 
 
 // Call _throwNewIfNotLoaded if prefix is not NULL, otherwise call _throwNew.
-AstNode* Parser::ThrowNoSuchMethodError(intptr_t call_pos,
+AstNode* Parser::ThrowNoSuchMethodError(TokenPosition call_pos,
                                         const Class& cls,
                                         const String& function_name,
                                         ArgumentListNode* function_arguments,
@@ -10282,8 +10317,8 @@
       func->is_external() && !func->is_static()) {
     arguments->Add(LoadReceiver(func->token_pos()));
   } else {
-    Type& type = Type::ZoneHandle(Z,
-        Type::New(cls, TypeArguments::Handle(Z), call_pos, Heap::kOld));
+    AbstractType& type = AbstractType::ZoneHandle(Z);
+    type ^= Type::New(cls, TypeArguments::Handle(Z), call_pos, Heap::kOld);
     type ^= ClassFinalizer::FinalizeType(
         current_class(), type, ClassFinalizer::kCanonicalize);
     arguments->Add(new(Z) LiteralNode(call_pos, type));
@@ -10363,7 +10398,7 @@
   while (current_preced >= min_preced) {
     while (Token::Precedence(CurrentToken()) == current_preced) {
       Token::Kind op_kind = CurrentToken();
-      const intptr_t op_pos = TokenPos();
+      const TokenPosition op_pos = TokenPos();
       ConsumeToken();
       AstNode* right_operand = NULL;
       if ((op_kind != Token::kIS) && (op_kind != Token::kAS)) {
@@ -10374,7 +10409,7 @@
           ConsumeToken();
           op_kind = Token::kISNOT;
         }
-        const intptr_t type_pos = TokenPos();
+        const TokenPosition type_pos = TokenPos();
         const AbstractType& type = AbstractType::ZoneHandle(Z,
             ParseType(ClassFinalizer::kCanonicalize));
         if (!type.IsInstantiated() &&
@@ -10452,10 +10487,10 @@
 }
 
 
-LocalVariable* Parser::CreateTempConstVariable(intptr_t token_pos,
+LocalVariable* Parser::CreateTempConstVariable(TokenPosition token_pos,
                                                const char* s) {
   char name[64];
-  OS::SNPrint(name, 64, ":%s%" Pd, s, token_pos);
+  OS::SNPrint(name, 64, ":%s%" Pd "", s, token_pos.value());
   LocalVariable* temp = new(Z) LocalVariable(
       token_pos,
       String::ZoneHandle(Z, Symbols::New(name)),
@@ -10467,7 +10502,7 @@
 
 
 // TODO(srdjan): Implement other optimizations.
-AstNode* Parser::OptimizeBinaryOpNode(intptr_t op_pos,
+AstNode* Parser::OptimizeBinaryOpNode(TokenPosition op_pos,
                                       Token::Kind binary_op,
                                       AstNode* lhs,
                                       AstNode* rhs) {
@@ -10510,9 +10545,22 @@
   }
   if (binary_op == Token::kIFNULL) {
     // Handle a ?? b.
+    if ((lhs->EvalConstExpr() != NULL) && (rhs->EvalConstExpr() != NULL)) {
+      Instance& expr_value = Instance::ZoneHandle(Z);
+      if (!GetCachedConstant(op_pos, &expr_value)) {
+        expr_value = EvaluateConstExpr(lhs->token_pos(), lhs).raw();
+        if (expr_value.IsNull()) {
+          expr_value = EvaluateConstExpr(rhs->token_pos(), rhs).raw();
+        }
+        CacheConstantValue(op_pos, expr_value);
+      }
+      return new(Z) LiteralNode(op_pos, expr_value);
+    }
+
     LetNode* result = new(Z) LetNode(op_pos);
     LocalVariable* left_temp = result->AddInitializer(lhs);
-    const intptr_t no_pos = Scanner::kNoSourcePos;
+    left_temp->set_is_final();
+    const TokenPosition no_pos = TokenPosition::kNoSource;
     LiteralNode* null_operand =
         new(Z) LiteralNode(no_pos, Object::null_instance());
     LoadLocalNode* load_left_temp = new(Z) LoadLocalNode(no_pos, left_temp);
@@ -10531,7 +10579,7 @@
 }
 
 
-AstNode* Parser::ExpandAssignableOp(intptr_t op_pos,
+AstNode* Parser::ExpandAssignableOp(TokenPosition op_pos,
                                     Token::Kind assignment_op,
                                     AstNode* lhs,
                                     AstNode* rhs) {
@@ -10575,7 +10623,7 @@
 
 // Evaluates the value of the compile time constant expression
 // and returns a literal node for the value.
-LiteralNode* Parser::FoldConstExpr(intptr_t expr_pos, AstNode* expr) {
+LiteralNode* Parser::FoldConstExpr(TokenPosition expr_pos, AstNode* expr) {
   if (expr->IsLiteralNode()) {
     return expr->AsLiteralNode();
   }
@@ -10589,7 +10637,7 @@
 
 LetNode* Parser::PrepareCompoundAssignmentNodes(AstNode** expr) {
   AstNode* node = *expr;
-  intptr_t token_pos = node->token_pos();
+  TokenPosition token_pos = node->token_pos();
   LetNode* result = new(Z) LetNode(token_pos);
   if (node->IsLoadIndexedNode()) {
     LoadIndexedNode* load_indexed = node->AsLoadIndexedNode();
@@ -10633,8 +10681,8 @@
 // A syntactically legal assignable expression always ends with an
 // identifier token or a ] token. We rewind the token iterator and
 // check whether the token before end_pos is an identifier or ].
-bool Parser::IsLegalAssignableSyntax(AstNode* expr, intptr_t end_pos) {
-  ASSERT(expr->token_pos() >= 0);
+bool Parser::IsLegalAssignableSyntax(AstNode* expr, TokenPosition end_pos) {
+  ASSERT(expr->token_pos().IsReal());
   ASSERT(expr->token_pos() < end_pos);
   SetPosition(expr->token_pos());
   Token::Kind token = Token::kILLEGAL;
@@ -10650,7 +10698,7 @@
 AstNode* Parser::CreateAssignmentNode(AstNode* original,
                                       AstNode* rhs,
                                       const String* left_ident,
-                                      intptr_t left_pos,
+                                      TokenPosition left_pos,
                                       bool is_compound /* = false */) {
   AstNode* result = original->MakeAssignmentNode(rhs);
   if (result == NULL) {
@@ -10661,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())) {
@@ -10708,7 +10756,7 @@
 
 
 AstNode* Parser::ParseCascades(AstNode* expr) {
-  intptr_t cascade_pos = TokenPos();
+  TokenPosition cascade_pos = TokenPos();
   LetNode* cascade = new(Z) LetNode(cascade_pos);
   LocalVariable* cascade_receiver_var = cascade->AddInitializer(expr);
   while (CurrentToken() == Token::kCASCADE) {
@@ -10725,14 +10773,14 @@
     }
     String* expr_ident =
         Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
-    const intptr_t expr_pos = TokenPos();
+    const TokenPosition expr_pos = TokenPos();
     expr = ParseSelectors(load_cascade_receiver, true);
 
     // Assignments after a cascade are part of the cascade. The
     // assigned expression must not contain cascades.
     if (Token::IsAssignmentOperator(CurrentToken())) {
       Token::Kind assignment_op = CurrentToken();
-      const intptr_t assignment_pos = TokenPos();
+      const TokenPosition assignment_pos = TokenPos();
       ConsumeToken();
       AstNode* right_expr = ParseExpr(kAllowConst, kNoCascades);
       if (assignment_op != Token::kASSIGN) {
@@ -10812,7 +10860,9 @@
   TRACE_PARSER("ParseExpr");
   String* expr_ident =
       Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
-  const intptr_t expr_pos = TokenPos();
+  const TokenPosition expr_pos = TokenPos();
+
+  RecursionChecker rc(this);
 
   if (CurrentToken() == Token::kTHROW) {
     if (require_compiletime_const) {
@@ -10856,9 +10906,9 @@
     ReportError(expr_pos, "expression is not assignable");
   }
   const Token::Kind assignment_op = CurrentToken();
-  const intptr_t assignment_pos = TokenPos();
+  const TokenPosition assignment_pos = TokenPos();
   ConsumeToken();
-  const intptr_t right_expr_pos = TokenPos();
+  const TokenPosition right_expr_pos = TokenPos();
   if (require_compiletime_const && (assignment_op != Token::kASSIGN)) {
     ReportError(right_expr_pos,
                 "expression is not a valid compile-time constant");
@@ -10886,7 +10936,7 @@
 
 LiteralNode* Parser::ParseConstExpr() {
   TRACE_PARSER("ParseConstExpr");
-  intptr_t expr_pos = TokenPos();
+  TokenPosition expr_pos = TokenPos();
   AstNode* expr = ParseExpr(kRequireConst, kNoCascades);
   if (!expr->IsLiteralNode()) {
     ReportError(expr_pos, "expression must be a compile-time constant");
@@ -10897,7 +10947,7 @@
 
 AstNode* Parser::ParseConditionalExpr() {
   TRACE_PARSER("ParseConditionalExpr");
-  const intptr_t expr_pos = TokenPos();
+  const TokenPosition expr_pos = TokenPos();
   AstNode* expr = ParseBinaryExpr(Token::Precedence(Token::kIFNULL));
   if (CurrentToken() == Token::kCONDITIONAL) {
     EnsureExpressionTemp();
@@ -10914,7 +10964,7 @@
 AstNode* Parser::ParseUnaryExpr() {
   TRACE_PARSER("ParseUnaryExpr");
   AstNode* expr = NULL;
-  const intptr_t op_pos = TokenPos();
+  const TokenPosition op_pos = TokenPos();
   if (IsAwaitKeyword()) {
     TRACE_PARSER("ParseAwaitExpr");
     if (!innermost_function().IsAsyncFunction() &&
@@ -10958,7 +11008,7 @@
     ConsumeToken();
     String* expr_ident =
         Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
-    const intptr_t expr_pos = TokenPos();
+    const TokenPosition expr_pos = TokenPos();
     expr = ParseUnaryExpr();
     if (!IsLegalAssignableSyntax(expr, TokenPos())) {
       ReportError(expr_pos, "expression is not assignable");
@@ -11039,9 +11089,9 @@
 
 AstNode* Parser::ParseStaticCall(const Class& cls,
                                  const String& func_name,
-                                 intptr_t ident_pos) {
+                                 TokenPosition ident_pos) {
   TRACE_PARSER("ParseStaticCall");
-  const intptr_t call_pos = TokenPos();
+  const TokenPosition call_pos = TokenPos();
   ASSERT(CurrentToken() == Token::kLPAREN);
   ArgumentListNode* arguments = ParseActualParameters(NULL, kAllowConst);
   const int num_arguments = arguments->length();
@@ -11090,36 +11140,32 @@
       (cls.library() == Library::CoreLibrary()) &&
       (func.name() == Symbols::Identical().raw())) {
     // This is the predefined toplevel function identical(a,b).
-    // Create a comparison node instead of a static call to the function, unless
-    // javascript warnings are desired and identical is not invoked from a patch
-    // source.
-    if (!FLAG_warn_on_javascript_compatibility || is_patch_source()) {
-      ASSERT(num_arguments == 2);
+    // Create a comparison node instead of a static call to the function.
+    ASSERT(num_arguments == 2);
 
-      // If both arguments are constant expressions of type string,
-      // evaluate and canonicalize them.
-      // This guarantees that identical("ab", "a"+"b") is true.
-      // An alternative way to guarantee this would be to introduce
-      // an AST node that canonicalizes a value.
-      AstNode* arg0 = arguments->NodeAt(0);
-      const Instance* val0 = arg0->EvalConstExpr();
-      if ((val0 != NULL) && (val0->IsString())) {
-        AstNode* arg1 = arguments->NodeAt(1);
-        const Instance* val1 = arg1->EvalConstExpr();
-        if ((val1 != NULL) && (val1->IsString())) {
-          arguments->SetNodeAt(0,
-              new(Z) LiteralNode(arg0->token_pos(),
-                                 EvaluateConstExpr(arg0->token_pos(), arg0)));
-          arguments->SetNodeAt(1,
-              new(Z) LiteralNode(arg1->token_pos(),
-                                 EvaluateConstExpr(arg1->token_pos(), arg1)));
-        }
+    // If both arguments are constant expressions of type string,
+    // evaluate and canonicalize them.
+    // This guarantees that identical("ab", "a"+"b") is true.
+    // An alternative way to guarantee this would be to introduce
+    // an AST node that canonicalizes a value.
+    AstNode* arg0 = arguments->NodeAt(0);
+    const Instance* val0 = arg0->EvalConstExpr();
+    if ((val0 != NULL) && (val0->IsString())) {
+      AstNode* arg1 = arguments->NodeAt(1);
+      const Instance* val1 = arg1->EvalConstExpr();
+      if ((val1 != NULL) && (val1->IsString())) {
+        arguments->SetNodeAt(0,
+            new(Z) LiteralNode(arg0->token_pos(),
+                               EvaluateConstExpr(arg0->token_pos(), arg0)));
+        arguments->SetNodeAt(1,
+            new(Z) LiteralNode(arg1->token_pos(),
+                               EvaluateConstExpr(arg1->token_pos(), arg1)));
       }
-      return new(Z) ComparisonNode(ident_pos,
-                                   Token::kEQ_STRICT,
-                                   arguments->NodeAt(0),
-                                   arguments->NodeAt(1));
     }
+    return new(Z) ComparisonNode(ident_pos,
+                                 Token::kEQ_STRICT,
+                                 arguments->NodeAt(0),
+                                 arguments->NodeAt(1));
   }
   return new(Z) StaticCallNode(ident_pos, func, arguments);
 }
@@ -11127,7 +11173,7 @@
 
 AstNode* Parser::ParseInstanceCall(AstNode* receiver,
                                    const String& func_name,
-                                   intptr_t ident_pos,
+                                   TokenPosition ident_pos,
                                    bool is_conditional) {
   TRACE_PARSER("ParseInstanceCall");
   CheckToken(Token::kLPAREN);
@@ -11142,7 +11188,7 @@
 
 AstNode* Parser::ParseClosureCall(AstNode* closure) {
   TRACE_PARSER("ParseClosureCall");
-  const intptr_t call_pos = TokenPos();
+  const TokenPosition call_pos = TokenPos();
   ASSERT(CurrentToken() == Token::kLPAREN);
   ArgumentListNode* arguments = ParseActualParameters(NULL, kAllowConst);
   return BuildClosureCall(call_pos, closure, arguments);
@@ -11150,7 +11196,7 @@
 
 
 AstNode* Parser::GenerateStaticFieldLookup(const Field& field,
-                                           intptr_t ident_pos) {
+                                           TokenPosition ident_pos) {
   // If the static field has an initializer, initialize the field at compile
   // time, which is only possible if the field is const.
   AstNode* initializing_getter = RunStaticFieldInitializer(field, ident_pos);
@@ -11161,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));
@@ -11184,7 +11230,7 @@
 // Reference to 'field_name' with explicit class as primary.
 AstNode* Parser::GenerateStaticFieldAccess(const Class& cls,
                                            const String& field_name,
-                                           intptr_t ident_pos) {
+                                           TokenPosition ident_pos) {
   AstNode* access = NULL;
   const Field& field = Field::ZoneHandle(Z, cls.LookupStaticField(field_name));
   Function& func = Function::ZoneHandle(Z);
@@ -11291,7 +11337,7 @@
       ConsumeToken();
       if (left->IsPrimaryNode()) {
         PrimaryNode* primary_node = left->AsPrimaryNode();
-        const intptr_t primary_pos = primary_node->token_pos();
+        const TokenPosition primary_pos = primary_node->token_pos();
         if (primary_node->primary().IsFunction()) {
           left = LoadClosure(primary_node);
         } else if (primary_node->primary().IsTypeParameter()) {
@@ -11321,7 +11367,7 @@
           left = LoadFieldIfUnresolved(left);
         }
       }
-      const intptr_t ident_pos = TokenPos();
+      const TokenPosition ident_pos = TokenPos();
       String* ident = ExpectIdentifier("identifier expected");
       if (CurrentToken() == Token::kLPAREN) {
         // Identifier followed by a opening paren: method call.
@@ -11367,7 +11413,7 @@
       // Super index operator handled in ParseSuperOperator().
       ASSERT(!left->IsPrimaryNode() || !left->AsPrimaryNode()->IsSuper());
 
-      const intptr_t bracket_pos = TokenPos();
+      const TokenPosition bracket_pos = TokenPos();
       ConsumeToken();
       left = LoadFieldIfUnresolved(left);
       const bool saved_mode = SetAllowFunctionLiterals(true);
@@ -11377,7 +11423,7 @@
       AstNode* array = left;
       if (left->IsPrimaryNode()) {
         PrimaryNode* primary_node = left->AsPrimaryNode();
-        const intptr_t primary_pos = primary_node->token_pos();
+        const TokenPosition primary_pos = primary_node->token_pos();
         if (primary_node->primary().IsFunction()) {
           array = LoadClosure(primary_node);
         } else if (primary_node->primary().IsClass()) {
@@ -11419,7 +11465,7 @@
     } else if (CurrentToken() == Token::kLPAREN) {
       if (left->IsPrimaryNode()) {
         PrimaryNode* primary_node = left->AsPrimaryNode();
-        const intptr_t primary_pos = primary_node->token_pos();
+        const TokenPosition primary_pos = primary_node->token_pos();
         if (primary_node->primary().IsFunction()) {
           const Function& func = Function::Cast(primary_node->primary());
           const String& func_name = String::ZoneHandle(Z, func.name());
@@ -11495,7 +11541,7 @@
       left = LoadFieldIfUnresolved(left);
       if (left->IsPrimaryNode()) {
         PrimaryNode* primary_node = left->AsPrimaryNode();
-        const intptr_t primary_pos = primary->token_pos();
+        const TokenPosition primary_pos = primary->token_pos();
         if (primary_node->primary().IsFunction()) {
           // Treat as implicit closure.
           left = LoadClosure(primary_node);
@@ -11548,7 +11594,7 @@
 // Closurization e#m of getter, setter, method or operator.
 AstNode* Parser::ParseClosurization(AstNode* primary) {
   ExpectToken(Token::kHASH);
-  intptr_t property_pos = TokenPos();
+  TokenPosition property_pos = TokenPos();
   bool is_setter_name = false;
 
   String& extractor_name = String::ZoneHandle(Z);
@@ -11689,7 +11735,7 @@
   TRACE_PARSER("ParsePostfixExpr");
   String* expr_ident =
       Token::IsIdentifier(CurrentToken()) ? CurrentLiteral() : NULL;
-  const intptr_t expr_pos = TokenPos();
+  const TokenPosition expr_pos = TokenPos();
   AstNode* expr = ParsePrimary();
   if (CurrentToken() == Token::kHASH) {
     expr = LoadFieldIfUnresolved(expr);
@@ -11703,7 +11749,7 @@
       ReportError(expr_pos, "expression is not assignable");
     }
     Token::Kind incr_op = CurrentToken();
-    const intptr_t op_pos = TokenPos();
+    const TokenPosition op_pos = TokenPos();
     ConsumeToken();
     // Not prefix.
     LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr);
@@ -11836,7 +11882,7 @@
 }
 
 
-void Parser::CheckInstanceFieldAccess(intptr_t field_pos,
+void Parser::CheckInstanceFieldAccess(TokenPosition field_pos,
                                       const String& field_name) {
   // Fields are not accessible from a static function, except from a
   // constructor, which is considered as non-static by the compiler.
@@ -11861,16 +11907,15 @@
 
 const AbstractType* Parser::ReceiverType(const Class& cls) {
   ASSERT(!cls.IsNull());
+  ASSERT(!cls.IsTypedefClass());
+  // Note that if cls is _Closure, the returned type will be _Closure,
+  // and not the signature type.
   Type& type = Type::ZoneHandle(Z, cls.CanonicalType());
   if (!type.IsNull()) {
     return &type;
   }
-  if (cls.IsSignatureClass()) {
-    type = cls.SignatureType();
-  } else {
-    type = Type::New(cls,
-        TypeArguments::Handle(Z, cls.type_parameters()), cls.token_pos());
-  }
+  type = Type::New(cls,
+      TypeArguments::Handle(Z, cls.type_parameters()), cls.token_pos());
   if (cls.is_type_finalized()) {
     type ^= ClassFinalizer::FinalizeType(
         cls, type, ClassFinalizer::kCanonicalizeWellFormed);
@@ -11887,7 +11932,7 @@
       !current_function().IsInFactoryScope()) {
     return false;
   }
-  return current_class().NumTypeParameters() > 0;
+  return current_class().IsGeneric();
 }
 
 // We cache computed compile-time constants in a map so we can look them
@@ -11900,10 +11945,10 @@
 // ConstantPosKey allows us to look up a constant in the map without
 // allocating a key pair (array).
 struct ConstantPosKey : ValueObject {
-  ConstantPosKey(const String& url, intptr_t pos)
+  ConstantPosKey(const String& url, TokenPosition pos)
       : script_url(url), token_pos(pos) { }
   const String& script_url;
-  intptr_t token_pos;
+  TokenPosition token_pos;
 };
 
 
@@ -11919,7 +11964,7 @@
     const Array& key2 = Array::Cast(b);
     // Compare raw strings of script url symbol and token positon.
     return (key1.script_url.raw() == key2.At(0))
-        && (key1.token_pos == Smi::Value(Smi::RawCast(key2.At(1))));
+        && (key1.token_pos.value() == Smi::Value(Smi::RawCast(key2.At(1))));
   }
   static uword Hash(const Object& obj) {
     const Array& key = Array::Cast(obj);
@@ -11929,13 +11974,13 @@
   }
   static uword Hash(const ConstantPosKey& key) {
     return HashValue(String::HashRawSymbol(key.script_url.raw()),
-                     key.token_pos);
+                     key.token_pos.value());
   }
   // Used by CachConstantValue if a new constant is added to the map.
   static RawObject* NewKey(const ConstantPosKey& key) {
     const Array& key_obj = Array::Handle(Array::New(2));
     key_obj.SetAt(0, key.script_url);
-    key_obj.SetAt(1, Smi::Handle(Smi::New(key.token_pos)));
+    key_obj.SetAt(1, Smi::Handle(Smi::New(key.token_pos.value())));
     return key_obj.raw();;
   }
 
@@ -11947,7 +11992,8 @@
 typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
 
 
-void Parser::CacheConstantValue(intptr_t token_pos, const Instance& value) {
+void Parser::CacheConstantValue(TokenPosition token_pos,
+                                const Instance& value) {
   ConstantPosKey key(String::Handle(Z, script_.url()), token_pos);
   if (isolate()->object_store()->compile_time_constants() == Array::null()) {
     const intptr_t kInitialConstMapSize = 16;
@@ -11964,7 +12010,7 @@
 }
 
 
-bool Parser::GetCachedConstant(intptr_t token_pos, Instance* value) {
+bool Parser::GetCachedConstant(TokenPosition token_pos, Instance* value) {
   if (isolate()->object_store()->compile_time_constants() == Array::null()) {
     return false;
   }
@@ -11984,7 +12030,7 @@
 
 
 RawInstance* Parser::TryCanonicalize(const Instance& instance,
-                                     intptr_t token_pos) {
+                                     TokenPosition token_pos) {
   if (instance.IsNull()) {
     return instance.raw();
   }
@@ -12001,10 +12047,10 @@
 // If the field is already initialized, return no ast (NULL).
 // Otherwise, if the field is constant, initialize the field and return no ast.
 // If the field is not initialized and not const, return the ast for the getter.
-StaticGetterNode* Parser::RunStaticFieldInitializer(const Field& field,
-                                                    intptr_t field_ref_pos) {
+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));
@@ -12139,7 +12185,7 @@
 // Do a lookup for the identifier in the block scope and the class scope
 // return true if the identifier is found, false otherwise.
 // If node is non NULL return an AST node corresponding to the identifier.
-bool Parser::ResolveIdentInLocalScope(intptr_t ident_pos,
+bool Parser::ResolveIdentInLocalScope(TokenPosition ident_pos,
                                       const String &ident,
                                       AstNode** node) {
   TRACE_PARSER("ResolveIdentInLocalScope");
@@ -12244,7 +12290,7 @@
 // Resolve an identifier by checking the global scope of the current
 // library. If not found in the current library, then look in the scopes
 // of all libraries that are imported without a library prefix.
-AstNode* Parser::ResolveIdentInCurrentLibraryScope(intptr_t ident_pos,
+AstNode* Parser::ResolveIdentInCurrentLibraryScope(TokenPosition ident_pos,
                                                    const String& ident) {
   TRACE_PARSER("ResolveIdentInCurrentLibraryScope");
   HANDLESCOPE(thread());
@@ -12290,7 +12336,7 @@
 // Do a lookup for the identifier in the scope of the specified
 // library prefix. This means trying to resolve it locally in all of the
 // libraries present in the library prefix.
-AstNode* Parser::ResolveIdentInPrefixScope(intptr_t ident_pos,
+AstNode* Parser::ResolveIdentInPrefixScope(TokenPosition ident_pos,
                                            const LibraryPrefix& prefix,
                                            const String& ident) {
   TRACE_PARSER("ResolveIdentInPrefixScope");
@@ -12369,7 +12415,7 @@
 // If the name cannot be resolved, turn it into an instance field access
 // if we're compiling an instance method, or generate
 // throw NoSuchMethodError if we're compiling a static method.
-AstNode* Parser::ResolveIdent(intptr_t ident_pos,
+AstNode* Parser::ResolveIdent(TokenPosition ident_pos,
                               const String& ident,
                               bool allow_closure_names) {
   TRACE_PARSER("ResolveIdent");
@@ -12400,7 +12446,7 @@
   }
   if (resolved->IsPrimaryNode()) {
     PrimaryNode* primary = resolved->AsPrimaryNode();
-    const intptr_t primary_pos = primary->token_pos();
+    const TokenPosition primary_pos = primary->token_pos();
     if (primary->primary().IsString()) {
       // We got an unresolved name. If we are compiling a static
       // method, evaluation of an unresolved identifier causes a
@@ -12447,7 +12493,7 @@
     bool consume_unresolved_prefix) {
   LibraryPrefix& prefix = LibraryPrefix::Handle(Z);
   return ParseType(finalization, allow_deferred_type,
-                         consume_unresolved_prefix, &prefix);
+                   consume_unresolved_prefix, &prefix);
 }
 
 // Parses type = [ident "."] ident ["<" type { "," type } ">"], then resolve and
@@ -12459,7 +12505,7 @@
     LibraryPrefix* prefix) {
   TRACE_PARSER("ParseType");
   CheckToken(Token::kIDENT, "type name expected");
-  intptr_t ident_pos = TokenPos();
+  TokenPosition ident_pos = TokenPos();
   String& type_name = String::Handle(Z);
 
   if (finalization == ClassFinalizer::kIgnore) {
@@ -12572,7 +12618,7 @@
 
 
 void Parser::CheckConstructorCallTypeArguments(
-    intptr_t pos, const Function& constructor,
+    TokenPosition pos, const Function& constructor,
     const TypeArguments& type_arguments) {
   if (!type_arguments.IsNull()) {
     const Class& constructor_class = Class::Handle(Z, constructor.Owner());
@@ -12592,13 +12638,13 @@
 // Note: if the list literal is empty and the brackets have no whitespace
 // between them, the scanner recognizes the opening and closing bracket
 // as one token of type Token::kINDEX.
-AstNode* Parser::ParseListLiteral(intptr_t type_pos,
+AstNode* Parser::ParseListLiteral(TokenPosition type_pos,
                                   bool is_const,
                                   const TypeArguments& type_arguments) {
   TRACE_PARSER("ParseListLiteral");
-  ASSERT(type_pos >= 0);
+  ASSERT(type_pos.IsReal());
   ASSERT(CurrentToken() == Token::kLBRACK || CurrentToken() == Token::kINDEX);
-  const intptr_t literal_pos = TokenPos();
+  const TokenPosition literal_pos = TokenPos();
 
   if (is_const) {
     Instance& existing_const = Instance::ZoneHandle(Z);
@@ -12631,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");
@@ -12652,9 +12698,9 @@
   if (!is_empty_literal) {
     const bool saved_mode = SetAllowFunctionLiterals(true);
     while (CurrentToken() != Token::kRBRACK) {
-      const intptr_t element_pos = TokenPos();
+      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,
@@ -12685,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(
@@ -12758,7 +12804,7 @@
 
 
 ConstructorCallNode* Parser::CreateConstructorCallNode(
-    intptr_t token_pos,
+    TokenPosition token_pos,
     const TypeArguments& type_arguments,
     const Function& constructor,
     ArgumentListNode* arguments) {
@@ -12795,13 +12841,13 @@
 }
 
 
-AstNode* Parser::ParseMapLiteral(intptr_t type_pos,
+AstNode* Parser::ParseMapLiteral(TokenPosition type_pos,
                                  bool is_const,
                                  const TypeArguments& type_arguments) {
   TRACE_PARSER("ParseMapLiteral");
-  ASSERT(type_pos >= 0);
+  ASSERT(type_pos.IsReal());
   ASSERT(CurrentToken() == Token::kLBRACE);
-  const intptr_t literal_pos = TokenPos();
+  const TokenPosition literal_pos = TokenPos();
 
   if (is_const) {
     Instance& existing_const = Instance::ZoneHandle(Z);
@@ -12837,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");
@@ -12854,9 +12900,9 @@
   // comma after the last entry.
   while (CurrentToken() != Token::kRBRACE) {
     const bool saved_mode = SetAllowFunctionLiterals(true);
-    const intptr_t key_pos = TokenPos();
+    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(
@@ -12876,10 +12922,10 @@
       }
     }
     ExpectToken(Token::kCOLON);
-    const intptr_t value_pos = TokenPos();
+    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(
@@ -12911,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();
@@ -13026,7 +13072,7 @@
     is_const = true;
     ConsumeToken();
   }
-  const intptr_t type_pos = TokenPos();
+  const TokenPosition type_pos = TokenPos();
   TypeArguments& type_arguments = TypeArguments::Handle(Z,
       ParseTypeArguments(ClassFinalizer::kCanonicalize));
   // Malformed type arguments are mapped to dynamic, so we will not encounter
@@ -13049,7 +13095,7 @@
 AstNode* Parser::ParseSymbolLiteral() {
   ASSERT(CurrentToken() == Token::kHASH);
   ConsumeToken();
-  intptr_t symbol_pos = TokenPos();
+  TokenPosition symbol_pos = TokenPos();
   String& symbol = String::ZoneHandle(Z);
   if (IsIdentifier()) {
     symbol = CurrentLiteral()->raw();
@@ -13099,8 +13145,8 @@
 }
 
 
-RawFunction* Parser::BuildConstructorClosureFunction(const Function& ctr,
-                                                     intptr_t token_pos) {
+RawFunction* Parser::BuildConstructorClosureFunction(
+    const Function& ctr, TokenPosition token_pos) {
   ASSERT(ctr.kind() == RawFunction::kConstructor);
   Function& closure = Function::Handle(Z);
   closure = I->LookupClosureFunction(innermost_function(), token_pos);
@@ -13132,19 +13178,12 @@
   closure.set_result_type(Object::dynamic_type());
   AddFormalParamsToFunction(&params, closure);
 
-  // Create and set the signature class of the closure.
-  const String& sig = String::Handle(Z, closure.Signature());
-  Class& sig_cls = Class::Handle(Z, library_.LookupLocalClass(sig));
-  if (sig_cls.IsNull()) {
-    sig_cls = Class::NewSignatureClass(sig, closure, script_, token_pos);
-    library_.AddClass(sig_cls);
-  }
-  closure.set_signature_class(sig_cls);
-  // Finalize types in signature class here, so that the
-  // signature type is not computed twice.
-  ClassFinalizer::FinalizeTypesInClass(sig_cls);
-  const Type& sig_type = Type::Handle(Z, sig_cls.SignatureType());
-  ASSERT(sig_type.IsFinalized());
+  // Finalize function type.
+  FunctionType& signature_type =
+      FunctionType::Handle(Z, closure.SignatureType());
+  signature_type ^= ClassFinalizer::FinalizeType(
+      current_class(), signature_type, ClassFinalizer::kCanonicalize);
+  closure.SetSignatureType(signature_type);
   // Finalization would be premature when top-level parsing.
   ASSERT(!is_top_level_);
   return closure.raw();
@@ -13212,7 +13251,11 @@
       ASSERT(!type.IsMalformedOrMalbounded());
       if (!type.IsInstantiated()) {
         Error& error = Error::Handle(Z);
-        type ^= type.InstantiateFrom(*type_arguments, &error, NULL, Heap::kOld);
+        type ^= type.InstantiateFrom(*type_arguments,
+                                     &error,
+                                     NULL,  // instantiation_trail
+                                     NULL,  // bound_trail
+                                     Heap::kOld);
         ASSERT(error.IsNull());
       }
       *type_arguments = type.arguments();
@@ -13224,13 +13267,13 @@
 
 AstNode* Parser::ParseNewOperator(Token::Kind op_kind) {
   TRACE_PARSER("ParseNewOperator");
-  const intptr_t new_pos = TokenPos();
+  const TokenPosition new_pos = TokenPos();
   ASSERT((op_kind == Token::kNEW) || (op_kind == Token::kCONST));
   bool is_const = (op_kind == Token::kCONST);
   if (!IsIdentifier()) {
     ReportError("type name expected");
   }
-  intptr_t type_pos = TokenPos();
+  TokenPosition type_pos = TokenPos();
   // Can't allocate const objects of a deferred type.
   const bool allow_deferred_type = !is_const;
   const Token::Kind la3 = LookaheadToken(3);
@@ -13301,7 +13344,7 @@
   }
 
   // Parse constructor parameters.
-  intptr_t call_pos = TokenPos();
+  TokenPosition call_pos = TokenPos();
   ArgumentListNode* arguments = NULL;
   if (!is_tearoff_expression) {
     CheckToken(Token::kLPAREN);
@@ -13376,7 +13419,8 @@
         redirect_type ^= redirect_type.InstantiateFrom(
             type_arguments,
             &error,
-            NULL,  // trail
+            NULL,  // instantiation_trail
+            NULL,  // bound_trail
             Heap::kOld);
         if (!error.IsNull()) {
           redirect_type = ClassFinalizer::NewFinalizedMalformedType(
@@ -13415,8 +13459,8 @@
         }
         return ThrowTypeError(redirect_type.token_pos(), redirect_type);
       }
-      if (I->flags().type_checks() &&
-              !redirect_type.IsSubtypeOf(type, NULL, Heap::kOld)) {
+      if (I->type_checks() &&
+              !redirect_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
         // Additional type checking of the result is necessary.
         type_bound = type.raw();
       }
@@ -13441,7 +13485,7 @@
     }
     ArgumentListNode* error_arguments = new(Z) ArgumentListNode(type_pos);
     error_arguments->Add(new(Z) LiteralNode(
-        TokenPos(), Integer::ZoneHandle(Z, Integer::New(type_pos))));
+        TokenPos(), Integer::ZoneHandle(Z, Integer::New(type_pos.value()))));
     error_arguments->Add(new(Z) LiteralNode(
         TokenPos(), String::ZoneHandle(Z, type_class_name.raw())));
     result->AddNode(
@@ -13619,7 +13663,7 @@
 AstNode* Parser::ParseStringLiteral(bool allow_interpolation) {
   TRACE_PARSER("ParseStringLiteral");
   AstNode* primary = NULL;
-  const intptr_t literal_start = TokenPos();
+  const TokenPosition literal_start = TokenPos();
   ASSERT(CurrentToken() == Token::kSTRING);
   Token::Kind l1_token = LookaheadToken(1);
   if ((l1_token != Token::kSTRING) &&
@@ -13658,7 +13702,7 @@
       }
       has_interpolation = true;
       AstNode* expr = NULL;
-      const intptr_t expr_pos = TokenPos();
+      const TokenPosition expr_pos = TokenPos();
       if (CurrentToken() == Token::kINTERPOL_VAR) {
         expr = ResolveIdent(TokenPos(), *CurrentLiteral(), true);
         ConsumeToken();
@@ -13731,7 +13775,7 @@
     primary = ParseFunctionStatement(true);
     CloseBlock();
   } else if (IsIdentifier()) {
-    intptr_t qual_ident_pos = TokenPos();
+    TokenPosition qual_ident_pos = TokenPos();
     const LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(Z, ParsePrefix());
     if (!prefix.IsNull()) {
       if (CurrentToken() == Token::kHASH) {
@@ -13890,11 +13934,11 @@
       ReportError("class '%s' does not have a superclass",
                   String::Handle(Z, current_class().Name()).ToCString());
     }
-    const intptr_t super_pos = TokenPos();
+    const TokenPosition super_pos = TokenPos();
     ConsumeToken();
     if (CurrentToken() == Token::kPERIOD) {
       ConsumeToken();
-      const intptr_t ident_pos = TokenPos();
+      const TokenPosition ident_pos = TokenPos();
       const String& ident = *ExpectIdentifier("identifier expected");
       if (CurrentToken() == Token::kLPAREN) {
         primary = ParseSuperCall(ident);
@@ -13919,7 +13963,8 @@
 
 // Evaluate expression in expr and return the value. The expression must
 // be a compile time constant.
-const Instance& Parser::EvaluateConstExpr(intptr_t expr_pos, AstNode* expr) {
+const Instance& Parser::EvaluateConstExpr(TokenPosition expr_pos,
+                                          AstNode* expr) {
   if (expr->IsLiteralNode()) {
     return expr->AsLiteralNode()->literal();
   } else if (expr->IsLoadLocalNode() &&
@@ -14318,16 +14363,15 @@
 }  // namespace dart
 
 
-#else  // DART_PRECOMPILED
+#else  // DART_PRECOMPILED_RUNTIME
 
 
 namespace dart {
 
-DEFINE_FLAG(bool, enable_mirrors, true,
-    "Disable to make importing dart:mirrors an error.");
-DEFINE_FLAG(bool, load_deferred_eagerly, false,
-    "Load deferred libraries eagerly.");
-DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
+void ParsedFunction::AddToGuardedFields(const Field* field) const {
+  UNREACHABLE();
+}
+
 
 LocalVariable* ParsedFunction::EnsureExpressionTemp() {
   UNREACHABLE();
@@ -14391,7 +14435,7 @@
 
 
 ArgumentListNode* Parser::BuildNoSuchMethodArguments(
-    intptr_t call_pos,
+    TokenPosition call_pos,
     const String& function_name,
     const ArgumentListNode& function_args,
     const LocalVariable* temp_for_last_arg,
@@ -14402,4 +14446,4 @@
 
 }  // namespace dart
 
-#endif  // DART_PRECOMPILED
+#endif  // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 1be0f50..dcd03a6 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -36,6 +36,7 @@
 struct ParamList;
 struct QualIdent;
 class TopLevel;
+class RecursionChecker;
 
 // The class ParsedFunction holds the result of parsing a function.
 class ParsedFunction : public ZoneAllocated {
@@ -165,6 +166,10 @@
   Isolate* isolate() const { return thread_->isolate(); }
   Zone* zone() const { return thread_->zone(); }
 
+  // Adds only relevant fields: field must be unique and its guarded_cid()
+  // relevant.
+  void AddToGuardedFields(const Field* field) const;
+
  private:
   Thread* thread_;
   const Function& function_;
@@ -232,8 +237,12 @@
   struct Block;
   class TryStack;
 
-  Parser(const Script& script, const Library& library, intptr_t token_pos);
-  Parser(const Script& script, ParsedFunction* function, intptr_t token_pos);
+  Parser(const Script& script,
+         const Library& library,
+         TokenPosition token_pos);
+  Parser(const Script& script,
+         ParsedFunction* function,
+         TokenPosition token_pos);
   ~Parser();
 
   // The function for which we will generate code.
@@ -273,7 +282,7 @@
   }
 
   const Script& script() const { return script_; }
-  void SetScript(const Script& script, intptr_t token_pos);
+  void SetScript(const Script& script, TokenPosition token_pos);
 
   const Library& library() const { return library_; }
   void set_library(const Library& value) const { library_ = value.raw(); }
@@ -293,7 +302,10 @@
     return script_.kind() == RawScript::kPatchTag;
   }
 
-  intptr_t TokenPos() const { return tokens_iterator_.CurrentPosition(); }
+  TokenPosition TokenPos() const {
+    return tokens_iterator_.CurrentPosition();
+  }
+  TokenPosition PrevTokenPos() const { return prev_token_pos_; }
 
   Token::Kind CurrentToken() {
     if (token_kind_ == Token::kILLEGAL) {
@@ -312,10 +324,11 @@
   RawInteger* CurrentIntegerLiteral() const;
 
   // Sets parser to given token position in the stream.
-  void SetPosition(intptr_t position);
+  void SetPosition(TokenPosition position);
 
   void ConsumeToken() {
     // Reset cache and advance the token.
+    prev_token_pos_ = tokens_iterator_.CurrentPosition();
     token_kind_ = Token::kILLEGAL;
     tokens_iterator_.Advance();
     INC_STAT(thread(), num_tokens_consumed, 1);
@@ -334,7 +347,7 @@
   void SkipToMatching();
   void SkipToMatchingParenthesis();
   void SkipBlock();
-  intptr_t SkipMetadata();
+  TokenPosition SkipMetadata();
   void SkipTypeArguments();
   void SkipType(bool allow_void);
   void SkipInitializers();
@@ -359,78 +372,83 @@
 
   AstNode* DartPrint(const char* str);
 
-  void CheckConstructorCallTypeArguments(intptr_t pos,
+  void CheckConstructorCallTypeArguments(TokenPosition pos,
                                          const Function& constructor,
                                          const TypeArguments& type_arguments);
 
+  // Report error if parsed code is too deeply nested; avoid stack overflow.
+  void CheckStack();
+
   // Report already formatted error.
   static void ReportError(const Error& error);
 
   // Concatenate and report an already formatted error and a new error message.
   static void ReportErrors(const Error& prev_error,
-                           const Script& script, intptr_t token_pos,
+                           const Script& script, TokenPosition token_pos,
                            const char* format, ...) PRINTF_ATTRIBUTE(4, 5);
 
   // Report error message at location of current token in current script.
   void ReportError(const char* msg, ...) const PRINTF_ATTRIBUTE(2, 3);
 
+  void ReportErrorBefore(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+
   // Report error message at given location in current script.
-  void ReportError(intptr_t token_pos,
+  void ReportError(TokenPosition token_pos,
                    const char* msg, ...) const PRINTF_ATTRIBUTE(3, 4);
 
   // Report warning message at location of current token in current script.
   void ReportWarning(const char* msg, ...) const PRINTF_ATTRIBUTE(2, 3);
 
   // Report warning message at given location in current script.
-  void ReportWarning(intptr_t token_pos,
+  void ReportWarning(TokenPosition token_pos,
                      const char* msg, ...) const PRINTF_ATTRIBUTE(3, 4);
 
   void CheckRecursiveInvocation();
 
-  const Instance& EvaluateConstExpr(intptr_t expr_pos, AstNode* expr);
+  const Instance& EvaluateConstExpr(TokenPosition expr_pos, AstNode* expr);
   StaticGetterNode* RunStaticFieldInitializer(const Field& field,
-                                              intptr_t field_ref_pos);
+                                              TokenPosition field_ref_pos);
   RawObject* EvaluateConstConstructorCall(const Class& type_class,
                                           const TypeArguments& type_arguments,
                                           const Function& constructor,
                                           ArgumentListNode* arguments);
-  LiteralNode* FoldConstExpr(intptr_t expr_pos, AstNode* expr);
+  LiteralNode* FoldConstExpr(TokenPosition expr_pos, AstNode* expr);
 
   // Support for parsing of scripts.
   void ParseTopLevel();
   void ParseEnumDeclaration(const GrowableObjectArray& pending_classes,
                             const Object& tl_owner,
-                            intptr_t metadata_pos);
+                            TokenPosition metadata_pos);
   void ParseEnumDefinition(const Class& cls);
   void ParseClassDeclaration(const GrowableObjectArray& pending_classes,
                              const Object& tl_owner,
-                             intptr_t metadata_pos);
+                             TokenPosition metadata_pos);
   void ParseClassDefinition(const Class& cls);
   void ParseMixinAppAlias(const GrowableObjectArray& pending_classes,
                           const Object& tl_owner,
-                          intptr_t metadata_pos);
+                          TokenPosition metadata_pos);
   void ParseTypedef(const GrowableObjectArray& pending_classes,
                     const Object& tl_owner,
-                    intptr_t metadata_pos);
+                    TokenPosition metadata_pos);
   void ParseTopLevelVariable(TopLevel* top_level,
-                             const Object& owner, intptr_t metadata_pos);
+                             const Object& owner, TokenPosition metadata_pos);
   void ParseTopLevelFunction(TopLevel* top_level,
-                             const Object& owner, intptr_t metadata_pos);
+                             const Object& owner, TokenPosition metadata_pos);
   void ParseTopLevelAccessor(TopLevel* top_level,
-                             const Object& owner, intptr_t metadata_pos);
+                             const Object& owner, TokenPosition metadata_pos);
   RawArray* EvaluateMetadata();
 
   RawFunction::AsyncModifier ParseFunctionModifier();
 
   // Support for parsing libraries.
   RawObject* CallLibraryTagHandler(Dart_LibraryTag tag,
-                                   intptr_t token_pos,
+                                   TokenPosition token_pos,
                                    const String& url);
   void ParseIdentList(GrowableObjectArray* names);
   void ParseLibraryDefinition(const Object& tl_owner);
   void ParseLibraryName();
   void ParseLibraryImportExport(const Object& tl_owner,
-                                intptr_t metadata_pos);
+                                TokenPosition metadata_pos);
   void ParseLibraryPart();
   void ParsePartHeader();
   void ParseLibraryNameObsoleteSyntax();
@@ -456,7 +474,7 @@
   void ParseFieldDefinition(ClassDesc* members, MemberDesc* field);
   void CheckMemberNameConflict(ClassDesc* members, MemberDesc* member);
   void ParseClassMemberDefinition(ClassDesc* members,
-                                  intptr_t metadata_pos);
+                                  TokenPosition metadata_pos);
   void ParseFormalParameter(bool allow_explicit_default_value,
                             bool evaluate_metadata,
                             ParamList* params);
@@ -475,14 +493,14 @@
       LocalVariable* receiver,
       GrowableArray<Field*>* initialized_fields);
   AstNode* CheckDuplicateFieldInit(
-      intptr_t init_pos,
+      TokenPosition init_pos,
       GrowableArray<Field*>* initialized_fields,
       AstNode* instance,
       Field* field,
       AstNode* init_value);
   StaticCallNode* GenerateSuperConstructorCall(
       const Class& cls,
-      intptr_t supercall_pos,
+      TokenPosition supercall_pos,
       LocalVariable* receiver,
       ArgumentListNode* forwarding_args);
   StaticCallNode* ParseSuperInitializer(
@@ -499,7 +517,7 @@
   void ParseInterfaceList(const Class& cls);
   RawAbstractType* ParseMixins(const AbstractType& super_type);
   static StaticCallNode* BuildInvocationMirrorAllocation(
-      intptr_t call_pos,
+      TokenPosition call_pos,
       const String& function_name,
       const ArgumentListNode& function_args,
       const LocalVariable* temp,
@@ -507,18 +525,19 @@
   // Build arguments for a NoSuchMethodCall. If LocalVariable temp is not NULL,
   // the last argument is stored in temp.
   static ArgumentListNode* BuildNoSuchMethodArguments(
-      intptr_t call_pos,
+      TokenPosition call_pos,
       const String& function_name,
       const ArgumentListNode& function_args,
       const LocalVariable* temp,
       bool is_super_invocation);
-  RawFunction* GetSuperFunction(intptr_t token_pos,
+  RawFunction* GetSuperFunction(TokenPosition token_pos,
                                 const String& name,
                                 ArgumentListNode* arguments,
                                 bool resolve_getter,
                                 bool* is_no_such_method);
   AstNode* ParseSuperCall(const String& function_name);
-  AstNode* ParseSuperFieldAccess(const String& field_name, intptr_t field_pos);
+  AstNode* ParseSuperFieldAccess(const String& field_name,
+                                 TokenPosition field_pos);
   AstNode* ParseSuperOperator();
   AstNode* BuildUnarySuperOperator(Token::Kind op, PrimaryNode* super);
 
@@ -526,14 +545,14 @@
 
   void SetupDefaultsForOptionalParams(const ParamList& params);
   ClosureNode* CreateImplicitClosureNode(const Function& func,
-                                         intptr_t token_pos,
+                                         TokenPosition token_pos,
                                          AstNode* receiver);
   static void AddFormalParamsToFunction(const ParamList* params,
                                         const Function& func);
   void AddFormalParamsToScope(const ParamList* params, LocalScope* scope);
 
   SequenceNode* ParseConstructor(const Function& func);
-  SequenceNode* ParseFunc(const Function& func);
+  SequenceNode* ParseFunc(const Function& func, bool check_semicolon);
 
   void ParseNativeFunctionBlock(const ParamList* params, const Function& func);
 
@@ -550,21 +569,21 @@
   void BuildDispatcherScope(const Function& func,
                             const ArgumentsDescriptor& desc);
 
-  void EnsureHasReturnStatement(SequenceNode* seq, intptr_t return_pos);
+  void EnsureHasReturnStatement(SequenceNode* seq, TokenPosition return_pos);
   void ChainNewBlock(LocalScope* outer_scope);
   void OpenBlock();
   void OpenLoopBlock();
   void OpenFunctionBlock(const Function& func);
   void OpenAsyncClosure();
-  RawFunction* OpenAsyncFunction(intptr_t formal_param_pos);
-  RawFunction* OpenSyncGeneratorFunction(intptr_t func_pos);
+  RawFunction* OpenAsyncFunction(TokenPosition formal_param_pos);
+  RawFunction* OpenSyncGeneratorFunction(TokenPosition func_pos);
   SequenceNode* CloseSyncGenFunction(const Function& closure,
                                      SequenceNode* closure_node);
   void AddSyncGenClosureParameters(ParamList* params);
   void AddAsyncGenClosureParameters(ParamList* params);
 
   // Support for async* functions.
-  RawFunction* OpenAsyncGeneratorFunction(intptr_t func_pos);
+  RawFunction* OpenAsyncGeneratorFunction(TokenPosition func_pos);
   SequenceNode* CloseAsyncGeneratorFunction(const Function& closure,
                                             SequenceNode* closure_node);
   void OpenAsyncGeneratorClosure();
@@ -588,10 +607,10 @@
   LocalVariable* LookupTypeArgumentsParameter(LocalScope* from_scope,
                                               bool test_only);
   void CaptureInstantiator();
-  AstNode* LoadReceiver(intptr_t token_pos);
+  AstNode* LoadReceiver(TokenPosition token_pos);
   AstNode* LoadFieldIfUnresolved(AstNode* node);
   AstNode* LoadClosure(PrimaryNode* primary);
-  InstanceGetterNode* CallGetter(intptr_t token_pos,
+  InstanceGetterNode* CallGetter(TokenPosition token_pos,
                                  AstNode* object,
                                  const String& name);
 
@@ -602,7 +621,7 @@
   AstNode* ParseDoWhileStatement(String* label_name);
   AstNode* ParseForStatement(String* label_name);
   AstNode* ParseAwaitForStatement(String* label_name);
-  AstNode* ParseForInStatement(intptr_t forin_pos, SourceLabel* label);
+  AstNode* ParseForInStatement(TokenPosition forin_pos, SourceLabel* label);
   RawClass* CheckCaseExpressions(const GrowableArray<LiteralNode*>& values);
   CaseNode* ParseCaseClause(LocalVariable* switch_expr_value,
                             GrowableArray<LiteralNode*>* case_expr_values,
@@ -626,7 +645,7 @@
                                   LocalVariable* saved_exception_var,
                                   LocalVariable* saved_stack_trace_var);
   // Parse all the catch clause of a try.
-  SequenceNode* ParseCatchClauses(intptr_t handler_pos,
+  SequenceNode* ParseCatchClauses(TokenPosition handler_pos,
                                   bool is_async,
                                   LocalVariable* exception_var,
                                   LocalVariable* stack_trace_var,
@@ -709,15 +728,15 @@
   String* ParseImportStringLiteral();
   AstNode* ParseCompoundLiteral();
   AstNode* ParseSymbolLiteral();
-  AstNode* ParseListLiteral(intptr_t type_pos,
+  AstNode* ParseListLiteral(TokenPosition type_pos,
                             bool is_const,
                             const TypeArguments& type_arguments);
-  AstNode* ParseMapLiteral(intptr_t type_pos,
+  AstNode* ParseMapLiteral(TokenPosition type_pos,
                            bool is_const,
                            const TypeArguments& type_arguments);
 
   RawFunction* BuildConstructorClosureFunction(const Function& ctr,
-                                               intptr_t token_pos);
+                                               TokenPosition token_pos);
   AstNode* ParseNewOperator(Token::Kind op_kind);
   void ParseConstructorClosurization(Function* constructor,
                                      TypeArguments* type_arguments);
@@ -727,24 +746,25 @@
                                           bool require_const);
   AstNode* ParseStaticCall(const Class& cls,
                            const String& method_name,
-                           intptr_t ident_pos);
+                           TokenPosition ident_pos);
   AstNode* ParseInstanceCall(AstNode* receiver,
                              const String& method_name,
-                             intptr_t ident_pos,
+                             TokenPosition ident_pos,
                              bool is_conditional);
   AstNode* ParseClosureCall(AstNode* closure);
   AstNode* GenerateStaticFieldLookup(const Field& field,
-                                     intptr_t ident_pos);
+                                     TokenPosition ident_pos);
   AstNode* GenerateStaticFieldAccess(const Class& cls,
                                      const String& field_name,
-                                     intptr_t ident_pos);
+                                     TokenPosition ident_pos);
 
   LocalVariable* LookupLocalScope(const String& ident);
-  void CheckInstanceFieldAccess(intptr_t field_pos, const String& field_name);
+  void CheckInstanceFieldAccess(TokenPosition field_pos,
+                                const String& field_name);
   bool ParsingStaticMember() const;
   const AbstractType* ReceiverType(const Class& cls);
   bool IsInstantiatorRequired() const;
-  bool ResolveIdentInLocalScope(intptr_t ident_pos,
+  bool ResolveIdentInLocalScope(TokenPosition ident_pos,
                                 const String &ident,
                                 AstNode** node);
   static const bool kResolveLocally = true;
@@ -752,28 +772,29 @@
 
   // Resolve a primary identifier in the library or prefix scope and
   // generate the corresponding AstNode.
-  AstNode* ResolveIdentInCurrentLibraryScope(intptr_t ident_pos,
+  AstNode* ResolveIdentInCurrentLibraryScope(TokenPosition ident_pos,
                                              const String& ident);
-  AstNode* ResolveIdentInPrefixScope(intptr_t ident_pos,
+  AstNode* ResolveIdentInPrefixScope(TokenPosition ident_pos,
                                      const LibraryPrefix& prefix,
                                      const String& ident);
 
-  AstNode* ResolveIdent(intptr_t ident_pos,
+  AstNode* ResolveIdent(TokenPosition ident_pos,
                         const String& ident,
                         bool allow_closure_names);
-  RawString* ResolveImportVar(intptr_t ident_pos, const String& ident);
-  AstNode* OptimizeBinaryOpNode(intptr_t op_pos,
+  RawString* ResolveImportVar(TokenPosition ident_pos, const String& ident);
+  AstNode* OptimizeBinaryOpNode(TokenPosition op_pos,
                                 Token::Kind binary_op,
                                 AstNode* lhs,
                                 AstNode* rhs);
-  AstNode* ExpandAssignableOp(intptr_t op_pos,
+  AstNode* ExpandAssignableOp(TokenPosition op_pos,
                               Token::Kind assignment_op,
                               AstNode* lhs,
                               AstNode* rhs);
   LetNode* PrepareCompoundAssignmentNodes(AstNode** expr);
-  LocalVariable* CreateTempConstVariable(intptr_t token_pos, const char* s);
+  LocalVariable* CreateTempConstVariable(TokenPosition token_pos,
+                                         const char* s);
 
-  static SequenceNode* NodeAsSequenceNode(intptr_t sequence_pos,
+  static SequenceNode* NodeAsSequenceNode(TokenPosition sequence_pos,
                                           AstNode* node,
                                           LocalScope* scope);
 
@@ -782,10 +803,11 @@
                           const String& func_name,
                           ArgumentListNode* arguments);
   String& Interpolate(const GrowableArray<AstNode*>& values);
-  AstNode* MakeAssertCall(intptr_t begin, intptr_t end);
-  AstNode* ThrowTypeError(intptr_t type_pos, const AbstractType& type,
-                           LibraryPrefix* prefix = NULL);
-  AstNode* ThrowNoSuchMethodError(intptr_t call_pos,
+  AstNode* MakeAssertCall(TokenPosition begin, TokenPosition end);
+  AstNode* ThrowTypeError(TokenPosition type_pos,
+                          const AbstractType& type,
+                          LibraryPrefix* prefix = NULL);
+  AstNode* ThrowNoSuchMethodError(TokenPosition call_pos,
                                   const Class& cls,
                                   const String& function_name,
                                   ArgumentListNode* function_arguments,
@@ -799,29 +821,30 @@
   void CheckOperatorArity(const MemberDesc& member);
 
   void EnsureExpressionTemp();
-  bool IsLegalAssignableSyntax(AstNode* expr, intptr_t end_pos);
+  bool IsLegalAssignableSyntax(AstNode* expr, TokenPosition end_pos);
   AstNode* CreateAssignmentNode(AstNode* original,
                                 AstNode* rhs,
                                 const String* left_ident,
-                                intptr_t left_pos,
+                                TokenPosition left_pos,
                                 bool is_compound = false);
   AstNode* InsertClosureCallNodes(AstNode* condition);
 
   ConstructorCallNode* CreateConstructorCallNode(
-      intptr_t token_pos,
+      TokenPosition token_pos,
       const TypeArguments& type_arguments,
       const Function& constructor,
       ArgumentListNode* arguments);
 
   void AddEqualityNullCheck();
 
-  AstNode* BuildClosureCall(intptr_t token_pos,
+  AstNode* BuildClosureCall(TokenPosition token_pos,
                             AstNode* closure,
                             ArgumentListNode* arguments);
 
-  RawInstance* TryCanonicalize(const Instance& instance, intptr_t token_pos);
-  void CacheConstantValue(intptr_t token_pos, const Instance& value);
-  bool GetCachedConstant(intptr_t token_pos, Instance* value);
+  RawInstance* TryCanonicalize(const Instance& instance,
+                               TokenPosition token_pos);
+  void CacheConstantValue(TokenPosition token_pos, const Instance& value);
+  bool GetCachedConstant(TokenPosition token_pos, Instance* value);
 
   Thread* thread() const { return thread_; }
   Isolate* isolate() const { return isolate_; }
@@ -833,6 +856,7 @@
   Script& script_;
   TokenStream::Iterator tokens_iterator_;
   Token::Kind token_kind_;  // Cached token kind for current token.
+  TokenPosition prev_token_pos_;
   Block* current_block_;
 
   // is_top_level_ is true if parsing the "top level" of a compilation unit,
@@ -889,6 +913,9 @@
   // Indentation of parser trace.
   intptr_t trace_indent_;
 
+  intptr_t recursion_counter_;
+  friend class RecursionChecker;
+
   DISALLOW_COPY_AND_ASSIGN(Parser);
 };
 
diff --git a/runtime/vm/parser_test.cc b/runtime/vm/parser_test.cc
index e7450b7..5889227 100644
--- a/runtime/vm/parser_test.cc
+++ b/runtime/vm/parser_test.cc
@@ -18,7 +18,9 @@
 DECLARE_FLAG(bool, show_invisible_frames);
 
 
-void DumpFunction(const Library& lib, const char* cname, const char* fname) {
+static void DumpFunction(const Library& lib,
+                         const char* cname,
+                         const char* fname) {
   const String& classname = String::Handle(Symbols::New(cname));
   String& funcname = String::Handle(String::New(fname));
 
@@ -36,7 +38,11 @@
     Parser::ParseFunction(parsed_function);
     EXPECT(parsed_function->node_sequence() != NULL);
     printf("Class %s function %s:\n", cname, fname);
-    AstPrinter::PrintFunctionNodes(*parsed_function);
+    if (FLAG_support_ast_printer) {
+      AstPrinter::PrintFunctionNodes(*parsed_function);
+    } else {
+      OS::Print("AST printer not supported.");
+    }
     retval = true;
   } else {
     retval = false;
@@ -168,10 +174,13 @@
 }
 
 
-const char* saved_vars = NULL;
+#ifndef PRODUCT
 
 
-char* SkipIndex(const char* input) {
+static const char* saved_vars = NULL;
+
+
+static char* SkipIndex(const char* input) {
   char* output_buffer = new char[strlen(input)];
   char* output = output_buffer;
 
@@ -270,7 +279,7 @@
       "   name=:current_context_var\n"
 
       // Closure call saves current context.
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -309,7 +318,7 @@
       "   name=:current_context_var\n"
 
       // Closure call saves current context.
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -325,7 +334,7 @@
       " 3 StackVar      scope=2   begin=18  end=38  name=c\n"
 
       // Closure call saves current context.
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -368,7 +377,7 @@
       "   name=:current_context_var\n"
 
       // Closure call saves current context.
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -384,7 +393,7 @@
       " 3 StackVar      scope=2   begin=30  end=52  name=bb\n"
 
       // Closure call saves current context.
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -397,7 +406,7 @@
       " 2 StackVar      scope=2   begin=18  end=62  name=aa\n"
 
       // Closure call saves current context.
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -450,7 +459,7 @@
       "   name=:current_context_var\n"
 
       // Closure call saves current context.
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -495,7 +504,7 @@
       "   name=:current_context_var\n"
 
       // Closure call saves current context.
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -536,7 +545,7 @@
       " 0 ContextVar    level=0   begin=50  end=62  name=x\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -551,7 +560,7 @@
       " 4 ContextVar    level=1   begin=22  end=47  name=i\n"
       " 5 StackVar      scope=4   begin=32  end=47  name=d\n"
 
-      "_FunctionImpl.call\n"
+      "_Closure.call\n"
       " 0 StackVar      scope=1   begin=0   end=4   name=this\n"
       " 1 CurrentCtx    scope=0   begin=0   end=0"
       "   name=:current_context_var\n"
@@ -565,4 +574,6 @@
       CaptureVarsAtLine(lib, "a", 10));
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc
index 3451ec6..a57b93f 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -305,12 +305,15 @@
 
 void PortMap::PrintPortsForMessageHandler(MessageHandler* handler,
                                           JSONStream* stream) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject jsobj(stream);
   jsobj.AddProperty("type", "_Ports");
   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 97f90c3..2f876e0 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -4,17 +4,42 @@
 
 #include "vm/precompiler.h"
 
+#include "vm/aot_optimizer.h"
+#include "vm/assembler.h"
+#include "vm/ast_printer.h"
+#include "vm/branch_optimizer.h"
 #include "vm/cha.h"
+#include "vm/code_generator.h"
 #include "vm/code_patcher.h"
 #include "vm/compiler.h"
+#include "vm/constant_propagator.h"
+#include "vm/dart_entry.h"
+#include "vm/disassembler.h"
+#include "vm/exceptions.h"
+#include "vm/flags.h"
+#include "vm/flow_graph.h"
+#include "vm/flow_graph_allocator.h"
+#include "vm/flow_graph_builder.h"
+#include "vm/flow_graph_compiler.h"
+#include "vm/flow_graph_inliner.h"
+#include "vm/flow_graph_range_analysis.h"
+#include "vm/flow_graph_type_propagator.h"
 #include "vm/hash_table.h"
+#include "vm/il_printer.h"
 #include "vm/isolate.h"
 #include "vm/log.h"
 #include "vm/longjump.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
+#include "vm/os.h"
+#include "vm/parser.h"
+#include "vm/redundancy_elimination.h"
+#include "vm/regexp_assembler.h"
+#include "vm/regexp_parser.h"
 #include "vm/resolver.h"
 #include "vm/symbols.h"
+#include "vm/tags.h"
+#include "vm/timer.h"
 
 namespace dart {
 
@@ -24,11 +49,57 @@
 #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,
+    "Max number of attempts with speculative inlining (precompilation only)");
+
+DECLARE_FLAG(bool, allocation_sinking);
+DECLARE_FLAG(bool, common_subexpression_elimination);
+DECLARE_FLAG(bool, constant_propagation);
+DECLARE_FLAG(bool, loop_invariant_code_motion);
+DECLARE_FLAG(bool, print_flow_graph);
+DECLARE_FLAG(bool, print_flow_graph_optimized);
+DECLARE_FLAG(bool, range_analysis);
+DECLARE_FLAG(bool, trace_compiler);
+DECLARE_FLAG(bool, trace_optimizing_compiler);
+DECLARE_FLAG(bool, trace_bailout);
+DECLARE_FLAG(bool, use_inlining);
+DECLARE_FLAG(bool, verify_compiler);
+DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
+DECLARE_FLAG(bool, trace_failed_optimization_attempts);
+DECLARE_FLAG(bool, trace_inlining_intervals);
+DECLARE_FLAG(bool, trace_irregexp);
+
+#ifdef DART_PRECOMPILER
+
+class PrecompileParsedFunctionHelper : public ValueObject {
+ public:
+  PrecompileParsedFunctionHelper(ParsedFunction* parsed_function,
+                                 bool optimized)
+      : parsed_function_(parsed_function),
+        optimized_(optimized),
+        thread_(Thread::Current()) {
+  }
+
+  bool Compile(CompilationPipeline* pipeline);
+
+ private:
+  ParsedFunction* parsed_function() const { return parsed_function_; }
+  bool optimized() const { return optimized_; }
+  Thread* thread() const { return thread_; }
+  Isolate* isolate() const { return thread_->isolate(); }
+
+  void FinalizeCompilation(Assembler* assembler,
+                           FlowGraphCompiler* graph_compiler,
+                           FlowGraph* flow_graph);
+
+  ParsedFunction* parsed_function_;
+  const bool optimized_;
+  Thread* const thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrecompileParsedFunctionHelper);
+};
 
 
 static void Jump(const Error& error) {
@@ -45,9 +116,9 @@
     precompiler.DoCompileAll(embedder_entry_points);
     return Error::null();
   } else {
-    Isolate* isolate = Isolate::Current();
-    const Error& error = Error::Handle(isolate->object_store()->sticky_error());
-    isolate->object_store()->clear_sticky_error();
+    Thread* thread = Thread::Current();
+    const Error& error = Error::Handle(thread->sticky_error());
+    thread->clear_sticky_error();
     return error.raw();
   }
 }
@@ -55,7 +126,7 @@
 
 Precompiler::Precompiler(Thread* thread, bool reset_fields) :
     thread_(thread),
-    zone_(thread->zone()),
+    zone_(NULL),
     isolate_(thread->isolate()),
     reset_fields_(reset_fields),
     changed_(false),
@@ -63,12 +134,21 @@
     class_count_(0),
     selector_count_(0),
     dropped_function_count_(0),
-    libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())),
+    dropped_field_count_(0),
+    dropped_class_count_(0),
+    dropped_typearg_count_(0),
+    dropped_type_count_(0),
+    dropped_library_count_(0),
+    libraries_(GrowableObjectArray::Handle(I->object_store()->libraries())),
     pending_functions_(
-        GrowableObjectArray::Handle(Z, GrowableObjectArray::New())),
+        GrowableObjectArray::Handle(GrowableObjectArray::New())),
     sent_selectors_(),
     enqueued_functions_(),
-    error_(Error::Handle(Z)) {
+    fields_to_retain_(),
+    classes_to_retain_(),
+    typeargs_to_retain_(),
+    types_to_retain_(),
+    error_(Error::Handle()) {
 }
 
 
@@ -76,58 +156,86 @@
     Dart_QualifiedFunctionName embedder_entry_points[]) {
   ASSERT(I->compilation_allowed());
 
-  // Make sure class hierarchy is stable before compilation so that CHA
-  // can be used. Also ensures lookup of entry points won't miss functions
-  // because their class hasn't been finalized yet.
-  FinalizeAllClasses();
+  {
+    StackZone stack_zone(T);
+    zone_ = stack_zone.GetZone();
 
-  const intptr_t kPrecompilerRounds = 1;
-  for (intptr_t round = 0; round < kPrecompilerRounds; round++) {
-    if (FLAG_trace_precompiler) {
-      OS::Print("Precompiler round %" Pd "\n", round);
+    // Make sure class hierarchy is stable before compilation so that CHA
+    // can be used. Also ensures lookup of entry points won't miss functions
+    // because their class hasn't been finalized yet.
+    FinalizeAllClasses();
+
+    const intptr_t kPrecompilerRounds = 1;
+    for (intptr_t round = 0; round < kPrecompilerRounds; round++) {
+      if (FLAG_trace_precompiler) {
+        THR_Print("Precompiler round %" Pd "\n", round);
+      }
+
+      if (round > 0) {
+        ResetPrecompilerState();
+      }
+
+      // TODO(rmacnak): We should be able to do a more thorough job and drop
+      // some
+      //  - implicit static closures
+      //  - field initializers
+      //  - invoke-field-dispatchers
+      //  - method-extractors
+      // that are needed in early iterations but optimized away in later
+      // iterations.
+      ClearAllCode();
+
+      CollectDynamicFunctionNames();
+
+      // Start with the allocations and invocations that happen from C++.
+      AddRoots(embedder_entry_points);
+
+      // Compile newly found targets and add their callees until we reach a
+      // fixed point.
+      Iterate();
     }
 
-    if (round > 0) {
-      ResetPrecompilerState();
+    I->set_compilation_allowed(false);
+
+    DropFunctions();
+    DropFields();
+    TraceTypesFromRetainedClasses();
+    DropTypes();
+    DropTypeArguments();
+    DropClasses();
+    DropLibraries();
+
+    BindStaticCalls();
+
+    DedupStackmaps();
+    DedupStackmapLists();
+
+    if (FLAG_dedup_instructions) {
+      // Reduces binary size but obfuscates profiler results.
+      DedupInstructions();
     }
 
-    // TODO(rmacnak): We should be able to do a more thorough job and drop some
-    //  - implicit static closures
-    //  - field initializers
-    //  - invoke-field-dispatchers
-    //  - method-extractors
-    // that are needed in early iterations but optimized away in later
-    // iterations.
-    ClearAllCode();
+    I->object_store()->set_compile_time_constants(Array::null_array());
+    I->object_store()->set_unique_dynamic_targets(Array::null_array());
 
-    CollectDynamicFunctionNames();
-
-    // Start with the allocations and invocations that happen from C++.
-    AddRoots(embedder_entry_points);
-
-    // Compile newly found targets and add their callees until we reach a fixed
-    // point.
-    Iterate();
+    zone_ = NULL;
   }
 
-  DropUncompiledFunctions();
-
-  // TODO(rmacnak): DropEmptyClasses();
-
-  BindStaticCalls();
-
-  DedupStackmaps();
+  intptr_t dropped_symbols_count = Symbols::Compact(I);
 
   if (FLAG_trace_precompiler) {
-    THR_Print("Precompiled %" Pd " functions, %" Pd " dynamic types,"
-              " %" Pd " dynamic selectors.\n Dropped %" Pd " functions.\n",
-              function_count_,
-              class_count_,
-              selector_count_,
-              dropped_function_count_);
-  }
+    THR_Print("Precompiled %" Pd " functions,", function_count_);
+    THR_Print(" %" Pd " dynamic types,", class_count_);
+    THR_Print(" %" Pd " dynamic selectors.\n", selector_count_);
 
-  I->set_compilation_allowed(false);
+    THR_Print("Dropped %" Pd " functions,", dropped_function_count_);
+    THR_Print(" %" Pd " fields,", dropped_field_count_);
+    THR_Print(" %" Pd " symbols,", dropped_symbols_count);
+    THR_Print(" %" Pd " types,", dropped_type_count_);
+    THR_Print(" %" Pd " type arguments,", dropped_typearg_count_);
+    THR_Print(" %" Pd " classes,", dropped_class_count_);
+    THR_Print(" %" Pd " libraries.\n", dropped_library_count_);
+  }
 }
 
 
@@ -135,6 +243,7 @@
   class ClearCodeFunctionVisitor : public FunctionVisitor {
     void VisitFunction(const Function& function) {
       function.ClearCode();
+      function.ClearICDataArray();
     }
   };
   ClearCodeFunctionVisitor visitor;
@@ -151,81 +260,25 @@
   AddSelector(Symbols::Call());  // For speed, not correctness.
 
   // Allocated from C++.
-  static const intptr_t kExternallyAllocatedCids[] = {
-    kBoolCid,
-    kNullCid,
-
-    kSmiCid,
-    kMintCid,
-    kBigintCid,
-    kDoubleCid,
-
-    kOneByteStringCid,
-    kTwoByteStringCid,
-    kExternalOneByteStringCid,
-    kExternalTwoByteStringCid,
-
-    kArrayCid,
-    kImmutableArrayCid,
-    kGrowableObjectArrayCid,
-    kLinkedHashMapCid,
-
-    kTypedDataUint8ClampedArrayCid,
-    kTypedDataUint8ArrayCid,
-    kTypedDataUint16ArrayCid,
-    kTypedDataUint32ArrayCid,
-    kTypedDataUint64ArrayCid,
-    kTypedDataInt8ArrayCid,
-    kTypedDataInt16ArrayCid,
-    kTypedDataInt32ArrayCid,
-    kTypedDataInt64ArrayCid,
-
-    kExternalTypedDataUint8ArrayCid,
-    kExternalTypedDataUint16ArrayCid,
-    kExternalTypedDataUint32ArrayCid,
-    kExternalTypedDataUint64ArrayCid,
-    kExternalTypedDataInt8ArrayCid,
-    kExternalTypedDataInt16ArrayCid,
-    kExternalTypedDataInt32ArrayCid,
-    kExternalTypedDataInt64ArrayCid,
-
-    kTypedDataFloat32ArrayCid,
-    kTypedDataFloat64ArrayCid,
-
-    kTypedDataFloat32x4ArrayCid,
-    kTypedDataInt32x4ArrayCid,
-    kTypedDataFloat64x2ArrayCid,
-
-    kInt32x4Cid,
-    kFloat32x4Cid,
-    kFloat64x2Cid,
-
-    kTypeCid,
-    kTypeRefCid,
-    kTypeParameterCid,
-    kBoundedTypeCid,
-    kLibraryPrefixCid,
-
-    kJSRegExpCid,
-    kUserTagCid,
-    kStacktraceCid,
-    kWeakPropertyCid,
-    kCapabilityCid,
-    ReceivePort::kClassId,
-    SendPort::kClassId,
-
-    kIllegalCid
-  };
-
   Class& cls = Class::Handle(Z);
-  for (intptr_t i = 0; kExternallyAllocatedCids[i] != kIllegalCid; i++) {
-    cls = isolate()->class_table()->At(kExternallyAllocatedCids[i]);
+  for (intptr_t cid = kInstanceCid; cid < kNumPredefinedCids; cid++) {
+    ASSERT(isolate()->class_table()->IsValidIndex(cid));
+    if (!isolate()->class_table()->HasValidClassAt(cid)) {
+      continue;
+    }
+    if ((cid == kDynamicCid) ||
+        (cid == kVoidCid) ||
+        (cid == kFreeListElement)) {
+      continue;
+    }
+    cls = isolate()->class_table()->At(cid);
     AddInstantiatedClass(cls);
   }
 
   Dart_QualifiedFunctionName vm_entry_points[] = {
+    // Functions
     { "dart:async", "::", "_setScheduleImmediateClosure" },
-    { "dart:core", "::", "_completeDeferredLoads"},
+    { "dart:core", "::", "_completeDeferredLoads" },
     { "dart:core", "AbstractClassInstantiationError",
                    "AbstractClassInstantiationError._create" },
     { "dart:core", "ArgumentError", "ArgumentError." },
@@ -244,10 +297,6 @@
     { "dart:core", "_CastError", "_CastError._create" },
     { "dart:core", "_InternalError", "_InternalError." },
     { "dart:core", "_InvocationMirror", "_allocateInvocationMirror" },
-    { "dart:core", "_JavascriptCompatibilityError",
-                   "_JavascriptCompatibilityError." },
-    { "dart:core", "_JavascriptIntegerOverflowError",
-                   "_JavascriptIntegerOverflowError." },
     { "dart:core", "_TypeError", "_TypeError._create" },
     { "dart:isolate", "IsolateSpawnException", "IsolateSpawnException." },
     { "dart:isolate", "::", "_getIsolateScheduleImmediateClosure" },
@@ -262,6 +311,9 @@
     { "dart:_vmservice", "::", "_registerIsolate" },
     { "dart:_vmservice", "::", "boot" },
     { "dart:developer", "Metrics", "_printMetrics" },
+    // Fields
+    { "dart:core", "Error", "_stackTrace" },
+    { "dart:math", "_Random", "_state" },
     { NULL, NULL, NULL }  // Must be terminated with NULL entries.
   };
 
@@ -274,6 +326,7 @@
   Library& lib = Library::Handle(Z);
   Class& cls = Class::Handle(Z);
   Function& func = Function::Handle(Z);
+  Field& field = Field::Handle(Z);
   String& library_uri = String::Handle(Z);
   String& class_name = String::Handle(Z);
   String& function_name = String::Handle(Z);
@@ -285,46 +338,60 @@
 
     lib = Library::LookupLibrary(library_uri);
     if (lib.IsNull()) {
-      if (FLAG_trace_precompiler) {
-        THR_Print("WARNING: Missing %s\n", entry_points[i].library_uri);
-      }
-      continue;
+      String& msg = String::Handle(Z, String::NewFormatted(
+          "Cannot find entry point %s\n", entry_points[i].library_uri));
+      Jump(Error::Handle(Z, ApiError::New(msg)));
+      UNREACHABLE();
     }
 
     if (class_name.raw() == Symbols::TopLevel().raw()) {
-      func = lib.LookupFunctionAllowPrivate(function_name);
+      if (Library::IsPrivate(function_name)) {
+        function_name = lib.PrivateName(function_name);
+      }
+      func = lib.LookupLocalFunction(function_name);
+      field = lib.LookupLocalField(function_name);
     } else {
-      cls = lib.LookupClassAllowPrivate(class_name);
+      if (Library::IsPrivate(class_name)) {
+        class_name = lib.PrivateName(class_name);
+      }
+      cls = lib.LookupLocalClass(class_name);
       if (cls.IsNull()) {
-        if (FLAG_trace_precompiler) {
-          THR_Print("WARNING: Missing %s %s\n",
-                    entry_points[i].library_uri,
-                    entry_points[i].class_name);
-        }
-        continue;
+        String& msg = String::Handle(Z, String::NewFormatted(
+            "Cannot find entry point %s %s\n",
+            entry_points[i].library_uri,
+            entry_points[i].class_name));
+        Jump(Error::Handle(Z, ApiError::New(msg)));
+        UNREACHABLE();
       }
 
       ASSERT(!cls.IsNull());
       func = cls.LookupFunctionAllowPrivate(function_name);
+      field = cls.LookupField(function_name);
     }
 
-    if (func.IsNull()) {
-      if (FLAG_trace_precompiler) {
-        THR_Print("WARNING: Missing %s %s %s\n",
-                  entry_points[i].library_uri,
-                  entry_points[i].class_name,
-                  entry_points[i].function_name);
+    if (func.IsNull() && field.IsNull()) {
+      String& msg = String::Handle(Z, String::NewFormatted(
+          "Cannot find entry point %s %s %s\n",
+          entry_points[i].library_uri,
+          entry_points[i].class_name,
+          entry_points[i].function_name));
+      Jump(Error::Handle(Z, ApiError::New(msg)));
+      UNREACHABLE();
+    }
+
+    if (!func.IsNull()) {
+      AddFunction(func);
+      if (func.IsGenerativeConstructor()) {
+        // Allocation stubs are referenced from the call site of the
+        // constructor, not in the constructor itself. So compiling the
+        // constructor isn't enough for us to discover the class is
+        // instantiated if the class isn't otherwise instantiated from Dart
+        // code and only instantiated from C++.
+        AddInstantiatedClass(cls);
       }
-      continue;
     }
-
-    AddFunction(func);
-    if (func.IsGenerativeConstructor()) {
-      // Allocation stubs are referenced from the call site of the constructor,
-      // not in the constructor itself. So compiling the constructor isn't
-      // enough for us to discover the class is instantiated if the class isn't
-      // otherwise instantiated from Dart code and only instantiated from C++.
-      AddInstantiatedClass(cls);
+    if (!field.IsNull()) {
+      AddField(field);
     }
   }
 }
@@ -351,27 +418,29 @@
     function_count_++;
 
     if (FLAG_trace_precompiler) {
-      THR_Print("Precompiling %" Pd " %s (%" Pd ", %s)\n",
+      THR_Print("Precompiling %" Pd " %s (%s, %s)\n",
                 function_count_,
                 function.ToLibNamePrefixedQualifiedCString(),
-                function.token_pos(),
+                function.token_pos().ToCString(),
                 Function::KindToCString(function.kind()));
     }
 
     ASSERT(!function.is_abstract());
     ASSERT(!function.IsRedirectingFactory());
 
-    error_ = Compiler::CompileFunction(thread_, function);
+    error_ = CompileFunction(thread_, function);
     if (!error_.IsNull()) {
       Jump(error_);
     }
+    // Used in the JIT to save type-feedback across compilations.
+    function.ClearICDataArray();
   } else {
     if (FLAG_trace_precompiler) {
       // This function was compiled from somewhere other than Precompiler,
       // such as const constructors compiled by the parser.
-      THR_Print("Already has code: %s (%" Pd ", %s)\n",
+      THR_Print("Already has code: %s (%s, %s)\n",
                 function.ToLibNamePrefixedQualifiedCString(),
-                function.token_pos(),
+                function.token_pos().ToCString(),
                 Function::KindToCString(function.kind()));
     }
   }
@@ -392,7 +461,7 @@
   for (intptr_t i = 0; i < table.Length(); i++) {
     entry = table.At(i);
     if (entry.IsFunction()) {
-      target ^= table.At(i);
+      target ^= entry.raw();
       AddFunction(target);
     }
   }
@@ -414,9 +483,8 @@
       entry = pool.ObjectAt(i);
       if (entry.IsICData()) {
         call_site ^= entry.raw();
-        if (call_site.NumberOfChecks() == 1) {
-          // Probably a static call.
-          target = call_site.GetTargetAt(0);
+        for (intptr_t j = 0; j < call_site.NumberOfChecks(); j++) {
+          target = call_site.GetTargetAt(j);
           AddFunction(target);
           if (!target.is_static()) {
             // Super call (should not enqueue selector) or dynamic call with a
@@ -424,7 +492,8 @@
             selector = call_site.target_name();
             AddSelector(selector);
           }
-        } else {
+        }
+        if (call_site.NumberOfChecks() == 0) {
           // A dynamic call.
           selector = call_site.target_name();
           AddSelector(selector);
@@ -445,7 +514,11 @@
       } else if (entry.IsInstance()) {
         // Const object, literal or args descriptor.
         instance ^= entry.raw();
-        AddConstObject(instance);
+        if (entry.IsAbstractType()) {
+          AddType(AbstractType::Cast(entry));
+        } else {
+          AddConstObject(instance);
+        }
       } else if (entry.IsFunction()) {
         // Local closure function.
         target ^= entry.raw();
@@ -456,21 +529,145 @@
           cls ^= target_code.owner();
           AddInstantiatedClass(cls);
         }
+      } else if (entry.IsTypeArguments()) {
+        AddTypeArguments(TypeArguments::Cast(entry));
       }
     }
   }
 }
 
 
+void Precompiler::AddTypesOf(const Class& cls) {
+  if (cls.IsNull()) return;
+  if (classes_to_retain_.Lookup(&cls) != NULL) return;
+  classes_to_retain_.Insert(&Class::ZoneHandle(Z, cls.raw()));
+
+  Array& interfaces = Array::Handle(Z, cls.interfaces());
+  AbstractType& type = AbstractType::Handle(Z);
+  for (intptr_t i = 0; i < interfaces.Length(); i++) {
+    type ^= interfaces.At(i);
+    AddType(type);
+  }
+
+  AddTypeArguments(TypeArguments::Handle(Z, cls.type_parameters()));
+
+  type = cls.super_type();
+  AddType(type);
+
+  type = cls.mixin();
+  AddType(type);
+
+  if (cls.IsTypedefClass()) {
+    AddTypesOf(Function::Handle(Z, cls.signature_function()));
+  }
+}
+
+
+void Precompiler::AddTypesOf(const Function& function) {
+  AbstractType& type = AbstractType::Handle(Z);
+  type = function.result_type();
+  AddType(type);
+  for (intptr_t i = 0; i < function.NumParameters(); i++) {
+    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);
+}
+
+
+void Precompiler::AddType(const AbstractType& abstype) {
+  if (abstype.IsNull()) return;
+
+  if (types_to_retain_.Lookup(&abstype) != NULL) return;
+  types_to_retain_.Insert(&AbstractType::ZoneHandle(Z, abstype.raw()));
+
+  if (abstype.IsType()) {
+    const Type& type = Type::Cast(abstype);
+    const Class& cls = Class::Handle(Z, type.type_class());
+    AddTypesOf(cls);
+    const TypeArguments& vector = TypeArguments::Handle(Z, abstype.arguments());
+    AddTypeArguments(vector);
+  } else if (abstype.IsFunctionType()) {
+    const FunctionType& func_type = FunctionType::Cast(abstype);
+    const Class& cls = Class::Handle(Z, func_type.scope_class());
+    AddTypesOf(cls);
+    const Function& func = Function::Handle(Z, func_type.signature());
+    AddTypesOf(func);
+    const TypeArguments& vector = TypeArguments::Handle(Z, abstype.arguments());
+    AddTypeArguments(vector);
+  } else if (abstype.IsBoundedType()) {
+    AbstractType& type = AbstractType::Handle(Z);
+    type = BoundedType::Cast(abstype).type();
+    AddType(type);
+    type = BoundedType::Cast(abstype).bound();
+    AddType(type);
+  } else if (abstype.IsTypeRef()) {
+    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);
+  }
+}
+
+
+void Precompiler::AddTypeArguments(const TypeArguments& args) {
+  if (args.IsNull()) return;
+
+  if (typeargs_to_retain_.Lookup(&args) != NULL) return;
+  typeargs_to_retain_.Insert(&TypeArguments::ZoneHandle(Z, args.raw()));
+
+  AbstractType& arg = AbstractType::Handle(Z);
+  for (intptr_t i = 0; i < args.Length(); i++) {
+    arg = args.TypeAt(i);
+    AddType(arg);
+  }
+}
+
+
 void Precompiler::AddConstObject(const Instance& instance) {
   const Class& cls = Class::Handle(Z, instance.clazz());
   AddInstantiatedClass(cls);
 
   if (instance.IsClosure()) {
     // An implicit static closure.
-    const Function& func = Function::Handle(Z, Closure::function(instance));
+    const Function& func =
+        Function::Handle(Z, Closure::Cast(instance).function());
     ASSERT(func.is_static());
     AddFunction(func);
+    AddTypeArguments(TypeArguments::Handle(Z, instance.GetTypeArguments()));
     return;
   }
 
@@ -481,6 +678,10 @@
   // argument descriptors.
   if (!instance.IsCanonical()) return;
 
+  if (cls.NumTypeArguments() > 0) {
+    AddTypeArguments(TypeArguments::Handle(Z, instance.GetTypeArguments()));
+  }
+
   class ConstObjectVisitor : public ObjectPointerVisitor {
    public:
     ConstObjectVisitor(Precompiler* precompiler, Isolate* isolate) :
@@ -511,10 +712,8 @@
 void Precompiler::AddClosureCall(const ICData& call_site) {
   const Array& arguments_descriptor =
       Array::Handle(Z, call_site.arguments_descriptor());
-  const Type& function_impl =
-      Type::Handle(Z, I->object_store()->function_impl_type());
   const Class& cache_class =
-      Class::Handle(Z, function_impl.type_class());
+      Class::Handle(Z, I->object_store()->closure_class());
   const Function& dispatcher = Function::Handle(Z,
       cache_class.GetInvocationDispatcher(Symbols::Call(),
                                           arguments_descriptor,
@@ -525,6 +724,8 @@
 
 
 void Precompiler::AddField(const Field& field) {
+  fields_to_retain_.Insert(&Field::ZoneHandle(Z, field.raw()));
+
   if (field.is_static()) {
     const Object& value = Object::Handle(Z, field.StaticValue());
     if (value.IsInstance()) {
@@ -544,7 +745,11 @@
         }
         ASSERT(!Dart::IsRunningPrecompiledCode());
         field.SetStaticValue(Instance::Handle(field.SavedInitialStaticValue()));
-        Compiler::CompileStaticInitializer(field);
+        const Function& initializer =
+            Function::Handle(CompileStaticInitializer(field));
+        if (!initializer.IsNull()) {
+          field.SetPrecompiledInitializer(initializer);
+        }
       }
 
       const Function& function =
@@ -555,6 +760,127 @@
 }
 
 
+RawFunction* Precompiler::CompileStaticInitializer(const Field& field) {
+  ASSERT(field.is_static());
+  if (field.HasPrecompiledInitializer()) {
+    // TODO(rmacnak): Investigate why this happens for _enum_names.
+    THR_Print("Warning: Ignoring repeated request for initializer for %s\n",
+              field.ToCString());
+    return Function::null();
+  }
+  Thread* thread = Thread::Current();
+  StackZone zone(thread);
+
+  ParsedFunction* parsed_function = Parser::ParseStaticFieldInitializer(field);
+
+  parsed_function->AllocateVariables();
+  // Non-optimized code generator.
+  DartCompilationPipeline pipeline;
+  PrecompileParsedFunctionHelper helper(parsed_function,
+                                        /* optimized = */ false);
+  helper.Compile(&pipeline);
+  return parsed_function->function().raw();
+}
+
+
+RawObject* Precompiler::EvaluateStaticInitializer(const Field& field) {
+  ASSERT(field.is_static());
+  // The VM sets the field's value to transiton_sentinel prior to
+  // evaluating the initializer value.
+  ASSERT(field.StaticValue() == Object::transition_sentinel().raw());
+  LongJumpScope jump;
+  if (setjmp(*jump.Set()) == 0) {
+    // Under precompilation, the initializer may have already been compiled, in
+    // which case use it. Under lazy compilation or early in precompilation, the
+    // initializer has not yet been created, so create it now, but don't bother
+    // remembering it because it won't be used again.
+    Function& initializer = Function::Handle();
+    if (!field.HasPrecompiledInitializer()) {
+      initializer = CompileStaticInitializer(field);
+      Code::Handle(initializer.unoptimized_code()).set_var_descriptors(
+          Object::empty_var_descriptors());
+    } else {
+      initializer ^= field.PrecompiledInitializer();
+    }
+    // Invoke the function to evaluate the expression.
+    return DartEntry::InvokeFunction(initializer, Object::empty_array());
+  } else {
+    Thread* const thread = Thread::Current();
+    StackZone zone(thread);
+    const Error& error =
+        Error::Handle(thread->zone(), thread->sticky_error());
+    thread->clear_sticky_error();
+    return error.raw();
+  }
+  UNREACHABLE();
+  return Object::null();
+}
+
+
+RawObject* Precompiler::ExecuteOnce(SequenceNode* fragment) {
+  LongJumpScope jump;
+  if (setjmp(*jump.Set()) == 0) {
+    Thread* const thread = Thread::Current();
+    if (FLAG_support_ast_printer && FLAG_trace_compiler) {
+      THR_Print("compiling expression: ");
+      AstPrinter::PrintNode(fragment);
+    }
+
+    // Create a dummy function object for the code generator.
+    // The function needs to be associated with a named Class: the interface
+    // Function fits the bill.
+    const char* kEvalConst = "eval_const";
+    const Function& func = Function::ZoneHandle(Function::New(
+        String::Handle(Symbols::New(kEvalConst)),
+        RawFunction::kRegularFunction,
+        true,  // static function
+        false,  // not const function
+        false,  // not abstract
+        false,  // not external
+        false,  // not native
+        Class::Handle(Type::Handle(Type::Function()).type_class()),
+        fragment->token_pos()));
+
+    func.set_result_type(Object::dynamic_type());
+    func.set_num_fixed_parameters(0);
+    func.SetNumOptionalParameters(0, true);
+    // Manually generated AST, do not recompile.
+    func.SetIsOptimizable(false);
+    func.set_is_debuggable(false);
+
+    // We compile the function here, even though InvokeFunction() below
+    // would compile func automatically. We are checking fewer invariants
+    // here.
+    ParsedFunction* parsed_function = new ParsedFunction(thread, func);
+    parsed_function->SetNodeSequence(fragment);
+    fragment->scope()->AddVariable(parsed_function->EnsureExpressionTemp());
+    fragment->scope()->AddVariable(
+        parsed_function->current_context_var());
+    parsed_function->AllocateVariables();
+
+    // Non-optimized code generator.
+    DartCompilationPipeline pipeline;
+    PrecompileParsedFunctionHelper helper(parsed_function,
+                                          /* optimized = */ false);
+    helper.Compile(&pipeline);
+    Code::Handle(func.unoptimized_code()).set_var_descriptors(
+        Object::empty_var_descriptors());
+
+    const Object& result = PassiveObject::Handle(
+        DartEntry::InvokeFunction(func, Object::empty_array()));
+    return result.raw();
+  } else {
+    Thread* const thread = Thread::Current();
+    const Object& result =
+      PassiveObject::Handle(thread->sticky_error());
+    thread->clear_sticky_error();
+    return result.raw();
+  }
+  UNREACHABLE();
+  return Object::null();
+}
+
+
 void Precompiler::AddFunction(const Function& function) {
   if (enqueued_functions_.Lookup(&function) != NULL) return;
 
@@ -731,33 +1057,6 @@
 typedef UnorderedHashMap<NameFunctionsTraits> Table;
 
 
-class FunctionsTraits {
- public:
-  static bool IsMatch(const Object& a, const Object& b) {
-    Zone* zone = Thread::Current()->zone();
-    String& a_s = String::Handle(zone);
-    String& b_s = String::Handle(zone);
-    a_s = a.IsFunction() ? Function::Cast(a).name() : String::Cast(a).raw();
-    b_s = b.IsFunction() ? Function::Cast(b).name() : String::Cast(b).raw();
-    ASSERT(a_s.IsSymbol() && b_s.IsSymbol());
-    return a_s.raw() == b_s.raw();
-  }
-  static uword Hash(const Object& obj) {
-    if (obj.IsFunction()) {
-      return String::Handle(Function::Cast(obj).name()).Hash();
-    } else {
-      ASSERT(String::Cast(obj).IsSymbol());
-      return String::Cast(obj).Hash();
-    }
-  }
-  static RawObject* NewKey(const Function& function) {
-    return function.raw();
-  }
-};
-
-typedef UnorderedHashSet<FunctionsTraits> UniqueFunctionsSet;
-
-
 static void AddNameToFunctionsTable(Zone* zone,
                                     Table* table,
                                     const String& fname,
@@ -863,7 +1162,7 @@
 }
 
 
-void Precompiler::DropUncompiledFunctions() {
+void Precompiler::DropFunctions() {
   Library& lib = Library::Handle(Z);
   Class& cls = Class::Handle(Z);
   Array& functions = Array::Handle(Z);
@@ -871,6 +1170,7 @@
   Function& function2 = Function::Handle(Z);
   GrowableObjectArray& retained_functions = GrowableObjectArray::Handle(Z);
   GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
+  String& name = String::Handle(Z);
 
   for (intptr_t i = 0; i < libraries_.Length(); i++) {
     lib ^= libraries_.At(i);
@@ -897,7 +1197,17 @@
         if (retain) {
           retained_functions.Add(function);
           function.DropUncompiledImplicitClosureFunction();
+          AddTypesOf(function);
         } else {
+          bool top_level = cls.IsTopLevel();
+          if (top_level &&
+              (function.kind() != RawFunction::kImplicitStaticFinalGetter)) {
+            // Implicit static final getters are not added to the library
+            // dictionary in the first place.
+            name = function.DictionaryName();
+            bool removed = lib.RemoveObject(function, name);
+            ASSERT(removed);
+          }
           dropped_function_count_++;
           if (FLAG_trace_precompiler) {
             THR_Print("Precompilation dropping %s\n",
@@ -906,12 +1216,12 @@
         }
       }
 
-      functions = Array::New(retained_functions.Length(), Heap::kOld);
-      for (intptr_t j = 0; j < retained_functions.Length(); j++) {
-        function ^= retained_functions.At(j);
-        functions.SetAt(j, function);
+      if (retained_functions.Length() > 0) {
+        functions = Array::MakeArray(retained_functions);
+        cls.SetFunctions(functions);
+      } else {
+        cls.SetFunctions(Object::empty_array());
       }
-      cls.SetFunctions(functions);
     }
   }
 
@@ -919,8 +1229,10 @@
   retained_functions = GrowableObjectArray::New();
   for (intptr_t j = 0; j < closures.Length(); j++) {
     function ^= closures.At(j);
-    if (function.HasCode()) {
+    bool retain = function.HasCode();
+    if (retain) {
       retained_functions.Add(function);
+      AddTypesOf(function);
     } else {
       dropped_function_count_++;
       if (FLAG_trace_precompiler) {
@@ -933,6 +1245,302 @@
 }
 
 
+void Precompiler::DropFields() {
+  Library& lib = Library::Handle(Z);
+  Class& cls = Class::Handle(Z);
+  Array& fields = Array::Handle(Z);
+  Field& field = Field::Handle(Z);
+  GrowableObjectArray& retained_fields = GrowableObjectArray::Handle(Z);
+  String& name = String::Handle(Z);
+  AbstractType& type = AbstractType::Handle(Z);
+
+  for (intptr_t i = 0; i < libraries_.Length(); i++) {
+    lib ^= libraries_.At(i);
+    ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+    while (it.HasNext()) {
+      cls = it.GetNextClass();
+      if (cls.IsDynamicClass()) {
+        continue;  // class 'dynamic' is in the read-only VM isolate.
+      }
+
+      fields = cls.fields();
+      retained_fields = GrowableObjectArray::New();
+      for (intptr_t j = 0; j < fields.Length(); j++) {
+        field ^= fields.At(j);
+        bool retain = fields_to_retain_.Lookup(&field) != NULL;
+        if (retain) {
+          retained_fields.Add(field);
+          type = field.type();
+          AddType(type);
+        } else {
+          bool top_level = cls.IsTopLevel();
+          if (top_level) {
+            name = field.DictionaryName();
+            bool removed = lib.RemoveObject(field, name);
+            ASSERT(removed);
+          }
+          dropped_field_count_++;
+          if (FLAG_trace_precompiler) {
+            THR_Print("Precompilation dropping %s\n",
+                      field.ToCString());
+          }
+        }
+      }
+
+      if (retained_fields.Length() > 0) {
+        fields = Array::MakeArray(retained_fields);
+        cls.SetFields(fields);
+      } else {
+        cls.SetFields(Object::empty_array());
+      }
+    }
+  }
+}
+
+
+void Precompiler::DropTypes() {
+  Library& lib = Library::Handle(Z);
+  Class& cls = Class::Handle(Z);
+  Object& obj = Object::Handle(Z);
+  Array& arr = Array::Handle(Z);
+  GrowableObjectArray& retained_types = GrowableObjectArray::Handle(Z);
+  AbstractType& type = AbstractType::Handle(Z);
+
+  for (intptr_t i = 0; i < libraries_.Length(); i++) {
+    lib ^= libraries_.At(i);
+    ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+    while (it.HasNext()) {
+      cls = it.GetNextClass();
+      if (cls.IsDynamicClass()) {
+        continue;  // class 'dynamic' is in the read-only VM isolate.
+      }
+      obj = cls.canonical_types();
+      if (!obj.IsArray()) {
+        // Class only has one type, keep it.
+      } else {
+        // Class has many types.
+        arr ^= obj.raw();
+        retained_types = GrowableObjectArray::New();
+
+        // Always keep the first one.
+        ASSERT(arr.Length() >= 1);
+        obj = arr.At(0);
+        retained_types.Add(obj);
+
+        for (intptr_t i = 1; i < arr.Length(); i++) {
+          obj = arr.At(i);
+          if (obj.IsNull()) {
+            continue;
+          }
+          type ^= obj.raw();
+          bool retain = types_to_retain_.Lookup(&type) != NULL;
+          if (retain) {
+            retained_types.Add(type);
+          } else {
+            dropped_type_count_++;
+          }
+        }
+        arr = Array::MakeArray(retained_types);
+        cls.set_canonical_types(arr);
+      }
+    }
+  }
+}
+
+
+void Precompiler::DropTypeArguments() {
+  const Array& typeargs_table =
+      Array::Handle(Z, I->object_store()->canonical_type_arguments());
+  GrowableObjectArray& retained_typeargs =
+      GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+  TypeArguments& typeargs = TypeArguments::Handle(Z);
+  for (intptr_t i = 0; i < (typeargs_table.Length() - 1); i++) {
+    typeargs ^= typeargs_table.At(i);
+    bool retain = typeargs_to_retain_.Lookup(&typeargs) != NULL;
+    if (retain) {
+      retained_typeargs.Add(typeargs);
+    } else {
+      dropped_typearg_count_++;
+    }
+  }
+
+  const intptr_t dict_size =
+      Utils::RoundUpToPowerOfTwo(retained_typeargs.Length() * 4 / 3);
+  const Array& new_table = Array::Handle(Z, Array::New(dict_size + 1));
+
+  Object& element = Object::Handle(Z);
+  for (intptr_t i = 0; i < retained_typeargs.Length(); i++) {
+    typeargs ^= retained_typeargs.At(i);
+    intptr_t hash = typeargs.Hash();
+    intptr_t index = hash & (dict_size - 1);
+    element = new_table.At(index);
+    while (!element.IsNull()) {
+      index = (index + 1) & (dict_size - 1);
+      element = new_table.At(index);
+    }
+    new_table.SetAt(index, typeargs);
+  }
+
+  const Smi& used = Smi::Handle(Z, Smi::New(retained_typeargs.Length()));
+  new_table.SetAt(dict_size, used);
+
+  I->object_store()->set_canonical_type_arguments(new_table);
+}
+
+
+void Precompiler::TraceTypesFromRetainedClasses() {
+  Library& lib = Library::Handle(Z);
+  Class& cls = Class::Handle(Z);
+  Array& members = Array::Handle(Z);
+
+  for (intptr_t i = 0; i < libraries_.Length(); i++) {
+    lib ^= libraries_.At(i);
+    ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+    while (it.HasNext()) {
+      cls = it.GetNextClass();
+      if (cls.IsDynamicClass()) {
+        continue;  // class 'dynamic' is in the read-only VM isolate.
+      }
+
+      // The subclasses array is only needed for CHA.
+      cls.ClearDirectSubclasses();
+
+      bool retain = false;
+      members = cls.fields();
+      if (members.Length() > 0) {
+        retain = true;
+      }
+      members = cls.functions();
+      if (members.Length() > 0) {
+        retain = true;
+      }
+      if (cls.is_allocated()) {
+        retain = true;
+      }
+      if (cls.is_enum_class()) {
+        // Enum classes have live instances, so we cannot unregister
+        // them.
+        retain = true;
+      }
+      members = cls.constants();
+      if (members.Length() > 0) {
+        // --compile_all?
+        retain = true;
+      }
+
+      if (retain) {
+        AddTypesOf(cls);
+      }
+    }
+  }
+}
+
+
+void Precompiler::DropClasses() {
+  Library& lib = Library::Handle(Z);
+  Class& cls = Class::Handle(Z);
+  Array& members = Array::Handle(Z);
+  String& name = String::Handle(Z);
+
+#if defined(DEBUG)
+  {
+    // Force GC for allocation stats.
+    I->heap()->CollectAllGarbage();
+  }
+#endif
+
+  ClassTable* class_table = I->class_table();
+  intptr_t num_cids = class_table->NumCids();
+
+  for (intptr_t cid = kNumPredefinedCids; cid < num_cids; cid++) {
+    if (!class_table->IsValidIndex(cid)) continue;
+    if (!class_table->HasValidClassAt(cid)) continue;
+
+    cls = class_table->At(cid);
+    ASSERT(!cls.IsNull());
+
+    if (cls.IsTopLevel()) {
+      // Top-level classes are referenced directly from their library. They
+      // will only be removed as a consequence of an entire library being
+      // removed.
+      continue;
+    }
+    if (cls.is_enum_class()) {
+      // Enum classes have live instances, so we cannot unregister
+      // them.
+      continue;
+    }
+    members = cls.constants();
+    if (members.Length() > 0) {
+      // --compile_all?
+      continue;
+    }
+
+    bool retain = classes_to_retain_.Lookup(&cls) != NULL;
+    if (retain) {
+      continue;
+    }
+
+#if defined(DEBUG)
+    intptr_t instances =
+        class_table->StatsWithUpdatedSize(cid)->post_gc.new_count +
+        class_table->StatsWithUpdatedSize(cid)->post_gc.old_count;
+    if (instances != 0) {
+      FATAL2("Want to drop class %s, but it has %" Pd " instances\n",
+             cls.ToCString(),
+             instances);
+    }
+#endif
+
+    dropped_class_count_++;
+    if (FLAG_trace_precompiler) {
+      THR_Print("Precompilation dropping %" Pd " %s\n", cid, cls.ToCString());
+    }
+
+#if defined(DEBUG)
+    class_table->Unregister(cid);
+#endif
+    cls.set_id(kIllegalCid);  // We check this when serializing.
+
+    lib = cls.library();
+    name = cls.DictionaryName();
+    lib.RemoveObject(cls, name);
+  }
+}
+
+
+void Precompiler::DropLibraries() {
+  const GrowableObjectArray& retained_libraries =
+      GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+  Library& lib = Library::Handle(Z);
+
+  for (intptr_t i = 0; i < libraries_.Length(); i++) {
+    lib ^= libraries_.At(i);
+    lib.DropDependencies();
+    intptr_t entries = 0;
+    DictionaryIterator it(lib);
+    while (it.HasNext()) {
+      it.GetNext();
+      entries++;
+    }
+    bool retain = (entries > 0) || lib.is_dart_scheme();
+    if (retain) {
+      lib.set_index(retained_libraries.Length());
+      retained_libraries.Add(lib);
+    } else {
+      dropped_library_count_++;
+      lib.set_index(-1);
+      if (FLAG_trace_precompiler) {
+        THR_Print("Precompilation dropping %s\n", lib.ToCString());
+      }
+    }
+  }
+
+  I->object_store()->set_libraries(retained_libraries);
+  libraries_ = retained_libraries.raw();
+}
+
+
 void Precompiler::BindStaticCalls() {
   class BindStaticCallsVisitor : public FunctionVisitor {
    public:
@@ -1044,6 +1652,101 @@
 }
 
 
+void Precompiler::DedupStackmapLists() {
+  class DedupStackmapListsVisitor : public FunctionVisitor {
+   public:
+    explicit DedupStackmapListsVisitor(Zone* zone) :
+      zone_(zone),
+      canonical_stackmap_lists_(),
+      code_(Code::Handle(zone)),
+      stackmaps_(Array::Handle(zone)),
+      stackmap_(Stackmap::Handle(zone)) {
+    }
+
+    void VisitFunction(const Function& function) {
+      if (!function.HasCode()) {
+        ASSERT(function.HasImplicitClosureFunction());
+        return;
+      }
+      code_ = function.CurrentCode();
+      stackmaps_ = code_.stackmaps();
+      if (stackmaps_.IsNull()) return;
+
+      stackmaps_ = DedupStackmapList(stackmaps_);
+      code_.set_stackmaps(stackmaps_);
+    }
+
+    RawArray* DedupStackmapList(const Array& stackmaps) {
+      const Array* canonical_stackmap_list =
+          canonical_stackmap_lists_.Lookup(&stackmaps);
+      if (canonical_stackmap_list == NULL) {
+        canonical_stackmap_lists_.Insert(
+            &Array::ZoneHandle(zone_, stackmaps.raw()));
+        return stackmaps.raw();
+      } else {
+        return canonical_stackmap_list->raw();
+      }
+    }
+
+   private:
+    Zone* zone_;
+    ArraySet canonical_stackmap_lists_;
+    Code& code_;
+    Array& stackmaps_;
+    Stackmap& stackmap_;
+  };
+
+  DedupStackmapListsVisitor visitor(Z);
+  VisitFunctions(&visitor);
+}
+
+
+void Precompiler::DedupInstructions() {
+  class DedupInstructionsVisitor : public FunctionVisitor {
+   public:
+    explicit DedupInstructionsVisitor(Zone* zone) :
+      zone_(zone),
+      canonical_instructions_set_(),
+      code_(Code::Handle(zone)),
+      instructions_(Instructions::Handle(zone)) {
+    }
+
+    void VisitFunction(const Function& function) {
+      if (!function.HasCode()) {
+        ASSERT(function.HasImplicitClosureFunction());
+        return;
+      }
+      code_ = function.CurrentCode();
+      instructions_ = code_.instructions();
+      instructions_ = DedupOneInstructions(instructions_);
+      code_.SetActiveInstructions(instructions_.raw());
+      code_.set_instructions(instructions_.raw());
+      function.SetInstructions(code_);  // Update cached entry point.
+    }
+
+    RawInstructions* DedupOneInstructions(const Instructions& instructions) {
+      const Instructions* canonical_instructions =
+          canonical_instructions_set_.Lookup(&instructions);
+      if (canonical_instructions == NULL) {
+        canonical_instructions_set_.Insert(
+            &Instructions::ZoneHandle(zone_, instructions.raw()));
+        return instructions.raw();
+      } else {
+        return canonical_instructions->raw();
+      }
+    }
+
+   private:
+    Zone* zone_;
+    InstructionsSet canonical_instructions_set_;
+    Code& code_;
+    Instructions& instructions_;
+  };
+
+  DedupInstructionsVisitor visitor(Z);
+  VisitFunctions(&visitor);
+}
+
 void Precompiler::VisitFunctions(FunctionVisitor* visitor) {
   Library& lib = Library::Handle(Z);
   Class& cls = Class::Handle(Z);
@@ -1126,6 +1829,7 @@
   class_count_ = 0;
   selector_count_ = 0;
   dropped_function_count_ = 0;
+  dropped_field_count_ = 0;
   ASSERT(pending_functions_.Length() == 0);
   sent_selectors_.Clear();
   enqueued_functions_.Clear();
@@ -1146,4 +1850,697 @@
   }
 }
 
+
+void PrecompileParsedFunctionHelper::FinalizeCompilation(
+    Assembler* assembler,
+    FlowGraphCompiler* graph_compiler,
+    FlowGraph* flow_graph) {
+  const Function& function = parsed_function()->function();
+  Zone* const zone = thread()->zone();
+
+  CSTAT_TIMER_SCOPE(thread(), codefinalizer_timer);
+  // CreateDeoptInfo uses the object pool and needs to be done before
+  // FinalizeCode.
+  const Array& deopt_info_array =
+      Array::Handle(zone, graph_compiler->CreateDeoptInfo(assembler));
+  INC_STAT(thread(), total_code_size,
+           deopt_info_array.Length() * sizeof(uword));
+  // Allocates instruction object. Since this occurs only at safepoint,
+  // there can be no concurrent access to the instruction page.
+  const Code& code = Code::Handle(
+      Code::FinalizeCode(function, assembler, optimized()));
+  code.set_is_optimized(optimized());
+  code.set_owner(function);
+  if (!function.IsOptimizable()) {
+    // A function with huge unoptimized code can become non-optimizable
+    // after generating unoptimized code.
+    function.set_usage_counter(INT_MIN);
+  }
+
+  const Array& intervals = graph_compiler->inlined_code_intervals();
+  INC_STAT(thread(), total_code_size,
+           intervals.Length() * sizeof(uword));
+  code.SetInlinedIntervals(intervals);
+
+  const Array& inlined_id_array =
+      Array::Handle(zone, graph_compiler->InliningIdToFunction());
+  INC_STAT(thread(), total_code_size,
+           inlined_id_array.Length() * sizeof(uword));
+  code.SetInlinedIdToFunction(inlined_id_array);
+
+  const Array& caller_inlining_id_map_array =
+      Array::Handle(zone, graph_compiler->CallerInliningIdMap());
+  INC_STAT(thread(), total_code_size,
+           caller_inlining_id_map_array.Length() * sizeof(uword));
+  code.SetInlinedCallerIdMap(caller_inlining_id_map_array);
+
+  graph_compiler->FinalizePcDescriptors(code);
+  code.set_deopt_info_array(deopt_info_array);
+
+  graph_compiler->FinalizeStackmaps(code);
+  graph_compiler->FinalizeVarDescriptors(code);
+  graph_compiler->FinalizeExceptionHandlers(code);
+  graph_compiler->FinalizeStaticCallTargetsTable(code);
+
+  if (optimized()) {
+    // Installs code while at safepoint.
+    ASSERT(thread()->IsMutatorThread());
+    function.InstallOptimizedCode(code, /* is_osr = */ false);
+  } else {  // not optimized.
+    function.set_unoptimized_code(code);
+    function.AttachCode(code);
+  }
+  ASSERT(!parsed_function()->HasDeferredPrefixes());
+  ASSERT(FLAG_load_deferred_eagerly);
+}
+
+
+// Return false if bailed out.
+// If optimized_result_code is not NULL then it is caller's responsibility
+// to install code.
+bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
+  ASSERT(FLAG_precompiled_mode);
+  const Function& function = parsed_function()->function();
+  if (optimized() && !function.IsOptimizable()) {
+    return false;
+  }
+  bool is_compiled = false;
+  Zone* const zone = thread()->zone();
+#ifndef PRODUCT
+  TimelineStream* compiler_timeline = isolate()->GetCompilerStream();
+#endif  // !PRODUCT
+  CSTAT_TIMER_SCOPE(thread(), codegen_timer);
+  HANDLESCOPE(thread());
+
+  // We may reattempt compilation if the function needs to be assembled using
+  // far branches on ARM and MIPS. In the else branch of the setjmp call,
+  // done is set to false, and use_far_branches is set to true if there is a
+  // longjmp from the ARM or MIPS assemblers. In all other paths through this
+  // while loop, done is set to true. use_far_branches is always false on ia32
+  // and x64.
+  bool done = false;
+  // volatile because the variable may be clobbered by a longjmp.
+  volatile bool use_far_branches = false;
+  volatile bool use_speculative_inlining =
+      FLAG_max_speculative_inlining_attempts > 0;
+  GrowableArray<intptr_t> inlining_black_list;
+
+  while (!done) {
+    const intptr_t prev_deopt_id = thread()->deopt_id();
+    thread()->set_deopt_id(0);
+    LongJumpScope jump;
+    const intptr_t val = setjmp(*jump.Set());
+    if (val == 0) {
+      FlowGraph* flow_graph = NULL;
+
+      // Class hierarchy analysis is registered with the isolate in the
+      // constructor and unregisters itself upon destruction.
+      CHA cha(thread());
+
+      // TimerScope needs an isolate to be properly terminated in case of a
+      // LongJump.
+      {
+        CSTAT_TIMER_SCOPE(thread(), graphbuilder_timer);
+        ZoneGrowableArray<const ICData*>* ic_data_array =
+            new(zone) ZoneGrowableArray<const ICData*>();
+#ifndef PRODUCT
+        TimelineDurationScope tds(thread(),
+                                  compiler_timeline,
+                                  "BuildFlowGraph");
+#endif  // !PRODUCT
+        flow_graph = pipeline->BuildFlowGraph(zone,
+                                              parsed_function(),
+                                              *ic_data_array,
+                                              Compiler::kNoOSRDeoptId);
+      }
+
+      const bool print_flow_graph =
+          (FLAG_print_flow_graph ||
+           (optimized() && FLAG_print_flow_graph_optimized)) &&
+          FlowGraphPrinter::ShouldPrint(function);
+
+      if (print_flow_graph) {
+        FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph);
+      }
+
+      if (optimized()) {
+#ifndef PRODUCT
+        TimelineDurationScope tds(thread(),
+                                  compiler_timeline,
+                                  "ComputeSSA");
+#endif  // !PRODUCT
+        CSTAT_TIMER_SCOPE(thread(), ssa_timer);
+        // Transform to SSA (virtual register 0 and no inlining arguments).
+        flow_graph->ComputeSSA(0, NULL);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        if (print_flow_graph) {
+          FlowGraphPrinter::PrintGraph("After SSA", flow_graph);
+        }
+      }
+
+      // 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
+      // have non-generic type feedback attached to them that can
+      // potentially affect optimizations.
+      if (optimized()) {
+#ifndef PRODUCT
+        TimelineDurationScope tds(thread(),
+                                  compiler_timeline,
+                                  "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);
+
+        AotOptimizer optimizer(flow_graph,
+                               use_speculative_inlining,
+                               &inlining_black_list);
+        optimizer.PopulateWithICData();
+
+        optimizer.ApplyClassIds();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        FlowGraphTypePropagator::Propagate(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        optimizer.ApplyICData();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        // Optimize (a << b) & c patterns, merge operations.
+        // Run early in order to have more opportunity to optimize left shifts.
+        optimizer.TryOptimizePatterns();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        FlowGraphInliner::SetInliningId(flow_graph, 0);
+
+        // Inlining (mutates the flow graph)
+        if (FLAG_use_inlining) {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "Inlining");
+#endif  // !PRODUCT
+          CSTAT_TIMER_SCOPE(thread(), graphinliner_timer);
+          // Propagate types to create more inlining opportunities.
+          FlowGraphTypePropagator::Propagate(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+          // Use propagated class-ids to create more inlining opportunities.
+          optimizer.ApplyClassIds();
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+          FlowGraphInliner inliner(flow_graph,
+                                   &inline_id_to_function,
+                                   &inline_id_to_token_pos,
+                                   &caller_inline_id,
+                                   use_speculative_inlining,
+                                   &inlining_black_list);
+          inliner.Inline();
+          // Use lists are maintained and validated by the inliner.
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        // Propagate types and eliminate more type tests.
+        FlowGraphTypePropagator::Propagate(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "ApplyClassIds");
+#endif  // !PRODUCT
+          // Use propagated class-ids to optimize further.
+          optimizer.ApplyClassIds();
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        // Propagate types for potentially newly added instructions by
+        // ApplyClassIds(). Must occur before canonicalization.
+        FlowGraphTypePropagator::Propagate(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        // Do optimizations that depend on the propagated type information.
+        if (flow_graph->Canonicalize()) {
+          // Invoke Canonicalize twice in order to fully canonicalize patterns
+          // like "if (a & const == 0) { }".
+          flow_graph->Canonicalize();
+        }
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "BranchSimplifier");
+#endif  // !PRODUCT
+          BranchSimplifier::Simplify(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+          IfConverter::Simplify(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        if (FLAG_constant_propagation) {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "ConstantPropagation");
+#endif  // !PRODUCT
+          ConstantPropagator::Optimize(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+          // A canonicalization pass to remove e.g. smi checks on smi constants.
+          flow_graph->Canonicalize();
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+          // Canonicalization introduced more opportunities for constant
+          // propagation.
+          ConstantPropagator::Optimize(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        // Optimistically convert loop phis that have a single non-smi input
+        // coming from the loop pre-header into smi-phis.
+        if (FLAG_loop_invariant_code_motion) {
+          LICM licm(flow_graph);
+          licm.OptimisticallySpecializeSmiPhis();
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        // Propagate types and eliminate even more type tests.
+        // Recompute types after constant propagation to infer more precise
+        // types for uses that were previously reached by now eliminated phis.
+        FlowGraphTypePropagator::Propagate(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "SelectRepresentations");
+#endif  // !PRODUCT
+          // Where beneficial convert Smi operations into Int32 operations.
+          // Only meanigful for 32bit platforms right now.
+          flow_graph->WidenSmiToInt32();
+
+          // Unbox doubles. Performed after constant propagation to minimize
+          // interference from phis merging double values and tagged
+          // values coming from dead paths.
+          flow_graph->SelectRepresentations();
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "CommonSubexpressionElinination");
+#endif  // !PRODUCT
+          if (FLAG_common_subexpression_elimination ||
+              FLAG_loop_invariant_code_motion) {
+            flow_graph->ComputeBlockEffects();
+          }
+
+          if (FLAG_common_subexpression_elimination) {
+            if (DominatorBasedCSE::Optimize(flow_graph)) {
+              DEBUG_ASSERT(flow_graph->VerifyUseLists());
+              flow_graph->Canonicalize();
+              // Do another round of CSE to take secondary effects into account:
+              // e.g. when eliminating dependent loads (a.x[0] + a.x[0])
+              // TODO(fschneider): Change to a one-pass optimization pass.
+              if (DominatorBasedCSE::Optimize(flow_graph)) {
+                flow_graph->Canonicalize();
+              }
+              DEBUG_ASSERT(flow_graph->VerifyUseLists());
+            }
+          }
+
+          // Run loop-invariant code motion right after load elimination since
+          // it depends on the numbering of loads from the previous
+          // load-elimination.
+          if (FLAG_loop_invariant_code_motion) {
+            LICM licm(flow_graph);
+            licm.Optimize();
+            DEBUG_ASSERT(flow_graph->VerifyUseLists());
+          }
+          flow_graph->RemoveRedefinitions();
+        }
+
+        // Optimize (a << b) & c patterns, merge operations.
+        // Run after CSE in order to have more opportunity to merge
+        // instructions that have same inputs.
+        optimizer.TryOptimizePatterns();
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "DeadStoreElimination");
+#endif  // !PRODUCT
+          DeadStoreElimination::Optimize(flow_graph);
+        }
+
+        if (FLAG_range_analysis) {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "RangeAnalysis");
+#endif  // !PRODUCT
+          // Propagate types after store-load-forwarding. Some phis may have
+          // become smi phis that can be processed by range analysis.
+          FlowGraphTypePropagator::Propagate(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+          // We have to perform range analysis after LICM because it
+          // optimistically moves CheckSmi through phis into loop preheaders
+          // making some phis smi.
+          RangeAnalysis range_analysis(flow_graph);
+          range_analysis.Analyze();
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        if (FLAG_constant_propagation) {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "ConstantPropagator::OptimizeBranches");
+#endif  // !PRODUCT
+          // Constant propagation can use information from range analysis to
+          // find unreachable branch targets and eliminate branches that have
+          // the same true- and false-target.
+          ConstantPropagator::OptimizeBranches(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        // Recompute types after code movement was done to ensure correct
+        // reaching types for hoisted values.
+        FlowGraphTypePropagator::Propagate(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "TryCatchAnalyzer::Optimize");
+#endif  // !PRODUCT
+          // Optimize try-blocks.
+          TryCatchAnalyzer::Optimize(flow_graph);
+        }
+
+        // Detach environments from the instructions that can't deoptimize.
+        // Do it before we attempt to perform allocation sinking to minimize
+        // amount of materializations it has to perform.
+        flow_graph->EliminateEnvironments();
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "EliminateDeadPhis");
+#endif  // !PRODUCT
+          DeadCodeElimination::EliminateDeadPhis(flow_graph);
+          DEBUG_ASSERT(flow_graph->VerifyUseLists());
+        }
+
+        if (flow_graph->Canonicalize()) {
+          flow_graph->Canonicalize();
+        }
+
+        // Attempt to sink allocations of temporary non-escaping objects to
+        // the deoptimization path.
+        AllocationSinking* sinking = NULL;
+        if (FLAG_allocation_sinking &&
+            (flow_graph->graph_entry()->SuccessorCount()  == 1)) {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "AllocationSinking::Optimize");
+#endif  // !PRODUCT
+          // TODO(fschneider): Support allocation sinking with try-catch.
+          sinking = new AllocationSinking(flow_graph);
+          sinking->Optimize();
+        }
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        DeadCodeElimination::EliminateDeadPhis(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        FlowGraphTypePropagator::Propagate(flow_graph);
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "SelectRepresentations");
+#endif  // !PRODUCT
+          // Ensure that all phis inserted by optimization passes have
+          // consistent representations.
+          flow_graph->SelectRepresentations();
+        }
+
+        if (flow_graph->Canonicalize()) {
+          // To fully remove redundant boxing (e.g. BoxDouble used only in
+          // environments and UnboxDouble instructions) instruction we
+          // first need to replace all their uses and then fold them away.
+          // For now we just repeat Canonicalize twice to do that.
+          // TODO(vegorov): implement a separate representation folding pass.
+          flow_graph->Canonicalize();
+        }
+        DEBUG_ASSERT(flow_graph->VerifyUseLists());
+
+        if (sinking != NULL) {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(
+              thread(),
+              compiler_timeline,
+              "AllocationSinking::DetachMaterializations");
+#endif  // !PRODUCT
+          // Remove all MaterializeObject instructions inserted by allocation
+          // sinking from the flow graph and let them float on the side
+          // referenced only from environments. Register allocator will consider
+          // them as part of a deoptimization environment.
+          sinking->DetachMaterializations();
+        }
+
+        // Compute and store graph informations (call & instruction counts)
+        // to be later used by the inliner.
+        FlowGraphInliner::CollectGraphInfo(flow_graph, true);
+
+        {
+#ifndef PRODUCT
+          TimelineDurationScope tds2(thread(),
+                                     compiler_timeline,
+                                     "AllocateRegisters");
+#endif  // !PRODUCT
+          // Perform register allocation on the SSA graph.
+          FlowGraphAllocator allocator(*flow_graph);
+          allocator.AllocateRegisters();
+        }
+
+        if (print_flow_graph) {
+          FlowGraphPrinter::PrintGraph("After Optimizations", flow_graph);
+        }
+      }
+
+      ASSERT(inline_id_to_function.length() == caller_inline_id.length());
+      Assembler assembler(use_far_branches);
+      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);
+#ifndef PRODUCT
+        TimelineDurationScope tds(thread(),
+                                  compiler_timeline,
+                                  "CompileGraph");
+#endif  // !PRODUCT
+        graph_compiler.CompileGraph();
+        pipeline->FinalizeCompilation();
+      }
+      {
+#ifndef PRODUCT
+        TimelineDurationScope tds(thread(),
+                                  compiler_timeline,
+                                  "FinalizeCompilation");
+#endif  // !PRODUCT
+        ASSERT(thread()->IsMutatorThread());
+        FinalizeCompilation(&assembler, &graph_compiler, flow_graph);
+      }
+      // Mark that this isolate now has compiled code.
+      isolate()->set_has_compiled_code(true);
+      // Exit the loop and the function with the correct result value.
+      is_compiled = true;
+      done = true;
+    } else {
+      // We bailed out or we encountered an error.
+      const Error& error = Error::Handle(thread()->sticky_error());
+
+      if (error.raw() == Object::branch_offset_error().raw()) {
+        // Compilation failed due to an out of range branch offset in the
+        // assembler. We try again (done = false) with far branches enabled.
+        done = false;
+        ASSERT(!use_far_branches);
+        use_far_branches = true;
+      } else if (error.raw() == Object::speculative_inlining_error().raw()) {
+        // The return value of setjmp is the deopt id of the check instruction
+        // that caused the bailout.
+        done = false;
+#if defined(DEBUG)
+        ASSERT(use_speculative_inlining);
+        for (intptr_t i = 0; i < inlining_black_list.length(); ++i) {
+          ASSERT(inlining_black_list[i] != val);
+        }
+#endif
+        inlining_black_list.Add(val);
+        const intptr_t max_attempts = FLAG_max_speculative_inlining_attempts;
+        if (inlining_black_list.length() >= max_attempts) {
+          use_speculative_inlining = false;
+          if (FLAG_trace_compiler || FLAG_trace_optimizing_compiler) {
+            THR_Print("Disabled speculative inlining after %" Pd " attempts.\n",
+                      inlining_black_list.length());
+          }
+        }
+      } else {
+        // If the error isn't due to an out of range branch offset, we don't
+        // try again (done = true), and indicate that we did not finish
+        // compiling (is_compiled = false).
+        if (FLAG_trace_bailout) {
+          THR_Print("%s\n", error.ToErrorCString());
+        }
+        done = true;
+      }
+
+      // Clear the error if it was not a real error, but just a bailout.
+      if (error.IsLanguageError() &&
+          (LanguageError::Cast(error).kind() == Report::kBailout)) {
+        thread()->clear_sticky_error();
+      }
+      is_compiled = false;
+    }
+    // Reset global isolate state.
+    thread()->set_deopt_id(prev_deopt_id);
+  }
+  return is_compiled;
+}
+
+
+static RawError* PrecompileFunctionHelper(CompilationPipeline* pipeline,
+                                          const Function& function,
+                                          bool optimized) {
+  // Check that we optimize, except if the function is not optimizable.
+  ASSERT(FLAG_precompiled_mode);
+  ASSERT(!function.IsOptimizable() || optimized);
+  ASSERT(!function.HasCode());
+  LongJumpScope jump;
+  if (setjmp(*jump.Set()) == 0) {
+    Thread* const thread = Thread::Current();
+    StackZone stack_zone(thread);
+    Zone* const zone = stack_zone.GetZone();
+    const bool trace_compiler =
+        FLAG_trace_compiler ||
+        (FLAG_trace_optimizing_compiler && optimized);
+    Timer per_compile_timer(trace_compiler, "Compilation time");
+    per_compile_timer.Start();
+
+    ParsedFunction* parsed_function = new(zone) ParsedFunction(
+        thread, Function::ZoneHandle(zone, function.raw()));
+    if (trace_compiler) {
+      THR_Print(
+          "Precompiling %sfunction: '%s' @ token %" Pd ", size %" Pd "\n",
+          (optimized ? "optimized " : ""),
+          function.ToFullyQualifiedCString(),
+          function.token_pos().Pos(),
+          (function.end_token_pos().Pos() - function.token_pos().Pos()));
+    }
+    INC_STAT(thread, num_functions_compiled, 1);
+    if (optimized) {
+      INC_STAT(thread, num_functions_optimized, 1);
+    }
+    {
+      HANDLESCOPE(thread);
+      const int64_t num_tokens_before = STAT_VALUE(thread, num_tokens_consumed);
+      pipeline->ParseFunction(parsed_function);
+      const int64_t num_tokens_after = STAT_VALUE(thread, num_tokens_consumed);
+      INC_STAT(thread,
+               num_func_tokens_compiled,
+               num_tokens_after - num_tokens_before);
+    }
+
+    PrecompileParsedFunctionHelper helper(parsed_function, optimized);
+    const bool success = helper.Compile(pipeline);
+    if (!success) {
+      // Encountered error.
+      Error& error = Error::Handle();
+      // We got an error during compilation.
+      error = thread->sticky_error();
+      thread->clear_sticky_error();
+      ASSERT(error.IsLanguageError() &&
+             LanguageError::Cast(error).kind() != Report::kBailout);
+      return error.raw();
+    }
+
+    per_compile_timer.Stop();
+
+    if (trace_compiler && success) {
+      THR_Print("--> '%s' entry: %#" Px " size: %" Pd " time: %" Pd64 " us\n",
+                function.ToFullyQualifiedCString(),
+                Code::Handle(function.CurrentCode()).EntryPoint(),
+                Code::Handle(function.CurrentCode()).Size(),
+                per_compile_timer.TotalElapsedTime());
+    }
+
+    if (FLAG_disassemble && FlowGraphPrinter::ShouldPrint(function)) {
+      Disassembler::DisassembleCode(function, optimized);
+    } else if (FLAG_disassemble_optimized &&
+               optimized &&
+               FlowGraphPrinter::ShouldPrint(function)) {
+      // TODO(fschneider): Print unoptimized code along with the optimized code.
+      THR_Print("*** BEGIN CODE\n");
+      Disassembler::DisassembleCode(function, true);
+      THR_Print("*** END CODE\n");
+    }
+    return Error::null();
+  } else {
+    Thread* const thread = Thread::Current();
+    StackZone stack_zone(thread);
+    Error& error = Error::Handle();
+    // We got an error during compilation.
+    error = thread->sticky_error();
+    thread->clear_sticky_error();
+    // Precompilation may encounter compile-time errors.
+    // Do not attempt to optimize functions that can cause errors.
+    function.set_is_optimizable(false);
+    return error.raw();
+  }
+  UNREACHABLE();
+  return Error::null();
+}
+
+
+RawError* Precompiler::CompileFunction(Thread* thread,
+                                       const Function& function) {
+  VMTagScope tagScope(thread, VMTag::kCompileUnoptimizedTagId);
+  TIMELINE_FUNCTION_COMPILATION_DURATION(thread, "Function", function);
+
+  CompilationPipeline* pipeline =
+      CompilationPipeline::New(thread->zone(), function);
+
+  ASSERT(FLAG_precompiled_mode);
+  const bool optimized = function.IsOptimizable();  // False for natives.
+  return PrecompileFunctionHelper(pipeline, function, optimized);
+}
+
+#endif  // DART_PRECOMPILER
+
 }  // namespace dart
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 50f9551..43b7b96 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -7,6 +7,7 @@
 
 #include "vm/allocation.h"
 #include "vm/hash_map.h"
+#include "vm/hash_table.h"
 #include "vm/object.h"
 
 namespace dart {
@@ -18,6 +19,7 @@
 class Function;
 class GrowableObjectArray;
 class RawError;
+class SequenceNode;
 class String;
 
 class SymbolKeyValueTrait {
@@ -64,6 +66,61 @@
 
 typedef DirectChainedHashMap<StackmapKeyValueTrait> StackmapSet;
 
+
+class ArrayKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const Array* Key;
+  typedef const Array* Value;
+  typedef const Array* Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) {
+    return key->Length();
+  }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    if (pair->Length() != key->Length()) {
+      return false;
+    }
+    for (intptr_t i = 0; i < pair->Length(); i++) {
+      if (pair->At(i) != key->At(i)) {
+        return false;
+      }
+    }
+    return true;
+  }
+};
+
+typedef DirectChainedHashMap<ArrayKeyValueTrait> ArraySet;
+
+
+class InstructionsKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const Instructions* Key;
+  typedef const Instructions* Value;
+  typedef const Instructions* Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) {
+    return key->size();
+  }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    return pair->Equals(*key);
+  }
+};
+
+typedef DirectChainedHashMap<InstructionsKeyValueTrait> InstructionsSet;
+
+
 class FunctionKeyValueTrait {
  public:
   // Typedefs needed for the DirectChainedHashMap template.
@@ -76,7 +133,7 @@
   static Value ValueOf(Pair kv) { return kv; }
 
   static inline intptr_t Hashcode(Key key) {
-    return key->token_pos();
+    return key->token_pos().value();
   }
 
   static inline bool IsKeyEqual(Pair pair, Key key) {
@@ -87,6 +144,98 @@
 typedef DirectChainedHashMap<FunctionKeyValueTrait> FunctionSet;
 
 
+class FieldKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const Field* Key;
+  typedef const Field* Value;
+  typedef const Field* Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) {
+    return key->token_pos().value();
+  }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    return pair->raw() == key->raw();
+  }
+};
+
+typedef DirectChainedHashMap<FieldKeyValueTrait> FieldSet;
+
+
+class ClassKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const Class* Key;
+  typedef const Class* Value;
+  typedef const Class* Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) {
+    return key->token_pos().value();
+  }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    return pair->raw() == key->raw();
+  }
+};
+
+typedef DirectChainedHashMap<ClassKeyValueTrait> ClassSet;
+
+
+class AbstractTypeKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const AbstractType* Key;
+  typedef const AbstractType* Value;
+  typedef const AbstractType* Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) {
+    return key->Hash();
+  }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    return pair->raw() == key->raw();
+  }
+};
+
+typedef DirectChainedHashMap<AbstractTypeKeyValueTrait> AbstractTypeSet;
+
+
+class TypeArgumentsKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const TypeArguments* Key;
+  typedef const TypeArguments* Value;
+  typedef const TypeArguments* Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) {
+    return key->Hash();
+  }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    return pair->raw() == key->raw();
+  }
+};
+
+typedef DirectChainedHashMap<TypeArgumentsKeyValueTrait> TypeArgumentsSet;
+
+
 class Precompiler : public ValueObject {
  public:
   static RawError* CompileAll(
@@ -103,15 +252,27 @@
                                      const String& fname,
                                      Object* function);
 
+  static RawError* CompileFunction(Thread* thread, const Function& function);
+
+  static RawObject* EvaluateStaticInitializer(const Field& field);
+  static RawObject* ExecuteOnce(SequenceNode* fragment);
+
  private:
   Precompiler(Thread* thread, bool reset_fields);
 
+
+  static RawFunction* CompileStaticInitializer(const Field& field);
+
   void DoCompileAll(Dart_QualifiedFunctionName embedder_entry_points[]);
   void ClearAllCode();
   void AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]);
   void AddEntryPoints(Dart_QualifiedFunctionName entry_points[]);
   void Iterate();
 
+  void AddType(const AbstractType& type);
+  void AddTypesOf(const Class& cls);
+  void AddTypesOf(const Function& function);
+  void AddTypeArguments(const TypeArguments& args);
   void AddCalleesOf(const Function& function);
   void AddConstObject(const Instance& instance);
   void AddClosureCall(const ICData& call_site);
@@ -124,12 +285,22 @@
   void ProcessFunction(const Function& function);
   void CheckForNewDynamicFunctions();
 
-  void DropUncompiledFunctions();
-  void CollectDynamicFunctionNames();
+  void DropFunctions();
+  void DropFields();
+  void TraceTypesFromRetainedClasses();
+  void DropTypes();
+  void DropTypeArguments();
+  void DropClasses();
+  void DropLibraries();
+
   void BindStaticCalls();
   void DedupStackmaps();
+  void DedupStackmapLists();
+  void DedupInstructions();
   void ResetPrecompilerState();
 
+  void CollectDynamicFunctionNames();
+
   class FunctionVisitor : public ValueObject {
    public:
     virtual ~FunctionVisitor() {}
@@ -155,14 +326,51 @@
   intptr_t class_count_;
   intptr_t selector_count_;
   intptr_t dropped_function_count_;
+  intptr_t dropped_field_count_;
+  intptr_t dropped_class_count_;
+  intptr_t dropped_typearg_count_;
+  intptr_t dropped_type_count_;
+  intptr_t dropped_library_count_;
 
-  const GrowableObjectArray& libraries_;
+  GrowableObjectArray& libraries_;
   const GrowableObjectArray& pending_functions_;
   SymbolSet sent_selectors_;
   FunctionSet enqueued_functions_;
+  FieldSet fields_to_retain_;
+  ClassSet classes_to_retain_;
+  TypeArgumentsSet typeargs_to_retain_;
+  AbstractTypeSet types_to_retain_;
   Error& error_;
 };
 
+
+class FunctionsTraits {
+ public:
+  static bool IsMatch(const Object& a, const Object& b) {
+    Zone* zone = Thread::Current()->zone();
+    String& a_s = String::Handle(zone);
+    String& b_s = String::Handle(zone);
+    a_s = a.IsFunction() ? Function::Cast(a).name() : String::Cast(a).raw();
+    b_s = b.IsFunction() ? Function::Cast(b).name() : String::Cast(b).raw();
+    ASSERT(a_s.IsSymbol() && b_s.IsSymbol());
+    return a_s.raw() == b_s.raw();
+  }
+  static uword Hash(const Object& obj) {
+    if (obj.IsFunction()) {
+      return String::Handle(Function::Cast(obj).name()).Hash();
+    } else {
+      ASSERT(String::Cast(obj).IsSymbol());
+      return String::Cast(obj).Hash();
+    }
+  }
+  static RawObject* NewKey(const Function& function) {
+    return function.raw();
+  }
+};
+
+typedef UnorderedHashSet<FunctionsTraits> UniqueFunctionsSet;
+
+
 }  // namespace dart
 
 #endif  // VM_PRECOMPILER_H_
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 53f04b6..0d1ad84 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -26,12 +26,9 @@
 
 namespace dart {
 
-
 static const intptr_t kSampleSize = 8;
 
 DECLARE_FLAG(bool, trace_profiler);
-
-DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
 
 #if defined(TARGET_OS_ANDROID) || defined(TARGET_ARCH_ARM64) ||                \
@@ -52,6 +49,8 @@
             "Always collect native stack traces.");
 #endif
 
+#ifndef PRODUCT
+
 bool Profiler::initialized_ = false;
 SampleBuffer* Profiler::sample_buffer_ = NULL;
 
@@ -61,7 +60,7 @@
   SetSamplePeriod(FLAG_profile_period);
   SetSampleDepth(FLAG_max_profile_depth);
   Sample::InitOnce();
-  if (!FLAG_profile) {
+  if (!FLAG_profiler) {
     return;
   }
   ASSERT(!initialized_);
@@ -74,7 +73,7 @@
 
 
 void Profiler::Shutdown() {
-  if (!FLAG_profile) {
+  if (!FLAG_profiler) {
     return;
   }
   ASSERT(initialized_);
@@ -1385,4 +1384,6 @@
   ASSERT(code_lookup_table_ != NULL);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index c755890..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_;
 
@@ -340,17 +339,19 @@
     kClassAllocationSampleBit = 6,
     kContinuationSampleBit = 7,
   };
-  class HeadSampleBit : public BitField<bool, kHeadSampleBit, 1> {};
-  class LeafFrameIsDart : public BitField<bool, kLeafFrameIsDartBit, 1> {};
-  class IgnoreBit : public BitField<bool, kIgnoreBit, 1> {};
-  class ExitFrameBit : public BitField<bool, kExitFrameBit, 1> {};
+  class HeadSampleBit : public BitField<uword, bool, kHeadSampleBit, 1> {};
+  class LeafFrameIsDart :
+      public BitField<uword, bool, kLeafFrameIsDartBit, 1> {};
+  class IgnoreBit : public BitField<uword, bool, kIgnoreBit, 1> {};
+  class ExitFrameBit : public BitField<uword, bool, kExitFrameBit, 1> {};
   class MissingFrameInsertedBit
-      : public BitField<bool, kMissingFrameInsertedBit, 1> {};
-  class TruncatedTraceBit : public BitField<bool, kTruncatedTraceBit, 1> {};
+      : public BitField<uword, bool, kMissingFrameInsertedBit, 1> {};
+  class TruncatedTraceBit :
+      public BitField<uword, bool, kTruncatedTraceBit, 1> {};
   class ClassAllocationSampleBit
-      : public BitField<bool, kClassAllocationSampleBit, 1> {};
+      : public BitField<uword, bool, kClassAllocationSampleBit, 1> {};
   class ContinuationSampleBit
-      : public BitField<bool, kContinuationSampleBit, 1> {};
+      : public BitField<uword, bool, kContinuationSampleBit, 1> {};
 
   int64_t timestamp_;
   ThreadId tid_;
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 17a8a73..3de17c8 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -19,6 +19,8 @@
 
 DEFINE_FLAG(bool, trace_profiler, false, "Trace profiler.");
 
+#ifndef PRODUCT
+
 class DeoptimizedCodeSet : public ZoneAllocated {
  public:
   explicit DeoptimizedCodeSet(Isolate* isolate)
@@ -551,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.
@@ -2407,4 +2407,6 @@
   sample_buffer->VisitSamples(&clear_profile);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 63ac759..f9ae241 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -13,7 +13,8 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, background_compilation);
+#ifndef PRODUCT
+
 DECLARE_FLAG(bool, profile_vm);
 DECLARE_FLAG(int, max_profile_depth);
 
@@ -853,7 +854,7 @@
 }
 
 
-TEST_CASE(Profiler_ClassAllocation) {
+TEST_CASE(Profiler_ClosureAllocation) {
   DisableNativeProfileScope dnps;
   const char* kScript =
       "var msg1 = 'a';\n"
@@ -875,12 +876,12 @@
   root_library ^= Api::UnwrapHandle(lib);
   Isolate* isolate = thread->isolate();
 
-  const Class& class_class =
-      Class::Handle(Object::class_class());
-  EXPECT(!class_class.IsNull());
-  class_class.SetTraceAllocation(true);
+  const Class& closure_class =
+      Class::Handle(Isolate::Current()->object_store()->closure_class());
+  EXPECT(!closure_class.IsNull());
+  closure_class.SetTraceAllocation(true);
 
-  // Invoke "foo" which during compilation, triggers a closure class allocation.
+  // Invoke "foo" which during compilation, triggers a closure allocation.
   Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 0, NULL);
   EXPECT_VALID(result);
 
@@ -888,7 +889,7 @@
     StackZone zone(thread);
     HANDLESCOPE(thread);
     Profile profile(isolate);
-    AllocationFilter filter(isolate, class_class.id());
+    AllocationFilter filter(isolate, closure_class.id());
     filter.set_enable_vm_ticks(true);
     profile.Build(thread, &filter, Profile::kNoTags);
     // We should have one allocation sample.
@@ -897,19 +898,14 @@
 
     walker.Reset(Profile::kExclusiveCode);
     EXPECT(walker.Down());
-#if defined(TARGET_OS_WINDOWS)
-    // TODO(johnmccutchan): Hookup native symbol resolver on Windows.
-    EXPECT_SUBSTRING("[Native]", walker.CurrentName());
-#else
-    EXPECT_SUBSTRING("dart::Profiler::SampleAllocation", walker.CurrentName());
-#endif
+    EXPECT_SUBSTRING("foo", walker.CurrentName());
     EXPECT(!walker.Down());
   }
 
-  // Disable allocation tracing for Class.
-  class_class.SetTraceAllocation(false);
+  // Disable allocation tracing for Closure.
+  closure_class.SetTraceAllocation(false);
 
-  // Invoke "bar" which during compilation, triggers a closure class allocation.
+  // Invoke "bar" which during compilation, triggers a closure allocation.
   result = Dart_Invoke(lib, NewString("bar"), 0, NULL);
   EXPECT_VALID(result);
 
@@ -917,7 +913,7 @@
     StackZone zone(thread);
     HANDLESCOPE(thread);
     Profile profile(isolate);
-    AllocationFilter filter(isolate, class_class.id());
+    AllocationFilter filter(isolate, closure_class.id());
     filter.set_enable_vm_ticks(true);
     profile.Build(thread, &filter, Profile::kNoTags);
     // We should still only have one allocation sample.
@@ -1662,5 +1658,6 @@
   }
 }
 
-}  // namespace dart
+#endif  // !PRODUCT
 
+}  // namespace dart
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index ba53d37..d32b5ab 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -144,6 +144,13 @@
       instance_size = PcDescriptors::InstanceSize(length);
       break;
     }
+    case kCodeSourceMapCid: {
+      const RawCodeSourceMap* raw_code_source_map =
+          reinterpret_cast<const RawCodeSourceMap*>(this);
+      intptr_t length = raw_code_source_map->ptr()->length_;
+      instance_size = CodeSourceMap::InstanceSize(length);
+      break;
+    }
     case kStackmapCid: {
       const RawStackmap* map = reinterpret_cast<const RawStackmap*>(this);
       intptr_t length = map->ptr()->length_;
@@ -336,6 +343,13 @@
 }
 
 
+intptr_t RawFunctionType::VisitFunctionTypePointers(
+    RawFunctionType* raw_obj, ObjectPointerVisitor* visitor) {
+  visitor->VisitPointers(raw_obj->from(), raw_obj->to());
+  return FunctionType::InstanceSize();
+}
+
+
 intptr_t RawTypeRef::VisitTypeRefPointers(
     RawTypeRef* raw_obj, ObjectPointerVisitor* visitor) {
   visitor->VisitPointers(raw_obj->from(), raw_obj->to());
@@ -379,6 +393,13 @@
 }
 
 
+intptr_t RawClosure::VisitClosurePointers(
+    RawClosure* raw_obj, ObjectPointerVisitor* visitor) {
+  visitor->VisitPointers(raw_obj->from(), raw_obj->to());
+  return Closure::InstanceSize();
+}
+
+
 intptr_t RawClosureData::VisitClosureDataPointers(
     RawClosureData* raw_obj, ObjectPointerVisitor* visitor) {
   visitor->VisitPointers(raw_obj->from(), raw_obj->to());
@@ -575,6 +596,12 @@
 }
 
 
+intptr_t RawCodeSourceMap::VisitCodeSourceMapPointers(
+    RawCodeSourceMap* raw_obj, ObjectPointerVisitor* visitor) {
+  return CodeSourceMap::InstanceSize(raw_obj->ptr()->length_);
+}
+
+
 intptr_t RawStackmap::VisitStackmapPointers(RawStackmap* raw_obj,
                                             ObjectPointerVisitor* visitor) {
   return Stackmap::InstanceSize(raw_obj->ptr()->length_);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index ee5450d..c30823f 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -10,6 +10,7 @@
 #include "vm/globals.h"
 #include "vm/snapshot.h"
 #include "vm/token.h"
+#include "vm/token_position.h"
 #include "vm/verified_memory.h"
 
 namespace dart {
@@ -33,6 +34,7 @@
   V(Instructions)                                                              \
   V(ObjectPool)                                                                \
   V(PcDescriptors)                                                             \
+  V(CodeSourceMap)                                                             \
   V(Stackmap)                                                                  \
   V(LocalVarDescriptors)                                                       \
   V(ExceptionHandlers)                                                         \
@@ -50,10 +52,12 @@
     V(LibraryPrefix)                                                           \
     V(AbstractType)                                                            \
       V(Type)                                                                  \
+      V(FunctionType)                                                          \
       V(TypeRef)                                                               \
       V(TypeParameter)                                                         \
       V(BoundedType)                                                           \
       V(MixinAppType)                                                          \
+    V(Closure)                                                                 \
     V(Number)                                                                  \
       V(Integer)                                                               \
         V(Smi)                                                                 \
@@ -145,9 +149,10 @@
 #define DEFINE_OBJECT_KIND(clazz)                                              \
   kTypedData##clazz##ViewCid,
 CLASS_LIST_TYPED_DATA(DEFINE_OBJECT_KIND)
-  kByteDataViewCid,
 #undef DEFINE_OBJECT_KIND
 
+  kByteDataViewCid,
+
 #define DEFINE_OBJECT_KIND(clazz)                                              \
   kExternalTypedData##clazz##Cid,
 CLASS_LIST_TYPED_DATA(DEFINE_OBJECT_KIND)
@@ -280,7 +285,8 @@
 
    private:
     // The actual unscaled bit field used within the tag field.
-    class SizeBits : public BitField<intptr_t, kSizeTagPos, kSizeTagSize> {};
+    class SizeBits :
+        public BitField<uword, intptr_t, kSizeTagPos, kSizeTagSize> {};
 
     static intptr_t SizeToTagValue(intptr_t size) {
       ASSERT(Utils::IsAligned(size, kObjectAlignment));
@@ -292,7 +298,7 @@
   };
 
   class ClassIdTag :
-      public BitField<intptr_t, kClassIdTagPos, kClassIdTagSize> {};  // NOLINT
+      public BitField<uword, intptr_t, kClassIdTagPos, kClassIdTagSize> {};
 
   bool IsWellFormed() const {
     uword value = reinterpret_cast<uword>(this);
@@ -418,6 +424,9 @@
   bool IsScript() {
     return ((GetClassId() == kScriptCid));
   }
+  bool IsField() {
+    return ((GetClassId() == kFieldCid));
+  }
   bool IsFunction() {
     return ((GetClassId() == kFunctionCid));
   }
@@ -427,6 +436,18 @@
   bool IsCode() {
     return ((GetClassId() == kCodeCid));
   }
+  bool IsString() {
+    return IsStringClassId(GetClassId());
+  }
+  bool IsStackmap() {
+    return ((GetClassId() == kStackmapCid));
+  }
+  bool IsPcDescriptors() {
+    return ((GetClassId() == kPcDescriptorsCid));
+  }
+  bool IsOneByteString() {
+    return ((GetClassId() == kOneByteStringCid));
+  }
 
   intptr_t Size() const {
     uword tags = ptr()->tags_;
@@ -489,18 +510,18 @@
  private:
   uword tags_;  // Various object tags (bits).
 
-  class WatchedBit : public BitField<bool, kWatchedBit, 1> {};
+  class WatchedBit : public BitField<uword, bool, kWatchedBit, 1> {};
 
-  class MarkBit : public BitField<bool, kMarkBit, 1> {};
+  class MarkBit : public BitField<uword, bool, kMarkBit, 1> {};
 
-  class RememberedBit : public BitField<bool, kRememberedBit, 1> {};
+  class RememberedBit : public BitField<uword, bool, kRememberedBit, 1> {};
 
-  class CanonicalObjectTag : public BitField<bool, kCanonicalBit, 1> {};
+  class CanonicalObjectTag : public BitField<uword, bool, kCanonicalBit, 1> {};
 
-  class VMHeapObjectTag : public BitField<bool, kVMHeapObjectBit, 1> {};
+  class VMHeapObjectTag : public BitField<uword, bool, kVMHeapObjectBit, 1> {};
 
   class ReservedBits : public
-      BitField<intptr_t, kReservedTagPos, kReservedTagSize> {};  // NOLINT
+      BitField<uword, intptr_t, kReservedTagPos, kReservedTagSize> {};
 
   // TODO(koda): After handling tags_, return const*, like Object::raw_ptr().
   RawObject* ptr() const {
@@ -590,8 +611,8 @@
   friend class Array;
   friend class Bigint;
   friend class ByteBuffer;
-  friend class Code;
   friend class Closure;
+  friend class Code;
   friend class Double;
   friend class FreeListElement;
   friend class Function;
@@ -628,6 +649,7 @@
   friend class Instance;  // StorePointer
   friend class StackFrame;  // GetCodeObject assertion.
   friend class CodeLookupTableBuilder;  // profiler
+  friend class NativeEntry;  // GetClassId
 
   DISALLOW_ALLOCATION();
   DISALLOW_IMPLICIT_CONSTRUCTORS(RawObject);
@@ -647,31 +669,31 @@
 
   RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
   RawString* name_;
-  RawString* user_name_;
+  NOT_IN_PRODUCT(RawString* user_name_);
   RawArray* functions_;
   RawArray* functions_hash_table_;
   RawArray* fields_;
   RawArray* offset_in_words_to_field_;
   RawArray* interfaces_;  // Array of AbstractType.
-  RawGrowableObjectArray* direct_subclasses_;  // Array of Class.
   RawScript* script_;
   RawLibrary* library_;
   RawTypeArguments* type_parameters_;  // Array of TypeParameter.
   RawAbstractType* super_type_;
   RawType* mixin_;  // Generic mixin type, e.g. M<T>, not M<int>.
-  RawFunction* signature_function_;  // Associated function for signature class.
+  RawFunction* signature_function_;  // Associated function for typedef class.
   RawArray* constants_;  // Canonicalized values of this class.
   RawObject* canonical_types_;  // An array of canonicalized types of this class
                                 // or the canonical type.
   RawArray* invocation_dispatcher_cache_;  // Cache for dispatcher functions.
-  RawArray* cha_codes_;  // CHA optimized codes.
   RawCode* allocation_stub_;  // Stub code for allocation of instances.
+  RawGrowableObjectArray* direct_subclasses_;  // Array of Class.
+  RawArray* cha_codes_;  // CHA optimized codes.
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->allocation_stub_);
+    return reinterpret_cast<RawObject**>(&ptr()->cha_codes_);
   }
 
   cpp_vtable handle_vtable_;
-  int32_t token_pos_;
+  TokenPosition token_pos_;
   int32_t instance_size_in_words_;  // Size if fixed len or 0 if variable len.
   int32_t type_arguments_field_offset_in_words_;  // Offset of type args fld.
   int32_t next_field_offset_in_words_;  // Offset of the next instance field.
@@ -700,7 +722,7 @@
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->ident_);
   }
-  int32_t token_pos_;
+  TokenPosition token_pos_;
 };
 
 
@@ -809,8 +831,8 @@
   }
   uword entry_point_;
 
-  int32_t token_pos_;
-  int32_t end_token_pos_;
+  TokenPosition token_pos_;
+  TokenPosition end_token_pos_;
   int32_t usage_counter_;  // Incremented while function is running.
   int16_t num_fixed_parameters_;
   int16_t num_optional_parameters_;  // > 0: positional; < 0: named.
@@ -830,7 +852,7 @@
   }
   RawContextScope* context_scope_;
   RawFunction* parent_function_;  // Enclosing function of this local function.
-  RawClass* signature_class_;
+  RawFunctionType* signature_type_;
   RawInstance* closure_;  // Closure object for static implicit closures.
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->closure_);
@@ -862,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.
@@ -886,7 +908,7 @@
     return reinterpret_cast<RawObject**>(&ptr()->guarded_list_length_);
   }
 
-  int32_t token_pos_;
+  TokenPosition token_pos_;
   classid_t guarded_cid_;
   classid_t is_nullable_;  // kNullCid if field can contain null value and
                            // any other value otherwise.
@@ -1033,7 +1055,8 @@
     kInlinedIntervalsIndex = 0,
     kInlinedIdToFunctionIndex = 1,
     kInlinedCallerIdMapIndex = 2,
-    kInlinedMetadataSize = 3,
+    kInlinedIdToTokenPosIndex = 3,
+    kInlinedMetadataSize = 4,
   };
 
   RAW_HEAP_OBJECT_IMPLEMENTATION(Code);
@@ -1052,6 +1075,7 @@
   RawObject* owner_;  // Function, Null, or a Class.
   RawExceptionHandlers* exception_handlers_;
   RawPcDescriptors* pc_descriptors_;
+  RawCodeSourceMap* code_source_map_;
   RawArray* stackmaps_;
   RawObject** to_snapshot() {
     return reinterpret_cast<RawObject**>(&ptr()->stackmaps_);
@@ -1199,6 +1223,23 @@
 };
 
 
+// CodeSourceMap stores a mapping between code PC ranges and source token
+// positions.
+class RawCodeSourceMap : public RawObject {
+ private:
+  RAW_HEAP_OBJECT_IMPLEMENTATION(CodeSourceMap);
+
+  int32_t length_;  // Number of entries.
+
+  // Variable length data follows here.
+  uint8_t* data() { OPEN_ARRAY_START(uint8_t, intptr_t); }
+  const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, intptr_t); }
+
+  friend class Object;
+  friend class SnapshotReader;
+};
+
+
 // Stackmap is an immutable representation of the layout of the stack at a
 // PC. The stack map representation consists of a bit map which marks each
 // live object index starting from the base of the frame.
@@ -1248,14 +1289,14 @@
     kMaxIndex = (1 << (kIndexSize - 1)) - 1,
   };
 
-  class IndexBits : public BitField<int32_t, kIndexPos, kIndexSize> {};
-  class KindBits : public BitField<int8_t, kKindPos, kKindSize>{};
+  class IndexBits : public BitField<int32_t, int32_t, kIndexPos, kIndexSize> {};
+  class KindBits : public BitField<int32_t, int8_t, kKindPos, kKindSize>{};
 
   struct VarInfo {
     int32_t index_kind;  // Bitfield for slot index on stack or in context,
                          // and Entry kind of type VarInfoKind.
-    int32_t begin_pos;   // Token position of scope start.
-    int32_t end_pos;     // Token position of scope end.
+    TokenPosition begin_pos;   // Token position of scope start.
+    TokenPosition end_pos;     // Token position of scope end.
     int16_t scope_id;    // Scope to which the variable belongs.
 
     VarInfoKind kind() const {
@@ -1400,14 +1441,17 @@
   RAW_HEAP_OBJECT_IMPLEMENTATION(ICData);
 
   RawObject** from() {
-    return reinterpret_cast<RawObject**>(&ptr()->owner_);
+    return reinterpret_cast<RawObject**>(&ptr()->ic_data_);
   }
-  RawObject* owner_;  // Parent/calling function or original IC of cloned IC.
+  RawArray* ic_data_;  // Contains class-ids, target and count.
   RawString* target_name_;  // Name of target function.
   RawArray* args_descriptor_;  // Arguments descriptor.
-  RawArray* ic_data_;  // Contains class-ids, target and count.
+  RawObject** to_precompiled_snapshot() {
+    return reinterpret_cast<RawObject**>(&ptr()->args_descriptor_);
+  }
+  RawObject* owner_;  // Parent/calling function or original IC of cloned IC.
   RawObject** to() {
-    return reinterpret_cast<RawObject**>(&ptr()->ic_data_);
+    return reinterpret_cast<RawObject**>(&ptr()->owner_);
   }
   int32_t deopt_id_;     // Deoptimization id corresponding to this IC.
   uint32_t state_bits_;  // Number of arguments tested in IC, deopt reasons,
@@ -1470,7 +1514,8 @@
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->formatted_message_);
   }
-  int32_t token_pos_;  // Source position in script_.
+  TokenPosition token_pos_;  // Source position in script_.
+  bool report_after_token_;  // Report message at or after the token.
   int8_t kind_;  // Of type LanguageError::Kind.
 };
 
@@ -1514,8 +1559,11 @@
 
   RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
   RawString* name_;               // Library prefix name.
-  RawArray* imports_;             // Libraries imported with this prefix.
   RawLibrary* importer_;          // Library which declares this prefix.
+  RawObject** to_precompiled_snapshot() {
+    return reinterpret_cast<RawObject**>(&ptr()->importer_);
+  }
+  RawArray* imports_;             // Libraries imported with this prefix.
   RawArray* dependent_code_;      // Code that refers to deferred, unloaded
                                   // library prefix.
   RawObject** to() {
@@ -1557,7 +1605,26 @@
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->error_);
   }
-  int32_t token_pos_;
+  TokenPosition token_pos_;
+  int8_t type_state_;
+};
+
+
+class RawFunctionType : public RawAbstractType {
+ private:
+  RAW_HEAP_OBJECT_IMPLEMENTATION(FunctionType);
+
+  RawObject** from() {
+    return reinterpret_cast<RawObject**>(&ptr()->scope_class_);
+  }
+  RawClass* scope_class_;
+  RawTypeArguments* arguments_;
+  RawFunction* signature_;
+  RawLanguageError* error_;  // Error object if type is malformed or malbounded.
+  RawObject** to() {
+    return reinterpret_cast<RawObject**>(&ptr()->error_);
+  }
+  TokenPosition token_pos_;
   int8_t type_state_;
 };
 
@@ -1587,7 +1654,7 @@
   RawString* name_;
   RawAbstractType* bound_;  // ObjectType if no explicit bound specified.
   RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->bound_); }
-  int32_t token_pos_;
+  TokenPosition token_pos_;
   int16_t index_;
   int8_t type_state_;
 };
@@ -1624,6 +1691,24 @@
 };
 
 
+class RawClosure : public RawInstance {
+ private:
+  RAW_HEAP_OBJECT_IMPLEMENTATION(Closure);
+
+  RawObject** from() {
+    return reinterpret_cast<RawObject**>(&ptr()->type_arguments_);
+  }
+
+  RawTypeArguments* type_arguments_;
+  RawFunction* function_;
+  RawContext* context_;
+
+  RawObject** to() {
+    return reinterpret_cast<RawObject**>(&ptr()->context_);
+  }
+};
+
+
 class RawNumber : public RawInstance {
   RAW_OBJECT_IMPLEMENTATION(Number);
 };
@@ -2245,6 +2330,7 @@
          (index == kInstructionsCid) ||
          (index == kObjectPoolCid) ||
          (index == kPcDescriptorsCid) ||
+         (index == kCodeSourceMapCid) ||
          (index == kStackmapCid) ||
          (index == kLocalVarDescriptorsCid) ||
          (index == kExceptionHandlersCid) ||
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 87305ba..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())
 
@@ -77,7 +74,7 @@
     cls.set_num_type_arguments(reader->Read<int16_t>());
     cls.set_num_own_type_arguments(reader->Read<int16_t>());
     cls.set_num_native_fields(reader->Read<uint16_t>());
-    cls.set_token_pos(reader->Read<int32_t>());
+    cls.set_token_pos(TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
     cls.set_state_bits(reader->Read<uint16_t>());
 
     // Set all the object fields.
@@ -115,6 +112,7 @@
     // Write out all the non object pointer fields.
     // NOTE: cpp_vtable_ is not written.
     classid_t class_id = ptr()->id_;
+    ASSERT(class_id != kIllegalCid);
     writer->Write<classid_t>(class_id);
     if (!RawObject::IsInternalVMdefinedClassId(class_id)) {
       // We don't write the instance size of VM defined classes as they
@@ -127,7 +125,7 @@
     writer->Write<uint16_t>(ptr()->num_type_arguments_);
     writer->Write<uint16_t>(ptr()->num_own_type_arguments_);
     writer->Write<uint16_t>(ptr()->num_native_fields_);
-    writer->Write<int32_t>(ptr()->token_pos_);
+    writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
     writer->Write<uint16_t>(ptr()->state_bits_);
 
     // Write out all the object pointer fields.
@@ -160,7 +158,8 @@
   reader->AddBackRef(object_id, &unresolved_class, kIsDeserialized);
 
   // Set all non object fields.
-  unresolved_class.set_token_pos(reader->Read<int32_t>());
+  unresolved_class.set_token_pos(
+      TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
 
   // Set all the object fields.
   READ_OBJECT_FIELDS(unresolved_class,
@@ -186,7 +185,7 @@
   writer->WriteTags(writer->GetObjectTags(this));
 
   // Write out all the non object pointer fields.
-  writer->Write<int32_t>(ptr()->token_pos_);
+  writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
 
   // Write out all the object pointer fields.
   SnapshotWriterVisitor visitor(writer, kAsReference);
@@ -230,14 +229,14 @@
   reader->AddBackRef(object_id, &type, kIsDeserialized, defer_canonicalization);
 
   // Set all non object fields.
-  type.set_token_pos(reader->Read<int32_t>());
+  type.set_token_pos(TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
   type.set_type_state(reader->Read<int8_t>());
 
   // Set all the object fields.
   READ_OBJECT_FIELDS(type, type.raw()->from(), type.raw()->to(), kAsReference);
 
   // Set the canonical bit.
-  if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
+  if (!defer_canonicalization && is_canonical) {
     type.SetCanonical();
   }
 
@@ -272,18 +271,93 @@
   writer->Write<bool>(typeclass_is_in_fullsnapshot);
 
   // Write out all the non object pointer fields.
-  writer->Write<int32_t>(ptr()->token_pos_);
+  writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
   writer->Write<int8_t>(ptr()->type_state_);
 
-  // Write out all the object pointer fields. Since we will be canonicalizing
-  // the type object when reading it back we should write out all the fields
-  // inline and not as references.
+  // Write out all the object pointer fields.
   ASSERT(ptr()->type_class_ != Object::null());
   SnapshotWriterVisitor visitor(writer, kAsReference);
   visitor.VisitPointers(from(), to());
 }
 
 
+RawFunctionType* FunctionType::ReadFrom(SnapshotReader* reader,
+                                        intptr_t object_id,
+                                        intptr_t tags,
+                                        Snapshot::Kind kind,
+                                        bool as_reference) {
+  ASSERT(reader != NULL);
+
+  // Determine if the scope class of this function type is in the full snapshot.
+  bool scopeclass_is_in_fullsnapshot = reader->Read<bool>();
+
+  // Allocate function type object.
+  FunctionType& function_type =
+      FunctionType::ZoneHandle(reader->zone(), NEW_OBJECT(FunctionType));
+  bool is_canonical = RawObject::IsCanonical(tags);
+  bool defer_canonicalization = is_canonical &&
+      (kind != Snapshot::kFull && scopeclass_is_in_fullsnapshot);
+  reader->AddBackRef(object_id,
+                     &function_type,
+                     kIsDeserialized,
+                     defer_canonicalization);
+
+  // Set all non object fields.
+  function_type.set_token_pos(
+      TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
+  function_type.set_type_state(reader->Read<int8_t>());
+
+  // Set all the object fields.
+  READ_OBJECT_FIELDS(function_type,
+                     function_type.raw()->from(), function_type.raw()->to(),
+                     kAsReference);
+
+  // Set the canonical bit.
+  if (!defer_canonicalization && is_canonical) {
+    function_type.SetCanonical();
+  }
+
+  return function_type.raw();
+}
+
+
+void RawFunctionType::WriteTo(SnapshotWriter* writer,
+                              intptr_t object_id,
+                              Snapshot::Kind kind,
+                              bool as_reference) {
+  ASSERT(writer != NULL);
+
+  // Only resolved and finalized function types should be written to a snapshot.
+  ASSERT((ptr()->type_state_ == RawFunctionType::kFinalizedInstantiated) ||
+         (ptr()->type_state_ == RawFunctionType::kFinalizedUninstantiated));
+  ASSERT(ptr()->scope_class_ != Object::null());
+
+  // Write out the serialization header value for this object.
+  writer->WriteInlinedObjectHeader(object_id);
+
+  // Write out the class and tags information.
+  writer->WriteIndexedObject(kFunctionTypeCid);
+  writer->WriteTags(writer->GetObjectTags(this));
+
+  // Write out scopeclass_is_in_fullsnapshot first as this will
+  // help the reader decide on how to canonicalize the type object.
+  intptr_t tags = writer->GetObjectTags(ptr()->scope_class_);
+  bool scopeclass_is_in_fullsnapshot =
+      (ClassIdTag::decode(tags) == kClassCid) &&
+      Class::IsInFullSnapshot(reinterpret_cast<RawClass*>(ptr()->scope_class_));
+  writer->Write<bool>(scopeclass_is_in_fullsnapshot);
+
+  // Write out all the non object pointer fields.
+  writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
+  writer->Write<int8_t>(ptr()->type_state_);
+
+  // Write out all the object pointer fields.
+  ASSERT(ptr()->scope_class_ != Object::null());
+  SnapshotWriterVisitor visitor(writer, kAsReference);
+  visitor.VisitPointers(from(), to());
+}
+
+
 RawTypeRef* TypeRef::ReadFrom(SnapshotReader* reader,
                               intptr_t object_id,
                               intptr_t tags,
@@ -337,7 +411,8 @@
   reader->AddBackRef(object_id, &type_parameter, kIsDeserialized);
 
   // Set all non object fields.
-  type_parameter.set_token_pos(reader->Read<int32_t>());
+  type_parameter.set_token_pos(
+      TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
   type_parameter.set_index(reader->Read<int16_t>());
   type_parameter.set_type_state(reader->Read<int8_t>());
 
@@ -367,7 +442,7 @@
   writer->WriteTags(writer->GetObjectTags(this));
 
   // Write out all the non object pointer fields.
-  writer->Write<int32_t>(ptr()->token_pos_);
+  writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
   writer->Write<int16_t>(ptr()->index_);
   writer->Write<int8_t>(ptr()->type_state_);
 
@@ -472,7 +547,7 @@
   }
 
   // Set the canonical bit.
-  if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
+  if (!defer_canonicalization && is_canonical) {
     type_arguments.SetCanonical();
   }
 
@@ -548,6 +623,61 @@
 }
 
 
+RawClosure* Closure::ReadFrom(SnapshotReader* reader,
+                              intptr_t object_id,
+                              intptr_t tags,
+                              Snapshot::Kind kind,
+                              bool as_reference) {
+  ASSERT(reader != NULL);
+  ASSERT(kind == Snapshot::kFull);
+
+  // Allocate closure object.
+  Closure& closure = Closure::ZoneHandle(
+      reader->zone(), NEW_OBJECT(Closure));
+  reader->AddBackRef(object_id, &closure, kIsDeserialized);
+
+  // Set all the object fields.
+  READ_OBJECT_FIELDS(closure,
+                     closure.raw()->from(), closure.raw()->to(),
+                     kAsReference);
+
+  // Set the canonical bit.
+  if (RawObject::IsCanonical(tags)) {
+    closure.SetCanonical();
+  }
+  return closure.raw();
+}
+
+
+void RawClosure::WriteTo(SnapshotWriter* writer,
+                         intptr_t object_id,
+                         Snapshot::Kind kind,
+                         bool as_reference) {
+  ASSERT(writer != NULL);
+  if ((kind == Snapshot::kMessage) || (kind == Snapshot::kScript)) {
+    // Check if closure is serializable, throw an exception otherwise.
+    RawFunction* func = writer->IsSerializableClosure(this);
+    if (func != Function::null()) {
+      writer->WriteStaticImplicitClosure(object_id,
+                                         func,
+                                         writer->GetObjectTags(this));
+      return;
+    }
+  }
+
+  // Write out the serialization header value for this object.
+  writer->WriteInlinedObjectHeader(object_id);
+
+  // Write out the class and tags information.
+  writer->WriteIndexedObject(kClosureCid);
+  writer->WriteTags(writer->GetObjectTags(this));
+
+  // Write out all the object pointer fields.
+  SnapshotWriterVisitor visitor(writer, kAsReference);
+  visitor.VisitPointers(from(), to());
+}
+
+
 RawClosureData* ClosureData::ReadFrom(SnapshotReader* reader,
                                       intptr_t object_id,
                                       intptr_t tags,
@@ -599,8 +729,8 @@
   // Parent function.
   writer->WriteObjectImpl(ptr()->parent_function_, kAsInlinedObject);
 
-  // Signature class.
-  writer->WriteObjectImpl(ptr()->signature_class_, kAsInlinedObject);
+  // Signature type.
+  writer->WriteObjectImpl(ptr()->signature_type_, kAsInlinedObject);
 
   // Static closure/Closure allocation stub.
   // We don't write the closure or allocation stub in the snapshot.
@@ -665,12 +795,15 @@
         reader->zone(), NEW_OBJECT(Function));
     reader->AddBackRef(object_id, &func, kIsDeserialized);
 
-    // Set all the non object fields.
-    func.set_token_pos(reader->Read<int32_t>());
-    func.set_end_token_pos(reader->Read<int32_t>());
+    // Set all the non object fields. Read the token positions now but
+    // don't set them until after setting the kind.
+    const int32_t token_pos = reader->Read<int32_t>();
+    const int32_t end_token_pos = reader->Read<uint32_t>();
     func.set_num_fixed_parameters(reader->Read<int16_t>());
     func.set_num_optional_parameters(reader->Read<int16_t>());
     func.set_kind_tag(reader->Read<uint32_t>());
+    func.set_token_pos(TokenPosition::SnapshotDecode(token_pos));
+    func.set_end_token_pos(TokenPosition::SnapshotDecode(end_token_pos));
     if (reader->snapshot_code()) {
       func.set_usage_counter(0);
       func.set_deoptimization_counter(0);
@@ -720,7 +853,7 @@
   ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
   bool is_in_fullsnapshot = false;
   bool owner_is_class = false;
-  if (kind == Snapshot::kScript) {
+  if ((kind == Snapshot::kScript) && !Function::IsSignatureFunction(this)) {
     intptr_t tags = writer->GetObjectTags(ptr()->owner_);
     intptr_t cid = ClassIdTag::decode(tags);
     owner_is_class = (cid == kClassCid);
@@ -746,8 +879,8 @@
     bool is_optimized = Code::IsOptimized(ptr()->code_);
 
     // Write out all the non object fields.
-    writer->Write<int32_t>(ptr()->token_pos_);
-    writer->Write<int32_t>(ptr()->end_token_pos_);
+    writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
+    writer->Write<int32_t>(ptr()->end_token_pos_.SnapshotEncode());
     writer->Write<int16_t>(ptr()->num_fixed_parameters_);
     writer->Write<int16_t>(ptr()->num_optional_parameters_);
     writer->Write<uint32_t>(ptr()->kind_tag_);
@@ -798,12 +931,13 @@
 
   // Set all non object fields.
   if (reader->snapshot_code()) {
-    field.set_token_pos(0);
+    field.set_token_pos(TokenPosition::kNoSource);
     ASSERT(!FLAG_use_field_guards);
     field.set_guarded_cid(kDynamicCid);
     field.set_is_nullable(true);
   } else {
-    field.set_token_pos(reader->Read<int32_t>());
+    field.set_token_pos(
+        TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
     field.set_guarded_cid(reader->Read<int32_t>());
     field.set_is_nullable(reader->Read<int32_t>());
   }
@@ -845,7 +979,7 @@
 
   // Write out all the non object fields.
   if (!writer->snapshot_code()) {
-    writer->Write<int32_t>(ptr()->token_pos_);
+    writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
     writer->Write<int32_t>(ptr()->guarded_cid_);
     writer->Write<int32_t>(ptr()->is_nullable_);
   }
@@ -1107,26 +1241,27 @@
     // The native resolver and symbolizer are not serialized.
     library.set_native_entry_resolver(NULL);
     library.set_native_entry_symbol_resolver(NULL);
-    // The cache of loaded scripts is not serialized.
-    library.StorePointer(&library.raw_ptr()->loaded_scripts_, Array::null());
 
     // Set all the object fields.
     // TODO(5411462): Need to assert No GC can happen here, even though
     // allocations may happen.
-    RawObject** toobj = (kind == Snapshot::kFull) ?
-        library.raw()->to() : library.raw()->to_snapshot();
-    intptr_t num_flds = (toobj - library.raw()->from());
+    intptr_t num_flds = (library.raw()->to_snapshot() - library.raw()->from());
     for (intptr_t i = 0; i <= num_flds; i++) {
       (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference);
       library.StorePointer((library.raw()->from() + i),
                            reader->PassiveObjectHandle()->raw());
     }
+    // Initialize cache of resolved names.
+    const intptr_t kInitialNameCacheSize = 64;
     if (kind != Snapshot::kFull) {
       // The cache of resolved names in library scope is not serialized.
-      const intptr_t kInitialNameCacheSize = 64;
       library.InitResolvedNamesCache(kInitialNameCacheSize);
       library.Register();
+    } else {
+      library.InitResolvedNamesCache(kInitialNameCacheSize, reader);
     }
+    // Initialize cache of loaded scripts.
+    library.StorePointer(&library.raw_ptr()->loaded_scripts_, Array::null());
   }
   return library.raw();
 }
@@ -1157,6 +1292,7 @@
   } else {
     ASSERT((kind == Snapshot::kFull) || !ptr()->is_in_fullsnapshot_);
     // Write out all non object fields.
+    ASSERT(ptr()->index_ != static_cast<classid_t>(-1));
     writer->WriteClassIDValue(ptr()->index_);
     writer->Write<uint16_t>(ptr()->num_imports_);
     writer->Write<int8_t>(ptr()->load_state_);
@@ -1165,14 +1301,13 @@
     writer->Write<bool>(ptr()->debuggable_);
     // We do not serialize the native resolver or symbolizer. These need to be
     // explicitly set after deserialization.
-    // We do not write the loaded_scripts_ cache to the snapshot. It gets
-    // set to NULL when reading the library from the snapshot, and will
-    // be rebuilt lazily.
 
+    // We do not write the loaded_scripts_ and resolved_names_ caches to the
+    // snapshot. They get initialized when reading the library from the
+    // snapshot and will be rebuilt lazily.
     // Write out all the object pointer fields.
-    RawObject** toobj = (kind == Snapshot::kFull) ? to() : to_snapshot();
     SnapshotWriterVisitor visitor(writer, kAsReference);
-    visitor.VisitPointers(from(), toobj);
+    visitor.VisitPointers(from(), to_snapshot());
   }
 }
 
@@ -1198,9 +1333,18 @@
   prefix.StoreNonPointer(&prefix.raw_ptr()->is_loaded_, reader->Read<bool>());
 
   // Set all the object fields.
+  RawObject** toobj = reader->snapshot_code()
+      ? prefix.raw()->to_precompiled_snapshot()
+      : prefix.raw()->to();
   READ_OBJECT_FIELDS(prefix,
-                     prefix.raw()->from(), prefix.raw()->to(),
+                     prefix.raw()->from(), toobj,
                      kAsReference);
+  if (reader->snapshot_code()) {
+    prefix.StorePointer(&prefix.raw_ptr()->imports_,
+                        Array::null());
+    prefix.StorePointer(&prefix.raw_ptr()->dependent_code_,
+                        Array::null());
+  }
 
   return prefix.raw();
 }
@@ -1227,7 +1371,9 @@
 
   // Write out all the object pointer fields.
   SnapshotWriterVisitor visitor(writer, kAsReference);
-  visitor.VisitPointers(from(), to());
+  RawObject** toobj = writer->snapshot_code() ? to_precompiled_snapshot()
+                                              : to();
+  visitor.VisitPointers(from(), toobj);
 }
 
 
@@ -1345,7 +1491,11 @@
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
+#ifdef DEBUG
   intptr_t full_tags = static_cast<uword>(reader->Read<intptr_t>());
+#else
+  intptr_t full_tags = 0;  // unused in release mode
+#endif
   intptr_t offset = reader->Read<int32_t>();
   Instructions& result =
       Instructions::ZoneHandle(reader->zone(),
@@ -1367,6 +1517,7 @@
   writer->WriteVMIsolateObject(kInstructionsCid);
   writer->WriteTags(writer->GetObjectTags(this));
 
+#ifdef DEBUG
   // Instructions will be written pre-marked and in the VM heap. Write out
   // the tags we expect to find when reading the snapshot for a sanity check
   // that our offsets/alignment didn't get out of sync.
@@ -1374,6 +1525,7 @@
   written_tags = RawObject::VMHeapObjectTag::update(true, written_tags);
   written_tags = RawObject::MarkBit::update(true, written_tags);
   writer->Write<intptr_t>(written_tags);
+#endif
 
   writer->Write<int32_t>(writer->GetInstructionsId(this));
 }
@@ -1511,19 +1663,11 @@
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
-  const int32_t length = reader->Read<int32_t>();
-  PcDescriptors& result =
-      PcDescriptors::ZoneHandle(reader->zone(),
-                                NEW_OBJECT_WITH_LEN(PcDescriptors, length));
+  intptr_t offset = reader->Read<int32_t>();
+  PcDescriptors& result = PcDescriptors::ZoneHandle(reader->zone());
+  result ^= reader->GetObjectAt(offset);
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  if (result.Length() > 0) {
-    NoSafepointScope no_safepoint;
-    intptr_t len = result.Length();
-    uint8_t* data = result.UnsafeMutableNonPointer(result.raw_ptr()->data());
-    reader->ReadBytes(data, len);
-  }
-
   return result.raw();
 }
 
@@ -1539,6 +1683,47 @@
   writer->WriteInlinedObjectHeader(object_id);
   writer->WriteIndexedObject(kPcDescriptorsCid);
   writer->WriteTags(writer->GetObjectTags(this));
+
+  writer->Write<int32_t>(writer->GetObjectId(this));
+}
+
+
+RawCodeSourceMap* CodeSourceMap::ReadFrom(SnapshotReader* reader,
+                                          intptr_t object_id,
+                                          intptr_t tags,
+                                          Snapshot::Kind kind,
+                                          bool as_reference) {
+  ASSERT(reader->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
+
+  const int32_t length = reader->Read<int32_t>();
+  CodeSourceMap& result =
+      CodeSourceMap::ZoneHandle(reader->zone(),
+                                NEW_OBJECT_WITH_LEN(CodeSourceMap, length));
+  reader->AddBackRef(object_id, &result, kIsDeserialized);
+
+  if (result.Length() > 0) {
+    NoSafepointScope no_safepoint;
+    intptr_t len = result.Length();
+    uint8_t* data = result.UnsafeMutableNonPointer(result.raw_ptr()->data());
+    reader->ReadBytes(data, len);
+  }
+
+  return result.raw();
+}
+
+
+void RawCodeSourceMap::WriteTo(SnapshotWriter* writer,
+                               intptr_t object_id,
+                               Snapshot::Kind kind,
+                               bool as_reference) {
+  ASSERT(writer->snapshot_code());
+  ASSERT(kind == Snapshot::kFull);
+
+  // Write out the serialization header value for this object.
+  writer->WriteInlinedObjectHeader(object_id);
+  writer->WriteIndexedObject(kCodeSourceMapCid);
+  writer->WriteTags(writer->GetObjectTags(this));
   writer->Write<int32_t>(ptr()->length_);
   if (ptr()->length_ > 0) {
     intptr_t len = ptr()->length_;
@@ -1556,22 +1741,11 @@
   ASSERT(reader->snapshot_code());
   ASSERT(kind == Snapshot::kFull);
 
-  const int32_t length = reader->Read<int32_t>();
-  Stackmap& result =
-      Stackmap::ZoneHandle(reader->zone(),
-                           reader->NewStackmap(length));
+  intptr_t offset = reader->Read<int32_t>();
+  Stackmap& result = Stackmap::ZoneHandle(reader->zone());
+  result ^= reader->GetObjectAt(offset);
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  result.SetRegisterBitCount(reader->Read<int32_t>());
-  result.SetPcOffset(reader->Read<uint32_t>());
-
-  if (length > 0) {
-    NoSafepointScope no_safepoint;
-    intptr_t len = (result.Length() + 7) / 8;
-    uint8_t* data = result.UnsafeMutableNonPointer(result.raw_ptr()->data());
-    reader->ReadBytes(data, len);
-  }
-
   return result.raw();
 }
 
@@ -1588,14 +1762,7 @@
   writer->WriteIndexedObject(kStackmapCid);
   writer->WriteTags(writer->GetObjectTags(this));
 
-  writer->Write<int32_t>(ptr()->length_);
-  writer->Write<int32_t>(ptr()->register_bit_count_);
-  writer->Write<uint32_t>(ptr()->pc_offset_);
-  if (ptr()->length_ > 0) {
-    intptr_t len = (ptr()->length_ + 7) / 8;
-    uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
-    writer->WriteBytes(data, len);
-  }
+  writer->Write<int32_t>(writer->GetObjectId(this));
 }
 
 
@@ -1787,7 +1954,7 @@
     *reader->TypeHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
 
     // Create a descriptor for 'this' variable.
-    context_scope.SetTokenIndexAt(0, 0);
+    context_scope.SetTokenIndexAt(0, TokenPosition::kMinSource);
     context_scope.SetNameAt(0, Symbols::This());
     context_scope.SetIsFinalAt(0, true);
     context_scope.SetIsConstAt(0, false);
@@ -1844,9 +2011,15 @@
   result.set_state_bits(reader->Read<uint32_t>());
 
   // Set all the object fields.
+  RawObject** toobj = reader->snapshot_code()
+      ? result.raw()->to_precompiled_snapshot()
+      : result.raw()->to();
   READ_OBJECT_FIELDS(result,
-                     result.raw()->from(), result.raw()->to(),
+                     result.raw()->from(), toobj,
                      kAsReference);
+  if (reader->snapshot_code()) {
+    result.set_owner(Function::Handle(reader->zone()));
+  }
 
   return result.raw();
 }
@@ -1870,8 +2043,12 @@
   writer->Write<uint32_t>(ptr()->state_bits_);
 
   // Write out all the object pointer fields.
+  // In precompiled snapshots, omit the owner field. The owner field may
+  // refer to a function which was always inlined and no longer needed.
   SnapshotWriterVisitor visitor(writer, kAsReference);
-  visitor.VisitPointers(from(), to());
+  RawObject** toobj = writer->snapshot_code() ? to_precompiled_snapshot()
+                                              : to();
+  visitor.VisitPointers(from(), toobj);
 }
 
 
@@ -2036,7 +2213,9 @@
   reader->AddBackRef(object_id, &language_error, kIsDeserialized);
 
   // Set all non object fields.
-  language_error.set_token_pos(reader->Read<int32_t>());
+  language_error.set_token_pos(
+      TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
+  language_error.set_report_after_token(reader->Read<bool>());
   language_error.set_kind(reader->Read<uint8_t>());
 
   // Set all the object fields.
@@ -2062,7 +2241,8 @@
   writer->WriteTags(writer->GetObjectTags(this));
 
   // Write out all the non object fields.
-  writer->Write<int32_t>(ptr()->token_pos_);
+  writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
+  writer->Write<bool>(ptr()->report_after_token_);
   writer->Write<uint8_t>(ptr()->kind_);
 
   // Write out all the object pointer fields.
@@ -2392,6 +2572,14 @@
                                           intptr_t tags,
                                           Snapshot::Kind kind,
                                           bool as_reference) {
+  if (reader->snapshot_code()) {
+    ASSERT(kind == Snapshot::kFull);
+    intptr_t offset = reader->Read<int32_t>();
+    String& result = String::ZoneHandle(reader->zone());
+    result ^= reader->GetObjectAt(offset);
+    reader->AddBackRef(object_id, &result, kIsDeserialized);
+    return raw(result);
+  }
   // Read the length so that we can determine instance size to allocate.
   ASSERT(reader != NULL);
   intptr_t len = reader->ReadSmiValue();
@@ -2499,6 +2687,22 @@
                                intptr_t object_id,
                                Snapshot::Kind kind,
                                bool as_reference) {
+  if (writer->snapshot_code()) {
+    ASSERT(writer->snapshot_code());
+    ASSERT(kind == Snapshot::kFull);
+    // Assert that hash is computed.
+    if (ptr()->hash_ == NULL) {
+      ptr()->hash_ = Smi::New(String::Hash(ptr()->data(),
+                                           Smi::Value(ptr()->length_)));
+    }
+    ASSERT(ptr()->hash_ != NULL);
+    // Write out the serialization header value for this object.
+    writer->WriteInlinedObjectHeader(object_id);
+    writer->WriteIndexedObject(kOneByteStringCid);
+    writer->WriteTags(writer->GetObjectTags(this));
+    writer->Write<int32_t>(writer->GetObjectId(this));
+    return;
+  }
   StringWriteTo(writer,
                 object_id,
                 kind,
@@ -3064,6 +3268,21 @@
     default:
       UNREACHABLE();
   }
+  // If it is a canonical constant make it one.
+  // When reading a full snapshot we don't need to canonicalize the object
+  // as it would already be a canonical object.
+  // When reading a script snapshot or a message snapshot we always have
+  // to canonicalize the object.
+  if (RawObject::IsCanonical(tags)) {
+    if (kind == Snapshot::kFull) {
+      // Set the canonical bit.
+      result.SetCanonical();
+    } else {
+      result ^= result.CheckAndCanonicalize(NULL);
+      ASSERT(!result.IsNull());
+      ASSERT(result.IsCanonical());
+    }
+  }
   return result.raw();
 }
 #undef TYPED_DATA_READ
diff --git a/runtime/vm/redundancy_elimination.cc b/runtime/vm/redundancy_elimination.cc
new file mode 100644
index 0000000..adc1319
--- /dev/null
+++ b/runtime/vm/redundancy_elimination.cc
@@ -0,0 +1,3470 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/redundancy_elimination.h"
+
+#include "vm/bit_vector.h"
+#include "vm/flow_graph.h"
+#include "vm/hash_map.h"
+#include "vm/il_printer.h"
+#include "vm/intermediate_language.h"
+#include "vm/stack_frame.h"
+
+namespace dart {
+
+
+DEFINE_FLAG(bool, dead_store_elimination, true, "Eliminate dead stores");
+DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination.");
+DEFINE_FLAG(bool, trace_load_optimization, false,
+    "Print live sets for load optimization pass.");
+
+// Quick access to the current zone.
+#define Z (zone())
+
+
+class CSEInstructionMap : public ValueObject {
+ public:
+  // Right now CSE and LICM track a single effect: possible externalization of
+  // strings.
+  // Other effects like modifications of fields are tracked in a separate load
+  // forwarding pass via Alias structure.
+  COMPILE_ASSERT(EffectSet::kLastEffect == 1);
+
+  CSEInstructionMap() : independent_(), dependent_() { }
+  explicit CSEInstructionMap(const CSEInstructionMap& other)
+      : ValueObject(),
+        independent_(other.independent_),
+        dependent_(other.dependent_) {
+  }
+
+  void RemoveAffected(EffectSet effects) {
+    if (!effects.IsNone()) {
+      dependent_.Clear();
+    }
+  }
+
+  Instruction* Lookup(Instruction* other) const {
+    return GetMapFor(other)->Lookup(other);
+  }
+
+  void Insert(Instruction* instr) {
+    return GetMapFor(instr)->Insert(instr);
+  }
+
+ private:
+  typedef DirectChainedHashMap<PointerKeyValueTrait<Instruction> >  Map;
+
+  Map* GetMapFor(Instruction* instr) {
+    return instr->Dependencies().IsNone() ? &independent_ : &dependent_;
+  }
+
+  const Map* GetMapFor(Instruction* instr) const {
+    return instr->Dependencies().IsNone() ? &independent_ : &dependent_;
+  }
+
+  // All computations that are not affected by any side-effect.
+  // Majority of computations are not affected by anything and will be in
+  // this map.
+  Map independent_;
+
+  // All computations that are affected by side effect.
+  Map dependent_;
+};
+
+
+// Place describes an abstract location (e.g. field) that IR can load
+// from or store to.
+//
+// Places are also used to describe wild-card locations also known as aliases,
+// that essentially represent sets of places that alias each other. Places A
+// and B are said to alias each other if store into A can affect load from B.
+//
+// We distinguish the following aliases:
+//
+//   - for fields
+//     - *.f, *.@offs - field inside some object;
+//     - X.f, X.@offs - field inside an allocated object X;
+//   - for indexed accesses
+//     - *[*] - non-constant index inside some object;
+//     - *[C] - constant index inside some object;
+//     - X[*] - non-constant index inside an allocated object X;
+//     - X[C] - constant index inside an allocated object X.
+//
+// Constant indexed places are divided into two subcategories:
+//
+//   - Access to homogeneous array-like objects: Array, ImmutableArray,
+//     OneByteString, TwoByteString. These objects can only be accessed
+//     on element by element basis with all elements having the same size.
+//     This means X[C] aliases X[K] if and only if C === K.
+//   - TypedData accesses. TypedData allow to read one of the primitive
+//     data types at the given byte offset. When TypedData is accessed through
+//     index operator on a typed array or a typed array view it is guaranteed
+//     that the byte offset is always aligned by the element size. We write
+//     these accesses as X[C|S], where C is constant byte offset and S is size
+//     of the data type. Obviously X[C|S] and X[K|U] alias if and only if either
+//     C = RoundDown(K, S) or K = RoundDown(C, U).
+//     Note that not all accesses to typed data are aligned: e.g. ByteData
+//     allows unanaligned access through it's get*/set* methods.
+//     Check in Place::SetIndex ensures that we never create a place X[C|S]
+//     such that C is not aligned by S.
+//
+// Separating allocations from other objects improves precision of the
+// load forwarding pass because of the following two properties:
+//
+//   - if X can be proven to have no aliases itself (i.e. there is no other SSA
+//     variable that points to X) then no place inside X can be aliased with any
+//     wildcard dependent place (*.f, *.@offs, *[*], *[C]);
+//   - given allocations X and Y no place inside X can be aliased with any place
+//     inside Y even if any of them or both escape.
+//
+// It important to realize that single place can belong to multiple aliases.
+// For example place X.f with aliased allocation X belongs both to X.f and *.f
+// aliases. Likewise X[C] with non-aliased allocation X belongs to X[C] and X[*]
+// aliases.
+//
+class Place : public ValueObject {
+ public:
+  enum Kind {
+    kNone,
+
+    // Field location. For instance fields is represented as a pair of a Field
+    // object and an instance (SSA definition) that is being accessed.
+    // For static fields instance is NULL.
+    kField,
+
+    // VMField location. Represented as a pair of an instance (SSA definition)
+    // being accessed and offset to the field.
+    kVMField,
+
+    // Indexed location with a non-constant index.
+    kIndexed,
+
+    // Indexed location with a constant index.
+    kConstantIndexed,
+  };
+
+  // Size of the element accessed by constant index. Size is only important
+  // for TypedData because those accesses can alias even when constant indexes
+  // are not the same: X[0|4] aliases X[0|2] and X[2|2].
+  enum ElementSize {
+    // If indexed access is not a TypedData access then element size is not
+    // important because there is only a single possible access size depending
+    // on the receiver - X[C] aliases X[K] if and only if C == K.
+    // This is the size set for Array, ImmutableArray, OneByteString and
+    // TwoByteString accesses.
+    kNoSize,
+
+    // 1 byte (Int8List, Uint8List, Uint8ClampedList).
+    kInt8,
+
+    // 2 bytes (Int16List, Uint16List).
+    kInt16,
+
+    // 4 bytes (Int32List, Uint32List, Float32List).
+    kInt32,
+
+    // 8 bytes (Int64List, Uint64List, Float64List).
+    kInt64,
+
+    // 16 bytes (Int32x4List, Float32x4List, Float64x2List).
+    kInt128,
+
+    kLargestElementSize = kInt128,
+  };
+
+  Place(const Place& other)
+      : ValueObject(),
+        flags_(other.flags_),
+        instance_(other.instance_),
+        raw_selector_(other.raw_selector_),
+        id_(other.id_) {
+  }
+
+  // Construct a place from instruction if instruction accesses any place.
+  // Otherwise constructs kNone place.
+  Place(Instruction* instr, bool* is_load, bool* is_store)
+      : flags_(0),
+        instance_(NULL),
+        raw_selector_(0),
+        id_(0) {
+    switch (instr->tag()) {
+      case Instruction::kLoadField: {
+        LoadFieldInstr* load_field = instr->AsLoadField();
+        set_representation(load_field->representation());
+        instance_ = load_field->instance()->definition()->OriginalDefinition();
+        if (load_field->field() != NULL) {
+          set_kind(kField);
+          field_ = load_field->field();
+        } else {
+          set_kind(kVMField);
+          offset_in_bytes_ = load_field->offset_in_bytes();
+        }
+        *is_load = true;
+        break;
+      }
+
+      case Instruction::kStoreInstanceField: {
+        StoreInstanceFieldInstr* store =
+            instr->AsStoreInstanceField();
+        set_representation(store->RequiredInputRepresentation(
+            StoreInstanceFieldInstr::kValuePos));
+        instance_ = store->instance()->definition()->OriginalDefinition();
+        if (!store->field().IsNull()) {
+          set_kind(kField);
+          field_ = &store->field();
+        } else {
+          set_kind(kVMField);
+          offset_in_bytes_ = store->offset_in_bytes();
+        }
+        *is_store = true;
+        break;
+      }
+
+      case Instruction::kLoadStaticField:
+        set_kind(kField);
+        set_representation(instr->AsLoadStaticField()->representation());
+        field_ = &instr->AsLoadStaticField()->StaticField();
+        *is_load = true;
+        break;
+
+      case Instruction::kStoreStaticField:
+        set_kind(kField);
+        set_representation(instr->AsStoreStaticField()->
+            RequiredInputRepresentation(StoreStaticFieldInstr::kValuePos));
+        field_ = &instr->AsStoreStaticField()->field();
+        *is_store = true;
+        break;
+
+      case Instruction::kLoadIndexed: {
+        LoadIndexedInstr* load_indexed = instr->AsLoadIndexed();
+        set_representation(load_indexed->representation());
+        instance_ = load_indexed->array()->definition()->OriginalDefinition();
+        SetIndex(load_indexed->index()->definition(),
+                 load_indexed->index_scale(),
+                 load_indexed->class_id());
+        *is_load = true;
+        break;
+      }
+
+      case Instruction::kStoreIndexed: {
+        StoreIndexedInstr* store_indexed = instr->AsStoreIndexed();
+        set_representation(store_indexed->
+            RequiredInputRepresentation(StoreIndexedInstr::kValuePos));
+        instance_ = store_indexed->array()->definition()->OriginalDefinition();
+        SetIndex(store_indexed->index()->definition(),
+                 store_indexed->index_scale(),
+                 store_indexed->class_id());
+        *is_store = true;
+        break;
+      }
+
+      default:
+        break;
+    }
+  }
+
+  // Create object representing *[*] alias.
+  static Place* CreateAnyInstanceAnyIndexAlias(Zone* zone,
+                                               intptr_t id) {
+    return Wrap(zone, Place(
+        EncodeFlags(kIndexed, kNoRepresentation, kNoSize),
+        NULL,
+        0), id);
+  }
+
+  // Return least generic alias for this place. Given that aliases are
+  // essentially sets of places we define least generic alias as a smallest
+  // alias that contains this place.
+  //
+  // We obtain such alias by a simple transformation:
+  //
+  //    - for places that depend on an instance X.f, X.@offs, X[i], X[C]
+  //      we drop X if X is not an allocation because in this case X does not
+  //      posess an identity obtaining aliases *.f, *.@offs, *[i] and *[C]
+  //      respectively;
+  //    - for non-constant indexed places X[i] we drop information about the
+  //      index obtaining alias X[*].
+  //    - we drop information about representation, but keep element size
+  //      if any.
+  //
+  Place ToAlias() const {
+    return Place(
+        RepresentationBits::update(kNoRepresentation, flags_),
+        (DependsOnInstance() && IsAllocation(instance())) ? instance() : NULL,
+        (kind() == kIndexed) ? 0 : raw_selector_);
+  }
+
+  bool DependsOnInstance() const {
+    switch (kind()) {
+      case kField:
+      case kVMField:
+      case kIndexed:
+      case kConstantIndexed:
+        return true;
+
+      case kNone:
+        return false;
+    }
+
+    UNREACHABLE();
+    return false;
+  }
+
+  // Given instance dependent alias X.f, X.@offs, X[C], X[*] return
+  // wild-card dependent alias *.f, *.@offs, *[C] or *[*] respectively.
+  Place CopyWithoutInstance() const {
+    ASSERT(DependsOnInstance());
+    return Place(flags_, NULL, raw_selector_);
+  }
+
+  // Given alias X[C] or *[C] return X[*] and *[*] respectively.
+  Place CopyWithoutIndex() const {
+    ASSERT(kind() == kConstantIndexed);
+    return Place(EncodeFlags(kIndexed, kNoRepresentation, kNoSize),
+                 instance_,
+                 0);
+  }
+
+  // Given alias X[ByteOffs|S] and a larger element size S', return
+  // alias X[RoundDown(ByteOffs, S')|S'] - this is the byte offset of a larger
+  // typed array element that contains this typed array element.
+  // In other words this method computes the only possible place with the given
+  // size that can alias this place (due to alignment restrictions).
+  // For example for X[9|kInt8] and target size kInt32 we would return
+  // X[8|kInt32].
+  Place ToLargerElement(ElementSize to) const {
+    ASSERT(kind() == kConstantIndexed);
+    ASSERT(element_size() != kNoSize);
+    ASSERT(element_size() < to);
+    return Place(ElementSizeBits::update(to, flags_),
+                 instance_,
+                 RoundByteOffset(to, index_constant_));
+  }
+
+
+  intptr_t id() const { return id_; }
+
+  Kind kind() const { return KindBits::decode(flags_); }
+
+  Representation representation() const {
+    return RepresentationBits::decode(flags_);
+  }
+
+  Definition* instance() const {
+    ASSERT(DependsOnInstance());
+    return instance_;
+  }
+
+  void set_instance(Definition* def) {
+    ASSERT(DependsOnInstance());
+    instance_ = def->OriginalDefinition();
+  }
+
+  const Field& field() const {
+    ASSERT(kind() == kField);
+    return *field_;
+  }
+
+  intptr_t offset_in_bytes() const {
+    ASSERT(kind() == kVMField);
+    return offset_in_bytes_;
+  }
+
+  Definition* index() const {
+    ASSERT(kind() == kIndexed);
+    return index_;
+  }
+
+  ElementSize element_size() const {
+    return ElementSizeBits::decode(flags_);
+  }
+
+  intptr_t index_constant() const {
+    ASSERT(kind() == kConstantIndexed);
+    return index_constant_;
+  }
+
+  static const char* DefinitionName(Definition* def) {
+    if (def == NULL) {
+      return "*";
+    } else {
+      return Thread::Current()->zone()->PrintToString(
+            "v%" Pd, def->ssa_temp_index());
+    }
+  }
+
+  const char* ToCString() const {
+    switch (kind()) {
+      case kNone:
+        return "<none>";
+
+      case kField: {
+        const char* field_name = String::Handle(field().name()).ToCString();
+        if (field().is_static()) {
+          return Thread::Current()->zone()->PrintToString(
+              "<%s>", field_name);
+        } else {
+          return Thread::Current()->zone()->PrintToString(
+              "<%s.%s>", DefinitionName(instance()), field_name);
+        }
+      }
+
+      case kVMField:
+        return Thread::Current()->zone()->PrintToString(
+            "<%s.@%" Pd ">",
+            DefinitionName(instance()),
+            offset_in_bytes());
+
+      case kIndexed:
+        return Thread::Current()->zone()->PrintToString(
+            "<%s[%s]>",
+            DefinitionName(instance()),
+            DefinitionName(index()));
+
+      case kConstantIndexed:
+        if (element_size() == kNoSize) {
+          return Thread::Current()->zone()->PrintToString(
+              "<%s[%" Pd "]>",
+              DefinitionName(instance()),
+              index_constant());
+        } else {
+          return Thread::Current()->zone()->PrintToString(
+              "<%s[%" Pd "|%" Pd "]>",
+              DefinitionName(instance()),
+              index_constant(),
+              ElementSizeMultiplier(element_size()));
+        }
+    }
+    UNREACHABLE();
+    return "<?>";
+  }
+
+  // Fields that are considered immutable by load optimization.
+  // Handle static finals as non-final with precompilation because
+  // they may be reset to uninitialized after compilation.
+  bool IsImmutableField() const {
+    return (kind() == kField)
+        && field().is_final()
+        && (!field().is_static() || !FLAG_fields_may_be_reset);
+  }
+
+  intptr_t Hashcode() const {
+    return (flags_ * 63 + reinterpret_cast<intptr_t>(instance_)) * 31 +
+        FieldHashcode();
+  }
+
+  bool Equals(const Place* other) const {
+    return (flags_ == other->flags_) &&
+        (instance_ == other->instance_) &&
+        SameField(other);
+  }
+
+  // Create a zone allocated copy of this place and assign given id to it.
+  static Place* Wrap(Zone* zone, const Place& place, intptr_t id);
+
+  static bool IsAllocation(Definition* defn) {
+    return (defn != NULL) &&
+        (defn->IsAllocateObject() ||
+         defn->IsCreateArray() ||
+         defn->IsAllocateUninitializedContext() ||
+         (defn->IsStaticCall() &&
+          defn->AsStaticCall()->IsRecognizedFactory()));
+  }
+
+ private:
+  Place(uword flags, Definition* instance, intptr_t selector)
+      : flags_(flags),
+        instance_(instance),
+        raw_selector_(selector),
+        id_(0) {
+  }
+
+  bool SameField(const Place* other) const {
+    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().Original())
+                              : offset_in_bytes_;
+  }
+
+  void set_representation(Representation rep) {
+    flags_ = RepresentationBits::update(rep, flags_);
+  }
+
+  void set_kind(Kind kind) {
+    flags_ = KindBits::update(kind, flags_);
+  }
+
+  void set_element_size(ElementSize scale) {
+    flags_ = ElementSizeBits::update(scale, flags_);
+  }
+
+  void SetIndex(Definition* index, intptr_t scale, intptr_t class_id) {
+    ConstantInstr* index_constant = index->AsConstant();
+    if ((index_constant != NULL) && index_constant->value().IsSmi()) {
+      const intptr_t index_value = Smi::Cast(index_constant->value()).Value();
+      const ElementSize size = ElementSizeFor(class_id);
+      const bool is_typed_data = (size != kNoSize);
+
+      // If we are writing into the typed data scale the index to
+      // get byte offset. Otherwise ignore the scale.
+      if (!is_typed_data) {
+        scale = 1;
+      }
+
+      // Guard against potential multiplication overflow and negative indices.
+      if ((0 <= index_value) && (index_value < (kMaxInt32 / scale))) {
+        const intptr_t scaled_index = index_value * scale;
+
+        // Guard against unaligned byte offsets.
+        if (!is_typed_data ||
+            Utils::IsAligned(scaled_index, ElementSizeMultiplier(size))) {
+          set_kind(kConstantIndexed);
+          set_element_size(size);
+          index_constant_ = scaled_index;
+          return;
+        }
+      }
+
+      // Fallthrough: create generic _[*] place.
+    }
+
+    set_kind(kIndexed);
+    index_ = index;
+  }
+
+  static uword EncodeFlags(Kind kind, Representation rep, ElementSize scale) {
+    ASSERT((kind == kConstantIndexed) || (scale == kNoSize));
+    return KindBits::encode(kind) |
+        RepresentationBits::encode(rep) |
+        ElementSizeBits::encode(scale);
+  }
+
+  static ElementSize ElementSizeFor(intptr_t class_id) {
+    switch (class_id) {
+      case kArrayCid:
+      case kImmutableArrayCid:
+      case kOneByteStringCid:
+      case kTwoByteStringCid:
+        // Object arrays and strings do not allow accessing them through
+        // different types. No need to attach scale.
+        return kNoSize;
+
+      case kTypedDataInt8ArrayCid:
+      case kTypedDataUint8ArrayCid:
+      case kTypedDataUint8ClampedArrayCid:
+      case kExternalTypedDataUint8ArrayCid:
+      case kExternalTypedDataUint8ClampedArrayCid:
+        return kInt8;
+
+      case kTypedDataInt16ArrayCid:
+      case kTypedDataUint16ArrayCid:
+        return kInt16;
+
+      case kTypedDataInt32ArrayCid:
+      case kTypedDataUint32ArrayCid:
+      case kTypedDataFloat32ArrayCid:
+        return kInt32;
+
+      case kTypedDataInt64ArrayCid:
+      case kTypedDataUint64ArrayCid:
+      case kTypedDataFloat64ArrayCid:
+        return kInt64;
+
+      case kTypedDataInt32x4ArrayCid:
+      case kTypedDataFloat32x4ArrayCid:
+      case kTypedDataFloat64x2ArrayCid:
+        return kInt128;
+
+      default:
+        UNREACHABLE();
+        return kNoSize;
+    }
+  }
+
+  static intptr_t ElementSizeMultiplier(ElementSize size) {
+    return 1 << (static_cast<intptr_t>(size) - static_cast<intptr_t>(kInt8));
+  }
+
+  static intptr_t RoundByteOffset(ElementSize size, intptr_t offset) {
+    return offset & ~(ElementSizeMultiplier(size) - 1);
+  }
+
+  class KindBits : public BitField<uword, Kind, 0, 3> {};
+  class RepresentationBits :
+      public BitField<uword, Representation, KindBits::kNextBit, 11> {};
+  class ElementSizeBits :
+      public BitField<uword, ElementSize, RepresentationBits::kNextBit, 3> {};
+
+  uword flags_;
+  Definition* instance_;
+  union {
+    intptr_t raw_selector_;
+    const Field* field_;
+    intptr_t offset_in_bytes_;
+    intptr_t index_constant_;
+    Definition* index_;
+  };
+
+  intptr_t id_;
+};
+
+
+class ZonePlace : public ZoneAllocated {
+ public:
+  explicit ZonePlace(const Place& place) : place_(place) { }
+
+  Place* place() { return &place_; }
+
+ private:
+  Place place_;
+};
+
+
+Place* Place::Wrap(Zone* zone, const Place& place, intptr_t id) {
+  Place* wrapped = (new(zone) ZonePlace(place))->place();
+  wrapped->id_ = id;
+  return wrapped;
+}
+
+
+// Correspondence between places connected through outgoing phi moves on the
+// edge that targets join.
+class PhiPlaceMoves : public ZoneAllocated {
+ public:
+  // Record a move from the place with id |from| to the place with id |to| at
+  // the given block.
+  void CreateOutgoingMove(Zone* zone,
+                          BlockEntryInstr* block, intptr_t from, intptr_t to) {
+    const intptr_t block_num = block->preorder_number();
+    while (moves_.length() <= block_num) {
+      moves_.Add(NULL);
+    }
+
+    if (moves_[block_num] == NULL) {
+      moves_[block_num] = new(zone) ZoneGrowableArray<Move>(5);
+    }
+
+    moves_[block_num]->Add(Move(from, to));
+  }
+
+  class Move {
+   public:
+    Move(intptr_t from, intptr_t to) : from_(from), to_(to) { }
+
+    intptr_t from() const { return from_; }
+    intptr_t to() const { return to_; }
+
+   private:
+    intptr_t from_;
+    intptr_t to_;
+  };
+
+  typedef const ZoneGrowableArray<Move>* MovesList;
+
+  MovesList GetOutgoingMoves(BlockEntryInstr* block) const {
+    const intptr_t block_num = block->preorder_number();
+    return (block_num < moves_.length()) ?
+        moves_[block_num] : NULL;
+  }
+
+ private:
+  GrowableArray<ZoneGrowableArray<Move>* > moves_;
+};
+
+
+// A map from aliases to a set of places sharing the alias. Additionally
+// carries a set of places that can be aliased by side-effects, essentially
+// those that are affected by calls.
+class AliasedSet : public ZoneAllocated {
+ public:
+  AliasedSet(Zone* zone,
+             DirectChainedHashMap<PointerKeyValueTrait<Place> >* places_map,
+             ZoneGrowableArray<Place*>* places,
+             PhiPlaceMoves* phi_moves)
+      : zone_(zone),
+        places_map_(places_map),
+        places_(*places),
+        phi_moves_(phi_moves),
+        aliases_(5),
+        aliases_map_(),
+        typed_data_access_sizes_(),
+        representatives_(),
+        killed_(),
+        aliased_by_effects_(new(zone) BitVector(zone, places->length())) {
+    InsertAlias(Place::CreateAnyInstanceAnyIndexAlias(zone_,
+        kAnyInstanceAnyIndexAlias));
+    for (intptr_t i = 0; i < places_.length(); i++) {
+      AddRepresentative(places_[i]);
+    }
+    ComputeKillSets();
+  }
+
+  intptr_t LookupAliasId(const Place& alias) {
+    const Place* result = aliases_map_.Lookup(&alias);
+    return (result != NULL) ? result->id() : static_cast<intptr_t>(kNoAlias);
+  }
+
+  BitVector* GetKilledSet(intptr_t alias) {
+    return (alias < killed_.length()) ? killed_[alias] : NULL;
+  }
+
+  intptr_t max_place_id() const { return places().length(); }
+  bool IsEmpty() const { return max_place_id() == 0; }
+
+  BitVector* aliased_by_effects() const { return aliased_by_effects_; }
+
+  const ZoneGrowableArray<Place*>& places() const {
+    return places_;
+  }
+
+  Place* LookupCanonical(Place* place) const {
+    return places_map_->Lookup(place);
+  }
+
+  void PrintSet(BitVector* set) {
+    bool comma = false;
+    for (BitVector::Iterator it(set);
+         !it.Done();
+         it.Advance()) {
+      if (comma) {
+        THR_Print(", ");
+      }
+      THR_Print("%s", places_[it.Current()]->ToCString());
+      comma = true;
+    }
+  }
+
+  const PhiPlaceMoves* phi_moves() const { return phi_moves_; }
+
+  void RollbackAliasedIdentites() {
+    for (intptr_t i = 0; i < identity_rollback_.length(); ++i) {
+      identity_rollback_[i]->SetIdentity(AliasIdentity::Unknown());
+    }
+  }
+
+  // Returns false if the result of an allocation instruction can't be aliased
+  // by another SSA variable and true otherwise.
+  bool CanBeAliased(Definition* alloc) {
+    if (!Place::IsAllocation(alloc)) {
+      return true;
+    }
+
+    if (alloc->Identity().IsUnknown()) {
+      ComputeAliasing(alloc);
+    }
+
+    return !alloc->Identity().IsNotAliased();
+  }
+
+  enum {
+    kNoAlias = 0
+  };
+
+ private:
+  enum {
+    // Artificial alias that is used to collect all representatives of the
+    // *[C], X[C] aliases for arbitrary C.
+    kAnyConstantIndexedAlias = 1,
+
+    // Artificial alias that is used to collect all representatives of
+    // *[C] alias for arbitrary C.
+    kUnknownInstanceConstantIndexedAlias = 2,
+
+    // Artificial alias that is used to collect all representatives of
+    // X[*] alias for all X.
+    kAnyAllocationIndexedAlias = 3,
+
+    // *[*] alias.
+    kAnyInstanceAnyIndexAlias = 4
+  };
+
+  // Compute least generic alias for the place and assign alias id to it.
+  void AddRepresentative(Place* place) {
+    if (!place->IsImmutableField()) {
+      const Place* alias = CanonicalizeAlias(place->ToAlias());
+      EnsureSet(&representatives_, alias->id())->Add(place->id());
+
+      // Update cumulative representative sets that are used during
+      // killed sets computation.
+      if (alias->kind() == Place::kConstantIndexed) {
+        if (CanBeAliased(alias->instance())) {
+          EnsureSet(&representatives_, kAnyConstantIndexedAlias)->
+              Add(place->id());
+        }
+
+        if (alias->instance() == NULL) {
+          EnsureSet(&representatives_, kUnknownInstanceConstantIndexedAlias)->
+              Add(place->id());
+        }
+
+        // Collect all element sizes used to access TypedData arrays in
+        // the function. This is used to skip sizes without representatives
+        // when computing kill sets.
+        if (alias->element_size() != Place::kNoSize) {
+          typed_data_access_sizes_.Add(alias->element_size());
+        }
+      } else if ((alias->kind() == Place::kIndexed) &&
+                 CanBeAliased(place->instance())) {
+        EnsureSet(&representatives_, kAnyAllocationIndexedAlias)->
+            Add(place->id());
+      }
+
+      if (!IsIndependentFromEffects(place)) {
+        aliased_by_effects_->Add(place->id());
+      }
+    }
+  }
+
+  void ComputeKillSets() {
+    for (intptr_t i = 0; i < aliases_.length(); ++i) {
+      const Place* alias = aliases_[i];
+      // Add all representatives to the kill set.
+      AddAllRepresentatives(alias->id(), alias->id());
+      ComputeKillSet(alias);
+    }
+
+    if (FLAG_trace_load_optimization) {
+      THR_Print("Aliases KILL sets:\n");
+      for (intptr_t i = 0; i < aliases_.length(); ++i) {
+        const Place* alias = aliases_[i];
+        BitVector* kill = GetKilledSet(alias->id());
+
+        THR_Print("%s: ", alias->ToCString());
+        if (kill != NULL) {
+          PrintSet(kill);
+        }
+        THR_Print("\n");
+      }
+    }
+  }
+
+  void InsertAlias(const Place* alias) {
+    aliases_map_.Insert(alias);
+    aliases_.Add(alias);
+  }
+
+  const Place* CanonicalizeAlias(const Place& alias) {
+    const Place* canonical = aliases_map_.Lookup(&alias);
+    if (canonical == NULL) {
+      canonical = Place::Wrap(zone_,
+                              alias,
+                              kAnyInstanceAnyIndexAlias + aliases_.length());
+      InsertAlias(canonical);
+    }
+    ASSERT(aliases_map_.Lookup(&alias) == canonical);
+    return canonical;
+  }
+
+  BitVector* GetRepresentativesSet(intptr_t alias) {
+    return (alias < representatives_.length()) ? representatives_[alias] : NULL;
+  }
+
+  BitVector* EnsureSet(GrowableArray<BitVector*>* sets,
+                       intptr_t alias) {
+    while (sets->length() <= alias) {
+      sets->Add(NULL);
+    }
+
+    BitVector* set = (*sets)[alias];
+    if (set == NULL) {
+      (*sets)[alias] = set = new(zone_) BitVector(zone_, max_place_id());
+    }
+    return set;
+  }
+
+  void AddAllRepresentatives(const Place* to, intptr_t from) {
+    AddAllRepresentatives(to->id(), from);
+  }
+
+  void AddAllRepresentatives(intptr_t to, intptr_t from) {
+    BitVector* from_set = GetRepresentativesSet(from);
+    if (from_set != NULL) {
+      EnsureSet(&killed_, to)->AddAll(from_set);
+    }
+  }
+
+  void CrossAlias(const Place* to, const Place& from) {
+    const intptr_t from_id = LookupAliasId(from);
+    if (from_id == kNoAlias) {
+      return;
+    }
+    CrossAlias(to, from_id);
+  }
+
+  void CrossAlias(const Place* to, intptr_t from) {
+    AddAllRepresentatives(to->id(), from);
+    AddAllRepresentatives(from, to->id());
+  }
+
+  // When computing kill sets we let less generic alias insert its
+  // representatives into more generic alias'es kill set. For example
+  // when visiting alias X[*] instead of searching for all aliases X[C]
+  // and inserting their representatives into kill set for X[*] we update
+  // kill set for X[*] each time we visit new X[C] for some C.
+  // There is an exception however: if both aliases are parametric like *[C]
+  // and X[*] which cross alias when X is an aliased allocation then we use
+  // artificial aliases that contain all possible representatives for the given
+  // alias for any value of the parameter to compute resulting kill set.
+  void ComputeKillSet(const Place* alias) {
+    switch (alias->kind()) {
+      case Place::kIndexed:  // Either *[*] or X[*] alias.
+        if (alias->instance() == NULL) {
+          // *[*] aliases with X[*], X[C], *[C].
+          AddAllRepresentatives(alias, kAnyConstantIndexedAlias);
+          AddAllRepresentatives(alias, kAnyAllocationIndexedAlias);
+        } else if (CanBeAliased(alias->instance())) {
+          // X[*] aliases with X[C].
+          // If X can be aliased then X[*] also aliases with *[C], *[*].
+          CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+          AddAllRepresentatives(alias, kUnknownInstanceConstantIndexedAlias);
+        }
+        break;
+
+      case Place::kConstantIndexed:  // Either X[C] or *[C] alias.
+        if (alias->element_size() != Place::kNoSize) {
+          const bool has_aliased_instance =
+              (alias->instance() != NULL) && CanBeAliased(alias->instance());
+
+          // If this is a TypedData access then X[C|S] aliases larger elements
+          // covering this one X[RoundDown(C, S')|S'] for all S' > S and
+          // all smaller elements being covered by this one X[C'|S'] for
+          // some S' < S and all C' such that C = RoundDown(C', S).
+          // In the loop below it's enough to only propagate aliasing to
+          // larger aliases because propagation is symmetric: smaller aliases
+          // (if there are any) would update kill set for this alias when they
+          // are visited.
+          for (intptr_t i = static_cast<intptr_t>(alias->element_size()) + 1;
+               i <= Place::kLargestElementSize;
+               i++) {
+            // Skip element sizes that a guaranteed to have no representatives.
+            if (!typed_data_access_sizes_.Contains(alias->element_size())) {
+              continue;
+            }
+
+            // X[C|S] aliases with X[RoundDown(C, S')|S'] and likewise
+            // *[C|S] aliases with *[RoundDown(C, S')|S'].
+            const Place larger_alias =
+                alias->ToLargerElement(static_cast<Place::ElementSize>(i));
+            CrossAlias(alias, larger_alias);
+            if (has_aliased_instance) {
+              // If X is an aliased instance then X[C|S] aliases
+              // with *[RoundDown(C, S')|S'].
+              CrossAlias(alias, larger_alias.CopyWithoutInstance());
+            }
+          }
+        }
+
+        if (alias->instance() == NULL) {
+          // *[C] aliases with X[C], X[*], *[*].
+          AddAllRepresentatives(alias, kAnyAllocationIndexedAlias);
+          CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+        } else {
+          // X[C] aliases with X[*].
+          // If X can be aliased then X[C] also aliases with *[C], *[*].
+          CrossAlias(alias, alias->CopyWithoutIndex());
+          if (CanBeAliased(alias->instance())) {
+            CrossAlias(alias, alias->CopyWithoutInstance());
+            CrossAlias(alias, kAnyInstanceAnyIndexAlias);
+          }
+        }
+        break;
+
+      case Place::kField:
+      case Place::kVMField:
+        if (CanBeAliased(alias->instance())) {
+          // X.f or X.@offs alias with *.f and *.@offs respectively.
+          CrossAlias(alias, alias->CopyWithoutInstance());
+        }
+        break;
+
+      case Place::kNone:
+        UNREACHABLE();
+    }
+  }
+
+  // Returns true if the given load is unaffected by external side-effects.
+  // This essentially means that no stores to the same location can
+  // occur in other functions.
+  bool IsIndependentFromEffects(Place* place) {
+    if (place->IsImmutableField()) {
+      // Note that we can't use LoadField's is_immutable attribute here because
+      // some VM-fields (those that have no corresponding Field object and
+      // accessed through offset alone) can share offset but have different
+      // immutability properties.
+      // One example is the length property of growable and fixed size list. If
+      // loads of these two properties occur in the same function for the same
+      // receiver then they will get the same expression number. However
+      // immutability of the length of fixed size list does not mean that
+      // growable list also has immutable property. Thus we will make a
+      // conservative assumption for the VM-properties.
+      // TODO(vegorov): disambiguate immutable and non-immutable VM-fields with
+      // the same offset e.g. through recognized kind.
+      return true;
+    }
+
+    return ((place->kind() == Place::kField) ||
+         (place->kind() == Place::kVMField)) &&
+        !CanBeAliased(place->instance());
+  }
+
+  // Returns true if there are direct loads from the given place.
+  bool HasLoadsFromPlace(Definition* defn, const Place* place) {
+    ASSERT((place->kind() == Place::kField) ||
+           (place->kind() == Place::kVMField));
+
+    for (Value* use = defn->input_use_list();
+         use != NULL;
+         use = use->next_use()) {
+      Instruction* instr = use->instruction();
+      if ((instr->IsRedefinition() ||
+           instr->IsAssertAssignable()) &&
+          HasLoadsFromPlace(instr->AsDefinition(), place)) {
+        return true;
+      }
+      bool is_load = false, is_store;
+      Place load_place(instr, &is_load, &is_store);
+
+      if (is_load && load_place.Equals(place)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  // Check if any use of the definition can create an alias.
+  // Can add more objects into aliasing_worklist_.
+  bool AnyUseCreatesAlias(Definition* defn) {
+    for (Value* use = defn->input_use_list();
+         use != NULL;
+         use = use->next_use()) {
+      Instruction* instr = use->instruction();
+      if (instr->IsPushArgument() ||
+          (instr->IsStoreIndexed()
+           && (use->use_index() == StoreIndexedInstr::kValuePos)) ||
+          instr->IsStoreStaticField() ||
+          instr->IsPhi()) {
+        return true;
+      } else if ((instr->IsAssertAssignable() || instr->IsRedefinition()) &&
+                 AnyUseCreatesAlias(instr->AsDefinition())) {
+        return true;
+      } else if ((instr->IsStoreInstanceField()
+           && (use->use_index() != StoreInstanceFieldInstr::kInstancePos))) {
+        ASSERT(use->use_index() == StoreInstanceFieldInstr::kValuePos);
+        // If we store this value into an object that is not aliased itself
+        // and we never load again then the store does not create an alias.
+        StoreInstanceFieldInstr* store = instr->AsStoreInstanceField();
+        Definition* instance =
+            store->instance()->definition()->OriginalDefinition();
+        if (Place::IsAllocation(instance) &&
+            !instance->Identity().IsAliased()) {
+          bool is_load, is_store;
+          Place store_place(instr, &is_load, &is_store);
+
+          if (!HasLoadsFromPlace(instance, &store_place)) {
+            // No loads found that match this store. If it is yet unknown if
+            // the object is not aliased then optimistically assume this but
+            // add it to the worklist to check its uses transitively.
+            if (instance->Identity().IsUnknown()) {
+              instance->SetIdentity(AliasIdentity::NotAliased());
+              aliasing_worklist_.Add(instance);
+            }
+            continue;
+          }
+        }
+        return true;
+      }
+    }
+    return false;
+  }
+
+  // Mark any value stored into the given object as potentially aliased.
+  void MarkStoredValuesEscaping(Definition* defn) {
+    // Find all stores into this object.
+    for (Value* use = defn->input_use_list();
+         use != NULL;
+         use = use->next_use()) {
+      if (use->instruction()->IsRedefinition() ||
+          use->instruction()->IsAssertAssignable()) {
+        MarkStoredValuesEscaping(use->instruction()->AsDefinition());
+        continue;
+      }
+      if ((use->use_index() == StoreInstanceFieldInstr::kInstancePos) &&
+          use->instruction()->IsStoreInstanceField()) {
+        StoreInstanceFieldInstr* store =
+            use->instruction()->AsStoreInstanceField();
+        Definition* value = store->value()->definition()->OriginalDefinition();
+        if (value->Identity().IsNotAliased()) {
+          value->SetIdentity(AliasIdentity::Aliased());
+          identity_rollback_.Add(value);
+
+          // Add to worklist to propagate the mark transitively.
+          aliasing_worklist_.Add(value);
+        }
+      }
+    }
+  }
+
+  // Determine if the given definition can't be aliased.
+  void ComputeAliasing(Definition* alloc) {
+    ASSERT(Place::IsAllocation(alloc));
+    ASSERT(alloc->Identity().IsUnknown());
+    ASSERT(aliasing_worklist_.is_empty());
+
+    alloc->SetIdentity(AliasIdentity::NotAliased());
+    aliasing_worklist_.Add(alloc);
+
+    while (!aliasing_worklist_.is_empty()) {
+      Definition* defn = aliasing_worklist_.RemoveLast();
+      ASSERT(Place::IsAllocation(defn));
+      // If the definition in the worklist was optimistically marked as
+      // not-aliased check that optimistic assumption still holds: check if
+      // any of its uses can create an alias.
+      if (!defn->Identity().IsAliased() && AnyUseCreatesAlias(defn)) {
+        defn->SetIdentity(AliasIdentity::Aliased());
+        identity_rollback_.Add(defn);
+      }
+
+      // If the allocation site is marked as aliased conservatively mark
+      // any values stored into the object aliased too.
+      if (defn->Identity().IsAliased()) {
+        MarkStoredValuesEscaping(defn);
+      }
+    }
+  }
+
+  Zone* zone_;
+
+  DirectChainedHashMap<PointerKeyValueTrait<Place> >* places_map_;
+
+  const ZoneGrowableArray<Place*>& places_;
+
+  const PhiPlaceMoves* phi_moves_;
+
+  // A list of all seen aliases and a map that allows looking up canonical
+  // alias object.
+  GrowableArray<const Place*> aliases_;
+  DirectChainedHashMap<PointerKeyValueTrait<const Place> > aliases_map_;
+
+  SmallSet<Place::ElementSize> typed_data_access_sizes_;
+
+  // Maps alias id to set of ids of places representing the alias.
+  // Place represents an alias if this alias is least generic alias for
+  // the place.
+  // (see ToAlias for the definition of least generic alias).
+  GrowableArray<BitVector*> representatives_;
+
+  // Maps alias id to set of ids of places aliased.
+  GrowableArray<BitVector*> killed_;
+
+  // Set of ids of places that can be affected by side-effects other than
+  // explicit stores (i.e. through calls).
+  BitVector* aliased_by_effects_;
+
+  // Worklist used during alias analysis.
+  GrowableArray<Definition*> aliasing_worklist_;
+
+  // List of definitions that had their identity set to Aliased. At the end
+  // of load optimization their identity will be rolled back to Unknown to
+  // avoid treating them as Aliased at later stages without checking first
+  // as optimizations can potentially eliminate instructions leading to
+  // aliasing.
+  GrowableArray<Definition*> identity_rollback_;
+};
+
+
+static Definition* GetStoredValue(Instruction* instr) {
+  if (instr->IsStoreIndexed()) {
+    return instr->AsStoreIndexed()->value()->definition();
+  }
+
+  StoreInstanceFieldInstr* store_instance_field = instr->AsStoreInstanceField();
+  if (store_instance_field != NULL) {
+    return store_instance_field->value()->definition();
+  }
+
+  StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
+  if (store_static_field != NULL) {
+    return store_static_field->value()->definition();
+  }
+
+  UNREACHABLE();  // Should only be called for supported store instructions.
+  return NULL;
+}
+
+
+static bool IsPhiDependentPlace(Place* place) {
+  return ((place->kind() == Place::kField) ||
+          (place->kind() == Place::kVMField)) &&
+        (place->instance() != NULL) &&
+        place->instance()->IsPhi();
+}
+
+
+// For each place that depends on a phi ensure that equivalent places
+// corresponding to phi input are numbered and record outgoing phi moves
+// for each block which establish correspondence between phi dependent place
+// and phi input's place that is flowing in.
+static PhiPlaceMoves* ComputePhiMoves(
+    DirectChainedHashMap<PointerKeyValueTrait<Place> >* map,
+    ZoneGrowableArray<Place*>* places) {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  PhiPlaceMoves* phi_moves = new(zone) PhiPlaceMoves();
+
+  for (intptr_t i = 0; i < places->length(); i++) {
+    Place* place = (*places)[i];
+
+    if (IsPhiDependentPlace(place)) {
+      PhiInstr* phi = place->instance()->AsPhi();
+      BlockEntryInstr* block = phi->GetBlock();
+
+      if (FLAG_trace_optimization) {
+        THR_Print("phi dependent place %s\n", place->ToCString());
+      }
+
+      Place input_place(*place);
+      for (intptr_t j = 0; j < phi->InputCount(); j++) {
+        input_place.set_instance(phi->InputAt(j)->definition());
+
+        Place* result = map->Lookup(&input_place);
+        if (result == NULL) {
+          result = Place::Wrap(zone, input_place, places->length());
+          map->Insert(result);
+          places->Add(result);
+          if (FLAG_trace_optimization) {
+            THR_Print("  adding place %s as %" Pd "\n",
+                      result->ToCString(),
+                      result->id());
+          }
+        }
+        phi_moves->CreateOutgoingMove(zone,
+                                      block->PredecessorAt(j),
+                                      result->id(),
+                                      place->id());
+      }
+    }
+  }
+
+  return phi_moves;
+}
+
+
+enum CSEMode {
+  kOptimizeLoads,
+  kOptimizeStores
+};
+
+
+static AliasedSet* NumberPlaces(
+    FlowGraph* graph,
+    DirectChainedHashMap<PointerKeyValueTrait<Place> >* map,
+    CSEMode mode) {
+  // Loads representing different expression ids will be collected and
+  // used to build per offset kill sets.
+  Zone* zone = graph->zone();
+  ZoneGrowableArray<Place*>* places =
+      new(zone) ZoneGrowableArray<Place*>(10);
+
+  bool has_loads = false;
+  bool has_stores = false;
+  for (BlockIterator it = graph->reverse_postorder_iterator();
+       !it.Done();
+       it.Advance()) {
+    BlockEntryInstr* block = it.Current();
+
+    for (ForwardInstructionIterator instr_it(block);
+         !instr_it.Done();
+         instr_it.Advance()) {
+      Instruction* instr = instr_it.Current();
+      Place place(instr, &has_loads, &has_stores);
+      if (place.kind() == Place::kNone) {
+        continue;
+      }
+
+      Place* result = map->Lookup(&place);
+      if (result == NULL) {
+        result = Place::Wrap(zone, place, places->length());
+        map->Insert(result);
+        places->Add(result);
+
+        if (FLAG_trace_optimization) {
+          THR_Print("numbering %s as %" Pd "\n",
+                    result->ToCString(),
+                    result->id());
+        }
+      }
+
+      instr->set_place_id(result->id());
+    }
+  }
+
+  if ((mode == kOptimizeLoads) && !has_loads) {
+    return NULL;
+  }
+  if ((mode == kOptimizeStores) && !has_stores) {
+    return NULL;
+  }
+
+  PhiPlaceMoves* phi_moves = ComputePhiMoves(map, places);
+
+  // Build aliasing sets mapping aliases to loads.
+  return new(zone) AliasedSet(zone, map, places, phi_moves);
+}
+
+
+// Load instructions handled by load elimination.
+static bool IsLoadEliminationCandidate(Instruction* instr) {
+  return instr->IsLoadField()
+      || instr->IsLoadIndexed()
+      || instr->IsLoadStaticField();
+}
+
+
+static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets,
+                                intptr_t loop_header_index,
+                                Instruction* instr) {
+  return IsLoadEliminationCandidate(instr) &&
+      (sets != NULL) &&
+      instr->HasPlaceId() &&
+      ((*sets)[loop_header_index] != NULL) &&
+      (*sets)[loop_header_index]->Contains(instr->place_id());
+}
+
+
+LICM::LICM(FlowGraph* flow_graph) : flow_graph_(flow_graph) {
+  ASSERT(flow_graph->is_licm_allowed());
+}
+
+
+void LICM::Hoist(ForwardInstructionIterator* it,
+                 BlockEntryInstr* pre_header,
+                 Instruction* current) {
+  if (current->IsCheckClass()) {
+    current->AsCheckClass()->set_licm_hoisted(true);
+  } else if (current->IsCheckSmi()) {
+    current->AsCheckSmi()->set_licm_hoisted(true);
+  } else if (current->IsCheckEitherNonSmi()) {
+    current->AsCheckEitherNonSmi()->set_licm_hoisted(true);
+  } else if (current->IsCheckArrayBound()) {
+    current->AsCheckArrayBound()->set_licm_hoisted(true);
+  }
+  if (FLAG_trace_optimization) {
+    THR_Print("Hoisting instruction %s:%" Pd " from B%" Pd " to B%" Pd "\n",
+              current->DebugName(),
+              current->GetDeoptId(),
+              current->GetBlock()->block_id(),
+              pre_header->block_id());
+  }
+  // Move the instruction out of the loop.
+  current->RemoveEnvironment();
+  if (it != NULL) {
+    it->RemoveCurrentFromGraph();
+  } else {
+    current->RemoveFromGraph();
+  }
+  GotoInstr* last = pre_header->last_instruction()->AsGoto();
+  // Using kind kEffect will not assign a fresh ssa temporary index.
+  flow_graph()->InsertBefore(last, current, last->env(), FlowGraph::kEffect);
+  current->CopyDeoptIdFrom(*last);
+}
+
+
+void LICM::TrySpecializeSmiPhi(PhiInstr* phi,
+                               BlockEntryInstr* header,
+                               BlockEntryInstr* pre_header) {
+  if (phi->Type()->ToCid() == kSmiCid) {
+    return;
+  }
+
+  // Check if there is only a single kDynamicCid input to the phi that
+  // comes from the pre-header.
+  const intptr_t kNotFound = -1;
+  intptr_t non_smi_input = kNotFound;
+  for (intptr_t i = 0; i < phi->InputCount(); ++i) {
+    Value* input = phi->InputAt(i);
+    if (input->Type()->ToCid() != kSmiCid) {
+      if ((non_smi_input != kNotFound) ||
+          (input->Type()->ToCid() != kDynamicCid)) {
+        // There are multiple kDynamicCid inputs or there is an input that is
+        // known to be non-smi.
+        return;
+      } else {
+        non_smi_input = i;
+      }
+    }
+  }
+
+  if ((non_smi_input == kNotFound) ||
+      (phi->block()->PredecessorAt(non_smi_input) != pre_header)) {
+    return;
+  }
+
+  CheckSmiInstr* check = NULL;
+  for (Value* use = phi->input_use_list();
+       (use != NULL) && (check == NULL);
+       use = use->next_use()) {
+    check = use->instruction()->AsCheckSmi();
+  }
+
+  if (check == NULL) {
+    return;
+  }
+
+  // Host CheckSmi instruction and make this phi smi one.
+  Hoist(NULL, pre_header, check);
+
+  // Replace value we are checking with phi's input.
+  check->value()->BindTo(phi->InputAt(non_smi_input)->definition());
+
+  phi->UpdateType(CompileType::FromCid(kSmiCid));
+}
+
+
+void LICM::OptimisticallySpecializeSmiPhis() {
+  if (!flow_graph()->function().allows_hoisting_check_class() ||
+      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.
+    return;
+  }
+
+  const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
+      flow_graph()->LoopHeaders();
+
+  for (intptr_t i = 0; i < loop_headers.length(); ++i) {
+    JoinEntryInstr* header = loop_headers[i]->AsJoinEntry();
+    // Skip loop that don't have a pre-header block.
+    BlockEntryInstr* pre_header = header->ImmediateDominator();
+    if (pre_header == NULL) continue;
+
+    for (PhiIterator it(header); !it.Done(); it.Advance()) {
+      TrySpecializeSmiPhi(it.Current(), header, pre_header);
+    }
+  }
+}
+
+
+void LICM::Optimize() {
+  if (!flow_graph()->function().allows_hoisting_check_class()) {
+    // Do not hoist any.
+    return;
+  }
+
+  const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
+      flow_graph()->LoopHeaders();
+
+  ZoneGrowableArray<BitVector*>* loop_invariant_loads =
+      flow_graph()->loop_invariant_loads();
+
+  BlockEffects* block_effects = flow_graph()->block_effects();
+
+  for (intptr_t i = 0; i < loop_headers.length(); ++i) {
+    BlockEntryInstr* header = loop_headers[i];
+    // Skip loop that don't have a pre-header block.
+    BlockEntryInstr* pre_header = header->ImmediateDominator();
+    if (pre_header == NULL) continue;
+
+    for (BitVector::Iterator loop_it(header->loop_info());
+         !loop_it.Done();
+         loop_it.Advance()) {
+      BlockEntryInstr* block = flow_graph()->preorder()[loop_it.Current()];
+      for (ForwardInstructionIterator it(block);
+           !it.Done();
+           it.Advance()) {
+        Instruction* current = it.Current();
+        if ((current->AllowsCSE() &&
+             block_effects->CanBeMovedTo(current, pre_header)) ||
+            IsLoopInvariantLoad(loop_invariant_loads, i, current)) {
+          bool inputs_loop_invariant = true;
+          for (int i = 0; i < current->InputCount(); ++i) {
+            Definition* input_def = current->InputAt(i)->definition();
+            if (!input_def->GetBlock()->Dominates(pre_header)) {
+              inputs_loop_invariant = false;
+              break;
+            }
+          }
+          if (inputs_loop_invariant &&
+              !current->IsAssertAssignable() &&
+              !current->IsAssertBoolean()) {
+            // TODO(fschneider): Enable hoisting of Assert-instructions
+            // if it safe to do.
+            Hoist(&it, pre_header, current);
+          }
+        }
+      }
+    }
+  }
+}
+
+
+class LoadOptimizer : public ValueObject {
+ public:
+  LoadOptimizer(FlowGraph* graph, AliasedSet* aliased_set)
+      : graph_(graph),
+        aliased_set_(aliased_set),
+        in_(graph_->preorder().length()),
+        out_(graph_->preorder().length()),
+        gen_(graph_->preorder().length()),
+        kill_(graph_->preorder().length()),
+        exposed_values_(graph_->preorder().length()),
+        out_values_(graph_->preorder().length()),
+        phis_(5),
+        worklist_(5),
+        congruency_worklist_(6),
+        in_worklist_(NULL),
+        forwarded_(false) {
+    const intptr_t num_blocks = graph_->preorder().length();
+    for (intptr_t i = 0; i < num_blocks; i++) {
+      out_.Add(NULL);
+      gen_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id()));
+      kill_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id()));
+      in_.Add(new(Z) BitVector(Z, aliased_set_->max_place_id()));
+
+      exposed_values_.Add(NULL);
+      out_values_.Add(NULL);
+    }
+  }
+
+  ~LoadOptimizer() {
+    aliased_set_->RollbackAliasedIdentites();
+  }
+
+  Isolate* isolate() const { return graph_->isolate(); }
+  Zone* zone() const { return graph_->zone(); }
+
+  static bool OptimizeGraph(FlowGraph* graph) {
+    ASSERT(FLAG_load_cse);
+    if (FLAG_trace_load_optimization) {
+      FlowGraphPrinter::PrintGraph("Before LoadOptimizer", graph);
+    }
+
+    DirectChainedHashMap<PointerKeyValueTrait<Place> > map;
+    AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeLoads);
+    if ((aliased_set != NULL) && !aliased_set->IsEmpty()) {
+      // If any loads were forwarded return true from Optimize to run load
+      // forwarding again. This will allow to forward chains of loads.
+      // This is especially important for context variables as they are built
+      // as loads from loaded context.
+      // TODO(vegorov): renumber newly discovered congruences during the
+      // forwarding to forward chains without running whole pass twice.
+      LoadOptimizer load_optimizer(graph, aliased_set);
+      return load_optimizer.Optimize();
+    }
+    return false;
+  }
+
+ private:
+  bool Optimize() {
+    ComputeInitialSets();
+    ComputeOutSets();
+    ComputeOutValues();
+    if (graph_->is_licm_allowed()) {
+      MarkLoopInvariantLoads();
+    }
+    ForwardLoads();
+    EmitPhis();
+
+    if (FLAG_trace_load_optimization) {
+      FlowGraphPrinter::PrintGraph("After LoadOptimizer", graph_);
+    }
+
+    return forwarded_;
+  }
+
+  // Compute sets of loads generated and killed by each block.
+  // Additionally compute upwards exposed and generated loads for each block.
+  // Exposed loads are those that can be replaced if a corresponding
+  // reaching load will be found.
+  // Loads that are locally redundant will be replaced as we go through
+  // instructions.
+  void ComputeInitialSets() {
+    for (BlockIterator block_it = graph_->reverse_postorder_iterator();
+         !block_it.Done();
+         block_it.Advance()) {
+      BlockEntryInstr* block = block_it.Current();
+      const intptr_t preorder_number = block->preorder_number();
+
+      BitVector* kill = kill_[preorder_number];
+      BitVector* gen = gen_[preorder_number];
+
+      ZoneGrowableArray<Definition*>* exposed_values = NULL;
+      ZoneGrowableArray<Definition*>* out_values = NULL;
+
+      for (ForwardInstructionIterator instr_it(block);
+           !instr_it.Done();
+           instr_it.Advance()) {
+        Instruction* instr = instr_it.Current();
+
+        bool is_load = false, is_store = false;
+        Place place(instr, &is_load, &is_store);
+
+        BitVector* killed = NULL;
+        if (is_store) {
+          const intptr_t alias_id =
+              aliased_set_->LookupAliasId(place.ToAlias());
+          if (alias_id != AliasedSet::kNoAlias) {
+            killed = aliased_set_->GetKilledSet(alias_id);
+          } else if (!place.IsImmutableField()) {
+            // We encountered unknown alias: this means intrablock load
+            // forwarding refined parameter of this store, for example
+            //
+            //     o   <- alloc()
+            //     a.f <- o
+            //     u   <- a.f
+            //     u.x <- null ;; this store alias is *.x
+            //
+            // after intrablock load forwarding
+            //
+            //     o   <- alloc()
+            //     a.f <- o
+            //     o.x <- null ;; this store alias is o.x
+            //
+            // In this case we fallback to using place id recorded in the
+            // instruction that still points to the old place with a more
+            // generic alias.
+            const intptr_t old_alias_id = aliased_set_->LookupAliasId(
+                aliased_set_->places()[instr->place_id()]->ToAlias());
+            killed = aliased_set_->GetKilledSet(old_alias_id);
+          }
+
+          if (killed != NULL) {
+            kill->AddAll(killed);
+            // There is no need to clear out_values when clearing GEN set
+            // because only those values that are in the GEN set
+            // will ever be used.
+            gen->RemoveAll(killed);
+          }
+
+          // Only forward stores to normal arrays, float64, and simd arrays
+          // to loads because other array stores (intXX/uintXX/float32)
+          // may implicitly convert the value stored.
+          StoreIndexedInstr* array_store = instr->AsStoreIndexed();
+          if ((array_store == NULL) ||
+              (array_store->class_id() == kArrayCid) ||
+              (array_store->class_id() == kTypedDataFloat64ArrayCid) ||
+              (array_store->class_id() == kTypedDataFloat32ArrayCid) ||
+              (array_store->class_id() == kTypedDataFloat32x4ArrayCid)) {
+            Place* canonical_place = aliased_set_->LookupCanonical(&place);
+            if (canonical_place != NULL) {
+              // Store has a corresponding numbered place that might have a
+              // load. Try forwarding stored value to it.
+              gen->Add(canonical_place->id());
+              if (out_values == NULL) out_values = CreateBlockOutValues();
+              (*out_values)[canonical_place->id()] = GetStoredValue(instr);
+            }
+          }
+
+          ASSERT(!instr->IsDefinition() ||
+                 !IsLoadEliminationCandidate(instr->AsDefinition()));
+          continue;
+        } else if (is_load) {
+          // Check if this load needs renumbering because of the intrablock
+          // load forwarding.
+          const Place* canonical = aliased_set_->LookupCanonical(&place);
+          if ((canonical != NULL) &&
+            (canonical->id() != instr->AsDefinition()->place_id())) {
+            instr->AsDefinition()->set_place_id(canonical->id());
+          }
+        }
+
+        // If instruction has effects then kill all loads affected.
+        if (!instr->Effects().IsNone()) {
+          kill->AddAll(aliased_set_->aliased_by_effects());
+          // There is no need to clear out_values when removing values from GEN
+          // set because only those values that are in the GEN set
+          // will ever be used.
+          gen->RemoveAll(aliased_set_->aliased_by_effects());
+          continue;
+        }
+
+        Definition* defn = instr->AsDefinition();
+        if (defn == NULL) {
+          continue;
+        }
+
+        // For object allocation forward initial values of the fields to
+        // subsequent loads. For skip final fields.  Final fields are
+        // initialized in constructor that potentially can be not inlined into
+        // the function that we are currently optimizing. However at the same
+        // time we assume that values of the final fields can be forwarded
+        // across side-effects. If we add 'null' as known values for these
+        // fields here we will incorrectly propagate this null across
+        // constructor invocation.
+        AllocateObjectInstr* alloc = instr->AsAllocateObject();
+        if ((alloc != NULL)) {
+          for (Value* use = alloc->input_use_list();
+               use != NULL;
+               use = use->next_use()) {
+            // Look for all immediate loads from this object.
+            if (use->use_index() != 0) {
+              continue;
+            }
+
+            LoadFieldInstr* load = use->instruction()->AsLoadField();
+            if (load != NULL) {
+              // Found a load. Initialize current value of the field to null for
+              // normal fields, or with type arguments.
+
+              // Forward for all fields for non-escaping objects and only
+              // non-final fields and type arguments for escaping ones.
+              if (aliased_set_->CanBeAliased(alloc) &&
+                  (load->field() != NULL) &&
+                  load->field()->is_final()) {
+                continue;
+              }
+
+              Definition* forward_def = graph_->constant_null();
+              if (alloc->ArgumentCount() > 0) {
+                ASSERT(alloc->ArgumentCount() == 1);
+                intptr_t type_args_offset =
+                    alloc->cls().type_arguments_field_offset();
+                if (load->offset_in_bytes() == type_args_offset) {
+                  forward_def = alloc->PushArgumentAt(0)->value()->definition();
+                }
+              }
+              gen->Add(load->place_id());
+              if (out_values == NULL) out_values = CreateBlockOutValues();
+              (*out_values)[load->place_id()] = forward_def;
+            }
+          }
+          continue;
+        }
+
+        if (!IsLoadEliminationCandidate(defn)) {
+          continue;
+        }
+
+        const intptr_t place_id = defn->place_id();
+        if (gen->Contains(place_id)) {
+          // This is a locally redundant load.
+          ASSERT((out_values != NULL) && ((*out_values)[place_id] != NULL));
+
+          Definition* replacement = (*out_values)[place_id];
+          graph_->EnsureSSATempIndex(defn, replacement);
+          if (FLAG_trace_optimization) {
+            THR_Print("Replacing load v%" Pd " with v%" Pd "\n",
+                      defn->ssa_temp_index(),
+                      replacement->ssa_temp_index());
+          }
+
+          defn->ReplaceUsesWith(replacement);
+          instr_it.RemoveCurrentFromGraph();
+          forwarded_ = true;
+          continue;
+        } else if (!kill->Contains(place_id)) {
+          // This is an exposed load: it is the first representative of a
+          // given expression id and it is not killed on the path from
+          // the block entry.
+          if (exposed_values == NULL) {
+            static const intptr_t kMaxExposedValuesInitialSize = 5;
+            exposed_values = new(Z) ZoneGrowableArray<Definition*>(
+                Utils::Minimum(kMaxExposedValuesInitialSize,
+                               aliased_set_->max_place_id()));
+          }
+
+          exposed_values->Add(defn);
+        }
+
+        gen->Add(place_id);
+
+        if (out_values == NULL) out_values = CreateBlockOutValues();
+        (*out_values)[place_id] = defn;
+      }
+
+      exposed_values_[preorder_number] = exposed_values;
+      out_values_[preorder_number] = out_values;
+    }
+  }
+
+  static void PerformPhiMoves(PhiPlaceMoves::MovesList phi_moves,
+                              BitVector* out,
+                              BitVector* forwarded_loads) {
+    forwarded_loads->Clear();
+
+    for (intptr_t i = 0; i < phi_moves->length(); i++) {
+      const intptr_t from = (*phi_moves)[i].from();
+      const intptr_t to = (*phi_moves)[i].to();
+      if (from == to) continue;
+
+      if (out->Contains(from)) {
+        forwarded_loads->Add(to);
+      }
+    }
+
+    for (intptr_t i = 0; i < phi_moves->length(); i++) {
+      const intptr_t from = (*phi_moves)[i].from();
+      const intptr_t to = (*phi_moves)[i].to();
+      if (from == to) continue;
+
+      out->Remove(to);
+    }
+
+    out->AddAll(forwarded_loads);
+  }
+
+  // Compute OUT sets by propagating them iteratively until fix point
+  // is reached.
+  void ComputeOutSets() {
+    BitVector* temp = new(Z) BitVector(Z, aliased_set_->max_place_id());
+    BitVector* forwarded_loads =
+        new(Z) BitVector(Z, aliased_set_->max_place_id());
+    BitVector* temp_out = new(Z) BitVector(Z, aliased_set_->max_place_id());
+
+    bool changed = true;
+    while (changed) {
+      changed = false;
+
+      for (BlockIterator block_it = graph_->reverse_postorder_iterator();
+           !block_it.Done();
+           block_it.Advance()) {
+        BlockEntryInstr* block = block_it.Current();
+
+        const intptr_t preorder_number = block->preorder_number();
+
+        BitVector* block_in = in_[preorder_number];
+        BitVector* block_out = out_[preorder_number];
+        BitVector* block_kill = kill_[preorder_number];
+        BitVector* block_gen = gen_[preorder_number];
+
+        // Compute block_in as the intersection of all out(p) where p
+        // is a predecessor of the current block.
+        if (block->IsGraphEntry()) {
+          temp->Clear();
+        } else {
+          temp->SetAll();
+          ASSERT(block->PredecessorCount() > 0);
+          for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
+            BlockEntryInstr* pred = block->PredecessorAt(i);
+            BitVector* pred_out = out_[pred->preorder_number()];
+            if (pred_out == NULL) continue;
+            PhiPlaceMoves::MovesList phi_moves =
+                aliased_set_->phi_moves()->GetOutgoingMoves(pred);
+            if (phi_moves != NULL) {
+              // If there are phi moves, perform intersection with
+              // a copy of pred_out where the phi moves are applied.
+              temp_out->CopyFrom(pred_out);
+              PerformPhiMoves(phi_moves, temp_out, forwarded_loads);
+              pred_out = temp_out;
+            }
+            temp->Intersect(pred_out);
+          }
+        }
+
+        if (!temp->Equals(*block_in) || (block_out == NULL)) {
+          // If IN set has changed propagate the change to OUT set.
+          block_in->CopyFrom(temp);
+
+          temp->RemoveAll(block_kill);
+          temp->AddAll(block_gen);
+
+          if ((block_out == NULL) || !block_out->Equals(*temp)) {
+            if (block_out == NULL) {
+              block_out = out_[preorder_number] =
+                  new(Z) BitVector(Z, aliased_set_->max_place_id());
+            }
+            block_out->CopyFrom(temp);
+            changed = true;
+          }
+        }
+      }
+    }
+  }
+
+  // Compute out_values mappings by propagating them in reverse postorder once
+  // through the graph. Generate phis on back edges where eager merge is
+  // impossible.
+  // No replacement is done at this point and thus any out_value[place_id] is
+  // changed at most once: from NULL to an actual value.
+  // When merging incoming loads we might need to create a phi.
+  // These phis are not inserted at the graph immediately because some of them
+  // might become redundant after load forwarding is done.
+  void ComputeOutValues() {
+    GrowableArray<PhiInstr*> pending_phis(5);
+    ZoneGrowableArray<Definition*>* temp_forwarded_values = NULL;
+
+    for (BlockIterator block_it = graph_->reverse_postorder_iterator();
+         !block_it.Done();
+         block_it.Advance()) {
+      BlockEntryInstr* block = block_it.Current();
+
+      const bool can_merge_eagerly = CanMergeEagerly(block);
+
+      const intptr_t preorder_number = block->preorder_number();
+
+      ZoneGrowableArray<Definition*>* block_out_values =
+          out_values_[preorder_number];
+
+
+      // If OUT set has changed then we have new values available out of
+      // the block. Compute these values creating phi where necessary.
+      for (BitVector::Iterator it(out_[preorder_number]);
+           !it.Done();
+           it.Advance()) {
+        const intptr_t place_id = it.Current();
+
+        if (block_out_values == NULL) {
+          out_values_[preorder_number] = block_out_values =
+              CreateBlockOutValues();
+        }
+
+        if ((*block_out_values)[place_id] == NULL) {
+          ASSERT(block->PredecessorCount() > 0);
+          Definition* in_value = can_merge_eagerly ?
+              MergeIncomingValues(block, place_id) : NULL;
+          if ((in_value == NULL) &&
+              (in_[preorder_number]->Contains(place_id))) {
+            PhiInstr* phi = new(Z) PhiInstr(block->AsJoinEntry(),
+                                            block->PredecessorCount());
+            phi->set_place_id(place_id);
+            pending_phis.Add(phi);
+            in_value = phi;
+          }
+          (*block_out_values)[place_id] = in_value;
+        }
+      }
+
+      // If the block has outgoing phi moves perform them. Use temporary list
+      // of values to ensure that cyclic moves are performed correctly.
+      PhiPlaceMoves::MovesList phi_moves =
+          aliased_set_->phi_moves()->GetOutgoingMoves(block);
+      if ((phi_moves != NULL) && (block_out_values != NULL)) {
+        if (temp_forwarded_values == NULL) {
+          temp_forwarded_values = CreateBlockOutValues();
+        }
+
+        for (intptr_t i = 0; i < phi_moves->length(); i++) {
+          const intptr_t from = (*phi_moves)[i].from();
+          const intptr_t to = (*phi_moves)[i].to();
+          if (from == to) continue;
+
+          (*temp_forwarded_values)[to] = (*block_out_values)[from];
+        }
+
+        for (intptr_t i = 0; i < phi_moves->length(); i++) {
+          const intptr_t from = (*phi_moves)[i].from();
+          const intptr_t to = (*phi_moves)[i].to();
+          if (from == to) continue;
+
+          (*block_out_values)[to] = (*temp_forwarded_values)[to];
+        }
+      }
+
+      if (FLAG_trace_load_optimization) {
+        THR_Print("B%" Pd "\n", block->block_id());
+        THR_Print("  IN: ");
+        aliased_set_->PrintSet(in_[preorder_number]);
+        THR_Print("\n");
+
+        THR_Print("  KILL: ");
+        aliased_set_->PrintSet(kill_[preorder_number]);
+        THR_Print("\n");
+
+        THR_Print("  OUT: ");
+        aliased_set_->PrintSet(out_[preorder_number]);
+        THR_Print("\n");
+      }
+    }
+
+    // All blocks were visited. Fill pending phis with inputs
+    // that flow on back edges.
+    for (intptr_t i = 0; i < pending_phis.length(); i++) {
+      FillPhiInputs(pending_phis[i]);
+    }
+  }
+
+  bool CanMergeEagerly(BlockEntryInstr* block) {
+    for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
+      BlockEntryInstr* pred = block->PredecessorAt(i);
+      if (pred->postorder_number() < block->postorder_number()) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  void MarkLoopInvariantLoads() {
+    const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
+        graph_->LoopHeaders();
+
+    ZoneGrowableArray<BitVector*>* invariant_loads =
+        new(Z) ZoneGrowableArray<BitVector*>(loop_headers.length());
+
+    for (intptr_t i = 0; i < loop_headers.length(); i++) {
+      BlockEntryInstr* header = loop_headers[i];
+      BlockEntryInstr* pre_header = header->ImmediateDominator();
+      if (pre_header == NULL) {
+        invariant_loads->Add(NULL);
+        continue;
+      }
+
+      BitVector* loop_gen = new(Z) BitVector(Z, aliased_set_->max_place_id());
+      for (BitVector::Iterator loop_it(header->loop_info());
+           !loop_it.Done();
+           loop_it.Advance()) {
+        const intptr_t preorder_number = loop_it.Current();
+        loop_gen->AddAll(gen_[preorder_number]);
+      }
+
+      for (BitVector::Iterator loop_it(header->loop_info());
+           !loop_it.Done();
+           loop_it.Advance()) {
+        const intptr_t preorder_number = loop_it.Current();
+        loop_gen->RemoveAll(kill_[preorder_number]);
+      }
+
+      if (FLAG_trace_optimization) {
+        for (BitVector::Iterator it(loop_gen); !it.Done(); it.Advance()) {
+          THR_Print("place %s is loop invariant for B%" Pd "\n",
+                    aliased_set_->places()[it.Current()]->ToCString(),
+                    header->block_id());
+        }
+      }
+
+      invariant_loads->Add(loop_gen);
+    }
+
+    graph_->set_loop_invariant_loads(invariant_loads);
+  }
+
+  // Compute incoming value for the given expression id.
+  // Will create a phi if different values are incoming from multiple
+  // predecessors.
+  Definition* MergeIncomingValues(BlockEntryInstr* block, intptr_t place_id) {
+    // First check if the same value is coming in from all predecessors.
+    static Definition* const kDifferentValuesMarker =
+        reinterpret_cast<Definition*>(-1);
+    Definition* incoming = NULL;
+    for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
+      BlockEntryInstr* pred = block->PredecessorAt(i);
+      ZoneGrowableArray<Definition*>* pred_out_values =
+          out_values_[pred->preorder_number()];
+      if ((pred_out_values == NULL) || ((*pred_out_values)[place_id] == NULL)) {
+        return NULL;
+      } else if (incoming == NULL) {
+        incoming = (*pred_out_values)[place_id];
+      } else if (incoming != (*pred_out_values)[place_id]) {
+        incoming = kDifferentValuesMarker;
+      }
+    }
+
+    if (incoming != kDifferentValuesMarker) {
+      ASSERT(incoming != NULL);
+      return incoming;
+    }
+
+    // Incoming values are different. Phi is required to merge.
+    PhiInstr* phi = new(Z) PhiInstr(
+        block->AsJoinEntry(), block->PredecessorCount());
+    phi->set_place_id(place_id);
+    FillPhiInputs(phi);
+    return phi;
+  }
+
+  void FillPhiInputs(PhiInstr* phi) {
+    BlockEntryInstr* block = phi->GetBlock();
+    const intptr_t place_id = phi->place_id();
+
+    for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
+      BlockEntryInstr* pred = block->PredecessorAt(i);
+      ZoneGrowableArray<Definition*>* pred_out_values =
+          out_values_[pred->preorder_number()];
+      ASSERT((*pred_out_values)[place_id] != NULL);
+
+      // Sets of outgoing values are not linked into use lists so
+      // they might contain values that were replaced and removed
+      // from the graph by this iteration.
+      // To prevent using them we additionally mark definitions themselves
+      // as replaced and store a pointer to the replacement.
+      Definition* replacement = (*pred_out_values)[place_id]->Replacement();
+      Value* input = new(Z) Value(replacement);
+      phi->SetInputAt(i, input);
+      replacement->AddInputUse(input);
+    }
+
+    graph_->AllocateSSAIndexes(phi);
+    phis_.Add(phi);  // Postpone phi insertion until after load forwarding.
+
+    if (FLAG_support_il_printer && FLAG_trace_load_optimization) {
+      THR_Print("created pending phi %s for %s at B%" Pd "\n",
+                phi->ToCString(),
+                aliased_set_->places()[place_id]->ToCString(),
+                block->block_id());
+    }
+  }
+
+  // Iterate over basic blocks and replace exposed loads with incoming
+  // values.
+  void ForwardLoads() {
+    for (BlockIterator block_it = graph_->reverse_postorder_iterator();
+         !block_it.Done();
+         block_it.Advance()) {
+      BlockEntryInstr* block = block_it.Current();
+
+      ZoneGrowableArray<Definition*>* loads =
+          exposed_values_[block->preorder_number()];
+      if (loads == NULL) continue;  // No exposed loads.
+
+      BitVector* in = in_[block->preorder_number()];
+
+      for (intptr_t i = 0; i < loads->length(); i++) {
+        Definition* load = (*loads)[i];
+        if (!in->Contains(load->place_id())) continue;  // No incoming value.
+
+        Definition* replacement = MergeIncomingValues(block, load->place_id());
+        ASSERT(replacement != NULL);
+
+        // Sets of outgoing values are not linked into use lists so
+        // they might contain values that were replace and removed
+        // from the graph by this iteration.
+        // To prevent using them we additionally mark definitions themselves
+        // as replaced and store a pointer to the replacement.
+        replacement = replacement->Replacement();
+
+        if (load != replacement) {
+          graph_->EnsureSSATempIndex(load, replacement);
+
+          if (FLAG_trace_optimization) {
+            THR_Print("Replacing load v%" Pd " with v%" Pd "\n",
+                      load->ssa_temp_index(),
+                      replacement->ssa_temp_index());
+          }
+
+          load->ReplaceUsesWith(replacement);
+          load->RemoveFromGraph();
+          load->SetReplacement(replacement);
+          forwarded_ = true;
+        }
+      }
+    }
+  }
+
+  // Check if the given phi take the same value on all code paths.
+  // Eliminate it as redundant if this is the case.
+  // When analyzing phi operands assumes that only generated during
+  // this load phase can be redundant. They can be distinguished because
+  // they are not marked alive.
+  // TODO(vegorov): move this into a separate phase over all phis.
+  bool EliminateRedundantPhi(PhiInstr* phi) {
+    Definition* value = NULL;  // Possible value of this phi.
+
+    worklist_.Clear();
+    if (in_worklist_ == NULL) {
+      in_worklist_ = new(Z) BitVector(Z, graph_->current_ssa_temp_index());
+    } else {
+      in_worklist_->Clear();
+    }
+
+    worklist_.Add(phi);
+    in_worklist_->Add(phi->ssa_temp_index());
+
+    for (intptr_t i = 0; i < worklist_.length(); i++) {
+      PhiInstr* phi = worklist_[i];
+
+      for (intptr_t i = 0; i < phi->InputCount(); i++) {
+        Definition* input = phi->InputAt(i)->definition();
+        if (input == phi) continue;
+
+        PhiInstr* phi_input = input->AsPhi();
+        if ((phi_input != NULL) && !phi_input->is_alive()) {
+          if (!in_worklist_->Contains(phi_input->ssa_temp_index())) {
+            worklist_.Add(phi_input);
+            in_worklist_->Add(phi_input->ssa_temp_index());
+          }
+          continue;
+        }
+
+        if (value == NULL) {
+          value = input;
+        } else if (value != input) {
+          return false;  // This phi is not redundant.
+        }
+      }
+    }
+
+    // All phis in the worklist are redundant and have the same computed
+    // value on all code paths.
+    ASSERT(value != NULL);
+    for (intptr_t i = 0; i < worklist_.length(); i++) {
+      worklist_[i]->ReplaceUsesWith(value);
+    }
+
+    return true;
+  }
+
+  // Returns true if definitions are congruent assuming their inputs
+  // are congruent.
+  bool CanBeCongruent(Definition* a, Definition* b) {
+    return (a->tag() == b->tag()) &&
+       ((a->IsPhi() && (a->GetBlock() == b->GetBlock())) ||
+        (a->AllowsCSE() && a->Dependencies().IsNone() &&
+         a->AttributesEqual(b)));
+  }
+
+  // Given two definitions check if they are congruent under assumption that
+  // their inputs will be proven congruent. If they are - add them to the
+  // worklist to check their inputs' congruency.
+  // Returns true if pair was added to the worklist or is already in the
+  // worklist and false if a and b are not congruent.
+  bool AddPairToCongruencyWorklist(Definition* a, Definition* b) {
+    if (!CanBeCongruent(a, b)) {
+      return false;
+    }
+
+    // If a is already in the worklist check if it is being compared to b.
+    // Give up if it is not.
+    if (in_worklist_->Contains(a->ssa_temp_index())) {
+      for (intptr_t i = 0; i < congruency_worklist_.length(); i += 2) {
+        if (a == congruency_worklist_[i]) {
+          return (b == congruency_worklist_[i + 1]);
+        }
+      }
+      UNREACHABLE();
+    } else if (in_worklist_->Contains(b->ssa_temp_index())) {
+      return AddPairToCongruencyWorklist(b, a);
+    }
+
+    congruency_worklist_.Add(a);
+    congruency_worklist_.Add(b);
+    in_worklist_->Add(a->ssa_temp_index());
+    return true;
+  }
+
+  bool AreInputsCongruent(Definition* a, Definition* b) {
+    ASSERT(a->tag() == b->tag());
+    ASSERT(a->InputCount() == b->InputCount());
+    for (intptr_t j = 0; j < a->InputCount(); j++) {
+      Definition* inputA = a->InputAt(j)->definition();
+      Definition* inputB = b->InputAt(j)->definition();
+
+      if (inputA != inputB) {
+        if (!AddPairToCongruencyWorklist(inputA, inputB)) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  // Returns true if instruction dom dominates instruction other.
+  static bool Dominates(Instruction* dom, Instruction* other) {
+    BlockEntryInstr* dom_block = dom->GetBlock();
+    BlockEntryInstr* other_block = other->GetBlock();
+
+    if (dom_block == other_block) {
+      for (Instruction* current = dom->next();
+           current != NULL;
+           current = current->next()) {
+        if (current == other) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    return dom_block->Dominates(other_block);
+  }
+
+  // Replace the given phi with another if they are congruent.
+  // Returns true if succeeds.
+  bool ReplacePhiWith(PhiInstr* phi, PhiInstr* replacement) {
+    ASSERT(phi->InputCount() == replacement->InputCount());
+    ASSERT(phi->block() == replacement->block());
+
+    congruency_worklist_.Clear();
+    if (in_worklist_ == NULL) {
+      in_worklist_ = new(Z) BitVector(Z, graph_->current_ssa_temp_index());
+    } else {
+      in_worklist_->Clear();
+    }
+
+    // During the comparison worklist contains pairs of definitions to be
+    // compared.
+    if (!AddPairToCongruencyWorklist(phi, replacement)) {
+      return false;
+    }
+
+    // Process the worklist. It might grow during each comparison step.
+    for (intptr_t i = 0; i < congruency_worklist_.length(); i += 2) {
+      if (!AreInputsCongruent(congruency_worklist_[i],
+                              congruency_worklist_[i + 1])) {
+        return false;
+      }
+    }
+
+    // At this point worklist contains pairs of congruent definitions.
+    // Replace the one member of the pair with another maintaining proper
+    // domination relation between definitions and uses.
+    for (intptr_t i = 0; i < congruency_worklist_.length(); i += 2) {
+      Definition* a = congruency_worklist_[i];
+      Definition* b = congruency_worklist_[i + 1];
+
+      // If these definitions are not phis then we need to pick up one
+      // that dominates another as the replacement: if a dominates b swap them.
+      // Note: both a and b are used as a phi input at the same block B which
+      // means a dominates B and b dominates B, which guarantees that either
+      // a dominates b or b dominates a.
+      if (!a->IsPhi()) {
+        if (Dominates(a, b)) {
+          Definition* t = a;
+          a = b;
+          b = t;
+        }
+        ASSERT(Dominates(b, a));
+      }
+
+      if (FLAG_support_il_printer && FLAG_trace_load_optimization) {
+        THR_Print("Replacing %s with congruent %s\n",
+                  a->ToCString(),
+                  b->ToCString());
+      }
+
+      a->ReplaceUsesWith(b);
+      if (a->IsPhi()) {
+        // We might be replacing a phi introduced by the load forwarding
+        // that is not inserted in the graph yet.
+        ASSERT(b->IsPhi());
+        PhiInstr* phi_a = a->AsPhi();
+        if (phi_a->is_alive()) {
+          phi_a->mark_dead();
+          phi_a->block()->RemovePhi(phi_a);
+          phi_a->UnuseAllInputs();
+        }
+      } else {
+        a->RemoveFromGraph();
+      }
+    }
+
+    return true;
+  }
+
+  // Insert the given phi into the graph. Attempt to find an equal one in the
+  // target block first.
+  // Returns true if the phi was inserted and false if it was replaced.
+  bool EmitPhi(PhiInstr* phi) {
+    for (PhiIterator it(phi->block()); !it.Done(); it.Advance()) {
+      if (ReplacePhiWith(phi, it.Current())) {
+        return false;
+      }
+    }
+
+    phi->mark_alive();
+    phi->block()->InsertPhi(phi);
+    return true;
+  }
+
+  // Phis have not yet been inserted into the graph but they have uses of
+  // their inputs.  Insert the non-redundant ones and clear the input uses
+  // of the redundant ones.
+  void EmitPhis() {
+    // First eliminate all redundant phis.
+    for (intptr_t i = 0; i < phis_.length(); i++) {
+      PhiInstr* phi = phis_[i];
+      if (!phi->HasUses() || EliminateRedundantPhi(phi)) {
+        phi->UnuseAllInputs();
+        phis_[i] = NULL;
+      }
+    }
+
+    // Now emit phis or replace them with equal phis already present in the
+    // graph.
+    for (intptr_t i = 0; i < phis_.length(); i++) {
+      PhiInstr* phi = phis_[i];
+      if ((phi != NULL) && (!phi->HasUses() || !EmitPhi(phi))) {
+        phi->UnuseAllInputs();
+      }
+    }
+  }
+
+  ZoneGrowableArray<Definition*>* CreateBlockOutValues() {
+    ZoneGrowableArray<Definition*>* out =
+        new(Z) ZoneGrowableArray<Definition*>(aliased_set_->max_place_id());
+    for (intptr_t i = 0; i < aliased_set_->max_place_id(); i++) {
+      out->Add(NULL);
+    }
+    return out;
+  }
+
+  FlowGraph* graph_;
+  DirectChainedHashMap<PointerKeyValueTrait<Place> >* map_;
+
+  // Mapping between field offsets in words and expression ids of loads from
+  // that offset.
+  AliasedSet* aliased_set_;
+
+  // Per block sets of expression ids for loads that are: incoming (available
+  // on the entry), outgoing (available on the exit), generated and killed.
+  GrowableArray<BitVector*> in_;
+  GrowableArray<BitVector*> out_;
+  GrowableArray<BitVector*> gen_;
+  GrowableArray<BitVector*> kill_;
+
+  // Per block list of upwards exposed loads.
+  GrowableArray<ZoneGrowableArray<Definition*>*> exposed_values_;
+
+  // Per block mappings between expression ids and outgoing definitions that
+  // represent those ids.
+  GrowableArray<ZoneGrowableArray<Definition*>*> out_values_;
+
+  // List of phis generated during ComputeOutValues and ForwardLoads.
+  // Some of these phis might be redundant and thus a separate pass is
+  // needed to emit only non-redundant ones.
+  GrowableArray<PhiInstr*> phis_;
+
+  // Auxiliary worklist used by redundant phi elimination.
+  GrowableArray<PhiInstr*> worklist_;
+  GrowableArray<Definition*> congruency_worklist_;
+  BitVector* in_worklist_;
+
+
+  // True if any load was eliminated.
+  bool forwarded_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoadOptimizer);
+};
+
+
+bool DominatorBasedCSE::Optimize(FlowGraph* graph) {
+  bool changed = false;
+  if (FLAG_load_cse) {
+    changed = LoadOptimizer::OptimizeGraph(graph) || changed;
+  }
+
+  CSEInstructionMap map;
+  changed = OptimizeRecursive(graph, graph->graph_entry(), &map) || changed;
+
+  return changed;
+}
+
+
+bool DominatorBasedCSE::OptimizeRecursive(
+    FlowGraph* graph,
+    BlockEntryInstr* block,
+    CSEInstructionMap* map) {
+  bool changed = false;
+  for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+    Instruction* current = it.Current();
+    if (current->AllowsCSE()) {
+      Instruction* replacement = map->Lookup(current);
+      if ((replacement != NULL) &&
+          graph->block_effects()->IsAvailableAt(replacement, block)) {
+        // Replace current with lookup result.
+        graph->ReplaceCurrentInstruction(&it, current, replacement);
+        changed = true;
+        continue;
+      }
+
+      // For simplicity we assume that instruction either does not depend on
+      // anything or does not affect anything. If this is not the case then
+      // we should first remove affected instructions from the map and
+      // then add instruction to the map so that it does not kill itself.
+      ASSERT(current->Effects().IsNone() || current->Dependencies().IsNone());
+      map->Insert(current);
+    }
+
+    map->RemoveAffected(current->Effects());
+  }
+
+  // Process children in the dominator tree recursively.
+  intptr_t num_children = block->dominated_blocks().length();
+  for (intptr_t i = 0; i < num_children; ++i) {
+    BlockEntryInstr* child = block->dominated_blocks()[i];
+    if (i  < num_children - 1) {
+      // Copy map.
+      CSEInstructionMap child_map(*map);
+      changed = OptimizeRecursive(graph, child, &child_map) || changed;
+    } else {
+      // Reuse map for the last child.
+      changed = OptimizeRecursive(graph, child, map) || changed;
+    }
+  }
+  return changed;
+}
+
+
+class StoreOptimizer : public LivenessAnalysis {
+ public:
+  StoreOptimizer(FlowGraph* graph,
+                 AliasedSet* aliased_set,
+                 DirectChainedHashMap<PointerKeyValueTrait<Place> >* map)
+      : LivenessAnalysis(aliased_set->max_place_id(), graph->postorder()),
+        graph_(graph),
+        map_(map),
+        aliased_set_(aliased_set),
+        exposed_stores_(graph_->postorder().length()) {
+    const intptr_t num_blocks = graph_->postorder().length();
+    for (intptr_t i = 0; i < num_blocks; i++) {
+      exposed_stores_.Add(NULL);
+    }
+  }
+
+  static void OptimizeGraph(FlowGraph* graph) {
+    ASSERT(FLAG_load_cse);
+    if (FLAG_trace_load_optimization) {
+      FlowGraphPrinter::PrintGraph("Before StoreOptimizer", graph);
+    }
+
+    DirectChainedHashMap<PointerKeyValueTrait<Place> > map;
+    AliasedSet* aliased_set = NumberPlaces(graph, &map, kOptimizeStores);
+    if ((aliased_set != NULL) && !aliased_set->IsEmpty()) {
+      StoreOptimizer store_optimizer(graph, aliased_set, &map);
+      store_optimizer.Optimize();
+    }
+  }
+
+ private:
+  void Optimize() {
+    Analyze();
+    if (FLAG_trace_load_optimization) {
+      Dump();
+    }
+    EliminateDeadStores();
+    if (FLAG_trace_load_optimization) {
+      FlowGraphPrinter::PrintGraph("After StoreOptimizer", graph_);
+    }
+  }
+
+  bool CanEliminateStore(Instruction* instr) {
+    switch (instr->tag()) {
+      case Instruction::kStoreInstanceField: {
+        StoreInstanceFieldInstr* store_instance = instr->AsStoreInstanceField();
+        // Can't eliminate stores that initialize fields.
+        return !(store_instance->is_potential_unboxed_initialization() ||
+                 store_instance->is_object_reference_initialization());
+      }
+      case Instruction::kStoreIndexed:
+      case Instruction::kStoreStaticField:
+        return true;
+      default:
+        UNREACHABLE();
+        return false;
+    }
+  }
+
+  virtual void ComputeInitialSets() {
+    Zone* zone = graph_->zone();
+    BitVector* all_places = new(zone) BitVector(zone,
+        aliased_set_->max_place_id());
+    all_places->SetAll();
+    for (BlockIterator block_it = graph_->postorder_iterator();
+         !block_it.Done();
+         block_it.Advance()) {
+      BlockEntryInstr* block = block_it.Current();
+      const intptr_t postorder_number = block->postorder_number();
+
+      BitVector* kill = kill_[postorder_number];
+      BitVector* live_in = live_in_[postorder_number];
+      BitVector* live_out = live_out_[postorder_number];
+
+      ZoneGrowableArray<Instruction*>* exposed_stores = NULL;
+
+      // Iterate backwards starting at the last instruction.
+      for (BackwardInstructionIterator instr_it(block);
+           !instr_it.Done();
+           instr_it.Advance()) {
+        Instruction* instr = instr_it.Current();
+
+        bool is_load = false;
+        bool is_store = false;
+        Place place(instr, &is_load, &is_store);
+        if (place.IsImmutableField()) {
+          // Loads/stores of final fields do not participate.
+          continue;
+        }
+
+        // Handle stores.
+        if (is_store) {
+          if (kill->Contains(instr->place_id())) {
+            if (!live_in->Contains(instr->place_id()) &&
+                CanEliminateStore(instr)) {
+              if (FLAG_trace_optimization) {
+                THR_Print(
+                    "Removing dead store to place %" Pd " in block B%" Pd "\n",
+                    instr->place_id(), block->block_id());
+              }
+              instr_it.RemoveCurrentFromGraph();
+            }
+          } else if (!live_in->Contains(instr->place_id())) {
+            // Mark this store as down-ward exposed: They are the only
+            // candidates for the global store elimination.
+            if (exposed_stores == NULL) {
+              const intptr_t kMaxExposedStoresInitialSize = 5;
+              exposed_stores = new(zone) ZoneGrowableArray<Instruction*>(
+                  Utils::Minimum(kMaxExposedStoresInitialSize,
+                                 aliased_set_->max_place_id()));
+            }
+            exposed_stores->Add(instr);
+          }
+          // Interfering stores kill only loads from the same place.
+          kill->Add(instr->place_id());
+          live_in->Remove(instr->place_id());
+          continue;
+        }
+
+        // Handle side effects, deoptimization and function return.
+        if (!instr->Effects().IsNone() ||
+            instr->CanDeoptimize() ||
+            instr->IsThrow() ||
+            instr->IsReThrow() ||
+            instr->IsReturn()) {
+          // Instructions that return from the function, instructions with side
+          // effects and instructions that can deoptimize are considered as
+          // loads from all places.
+          live_in->CopyFrom(all_places);
+          if (instr->IsThrow() || instr->IsReThrow() || instr->IsReturn()) {
+            // Initialize live-out for exit blocks since it won't be computed
+            // otherwise during the fixed point iteration.
+            live_out->CopyFrom(all_places);
+          }
+          continue;
+        }
+
+        // Handle loads.
+        Definition* defn = instr->AsDefinition();
+        if ((defn != NULL) && IsLoadEliminationCandidate(defn)) {
+          const intptr_t alias = aliased_set_->LookupAliasId(place.ToAlias());
+          live_in->AddAll(aliased_set_->GetKilledSet(alias));
+          continue;
+        }
+      }
+      exposed_stores_[postorder_number] = exposed_stores;
+    }
+    if (FLAG_trace_load_optimization) {
+      Dump();
+      THR_Print("---\n");
+    }
+  }
+
+  void EliminateDeadStores() {
+    // Iteration order does not matter here.
+    for (BlockIterator block_it = graph_->postorder_iterator();
+         !block_it.Done();
+         block_it.Advance()) {
+      BlockEntryInstr* block = block_it.Current();
+      const intptr_t postorder_number = block->postorder_number();
+
+      BitVector* live_out = live_out_[postorder_number];
+
+      ZoneGrowableArray<Instruction*>* exposed_stores =
+        exposed_stores_[postorder_number];
+      if (exposed_stores == NULL) continue;  // No exposed stores.
+
+      // Iterate over candidate stores.
+      for (intptr_t i = 0; i < exposed_stores->length(); ++i) {
+        Instruction* instr = (*exposed_stores)[i];
+        bool is_load = false;
+        bool is_store = false;
+        Place place(instr, &is_load, &is_store);
+        ASSERT(!is_load && is_store);
+        if (place.IsImmutableField()) {
+          // Final field do not participate in dead store elimination.
+          continue;
+        }
+        // Eliminate a downward exposed store if the corresponding place is not
+        // in live-out.
+        if (!live_out->Contains(instr->place_id()) &&
+            CanEliminateStore(instr)) {
+          if (FLAG_trace_optimization) {
+            THR_Print("Removing dead store to place %" Pd " block B%" Pd "\n",
+                      instr->place_id(), block->block_id());
+          }
+          instr->RemoveFromGraph(/* ignored */ false);
+        }
+      }
+    }
+  }
+
+  FlowGraph* graph_;
+  DirectChainedHashMap<PointerKeyValueTrait<Place> >* map_;
+
+  // Mapping between field offsets in words and expression ids of loads from
+  // that offset.
+  AliasedSet* aliased_set_;
+
+  // Per block list of downward exposed stores.
+  GrowableArray<ZoneGrowableArray<Instruction*>*> exposed_stores_;
+
+  DISALLOW_COPY_AND_ASSIGN(StoreOptimizer);
+};
+
+
+void DeadStoreElimination::Optimize(FlowGraph* graph) {
+  if (FLAG_dead_store_elimination) {
+    StoreOptimizer::OptimizeGraph(graph);
+  }
+}
+
+
+enum SafeUseCheck { kOptimisticCheck, kStrictCheck };
+
+// Check if the use is safe for allocation sinking. Allocation sinking
+// candidates can only be used at store instructions:
+//
+//     - any store into the allocation candidate itself is unconditionally safe
+//       as it just changes the rematerialization state of this candidate;
+//     - store into another object is only safe if another object is allocation
+//       candidate.
+//
+// We use a simple fix-point algorithm to discover the set of valid candidates
+// (see CollectCandidates method), that's why this IsSafeUse can operate in two
+// modes:
+//
+//     - optimistic, when every allocation is assumed to be an allocation
+//       sinking candidate;
+//     - strict, when only marked allocations are assumed to be allocation
+//       sinking candidates.
+//
+// Fix-point algorithm in CollectCandiates first collects a set of allocations
+// optimistically and then checks each collected candidate strictly and unmarks
+// invalid candidates transitively until only strictly valid ones remain.
+static bool IsSafeUse(Value* use, SafeUseCheck check_type) {
+  if (use->instruction()->IsMaterializeObject()) {
+    return true;
+  }
+
+  StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
+  if (store != NULL) {
+    if (use == store->value()) {
+      Definition* instance = store->instance()->definition();
+      return instance->IsAllocateObject() &&
+          ((check_type == kOptimisticCheck) ||
+           instance->Identity().IsAllocationSinkingCandidate());
+    }
+    return true;
+  }
+
+  return false;
+}
+
+
+// Right now we are attempting to sink allocation only into
+// deoptimization exit. So candidate should only be used in StoreInstanceField
+// instructions that write into fields of the allocated object.
+// We do not support materialization of the object that has type arguments.
+static bool IsAllocationSinkingCandidate(Definition* alloc,
+                                         SafeUseCheck check_type) {
+  for (Value* use = alloc->input_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    if (!IsSafeUse(use, check_type)) {
+      if (FLAG_support_il_printer && FLAG_trace_optimization) {
+        THR_Print("use of %s at %s is unsafe for allocation sinking\n",
+                  alloc->ToCString(),
+                  use->instruction()->ToCString());
+      }
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+// If the given use is a store into an object then return an object we are
+// storing into.
+static Definition* StoreInto(Value* use) {
+  StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
+  if (store != NULL) {
+    return store->instance()->definition();
+  }
+
+  return NULL;
+}
+
+
+// Remove the given allocation from the graph. It is not observable.
+// If deoptimization occurs the object will be materialized.
+void AllocationSinking::EliminateAllocation(Definition* alloc) {
+  ASSERT(IsAllocationSinkingCandidate(alloc, kStrictCheck));
+
+  if (FLAG_trace_optimization) {
+    THR_Print("removing allocation from the graph: v%" Pd "\n",
+              alloc->ssa_temp_index());
+  }
+
+  // As an allocation sinking candidate it is only used in stores to its own
+  // fields. Remove these stores.
+  for (Value* use = alloc->input_use_list();
+       use != NULL;
+       use = alloc->input_use_list()) {
+    use->instruction()->RemoveFromGraph();
+  }
+
+  // There should be no environment uses. The pass replaced them with
+  // MaterializeObject instructions.
+#ifdef DEBUG
+  for (Value* use = alloc->env_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    ASSERT(use->instruction()->IsMaterializeObject());
+  }
+#endif
+  ASSERT(alloc->input_use_list() == NULL);
+  alloc->RemoveFromGraph();
+  if (alloc->ArgumentCount() > 0) {
+    ASSERT(alloc->ArgumentCount() == 1);
+    for (intptr_t i = 0; i < alloc->ArgumentCount(); ++i) {
+      alloc->PushArgumentAt(i)->RemoveFromGraph();
+    }
+  }
+}
+
+
+// Find allocation instructions that can be potentially eliminated and
+// rematerialized at deoptimization exits if needed. See IsSafeUse
+// for the description of algorithm used below.
+void AllocationSinking::CollectCandidates() {
+  // Optimistically collect all potential candidates.
+  for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
+       !block_it.Done();
+       block_it.Advance()) {
+    BlockEntryInstr* block = block_it.Current();
+    for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+      { AllocateObjectInstr* alloc = it.Current()->AsAllocateObject();
+        if ((alloc != NULL) &&
+            IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) {
+          alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate());
+          candidates_.Add(alloc);
+        }
+      }
+      { AllocateUninitializedContextInstr* alloc =
+            it.Current()->AsAllocateUninitializedContext();
+        if ((alloc != NULL) &&
+            IsAllocationSinkingCandidate(alloc, kOptimisticCheck)) {
+          alloc->SetIdentity(AliasIdentity::AllocationSinkingCandidate());
+          candidates_.Add(alloc);
+        }
+      }
+    }
+  }
+
+  // Transitively unmark all candidates that are not strictly valid.
+  bool changed;
+  do {
+    changed = false;
+    for (intptr_t i = 0; i < candidates_.length(); i++) {
+      Definition* alloc = candidates_[i];
+      if (alloc->Identity().IsAllocationSinkingCandidate()) {
+        if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) {
+          alloc->SetIdentity(AliasIdentity::Unknown());
+          changed = true;
+        }
+      }
+    }
+  } while (changed);
+
+  // Shrink the list of candidates removing all unmarked ones.
+  intptr_t j = 0;
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    Definition* alloc = candidates_[i];
+    if (alloc->Identity().IsAllocationSinkingCandidate()) {
+      if (FLAG_trace_optimization) {
+        THR_Print("discovered allocation sinking candidate: v%" Pd "\n",
+                  alloc->ssa_temp_index());
+      }
+
+      if (j != i) {
+        candidates_[j] = alloc;
+      }
+      j++;
+    }
+  }
+  candidates_.TruncateTo(j);
+}
+
+
+// If materialization references an allocation sinking candidate then replace
+// this reference with a materialization which should have been computed for
+// this side-exit. CollectAllExits should have collected this exit.
+void AllocationSinking::NormalizeMaterializations() {
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    Definition* alloc = candidates_[i];
+
+    Value* next_use;
+    for (Value* use = alloc->input_use_list();
+         use != NULL;
+         use = next_use) {
+      next_use = use->next_use();
+      if (use->instruction()->IsMaterializeObject()) {
+        use->BindTo(MaterializationFor(alloc, use->instruction()));
+      }
+    }
+  }
+}
+
+
+// We transitively insert materializations at each deoptimization exit that
+// might see the given allocation (see ExitsCollector). Some of this
+// materializations are not actually used and some fail to compute because
+// they are inserted in the block that is not dominated by the allocation.
+// Remove them unused materializations from the graph.
+void AllocationSinking::RemoveUnusedMaterializations() {
+  intptr_t j = 0;
+  for (intptr_t i = 0; i < materializations_.length(); i++) {
+    MaterializeObjectInstr* mat = materializations_[i];
+    if ((mat->input_use_list() == NULL) && (mat->env_use_list() == NULL)) {
+      // Check if this materialization failed to compute and remove any
+      // unforwarded loads. There were no loads from any allocation sinking
+      // candidate in the beggining so it is safe to assume that any encountered
+      // load was inserted by CreateMaterializationAt.
+      for (intptr_t i = 0; i < mat->InputCount(); i++) {
+        LoadFieldInstr* load = mat->InputAt(i)->definition()->AsLoadField();
+        if ((load != NULL) &&
+            (load->instance()->definition() == mat->allocation())) {
+          load->ReplaceUsesWith(flow_graph_->constant_null());
+          load->RemoveFromGraph();
+        }
+      }
+      mat->RemoveFromGraph();
+    } else {
+      if (j != i) {
+        materializations_[j] = mat;
+      }
+      j++;
+    }
+  }
+  materializations_.TruncateTo(j);
+}
+
+
+// Some candidates might stop being eligible for allocation sinking after
+// the load forwarding because they flow into phis that load forwarding
+// inserts. Discover such allocations and remove them from the list
+// of allocation sinking candidates undoing all changes that we did
+// in preparation for sinking these allocations.
+void AllocationSinking::DiscoverFailedCandidates() {
+  // Transitively unmark all candidates that are not strictly valid.
+  bool changed;
+  do {
+    changed = false;
+    for (intptr_t i = 0; i < candidates_.length(); i++) {
+      Definition* alloc = candidates_[i];
+      if (alloc->Identity().IsAllocationSinkingCandidate()) {
+        if (!IsAllocationSinkingCandidate(alloc, kStrictCheck)) {
+          alloc->SetIdentity(AliasIdentity::Unknown());
+          changed = true;
+        }
+      }
+    }
+  } while (changed);
+
+  // Remove all failed candidates from the candidates list.
+  intptr_t j = 0;
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    Definition* alloc = candidates_[i];
+    if (!alloc->Identity().IsAllocationSinkingCandidate()) {
+      if (FLAG_trace_optimization) {
+        THR_Print("allocation v%" Pd " can't be eliminated\n",
+                  alloc->ssa_temp_index());
+      }
+
+#ifdef DEBUG
+      for (Value* use = alloc->env_use_list();
+           use != NULL;
+           use = use->next_use()) {
+        ASSERT(use->instruction()->IsMaterializeObject());
+      }
+#endif
+
+      // All materializations will be removed from the graph. Remove inserted
+      // loads first and detach materializations from allocation's environment
+      // use list: we will reconstruct it when we start removing
+      // materializations.
+      alloc->set_env_use_list(NULL);
+      for (Value* use = alloc->input_use_list();
+           use != NULL;
+           use = use->next_use()) {
+        if (use->instruction()->IsLoadField()) {
+          LoadFieldInstr* load = use->instruction()->AsLoadField();
+          load->ReplaceUsesWith(flow_graph_->constant_null());
+          load->RemoveFromGraph();
+        } else {
+          ASSERT(use->instruction()->IsMaterializeObject() ||
+                 use->instruction()->IsPhi() ||
+                 use->instruction()->IsStoreInstanceField());
+        }
+      }
+    } else {
+      if (j != i) {
+        candidates_[j] = alloc;
+      }
+      j++;
+    }
+  }
+
+  if (j != candidates_.length()) {  // Something was removed from candidates.
+    intptr_t k = 0;
+    for (intptr_t i = 0; i < materializations_.length(); i++) {
+      MaterializeObjectInstr* mat = materializations_[i];
+      if (!mat->allocation()->Identity().IsAllocationSinkingCandidate()) {
+        // Restore environment uses of the allocation that were replaced
+        // by this materialization and drop materialization.
+        mat->ReplaceUsesWith(mat->allocation());
+        mat->RemoveFromGraph();
+      } else {
+        if (k != i) {
+          materializations_[k] = mat;
+        }
+        k++;
+      }
+    }
+    materializations_.TruncateTo(k);
+  }
+
+  candidates_.TruncateTo(j);
+}
+
+
+void AllocationSinking::Optimize() {
+  CollectCandidates();
+
+  // Insert MaterializeObject instructions that will describe the state of the
+  // object at all deoptimization points. Each inserted materialization looks
+  // like this (where v_0 is allocation that we are going to eliminate):
+  //   v_1     <- LoadField(v_0, field_1)
+  //           ...
+  //   v_N     <- LoadField(v_0, field_N)
+  //   v_{N+1} <- MaterializeObject(field_1 = v_1, ..., field_N = v_{N})
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    InsertMaterializations(candidates_[i]);
+  }
+
+  // Run load forwarding to eliminate LoadField instructions inserted above.
+  // All loads will be successfully eliminated because:
+  //   a) they use fields (not offsets) and thus provide precise aliasing
+  //      information
+  //   b) candidate does not escape and thus its fields is not affected by
+  //      external effects from calls.
+  LoadOptimizer::OptimizeGraph(flow_graph_);
+
+  NormalizeMaterializations();
+
+  RemoveUnusedMaterializations();
+
+  // If any candidates are no longer eligible for allocation sinking abort
+  // the optimization for them and undo any changes we did in preparation.
+  DiscoverFailedCandidates();
+
+  // At this point we have computed the state of object at each deoptimization
+  // point and we can eliminate it. Loads inserted above were forwarded so there
+  // are no uses of the allocation just as in the begging of the pass.
+  for (intptr_t i = 0; i < candidates_.length(); i++) {
+    EliminateAllocation(candidates_[i]);
+  }
+
+  // Process materializations and unbox their arguments: materializations
+  // are part of the environment and can materialize boxes for double/mint/simd
+  // values when needed.
+  // TODO(vegorov): handle all box types here.
+  for (intptr_t i = 0; i < materializations_.length(); i++) {
+    MaterializeObjectInstr* mat = materializations_[i];
+    for (intptr_t j = 0; j < mat->InputCount(); j++) {
+      Definition* defn = mat->InputAt(j)->definition();
+      if (defn->IsBox()) {
+        mat->InputAt(j)->BindTo(defn->InputAt(0)->definition());
+      }
+    }
+  }
+}
+
+
+// Remove materializations from the graph. Register allocator will treat them
+// as part of the environment not as a real instruction.
+void AllocationSinking::DetachMaterializations() {
+  for (intptr_t i = 0; i < materializations_.length(); i++) {
+    materializations_[i]->previous()->LinkTo(materializations_[i]->next());
+  }
+}
+
+
+// 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;
+    }
+  }
+  slots->Add(&slot);
+  return true;
+}
+
+
+// Find deoptimization exit for the given materialization assuming that all
+// materializations are emitted right before the instruction which is a
+// deoptimization exit.
+static Instruction* ExitForMaterialization(MaterializeObjectInstr* mat) {
+  while (mat->next()->IsMaterializeObject()) {
+    mat = mat->next()->AsMaterializeObject();
+  }
+  return mat->next();
+}
+
+
+// Given the deoptimization exit find first materialization that was inserted
+// before it.
+static Instruction* FirstMaterializationAt(Instruction* exit) {
+  while (exit->previous()->IsMaterializeObject()) {
+    exit = exit->previous();
+  }
+  return exit;
+}
+
+
+// Given the allocation and deoptimization exit try to find MaterializeObject
+// instruction corresponding to this allocation at this exit.
+MaterializeObjectInstr* AllocationSinking::MaterializationFor(
+    Definition* alloc, Instruction* exit) {
+  if (exit->IsMaterializeObject()) {
+    exit = ExitForMaterialization(exit->AsMaterializeObject());
+  }
+
+  for (MaterializeObjectInstr* mat = exit->previous()->AsMaterializeObject();
+       mat != NULL;
+       mat = mat->previous()->AsMaterializeObject()) {
+    if (mat->allocation() == alloc) {
+      return mat;
+    }
+  }
+
+  return NULL;
+}
+
+
+// Insert MaterializeObject instruction for the given allocation before
+// the given instruction that can deoptimize.
+void AllocationSinking::CreateMaterializationAt(
+    Instruction* exit,
+    Definition* alloc,
+    const ZoneGrowableArray<const Object*>& slots) {
+  ZoneGrowableArray<Value*>* values =
+      new(Z) ZoneGrowableArray<Value*>(slots.length());
+
+  // All loads should be inserted before the first materialization so that
+  // IR follows the following pattern: loads, materializations, deoptimizing
+  // instruction.
+  Instruction* load_point = FirstMaterializationAt(exit);
+
+  // Insert load instruction for every field.
+  for (intptr_t i = 0; i < slots.length(); i++) {
+    LoadFieldInstr* load = slots[i]->IsField()
+        ? new(Z) LoadFieldInstr(
+            new(Z) Value(alloc),
+            &Field::Cast(*slots[i]),
+            AbstractType::ZoneHandle(Z),
+            alloc->token_pos())
+        : new(Z) LoadFieldInstr(
+            new(Z) Value(alloc),
+            Smi::Cast(*slots[i]).Value(),
+            AbstractType::ZoneHandle(Z),
+            alloc->token_pos());
+    flow_graph_->InsertBefore(
+        load_point, load, NULL, FlowGraph::kValue);
+    values->Add(new(Z) Value(load));
+  }
+
+  MaterializeObjectInstr* mat = NULL;
+  if (alloc->IsAllocateObject()) {
+    mat = new(Z) MaterializeObjectInstr(
+        alloc->AsAllocateObject(), slots, values);
+  } else {
+    ASSERT(alloc->IsAllocateUninitializedContext());
+    mat = new(Z) MaterializeObjectInstr(
+        alloc->AsAllocateUninitializedContext(), slots, values);
+  }
+
+  flow_graph_->InsertBefore(exit, mat, NULL, FlowGraph::kValue);
+
+  // Replace all mentions of this allocation with a newly inserted
+  // MaterializeObject instruction.
+  // We must preserve the identity: all mentions are replaced by the same
+  // materialization.
+  for (Environment::DeepIterator env_it(exit->env());
+       !env_it.Done();
+       env_it.Advance()) {
+    Value* use = env_it.CurrentValue();
+    if (use->definition() == alloc) {
+      use->RemoveFromUseList();
+      use->set_definition(mat);
+      mat->AddEnvUse(use);
+    }
+  }
+
+  // Mark MaterializeObject as an environment use of this allocation.
+  // This will allow us to discover it when we are looking for deoptimization
+  // exits for another allocation that potentially flows into this one.
+  Value* val = new(Z) Value(alloc);
+  val->set_instruction(mat);
+  alloc->AddEnvUse(val);
+
+  // Record inserted materialization.
+  materializations_.Add(mat);
+}
+
+
+// Add given instruction to the list of the instructions if it is not yet
+// present there.
+template<typename T>
+void AddInstruction(GrowableArray<T*>* list, T* value) {
+  ASSERT(!value->IsGraphEntry());
+  for (intptr_t i = 0; i < list->length(); i++) {
+    if ((*list)[i] == value) {
+      return;
+    }
+  }
+  list->Add(value);
+}
+
+
+// Transitively collect all deoptimization exits that might need this allocation
+// rematerialized. It is not enough to collect only environment uses of this
+// allocation because it can flow into other objects that will be
+// dematerialized and that are referenced by deopt environments that
+// don't contain this allocation explicitly.
+void AllocationSinking::ExitsCollector::Collect(Definition* alloc) {
+  for (Value* use = alloc->env_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    if (use->instruction()->IsMaterializeObject()) {
+      AddInstruction(&exits_, ExitForMaterialization(
+          use->instruction()->AsMaterializeObject()));
+    } else {
+      AddInstruction(&exits_, use->instruction());
+    }
+  }
+
+  // Check if this allocation is stored into any other allocation sinking
+  // candidate and put it on worklist so that we conservatively collect all
+  // exits for that candidate as well because they potentially might see
+  // this object.
+  for (Value* use = alloc->input_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    Definition* obj = StoreInto(use);
+    if ((obj != NULL) && (obj != alloc)) {
+      AddInstruction(&worklist_, obj);
+    }
+  }
+}
+
+
+void AllocationSinking::ExitsCollector::CollectTransitively(Definition* alloc) {
+  exits_.TruncateTo(0);
+  worklist_.TruncateTo(0);
+
+  worklist_.Add(alloc);
+
+  // Note: worklist potentially will grow while we are iterating over it.
+  // We are not removing allocations from the worklist not to waste space on
+  // the side maintaining BitVector of already processed allocations: worklist
+  // is expected to be very small thus linear search in it is just as effecient
+  // as a bitvector.
+  for (intptr_t i = 0; i < worklist_.length(); i++) {
+    Collect(worklist_[i]);
+  }
+}
+
+
+void AllocationSinking::InsertMaterializations(Definition* alloc) {
+  // Collect all fields that are written for this instance.
+  ZoneGrowableArray<const Object*>* slots =
+      new(Z) ZoneGrowableArray<const Object*>(5);
+
+  for (Value* use = alloc->input_use_list();
+       use != NULL;
+       use = use->next_use()) {
+    StoreInstanceFieldInstr* store = use->instruction()->AsStoreInstanceField();
+    if ((store != NULL) && (store->instance()->definition() == alloc)) {
+      if (!store->field().IsNull()) {
+        AddSlot(slots, Field::ZoneHandle(Z, store->field().Original()));
+      } else {
+        AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(store->offset_in_bytes())));
+      }
+    }
+  }
+
+  if (alloc->ArgumentCount() > 0) {
+    AllocateObjectInstr* alloc_object = alloc->AsAllocateObject();
+    ASSERT(alloc_object->ArgumentCount() == 1);
+    intptr_t type_args_offset =
+        alloc_object->cls().type_arguments_field_offset();
+    AddSlot(slots, Smi::ZoneHandle(Z, Smi::New(type_args_offset)));
+  }
+
+  // Collect all instructions that mention this object in the environment.
+  exits_collector_.CollectTransitively(alloc);
+
+  // Insert materializations at environment uses.
+  for (intptr_t i = 0; i < exits_collector_.exits().length(); i++) {
+    CreateMaterializationAt(
+        exits_collector_.exits()[i], alloc, *slots);
+  }
+}
+
+
+void TryCatchAnalyzer::Optimize(FlowGraph* flow_graph) {
+  // For every catch-block: Iterate over all call instructions inside the
+  // corresponding try-block and figure out for each environment value if it
+  // is the same constant at all calls. If yes, replace the initial definition
+  // at the catch-entry with this constant.
+  const GrowableArray<CatchBlockEntryInstr*>& catch_entries =
+      flow_graph->graph_entry()->catch_entries();
+  intptr_t base = kFirstLocalSlotFromFp + flow_graph->num_non_copied_params();
+  for (intptr_t catch_idx = 0;
+       catch_idx < catch_entries.length();
+       ++catch_idx) {
+    CatchBlockEntryInstr* catch_entry = catch_entries[catch_idx];
+
+    // Initialize cdefs with the original initial definitions (ParameterInstr).
+    // The following representation is used:
+    // ParameterInstr => unknown
+    // ConstantInstr => known constant
+    // NULL => non-constant
+    GrowableArray<Definition*>* idefs = catch_entry->initial_definitions();
+    GrowableArray<Definition*> cdefs(idefs->length());
+    cdefs.AddArray(*idefs);
+
+    // exception_var and stacktrace_var are never constant.
+    intptr_t ex_idx = base - catch_entry->exception_var().index();
+    intptr_t st_idx = base - catch_entry->stacktrace_var().index();
+    cdefs[ex_idx] = cdefs[st_idx] = NULL;
+
+    for (BlockIterator block_it = flow_graph->reverse_postorder_iterator();
+         !block_it.Done();
+         block_it.Advance()) {
+      BlockEntryInstr* block = block_it.Current();
+      if (block->try_index() == catch_entry->catch_try_index()) {
+        for (ForwardInstructionIterator instr_it(block);
+             !instr_it.Done();
+             instr_it.Advance()) {
+          Instruction* current = instr_it.Current();
+          if (current->MayThrow()) {
+            Environment* env = current->env()->Outermost();
+            ASSERT(env != NULL);
+            for (intptr_t env_idx = 0; env_idx < cdefs.length(); ++env_idx) {
+              if (cdefs[env_idx] != NULL &&
+                  env->ValueAt(env_idx)->BindsToConstant()) {
+                cdefs[env_idx] = env->ValueAt(env_idx)->definition();
+              }
+              if (cdefs[env_idx] != env->ValueAt(env_idx)->definition()) {
+                cdefs[env_idx] = NULL;
+              }
+            }
+          }
+        }
+      }
+    }
+    for (intptr_t j = 0; j < idefs->length(); ++j) {
+      if (cdefs[j] != NULL && cdefs[j]->IsConstant()) {
+        // TODO(fschneider): Use constants from the constant pool.
+        Definition* old = (*idefs)[j];
+        ConstantInstr* orig = cdefs[j]->AsConstant();
+        ConstantInstr* copy =
+            new(flow_graph->zone()) ConstantInstr(orig->value());
+        copy->set_ssa_temp_index(flow_graph->alloc_ssa_temp_index());
+        old->ReplaceUsesWith(copy);
+        (*idefs)[j] = copy;
+      }
+    }
+  }
+}
+
+
+// Returns true iff this definition is used in a non-phi instruction.
+static bool HasRealUse(Definition* def) {
+  // Environment uses are real (non-phi) uses.
+  if (def->env_use_list() != NULL) return true;
+
+  for (Value::Iterator it(def->input_use_list());
+       !it.Done();
+       it.Advance()) {
+    if (!it.Current()->instruction()->IsPhi()) return true;
+  }
+  return false;
+}
+
+
+void DeadCodeElimination::EliminateDeadPhis(FlowGraph* flow_graph) {
+  GrowableArray<PhiInstr*> live_phis;
+  for (BlockIterator b = flow_graph->postorder_iterator();
+       !b.Done();
+       b.Advance()) {
+    JoinEntryInstr* join = b.Current()->AsJoinEntry();
+    if (join != NULL) {
+      for (PhiIterator it(join); !it.Done(); it.Advance()) {
+        PhiInstr* phi = it.Current();
+        // Phis that have uses and phis inside try blocks are
+        // marked as live.
+        if (HasRealUse(phi) || join->InsideTryBlock()) {
+          live_phis.Add(phi);
+          phi->mark_alive();
+        } else {
+          phi->mark_dead();
+        }
+      }
+    }
+  }
+
+  while (!live_phis.is_empty()) {
+    PhiInstr* phi = live_phis.RemoveLast();
+    for (intptr_t i = 0; i < phi->InputCount(); i++) {
+      Value* val = phi->InputAt(i);
+      PhiInstr* used_phi = val->definition()->AsPhi();
+      if ((used_phi != NULL) && !used_phi->is_alive()) {
+        used_phi->mark_alive();
+        live_phis.Add(used_phi);
+      }
+    }
+  }
+
+  for (BlockIterator it(flow_graph->postorder_iterator());
+       !it.Done();
+       it.Advance()) {
+    JoinEntryInstr* join = it.Current()->AsJoinEntry();
+    if (join != NULL) {
+      if (join->phis_ == NULL) continue;
+
+      // Eliminate dead phis and compact the phis_ array of the block.
+      intptr_t to_index = 0;
+      for (intptr_t i = 0; i < join->phis_->length(); ++i) {
+        PhiInstr* phi = (*join->phis_)[i];
+        if (phi != NULL) {
+          if (!phi->is_alive()) {
+            phi->ReplaceUsesWith(flow_graph->constant_null());
+            phi->UnuseAllInputs();
+            (*join->phis_)[i] = NULL;
+            if (FLAG_trace_optimization) {
+              THR_Print("Removing dead phi v%" Pd "\n", phi->ssa_temp_index());
+            }
+          } else if (phi->IsRedundant()) {
+            phi->ReplaceUsesWith(phi->InputAt(0)->definition());
+            phi->UnuseAllInputs();
+            (*join->phis_)[i] = NULL;
+            if (FLAG_trace_optimization) {
+              THR_Print("Removing redundant phi v%" Pd "\n",
+                         phi->ssa_temp_index());
+            }
+          } else {
+            (*join->phis_)[to_index++] = phi;
+          }
+        }
+      }
+      if (to_index == 0) {
+        join->phis_ = NULL;
+      } else {
+        join->phis_->TruncateTo(to_index);
+      }
+    }
+  }
+}
+
+
+}  // namespace dart
diff --git a/runtime/vm/redundancy_elimination.h b/runtime/vm/redundancy_elimination.h
new file mode 100644
index 0000000..73a9850
--- /dev/null
+++ b/runtime/vm/redundancy_elimination.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_REDUNDANCY_ELIMINATION_H_
+#define VM_REDUNDANCY_ELIMINATION_H_
+
+#include "vm/intermediate_language.h"
+#include "vm/flow_graph.h"
+
+namespace dart {
+
+class CSEInstructionMap;
+
+class AllocationSinking : public ZoneAllocated {
+ public:
+  explicit AllocationSinking(FlowGraph* flow_graph)
+      : flow_graph_(flow_graph),
+        candidates_(5),
+        materializations_(5) { }
+
+  const GrowableArray<Definition*>& candidates() const {
+    return candidates_;
+  }
+
+  // Find the materialization insterted for the given allocation
+  // at the given exit.
+  MaterializeObjectInstr* MaterializationFor(Definition* alloc,
+                                             Instruction* exit);
+
+  void Optimize();
+
+  void DetachMaterializations();
+
+ private:
+  // Helper class to collect deoptimization exits that might need to
+  // rematerialize an object: that is either instructions that reference
+  // this object explicitly in their deoptimization environment or
+  // reference some other allocation sinking candidate that points to
+  // this object.
+  class ExitsCollector : public ValueObject {
+   public:
+    ExitsCollector() : exits_(10), worklist_(3) { }
+
+    const GrowableArray<Instruction*>& exits() const { return exits_; }
+
+    void CollectTransitively(Definition* alloc);
+
+   private:
+    // Collect immediate uses of this object in the environments.
+    // If this object is stored into other allocation sinking candidates
+    // put them onto worklist so that CollectTransitively will process them.
+    void Collect(Definition* alloc);
+
+    GrowableArray<Instruction*> exits_;
+    GrowableArray<Definition*> worklist_;
+  };
+
+  void CollectCandidates();
+
+  void NormalizeMaterializations();
+
+  void RemoveUnusedMaterializations();
+
+  void DiscoverFailedCandidates();
+
+  void InsertMaterializations(Definition* alloc);
+
+  void CreateMaterializationAt(
+      Instruction* exit,
+      Definition* alloc,
+      const ZoneGrowableArray<const Object*>& fields);
+
+  void EliminateAllocation(Definition* alloc);
+
+  Isolate* isolate() const { return flow_graph_->isolate(); }
+  Zone* zone() const { return flow_graph_->zone(); }
+
+  FlowGraph* flow_graph_;
+
+  GrowableArray<Definition*> candidates_;
+  GrowableArray<MaterializeObjectInstr*> materializations_;
+
+  ExitsCollector exits_collector_;
+};
+
+
+// A simple common subexpression elimination based
+// on the dominator tree.
+class DominatorBasedCSE : public AllStatic {
+ public:
+  // Return true, if the optimization changed the flow graph.
+  // False, if nothing changed.
+  static bool Optimize(FlowGraph* graph);
+
+ private:
+  static bool OptimizeRecursive(
+      FlowGraph* graph,
+      BlockEntryInstr* entry,
+      CSEInstructionMap* map);
+};
+
+
+class DeadStoreElimination : public AllStatic {
+ public:
+  static void Optimize(FlowGraph* graph);
+};
+
+
+class DeadCodeElimination : public AllStatic {
+ public:
+  static void EliminateDeadPhis(FlowGraph* graph);
+};
+
+
+// Optimize spill stores inside try-blocks by identifying values that always
+// contain a single known constant at catch block entry.
+class TryCatchAnalyzer : public AllStatic {
+ public:
+  static void Optimize(FlowGraph* flow_graph);
+};
+
+
+// Loop invariant code motion.
+class LICM : public ValueObject {
+ public:
+  explicit LICM(FlowGraph* flow_graph);
+
+  void Optimize();
+
+  void OptimisticallySpecializeSmiPhis();
+
+ private:
+  FlowGraph* flow_graph() const { return flow_graph_; }
+
+  void Hoist(ForwardInstructionIterator* it,
+             BlockEntryInstr* pre_header,
+             Instruction* current);
+
+  void TrySpecializeSmiPhi(PhiInstr* phi,
+                           BlockEntryInstr* header,
+                           BlockEntryInstr* pre_header);
+
+  FlowGraph* const flow_graph_;
+};
+
+}  // namespace dart
+
+#endif  // VM_REDUNDANCY_ELIMINATION_H_
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 46122bd..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;
@@ -5267,14 +5265,14 @@
       false,  // Not external.
       false,  // Not native.
       owner,
-      0));  // No token position.
+      TokenPosition::kMinSource));
 
   // TODO(zerny): Share these arrays between all irregexp functions.
   fn.set_num_fixed_parameters(kParamCount);
   fn.set_parameter_types(Array::Handle(zone, Array::New(kParamCount,
-                                                           Heap::kOld)));
+                                                        Heap::kOld)));
   fn.set_parameter_names(Array::Handle(zone, Array::New(kParamCount,
-                                                           Heap::kOld)));
+                                                        Heap::kOld)));
   fn.SetParameterTypeAt(RegExpMacroAssembler::kParamRegExpIndex,
                         Object::dynamic_type());
   fn.SetParameterNameAt(RegExpMacroAssembler::kParamRegExpIndex,
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/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc
index a41db46..1d6de6c 100644
--- a/runtime/vm/regexp_assembler_ir.cc
+++ b/runtime/vm/regexp_assembler_ir.cc
@@ -36,7 +36,6 @@
 
 
 static const intptr_t kInvalidTryIndex = CatchClauseNode::kInvalidTryIndex;
-static const intptr_t kNoSourcePos = Scanner::kNoSourcePos;
 static const intptr_t kMinStackSize = 512;
 
 
@@ -246,7 +245,8 @@
   Value* type = Bind(new(Z) ConstantInstr(
       TypeArguments::ZoneHandle(Z, TypeArguments::null())));
   Value* length = Bind(Uint64Constant(saved_registers_count_));
-  Value* array = Bind(new(Z) CreateArrayInstr(kNoSourcePos, type, length));
+  Value* array = Bind(new(Z) CreateArrayInstr(
+      TokenPosition::kNoSource, type, length));
   StoreLocal(result_, array);
 
   // Store captured offsets in the `matches` parameter.
@@ -271,7 +271,8 @@
   PRINT(PushLocal(result_));
 
   // Return true on success.
-  AppendInstruction(new(Z) ReturnInstr(kNoSourcePos, Bind(LoadLocal(result_))));
+  AppendInstruction(new(Z) ReturnInstr(
+      TokenPosition::kNoSource, Bind(LoadLocal(result_))));
 }
 
 
@@ -280,7 +281,8 @@
   TAG();
 
   // Return false on failure.
-  AppendInstruction(new(Z) ReturnInstr(kNoSourcePos, Bind(LoadLocal(result_))));
+  AppendInstruction(new(Z) ReturnInstr(
+      TokenPosition::kNoSource, Bind(LoadLocal(result_))));
 }
 
 
@@ -382,8 +384,8 @@
 
 LocalVariable* IRRegExpMacroAssembler::Parameter(const String& name,
                                                  intptr_t index) const {
-  LocalVariable* local =
-      new(Z) LocalVariable(kNoSourcePos, name, Object::dynamic_type());
+  LocalVariable* local = new(Z) LocalVariable(
+      TokenPosition::kNoSource, name, Object::dynamic_type());
 
   intptr_t param_frame_index = kParamEndSlotFromFp + kParamCount - index;
   local->set_index(param_frame_index);
@@ -393,8 +395,8 @@
 
 
 LocalVariable* IRRegExpMacroAssembler::Local(const String& name) {
-  LocalVariable* local =
-      new(Z) LocalVariable(kNoSourcePos, name, Object::dynamic_type());
+  LocalVariable* local = new(Z) LocalVariable(
+      TokenPosition::kNoSource, name, Object::dynamic_type());
   local->set_index(GetNextLocalIndex());
 
   return local;
@@ -480,7 +482,7 @@
   Value* rhs_value = Bind(BoolConstant(true));
 
   return new(Z) StrictCompareInstr(
-      kNoSourcePos, strict_comparison, lhs_value, rhs_value, true);
+      TokenPosition::kNoSource, strict_comparison, lhs_value, rhs_value, true);
 }
 
 ComparisonInstr* IRRegExpMacroAssembler::Comparison(
@@ -526,7 +528,7 @@
 StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
     const Function& function,
     ZoneGrowableArray<PushArgumentInstr*>* arguments) const {
-  return new(Z) StaticCallInstr(kNoSourcePos,
+  return new(Z) StaticCallInstr(TokenPosition::kNoSource,
                                 function,
                                 Object::null_array(),
                                 arguments,
@@ -577,7 +579,7 @@
     const InstanceCallDescriptor& desc,
     ZoneGrowableArray<PushArgumentInstr*> *arguments) const {
   return
-    new(Z) InstanceCallInstr(kNoSourcePos,
+    new(Z) InstanceCallInstr(TokenPosition::kNoSource,
                              desc.name,
                              desc.token_kind,
                              arguments,
@@ -588,13 +590,13 @@
 
 
 LoadLocalInstr* IRRegExpMacroAssembler::LoadLocal(LocalVariable* local) const {
-  return new(Z) LoadLocalInstr(*local);
+  return new(Z) LoadLocalInstr(*local, TokenPosition::kNoSource);
 }
 
 
 void IRRegExpMacroAssembler::StoreLocal(LocalVariable* local,
                                         Value* value) {
-  Do(new(Z) StoreLocalInstr(*local, value));
+  Do(new(Z) StoreLocalInstr(*local, value, TokenPosition::kNoSource));
 }
 
 
@@ -621,7 +623,7 @@
     return Bind(new(Z) ConstantInstr(*local.ConstValue()));
   }
   ASSERT(!local.is_captured());
-  return Bind(new(Z) LoadLocalInstr(local));
+  return Bind(new(Z) LoadLocalInstr(local, TokenPosition::kNoSource));
 }
 
 
@@ -1834,7 +1836,8 @@
 
 void IRRegExpMacroAssembler::CheckPreemption() {
   TAG();
-  AppendInstruction(new(Z) CheckStackOverflowInstr(kNoSourcePos, 0));
+  AppendInstruction(new(Z) CheckStackOverflowInstr(
+      TokenPosition::kNoSource, 0));
 }
 
 
@@ -1924,7 +1927,7 @@
       index_val,
       characters,
       specialization_cid_,
-      Scanner::kNoSourcePos));
+      TokenPosition::kNoSource));
 }
 
 
diff --git a/runtime/vm/regexp_parser.cc b/runtime/vm/regexp_parser.cc
index b24e8ca..7b0e01a 100644
--- a/runtime/vm/regexp_parser.cc
+++ b/runtime/vm/regexp_parser.cc
@@ -1064,7 +1064,7 @@
     result->capture_count = capture_count;
   } else {
     ASSERT(!result->error.IsNull());
-    Isolate::Current()->object_store()->clear_sticky_error();
+    Thread::Current()->clear_sticky_error();
 
     // Throw a FormatException on parsing failures.
     const String& message = String::Handle(
diff --git a/runtime/vm/report.cc b/runtime/vm/report.cc
index d09d2a9..21bbdc8 100644
--- a/runtime/vm/report.cc
+++ b/runtime/vm/report.cc
@@ -14,23 +14,17 @@
 
 namespace dart {
 
-DEFINE_FLAG(int, stacktrace_depth_on_warning, 5,
-            "Maximal number of stack frames to print after a runtime warning.");
 DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings.");
-DEFINE_FLAG(bool, warn_on_javascript_compatibility, false,
-            "Warn on incompatibilities between vm and dart2js.");
 DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors.");
 
-DECLARE_FLAG(bool, always_megamorphic_calls);
-
 RawString* Report::PrependSnippet(Kind kind,
                                   const Script& script,
-                                  intptr_t token_pos,
+                                  TokenPosition token_pos,
+                                  bool report_after_token,
                                   const String& message) {
   const char* message_header;
   switch (kind) {
     case kWarning: message_header = "warning"; break;
-    case kJSWarning: message_header = "javascript compatibility warning"; break;
     case kError: message_header = "error"; break;
     case kMalformedType: message_header = "malformed type"; break;
     case kMalboundedType: message_header = "malbounded type"; break;
@@ -40,9 +34,12 @@
   String& result = String::Handle();
   if (!script.IsNull()) {
     const String& script_url = String::Handle(script.url());
-    if (token_pos >= 0) {
-      intptr_t line, column;
-      script.GetTokenLocation(token_pos, &line, &column);
+    if (token_pos.IsReal()) {
+      intptr_t line, column, token_len;
+      script.GetTokenLocation(token_pos, &line, &column, &token_len);
+      if (report_after_token) {
+        column += token_len;
+      }
       // Only report the line position if we have the original source. We still
       // need to get a valid column so that we can report the ^ mark below the
       // snippet.
@@ -106,7 +103,7 @@
 
 
 void Report::LongJumpF(const Error& prev_error,
-                       const Script& script, intptr_t token_pos,
+                       const Script& script, TokenPosition token_pos,
                        const char* format, ...) {
   va_list args;
   va_start(args, format);
@@ -117,10 +114,10 @@
 
 
 void Report::LongJumpV(const Error& prev_error,
-                       const Script& script, intptr_t token_pos,
+                       const Script& script, TokenPosition token_pos,
                        const char* format, va_list args) {
   const Error& error = Error::Handle(LanguageError::NewFormattedV(
-      prev_error, script, token_pos,
+      prev_error, script, token_pos, Report::AtLocation,
       kError, Heap::kNew,
       format, args));
   LongJump(error);
@@ -128,16 +125,22 @@
 }
 
 
-void Report::MessageF(Kind kind, const Script& script, intptr_t token_pos,
+void Report::MessageF(Kind kind,
+                      const Script& script,
+                      TokenPosition token_pos,
+                      bool report_after_token,
                       const char* format, ...) {
   va_list args;
   va_start(args, format);
-  MessageV(kind, script, token_pos, format, args);
+  MessageV(kind, script, token_pos, report_after_token, format, args);
   va_end(args);
 }
 
 
-void Report::MessageV(Kind kind, const Script& script, intptr_t token_pos,
+void Report::MessageV(Kind kind,
+                      const Script& script,
+                      TokenPosition token_pos,
+                      bool report_after_token,
                       const char* format, va_list args) {
   if (kind < kError) {
     // Reporting a warning.
@@ -147,115 +150,20 @@
     if (!FLAG_warning_as_error) {
       const String& msg = String::Handle(String::NewFormattedV(format, args));
       const String& snippet_msg = String::Handle(
-          PrependSnippet(kind, script, token_pos, msg));
+          PrependSnippet(kind, script, token_pos, report_after_token, msg));
       OS::Print("%s", snippet_msg.ToCString());
-      if (kind == kJSWarning) {
-        TraceJSWarning(script, token_pos, msg);
-        // Do not print stacktrace if we have not executed Dart code yet.
-        if (Thread::Current()->top_exit_frame_info() != 0) {
-          const Stacktrace& stacktrace =
-              Stacktrace::Handle(Exceptions::CurrentStacktrace());
-          intptr_t idx = 0;
-          OS::Print("%s", stacktrace.ToCStringInternal(
-              &idx, FLAG_stacktrace_depth_on_warning));
-        }
-      }
       return;
     }
   }
   // Reporting an error (or a warning as error).
   const Error& error = Error::Handle(
       LanguageError::NewFormattedV(Error::Handle(),  // No previous error.
-                                   script, token_pos,
+                                   script, token_pos, report_after_token,
                                    kind, Heap::kNew,
                                    format, args));
-  if (kind == kJSWarning) {
-    Exceptions::ThrowJavascriptCompatibilityError(error.ToErrorCString());
-    UNREACHABLE();
-  }
   LongJump(error);
   UNREACHABLE();
 }
 
-
-void Report::JSWarningFromNative(bool is_static_native, const char* msg) {
-  DartFrameIterator iterator;
-  iterator.NextFrame();  // Skip native call.
-  StackFrame* caller_frame = iterator.NextFrame();
-  ASSERT(caller_frame != NULL);
-  const Code& caller_code = Code::Handle(caller_frame->LookupDartCode());
-  ASSERT(!caller_code.IsNull());
-  const uword caller_pc = caller_frame->pc();
-  ICData& ic_data = ICData::Handle();
-  if (is_static_native) {
-    // Assume an unoptimized static call. Optimization was prevented.
-    CodePatcher::GetUnoptimizedStaticCallAt(caller_pc, caller_code, &ic_data);
-  } else {
-    if (FLAG_always_megamorphic_calls) {
-      Report::JSWarningFromFrame(caller_frame, msg);
-      return;
-    } else {
-      // Assume an instance call.
-      CodePatcher::GetInstanceCallAt(caller_pc, caller_code, &ic_data);
-    }
-  }
-  ASSERT(!ic_data.IsNull());
-  // Report warning only if not already reported at this location.
-  if (!ic_data.IssuedJSWarning()) {
-    ic_data.SetIssuedJSWarning();
-    Report::JSWarningFromFrame(caller_frame, msg);
-  }
-}
-
-
-void Report::JSWarningFromIC(const ICData& ic_data, const char* msg) {
-  DartFrameIterator iterator;
-  StackFrame* caller_frame = iterator.NextFrame();
-  ASSERT(caller_frame != NULL);
-  // Report warning only if not already reported at this location.
-  if (!ic_data.IssuedJSWarning()) {
-    ic_data.SetIssuedJSWarning();
-    JSWarningFromFrame(caller_frame, msg);
-  }
-}
-
-
-void Report::JSWarningFromFrame(StackFrame* caller_frame, const char* msg) {
-  ASSERT(caller_frame != NULL);
-  ASSERT(FLAG_warn_on_javascript_compatibility);
-  if (FLAG_silent_warnings) return;
-  Zone* zone = Thread::Current()->zone();
-  const Code& caller_code = Code::Handle(zone,
-                                         caller_frame->LookupDartCode());
-  ASSERT(!caller_code.IsNull());
-  const uword caller_pc = caller_frame->pc();
-  const intptr_t token_pos = caller_code.GetTokenIndexOfPC(caller_pc);
-  const Function& caller = Function::Handle(zone, caller_code.function());
-  const Script& script = Script::Handle(zone, caller.script());
-  MessageF(kJSWarning, script, token_pos, "%s", msg);
-}
-
-
-void Report::TraceJSWarning(const Script& script,
-                            intptr_t token_pos,
-                            const String& message) {
-  const int64_t micros = OS::GetCurrentTimeMicros();
-  Isolate* isolate = Isolate::Current();
-  TraceBuffer* trace_buffer = isolate->trace_buffer();
-  if (trace_buffer == NULL) {
-    TraceBuffer::Init(isolate);
-    trace_buffer = isolate->trace_buffer();
-  }
-  JSONStream js;
-  {
-    JSONObject trace_warning(&js);
-    trace_warning.AddProperty("type", "JSCompatibilityWarning");
-    trace_warning.AddProperty("script", script);
-    trace_warning.AddProperty("tokenPos", token_pos);
-    trace_warning.AddProperty("message", message);
-  }
-  trace_buffer->Trace(micros, js.ToCString(), true);  // Already escaped.
-}
-
 }  // namespace dart
 
diff --git a/runtime/vm/report.h b/runtime/vm/report.h
index 8cc50a1..f95cb84 100644
--- a/runtime/vm/report.h
+++ b/runtime/vm/report.h
@@ -6,6 +6,7 @@
 #define VM_REPORT_H_
 
 #include "vm/allocation.h"
+#include "vm/token_position.h"
 
 namespace dart {
 
@@ -21,60 +22,47 @@
  public:
   enum Kind {
     kWarning,
-    kJSWarning,
     kError,
     kMalformedType,
     kMalboundedType,
     kBailout,
   };
 
+  static const bool AtLocation = false;
+  static const bool AfterLocation = true;
+
   // Report an already formatted error via a long jump.
   static void LongJump(const Error& error);
 
   // Concatenate and report an already formatted error and a new error message.
   static void LongJumpF(const Error& prev_error,
-                        const Script& script, intptr_t token_pos,
+                        const Script& script, TokenPosition token_pos,
                         const char* format, ...) PRINTF_ATTRIBUTE(4, 5);
   static void LongJumpV(const Error& prev_error,
-                        const Script& script, intptr_t token_pos,
+                        const Script& script, TokenPosition token_pos,
                         const char* format, va_list args);
 
   // Report a warning/jswarning/error/bailout message.
-  static void MessageF(Kind kind, const Script& script, intptr_t token_pos,
-                       const char* format, ...) PRINTF_ATTRIBUTE(4, 5);
-  static void MessageV(Kind kind, const Script& script, intptr_t token_pos,
+  static void MessageF(Kind kind,
+                       const Script& script,
+                       TokenPosition token_pos,
+                       bool report_after_token,
+                       const char* format, ...) PRINTF_ATTRIBUTE(5, 6);
+  static void MessageV(Kind kind,
+                       const Script& script,
+                       TokenPosition token_pos,
+                       bool report_after_token,
                        const char* format, va_list args);
 
-  // Support to report Javascript compatibility warnings. Note that a
-  // JavascriptCompatibilityError is thrown if --warning_as_error is specified.
-  // If a warning is issued by the various JSWarning calls, the warning is also
-  // emitted in the trace buffer of the current isolate.
-
-  // Report a Javascript compatibility warning at the call site given by
-  // ic_data, unless one has already been emitted at that location.
-  static void JSWarningFromIC(const ICData& ic_data, const char* msg);
-
-  // Report a Javascript compatibility warning at the current native call,
-  // unless one has already been emitted at that location.
-  static void JSWarningFromNative(bool is_static_native, const char* msg);
-
-  // Report a Javascript compatibility warning at the call site given by
-  // caller_frame.
-  static void JSWarningFromFrame(StackFrame* caller_frame, const char* msg);
-
   // Prepend a source snippet to the message.
   // A null script means no source and a negative token_pos means no position.
   static RawString* PrependSnippet(Kind kind,
                                    const Script& script,
-                                   intptr_t token_pos,
+                                   TokenPosition token_pos,
+                                   bool report_after_token,
                                    const String& message);
 
  private:
-  // Emit a Javascript compatibility warning to the current trace buffer.
-  static void TraceJSWarning(const Script& script,
-                             intptr_t token_pos,
-                             const String& message);
-
   DISALLOW_COPY_AND_ASSIGN(Report);
 };
 
diff --git a/runtime/vm/report_test.cc b/runtime/vm/report_test.cc
deleted file mode 100644
index 6338f5b..0000000
--- a/runtime/vm/report_test.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/assert.h"
-#include "vm/report.h"
-#include "vm/unit_test.h"
-
-namespace dart {
-
-TEST_CASE(TraceJSWarning) {
-  Zone* zone = thread->zone();
-  Isolate* isolate = thread->isolate();
-  TraceBuffer::Init(isolate, 3);
-  TraceBuffer* trace_buffer = isolate->trace_buffer();
-  const String& url = String::Handle(zone, String::New("Plug"));
-  const String& source = String::Handle(zone, String::New("240 100"));
-  const Script& script = Script::Handle(zone,
-      Script::New(url, source, RawScript::kEvaluateTag));
-  script.Tokenize(String::Handle(String::New("")));
-  {
-    const intptr_t token_pos = 0;
-    const char* message = "High Voltage";
-    Report::MessageF(Report::kJSWarning, script, token_pos, "%s", message);
-    {
-      JSONStream js;
-      trace_buffer->PrintToJSONStream(&js);
-      EXPECT_SUBSTRING("{\"type\":\"TraceBuffer\",\"members\":["
-                       "{\"type\":\"TraceBufferEntry\",\"time\":",
-                       js.ToCString());
-      // Skip time.
-      EXPECT_SUBSTRING("\"message\":{\"type\":\"JSCompatibilityWarning\","
-                       "\"script\":{\"type\":\"@Script\"",
-                       js.ToCString());
-      // Skip object ring id.
-      EXPECT_SUBSTRING("\"uri\":\"Plug\","
-                       "\"_kind\":\"evaluate\"},\"tokenPos\":0,"
-                       "\"message\":{\"type\":\"@Instance\"",
-                       js.ToCString());
-      // Skip private _OneByteString.
-      EXPECT_SUBSTRING("\"valueAsString\":\"High Voltage\"",
-                       js.ToCString());
-    }
-  }
-  {
-    const intptr_t token_pos = 1;
-    const char* message = "Low Voltage";
-    Report::MessageF(Report::kJSWarning, script, token_pos, "%s", message);
-  }
-  EXPECT_EQ(2, trace_buffer->Length());
-  EXPECT_SUBSTRING("{\"type\":\"JSCompatibilityWarning\",\"script\":{\"type\":"
-                   "\"@Script\"",
-                   trace_buffer->At(0)->message);
-  // Skip object ring id.
-  EXPECT_SUBSTRING("\"uri\":\"Plug\","
-                   "\"_kind\":\"evaluate\"},\"tokenPos\":0,"
-                   "\"message\":{\"type\":\"@Instance\"",
-                   trace_buffer->At(0)->message);
-  // Skip private _OneByteString.
-  EXPECT_SUBSTRING("\"valueAsString\":\"High Voltage\"",
-                   trace_buffer->At(0)->message);
-
-  EXPECT_SUBSTRING("{\"type\":\"JSCompatibilityWarning\",\"script\":{\"type\":"
-                   "\"@Script\"",
-                   trace_buffer->At(1)->message);
-  // Skip object ring id.
-  EXPECT_SUBSTRING("\"uri\":\"Plug\","
-                   "\"_kind\":\"evaluate\"},\"tokenPos\":1,"
-                   "\"message\":{\"type\":\"@Instance\"",
-                   trace_buffer->At(1)->message);
-  // Skip private _OneByteString.
-  EXPECT_SUBSTRING("\"valueAsString\":\"Low Voltage\"",
-                   trace_buffer->At(1)->message);
-
-  delete trace_buffer;
-}
-
-}  // namespace dart
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index b0ae79b..caaf556 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -7,6 +7,7 @@
 #include "vm/dart_entry.h"
 #include "vm/flags.h"
 #include "vm/isolate.h"
+#include "vm/log.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
 #include "vm/symbols.h"
@@ -14,7 +15,6 @@
 namespace dart {
 
 DEFINE_FLAG(bool, trace_resolving, false, "Trace resolving.");
-DECLARE_FLAG(bool, lazy_dispatchers);
 
 // The actual names of named arguments are not checked by the dynamic resolver,
 // but by the method entry code. It is important that the dynamic resolver
@@ -34,22 +34,24 @@
 RawFunction* Resolver::ResolveDynamicForReceiverClass(
     const Class& receiver_class,
     const String& function_name,
-    const ArgumentsDescriptor& args_desc) {
+    const ArgumentsDescriptor& args_desc,
+    bool allow_add) {
 
-  Function& function =
-      Function::Handle(ResolveDynamicAnyArgs(receiver_class, function_name));
+  Function& function = Function::Handle(
+      ResolveDynamicAnyArgs(receiver_class, function_name, allow_add));
 
   if (function.IsNull() ||
       !function.AreValidArguments(args_desc, NULL)) {
     // Return a null function to signal to the upper levels to dispatch to
     // "noSuchMethod" function.
     if (FLAG_trace_resolving) {
-      String& error_message = String::Handle(String::New("function not found"));
+      String& error_message =
+          String::Handle(Symbols::New("function not found"));
       if (!function.IsNull()) {
         // Obtain more detailed error message.
         function.AreValidArguments(args_desc, &error_message);
       }
-      OS::Print("ResolveDynamic error '%s': %s.\n",
+      THR_Print("ResolveDynamic error '%s': %s.\n",
                 function_name.ToCString(),
                 error_message.ToCString());
     }
@@ -61,10 +63,11 @@
 
 RawFunction* Resolver::ResolveDynamicAnyArgs(
     const Class& receiver_class,
-    const String& function_name) {
+    const String& function_name,
+    bool allow_add) {
   Class& cls = Class::Handle(receiver_class.raw());
   if (FLAG_trace_resolving) {
-    OS::Print("ResolveDynamic '%s' for class %s\n",
+    THR_Print("ResolveDynamic '%s' for class %s\n",
               function_name.ToCString(),
               String::Handle(cls.Name()).ToCString());
   }
@@ -124,7 +127,7 @@
     if (FLAG_lazy_dispatchers) {
       if (is_getter && function.IsNull()) {
         function ^= cls.LookupDynamicFunction(field_name);
-        if (!function.IsNull()) {
+        if (!function.IsNull() && allow_add) {
           // We were looking for the getter but found a method with the same
           // name. Create a method extractor and return it.
           // The extractor does not exist yet, so using GetMethodExtractor is
@@ -159,7 +162,7 @@
           function.AreValidArguments(num_arguments,
                                      argument_names,
                                      &error_message);
-          OS::Print("ResolveStatic error '%s': %s.\n",
+          THR_Print("ResolveStatic error '%s': %s.\n",
                     function_name.ToCString(),
                     error_message.ToCString());
         }
@@ -167,7 +170,7 @@
       }
     } else {
       if (FLAG_trace_resolving) {
-        OS::Print("ResolveStatic error: function '%s' not found.\n",
+        THR_Print("ResolveStatic error: function '%s' not found.\n",
                   function_name.ToCString());
       }
     }
@@ -183,7 +186,7 @@
                                argument_names);
     }
     if (FLAG_trace_resolving && function.IsNull()) {
-      OS::Print("ResolveStatic error: function '%s.%s' not found.\n",
+      THR_Print("ResolveStatic error: function '%s.%s' not found.\n",
                 class_name.ToCString(),
                 function_name.ToCString());
     }
@@ -198,7 +201,7 @@
                                      const Array& argument_names) {
   ASSERT(!cls.IsNull());
   if (FLAG_trace_resolving) {
-    OS::Print("ResolveStatic '%s'\n", function_name.ToCString());
+    THR_Print("ResolveStatic '%s'\n", function_name.ToCString());
   }
   const Function& function =
       Function::Handle(cls.LookupStaticFunction(function_name));
@@ -214,7 +217,7 @@
                                    argument_names,
                                    &error_message);
       }
-      OS::Print("ResolveStatic error '%s': %s.\n",
+      THR_Print("ResolveStatic error '%s': %s.\n",
                 function_name.ToCString(),
                 error_message.ToCString());
     }
@@ -230,7 +233,7 @@
                                                  const Array& argument_names) {
   ASSERT(!cls.IsNull());
   if (FLAG_trace_resolving) {
-    OS::Print("ResolveStaticAllowPrivate '%s'\n", function_name.ToCString());
+    THR_Print("ResolveStaticAllowPrivate '%s'\n", function_name.ToCString());
   }
   const Function& function =
       Function::Handle(cls.LookupStaticFunctionAllowPrivate(function_name));
@@ -246,7 +249,7 @@
                                    argument_names,
                                    &error_message);
       }
-      OS::Print("ResolveStaticAllowPrivate error '%s': %s.\n",
+      THR_Print("ResolveStaticAllowPrivate error '%s': %s.\n",
                 function_name.ToCString(),
                 error_message.ToCString());
     }
diff --git a/runtime/vm/resolver.h b/runtime/vm/resolver.h
index 1ea883e..32629aa 100644
--- a/runtime/vm/resolver.h
+++ b/runtime/vm/resolver.h
@@ -28,14 +28,18 @@
                                      const String& function_name,
                                      const ArgumentsDescriptor& args_desc);
 
+  // If 'allow_add' is true we may add a function to the class during lookup.
   static RawFunction* ResolveDynamicForReceiverClass(
       const Class& receiver_class,
       const String& function_name,
-      const ArgumentsDescriptor& args_desc);
+      const ArgumentsDescriptor& args_desc,
+      bool allow_add = true);
 
+  // If 'allow_add' is true we may add a function to the class during lookup.
   static RawFunction* ResolveDynamicAnyArgs(
       const Class& receiver_class,
-      const String& function_name);
+      const String& function_name,
+      bool allow_add = true);
 
   // Resolve specified dart static function. If library.IsNull, use
   // either application library or core library if no application library
diff --git a/runtime/vm/reusable_handles.h b/runtime/vm/reusable_handles.h
index 8f057ea..beae36b 100644
--- a/runtime/vm/reusable_handles.h
+++ b/runtime/vm/reusable_handles.h
@@ -11,9 +11,9 @@
 
 namespace dart {
 
-// Classes registered in REUSABLE_HANDLE_LIST have an isolate specific reusable
+// Classes registered in REUSABLE_HANDLE_LIST have an thread specific reusable
 // handle. A guard class (Reusable*ClassName*HandleScope) should be used in
-// regions of the virtual machine where the isolate specific reusable handle
+// regions of the virtual machine where the thread specific reusable handle
 // of that type is used. The class asserts that we do not add code that will
 // result in recursive uses of the class's reusable handle.
 //
@@ -21,7 +21,7 @@
 // REUSABLE_*CLASSNAME*_HANDLESCOPE macro:
 //
 // {
-//   REUSABLE_ARRAY_HANDLESCOPE(isolate);
+//   REUSABLE_ARRAY_HANDLESCOPE(thread);
 //   ....
 //   ....
 //   Array& funcs = reused_array_handle.Handle();
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index f177a10..101898f 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -17,11 +17,19 @@
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
   const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+      Class::Handle(Class::New(class_name, script,
+                               TokenPosition::kNoSource));
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   const Function& function = Function::ZoneHandle(
-      Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+      Function::New(function_name,
+                    RawFunction::kRegularFunction,
+                    true,
+                    false,
+                    false,
+                    false,
+                    false,
+                    owner_class,
+                    TokenPosition::kMinSource));
   const Array& functions = Array::Handle(Array::New(1));
   functions.SetAt(0, function);
   owner_class.SetFunctions(functions);
diff --git a/runtime/vm/runtime_entry.h b/runtime/vm/runtime_entry.h
index fe8d2898..c52b6b5 100644
--- a/runtime/vm/runtime_entry.h
+++ b/runtime/vm/runtime_entry.h
@@ -9,6 +9,7 @@
 #include "vm/flags.h"
 #include "vm/native_arguments.h"
 #include "vm/runtime_entry_list.h"
+#include "vm/safepoint.h"
 #include "vm/tags.h"
 
 namespace dart {
@@ -75,6 +76,15 @@
   DISALLOW_COPY_AND_ASSIGN(RuntimeEntry);
 };
 
+#ifndef PRODUCT
+#define TRACE_RUNTIME_CALL(format, name)                                       \
+  if (FLAG_trace_runtime_calls) {                                              \
+    OS::Print("Runtime call: " format "\n", name);                             \
+  }
+#else
+#define TRACE_RUNTIME_CALL(format, name)                                       \
+  do { } while (0)
+#endif
 
 // Helper macros for declaring and defining runtime entries.
 
@@ -90,11 +100,12 @@
     CHECK_STACK_ALIGNMENT;                                                     \
     VERIFY_ON_TRANSITION;                                                      \
     ASSERT(arguments.ArgCount() == argument_count);                            \
-    if (FLAG_trace_runtime_calls) OS::Print("Runtime call: %s\n", ""#name);    \
+    TRACE_RUNTIME_CALL("%s", ""#name);                                         \
     {                                                                          \
       Thread* thread = arguments.thread();                                     \
       ASSERT(thread == Thread::Current());                                     \
       Isolate* isolate = thread->isolate();                                    \
+      TransitionGeneratedToVM transition(thread);                              \
       StackZone zone(thread);                                                  \
       HANDLESCOPE(thread);                                                     \
       DRT_Helper##name(isolate, thread, zone.GetZone(), arguments);            \
diff --git a/runtime/vm/runtime_entry_list.h b/runtime/vm/runtime_entry_list.h
index e44d0d4..60e46a0 100644
--- a/runtime/vm/runtime_entry_list.h
+++ b/runtime/vm/runtime_entry_list.h
@@ -58,6 +58,11 @@
   V(double, LibcRound, double)                                                 \
   V(double, LibcCos, double)                                                   \
   V(double, LibcSin, double)                                                   \
+  V(double, LibcTan, double)                                                   \
+  V(double, LibcAcos, double)                                                  \
+  V(double, LibcAsin, double)                                                  \
+  V(double, LibcAtan, double)                                                  \
+  V(double, LibcAtan2, double, double)                                         \
   V(RawBool*, CaseInsensitiveCompareUC16,                                      \
     RawString*, RawSmi*, RawSmi*, RawSmi*)                                     \
 
diff --git a/runtime/vm/safepoint.cc b/runtime/vm/safepoint.cc
new file mode 100644
index 0000000..47ef257
--- /dev/null
+++ b/runtime/vm/safepoint.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/safepoint.h"
+
+#include "vm/thread.h"
+#include "vm/thread_registry.h"
+
+namespace dart {
+
+SafepointOperationScope::SafepointOperationScope(Thread* T) : StackResource(T) {
+  ASSERT(T != NULL);
+  Isolate* I = T->isolate();
+  ASSERT(I != NULL);
+  ASSERT(T->no_safepoint_scope_depth() == 0);
+
+  SafepointHandler* handler = I->safepoint_handler();
+  ASSERT(handler != NULL);
+
+  // Signal all threads to get to a safepoint and wait for them to
+  // get to a safepoint.
+  handler->SafepointThreads(T);
+}
+
+
+SafepointOperationScope::~SafepointOperationScope() {
+  Thread* T = thread();
+  ASSERT(T != NULL);
+  Isolate* I = T->isolate();
+  ASSERT(I != NULL);
+
+  // Resume all threads which are blocked for the safepoint operation.
+  SafepointHandler* handler = I->safepoint_handler();
+  ASSERT(handler != NULL);
+  handler->ResumeThreads(T);
+}
+
+
+SafepointHandler::SafepointHandler(Isolate* isolate)
+    : isolate_(isolate),
+      safepoint_lock_(new Monitor()),
+      number_threads_not_at_safepoint_(0),
+      safepoint_in_progress_(false) {
+}
+
+
+SafepointHandler::~SafepointHandler() {
+  ASSERT(safepoint_in_progress_ == false);
+  delete safepoint_lock_;
+  safepoint_lock_ = NULL;
+  isolate_ = NULL;
+}
+
+
+void SafepointHandler::SafepointThreads(Thread* T) {
+  {
+    // First grab the threads list lock for this isolate
+    // and check if a safepoint is already in progress. This
+    // ensures that two threads do not start a safepoint operation
+    // at the same time.
+    MonitorLocker sl(threads_lock());
+
+    // Now check to see if a safepoint operation is already in progress
+    // for this isolate, block if an operation is in progress.
+    while (safepoint_in_progress()) {
+      sl.WaitWithSafepointCheck(T);
+    }
+
+    // Set safepoint in progress by this thread.
+    set_safepoint_in_progress(true);
+
+    // Go over the active thread list and ensure that all threads active
+    // in the isolate reach a safepoint.
+    Thread* current = isolate()->thread_registry()->active_list();
+    while (current != NULL) {
+      MonitorLocker tl(current->thread_lock());
+      if (current != T) {
+        uint32_t state = current->SetSafepointRequested(true);
+        if (!Thread::IsAtSafepoint(state)) {
+          // Thread is not already at a safepoint so try to
+          // get it to a safepoint and wait for it to check in.
+          if (current->IsMutatorThread()) {
+            ASSERT(T->isolate() != NULL);
+            T->isolate()->ScheduleInterrupts(Isolate::kVMInterrupt);
+          }
+          MonitorLocker sl(safepoint_lock_);
+          ++number_threads_not_at_safepoint_;
+        }
+      } else {
+        current->SetAtSafepoint(true);
+      }
+      current = current->next();
+    }
+  }
+  // Now wait for all threads that are not already at a safepoint to check-in.
+  {
+    MonitorLocker sl(safepoint_lock_);
+    while (number_threads_not_at_safepoint_ > 0) {
+      sl.Wait();
+    }
+  }
+}
+
+
+void SafepointHandler::ResumeThreads(Thread* T) {
+  // First resume all the threads which are blocked for the safepoint
+  // operation.
+  MonitorLocker sl(threads_lock());
+  Thread* current = isolate()->thread_registry()->active_list();
+  while (current != NULL) {
+    MonitorLocker tl(current->thread_lock());
+    if (current != T) {
+      uint32_t state = current->SetSafepointRequested(false);
+      if (Thread::IsBlockedForSafepoint(state)) {
+        tl.Notify();
+      }
+    } else {
+      current->SetAtSafepoint(false);
+    }
+    current = current->next();
+  }
+  // Now set the safepoint_in_progress_ flag to false and notify all threads
+  // that are waiting to enter the isolate or waiting to start another
+  // safepoint operation.
+  set_safepoint_in_progress(false);
+  sl.NotifyAll();
+}
+
+
+void SafepointHandler::EnterSafepointUsingLock(Thread* T) {
+  MonitorLocker tl(T->thread_lock());
+  T->SetAtSafepoint(true);
+  if (T->IsSafepointRequested()) {
+    MonitorLocker sl(safepoint_lock_);
+    ASSERT(number_threads_not_at_safepoint_ > 0);
+    number_threads_not_at_safepoint_ -= 1;
+    sl.Notify();
+  }
+}
+
+
+void SafepointHandler::ExitSafepointUsingLock(Thread* T) {
+  MonitorLocker tl(T->thread_lock());
+  ASSERT(T->IsAtSafepoint());
+  while (T->IsSafepointRequested()) {
+    T->SetBlockedForSafepoint(true);
+    tl.Wait();
+    T->SetBlockedForSafepoint(false);
+  }
+  T->SetAtSafepoint(false);
+}
+
+
+void SafepointHandler::BlockForSafepoint(Thread* T) {
+  MonitorLocker tl(T->thread_lock());
+  if (T->IsSafepointRequested()) {
+    T->SetAtSafepoint(true);
+    {
+      MonitorLocker sl(safepoint_lock_);
+      ASSERT(number_threads_not_at_safepoint_ > 0);
+      number_threads_not_at_safepoint_ -= 1;
+      sl.Notify();
+    }
+    while (T->IsSafepointRequested()) {
+      T->SetBlockedForSafepoint(true);
+      tl.Wait();
+      T->SetBlockedForSafepoint(false);
+    }
+    T->SetAtSafepoint(false);
+  }
+}
+
+}  // namespace dart
diff --git a/runtime/vm/safepoint.h b/runtime/vm/safepoint.h
new file mode 100644
index 0000000..1c13a87
--- /dev/null
+++ b/runtime/vm/safepoint.h
@@ -0,0 +1,328 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_SAFEPOINT_H_
+#define VM_SAFEPOINT_H_
+
+#include "vm/globals.h"
+#include "vm/lockers.h"
+#include "vm/thread.h"
+
+namespace dart {
+
+// A stack based scope that can be used to perform an operation after getting
+// all threads to a safepoint. At the end of the operation all the threads are
+// resumed.
+class SafepointOperationScope : public StackResource {
+ public:
+  explicit SafepointOperationScope(Thread* T);
+  ~SafepointOperationScope();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SafepointOperationScope);
+};
+
+
+// Implements handling of safepoint operations for all threads in an Isolate.
+class SafepointHandler {
+ public:
+  explicit SafepointHandler(Isolate* I);
+  ~SafepointHandler();
+
+  void EnterSafepointUsingLock(Thread* T);
+  void ExitSafepointUsingLock(Thread* T);
+
+  void SafepointThreads(Thread* T);
+  void ResumeThreads(Thread* T);
+
+  void BlockForSafepoint(Thread* T);
+
+ private:
+  Isolate* isolate() const { return isolate_; }
+  Monitor* threads_lock() const { return isolate_->threads_lock(); }
+  bool safepoint_in_progress() const {
+    ASSERT(threads_lock()->IsOwnedByCurrentThread());
+    return safepoint_in_progress_;
+  }
+  void set_safepoint_in_progress(bool value) {
+    ASSERT(threads_lock()->IsOwnedByCurrentThread());
+    safepoint_in_progress_ = value;
+  }
+
+  Isolate* isolate_;
+
+  // Monitor used by thread initiating a safepoint operation to track threads
+  // not at a safepoint and wait for these threads to reach a safepoint.
+  Monitor* safepoint_lock_;
+  int32_t number_threads_not_at_safepoint_;
+
+  // Flag to indicate if a safepoint operation is currently in progress.
+  bool safepoint_in_progress_;
+
+  friend class Isolate;
+  friend class SafepointOperationScope;
+};
+
+
+/*
+ * Set of StackResource classes to track thread execution state transitions:
+ *
+ * kThreadInGenerated transitioning to
+ *   ==> kThreadInVM:
+ *       - set_execution_state(kThreadInVM).
+ *       - block if safepoint is requested.
+ *   ==> kThreadInNative:
+ *       - set_execution_state(kThreadInNative).
+ *       - EnterSafepoint().
+ *   ==> kThreadInBlockedState:
+ *       - Invalid transition
+ *
+ * kThreadInVM transitioning to
+ *   ==> kThreadInGenerated
+ *       - set_execution_state(kThreadInGenerated).
+ *   ==> kThreadInNative
+ *       - set_execution_state(kThreadInNative).
+ *       - EnterSafepoint.
+ *   ==> kThreadInBlockedState
+ *       - set_execution_state(kThreadInBlockedState).
+ *       - EnterSafepoint.
+ *
+ * kThreadInNative transitioning to
+ *   ==> kThreadInGenerated
+ *       - ExitSafepoint.
+ *       - set_execution_state(kThreadInGenerated).
+ *   ==> kThreadInVM
+ *       - ExitSafepoint.
+ *       - set_execution_state(kThreadInVM).
+ *   ==> kThreadInBlocked
+ *       - Invalid transition.
+ *
+ * kThreadInBlocked transitioning to
+ *   ==> kThreadInVM
+ *       - ExitSafepoint.
+ *       - set_execution_state(kThreadInVM).
+ *   ==> kThreadInNative
+ *       - Invalid transition.
+ *   ==> kThreadInGenerated
+ *       - Invalid transition.
+ */
+class TransitionSafepointState : public StackResource {
+ public:
+  explicit TransitionSafepointState(Thread* T) : StackResource(T) {}
+  ~TransitionSafepointState() {}
+
+  SafepointHandler* handler() const {
+    ASSERT(thread()->isolate() != NULL);
+    ASSERT(thread()->isolate()->safepoint_handler() != NULL);
+    return thread()->isolate()->safepoint_handler();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TransitionSafepointState);
+};
+
+
+// TransitionGeneratedToVM is used to transition the safepoint state of a
+// thread from "running generated code" to "running vm code" and ensures
+// that the state is reverted back to "running generated code" when
+// exiting the scope/frame.
+class TransitionGeneratedToVM : public TransitionSafepointState {
+ public:
+  explicit TransitionGeneratedToVM(Thread* T) : TransitionSafepointState(T) {
+    ASSERT(T == Thread::Current());
+    ASSERT(T->execution_state() == Thread::kThreadInGenerated);
+    T->set_execution_state(Thread::kThreadInVM);
+    // Fast check to see if a safepoint is requested or not.
+    // We do the more expensive operation of blocking the thread
+    // only if a safepoint is requested.
+    if (T->IsSafepointRequested()) {
+      handler()->BlockForSafepoint(T);
+    }
+  }
+
+  ~TransitionGeneratedToVM() {
+    ASSERT(thread()->execution_state() == Thread::kThreadInVM);
+    thread()->set_execution_state(Thread::kThreadInGenerated);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToVM);
+};
+
+
+// TransitionGeneratedToNative is used to transition the safepoint state of a
+// thread from "running generated code" to "running native code" and ensures
+// that the state is reverted back to "running generated code" when
+// exiting the scope/frame.
+class TransitionGeneratedToNative : public TransitionSafepointState {
+ public:
+  explicit TransitionGeneratedToNative(Thread* T)
+      : TransitionSafepointState(T) {
+    // Native code is considered to be at a safepoint and so we mark it
+    // accordingly.
+    ASSERT(T->execution_state() == Thread::kThreadInGenerated);
+    T->set_execution_state(Thread::kThreadInNative);
+    T->EnterSafepoint();
+  }
+
+  ~TransitionGeneratedToNative() {
+    // We are returning to generated code and so we are not at a safepoint
+    // anymore.
+    ASSERT(thread()->execution_state() == Thread::kThreadInNative);
+    thread()->ExitSafepoint();
+    thread()->set_execution_state(Thread::kThreadInGenerated);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TransitionGeneratedToNative);
+};
+
+
+// TransitionVMToBlocked is used to transition the safepoint state of a
+// thread from "running vm code" to "blocked on a monitor" and ensures
+// that the state is reverted back to "running vm code" when
+// exiting the scope/frame.
+class TransitionVMToBlocked : public TransitionSafepointState {
+ public:
+  explicit TransitionVMToBlocked(Thread* T) : TransitionSafepointState(T) {
+    // A thread blocked on a monitor is considered to be at a safepoint.
+    ASSERT(T->execution_state() == Thread::kThreadInVM);
+    T->set_execution_state(Thread::kThreadInBlockedState);
+    T->EnterSafepoint();
+  }
+
+  ~TransitionVMToBlocked() {
+    // We are returning to vm code and so we are not at a safepoint anymore.
+    ASSERT(thread()->execution_state() == Thread::kThreadInBlockedState);
+    thread()->ExitSafepoint();
+    thread()->set_execution_state(Thread::kThreadInVM);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TransitionVMToBlocked);
+};
+
+
+// TransitionVMToNative is used to transition the safepoint state of a
+// thread from "running vm code" to "running native code" and ensures
+// that the state is reverted back to "running vm code" when
+// exiting the scope/frame.
+class TransitionVMToNative : public TransitionSafepointState {
+ public:
+  explicit TransitionVMToNative(Thread* T) : TransitionSafepointState(T) {
+    // A thread running native code is considered to be at a safepoint.
+    ASSERT(T->execution_state() == Thread::kThreadInVM);
+    T->set_execution_state(Thread::kThreadInNative);
+    T->EnterSafepoint();
+  }
+
+  ~TransitionVMToNative() {
+    // We are returning to vm code and so we are not at a safepoint anymore.
+    ASSERT(thread()->execution_state() == Thread::kThreadInNative);
+    thread()->ExitSafepoint();
+    thread()->set_execution_state(Thread::kThreadInVM);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TransitionVMToNative);
+};
+
+
+// TransitionVMToGenerated is used to transition the safepoint state of a
+// thread from "running vm code" to "running generated code" and ensures
+// that the state is reverted back to "running vm code" when
+// exiting the scope/frame.
+class TransitionVMToGenerated : public TransitionSafepointState {
+ public:
+  explicit TransitionVMToGenerated(Thread* T) : TransitionSafepointState(T) {
+    ASSERT(T == Thread::Current());
+    ASSERT(T->execution_state() == Thread::kThreadInVM);
+    T->set_execution_state(Thread::kThreadInGenerated);
+  }
+
+  ~TransitionVMToGenerated() {
+    ASSERT(thread()->execution_state() == Thread::kThreadInGenerated);
+    thread()->set_execution_state(Thread::kThreadInVM);
+    // Fast check to see if a safepoint is requested or not.
+    // We do the more expensive operation of blocking the thread
+    // only if a safepoint is requested.
+    if (thread()->IsSafepointRequested()) {
+      handler()->BlockForSafepoint(thread());
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TransitionVMToGenerated);
+};
+
+
+// TransitionNativeToVM is used to transition the safepoint state of a
+// thread from "running native code" to "running vm code" and ensures
+// that the state is reverted back to "running native code" when
+// exiting the scope/frame.
+class TransitionNativeToVM : public TransitionSafepointState {
+ public:
+  explicit TransitionNativeToVM(Thread* T) : TransitionSafepointState(T) {
+    // We are about to execute vm code and so we are not at a safepoint anymore.
+    ASSERT(T->execution_state() == Thread::kThreadInNative);
+    T->ExitSafepoint();
+    T->set_execution_state(Thread::kThreadInVM);
+  }
+
+  ~TransitionNativeToVM() {
+    // We are returning to native code and so we are at a safepoint.
+    ASSERT(thread()->execution_state() == Thread::kThreadInVM);
+    thread()->set_execution_state(Thread::kThreadInNative);
+    thread()->EnterSafepoint();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TransitionNativeToVM);
+};
+
+
+// TransitionToGenerated is used to transition the safepoint state of a
+// thread from "running vm code" or "running native code" to
+// "running generated code" and ensures that the state is reverted back
+// to "running vm code" or "running native code" when exiting the
+// scope/frame.
+class TransitionToGenerated : public TransitionSafepointState {
+ public:
+  explicit TransitionToGenerated(Thread* T)
+      : TransitionSafepointState(T),
+        execution_state_(T->execution_state()) {
+    ASSERT(T == Thread::Current());
+    ASSERT((execution_state_ == Thread::kThreadInVM) ||
+           (execution_state_ == Thread::kThreadInNative));
+    if (execution_state_ == Thread::kThreadInNative) {
+      T->ExitSafepoint();
+    }
+    T->set_execution_state(Thread::kThreadInGenerated);
+  }
+
+  ~TransitionToGenerated() {
+    ASSERT(thread()->execution_state() == Thread::kThreadInGenerated);
+    if (execution_state_ == Thread::kThreadInNative) {
+      thread()->set_execution_state(Thread::kThreadInNative);
+      thread()->EnterSafepoint();
+    } else {
+      ASSERT(execution_state_ == Thread::kThreadInVM);
+      thread()->set_execution_state(Thread::kThreadInVM);
+      // Fast check to see if a safepoint is requested or not.
+      // We do the more expensive operation of blocking the thread
+      // only if a safepoint is requested.
+      if (thread()->IsSafepointRequested()) {
+        handler()->BlockForSafepoint(thread());
+      }
+    }
+  }
+
+ private:
+  int16_t execution_state_;
+  DISALLOW_COPY_AND_ASSIGN(TransitionToGenerated);
+};
+
+}  // namespace dart
+
+#endif  // VM_SAFEPOINT_H_
diff --git a/runtime/vm/scanner.cc b/runtime/vm/scanner.cc
index 50073cd..a040476 100644
--- a/runtime/vm/scanner.cc
+++ b/runtime/vm/scanner.cc
@@ -909,8 +909,8 @@
 }
 
 
-void Scanner::ScanTo(intptr_t token_index) {
-  int index = 0;
+void Scanner::ScanTo(TokenPosition token_index) {
+  TokenPosition index = TokenPosition::kMinSource;
   Reset();
   do {
     Scan();
@@ -919,16 +919,18 @@
     for (intptr_t diff = current_token_.position.line - prev_token_line_;
          diff > 0;
          diff--) {
-      index++;  // Advance the index to account for tokens added in ScanAll.
+      // Advance the index to account for tokens added in ScanAll.
+      index.Next();
       inserted_new_lines = true;
     }
 
     if (inserted_new_lines &&
         ((current_token_.kind == Token::kINTERPOL_VAR) ||
          (current_token_.kind == Token::kINTERPOL_START))) {
-          index++;  // Advance the index to account for tokens added in ScanAll.
+          // Advance the index to account for tokens added in ScanAll.
+          index.Next();
     }
-    index++;
+    index.Next();
     prev_token_line_ = current_token_.position.line;
   } while ((token_index >= index) && (current_token_.kind != Token::kEOS));
 }
diff --git a/runtime/vm/scanner.h b/runtime/vm/scanner.h
index 7a81040..92ebcd6 100644
--- a/runtime/vm/scanner.h
+++ b/runtime/vm/scanner.h
@@ -11,6 +11,7 @@
 
 #include "vm/growable_array.h"
 #include "vm/token.h"
+#include "vm/token_position.h"
 
 namespace dart {
 
@@ -44,13 +45,6 @@
     const String* literal;    // Identifier, number or string literal.
   };
 
-  // Dummy token index reflecting an unknown source position.
-  static const intptr_t kNoSourcePos = -1;
-
-  static bool ValidSourcePosition(intptr_t token_pos) {
-    return (token_pos >= 0) || (token_pos == kNoSourcePos);
-  }
-
   typedef ZoneGrowableArray<TokenDescriptor> GrowableTokenStream;
 
   // Initializes scanner to scan string source.
@@ -62,7 +56,7 @@
 
   // Scans to specified token position.
   // Use CurrentPosition() to extract position.
-  void ScanTo(intptr_t token_index);
+  void ScanTo(TokenPosition token_index);
 
   // Scans entire source and returns a stream of tokens.
   // Should be called only once.
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index 60478d3..bcbb79f 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -14,6 +14,7 @@
 #include "vm/lockers.h"
 #include "vm/object.h"
 #include "vm/object_id_ring.h"
+#include "vm/safepoint.h"
 #include "vm/stack_frame.h"
 #include "vm/store_buffer.h"
 #include "vm/thread_registry.h"
@@ -449,7 +450,7 @@
   if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) {
     (isolate->gc_prologue_callback())();
   }
-  isolate->thread_registry()->PrepareForGC();
+  isolate->PrepareForGC();
   // Flip the two semi-spaces so that to_ is always the space for allocating
   // objects.
   SemiSpace* from = to_;
@@ -545,6 +546,9 @@
 
 void Scavenger::IterateObjectIdTable(Isolate* isolate,
                                      ScavengerVisitor* visitor) {
+  if (!FLAG_support_service) {
+    return;
+  }
   ObjectIdRing* ring = isolate->object_id_ring();
   if (ring == NULL) {
     // --gc_at_alloc can get us here before the ring has been initialized.
@@ -763,7 +767,7 @@
   // will continue with its scavenge after waiting for the winner to complete.
   // TODO(koda): Consider moving SafepointThreads into allocation failure/retry
   // logic to avoid needless collections.
-  isolate->thread_registry()->SafepointThreads();
+  SafepointOperationScope safepoint_scope(Thread::Current());
 
   // Scavenging is not reentrant. Make sure that is the case.
   ASSERT(!scavenging_);
@@ -823,8 +827,6 @@
   // Done scavenging. Reset the marker.
   ASSERT(scavenging_);
   scavenging_ = false;
-
-  isolate->thread_registry()->ResumeAllThreads();
 }
 
 
@@ -835,6 +837,9 @@
 
 
 void Scavenger::PrintToJSONObject(JSONObject* object) const {
+  if (!FLAG_support_service) {
+    return;
+  }
   Isolate* isolate = Isolate::Current();
   ASSERT(isolate != NULL);
   JSONObject space(object, "new");
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index 11a0aa1..c5f2b81 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -24,9 +24,6 @@
 class JSONObject;
 class ScavengerVisitor;
 
-DECLARE_FLAG(bool, gc_at_alloc);
-
-
 // Wrapper around VirtualMemory that adds caching and handles the empty case.
 class SemiSpace {
  public:
diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
index 4c52227..6060e7a 100644
--- a/runtime/vm/scopes.cc
+++ b/runtime/vm/scopes.cc
@@ -29,8 +29,8 @@
       loop_level_(loop_level),
       context_level_(LocalScope::kUnitializedContextLevel),
       num_context_variables_(0),
-      begin_token_pos_(Scanner::kNoSourcePos),
-      end_token_pos_(Scanner::kNoSourcePos),
+      begin_token_pos_(TokenPosition::kNoSourcePos),
+      end_token_pos_(TokenPosition::kNoSourcePos),
       variables_(),
       labels_(),
       referenced_() {
@@ -110,7 +110,7 @@
 }
 
 
-void LocalScope::AddReferencedName(intptr_t token_pos,
+void LocalScope::AddReferencedName(TokenPosition token_pos,
                                    const String& name) {
   if (LocalLookupVariable(name) != NULL) {
     return;
@@ -132,12 +132,12 @@
 }
 
 
-intptr_t LocalScope::PreviousReferencePos(const String& name) const {
+TokenPosition LocalScope::PreviousReferencePos(const String& name) const {
   NameReference* ref = FindReference(name);
   if (ref != NULL) {
     return ref->token_pos();
   }
-  return -1;
+  return TokenPosition::kNoSource;
 }
 
 
@@ -328,8 +328,8 @@
         desc.name = &var->name();
         desc.info.set_kind(RawLocalVarDescriptors::kSavedCurrentContext);
         desc.info.scope_id = 0;
-        desc.info.begin_pos = 0;
-        desc.info.end_pos = 0;
+        desc.info.begin_pos = TokenPosition::kMinSource;
+        desc.info.end_pos = TokenPosition::kMinSource;
         desc.info.set_index(var->index());
         vars->Add(desc);
       } else if (!IsFilteredIdentifier(var->name())) {
diff --git a/runtime/vm/scopes.h b/runtime/vm/scopes.h
index e68a244..aaf120d 100644
--- a/runtime/vm/scopes.h
+++ b/runtime/vm/scopes.h
@@ -21,7 +21,7 @@
 
 class LocalVariable : public ZoneAllocated {
  public:
-  LocalVariable(intptr_t token_pos,
+  LocalVariable(TokenPosition token_pos,
                 const String& name,
                 const AbstractType& type)
     : token_pos_(token_pos),
@@ -39,7 +39,7 @@
     ASSERT(name.IsSymbol());
   }
 
-  intptr_t token_pos() const { return token_pos_; }
+  TokenPosition token_pos() const { return token_pos_; }
   const String& name() const { return name_; }
   LocalScope* owner() const { return owner_; }
   void set_owner(LocalScope* owner) {
@@ -109,7 +109,7 @@
  private:
   static const int kUninitializedIndex = INT_MIN;
 
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const String& name_;
   LocalScope* owner_;  // Local scope declaring this variable.
 
@@ -132,16 +132,16 @@
 
 class NameReference : public ZoneAllocated {
  public:
-  NameReference(intptr_t token_pos, const String& name)
+  NameReference(TokenPosition token_pos, const String& name)
     : token_pos_(token_pos),
       name_(name) {
     ASSERT(name.IsSymbol());
   }
   const String& name() const { return name_; }
-  intptr_t token_pos() const { return token_pos_; }
-  void set_token_pos(intptr_t value) { token_pos_ = value; }
+  TokenPosition token_pos() const { return token_pos_; }
+  void set_token_pos(TokenPosition value) { token_pos_ = value; }
  private:
-  intptr_t token_pos_;
+  TokenPosition token_pos_;
   const String& name_;
 };
 
@@ -160,7 +160,7 @@
     kStatement  // Any statement other than the above
   };
 
-  SourceLabel(intptr_t token_pos, const String& name, Kind kind)
+  SourceLabel(TokenPosition token_pos, const String& name, Kind kind)
     : token_pos_(token_pos),
       name_(name),
       owner_(NULL),
@@ -168,7 +168,7 @@
     ASSERT(name.IsSymbol());
   }
 
-  static SourceLabel* New(intptr_t token_pos, String* name, Kind kind) {
+  static SourceLabel* New(TokenPosition token_pos, String* name, Kind kind) {
     if (name != NULL) {
       return new SourceLabel(token_pos, *name, kind);
     } else {
@@ -178,7 +178,7 @@
     }
   }
 
-  intptr_t token_pos() const { return token_pos_; }
+  TokenPosition token_pos() const { return token_pos_; }
   const String& name() const { return name_; }
   LocalScope* owner() const { return owner_; }
   void set_owner(LocalScope* owner) {
@@ -194,7 +194,7 @@
   void ResolveForwardReference() { kind_ = kCase; }
 
  private:
-  const intptr_t token_pos_;
+  const TokenPosition token_pos_;
   const String& name_;
   LocalScope* owner_;  // Local scope declaring this label.
 
@@ -232,11 +232,11 @@
     context_level_ = context_level;
   }
 
-  intptr_t begin_token_pos() const { return begin_token_pos_; }
-  void set_begin_token_pos(intptr_t value) { begin_token_pos_ = value; }
+  TokenPosition begin_token_pos() const { return begin_token_pos_; }
+  void set_begin_token_pos(TokenPosition value) { begin_token_pos_ = value; }
 
-  intptr_t end_token_pos() const { return end_token_pos_; }
-  void set_end_token_pos(intptr_t value) { end_token_pos_ = value; }
+  TokenPosition end_token_pos() const { return end_token_pos_; }
+  void set_end_token_pos(TokenPosition value) { end_token_pos_ = value; }
 
   // The number of variables allocated in the context and belonging to this
   // scope and to its children at the same loop level.
@@ -302,8 +302,8 @@
   // Add a reference to the given name into this scope and the enclosing
   // scopes that do not have a local variable declaration for this name
   // already.
-  void AddReferencedName(intptr_t token_pos, const String& name);
-  intptr_t PreviousReferencePos(const String& name) const;
+  void AddReferencedName(TokenPosition token_pos, const String& name);
+  TokenPosition PreviousReferencePos(const String& name) const;
 
   // Allocate both captured and non-captured variables declared in this scope
   // and in its children scopes of the same function level. Allocating means
@@ -367,8 +367,8 @@
   int loop_level_;      // Reflects the loop nesting level.
   int context_level_;   // Reflects the level of the runtime context.
   int num_context_variables_;   // Only set if this scope is a context owner.
-  intptr_t begin_token_pos_;  // Token index of beginning of scope.
-  intptr_t end_token_pos_;    // Token index of end of scope.
+  TokenPosition begin_token_pos_;  // Token index of beginning of scope.
+  TokenPosition end_token_pos_;    // Token index of end of scope.
   GrowableArray<LocalVariable*> variables_;
   GrowableArray<SourceLabel*> labels_;
 
diff --git a/runtime/vm/scopes_test.cc b/runtime/vm/scopes_test.cc
index 3640937..8dac606 100644
--- a/runtime/vm/scopes_test.cc
+++ b/runtime/vm/scopes_test.cc
@@ -14,18 +14,18 @@
   const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
   const String& a = String::ZoneHandle(Symbols::New("a"));
   LocalVariable* var_a =
-      new LocalVariable(Scanner::kNoSourcePos, a, dynamic_type);
+      new LocalVariable(TokenPosition::kNoSource, a, dynamic_type);
   LocalVariable* inner_var_a =
-      new LocalVariable(Scanner::kNoSourcePos, a, dynamic_type);
+      new LocalVariable(TokenPosition::kNoSource, a, dynamic_type);
   const String& b = String::ZoneHandle(Symbols::New("b"));
   LocalVariable* var_b =
-      new LocalVariable(Scanner::kNoSourcePos, b, dynamic_type);
+      new LocalVariable(TokenPosition::kNoSource, b, dynamic_type);
   const String& c = String::ZoneHandle(Symbols::New("c"));
   LocalVariable* var_c =
-      new LocalVariable(Scanner::kNoSourcePos, c, dynamic_type);
+      new LocalVariable(TokenPosition::kNoSource, c, dynamic_type);
   const String& L = String::ZoneHandle(Symbols::New("L"));
   SourceLabel* label_L =
-      new SourceLabel(Scanner::kNoSourcePos, L, SourceLabel::kFor);
+      new SourceLabel(TokenPosition::kNoSource, L, SourceLabel::kFor);
 
   LocalScope* outer_scope = new LocalScope(NULL, 0, 0);
   LocalScope* inner_scope1 = new LocalScope(outer_scope, 0, 0);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index c533852..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"
@@ -47,6 +49,11 @@
             "The default name of this vm as reported by the VM service "
             "protocol");
 
+DEFINE_FLAG(bool, warn_on_pause_with_no_debugger, false,
+            "Print a message when an isolate is paused but there is no "
+            "debugger attached.");
+
+#ifndef PRODUCT
 // The name of this of this vm as reported by the VM service protocol.
 static char* vm_name = NULL;
 
@@ -142,6 +149,8 @@
     }
   }
   if (stream_listen_callback_) {
+    Thread* T = Thread::Current();
+    TransitionVMToNative transition(T);
     return (*stream_listen_callback_)(stream_id);
   }
   return false;
@@ -162,12 +171,15 @@
     }
   }
   if (stream_cancel_callback_) {
+    Thread* T = Thread::Current();
+    TransitionVMToNative transition(T);
     return (*stream_cancel_callback_)(stream_id);
   }
 }
 
 RawObject* Service::RequestAssets() {
   Thread* T = Thread::Current();
+  TransitionVMToNative transition(T);
   Api::Scope api_scope(T);
   if (get_service_assets_callback_ == NULL) {
     return Object::null();
@@ -637,7 +649,6 @@
   // Returns number of elements in the list.  -1 on parse error.
   intptr_t ElementCount(const char* value) const {
     const char* kJsonWhitespaceChars = " \t\r\n";
-
     if (value == NULL) {
       return -1;
     }
@@ -947,11 +958,64 @@
 }
 
 
+static void ReportPauseOnConsole(ServiceEvent* event) {
+  const char* name = event->isolate()->debugger_name();
+  switch (event->kind())  {
+    case ServiceEvent::kPauseStart:
+      OS::PrintErr(
+          "vm-service: isolate '%s' has no debugger attached and is paused at "
+          "start.", name);
+      break;
+    case ServiceEvent::kPauseExit:
+      OS::PrintErr(
+          "vm-service: isolate '%s' has no debugger attached and is paused at "
+          "exit.", name);
+      break;
+    case ServiceEvent::kPauseException:
+      OS::PrintErr(
+          "vm-service: isolate '%s' has no debugger attached and is paused due "
+          "to exception.", name);
+      break;
+    case ServiceEvent::kPauseInterrupted:
+      OS::PrintErr(
+          "vm-service: isolate '%s' has no debugger attached and is paused due "
+          "to interrupt.", name);
+      break;
+    case ServiceEvent::kPauseBreakpoint:
+      OS::PrintErr(
+          "vm-service: isolate '%s' has no debugger attached and is paused.",
+          name);
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+  if (!ServiceIsolate::IsRunning()) {
+    OS::PrintErr("  Start the vm-service to debug.\n");
+  } else if (ServiceIsolate::server_address() == NULL) {
+    OS::PrintErr("  Connect to Observatory to debug.\n");
+  } else {
+    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());
+  }
+}
+
+
 void Service::HandleEvent(ServiceEvent* event) {
   if (event->isolate() != NULL &&
       ServiceIsolate::IsServiceIsolateDescendant(event->isolate())) {
     return;
   }
+  if (FLAG_warn_on_pause_with_no_debugger &&
+      event->IsPause() && !Service::debug_stream.enabled()) {
+    // If we are about to pause a running program which has no
+    // debugger connected, tell the user about it.
+    ReportPauseOnConsole(event);
+  }
   if (!ServiceIsolate::IsRunning()) {
     return;
   }
@@ -2336,24 +2400,22 @@
 }
 
 
-static const char* kCallSitesStr = "CallSites";
+static const char* kCallSitesStr = "_CallSites";
 static const char* kCoverageStr = "Coverage";
+static const char* kPossibleBreakpointsStr = "PossibleBreakpoints";
 
 
 static const char* const report_enum_names[] = {
   kCallSitesStr,
   kCoverageStr,
+  kPossibleBreakpointsStr,
   NULL,
 };
 
 
-static const EnumListParameter* reports_parameter =
-    new EnumListParameter("reports", true, report_enum_names);
-
-
 static const MethodParameter* get_source_report_params[] = {
   RUNNABLE_ISOLATE_PARAMETER,
-  reports_parameter,
+  new EnumListParameter("reports", true, report_enum_names),
   new IdParameter("scriptId", false),
   new UIntParameter("tokenPos", false),
   new UIntParameter("endTokenPos", false),
@@ -2363,7 +2425,14 @@
 
 
 static bool GetSourceReport(Thread* thread, JSONStream* js) {
+  if (!thread->isolate()->compilation_allowed()) {
+    js->PrintError(kFeatureDisabled,
+        "Cannot get source report when running a precompiled program.");
+    return true;
+  }
   const char* reports_str = js->LookupParam("reports");
+  const EnumListParameter* reports_parameter =
+      static_cast<const EnumListParameter*>(get_source_report_params[1]);
   const char** reports = reports_parameter->Parse(thread->zone(), reports_str);
   intptr_t report_set = 0;
   while (*reports != NULL) {
@@ -2371,6 +2440,8 @@
       report_set |= SourceReport::kCallSites;
     } else if (strcmp(*reports, kCoverageStr) == 0) {
       report_set |= SourceReport::kCoverage;
+    } else if (strcmp(*reports, kPossibleBreakpointsStr) == 0) {
+      report_set |= SourceReport::kPossibleBreakpoints;
     }
     reports++;
   }
@@ -2411,7 +2482,10 @@
     }
   }
   SourceReport report(report_set, compile_mode);
-  report.PrintJSON(js, script, start_pos, end_pos);
+  report.PrintJSON(js,
+                   script,
+                   TokenPosition(start_pos),
+                   TokenPosition(end_pos));
   return true;
 }
 
@@ -2566,7 +2640,7 @@
   }
   const Instance& closure = Instance::Cast(obj);
   Breakpoint* bpt =
-      thread->isolate()->debugger()->SetBreakpointAtActivation(closure);
+      thread->isolate()->debugger()->SetBreakpointAtActivation(closure, false);
   if (bpt == NULL) {
     js->PrintError(kCannotAddBreakpoint,
                    "%s: Cannot add breakpoint at activation",
@@ -2794,27 +2868,58 @@
   return false;
 }
 
+static const char* const timeline_streams_enum_names[] = {
+  "all",
+#define DEFINE_NAME(name, unused)                                              \
+  #name,
+ISOLATE_TIMELINE_STREAM_LIST(DEFINE_NAME)
+#undef DEFINE_NAME
+  "VM",
+  NULL
+};
 
-static const MethodParameter* set_vm_timeline_flag_params[] = {
+static const MethodParameter* set_vm_timeline_flags_params[] = {
   NO_ISOLATE_PARAMETER,
-  new MethodParameter("_record", true),
+  new EnumListParameter("recordedStreams",
+                        false,
+                        timeline_streams_enum_names),
   NULL,
 };
 
 
-static bool SetVMTimelineFlag(Thread* thread, JSONStream* js) {
+static bool HasStream(const char** recorded_streams, const char* stream) {
+  while (*recorded_streams != NULL) {
+    if ((strstr(*recorded_streams, "all") != NULL) ||
+        (strstr(*recorded_streams, stream) != NULL)) {
+      return true;
+    }
+    recorded_streams++;
+  }
+  return false;
+}
+
+
+static bool SetVMTimelineFlags(Thread* thread, JSONStream* js) {
+  if (!FLAG_support_timeline) {
+    PrintSuccess(js);
+    return true;
+  }
   Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
   StackZone zone(thread);
 
-  bool recording = strcmp(js->LookupParam("_record"), "all") == 0;
-  Timeline::SetStreamAPIEnabled(recording);
-  Timeline::SetStreamCompilerEnabled(recording);
-  Timeline::SetStreamDartEnabled(recording);
-  Timeline::SetStreamDebuggerEnabled(recording);
-  Timeline::SetStreamEmbedderEnabled(recording);
-  Timeline::SetStreamGCEnabled(recording);
-  Timeline::SetStreamIsolateEnabled(recording);
+  const EnumListParameter* recorded_streams_param =
+      static_cast<const EnumListParameter*>(set_vm_timeline_flags_params[1]);
+
+  const char* recorded_streams_str = js->LookupParam("recordedStreams");
+  const char** recorded_streams =
+      recorded_streams_param->Parse(thread->zone(), recorded_streams_str);
+
+#define SET_ENABLE_STREAM(name, unused)                                        \
+  Timeline::SetStream##name##Enabled(HasStream(recorded_streams, #name));
+ISOLATE_TIMELINE_STREAM_LIST(SET_ENABLE_STREAM);
+#undef SET_ENABLE_STREAM
+  Timeline::SetVMStreamEnabled(HasStream(recorded_streams, "VM"));
 
   PrintSuccess(js);
 
@@ -2822,19 +2927,22 @@
 }
 
 
-static const MethodParameter* get_vm_timeline_flag_params[] = {
+static const MethodParameter* get_vm_timeline_flags_params[] = {
   NO_ISOLATE_PARAMETER,
-  new MethodParameter("_record", false),
   NULL,
 };
 
 
-static bool GetVMTimelineFlag(Thread* thread, JSONStream* js) {
+static bool GetVMTimelineFlags(Thread* thread, JSONStream* js) {
+  if (!FLAG_support_timeline) {
+    JSONObject obj(js);
+    obj.AddProperty("type", "TimelineFlags");
+    return true;
+  }
   Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
   StackZone zone(thread);
-
-  js->PrintError(kFeatureDisabled, "TODO(johnmccutchan)");
+  Timeline::PrintFlagsToJSON(js);
   return true;
 }
 
@@ -2893,14 +3001,14 @@
 static bool Resume(Thread* thread, JSONStream* js) {
   const char* step_param = js->LookupParam("step");
   Isolate* isolate = thread->isolate();
-  if (isolate->message_handler()->paused_on_start()) {
+  if (isolate->message_handler()->is_paused_on_start()) {
     // If the user is issuing a 'Over' or an 'Out' step, that is the
     // same as a regular resume request.
     if ((step_param != NULL) && (strcmp(step_param, "Into") == 0)) {
       isolate->debugger()->EnterSingleStepMode();
     }
-    isolate->message_handler()->set_pause_on_start(false);
-    isolate->set_last_resume_timestamp();
+    isolate->message_handler()->set_should_pause_on_start(false);
+    isolate->SetResumeRequest();
     if (Service::debug_stream.enabled()) {
       ServiceEvent event(isolate, ServiceEvent::kResume);
       Service::HandleEvent(&event);
@@ -2908,8 +3016,9 @@
     PrintSuccess(js);
     return true;
   }
-  if (isolate->message_handler()->paused_on_exit()) {
-    isolate->message_handler()->set_pause_on_exit(false);
+  if (isolate->message_handler()->is_paused_on_exit()) {
+    isolate->message_handler()->set_should_pause_on_exit(false);
+    isolate->SetResumeRequest();
     // We don't send a resume event because we will be exiting.
     PrintSuccess(js);
     return true;
@@ -2922,12 +3031,18 @@
         isolate->debugger()->SetStepOver();
       } else if (strcmp(step_param, "Out") == 0) {
         isolate->debugger()->SetStepOut();
+      } else if (strcmp(step_param, "OverAsyncSuspension") == 0) {
+        if (!isolate->debugger()->SetupStepOverAsyncSuspension()) {
+          js->PrintError(kInvalidParams,
+                         "Isolate must be paused at an async suspension point");
+          return true;
+        }
       } else {
         PrintInvalidParamError(js, "step");
         return true;
       }
     }
-    isolate->Resume();
+    isolate->SetResumeRequest();
     PrintSuccess(js);
     return true;
   }
@@ -3354,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,
@@ -3507,7 +3715,7 @@
   JSONObject jsobj(js);
   jsobj.AddProperty("type", "Version");
   jsobj.AddProperty("major", static_cast<intptr_t>(3));
-  jsobj.AddProperty("minor", static_cast<intptr_t>(0));
+  jsobj.AddProperty("minor", static_cast<intptr_t>(3));
   jsobj.AddProperty("_privateMajor", static_cast<intptr_t>(0));
   jsobj.AddProperty("_privateMinor", static_cast<intptr_t>(0));
   return true;
@@ -3825,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,
@@ -3851,8 +4061,8 @@
     get_vm_metric_list_params },
   { "_getVMTimeline", GetVMTimeline,
     get_vm_timeline_params },
-  { "_getVMTimelineFlag", GetVMTimelineFlag,
-    get_vm_timeline_flag_params },
+  { "_getVMTimelineFlags", GetVMTimelineFlags,
+    get_vm_timeline_flags_params },
   { "pause", Pause,
     pause_params },
   { "removeBreakpoint", RemoveBreakpoint,
@@ -3875,8 +4085,8 @@
     set_trace_class_allocation_params },
   { "setVMName", SetVMName,
     set_vm_name_params },
-  { "_setVMTimelineFlag", SetVMTimelineFlag,
-    set_vm_timeline_flag_params },
+  { "_setVMTimelineFlags", SetVMTimelineFlags,
+    set_vm_timeline_flags_params },
 };
 
 
@@ -3892,5 +4102,6 @@
   return NULL;
 }
 
+#endif  // !PRODUCT
 
 }  // namespace dart
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index 9a719f1..3153563 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1,8 +1,8 @@
-# Dart VM Service Protocol 3.0
+# Dart VM Service Protocol 3.3
 
 > Please post feedback to the [observatory-discuss group][discuss-list]
 
-This document describes of _version 3.0_ of the Dart VM Service Protocol. This
+This document describes of _version 3.3_ of the Dart VM Service Protocol. This
 protocol is used to communicate with a running Dart Virtual Machine.
 
 To use the Service Protocol, start the VM with the *--observe* flag.
@@ -32,6 +32,7 @@
 	- [getFlagList](#getflaglist)
 	- [getIsolate](#getisolate)
 	- [getObject](#getobject)
+	- [getSourceReport](#getsourcereport)
 	- [getStack](#getstack)
 	- [getVersion](#getversion)
 	- [getVM](#getvm)
@@ -77,6 +78,10 @@
 	- [SentinelKind](#sentinelkind)
 	- [Script](#script)
 	- [SourceLocation](#sourcelocation)
+	- [SourceReport](#sourcereport)
+	- [SourceReportCoverage](#sourcereportcoverage)
+	- [SourceReportKind](#sourcereportkind)
+	- [SourceReportRange](#sourcereportrange)
 	- [Stack](#stack)
 	- [StepOption](#stepoption)
 	- [Success](#success)
@@ -551,7 +556,7 @@
 collected, then an [Object](#object) will be returned.
 
 The _offset_ and _count_ parameters are used to request subranges of
-Instance objects with the kinds: List, Map, Uint8ClampedList,
+Instance objects with the kinds: String, List, Map, Uint8ClampedList,
 Uint8List, Uint16List, Uint32List, Uint64List, Int8List, Int16List,
 Int32List, Int64List, Flooat32List, Float64List, Inst32x3List,
 Float32x4List, and Float64x2List.  These parameters are otherwise
@@ -568,6 +573,52 @@
 
 See [Stack](#stack).
 
+### getSourceReport
+
+```
+SourceReport getSourceReport(string isolateId,
+                             SourceReportKind[] reports,
+                             string scriptId [optional],
+                             int tokenPos [optional],
+                             int endTokenPos [optional],
+                             bool forceCompile [optional])
+```
+
+The _getSourceReport_ RPC is used to generate a set of reports tied to
+source locations in an isolate.
+
+The _reports_ parameter is used to specify which reports should be
+generated.  The _reports_ parameter is a list, which allows multiple
+reports to be generated simultaneously from a consistent isolate
+state.  The _reports_ parameter is allowed to be empty (this might be
+used to force compilation of a particular subrange of some script).
+
+The available report kinds are:
+
+report kind | meaning
+----------- | -------
+Coverage | Provide code coverage information
+PossibleBreakpoints | Provide a list of token positions which correspond to possible breakpoints.
+
+The _scriptId_ parameter is used to restrict the report to a
+particular script.  When analyzing a particular script, either or both
+of the _tokenPos_ and _endTokenPos_ parameters may be provided to
+restrict the analysis to a subrange of a script (for example, these
+can be used to restrict the report to the range of a particular class
+or function).
+
+If the _scriptId_ parameter is not provided then the reports are
+generated for all loaded scripts and the _tokenPos_ and _endTokenPos_
+parameters are disallowed.
+
+The _forceCompilation_ parameter can be used to force compilation of
+all functions in the range of the report.  Forcing compilation can
+cause a compilation error, which could terminate the running Dart
+program.  If this parameter is not provided, it is considered to have
+the value _false_.
+
+See [SourceReport](#sourcereport).
+
 ### getVersion
 
 ```
@@ -868,6 +919,10 @@
   // Has this breakpoint been assigned to a specific program location?
   bool resolved;
 
+  // Is this a breakpoint that was added synthetically as part of a step
+  // OverAsyncSuspension resume command?
+  bool isSyntheticAsyncContinuation [optional];
+
   // SourceLocation when breakpoint is resolved, UnresolvedSourceLocation
   // when a breakpoint is not resolved.
   SourceLocation|UnresolvedSourceLocation location;
@@ -1157,6 +1212,13 @@
   //
   // This is provided for the Extension event.
   ExtensionData extensionData [optional];
+
+  // Is the isolate paused at an await, yield, or yield* statement?
+  //
+  // This is provided for the event kinds:
+  //   PauseBreakpoint
+  //   PauseInterrupted
+  bool atAsyncSuspension [optional];
 }
 ```
 
@@ -1420,11 +1482,15 @@
 
   // The valueAsString for String references may be truncated. If so,
   // this property is added with the value 'true'.
+  //
+  // New code should use 'length' and 'count' instead.
   bool valueAsStringIsTruncated [optional];
 
-  // The length of a List or the number of associations in a Map.
+  // The length of a List or the number of associations in a Map or the
+  // number of codeunits in a String.
   //
   // Provided for instance kinds:
+  //   String
   //   List
   //   Map
   //   Uint8ClampedList
@@ -1493,11 +1559,15 @@
 
   // The valueAsString for String references may be truncated. If so,
   // this property is added with the value 'true'.
+  //
+  // New code should use 'length' and 'count' instead.
   bool valueAsStringIsTruncated [optional];
 
-  // The length of a List or the number of associations in a Map.
+  // The length of a List or the number of associations in a Map or the
+  // number of codeunits in a String.
   //
   // Provided for instance kinds:
+  //   String
   //   List
   //   Map
   //   Uint8ClampedList
@@ -1516,10 +1586,11 @@
   //   Float64x2List
   int length [optional];
 
-  // The index of the first element or association returned.
+  // The index of the first element or association or codeunit returned.
   // This is only provided when it is non-zero.
   //
   // Provided for instance kinds:
+  //   String
   //   List
   //   Map
   //   Uint8ClampedList
@@ -1538,10 +1609,11 @@
   //   Float64x2List
   int offset [optional];
 
-  // The number of elements or associations returned.
+  // The number of elements or associations or codeunits returned.
   // This is only provided when it is less than length.
   //
   // Provided for instance kinds:
+  //   String
   //   List
   //   Map
   //   Uint8ClampedList
@@ -1820,6 +1892,9 @@
   // Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
   int startTime;
 
+  // Is the isolate in a runnable state?
+  bool runnable;
+
   // The number of live ports for this isolate.
   int livePorts;
 
@@ -1849,8 +1924,9 @@
   // The current pause on exception mode for this isolate.
   ExceptionPauseMode exceptionPauseMode;
 
-  // The list of service extension RPCs that are registered for this isolate.
-  string[] extensionRPCs;
+  // The list of service extension RPCs that are registered for this isolate,
+  // if any.
+  string[] extensionRPCs [optional];
 }
 ```
 
@@ -2150,6 +2226,97 @@
 The _SourceLocation_ class is used to designate a position or range in
 some script.
 
+### SourceReport
+
+```
+class SourceReport extends Response {
+  // A list of ranges in the program source.  These ranges correspond
+  // to ranges of executable code in the user's program (functions,
+  // methods, constructors, etc.)
+  //
+  // Note that ranges may nest in other ranges, in the case of nested
+  // functions.
+  //
+  // Note that ranges may be duplicated, in the case of mixins.
+  SourceReportRange[] ranges;
+
+  // A list of scripts, referenced by index in the report's ranges.
+  ScriptRef[] scripts;
+}
+```
+
+The _SourceReport_ class represents a set of reports tied to source
+locations in an isolate.
+
+### SourceReportCoverage
+
+```
+class SourceReportCoverage {
+  // A list of token positions in a SourceReportRange which have been
+  // executed.  The list is sorted.
+  int[] hits;
+
+  // A list of token positions in a SourceReportRange which have not been
+  // executed.  The list is sorted.
+  int[] misses;
+}
+```
+
+The _SourceReportCoverage_ class represents coverage information for
+one [SourceReportRange](#sourcereportrange).
+
+Note that _SourceReportCoverage_ does not extend [Response](#response)
+and therefore will not contain a _type_ property.
+
+### SourceReportKind
+
+```
+enum SourceReportKind {
+  // Used to request a code coverage information.
+  Coverage,
+
+  // Used to request a list of token positions of possible breakpoints.
+  PossibleBreakpoints
+}
+```
+
+### SourceReportRange
+
+```
+class SourceReportRange {
+  // An index into the script table of the SourceReport, indicating
+  // which script contains this range of code.
+  int scriptIndex;
+
+  // The token position at which this range begins.
+  int startPos;
+
+  // The token position at which this range ends.  Inclusive.
+  int endPos;
+
+  // Has this range been compiled by the Dart VM?
+  bool compiled;
+
+  // Code coverage information for this range.  Provided only when the
+  // Coverage report has been requested and the range has been
+  // compiled.
+  SourceReportCoverage coverage [optional];
+
+  // Possible breakpoint information for this range, represented as a
+  // sorted list of token positions.  Provided only when the when the
+  // PossibleBreakpoint report has been requested and the range has been
+  // compiled.
+  int[] possibleBreakpoints [optional];
+}
+```
+
+The _SourceReportRange_ class represents a range of executable code
+(function, method, constructor, etc) in the running program.  It is
+part of a [SourceReport](#sourcereport).
+
+Note that _SourceReportRange_ does not extend [Response](#response)
+and therefore will not contain a _type_ property.
+
 ### Stack
 
 ```
@@ -2178,6 +2345,7 @@
 enum StepOption {
   Into,
   Over,
+  OverAsyncSuspension,
   Out
 }
 ```
@@ -2318,6 +2486,8 @@
 1.0 | initial revision
 2.0 | Describe protocol version 2.0.
 3.0 | Describe protocol version 3.0.  Added UnresolvedSourceLocation.  Added Sentinel return to getIsolate.  Add AddedBreakpointWithScriptUri.  Removed Isolate.entry. The type of VM.pid was changed from string to int.  Added VMUpdate events.  Add offset and count parameters to getObject() and offset and count fields to Instance. Added ServiceExtensionAdded event.
-
+3.1 | Add the getSourceReport RPC.  The getObject RPC now accepts offset and count for string objects.  String objects now contain length, offset, and count properties.
+3.2 | Isolate objects now include the runnable bit and many debugger related RPCs will return an error if executed on an isolate before it is runnable.
+3.3 | Pause event now indicates if the isolate is paused at an await, yield, or yield* suspension point via the 'atAsyncSuspension' field. Resume command now supports the step parameter 'OverAsyncSuspension'. A Breakpoint added synthetically by an 'OverAsyncSuspension' resume command identifies itself as such via the 'isSyntheticAsyncContinuation' field.
 
 [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index 92b6f43..2e64c66 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -8,6 +8,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 // Translate from the legacy DebugEvent to a ServiceEvent.
 static ServiceEvent::EventKind TranslateEventKind(
     DebuggerEvent::EventType kind) {
@@ -42,7 +44,6 @@
       top_frame_(NULL),
       extension_rpc_(NULL),
       exception_(NULL),
-      async_continuation_(NULL),
       at_async_jump_(false),
       inspectee_(NULL),
       gc_stats_(NULL),
@@ -65,7 +66,7 @@
       top_frame_(NULL),
       extension_rpc_(NULL),
       exception_(NULL),
-      async_continuation_(NULL),
+      at_async_jump_(false),
       inspectee_(NULL),
       gc_stats_(NULL),
       bytes_(NULL),
@@ -74,7 +75,6 @@
   DebuggerEvent::EventType type = debugger_event->type();
   if (type == DebuggerEvent::kBreakpointReached) {
     set_breakpoint(debugger_event->breakpoint());
-    set_async_continuation(debugger_event->async_continuation());
     set_at_async_jump(debugger_event->at_async_jump());
   }
   if (type == DebuggerEvent::kExceptionThrown) {
@@ -220,9 +220,8 @@
   if (exception() != NULL) {
     jsobj.AddProperty("exception", *(exception()));
   }
-  if (async_continuation() != NULL && !async_continuation()->IsNull()) {
-    jsobj.AddProperty("_asyncContinuation", *(async_continuation()));
-    jsobj.AddProperty("_atAsyncJump", at_async_jump());
+  if (at_async_jump()) {
+    jsobj.AddProperty("atAsyncSuspension", true);
   }
   if (inspectee() != NULL) {
     jsobj.AddProperty("inspectee", *(inspectee()));
@@ -271,4 +270,6 @@
   jsobj->AddPropertyTimeMillis("timestamp", timestamp_);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/service_event.h b/runtime/vm/service_event.h
index ed4153b..e5afb6d 100644
--- a/runtime/vm/service_event.h
+++ b/runtime/vm/service_event.h
@@ -70,6 +70,19 @@
 
   EventKind kind() const { return kind_; }
 
+  bool IsPause() const {
+    switch (kind())  {
+      case kPauseStart:
+      case kPauseExit:
+      case kPauseBreakpoint:
+      case kPauseInterrupted:
+      case kPauseException:
+        return true;
+      default:
+        return false;
+    }
+  }
+
   const char* embedder_kind() const { return embedder_kind_; }
 
   const char* KindAsCString() const;
@@ -121,14 +134,6 @@
     exception_ = exception;
   }
 
-  const Object* async_continuation() const {
-    return async_continuation_;
-  }
-  void set_async_continuation(const Object* closure) {
-    ASSERT(kind_ == kPauseBreakpoint);
-    async_continuation_ = closure;
-  }
-
   bool at_async_jump() const {
     return at_async_jump_;
   }
@@ -190,7 +195,6 @@
   ActivationFrame* top_frame_;
   const String* extension_rpc_;
   const Object* exception_;
-  const Object* async_continuation_;
   bool at_async_jump_;
   const Object* inspectee_;
   const Heap::GCStats* gc_stats_;
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index a316c6c..86c8aab 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -30,6 +30,8 @@
 DEFINE_FLAG(bool, trace_service, false, "Trace VM service requests.");
 DEFINE_FLAG(bool, trace_service_pause_events, false,
             "Trace VM service isolate pause events.");
+DEFINE_FLAG(bool, trace_service_verbose, false,
+            "Provide extra service tracing information.");
 
 static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
   void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
@@ -78,6 +80,18 @@
 Monitor* ServiceIsolate::monitor_ = NULL;
 bool ServiceIsolate::initializing_ = true;
 bool ServiceIsolate::shutting_down_ = false;
+char* ServiceIsolate::server_address_ = NULL;
+
+void ServiceIsolate::SetServerAddress(const char* address) {
+  if (server_address_ != NULL) {
+    free(server_address_);
+    server_address_ = NULL;
+  }
+  if (address == NULL) {
+    return;
+  }
+  server_address_ = strdup(address);
+}
 
 
 bool ServiceIsolate::NameEquals(const char* name) {
@@ -290,8 +304,10 @@
  public:
   virtual void Run() {
     ASSERT(Isolate::Current() == NULL);
+#ifndef PRODUCT
     TimelineDurationScope tds(Timeline::GetVMStream(),
                               "ServiceIsolateStartup");
+#endif  // !PRODUCT
     char* error = NULL;
     Isolate* isolate = NULL;
 
@@ -304,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,
@@ -355,7 +370,7 @@
       StackZone zone(T);
       HandleScope handle_scope(T);
       Error& error = Error::Handle(Z);
-      error = I->object_store()->sticky_error();
+      error = T->sticky_error();
       if (!error.IsNull() && !error.IsUnwindError()) {
         OS::PrintErr("vm-service: Error: %s\n", error.ToErrorCString());
       }
@@ -467,6 +482,10 @@
       ml.Wait();
     }
   }
+  if (server_address_ != NULL) {
+    free(server_address_);
+    server_address_ = NULL;
+  }
 }
 
 
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index a942ec1..1b1a9f6 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -34,6 +34,13 @@
 
   static void BootVmServiceLibrary();
 
+  static void SetServerAddress(const char* address);
+
+  // Returns the server's web address or NULL if none is running.
+  static const char* server_address() {
+    return server_address_;
+  }
+
  private:
   static void KillServiceIsolate();
 
@@ -59,6 +66,7 @@
   static Dart_Port port_;
   static Dart_Port load_port_;
   static Dart_Port origin_;
+  static char* server_address_;
 
   friend class Dart;
   friend class RunServiceTask;
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index dd2c004..b211fb7 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -21,6 +21,8 @@
 // This flag is used in the Service_Flags test below.
 DEFINE_FLAG(bool, service_testing_flag, false, "Comment");
 
+#ifndef PRODUCT
+
 class ServiceTestMessageHandler : public MessageHandler {
  public:
   ServiceTestMessageHandler() : _msg(NULL) {}
@@ -438,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++.
@@ -644,4 +721,6 @@
 
 #endif  // !defined(TARGET_ARCH_ARM64)
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index b65ae80..e5d06c8 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -95,11 +95,11 @@
   bool GetFValue(char* desc, float* value);
   bool GetDValue(char* desc, double* value);
 
-  static intptr_t GetApproximateTokenIndex(const Code& code, uword pc);
+  static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc);
 
   static void PrintDartFrame(uword pc, uword fp, uword sp,
                              const Function& function,
-                             intptr_t token_pos,
+                             TokenPosition token_pos,
                              bool is_optimized,
                              bool is_inlined);
   void PrintBacktrace();
@@ -245,9 +245,9 @@
 }
 
 
-intptr_t SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
-                                                     uword pc) {
-  intptr_t token_pos = -1;
+TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
+                                                            uword pc) {
+  TokenPosition token_pos = TokenPosition::kNoSource;
   uword pc_offset = pc - code.EntryPoint();
   const PcDescriptors& descriptors =
       PcDescriptors::Handle(code.pc_descriptors());
@@ -255,7 +255,7 @@
   while (iter.MoveNext()) {
     if (iter.PcOffset() == pc_offset) {
       return iter.TokenPos();
-    } else if ((token_pos <= 0) && (iter.PcOffset() > pc_offset)) {
+    } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) {
       token_pos = iter.TokenPos();
     }
   }
@@ -265,15 +265,15 @@
 
 void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp,
                                        const Function& function,
-                                       intptr_t token_pos,
+                                       TokenPosition token_pos,
                                        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;
-  if (token_pos >= 0) {
+  if (token_pos.IsReal()) {
     script.GetTokenLocation(token_pos, &line, &column);
   }
   OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd
@@ -407,7 +407,11 @@
       if (Simulator::IsIllegalAddress(last_pc)) {
         OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc);
       } else {
-        Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
+        if (FLAG_support_disassembler) {
+          Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
+        } else {
+          OS::Print("Disassembler not supported in this mode.\n");
+        }
       }
     }
     char* line = ReadLine("sim> ");
@@ -546,7 +550,11 @@
           }
         }
         if ((start > 0) && (end > start)) {
-          Disassembler::Disassemble(start, end);
+          if (FLAG_support_disassembler) {
+            Disassembler::Disassemble(start, end);
+          } else {
+            OS::Print("Disassembler not supported in this mode.\n");
+          }
         } else {
           OS::Print("disasm [<address> [<number_of_instructions>]]\n");
         }
@@ -3603,7 +3611,11 @@
     OS::Print("%" Pu64 " ", icount_);
     const uword start = reinterpret_cast<uword>(instr);
     const uword end = start + Instr::kInstrSize;
-    Disassembler::Disassemble(start, end);
+    if (FLAG_support_disassembler) {
+      Disassembler::Disassemble(start, end);
+    } else {
+      OS::Print("Disassembler not supported in this mode.\n");
+    }
   }
   if (instr->ConditionField() == kSpecialCondition) {
     if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) {
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index e0df115..a19311d 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -95,11 +95,11 @@
   bool GetDValue(char* desc, uint64_t* value);
   bool GetQValue(char* desc, simd_value_t* value);
 
-  static intptr_t GetApproximateTokenIndex(const Code& code, uword pc);
+  static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc);
 
   static void PrintDartFrame(uword pc, uword fp, uword sp,
                              const Function& function,
-                             intptr_t token_pos,
+                             TokenPosition token_pos,
                              bool is_optimized,
                              bool is_inlined);
   void PrintBacktrace();
@@ -263,9 +263,9 @@
 }
 
 
-intptr_t SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
-                                                     uword pc) {
-  intptr_t token_pos = -1;
+TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
+                                                            uword pc) {
+  TokenPosition token_pos = TokenPosition::kNoSource;
   uword pc_offset = pc - code.EntryPoint();
   const PcDescriptors& descriptors =
       PcDescriptors::Handle(code.pc_descriptors());
@@ -273,7 +273,7 @@
   while (iter.MoveNext()) {
     if (iter.PcOffset() == pc_offset) {
       return iter.TokenPos();
-    } else if ((token_pos <= 0) && (iter.PcOffset() > pc_offset)) {
+    } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) {
       token_pos = iter.TokenPos();
     }
   }
@@ -283,15 +283,15 @@
 
 void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp,
                                        const Function& function,
-                                       intptr_t token_pos,
+                                       TokenPosition token_pos,
                                        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;
-  if (token_pos >= 0) {
+  if (token_pos.IsReal()) {
     script.GetTokenLocation(token_pos, &line, &column);
   }
   OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd
@@ -425,7 +425,11 @@
       if (Simulator::IsIllegalAddress(last_pc)) {
         OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc);
       } else {
-        Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
+        if (FLAG_support_disassembler) {
+          Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
+        } else {
+          OS::Print("Disassembler not supported in this mode.\n");
+        }
       }
     }
     char* line = ReadLine("sim> ");
@@ -597,7 +601,11 @@
           }
         }
         if ((start > 0) && (end > start)) {
-          Disassembler::Disassemble(start, end);
+          if (FLAG_support_disassembler) {
+            Disassembler::Disassemble(start, end);
+          } else {
+            OS::Print("Disassembler not supported in this mode.\n");
+          }
         } else {
           OS::Print("disasm [<address> [<number_of_instructions>]]\n");
         }
@@ -1215,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.
@@ -1741,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)) {
@@ -2156,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);
@@ -2163,6 +2207,8 @@
     DecodeLoadStoreRegPair(instr);
   } else if (instr->IsLoadRegLiteralOp()) {
     DecodeLoadRegLiteral(instr);
+  } else if (instr->IsLoadStoreExclusiveOp()) {
+    DecodeLoadStoreExclusive(instr);
   } else {
     UnimplementedInstruction(instr);
   }
@@ -3364,7 +3410,11 @@
     OS::Print("%" Pu64 " ", icount_);
     const uword start = reinterpret_cast<uword>(instr);
     const uword end = start + Instr::kInstrSize;
-    Disassembler::Disassemble(start, end);
+    if (FLAG_support_disassembler) {
+      Disassembler::Disassemble(start, end);
+    } else {
+      OS::Print("Disassembler not supported in this mode.\n");
+    }
   }
 
   if (instr->IsDPImmediateOp()) {
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 f8007ed..074fc8c 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -94,11 +94,11 @@
   bool GetFValue(char* desc, double* value);
   bool GetDValue(char* desc, double* value);
 
-  static intptr_t GetApproximateTokenIndex(const Code& code, uword pc);
+  static TokenPosition GetApproximateTokenIndex(const Code& code, uword pc);
 
   static void PrintDartFrame(uword pc, uword fp, uword sp,
                              const Function& function,
-                             intptr_t token_pos,
+                             TokenPosition token_pos,
                              bool is_optimized,
                              bool is_inlined);
   void PrintBacktrace();
@@ -256,9 +256,9 @@
 }
 
 
-intptr_t SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
+TokenPosition SimulatorDebugger::GetApproximateTokenIndex(const Code& code,
                                                      uword pc) {
-  intptr_t token_pos = -1;
+  TokenPosition token_pos = TokenPosition::kNoSource;
   uword pc_offset = pc - code.EntryPoint();
   const PcDescriptors& descriptors =
       PcDescriptors::Handle(code.pc_descriptors());
@@ -266,7 +266,7 @@
   while (iter.MoveNext()) {
     if (iter.PcOffset() == pc_offset) {
       return iter.TokenPos();
-    } else if ((token_pos <= 0) && (iter.PcOffset() > pc_offset)) {
+    } else if (!token_pos.IsReal() && (iter.PcOffset() > pc_offset)) {
       token_pos = iter.TokenPos();
     }
   }
@@ -276,15 +276,15 @@
 
 void SimulatorDebugger::PrintDartFrame(uword pc, uword fp, uword sp,
                                        const Function& function,
-                                       intptr_t token_pos,
+                                       TokenPosition token_pos,
                                        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;
-  if (token_pos >= 0) {
+  if (token_pos.IsReal()) {
     script.GetTokenLocation(token_pos, &line, &column);
   }
   OS::Print("pc=0x%" Px " fp=0x%" Px " sp=0x%" Px " %s%s (%s:%" Pd
@@ -418,7 +418,11 @@
       if (Simulator::IsIllegalAddress(last_pc)) {
         OS::Print("pc is out of bounds: 0x%" Px "\n", last_pc);
       } else {
-        Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
+        if (FLAG_support_disassembler) {
+          Disassembler::Disassemble(last_pc, last_pc + Instr::kInstrSize);
+        } else {
+          OS::Print("Disassembler not supported in this mode.\n");
+        }
       }
     }
     char* line = ReadLine("sim> ");
@@ -556,7 +560,11 @@
           }
         }
         if ((start > 0) && (end > start)) {
-          Disassembler::Disassemble(start, end);
+          if (FLAG_support_disassembler) {
+            Disassembler::Disassemble(start, end);
+          } else {
+            OS::Print("Disassembler not supported in this mode.\n");
+          }
         } else {
           OS::Print("disasm [<address> [<number_of_instructions>]]\n");
         }
@@ -1165,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.
 }
 
 
@@ -1996,7 +2004,11 @@
     OS::Print("%" Pu64 " ", icount_);
     const uword start = reinterpret_cast<uword>(instr);
     const uword end = start + Instr::kInstrSize;
-    Disassembler::Disassemble(start, end);
+    if (FLAG_support_disassembler) {
+      Disassembler::Disassemble(start, end);
+    } else {
+      OS::Print("Disassembler not supported in this mode.\n");
+    }
   }
 
   switch (instr->OpcodeField()) {
@@ -2157,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());
@@ -2202,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 a57296f..294a90b 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -174,11 +174,13 @@
     const uint8_t* buffer,
     intptr_t size,
     const uint8_t* instructions_buffer,
+    const uint8_t* data_buffer,
     Snapshot::Kind kind,
     ZoneGrowableArray<BackRefNode>* backward_refs,
     Thread* thread)
     : BaseReader(buffer, size),
       instructions_buffer_(instructions_buffer),
+      data_buffer_(data_buffer),
       kind_(kind),
       snapshot_code_(instructions_buffer != NULL),
       thread_(thread),
@@ -208,7 +210,8 @@
       backward_references_(backward_refs),
       instructions_reader_(NULL) {
   if (instructions_buffer != NULL) {
-    instructions_reader_ = new InstructionsReader(instructions_buffer);
+    instructions_reader_ =
+        new InstructionsReader(instructions_buffer, data_buffer);
   }
 }
 
@@ -231,8 +234,8 @@
     return obj.raw();
   } else {
     // An error occurred while reading, return the error object.
-    const Error& err = Error::Handle(isolate()->object_store()->sticky_error());
-    isolate()->object_store()->clear_sticky_error();
+    const Error& err = Error::Handle(thread()->sticky_error());
+    thread()->clear_sticky_error();
     return err.raw();
   }
 }
@@ -480,6 +483,8 @@
     AddBackRef(object_id, result, state);
     cls_ ^= ReadObjectImpl(kAsInlinedObject);
     ASSERT(!cls_.IsNull());
+    // Closure instances are handled by Closure::ReadFrom().
+    ASSERT(!cls_.IsClosureClass());
     instance_size = cls_.instance_size();
     ASSERT(instance_size > 0);
     // Allocate the instance and read in all the fields for the object.
@@ -495,8 +500,7 @@
   }
   if (!as_reference) {
     // Read all the individual fields for inlined objects.
-    intptr_t next_field_offset = Class::IsSignatureClass(cls_.raw())
-        ? Closure::InstanceSize() : cls_.next_field_offset();
+    intptr_t next_field_offset = cls_.next_field_offset();
 
     intptr_t type_argument_field_offset = cls_.type_arguments_field_offset();
     ASSERT(next_field_offset > 0);
@@ -509,7 +513,8 @@
       pobj_ = ReadObjectImpl(read_as_reference);
       result->SetFieldAtOffset(offset, pobj_);
       if ((offset != type_argument_field_offset) &&
-          (kind_ == Snapshot::kMessage)) {
+          (kind_ == Snapshot::kMessage) &&
+          FLAG_use_field_guards) {
         // TODO(fschneider): Consider hoisting these lookups out of the loop.
         // This would involve creating a handle, since cls_ can't be reused
         // across the call to ReadObjectImpl.
@@ -675,8 +680,10 @@
                 kMessageBufferSize,
                 "No full snapshot version found, expected '%s'",
                 Version::SnapshotString());
-    const String& msg = String::Handle(String::New(message_buffer));
-    return ApiError::New(msg);
+    // This can also fail while bringing up the VM isolate, so make sure to
+    // allocate the error message in old space.
+    const String& msg = String::Handle(String::New(message_buffer, Heap::kOld));
+    return ApiError::New(msg, Heap::kOld);
   }
 
   const char* version = reinterpret_cast<const char*>(CurrentBufferAddress());
@@ -781,6 +788,17 @@
 }
 
 
+RawCodeSourceMap* SnapshotReader::NewCodeSourceMap(intptr_t len) {
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT_NO_SAFEPOINT_SCOPE();
+  RawCodeSourceMap* obj = reinterpret_cast<RawCodeSourceMap*>(
+      AllocateUninitialized(kCodeSourceMapCid,
+                            CodeSourceMap::InstanceSize(len)));
+  obj->ptr()->length_ = len;
+  return obj;
+}
+
+
 RawStackmap* SnapshotReader::NewStackmap(intptr_t len) {
   ASSERT(kind_ == Snapshot::kFull);
   ASSERT_NO_SAFEPOINT_SCOPE();
@@ -921,6 +939,11 @@
 }
 
 
+RawFunctionType* SnapshotReader::NewFunctionType() {
+  ALLOC_NEW_OBJECT(FunctionType);
+}
+
+
 RawTypeRef* SnapshotReader::NewTypeRef() {
   ALLOC_NEW_OBJECT(TypeRef);
 }
@@ -946,6 +969,11 @@
 }
 
 
+RawClosure* SnapshotReader::NewClosure() {
+  ALLOC_NEW_OBJECT(Closure);
+}
+
+
 RawClosureData* SnapshotReader::NewClosureData() {
   ALLOC_NEW_OBJECT(ClosureData);
 }
@@ -1107,6 +1135,15 @@
 }
 
 
+int32_t InstructionsWriter::GetObjectOffsetFor(RawObject* raw_object) {
+  intptr_t heap_size = raw_object->Size();
+  intptr_t offset = next_object_offset_;
+  next_object_offset_ += heap_size;
+  objects_.Add(ObjectData(raw_object));
+  return offset;
+}
+
+
 static void EnsureIdentifier(char* label) {
   for (char c = *label; c != '\0'; c = *++label) {
     if (((c >= 'a') && (c <= 'z')) ||
@@ -1130,10 +1167,16 @@
     ASSERT(data.raw_code_ != NULL);
     data.code_ = &Code::Handle(Z, data.raw_code_);
   }
+  for (intptr_t i = 0; i < objects_.length(); i++) {
+    ObjectData& data = objects_[i];
+    data.obj_ = &Object::Handle(Z, data.raw_obj_);
+  }
 
   stream_.Print(".text\n");
   stream_.Print(".globl _kInstructionsSnapshot\n");
-  stream_.Print(".balign %" Pd ", 0\n", OS::kMaxPreferredCodeAlignment);
+  // Start snapshot at page boundary.
+  ASSERT(VirtualMemory::PageSize() >= OS::kMaxPreferredCodeAlignment);
+  stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize());
   stream_.Print("_kInstructionsSnapshot:\n");
 
   // This head also provides the gap to make the instructions snapshot
@@ -1215,6 +1258,42 @@
       }
     }
   }
+#if defined(TARGET_OS_LINUX)
+  stream_.Print(".section .rodata\n");
+#elif defined(TARGET_OS_MACOS)
+  stream_.Print(".const\n");
+#else
+  // Unsupported platform.
+  UNREACHABLE();
+#endif
+  stream_.Print(".globl _kDataSnapshot\n");
+  // Start snapshot at page boundary.
+  stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize());
+  stream_.Print("_kDataSnapshot:\n");
+  WriteWordLiteral(next_object_offset_);  // Data length.
+  COMPILE_ASSERT(OS::kMaxPreferredCodeAlignment >= kObjectAlignment);
+  stream_.Print(".balign %" Pd ", 0\n", OS::kMaxPreferredCodeAlignment);
+
+  for (intptr_t i = 0; i < objects_.length(); i++) {
+    const Object& obj = *objects_[i].obj_;
+    stream_.Print("Precompiled_Obj_%d:\n", i);
+
+    NoSafepointScope no_safepoint;
+    uword start = reinterpret_cast<uword>(obj.raw()) - kHeapObjectTag;
+    uword end = start + obj.raw()->Size();
+
+    // Write object header with the mark and VM heap bits set.
+    uword marked_tags = obj.raw()->ptr()->tags_;
+    marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags);
+    marked_tags = RawObject::MarkBit::update(true, marked_tags);
+    WriteWordLiteral(marked_tags);
+    start += sizeof(uword);
+    for (uword* cursor = reinterpret_cast<uword*>(start);
+         cursor < reinterpret_cast<uword*>(end);
+         cursor++) {
+      WriteWordLiteral(*cursor);
+    }
+  }
 }
 
 
@@ -1224,14 +1303,17 @@
 
   RawInstructions* result =
       reinterpret_cast<RawInstructions*>(
-          reinterpret_cast<uword>(buffer_) + offset + kHeapObjectTag);
+          reinterpret_cast<uword>(instructions_buffer_) +
+          offset + kHeapObjectTag);
 
+#ifdef DEBUG
   uword actual_tags = result->ptr()->tags_;
   if (actual_tags != expected_tags) {
     FATAL2("Instructions tag mismatch: expected %" Pd ", saw %" Pd,
            expected_tags,
            actual_tags);
   }
+#endif
 
   ASSERT(result->IsMarked());
 
@@ -1239,6 +1321,18 @@
 }
 
 
+RawObject* InstructionsReader::GetObjectAt(int32_t offset) {
+  ASSERT(Utils::IsAligned(offset, kWordSize));
+
+  RawObject* result =
+      reinterpret_cast<RawObject*>(
+          reinterpret_cast<uword>(data_buffer_) + offset + kHeapObjectTag);
+  ASSERT(result->IsMarked());
+
+  return result;
+}
+
+
 intptr_t SnapshotReader::LookupInternalClass(intptr_t class_header) {
   // If the header is an object Id, lookup singleton VM classes or classes
   // stored in the object store.
@@ -1389,16 +1483,20 @@
 
 void SnapshotReader::ProcessDeferredCanonicalizations() {
   Type& typeobj = Type::Handle();
+  FunctionType& funtypeobj = FunctionType::Handle();
   TypeArguments& typeargs = TypeArguments::Handle();
   Object& newobj = Object::Handle();
   for (intptr_t i = 0; i < backward_references_->length(); i++) {
     BackRefNode& backref = (*backward_references_)[i];
     if (backref.defer_canonicalization()) {
       Object* objref = backref.reference();
-      // Object should either be an abstract type or a type argument.
+      // Object should either be a type, a function type, or a type argument.
       if (objref->IsType()) {
         typeobj ^= objref->raw();
         newobj = typeobj.Canonicalize();
+      } else if (objref->IsFunctionType()) {
+        funtypeobj ^= objref->raw();
+        newobj = funtypeobj.Canonicalize();
       } else {
         ASSERT(objref->IsTypeArguments());
         typeargs ^= objref->raw();
@@ -1459,10 +1557,12 @@
     const uint8_t* buffer,
     intptr_t size,
     const uint8_t* instructions_buffer,
+    const uint8_t* data_buffer,
     Thread* thread)
       : SnapshotReader(buffer,
                        size,
                        instructions_buffer,
+                       data_buffer,
                        Snapshot::kFull,
                        new ZoneGrowableArray<BackRefNode>(
                            kNumVmIsolateSnapshotReferences),
@@ -1480,6 +1580,7 @@
   }
   ResetBackwardReferenceTable();
   Dart::set_instructions_snapshot_buffer(instructions_buffer_);
+  Dart::set_data_snapshot_buffer(data_buffer_);
 }
 
 
@@ -1531,10 +1632,12 @@
 IsolateSnapshotReader::IsolateSnapshotReader(const uint8_t* buffer,
                                              intptr_t size,
                                              const uint8_t* instructions_buffer,
+                                             const uint8_t* data_buffer,
                                              Thread* thread)
     : SnapshotReader(buffer,
                      size,
                      instructions_buffer,
+                     data_buffer,
                      Snapshot::kFull,
                      new ZoneGrowableArray<BackRefNode>(
                          kNumInitialReferencesInFullSnapshot),
@@ -1554,6 +1657,7 @@
     : SnapshotReader(buffer,
                      size,
                      NULL, /* instructions_buffer */
+                     NULL, /* data_buffer */
                      Snapshot::kScript,
                      new ZoneGrowableArray<BackRefNode>(kNumInitialReferences),
                      thread) {
@@ -1571,6 +1675,7 @@
     : SnapshotReader(buffer,
                      size,
                      NULL, /* instructions_buffer */
+                     NULL, /* data_buffer */
                      Snapshot::kMessage,
                      new ZoneGrowableArray<BackRefNode>(kNumInitialReferences),
                      thread) {
@@ -2057,8 +2162,7 @@
     return true;
   }
 
-  // Now check if it is an object from the VM isolate (NOTE: premarked objects
-  // are considered to be objects in the VM isolate). These objects are shared
+  // Now check if it is an object from the VM isolate. These objects are shared
   // by all isolates.
   if (rawobj->IsVMHeapObject() && HandleVMIsolateObject(rawobj)) {
     return true;
@@ -2321,33 +2425,28 @@
 }
 
 
-RawFunction* SnapshotWriter::IsSerializableClosure(RawClass* cls,
-                                                   RawObject* obj) {
-  if (Class::IsSignatureClass(cls)) {
-    // 'obj' is a closure as its class is a signature class, extract
-    // the function object to check if this closure can be sent in an
-    // isolate message.
-    RawFunction* func = Closure::GetFunction(obj);
-    // We only allow closure of top level methods or static functions in a
-    // class to be sent in isolate messages.
-    if (can_send_any_object() &&
-        Function::IsImplicitStaticClosureFunction(func)) {
-      return func;
-    }
-    // Not a closure of a top level method or static function, throw an
-    // exception as we do not allow these objects to be serialized.
-    HANDLESCOPE(thread());
-
-    const Class& clazz = Class::Handle(zone(), cls);
-    const Function& errorFunc = Function::Handle(zone(), func);
-    ASSERT(!errorFunc.IsNull());
-
-    // All other closures are errors.
-    char* chars = OS::SCreate(thread()->zone(),
-        "Illegal argument in isolate message : (object is a closure - %s %s)",
-        clazz.ToCString(), errorFunc.ToCString());
-    SetWriteException(Exceptions::kArgument, chars);
+RawFunction* SnapshotWriter::IsSerializableClosure(RawClosure* closure) {
+  // Extract the function object to check if this closure
+  // can be sent in an isolate message.
+  RawFunction* func = closure->ptr()->function_;
+  // We only allow closure of top level methods or static functions in a
+  // class to be sent in isolate messages.
+  if (can_send_any_object() &&
+      Function::IsImplicitStaticClosureFunction(func)) {
+    return func;
   }
+  // Not a closure of a top level method or static function, throw an
+  // exception as we do not allow these objects to be serialized.
+  HANDLESCOPE(thread());
+
+  const Function& errorFunc = Function::Handle(zone(), func);
+  ASSERT(!errorFunc.IsNull());
+
+  // All other closures are errors.
+  char* chars = OS::SCreate(thread()->zone(),
+      "Illegal argument in isolate message : (object is a closure - %s)",
+      errorFunc.ToCString());
+  SetWriteException(Exceptions::kArgument, chars);
   return Function::null();
 }
 
@@ -2393,20 +2492,12 @@
                                    intptr_t tags,
                                    intptr_t object_id,
                                    bool as_reference) {
+  // Closure instances are handled by RawClosure::WriteTo().
+  ASSERT(!Class::IsClosureClass(cls));
+
   // Check if the instance has native fields and throw an exception if it does.
   CheckForNativeFields(cls);
 
-  if ((kind() == Snapshot::kMessage) || (kind() == Snapshot::kScript)) {
-    // Check if object is a closure that is serializable, if the object is a
-    // closure that is not serializable this will throw an exception.
-    RawFunction* func = IsSerializableClosure(cls, raw);
-    if (func != Function::null()) {
-      forward_list_->SetState(object_id, kIsSerialized);
-      WriteStaticImplicitClosure(object_id, func, tags);
-      return;
-    }
-  }
-
   // Object is regular dart instance.
   if (as_reference) {
     // Write out the serialization header value for this object.
@@ -2419,8 +2510,7 @@
     // Write out the class information for this object.
     WriteObjectImpl(cls, kAsInlinedObject);
   } else {
-    intptr_t next_field_offset = Class::IsSignatureClass(cls) ?
-        Closure::InstanceSize() :
+    intptr_t next_field_offset =
         cls->ptr()->next_field_offset_in_words_ << kWordSizeLog2;
     ASSERT(next_field_offset > 0);
 
@@ -2472,7 +2562,7 @@
 
 void SnapshotWriter::ThrowException(Exceptions::ExceptionType type,
                                     const char* msg) {
-  object_store()->clear_sticky_error();
+  thread()->clear_sticky_error();
   if (msg != NULL) {
     const String& msg_obj = String::Handle(String::New(msg));
     const Array& args = Array::Handle(Array::New(1));
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 8570a06..978dbd1 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -22,6 +22,7 @@
 class Array;
 class Class;
 class ClassTable;
+class Closure;
 class Code;
 class ExternalTypedData;
 class GrowableObjectArray;
@@ -40,7 +41,9 @@
 class RawBoundedType;
 class RawCapability;
 class RawClass;
+class RawClosure;
 class RawClosureData;
+class RawCodeSourceMap;
 class RawContext;
 class RawContextScope;
 class RawDouble;
@@ -49,6 +52,7 @@
 class RawFloat32x4;
 class RawFloat64x2;
 class RawFunction;
+class RawFunctionType;
 class RawGrowableObjectArray;
 class RawICData;
 class RawImmutableArray;
@@ -117,16 +121,12 @@
 static const intptr_t kInvalidPatchIndex = -1;
 
 
-class SerializedHeaderTag : public BitField<enum SerializedHeaderType,
-                                            0,
-                                            kHeaderTagBits> {
-};
+class SerializedHeaderTag :
+    public BitField<intptr_t, enum SerializedHeaderType, 0, kHeaderTagBits> {};
 
 
-class SerializedHeaderData : public BitField<intptr_t,
-                                             kHeaderTagBits,
-                                             kObjectIdBits> {
-};
+class SerializedHeaderData :
+    public BitField<intptr_t, intptr_t, kHeaderTagBits, kObjectIdBits> {};
 
 
 enum DeserializeState {
@@ -224,6 +224,34 @@
 };
 
 
+class DataSnapshot : ValueObject {
+ public:
+  explicit DataSnapshot(const void* raw_memory)
+    : raw_memory_(raw_memory) {
+    ASSERT(Utils::IsAligned(raw_memory, 2 * kWordSize));  // kObjectAlignment
+  }
+
+  void* data_start() {
+    return reinterpret_cast<void*>(
+        reinterpret_cast<uword>(raw_memory_) + kHeaderSize);
+  }
+
+  uword data_size() {
+    uword snapshot_size = *reinterpret_cast<const uword*>(raw_memory_);
+    return snapshot_size - kHeaderSize;
+  }
+
+  // Header: data length and padding for alignment. We use the same alignment
+  // as for code for now.
+  static const intptr_t kHeaderSize = OS::kMaxPreferredCodeAlignment;
+
+ private:
+  const void* raw_memory_;  // The symbol kDataSnapshot.
+
+  DISALLOW_COPY_AND_ASSIGN(DataSnapshot);
+};
+
+
 class BaseReader {
  public:
   BaseReader(const uint8_t* buffer, intptr_t size) : stream_(buffer, size) {}
@@ -333,17 +361,22 @@
 
 class InstructionsReader : public ZoneAllocated {
  public:
-  explicit InstructionsReader(const uint8_t* buffer)
-    : buffer_(buffer) {
-    ASSERT(buffer != NULL);
-    ASSERT(Utils::IsAligned(reinterpret_cast<uword>(buffer),
+  InstructionsReader(const uint8_t* instructions_buffer,
+                     const uint8_t* data_buffer)
+    : instructions_buffer_(instructions_buffer),
+      data_buffer_(data_buffer) {
+    ASSERT(instructions_buffer != NULL);
+    ASSERT(data_buffer != NULL);
+    ASSERT(Utils::IsAligned(reinterpret_cast<uword>(instructions_buffer),
                             OS::PreferredCodeAlignment()));
   }
 
   RawInstructions* GetInstructionsAt(int32_t offset, uword expected_tags);
+  RawObject* GetObjectAt(int32_t offset);
 
  private:
-  const uint8_t* buffer_;
+  const uint8_t* instructions_buffer_;
+  const uint8_t* data_buffer_;
 
   DISALLOW_COPY_AND_ASSIGN(InstructionsReader);
 };
@@ -412,17 +445,20 @@
   RawDouble* NewDouble(double value);
   RawUnresolvedClass* NewUnresolvedClass();
   RawType* NewType();
+  RawFunctionType* NewFunctionType();
   RawTypeRef* NewTypeRef();
   RawTypeParameter* NewTypeParameter();
   RawBoundedType* NewBoundedType();
   RawMixinAppType* NewMixinAppType();
   RawPatchClass* NewPatchClass();
+  RawClosure* NewClosure();
   RawClosureData* NewClosureData();
   RawRedirectionData* NewRedirectionData();
   RawFunction* NewFunction();
   RawCode* NewCode(intptr_t pointer_offsets_length);
   RawObjectPool* NewObjectPool(intptr_t length);
   RawPcDescriptors* NewPcDescriptors(intptr_t length);
+  RawCodeSourceMap* NewCodeSourceMap(intptr_t length);
   RawLocalVarDescriptors* NewLocalVarDescriptors(intptr_t num_entries);
   RawExceptionHandlers* NewExceptionHandlers(intptr_t num_entries);
   RawStackmap* NewStackmap(intptr_t length);
@@ -453,12 +489,18 @@
     return instructions_reader_->GetInstructionsAt(offset, expected_tags);
   }
 
+  RawObject* GetObjectAt(int32_t offset) {
+    return instructions_reader_->GetObjectAt(offset);
+  }
+
   const uint8_t* instructions_buffer_;
+  const uint8_t* data_buffer_;
 
  protected:
   SnapshotReader(const uint8_t* buffer,
                  intptr_t size,
                  const uint8_t* instructions_buffer,
+                 const uint8_t* data_buffer,
                  Snapshot::Kind kind,
                  ZoneGrowableArray<BackRefNode>* backward_references,
                  Thread* thread);
@@ -558,6 +600,7 @@
   friend class Bigint;
   friend class BoundedType;
   friend class Class;
+  friend class Closure;
   friend class ClosureData;
   friend class Code;
   friend class Context;
@@ -588,6 +631,7 @@
   friend class SubtypeTestCache;
   friend class TokenStream;
   friend class Type;
+  friend class FunctionType;
   friend class TypeArguments;
   friend class TypeParameter;
   friend class TypeRef;
@@ -603,6 +647,7 @@
   VmIsolateSnapshotReader(const uint8_t* buffer,
                           intptr_t size,
                           const uint8_t* instructions_buffer,
+                          const uint8_t* data_buffer,
                           Thread* thread);
   ~VmIsolateSnapshotReader();
 
@@ -618,6 +663,7 @@
   IsolateSnapshotReader(const uint8_t* buffer,
                         intptr_t size,
                         const uint8_t* instructions_buffer,
+                        const uint8_t* data_buffer,
                         Thread* thread);
   ~IsolateSnapshotReader();
 
@@ -806,8 +852,10 @@
                      intptr_t initial_size)
     : stream_(buffer, alloc, initial_size),
       next_offset_(InstructionsSnapshot::kHeaderSize),
+      next_object_offset_(DataSnapshot::kHeaderSize),
       binary_size_(0),
-      instructions_() {
+      instructions_(),
+      objects_() {
     ASSERT(buffer != NULL);
     ASSERT(alloc != NULL);
   }
@@ -819,6 +867,8 @@
 
   int32_t GetOffsetFor(RawInstructions* instructions);
 
+  int32_t GetObjectOffsetFor(RawObject* raw_object);
+
   void SetInstructionsCode(RawInstructions* insns, RawCode* code) {
     for (intptr_t i = 0; i < instructions_.length(); i++) {
       if (instructions_[i].raw_insns_ == insns) {
@@ -846,6 +896,16 @@
     };
   };
 
+  struct ObjectData {
+    explicit ObjectData(RawObject* raw_obj)
+        : raw_obj_(raw_obj) { }
+
+    union {
+      RawObject* raw_obj_;
+      const Object* obj_;
+    };
+  };
+
   void WriteWordLiteral(uword value) {
     // Padding is helpful for comparing the .S with --disassemble.
 #if defined(ARCH_IS_64_BIT)
@@ -858,8 +918,10 @@
 
   WriteStream stream_;
   intptr_t next_offset_;
+  intptr_t next_object_offset_;
   intptr_t binary_size_;
   GrowableArray<InstructionsData> instructions_;
+  GrowableArray<ObjectData> objects_;
 
   DISALLOW_COPY_AND_ASSIGN(InstructionsWriter);
 };
@@ -915,20 +977,27 @@
     return instructions_writer_->GetOffsetFor(instructions);
   }
 
+  int32_t GetObjectId(RawObject* raw) {
+    return instructions_writer_->GetObjectOffsetFor(raw);
+  }
+
   void SetInstructionsCode(RawInstructions* instructions, RawCode* code) {
     return instructions_writer_->SetInstructionsCode(instructions, code);
   }
 
   void WriteFunctionId(RawFunction* func, bool owner_is_class);
 
+  RawFunction* IsSerializableClosure(RawClosure* closure);
+
+  void WriteStaticImplicitClosure(intptr_t object_id,
+                                  RawFunction* func,
+                                  intptr_t tags);
+
  protected:
   bool CheckAndWritePredefinedObject(RawObject* raw);
   bool HandleVMIsolateObject(RawObject* raw);
 
   void WriteClassId(RawClass* cls);
-  void WriteStaticImplicitClosure(intptr_t object_id,
-                                  RawFunction* func,
-                                  intptr_t tags);
   void WriteObjectImpl(RawObject* raw, bool as_reference);
   void WriteMarkedObjectImpl(RawObject* raw,
                              intptr_t tags,
@@ -942,7 +1011,6 @@
                     RawTypeArguments* type_arguments,
                     RawObject* data[],
                     bool as_reference);
-  RawFunction* IsSerializableClosure(RawClass* cls, RawObject* obj);
   RawClass* GetFunctionOwner(RawFunction* func);
   void CheckForNativeFields(RawClass* cls);
   void SetWriteException(Exceptions::ExceptionType type, const char* msg);
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index c67a8ce..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.
@@ -864,7 +862,9 @@
   // the same.
   const TokenStream& expected_tokens = TokenStream::Handle(script.tokens());
   TokenStream::Iterator expected_iterator(
-      expected_tokens, 0, TokenStream::Iterator::kAllTokens);
+      expected_tokens,
+      TokenPosition::kMinSource,
+      TokenStream::Iterator::kAllTokens);
   const String& str = String::Handle(expected_tokens.GenerateSource());
   const String& private_key = String::Handle(expected_tokens.PrivateKey());
   Scanner scanner(str, private_key);
@@ -872,9 +872,11 @@
       TokenStream::Handle(TokenStream::New(scanner.GetStream(),
                                            private_key,
                                            false));
-  expected_iterator.SetCurrentPosition(0);
+  expected_iterator.SetCurrentPosition(TokenPosition::kMinSource);
   TokenStream::Iterator reconstructed_iterator(
-      reconstructed_tokens, 0, TokenStream::Iterator::kAllTokens);
+      reconstructed_tokens,
+      TokenPosition::kMinSource,
+      TokenStream::Iterator::kAllTokens);
   Token::Kind expected_kind = expected_iterator.CurrentTokenKind();
   Token::Kind reconstructed_kind = reconstructed_iterator.CurrentTokenKind();
   String& expected_literal = String::Handle();
@@ -971,8 +973,10 @@
   const ExternalTypedData& serialized_data =
       ExternalTypedData::Handle(serialized_tokens.GetStream());
   EXPECT_EQ(expected_data.Length(), serialized_data.Length());
-  TokenStream::Iterator expected_iterator(expected_tokens, 0);
-  TokenStream::Iterator serialized_iterator(serialized_tokens, 0);
+  TokenStream::Iterator expected_iterator(expected_tokens,
+                                          TokenPosition::kMinSource);
+  TokenStream::Iterator serialized_iterator(serialized_tokens,
+                                            TokenPosition::kMinSource);
   Token::Kind expected_kind = expected_iterator.CurrentTokenKind();
   Token::Kind serialized_kind = serialized_iterator.CurrentTokenKind();
   while (expected_kind != Token::kEOS && serialized_kind != Token::kEOS) {
@@ -995,6 +999,7 @@
 }
 
 
+#if !defined(PRODUCT)  // Uses deferred loading.
 UNIT_TEST_CASE(CanonicalizationInScriptSnapshots) {
   const char* kScriptChars =
       "\n"
@@ -1025,10 +1030,6 @@
 
   bool saved_load_deferred_eagerly_mode = FLAG_load_deferred_eagerly;
   FLAG_load_deferred_eagerly = true;
-  // Workaround until issue 21620 is fixed.
-  // (https://github.com/dart-lang/sdk/issues/21620)
-  bool saved_concurrent_sweep_mode = FLAG_concurrent_sweep;
-  FLAG_concurrent_sweep = false;
   {
     // Start an Isolate, and create a full snapshot of it.
     TestIsolateScope __test_isolate__;
@@ -1045,7 +1046,6 @@
     Dart_ExitScope();
   }
   FLAG_load_deferred_eagerly = saved_load_deferred_eagerly_mode;
-  FLAG_concurrent_sweep = saved_concurrent_sweep_mode;
 
   {
     // Now Create an Isolate using the full snapshot and load the
@@ -1105,6 +1105,7 @@
   free(script_snapshot);
   free(full_snapshot);
 }
+#endif
 
 
 static void IterateScripts(const Library& lib) {
@@ -1120,7 +1121,7 @@
   }
 }
 
-TEST_CASE(GenerateSource) {
+VM_TEST_CASE(GenerateSource) {
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
   const GrowableObjectArray& libs = GrowableObjectArray::Handle(
@@ -1285,6 +1286,9 @@
 }
 
 
+#ifndef PRODUCT
+
+
 UNIT_TEST_CASE(ScriptSnapshot) {
   const char* kLibScriptChars =
       "library dart_import_lib;"
@@ -1341,10 +1345,6 @@
 
   bool saved_load_deferred_eagerly_mode = FLAG_load_deferred_eagerly;
   FLAG_load_deferred_eagerly = true;
-  // Workaround until issue 21620 is fixed.
-  // (https://github.com/dart-lang/sdk/issues/21620)
-  bool saved_concurrent_sweep_mode = FLAG_concurrent_sweep;
-  FLAG_concurrent_sweep = false;
   {
     // Start an Isolate, and create a full snapshot of it.
     TestIsolateScope __test_isolate__;
@@ -1361,7 +1361,6 @@
     Dart_ExitScope();
   }
   FLAG_load_deferred_eagerly = saved_load_deferred_eagerly_mode;
-  FLAG_concurrent_sweep = saved_concurrent_sweep_mode;
 
   // Test for Dart_CreateScriptSnapshot.
   {
@@ -1535,6 +1534,7 @@
     EXPECT(script_snapshot != NULL);
     result = Dart_LoadScriptFromSnapshot(script_snapshot, size);
     EXPECT_VALID(result);
+    Dart_ExitScope();
   }
 
   FLAG_load_deferred_eagerly = saved_load_deferred_eagerly_mode;
@@ -1578,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;
@@ -1630,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;
 
   {
@@ -1655,6 +1655,7 @@
     // Invoke the test_b function.
     result = Dart_Invoke(lib, NewString("test_b"), 0, NULL);
     EXPECT(Dart_IsError(result) == saved_enable_type_checks_mode);
+    Dart_ExitScope();
   }
   Dart_ShutdownIsolate();
   free(full_snapshot);
@@ -1662,6 +1663,9 @@
 }
 
 
+#endif  // !PRODUCT
+
+
 TEST_CASE(IntArrayMessage) {
   StackZone zone(Thread::Current());
   uint8_t* buffer = NULL;
@@ -1841,10 +1845,12 @@
   EXPECT(Dart_IsString(crappy_string_result));
 
   {
-    DARTSCOPE(Thread::Current());
+    Thread* thread = Thread::Current();
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
 
     {
-      StackZone zone(Thread::Current());
+      StackZone zone(thread);
       Smi& smi = Smi::Handle();
       smi ^= Api::UnwrapHandle(smi_result);
       uint8_t* buffer;
@@ -1862,7 +1868,7 @@
       CheckEncodeDecodeMessage(root);
     }
     {
-      StackZone zone(Thread::Current());
+      StackZone zone(thread);
       Bigint& bigint = Bigint::Handle();
       bigint ^= Api::UnwrapHandle(bigint_result);
       uint8_t* buffer;
@@ -1933,7 +1939,8 @@
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(thread);
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     StackZone zone(thread);
     intptr_t buf_len = 0;
     {
@@ -2057,7 +2064,8 @@
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(thread);
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     StackZone zone(thread);
     intptr_t buf_len = 0;
     {
@@ -2296,7 +2304,8 @@
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(thread);
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     StackZone zone(thread);
     intptr_t buf_len = 0;
     {
@@ -2521,7 +2530,8 @@
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(thread);
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     StackZone zone(thread);
     intptr_t buf_len = 0;
     {
@@ -2762,7 +2772,8 @@
   EXPECT_VALID(lib);
 
   {
-    DARTSCOPE(thread);
+    CHECK_API_SCOPE(thread);
+    HANDLESCOPE(thread);
     StackZone zone(thread);
     intptr_t buf_len = 0;
     {
diff --git a/runtime/vm/snapshot_test.dart b/runtime/vm/snapshot_test.dart
index 5457ef5..ad5c8c1 100644
--- a/runtime/vm/snapshot_test.dart
+++ b/runtime/vm/snapshot_test.dart
@@ -1313,11 +1313,8 @@
     // Send objects and receive them back.
     for (int i = 0; i < MessageTest.elms.length; i++) {
       var sentObject = MessageTest.elms[i];
-      // TODO(asiva): remove this local var idx once thew new for-loop
-      // semantics for closures is implemented.
-      var idx = i;
       remote.call(sentObject).then(expectAsync1((var receivedObject) {
-        MessageTest.VerifyObject(idx, receivedObject);
+        MessageTest.VerifyObject(i, receivedObject);
       }));
     }
 
diff --git a/runtime/vm/source_report.cc b/runtime/vm/source_report.cc
index 8c08726..bbd35ab 100644
--- a/runtime/vm/source_report.cc
+++ b/runtime/vm/source_report.cc
@@ -15,16 +15,16 @@
       compile_mode_(compile_mode),
       thread_(NULL),
       script_(NULL),
-      start_pos_(-1),
-      end_pos_(-1),
+      start_pos_(TokenPosition::kNoSource),
+      end_pos_(TokenPosition::kNoSource),
       next_script_index_(0) {
 }
 
 
 void SourceReport::Init(Thread* thread,
                         const Script* script,
-                        intptr_t start_pos,
-                        intptr_t end_pos) {
+                        TokenPosition start_pos,
+                        TokenPosition end_pos) {
   thread_ = thread;
   script_ = script;
   start_pos_ = start_pos;
@@ -46,8 +46,10 @@
       // The function is from the wrong script.
       return true;
     }
-    if (((start_pos_ > 0) && (func.end_token_pos() < start_pos_)) ||
-        ((end_pos_ > 0) && (func.token_pos() > end_pos_))) {
+    if (((start_pos_ > TokenPosition::kMinSource) &&
+         (func.end_token_pos() < start_pos_)) ||
+        ((end_pos_ > TokenPosition::kMinSource) &&
+         (func.token_pos() > end_pos_))) {
       // The function does not intersect with the requested token range.
       return true;
     }
@@ -109,14 +111,14 @@
 
 
 void SourceReport::PrintCallSitesData(JSONObject* jsobj,
-                                      const Function& func,
+                                      const Function& function,
                                       const Code& code) {
-  const intptr_t begin_pos = func.token_pos();
-  const intptr_t end_pos = func.end_token_pos();
+  const TokenPosition begin_pos = function.token_pos();
+  const TokenPosition end_pos = function.end_token_pos();
 
   ZoneGrowableArray<const ICData*>* ic_data_array =
       new(zone()) ZoneGrowableArray<const ICData*>();
-  func.RestoreICDataMap(ic_data_array, false /* clone descriptors */);
+  function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
   const PcDescriptors& descriptors = PcDescriptors::Handle(
       zone(), code.pc_descriptors());
 
@@ -129,7 +131,7 @@
     HANDLESCOPE(thread());
     const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
     if (!ic_data->IsNull()) {
-      const intptr_t token_pos = iter.TokenPos();
+      const TokenPosition token_pos = iter.TokenPos();
       if ((token_pos < begin_pos) || (token_pos > end_pos)) {
         // Does not correspond to a valid source position.
         continue;
@@ -141,14 +143,14 @@
 }
 
 void SourceReport::PrintCoverageData(JSONObject* jsobj,
-                                     const Function& func,
+                                     const Function& function,
                                      const Code& code) {
-  const intptr_t begin_pos = func.token_pos();
-  const intptr_t end_pos = func.end_token_pos();
+  const TokenPosition begin_pos = function.token_pos();
+  const TokenPosition end_pos = function.end_token_pos();
 
   ZoneGrowableArray<const ICData*>* ic_data_array =
       new(zone()) ZoneGrowableArray<const ICData*>();
-  func.RestoreICDataMap(ic_data_array, false /* clone descriptors */);
+  function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
   const PcDescriptors& descriptors = PcDescriptors::Handle(
       zone(), code.pc_descriptors());
 
@@ -156,7 +158,7 @@
   const int kCoverageMiss = 1;
   const int kCoverageHit = 2;
 
-  intptr_t func_length = (end_pos - begin_pos) + 1;
+  intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1;
   GrowableArray<char> coverage(func_length);
   coverage.SetLength(func_length);
   for (int i = 0; i < func_length; i++) {
@@ -170,13 +172,13 @@
     HANDLESCOPE(thread());
     const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
     if (!ic_data->IsNull()) {
-      const intptr_t token_pos = iter.TokenPos();
+      const TokenPosition token_pos = iter.TokenPos();
       if ((token_pos < begin_pos) || (token_pos > end_pos)) {
         // Does not correspond to a valid source position.
         continue;
       }
       intptr_t count = ic_data->AggregateCount();
-      intptr_t token_offset = token_pos - begin_pos;
+      intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
       if (count > 0) {
         coverage[token_offset] = kCoverageHit;
       } else {
@@ -192,7 +194,8 @@
     JSONArray hits(&cov, "hits");
     for (int i = 0; i < func_length; i++) {
       if (coverage[i] == kCoverageHit) {
-        hits.AddValue(begin_pos + i);  // Add the token position of the hit.
+        // Add the token position of the hit.
+        hits.AddValue(begin_pos.Pos() + i);
       }
     }
   }
@@ -200,12 +203,52 @@
     JSONArray misses(&cov, "misses");
     for (int i = 0; i < func_length; i++) {
       if (coverage[i] == kCoverageMiss) {
-        misses.AddValue(begin_pos + i);  // Add the token position of the miss.
+        // Add the token position of the miss.
+        misses.AddValue(begin_pos.Pos() + i);
       }
     }
   }
 }
 
+void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj,
+                                                const Function& func,
+                                                const Code& code) {
+  const uint8_t kSafepointKind = (RawPcDescriptors::kIcCall |
+                                  RawPcDescriptors::kUnoptStaticCall |
+                                  RawPcDescriptors::kRuntimeCall);
+  const TokenPosition begin_pos = func.token_pos();
+  const TokenPosition end_pos = func.end_token_pos();
+
+  const PcDescriptors& descriptors = PcDescriptors::Handle(
+      zone(), code.pc_descriptors());
+
+  intptr_t func_length = (end_pos.Pos() - begin_pos.Pos()) + 1;
+  GrowableArray<char> possible(func_length);
+  possible.SetLength(func_length);
+  for (int i = 0; i < func_length; i++) {
+    possible[i] = false;
+  }
+
+  PcDescriptors::Iterator iter(descriptors, kSafepointKind);
+  while (iter.MoveNext()) {
+    const TokenPosition token_pos = iter.TokenPos();
+    if ((token_pos < begin_pos) || (token_pos > end_pos)) {
+      // Does not correspond to a valid source position.
+      continue;
+    }
+    intptr_t token_offset = token_pos.Pos() - begin_pos.Pos();
+    possible[token_offset] = true;
+  }
+
+  JSONArray bpts(jsobj, "possibleBreakpoints");
+  for (int i = 0; i < func_length; i++) {
+    if (possible[i]) {
+      // Add the token position.
+      bpts.AddValue(begin_pos.Pos() + i);
+    }
+  }
+}
+
 
 void SourceReport::PrintScriptTable(JSONArray* scripts) {
   for (int i = 0; i < script_table_entries_.length(); i++) {
@@ -221,8 +264,8 @@
   }
 
   const Script& script = Script::Handle(zone(), func.script());
-  const intptr_t begin_pos = func.token_pos();
-  const intptr_t end_pos = func.end_token_pos();
+  const TokenPosition begin_pos = func.token_pos();
+  const TokenPosition end_pos = func.end_token_pos();
 
   Code& code = Code::Handle(zone(), func.unoptimized_code());
   if (code.IsNull()) {
@@ -265,6 +308,9 @@
   if (IsReportRequested(kCoverage)) {
     PrintCoverageData(&range, func, code);
   }
+  if (IsReportRequested(kPossibleBreakpoints)) {
+    PrintPossibleBreakpointsData(&range, func, code);
+  }
 }
 
 
@@ -300,7 +346,8 @@
 
 void SourceReport::PrintJSON(JSONStream* js,
                              const Script& script,
-                             intptr_t start_pos, intptr_t end_pos) {
+                             TokenPosition start_pos,
+                             TokenPosition end_pos) {
   Init(Thread::Current(), &script, start_pos, end_pos);
 
   JSONObject report(js);
diff --git a/runtime/vm/source_report.h b/runtime/vm/source_report.h
index 09c8092..77bf6c2 100644
--- a/runtime/vm/source_report.h
+++ b/runtime/vm/source_report.h
@@ -9,6 +9,7 @@
 #include "vm/flags.h"
 #include "vm/hash_map.h"
 #include "vm/object.h"
+#include "vm/token_position.h"
 
 namespace dart {
 
@@ -18,8 +19,9 @@
 class SourceReport {
  public:
   enum ReportKind {
-    kCallSites = 0x1,
-    kCoverage  = 0x2,
+    kCallSites           = 0x1,
+    kCoverage            = 0x2,
+    kPossibleBreakpoints = 0x4,
   };
 
   enum CompileMode {
@@ -37,11 +39,12 @@
   // If script is null, then the report is generated for all scripts
   // in the isolate.
   void PrintJSON(JSONStream* js, const Script& script,
-                 intptr_t start_pos = -1, intptr_t end_pos = -1);
+                 TokenPosition start_pos = TokenPosition::kNoSource,
+                 TokenPosition end_pos = TokenPosition::kNoSource);
 
  private:
   void Init(Thread* thread, const Script* script,
-            intptr_t start_pos, intptr_t end_pos);
+            TokenPosition start_pos, TokenPosition end_pos);
 
   Thread* thread() const { return thread_; }
   Zone* zone() const { return thread_->zone(); }
@@ -55,6 +58,8 @@
                           const Function& func, const Code& code);
   void PrintCoverageData(JSONObject* jsobj,
                          const Function& func, const Code& code);
+  void PrintPossibleBreakpointsData(JSONObject* jsobj,
+                                    const Function& func, const Code& code);
   void PrintScriptTable(JSONArray* jsarr);
 
   void VisitFunction(JSONArray* jsarr, const Function& func);
@@ -97,8 +102,8 @@
   CompileMode compile_mode_;
   Thread* thread_;
   const Script* script_;
-  intptr_t start_pos_;
-  intptr_t end_pos_;
+  TokenPosition start_pos_;
+  TokenPosition end_pos_;
   GrowableArray<ScriptTableEntry> script_table_entries_;
   DirectChainedHashMap<ScriptTableTrait> script_table_;
   intptr_t next_script_index_;
diff --git a/runtime/vm/source_report_test.cc b/runtime/vm/source_report_test.cc
index 0e1bb79..ca02001 100644
--- a/runtime/vm/source_report_test.cc
+++ b/runtime/vm/source_report_test.cc
@@ -8,6 +8,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 static RawObject* ExecuteScript(const char* script) {
   Dart_Handle h_lib = TestCase::LoadTestScript(script, NULL);
   EXPECT_VALID(h_lib);
@@ -458,4 +460,51 @@
       buffer);
 }
 
+
+TEST_CASE(SourceReport_PossibleBreakpoints_Simple) {
+  char buffer[1024];
+  const char* kScript =
+      "helper0() {}\n"
+      "helper1() {}\n"
+      "main() {\n"
+      "  if (true) {\n"
+      "    helper0();\n"
+      "  } else {\n"
+      "    helper1();\n"
+      "  }\n"
+      "}";
+
+  Library& lib = Library::Handle();
+  lib ^= ExecuteScript(kScript);
+  ASSERT(!lib.IsNull());
+  const Script& script = Script::Handle(lib.LookupScript(
+      String::Handle(String::New("test-lib"))));
+
+  SourceReport report(SourceReport::kPossibleBreakpoints);
+  JSONStream js;
+  report.PrintJSON(&js, script);
+  ElideJSONSubstring("classes", js.ToCString(), buffer);
+  ElideJSONSubstring("libraries", buffer, buffer);
+  EXPECT_STREQ(
+      "{\"type\":\"SourceReport\",\"ranges\":["
+
+      // helper0.
+      "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":4,\"compiled\":true,"
+      "\"possibleBreakpoints\":[1,4]},"
+
+      // One range not compiled (helper1).
+      "{\"scriptIndex\":0,\"startPos\":6,\"endPos\":10,\"compiled\":false},"
+
+      // main.
+      "{\"scriptIndex\":0,\"startPos\":12,\"endPos\":39,\"compiled\":true,"
+      "\"possibleBreakpoints\":[13,23,32,39]}],"
+
+      // Only one script in the script table.
+      "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+      "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+      buffer);
+}
+
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 65f7c3b..fb3d8d8 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -240,10 +240,10 @@
 }
 
 
-intptr_t StackFrame::GetTokenPos() const {
+TokenPosition StackFrame::GetTokenPos() const {
   const Code& code = Code::Handle(LookupDartCode());
   if (code.IsNull()) {
-    return -1;  // Stub frames do not have token_pos.
+    return TokenPosition::kNoSource;  // Stub frames do not have token_pos.
   }
   uword pc_offset = pc() - code.EntryPoint();
   const PcDescriptors& descriptors =
@@ -252,10 +252,10 @@
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kAnyKind);
   while (iter.MoveNext()) {
     if (iter.PcOffset() == pc_offset) {
-      return iter.TokenPos();
+      return TokenPosition(iter.TokenPos());
     }
   }
-  return -1;
+  return TokenPosition::kNoSource;
 }
 
 
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index 1c59ccb..2d1b12c 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -82,7 +82,7 @@
                             bool* needs_stacktrace,
                             bool* is_catch_all) const;
   // Returns token_pos of the pc(), or -1 if none exists.
-  intptr_t GetTokenPos() const;
+  TokenPosition GetTokenPos() const;
 
  protected:
   explicit StackFrame(Thread* thread)
diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc
index c5f280a..0a7644b 100644
--- a/runtime/vm/stack_frame_test.cc
+++ b/runtime/vm/stack_frame_test.cc
@@ -16,10 +16,8 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, lazy_dispatchers);
-
 // Unit test for empty stack frame iteration.
-TEST_CASE(EmptyStackFrameIteration) {
+VM_TEST_CASE(EmptyStackFrameIteration) {
   StackFrameIterator iterator(StackFrameIterator::kValidateFrames);
   EXPECT(!iterator.HasNextFrame());
   EXPECT(iterator.NextFrame() == NULL);
@@ -28,7 +26,7 @@
 
 
 // Unit test for empty dart stack frame iteration.
-TEST_CASE(EmptyDartStackFrameIteration) {
+VM_TEST_CASE(EmptyDartStackFrameIteration) {
   DartFrameIterator iterator;
   EXPECT(iterator.NextFrame() == NULL);
   VerifyPointersVisitor::VerifyPointers();
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index ad3c995..6738a25 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -10,6 +10,7 @@
 #include "vm/disassembler.h"
 #include "vm/flags.h"
 #include "vm/object_store.h"
+#include "vm/safepoint.h"
 #include "vm/snapshot.h"
 #include "vm/virtual_memory.h"
 #include "vm/visitor.h"
@@ -45,13 +46,13 @@
 
 
 void StubCode::InitOnce() {
-#if !defined(DART_PRECOMPILED)
+#if !defined(DART_PRECOMPILED_RUNTIME)
   // Generate all the stubs.
   Code& code = Code::Handle();
   VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
 #else
   UNREACHABLE();
-#endif  // DART_PRECOMPILED
+#endif  // DART_PRECOMPILED_RUNTIME
 }
 
 
@@ -120,14 +121,48 @@
     Assembler assembler;
     const char* name = cls.ToCString();
     StubCode::GenerateAllocationStubForClass(&assembler, cls);
-    stub ^= Code::FinalizeCode(name, &assembler, false /* optimized */);
-    stub.set_owner(cls);
-    cls.set_allocation_stub(stub);
-    if (FLAG_disassemble_stubs) {
+
+    if (thread->IsMutatorThread()) {
+      stub ^= Code::FinalizeCode(name, &assembler, false /* optimized */);
+      // Check if background compilation thread has not already added the stub.
+      if (cls.allocation_stub() == Code::null()) {
+        stub.set_owner(cls);
+        cls.set_allocation_stub(stub);
+      }
+    } else {
+      // This part of stub code generation must be at a safepoint.
+      // Stop mutator thread before creating the instruction object and
+      // installing code.
+      // Mutator thread may not run code while we are creating the
+      // instruction object, since the creation of instruction object
+      // changes code page access permissions (makes them temporary not
+      // executable).
+      {
+        SafepointOperationScope safepoint_scope(thread);
+        stub = cls.allocation_stub();
+        // Check if stub was already generated.
+        if (!stub.IsNull()) {
+          return stub.raw();
+        }
+        // Do not Garbage collect during this stage and instead allow the
+        // heap to grow.
+        NoHeapGrowthControlScope no_growth_control;
+        stub ^= Code::FinalizeCode(name, &assembler, false /* optimized */);
+        stub.set_owner(cls);
+        cls.set_allocation_stub(stub);
+      }
+      Isolate* isolate = thread->isolate();
+      if (isolate->heap()->NeedsGarbageCollection()) {
+        isolate->heap()->CollectAllGarbage();
+      }
+    }
+    if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
       LogBlock lb;
       THR_Print("Code for allocation stub '%s': {\n", name);
+#ifndef PRODUCT
       DisassembleToStdout formatter;
       stub.Disassemble(&formatter);
+#endif
       THR_Print("}\n");
       const ObjectPool& object_pool = ObjectPool::Handle(stub.object_pool());
       object_pool.DebugPrint();
@@ -159,7 +194,7 @@
   GenerateStub(&assembler);
   const Code& code = Code::Handle(
       Code::FinalizeCode(name, &assembler, false /* optimized */));
-  if (FLAG_disassemble_stubs) {
+  if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
     LogBlock lb;
     THR_Print("Code for stub '%s': {\n", name);
     DisassembleToStdout formatter;
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 711c901..6b8812e 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -26,9 +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);
-DECLARE_FLAG(bool, support_debugger);
-DECLARE_FLAG(bool, lazy_dispatchers);
 
 // Input parameters:
 //   LR : return address.
@@ -1455,9 +1452,7 @@
   // Pop returned function object into R0.
   // Restore arguments descriptor array and IC data array.
   __ PopList((1 << R0) | (1 << R4) | (1 << R9));
-  if (range_collection_mode == kCollectRanges) {
-    __ RestoreCodePointer();
-  }
+  __ RestoreCodePointer();
   __ LeaveStubFrame();
   Label call_target_function;
   if (!FLAG_lazy_dispatchers) {
@@ -1804,8 +1799,12 @@
   // R3: instance class id.
   // R4: instance type arguments.
   __ SmiTag(R3);
+  __ CompareImmediate(R3, Smi::RawValue(kClosureCid));
+  __ ldr(R3, FieldAddress(R0, Closure::function_offset()), EQ);
+  // R3: instance class id as Smi or function.
   __ Bind(&loop);
-  __ ldr(R9, Address(R2, kWordSize * SubtypeTestCache::kInstanceClassId));
+  __ ldr(R9,
+         Address(R2, kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction));
   __ CompareObject(R9, Object::null_object());
   __ b(&not_found, EQ);
   __ cmp(R9, Operand(R3));
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 0585653..61c3a4b 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -25,9 +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);
-DECLARE_FLAG(bool, support_debugger);
-DECLARE_FLAG(bool, lazy_dispatchers);
 
 // Input parameters:
 //   LR : return address.
@@ -1042,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_.
@@ -1294,10 +1300,6 @@
                           Label* not_smi_or_overflow,
                           bool should_update_result_range) {
   __ Comment("Fast Smi op");
-  if (FLAG_throw_on_javascript_int_overflow) {
-    // The overflow check is more complex than implemented below.
-    return;
-  }
   __ ldr(R0, Address(SP, + 0 * kWordSize));  // Right.
   __ ldr(R1, Address(SP, + 1 * kWordSize));  // Left.
   __ orr(TMP, R0, Operand(R1));
@@ -1520,9 +1522,7 @@
   __ Pop(R0);  // Pop returned function object into R0.
   __ Pop(R5);  // Restore IC Data.
   __ Pop(R4);  // Restore arguments descriptor array.
-  if (range_collection_mode == kCollectRanges) {
-    __ RestoreCodePointer();
-  }
+  __ RestoreCodePointer();
   __ LeaveStubFrame();
   Label call_target_function;
   if (!FLAG_lazy_dispatchers) {
@@ -1865,9 +1865,13 @@
   // R3: instance class id.
   // R4: instance type arguments.
   __ SmiTag(R3);
+  __ CompareImmediate(R3, Smi::RawValue(kClosureCid));
+  __ b(&loop, NE);
+  __ LoadFieldFromOffset(R3, R0, Closure::function_offset());
+  // R3: instance class id as Smi or function.
   __ Bind(&loop);
   __ LoadFromOffset(
-      R5, R2, kWordSize * SubtypeTestCache::kInstanceClassId);
+      R5, R2, kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction);
   __ CompareObject(R5, Object::null_object());
   __ b(&not_found, EQ);
   __ CompareRegisters(R5, R3);
diff --git a/runtime/vm/stub_code_arm64_test.cc b/runtime/vm/stub_code_arm64_test.cc
index eba3949..7cc0b65 100644
--- a/runtime/vm/stub_code_arm64_test.cc
+++ b/runtime/vm/stub_code_arm64_test.cc
@@ -22,14 +22,15 @@
 static Function* CreateFunction(const char* name) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
   owner_class.set_library(lib);
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index 39aa9e6..e7c5bb9 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -22,14 +22,15 @@
 static Function* CreateFunction(const char* name) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
   owner_class.set_library(lib);
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index b6302d3..640f0ec 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -27,9 +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);
-DECLARE_FLAG(bool, support_debugger);
-DECLARE_FLAG(bool, lazy_dispatchers);
 
 #define INT32_SIZEOF(x) static_cast<int32_t>(sizeof(x))
 
@@ -1781,8 +1778,14 @@
   // ECX: instance class id.
   // EBX: instance type arguments.
   __ SmiTag(ECX);
+  __ cmpl(ECX, Immediate(Smi::RawValue(kClosureCid)));
+  __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
+  __ movl(ECX, FieldAddress(EAX, Closure::function_offset()));
+  // ECX: instance class id as Smi or function.
   __ Bind(&loop);
-  __ movl(EDI, Address(EDX, kWordSize * SubtypeTestCache::kInstanceClassId));
+  __ movl(EDI,
+          Address(EDX,
+                  kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction));
   __ cmpl(EDI, raw_null);
   __ j(EQUAL, &not_found, Assembler::kNearJump);
   __ cmpl(EDI, ECX);
diff --git a/runtime/vm/stub_code_ia32_test.cc b/runtime/vm/stub_code_ia32_test.cc
index 1ab200b..a3c20ec 100644
--- a/runtime/vm/stub_code_ia32_test.cc
+++ b/runtime/vm/stub_code_ia32_test.cc
@@ -22,14 +22,15 @@
 static Function* CreateFunction(const char* name) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
   owner_class.set_library(lib);
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kMinSource));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index 58af418..b4965c33 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -25,9 +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);
-DECLARE_FLAG(bool, support_debugger);
-DECLARE_FLAG(bool, lazy_dispatchers);
 
 // Input parameters:
 //   RA : return address.
@@ -1068,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_.
@@ -1556,9 +1559,7 @@
   // Remove the call arguments pushed earlier, including the IC data object
   // and the arguments descriptor array.
   __ addiu(SP, SP, Immediate(num_slots * kWordSize));
-  if (range_collection_mode == kCollectRanges) {
-    __ RestoreCodePointer();
-  }
+  __ RestoreCodePointer();
   __ LeaveStubFrame();
 
   Label call_target_function;
@@ -1943,8 +1944,12 @@
   // T2: Entry start.
   // T7: null.
   __ SmiTag(T0);
+  __ BranchNotEqual(T0, Immediate(Smi::RawValue(kClosureCid)), &loop);
+  __ lw(T0, FieldAddress(A0, Closure::function_offset()));
+  // T0: instance class id as Smi or function.
   __ Bind(&loop);
-  __ lw(T3, Address(T2, kWordSize * SubtypeTestCache::kInstanceClassId));
+  __ lw(T3,
+        Address(T2, kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction));
   __ beq(T3, T7, &not_found);
 
   if (n == 1) {
diff --git a/runtime/vm/stub_code_mips_test.cc b/runtime/vm/stub_code_mips_test.cc
index 512baaf..7f6d177 100644
--- a/runtime/vm/stub_code_mips_test.cc
+++ b/runtime/vm/stub_code_mips_test.cc
@@ -22,14 +22,15 @@
 static Function* CreateFunction(const char* name) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
   owner_class.set_library(lib);
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 39d8dc9..b33ee01 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -26,9 +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);
-DECLARE_FLAG(bool, support_debugger);
-DECLARE_FLAG(bool, lazy_dispatchers);
 
 // Input parameters:
 //   RSP : points to return address.
@@ -1235,10 +1232,6 @@
                           Label* not_smi_or_overflow,
                           bool should_update_result_range) {
   __ Comment("Fast Smi op");
-  if (FLAG_throw_on_javascript_int_overflow) {
-    // The overflow check is more complex than implemented below.
-    return;
-  }
   ASSERT(num_args == 2);
   __ movq(RCX, Address(RSP, + 1 * kWordSize));  // Right
   __ movq(RAX, Address(RSP, + 2 * kWordSize));  // Left.
@@ -1455,9 +1448,7 @@
   __ popq(RAX);  // Pop returned function object into RAX.
   __ popq(RBX);  // Restore IC data array.
   __ popq(R10);  // Restore arguments descriptor array.
-  if (range_collection_mode == kCollectRanges) {
-    __ RestoreCodePointer();
-  }
+  __ RestoreCodePointer();
   __ LeaveStubFrame();
   Label call_target_function;
   if (!FLAG_lazy_dispatchers) {
@@ -1841,8 +1832,14 @@
   // R13: instance type arguments.
   Label loop, found, not_found, next_iteration;
   __ SmiTag(R10);
+  __ cmpq(R10, Immediate(Smi::RawValue(kClosureCid)));
+  __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
+  __ movq(R10, FieldAddress(RAX, Closure::function_offset()));
+  // R10: instance class id as Smi or function.
   __ Bind(&loop);
-  __ movq(RDI, Address(RDX, kWordSize * SubtypeTestCache::kInstanceClassId));
+  __ movq(RDI,
+          Address(RDX,
+                  kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction));
   __ cmpq(RDI, R9);
   __ j(EQUAL, &not_found, Assembler::kNearJump);
   __ cmpq(RDI, R10);
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index ff020e7..b320f60 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -22,14 +22,15 @@
 static Function* CreateFunction(const char* name) {
   const String& class_name = String::Handle(Symbols::New("ownerClass"));
   const Script& script = Script::Handle();
-  const Class& owner_class =
-      Class::Handle(Class::New(class_name, script, Scanner::kNoSourcePos));
+  const Class& owner_class = Class::Handle(
+      Class::New(class_name, script, TokenPosition::kNoSource));
   const Library& lib = Library::Handle(Library::New(class_name));
   owner_class.set_library(lib);
   const String& function_name = String::ZoneHandle(Symbols::New(name));
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, owner_class, 0));
+                    true, false, false, false, false, owner_class,
+                    TokenPosition::kNoSource));
   return &function;
 }
 
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index e984c1b..d35dc6d 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -36,9 +36,6 @@
 #undef DEFINE_KEYWORD_SYMBOL_INDEX
 };
 
-DEFINE_FLAG(bool, dump_symbol_stats, false, "Dump symbol table statistics");
-
-
 RawString* StringFrom(const uint8_t* data, intptr_t len, Heap::Space space) {
   return String::FromLatin1(data, len, space);
 }
@@ -331,6 +328,91 @@
 }
 
 
+intptr_t Symbols::Compact(Isolate* isolate) {
+  ASSERT(isolate != Dart::vm_isolate());
+
+  Zone* zone = Thread::Current()->zone();
+  intptr_t initial_size = -1;
+  intptr_t final_size = -1;
+
+  // 1. Build a collection of all the predefined symbols so they are
+  // strongly referenced (the read only handles are not traced).
+  {
+    SymbolTable table(zone, isolate->object_store()->symbol_table());
+    initial_size = table.NumOccupied();
+
+    if (Object::vm_isolate_snapshot_object_table().Length() == 0) {
+      GrowableObjectArray& predefined_symbols = GrowableObjectArray::Handle(
+          GrowableObjectArray::New(kMaxPredefinedId));
+      String& symbol = String::Handle();
+      for (intptr_t i = 1; i < Symbols::kNullCharId; i++) {
+        const unsigned char* name =
+          reinterpret_cast<const unsigned char*>(names[i]);
+        symbol ^= table.GetOrNull(Latin1Array(name, strlen(names[i])));
+        ASSERT(!symbol.IsNull());
+        predefined_symbols.Add(symbol);
+      }
+      for (intptr_t c = 0; c < kNumberOfOneCharCodeSymbols; c++) {
+        intptr_t idx = (kNullCharId + c);
+        ASSERT(idx < kMaxPredefinedId);
+        ASSERT(Utf::IsLatin1(c));
+        uint8_t ch = static_cast<uint8_t>(c);
+        symbol ^= table.GetOrNull(Latin1Array(&ch, 1));
+        ASSERT(!symbol.IsNull());
+        predefined_symbols.Add(symbol);
+      }
+    }
+    table.Release();
+  }
+
+  // 2. Knock out the symbol table and do a full garbage collection.
+  isolate->object_store()->set_symbol_table(Object::empty_array());
+  isolate->heap()->CollectAllGarbage();
+
+  // 3. Walk the heap and build a new table from surviving symbols.
+  GrowableArray<String*> symbols;
+  class SymbolCollector : public ObjectVisitor {
+   public:
+    SymbolCollector(Thread* thread,
+                    GrowableArray<String*>* symbols)
+        : ObjectVisitor(thread->isolate()),
+          symbols_(symbols),
+          zone_(thread->zone()) {}
+
+    void VisitObject(RawObject* obj) {
+      if (obj->IsString() && obj->IsCanonical()) {
+        symbols_->Add(&String::ZoneHandle(zone_, String::RawCast(obj)));
+      }
+    }
+
+   private:
+    GrowableArray<String*>* symbols_;
+    Zone* zone_;
+  };
+
+  SymbolCollector visitor(Thread::Current(), &symbols);
+  isolate->heap()->IterateObjects(&visitor);
+
+  {
+    Array& array =
+        Array::Handle(HashTables::New<SymbolTable>(symbols.length() * 4 / 3,
+                                                   Heap::kOld));
+    SymbolTable table(zone, array.raw());
+    for (intptr_t i = 0; i < symbols.length(); i++) {
+      String& symbol = *symbols[i];
+      ASSERT(symbol.IsString());
+      ASSERT(symbol.IsCanonical());
+      bool present = table.Insert(symbol);
+      ASSERT(!present);
+    }
+    final_size = table.NumOccupied();
+    isolate->object_store()->set_symbol_table(table.Release());
+  }
+
+  return initial_size - final_size;
+}
+
+
 void Symbols::GetStats(Isolate* isolate, intptr_t* size, intptr_t* capacity) {
   ASSERT(isolate != NULL);
   SymbolTable table(isolate->object_store()->symbol_table());
@@ -482,6 +564,7 @@
     table.Release();
   }
   if (symbol.IsNull()) {
+    SafepointMutexLocker ml(isolate->symbols_mutex());
     SymbolTable table(zone, isolate->object_store()->symbol_table());
     symbol ^= table.InsertNewOrGet(str);
     isolate->object_store()->set_symbol_table(table.Release());
@@ -505,6 +588,7 @@
     table.Release();
   }
   if (symbol.IsNull()) {
+    SafepointMutexLocker ml(isolate->symbols_mutex());
     SymbolTable table(zone, isolate->object_store()->symbol_table());
     symbol ^= table.GetOrNull(str);
     table.Release();
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 1c40fb5..9390ee1 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -34,6 +34,7 @@
   V(Other, "other")                                                            \
   V(Call, "call")                                                              \
   V(Current, "current")                                                        \
+  V(_current, "_current")                                                      \
   V(MoveNext, "moveNext")                                                      \
   V(IsYieldEach, "isYieldEach")                                                \
   V(Value, "value")                                                            \
@@ -55,6 +56,7 @@
   V(_EnumNames, "_enum_names")                                                 \
   V(ExprTemp, ":expr_temp")                                                    \
   V(AnonymousClosure, "<anonymous closure>")                                   \
+  V(AnonymousSignature, "<anonymous signature>")                               \
   V(ImplicitClosure, "<implicit closure>")                                     \
   V(ClosureParameter, ":closure")                                              \
   V(TypeArgumentsParameter, ":type_arguments")                                 \
@@ -135,6 +137,7 @@
   V(Dynamic, "dynamic")                                                        \
   V(UnresolvedClass, "UnresolvedClass")                                        \
   V(Type, "_Type")                                                             \
+  V(FunctionType, "_FunctionType")                                             \
   V(TypeRef, "_TypeRef")                                                       \
   V(TypeParameter, "_TypeParameter")                                           \
   V(BoundedType, "_BoundedType")                                               \
@@ -143,7 +146,7 @@
   V(Patch, "patch")                                                            \
   V(PatchClass, "PatchClass")                                                  \
   V(Function, "Function")                                                      \
-  V(FunctionImpl, "_FunctionImpl")                                             \
+  V(_Closure, "_Closure")                                                      \
   V(FunctionResult, "function result")                                         \
   V(FactoryResult, "factory result")                                           \
   V(ClosureData, "ClosureData")                                                \
@@ -159,6 +162,7 @@
   V(Instructions, "Instructions")                                              \
   V(ObjectPool, "ObjectPool")                                                  \
   V(PcDescriptors, "PcDescriptors")                                            \
+  V(CodeSourceMap, "CodeSourceMap")                                            \
   V(Stackmap, "Stackmap")                                                      \
   V(LocalVarDescriptors, "LocalVarDescriptors")                                \
   V(ExceptionHandlers, "ExceptionHandlers")                                    \
@@ -304,8 +308,6 @@
   V(OutOfMemoryError, "OutOfMemoryError")                                      \
   V(NullThrownError, "NullThrownError")                                        \
   V(IsolateSpawnException, "IsolateSpawnException")                            \
-  V(JavascriptIntegerOverflowError, "_JavascriptIntegerOverflowError")         \
-  V(JavascriptCompatibilityError, "_JavascriptCompatibilityError")             \
   V(BooleanExpression, "boolean expression")                                   \
   V(Malformed, "malformed")                                                    \
   V(Malbounded, "malbounded")                                                  \
@@ -314,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, "  ")                                                           \
@@ -399,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
@@ -419,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
@@ -569,6 +576,11 @@
   // Initialize and setup a symbol table for the isolate.
   static void SetupSymbolTable(Isolate* isolate);
 
+  // Treat the symbol table as weak and collect garbage. Answer the number of
+  // symbols deleted from the symbol table because they where not referenced
+  // from anywhere else.
+  static intptr_t Compact(Isolate* isolate);
+
   // Creates a Symbol given a C string that is assumed to contain
   // UTF-8 encoded characters and '\0' is considered a termination character.
   // TODO(7123) - Rename this to FromCString(....).
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index 0a82be3..c90fe06 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -127,6 +127,9 @@
 
 
 void VMTagCounters::PrintToJSONObject(JSONObject* obj) {
+  if (!FLAG_support_service) {
+    return;
+  }
   {
     JSONArray arr(obj, "names");
     for (intptr_t i = 1; i < VMTag::kNumVMTags; i++) {
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index c220913..c5c6e70 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -24,6 +24,15 @@
 Thread::~Thread() {
   // We should cleanly exit any isolate before destruction.
   ASSERT(isolate_ == NULL);
+  // There should be no top api scopes at this point.
+  ASSERT(api_top_scope() == NULL);
+  // Delete the resusable api scope if there is one.
+  if (api_reusable_scope_) {
+    delete api_reusable_scope_;
+    api_reusable_scope_ = NULL;
+  }
+  delete thread_lock_;
+  thread_lock_ = NULL;
 }
 
 
@@ -41,6 +50,7 @@
 Thread::Thread(Isolate* isolate)
     : BaseThread(false),
       os_thread_(NULL),
+      thread_lock_(new Monitor()),
       isolate_(NULL),
       heap_(NULL),
       zone_(NULL),
@@ -61,8 +71,11 @@
       deopt_id_(0),
       vm_tag_(0),
       pending_functions_(GrowableObjectArray::null()),
+      sticky_error_(Error::null()),
       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
+      safepoint_state_(0),
+      execution_state_(kThreadInVM),
       next_(NULL) {
 #define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value)    \
   member_name = default_init_value;
@@ -172,15 +185,31 @@
 }
 
 
+void Thread::clear_pending_functions() {
+  pending_functions_ = GrowableObjectArray::null();
+}
+
+
+RawError* Thread::sticky_error() const {
+  return sticky_error_;
+}
+
+
+void Thread::set_sticky_error(const Error& value) {
+  ASSERT(!value.IsNull());
+  sticky_error_ = value.raw();
+}
+
+
+void Thread::clear_sticky_error() {
+  sticky_error_ = Error::null();
+}
+
+
 bool Thread::EnterIsolate(Isolate* isolate) {
   const bool kIsMutatorThread = true;
-  const bool kDontBypassSafepoints = false;
-  ThreadRegistry* tr = isolate->thread_registry();
-  Thread* thread = tr->Schedule(
-      isolate, kIsMutatorThread, kDontBypassSafepoints);
+  Thread* thread = isolate->ScheduleThread(kIsMutatorThread);
   if (thread != NULL) {
-    isolate->MakeCurrentThreadMutator(thread);
-    thread->set_vm_tag(VMTag::kVMTagId);
     ASSERT(thread->store_buffer_block_ == NULL);
     thread->StoreBufferAcquire();
     return true;
@@ -191,33 +220,29 @@
 
 void Thread::ExitIsolate() {
   Thread* thread = Thread::Current();
-  ASSERT(thread != NULL);
-  ASSERT(thread->IsMutatorThread());
-#if defined(DEBUG)
-  ASSERT(!thread->IsAnyReusableHandleScopeActive());
-#endif  // DEBUG
+  ASSERT(thread != NULL && thread->IsMutatorThread());
+  DEBUG_ASSERT(!thread->IsAnyReusableHandleScopeActive());
+
+  Isolate* isolate = thread->isolate();
+  ASSERT(isolate != NULL);
+  ASSERT(thread->execution_state() == Thread::kThreadInVM);
   // Clear since GC will not visit the thread once it is unscheduled.
   thread->ClearReusableHandles();
   thread->StoreBufferRelease();
-  Isolate* isolate = thread->isolate();
-  ASSERT(isolate != NULL);
   if (isolate->is_runnable()) {
     thread->set_vm_tag(VMTag::kIdleTagId);
   } else {
     thread->set_vm_tag(VMTag::kLoadWaitTagId);
   }
   const bool kIsMutatorThread = true;
-  const bool kDontBypassSafepoints = false;
-  ThreadRegistry* tr = isolate->thread_registry();
-  tr->Unschedule(thread, kIsMutatorThread, kDontBypassSafepoints);
-  isolate->ClearMutatorThread();
+  isolate->UnscheduleThread(thread, kIsMutatorThread);
 }
 
 
 bool Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) {
   const bool kIsNotMutatorThread = false;
-  ThreadRegistry* tr = isolate->thread_registry();
-  Thread* thread = tr->Schedule(isolate, kIsNotMutatorThread, bypass_safepoint);
+  Thread* thread = isolate->ScheduleThread(kIsNotMutatorThread,
+                                           bypass_safepoint);
   if (thread != NULL) {
     ASSERT(thread->store_buffer_block_ == NULL);
     // TODO(koda): Use StoreBufferAcquire once we properly flush
@@ -236,18 +261,19 @@
   Thread* thread = Thread::Current();
   ASSERT(thread != NULL);
   ASSERT(!thread->IsMutatorThread());
+  ASSERT(thread->execution_state() == Thread::kThreadInVM);
   thread->StoreBufferRelease();
   Isolate* isolate = thread->isolate();
   ASSERT(isolate != NULL);
   const bool kIsNotMutatorThread = false;
-  ThreadRegistry* tr = isolate->thread_registry();
-  tr->Unschedule(thread, kIsNotMutatorThread, bypass_safepoint);
+  isolate->UnscheduleThread(thread, kIsNotMutatorThread, bypass_safepoint);
 }
 
 
 void Thread::PrepareForGC() {
-  ASSERT(isolate()->thread_registry()->AtSafepoint());
+  ASSERT(IsAtSafepoint());
   // Prevent scheduling another GC by ignoring the threshold.
+  ASSERT(store_buffer_block_ != NULL);
   StoreBufferRelease(StoreBuffer::kIgnoreThreshold);
   // Make sure to get an *empty* block; the isolate needs all entries
   // at GC time.
@@ -299,9 +325,7 @@
   // We have non mutator threads grow the heap instead of triggering
   // a garbage collection when they are at a safepoint (e.g: background
   // compiler thread finalizing and installing code at a safepoint).
-  // Note: This code will change once the new Safepoint logic is in place.
-  return (IsMutatorThread() ||
-          (isolate_ != NULL && !isolate_->thread_registry()->AtSafepoint()));
+  return (IsMutatorThread() || IsAtSafepoint());
 }
 
 
@@ -339,11 +363,10 @@
   // Visit objects in thread specific handles area.
   reusable_handles_.VisitObjectPointers(visitor);
 
-  // Visit the pending functions.
-  if (pending_functions_ != GrowableObjectArray::null()) {
-    visitor->VisitPointer(
-        reinterpret_cast<RawObject**>(&pending_functions_));
-  }
+  visitor->VisitPointer(
+      reinterpret_cast<RawObject**>(&pending_functions_));
+  visitor->VisitPointer(
+      reinterpret_cast<RawObject**>(&sticky_error_));
 
   // Visit the api local scope as it has all the api local handles.
   ApiLocalScope* scope = api_top_scope_;
@@ -454,6 +477,21 @@
 }
 
 
+void Thread::EnterSafepointUsingLock() {
+  isolate()->safepoint_handler()->EnterSafepointUsingLock(this);
+}
+
+
+void Thread::ExitSafepointUsingLock() {
+  isolate()->safepoint_handler()->ExitSafepointUsingLock(this);
+}
+
+
+void Thread::BlockForSafepoint() {
+  isolate()->safepoint_handler()->BlockForSafepoint(this);
+}
+
+
 DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread)
     : StackResource(thread) {
   if (thread != NULL) {
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index ad073af..2d8531c 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -6,6 +6,9 @@
 #define VM_THREAD_H_
 
 #include "include/dart_api.h"
+#include "platform/assert.h"
+#include "vm/atomic.h"
+#include "vm/bitfield.h"
 #include "vm/globals.h"
 #include "vm/handles.h"
 #include "vm/os_thread.h"
@@ -37,6 +40,7 @@
 class RawBool;
 class RawObject;
 class RawCode;
+class RawError;
 class RawGrowableObjectArray;
 class RawString;
 class RuntimeEntry;
@@ -143,6 +147,9 @@
     os_thread_ = os_thread;
   }
 
+  // Monitor corresponding to this thread.
+  Monitor* thread_lock() const { return thread_lock_; }
+
   // The topmost zone used for allocation in this thread.
   Zone* zone() const { return zone_; }
 
@@ -209,7 +216,9 @@
     return OFFSET_OF(Thread, store_buffer_block_);
   }
 
-  uword top_exit_frame_info() const { return top_exit_frame_info_; }
+  uword top_exit_frame_info() const {
+    return top_exit_frame_info_;
+  }
   static intptr_t top_exit_frame_info_offset() {
     return OFFSET_OF(Thread, top_exit_frame_info_);
   }
@@ -356,6 +365,13 @@
     return OFFSET_OF(Thread, vm_tag_);
   }
 
+  RawGrowableObjectArray* pending_functions();
+  void clear_pending_functions();
+
+  RawError* sticky_error() const;
+  void set_sticky_error(const Error& value);
+  void clear_sticky_error();
+
 #if defined(DEBUG)
 #define REUSABLE_HANDLE_SCOPE_ACCESSORS(object)                                \
   void set_reusable_##object##_handle_scope_active(bool value) {               \
@@ -385,7 +401,120 @@
   REUSABLE_HANDLE_LIST(REUSABLE_HANDLE)
 #undef REUSABLE_HANDLE
 
-  RawGrowableObjectArray* pending_functions();
+  /*
+   * Fields used to support safepointing a thread.
+   *
+   * - Bit 0 of the safepoint_state_ field is used to indicate if the thread is
+   *   already at a safepoint,
+   * - Bit 1 of the safepoint_state_ field is used to indicate if a safepoint
+   *   operation is requested for this thread.
+   * - Bit 2 of the safepoint_state_ field is used to indicate that the thread
+   *   is blocked for the safepoint operation to complete.
+   *
+   * The safepoint execution state (described above) for a thread is stored in
+   * in the execution_state_ field.
+   * Potential execution states a thread could be in:
+   *   kThreadInGenerated - The thread is running jitted dart/stub code.
+   *   kThreadInVM - The thread is running VM code.
+   *   kThreadInNative - The thread is running native code.
+   *   kThreadInBlockedState - The thread is blocked waiting for a resource.
+   */
+  static intptr_t safepoint_state_offset() {
+    return OFFSET_OF(Thread, safepoint_state_);
+  }
+  static bool IsAtSafepoint(uint32_t state) {
+    return AtSafepointField::decode(state);
+  }
+  bool IsAtSafepoint() const {
+    return AtSafepointField::decode(safepoint_state_);
+  }
+  static uint32_t SetAtSafepoint(bool value, uint32_t state) {
+    return AtSafepointField::update(value, state);
+  }
+  void SetAtSafepoint(bool value) {
+    ASSERT(thread_lock()->IsOwnedByCurrentThread());
+    safepoint_state_ = AtSafepointField::update(value, safepoint_state_);
+  }
+  bool IsSafepointRequested() const {
+    return SafepointRequestedField::decode(safepoint_state_);
+  }
+  static uint32_t SetSafepointRequested(bool value, uint32_t state) {
+    return SafepointRequestedField::update(value, state);
+  }
+  uint32_t SetSafepointRequested(bool value) {
+    ASSERT(thread_lock()->IsOwnedByCurrentThread());
+    uint32_t old_state;
+    uint32_t new_state;
+    do {
+      old_state = safepoint_state_;
+      new_state = SafepointRequestedField::update(value, old_state);
+    } while (AtomicOperations::CompareAndSwapUint32(&safepoint_state_,
+                                                    old_state,
+                                                    new_state) != old_state);
+    return old_state;
+  }
+  static bool IsBlockedForSafepoint(uint32_t state) {
+    return BlockedForSafepointField::decode(state);
+  }
+  bool IsBlockedForSafepoint() const {
+    return BlockedForSafepointField::decode(safepoint_state_);
+  }
+  void SetBlockedForSafepoint(bool value) {
+    ASSERT(thread_lock()->IsOwnedByCurrentThread());
+    safepoint_state_ =
+        BlockedForSafepointField::update(value, safepoint_state_);
+  }
+
+  enum ExecutionState {
+    kThreadInVM = 0,
+    kThreadInGenerated,
+    kThreadInNative,
+    kThreadInBlockedState
+  };
+
+  ExecutionState execution_state() const {
+    return static_cast<ExecutionState>(execution_state_);
+  }
+  void set_execution_state(ExecutionState state) {
+    execution_state_ = static_cast<uint32_t>(state);
+  }
+  static intptr_t execution_state_offset() {
+    return OFFSET_OF(Thread, execution_state_);
+  }
+
+  void EnterSafepoint() {
+    // First try a fast update of the thread state to indicate it is at a
+    // safepoint.
+    uint32_t new_state = SetAtSafepoint(true, 0);
+    uword addr = reinterpret_cast<uword>(this) + safepoint_state_offset();
+    if (AtomicOperations::CompareAndSwapUint32(
+            reinterpret_cast<uint32_t*>(addr), 0, new_state) != 0) {
+      // Fast update failed which means we could potentially be in the middle
+      // of a safepoint operation.
+      EnterSafepointUsingLock();
+    }
+  }
+
+  void ExitSafepoint() {
+    // First try a fast update of the thread state to indicate it is not at a
+    // safepoint anymore.
+    uint32_t old_state = SetAtSafepoint(true, 0);
+    uword addr = reinterpret_cast<uword>(this) + safepoint_state_offset();
+    if (AtomicOperations::CompareAndSwapUint32(
+            reinterpret_cast<uint32_t*>(addr), old_state, 0) != old_state) {
+      // Fast update failed which means we could potentially be in the middle
+      // of a safepoint operation.
+      ExitSafepointUsingLock();
+    }
+  }
+
+  void CheckForSafepoint() {
+    if (IsSafepointRequested()) {
+      BlockForSafepoint();
+    }
+  }
+
+  Thread* next() const { return next_; }
 
   // Visit all object pointers.
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -401,6 +530,7 @@
   template<class T> T* AllocateReusableHandle();
 
   OSThread* os_thread_;
+  Monitor* thread_lock_;
   Isolate* isolate_;
   Heap* heap_;
   Zone* zone_;
@@ -424,6 +554,8 @@
   uword vm_tag_;
   RawGrowableObjectArray* pending_functions_;
 
+  RawError* sticky_error_;
+
   // State that is cached in the TLS for fast access in generated code.
 #define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value)      \
   type_name member_name;
@@ -453,6 +585,12 @@
 #undef REUSABLE_HANDLE_SCOPE_VARIABLE
 #endif  // defined(DEBUG)
 
+  class AtSafepointField : public BitField<uint32_t, bool, 0, 1> {};
+  class SafepointRequestedField : public BitField<uint32_t, bool, 1, 1> {};
+  class BlockedForSafepointField : public BitField<uint32_t, bool, 2, 1> {};
+  uint32_t safepoint_state_;
+  uint32_t execution_state_;
+
   Thread* next_;  // Used to chain the thread structures in an isolate.
 
   explicit Thread(Isolate* isolate);
@@ -469,6 +607,13 @@
     top_exit_frame_info_ = top_exit_frame_info;
   }
 
+  void set_safepoint_state(uint32_t value) {
+    safepoint_state_ = value;
+  }
+  void EnterSafepointUsingLock();
+  void ExitSafepointUsingLock();
+  void BlockForSafepoint();
+
   static void SetCurrent(Thread* current) {
     OSThread::SetCurrentTLS(reinterpret_cast<uword>(current));
   }
diff --git a/runtime/vm/thread_barrier.h b/runtime/vm/thread_barrier.h
index 9cc1d97..39c56a8 100644
--- a/runtime/vm/thread_barrier.h
+++ b/runtime/vm/thread_barrier.h
@@ -46,16 +46,20 @@
 //
 class ThreadBarrier {
  public:
-  explicit ThreadBarrier(intptr_t num_threads)
+  explicit ThreadBarrier(intptr_t num_threads,
+                         Monitor* monitor,
+                         Monitor* done_monitor)
     : num_threads_(num_threads),
+      monitor_(monitor),
       remaining_(num_threads),
       parity_(false),
+      done_monitor_(done_monitor),
       done_(false) {
     ASSERT(remaining_ > 0);
   }
 
   void Sync() {
-    MonitorLocker ml(&monitor_);
+    MonitorLocker ml(monitor_);
     ASSERT(remaining_ > 0);
     if (--remaining_ > 0) {
       // I'm not last to arrive; wait until next round.
@@ -75,13 +79,13 @@
   void Exit() {
     bool last = false;
     {
-      MonitorLocker ml(&monitor_);
+      MonitorLocker ml(monitor_);
       ASSERT(remaining_ > 0);
       last = (--remaining_ == 0);
     }
     if (last) {
       // Last one to exit sets done_.
-      MonitorLocker ml(&done_monitor_);
+      MonitorLocker ml(done_monitor_);
       ASSERT(!done_);
       done_ = true;
       // Tell the destructor in case it's already waiting.
@@ -90,7 +94,7 @@
   }
 
   ~ThreadBarrier() {
-    MonitorLocker ml(&done_monitor_);
+    MonitorLocker ml(done_monitor_);
     // Wait for everyone to exit before destroying the monitors.
     while (!done_) {
       ml.Wait();
@@ -101,11 +105,11 @@
  private:
   const intptr_t num_threads_;
 
-  Monitor monitor_;
+  Monitor* monitor_;
   intptr_t remaining_;
   bool parity_;
 
-  Monitor done_monitor_;  // TODO(koda): Try to optimize this away.
+  Monitor* done_monitor_;  // TODO(koda): Try to optimize this away.
   bool done_;
 
   DISALLOW_COPY_AND_ASSIGN(ThreadBarrier);
diff --git a/runtime/vm/thread_barrier_test.cc b/runtime/vm/thread_barrier_test.cc
index 4517e18..7ca11c6 100644
--- a/runtime/vm/thread_barrier_test.cc
+++ b/runtime/vm/thread_barrier_test.cc
@@ -46,14 +46,21 @@
   static const intptr_t kNumTasks = 5;
   static const intptr_t kNumRounds = 500;
 
-  ThreadBarrier barrier(kNumTasks + 1);
-  for (intptr_t i = 0; i < kNumTasks; ++i) {
-    Dart::thread_pool()->Run(new FuzzTask(kNumRounds, &barrier, i + 1));
+  Monitor* monitor = new Monitor();
+  Monitor* monitor_done = new Monitor();
+  {
+    ThreadBarrier barrier(kNumTasks + 1, monitor, monitor_done);
+    for (intptr_t i = 0; i < kNumTasks; ++i) {
+      Dart::thread_pool()->Run(new FuzzTask(kNumRounds, &barrier, i + 1));
+    }
+    for (intptr_t i = 0; i < kNumRounds; ++i) {
+      barrier.Sync();
+    }
+    barrier.Exit();
   }
-  for (intptr_t i = 0; i < kNumRounds; ++i) {
-    barrier.Sync();
-  }
-  barrier.Exit();
+
+  delete monitor_done;
+  delete monitor;
 }
 
 }  // namespace dart
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index 920baf6..e117703 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -11,6 +11,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 // Notes:
 //
 // The ThreadInterrupter interrupts all threads actively running isolates once
@@ -224,4 +226,6 @@
   }
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/thread_interrupter_android.cc b/runtime/vm/thread_interrupter_android.cc
index 6656775..82be148 100644
--- a/runtime/vm/thread_interrupter_android.cc
+++ b/runtime/vm/thread_interrupter_android.cc
@@ -16,6 +16,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 DECLARE_FLAG(bool, thread_interrupter);
 DECLARE_FLAG(bool, trace_thread_interrupter);
 
@@ -64,6 +66,8 @@
   SignalHandler::Remove();
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/thread_interrupter_macos.cc b/runtime/vm/thread_interrupter_macos.cc
index a25c3c2..e46dbc7 100644
--- a/runtime/vm/thread_interrupter_macos.cc
+++ b/runtime/vm/thread_interrupter_macos.cc
@@ -15,6 +15,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 DECLARE_FLAG(bool, thread_interrupter);
 DECLARE_FLAG(bool, trace_thread_interrupter);
 
@@ -61,6 +63,8 @@
   SignalHandler::Remove();
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
 
 #endif  // defined(TARGET_OS_MACOS)
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
index ac613c1..30d6d8b 100644
--- a/runtime/vm/thread_interrupter_win.cc
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -12,6 +12,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 DECLARE_FLAG(bool, thread_interrupter);
 DECLARE_FLAG(bool, trace_thread_interrupter);
 
@@ -115,6 +117,7 @@
   // Nothing to do on Windows.
 }
 
+#endif  // !PRODUCT
 
 }  // namespace dart
 
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_registry.cc b/runtime/vm/thread_registry.cc
index 2d2dee3..111ae57 100644
--- a/runtime/vm/thread_registry.cc
+++ b/runtime/vm/thread_registry.cc
@@ -12,7 +12,7 @@
 ThreadRegistry::~ThreadRegistry() {
   // Go over the free thread list and delete the thread objects.
   {
-    MonitorLocker ml(monitor_);
+    MonitorLocker ml(threads_lock());
     // At this point the active list should be empty.
     ASSERT(active_list_ == NULL);
     // We have cached the mutator thread, delete it.
@@ -27,114 +27,44 @@
   }
 
   // Delete monitor.
-  delete monitor_;
+  delete threads_lock_;
 }
 
 
-void ThreadRegistry::SafepointThreads() {
-  MonitorLocker ml(monitor_);
-  // First wait for any older rounds that are still in progress.
-  while (in_rendezvous_) {
-    // Assert we are not the organizer trying to nest calls to SafepointThreads.
-    ASSERT(remaining_ > 0);
-    CheckSafepointLocked();
-  }
-  // Start a new round.
-  in_rendezvous_ = true;
-  ++round_;  // Overflows after 240+ years @ 10^9 safepoints per second.
-  remaining_ = CountScheduledLocked();
-  Isolate* isolate = Isolate::Current();
-  // We only expect this method to be called from within the isolate itself.
-  ASSERT(isolate->thread_registry() == this);
-  --remaining_;  // Exclude this thread from the count.
-  // Ensure the main mutator will reach a safepoint (could be running Dart).
-  if (!Thread::Current()->IsMutatorThread()) {
-    isolate->ScheduleInterrupts(Isolate::kVMInterrupt);
-  }
-  while (remaining_ > 0) {
-    ml.Wait(Monitor::kNoTimeout);
-  }
-}
-
-
-void ThreadRegistry::ResumeAllThreads() {
-  MonitorLocker ml(monitor_);
-  ASSERT(in_rendezvous_);
-  in_rendezvous_ = false;
-  ml.NotifyAll();
-}
-
-
-Thread* ThreadRegistry::Schedule(Isolate* isolate,
-                                 bool is_mutator,
-                                 bool bypass_safepoint) {
-  MonitorLocker ml(monitor_);
-  // Wait for any rendezvous in progress.
-  while (!bypass_safepoint && in_rendezvous_) {
-    ml.Wait(Monitor::kNoTimeout);
-  }
-  Thread* thread = NULL;
-  OSThread* os_thread = OSThread::Current();
-  if (os_thread != NULL) {
-    ASSERT(isolate->heap() != NULL);
-    // First get a Thread structure. (we special case the mutator thread
-    // by reusing the cached structure, see comment in 'thread_registry.h').
-    if (is_mutator) {
-      if (mutator_thread_ == NULL) {
-        mutator_thread_ = GetThreadFromFreelist(isolate);
-      }
-      thread = mutator_thread_;
-    } else {
-      thread = GetThreadFromFreelist(isolate);
-      ASSERT(thread->api_top_scope() == NULL);
+// Gets a free Thread structure, we special case the mutator thread
+// by reusing the cached structure, see comment in 'thread_registry.h'.
+Thread* ThreadRegistry::GetFreeThreadLocked(Isolate* isolate, bool is_mutator) {
+  ASSERT(threads_lock()->IsOwnedByCurrentThread());
+  Thread* thread;
+  if (is_mutator) {
+    if (mutator_thread_ == NULL) {
+      mutator_thread_ = GetFromFreelistLocked(isolate);
     }
-    // Now add this Thread to the active list for the isolate.
-    AddThreadToActiveList(thread);
-    // Set up other values and set the TLS value.
-    thread->isolate_ = isolate;
-    thread->heap_ = isolate->heap();
-    thread->set_os_thread(os_thread);
-    os_thread->set_thread(thread);
-    Thread::SetCurrent(thread);
-    os_thread->EnableThreadInterrupts();
+    thread = mutator_thread_;
+  } else {
+    thread = GetFromFreelistLocked(isolate);
+    ASSERT(thread->api_top_scope() == NULL);
   }
+  // Now add this Thread to the active list for the isolate.
+  AddToActiveListLocked(thread);
   return thread;
 }
 
 
-void ThreadRegistry::Unschedule(Thread* thread,
-                                bool is_mutator,
-                                bool bypass_safepoint) {
-  MonitorLocker ml(monitor_);
-  OSThread* os_thread = thread->os_thread();
-  ASSERT(os_thread != NULL);
-  os_thread->DisableThreadInterrupts();
-  os_thread->set_thread(NULL);
-  OSThread::SetCurrent(os_thread);
-  thread->isolate_ = NULL;
-  thread->heap_ = NULL;
-  thread->set_os_thread(NULL);
+void ThreadRegistry::ReturnThreadLocked(bool is_mutator, Thread* thread) {
+  ASSERT(threads_lock()->IsOwnedByCurrentThread());
   // Remove thread from the active list for the isolate.
-  RemoveThreadFromActiveList(thread);
-  // Return thread to the free list (we special case the mutator
-  // thread by holding on to it, see comment in 'thread_registry.h').
+  RemoveFromActiveListLocked(thread);
   if (!is_mutator) {
     ASSERT(thread->api_top_scope() == NULL);
-    ReturnThreadToFreelist(thread);
-  }
-  if (!bypass_safepoint && in_rendezvous_) {
-    // Don't wait for this thread.
-    ASSERT(remaining_ > 0);
-    if (--remaining_ == 0) {
-      ml.NotifyAll();
-    }
+    ReturnToFreelistLocked(thread);
   }
 }
 
 
 void ThreadRegistry::VisitObjectPointers(ObjectPointerVisitor* visitor,
                                          bool validate_frames) {
-  MonitorLocker ml(monitor_);
+  MonitorLocker ml(threads_lock());
   Thread* thread = active_list_;
   while (thread != NULL) {
     if (thread->zone() != NULL) {
@@ -155,7 +85,7 @@
 
 
 void ThreadRegistry::PrepareForGC() {
-  MonitorLocker ml(monitor_);
+  MonitorLocker ml(threads_lock());
   Thread* thread = active_list_;
   while (thread != NULL) {
     thread->PrepareForGC();
@@ -164,17 +94,17 @@
 }
 
 
-void ThreadRegistry::AddThreadToActiveList(Thread* thread) {
+void ThreadRegistry::AddToActiveListLocked(Thread* thread) {
   ASSERT(thread != NULL);
-  ASSERT(monitor_->IsOwnedByCurrentThread());
+  ASSERT(threads_lock()->IsOwnedByCurrentThread());
   thread->next_ = active_list_;
   active_list_ = thread;
 }
 
 
-void ThreadRegistry::RemoveThreadFromActiveList(Thread* thread) {
+void ThreadRegistry::RemoveFromActiveListLocked(Thread* thread) {
   ASSERT(thread != NULL);
-  ASSERT(monitor_->IsOwnedByCurrentThread());
+  ASSERT(threads_lock()->IsOwnedByCurrentThread());
   Thread* prev = NULL;
   Thread* current = active_list_;
   while (current != NULL) {
@@ -192,8 +122,8 @@
 }
 
 
-Thread* ThreadRegistry::GetThreadFromFreelist(Isolate* isolate) {
-  ASSERT(monitor_->IsOwnedByCurrentThread());
+Thread* ThreadRegistry::GetFromFreelistLocked(Isolate* isolate) {
+  ASSERT(threads_lock()->IsOwnedByCurrentThread());
   Thread* thread = NULL;
   // Get thread structure from free list or create a new one.
   if (free_list_ == NULL) {
@@ -205,51 +135,15 @@
   return thread;
 }
 
-void ThreadRegistry::ReturnThreadToFreelist(Thread* thread) {
+void ThreadRegistry::ReturnToFreelistLocked(Thread* thread) {
   ASSERT(thread != NULL);
   ASSERT(thread->os_thread_ == NULL);
   ASSERT(thread->isolate_ == NULL);
   ASSERT(thread->heap_ == NULL);
-  ASSERT(monitor_->IsOwnedByCurrentThread());
+  ASSERT(threads_lock()->IsOwnedByCurrentThread());
   // Add thread to the free list.
   thread->next_ = free_list_;
   free_list_ = thread;
 }
 
-
-void ThreadRegistry::CheckSafepointLocked() {
-  int64_t last_round = -1;
-  while (in_rendezvous_) {
-    ASSERT(round_ >= last_round);
-    if (round_ != last_round) {
-      ASSERT((last_round == -1) || (round_ == (last_round + 1)));
-      last_round = round_;
-      // Participate in this round.
-      if (--remaining_ == 0) {
-        // Ensure the organizing thread is notified.
-        // TODO(koda): Use separate condition variables and plain 'Notify'.
-        monitor_->NotifyAll();
-      }
-    }
-    monitor_->Wait(Monitor::kNoTimeout);
-    // Note: Here, round_ is needed to detect and distinguish two cases:
-    // a) The old rendezvous is still in progress, so just keep waiting, or
-    // b) after ResumeAllThreads, another call to SafepointThreads was
-    // made before this thread got a chance to reaquire monitor_, thus this
-    // thread should (again) decrease remaining_ to indicate cooperation in
-    // this new round.
-  }
-}
-
-
-intptr_t ThreadRegistry::CountScheduledLocked() {
-  intptr_t count = 0;
-  Thread* current = active_list_;
-  while (current != NULL) {
-    ++count;
-    current = current->next_;
-  }
-  return count;
-}
-
 }  // namespace dart
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index 555e513..c765a5d 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -18,62 +18,32 @@
 class ThreadRegistry {
  public:
   ThreadRegistry()
-      : monitor_(new Monitor()),
+      : threads_lock_(new Monitor()),
         active_list_(NULL),
         free_list_(NULL),
-        mutator_thread_(NULL),
-        in_rendezvous_(false),
-        remaining_(0),
-        round_(0) {}
-
+        mutator_thread_(NULL) {}
   ~ThreadRegistry();
 
-  Thread* active_list() const { return active_list_; }
-
-  // Bring all threads in this isolate to a safepoint. The caller is
-  // expected to be implicitly at a safepoint. The threads will wait
-  // until ResumeAllThreads is called. First participates in any
-  // already pending rendezvous requested by another thread. Any
-  // thread that tries to enter this isolate during rendezvous will
-  // wait in RestoreStateTo. Nesting is not supported: the caller must
-  // call ResumeAllThreads before making further calls to
-  // SafepointThreads.
-  void SafepointThreads();
-
-  // Unblocks all threads participating in the rendezvous that was organized
-  // by a prior call to SafepointThreads.
-  // TODO(koda): Consider adding a scope helper to avoid omitting this call.
-  void ResumeAllThreads();
-
-  // Indicate that the current thread is at a safepoint, and offer to wait for
-  // any pending rendezvous request (if none, returns immediately).
-  void CheckSafepoint() {
-    MonitorLocker ml(monitor_);
-    CheckSafepointLocked();
-  }
-
-  bool AtSafepoint() const { return in_rendezvous_; }
-  Thread* Schedule(Isolate* isolate, bool is_mutator, bool bypass_safepoint);
-  void Unschedule(Thread* thread, bool is_mutator, bool bypass_safepoint);
   void VisitObjectPointers(ObjectPointerVisitor* visitor, bool validate_frames);
   void PrepareForGC();
 
  private:
-  void AddThreadToActiveList(Thread* thread);
-  void RemoveThreadFromActiveList(Thread* thread);
-  Thread* GetThreadFromFreelist(Isolate* isolate);
-  void ReturnThreadToFreelist(Thread* thread);
+  Thread* active_list() const { return active_list_; }
+  Monitor* threads_lock() const { return threads_lock_; }
 
-  // Note: Lock should be taken before this function is called.
-  void CheckSafepointLocked();
+  Thread* GetFreeThreadLocked(Isolate* isolate, bool is_mutator);
+  void ReturnThreadLocked(bool is_mutator, Thread* thread);
+  void AddToActiveListLocked(Thread* thread);
+  void RemoveFromActiveListLocked(Thread* thread);
+  Thread* GetFromFreelistLocked(Isolate* isolate);
+  void ReturnToFreelistLocked(Thread* thread);
 
-  // Returns the number threads that are scheduled on this isolate.
-  // Note: Lock should be taken before this function is called.
-  intptr_t CountScheduledLocked();
-
-  Monitor* monitor_;  // All access is synchronized through this monitor.
+  // This monitor protects the threads list for an isolate, it is used whenever
+  // we need to iterate over threads (both active and free) in an isolate.
+  Monitor* threads_lock_;
   Thread* active_list_;  // List of active threads in the isolate.
   Thread* free_list_;  // Free list of Thread objects that can be reused.
+
   // TODO(asiva): Currently we treat a mutator thread as a special thread
   // and always schedule execution of Dart code on the same mutator thread
   // object. The ApiLocalScope has been made thread specific but we still
@@ -89,12 +59,8 @@
   // added.
   Thread* mutator_thread_;
 
-  // Safepoint rendezvous state.
-  bool in_rendezvous_;    // A safepoint rendezvous request is in progress.
-  intptr_t remaining_;    // Number of threads yet to reach their safepoint.
-  int64_t round_;         // Counter, to prevent missing updates to remaining_
-                          // (see comments in CheckSafepointLocked).
-
+  friend class Isolate;
+  friend class SafepointHandler;
   DISALLOW_COPY_AND_ASSIGN(ThreadRegistry);
 };
 
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index f619d51..a20d7a4 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -7,8 +7,9 @@
 #include "vm/lockers.h"
 #include "vm/unit_test.h"
 #include "vm/profiler.h"
+#include "vm/safepoint.h"
+#include "vm/stack_frame.h"
 #include "vm/thread_pool.h"
-#include "vm/thread_registry.h"
 
 namespace dart {
 
@@ -44,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;
@@ -172,7 +175,7 @@
 };
 
 
-TEST_CASE(ManyTasksWithZones) {
+VM_TEST_CASE(ManyTasksWithZones) {
   const int kTaskCount = 100;
   Monitor sync[kTaskCount];
   bool done[kTaskCount];
@@ -208,7 +211,7 @@
   Isolate* orig = Thread::Current()->isolate();
   Zone* orig_zone = Thread::Current()->zone();
   char* orig_str = orig_zone->PrintToString("foo");
-  Thread::ExitIsolate();
+  Dart_ExitIsolate();
   // Create and enter a new isolate.
   Dart_CreateIsolate(
       NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
@@ -226,7 +229,7 @@
     EXPECT(zone1 != orig_zone);
   }
   Dart_ShutdownIsolate();
-  Thread::EnterIsolate(orig);
+  Dart_EnterIsolate(reinterpret_cast<Dart_Isolate>(orig));
   // Original zone should be preserved.
   EXPECT_EQ(orig_zone, Thread::Current()->zone());
   EXPECT_STREQ("foo", orig_str);
@@ -244,12 +247,12 @@
   static const intptr_t kTaskCount;
 
   SafepointTestTask(Isolate* isolate,
-                    Mutex* mutex,
+                    Monitor* monitor,
                     intptr_t* expected_count,
                     intptr_t* total_done,
                     intptr_t* exited)
     : isolate_(isolate),
-      mutex_(mutex),
+      monitor_(monitor),
       expected_count_(expected_count),
       total_done_(total_done),
       exited_(exited),
@@ -258,11 +261,11 @@
   virtual void Run() {
     Thread::EnterIsolateAsHelper(isolate_);
     {
-      MutexLocker ml(mutex_);
+      MonitorLocker ml(monitor_);
       ++*expected_count_;
     }
-    for (int i = 0; ; ++i) {
-      Thread* thread = Thread::Current();
+    Thread* thread = Thread::Current();
+    for (int i = reinterpret_cast<intptr_t>(thread); ; ++i) {
       StackZone stack_zone(thread);
       Zone* zone = thread->zone();
       HANDLESCOPE(thread);
@@ -270,23 +273,23 @@
       Smi& smi = Smi::Handle(zone, Smi::New(kUniqueSmi));
       if ((i % 100) != 0) {
         // Usually, we just cooperate.
-        isolate_->thread_registry()->CheckSafepoint();
+        TransitionVMToBlocked transition(thread);
       } else {
         // But occasionally, organize a rendezvous.
-        isolate_->thread_registry()->SafepointThreads();
+        SafepointOperationScope safepoint_scope(thread);
         ObjectCounter counter(isolate_, &smi);
         isolate_->IterateObjectPointers(
             &counter,
             StackFrameIterator::kValidateFrames);
         {
-          MutexLocker ml(mutex_);
+          MonitorLocker ml(monitor_);
           EXPECT_EQ(*expected_count_, counter.count());
         }
         UserTag& tag = UserTag::Handle(zone, isolate_->current_tag());
         if (tag.raw() != isolate_->default_tag()) {
           String& label = String::Handle(zone, tag.label());
           EXPECT(label.Equals("foo"));
-          MutexLocker ml(mutex_);
+          MonitorLocker ml(monitor_);
           if (*expected_count_ == kTaskCount && !local_done_) {
             // Success for the first time! Remember that we are done, and
             // update the total count.
@@ -294,11 +297,10 @@
             ++*total_done_;
           }
         }
-        isolate_->thread_registry()->ResumeAllThreads();
       }
       // Check whether everyone is done.
       {
-        MutexLocker ml(mutex_);
+        MonitorLocker ml(monitor_);
         if (*total_done_ == kTaskCount) {
           // Another task might be at SafepointThreads when resuming. Ensure its
           // expectation reflects reality, since we pop our handles here.
@@ -309,14 +311,15 @@
     }
     Thread::ExitIsolateAsHelper();
     {
-      MutexLocker ml(mutex_);
+      MonitorLocker ml(monitor_);
       ++*exited_;
+      ml.Notify();
     }
   }
 
  private:
   Isolate* isolate_;
-  Mutex* mutex_;
+  Monitor* monitor_;
   intptr_t* expected_count_;  // # copies of kUniqueSmi we expect to visit.
   intptr_t* total_done_;      // # tasks that successfully safepointed once.
   intptr_t* exited_;          // # tasks that are no longer running.
@@ -334,13 +337,13 @@
 // - helpers.
 TEST_CASE(SafepointTestDart) {
   Isolate* isolate = Thread::Current()->isolate();
-  Mutex mutex;
+  Monitor monitor;
   intptr_t expected_count = 0;
   intptr_t total_done = 0;
   intptr_t exited = 0;
   for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
     Dart::thread_pool()->Run(new SafepointTestTask(
-        isolate, &mutex, &expected_count, &total_done, &exited));
+        isolate, &monitor, &expected_count, &total_done, &exited));
   }
   // Run Dart code on the main thread long enough to allow all helpers
   // to get their verification done and exit. Use a specific UserTag
@@ -367,7 +370,10 @@
   EXPECT_VALID(result);
   // Ensure we looped long enough to allow all helpers to succeed and exit.
   {
-    MutexLocker ml(&mutex);
+    MonitorLocker ml(&monitor);
+    while (exited != SafepointTestTask::kTaskCount) {
+      ml.Wait();
+    }
     EXPECT_EQ(SafepointTestTask::kTaskCount, total_done);
     EXPECT_EQ(SafepointTestTask::kTaskCount, exited);
   }
@@ -379,30 +385,27 @@
 // - main thread in VM code,
 // organized by
 // - helpers.
-TEST_CASE(SafepointTestVM) {
+VM_TEST_CASE(SafepointTestVM) {
   Isolate* isolate = thread->isolate();
-  Mutex mutex;
+  Monitor monitor;
   intptr_t expected_count = 0;
   intptr_t total_done = 0;
   intptr_t exited = 0;
   for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
     Dart::thread_pool()->Run(new SafepointTestTask(
-        isolate, &mutex, &expected_count, &total_done, &exited));
+        isolate, &monitor, &expected_count, &total_done, &exited));
   }
   String& label = String::Handle(String::New("foo"));
   UserTag& tag = UserTag::Handle(UserTag::New(label));
   isolate->set_current_tag(tag);
-  while (true) {
-    isolate->thread_registry()->CheckSafepoint();
-    MutexLocker ml(&mutex);
-    if (exited == SafepointTestTask::kTaskCount) {
-      break;
-    }
+  MonitorLocker ml(&monitor);
+  while (exited != SafepointTestTask::kTaskCount) {
+    ml.WaitWithSafepointCheck(thread);
   }
 }
 
 
-TEST_CASE(ThreadIterator_Count) {
+VM_TEST_CASE(ThreadIterator_Count) {
   intptr_t thread_count_0 = 0;
   intptr_t thread_count_1 = 0;
 
@@ -430,7 +433,7 @@
 }
 
 
-TEST_CASE(ThreadIterator_FindSelf) {
+VM_TEST_CASE(ThreadIterator_FindSelf) {
   OSThread* current = OSThread::Current();
   EXPECT(OSThread::IsThreadInList(current->join_id()));
 }
@@ -490,36 +493,32 @@
 // organized by
 // - main thread, and
 // - helpers.
-TEST_CASE(SafepointTestVM2) {
+VM_TEST_CASE(SafepointTestVM2) {
   Isolate* isolate = thread->isolate();
-  Mutex mutex;
+  Monitor monitor;
   intptr_t expected_count = 0;
   intptr_t total_done = 0;
   intptr_t exited = 0;
   for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
     Dart::thread_pool()->Run(new SafepointTestTask(
-        isolate, &mutex, &expected_count, &total_done, &exited));
+        isolate, &monitor, &expected_count, &total_done, &exited));
   }
   bool all_helpers = false;
   do {
-    isolate->thread_registry()->SafepointThreads();
+    SafepointOperationScope safepoint_scope(thread);
     {
-      MutexLocker ml(&mutex);
+      MonitorLocker ml(&monitor);
       if (expected_count == SafepointTestTask::kTaskCount) {
         all_helpers = true;
       }
     }
-    isolate->thread_registry()->ResumeAllThreads();
   } while (!all_helpers);
   String& label = String::Handle(String::New("foo"));
   UserTag& tag = UserTag::Handle(UserTag::New(label));
   isolate->set_current_tag(tag);
-  while (true) {
-    isolate->thread_registry()->CheckSafepoint();
-    MutexLocker ml(&mutex);
-    if (exited == SafepointTestTask::kTaskCount) {
-      break;
-    }
+  MonitorLocker ml(&monitor);
+  while (exited != SafepointTestTask::kTaskCount) {
+    ml.WaitWithSafepointCheck(thread);
   }
 }
 
@@ -562,14 +561,14 @@
 };
 
 
-TEST_CASE(HelperAllocAndGC) {
+VM_TEST_CASE(HelperAllocAndGC) {
   Monitor done_monitor;
   bool done = false;
-  Isolate* isolate = Thread::Current()->isolate();
+  Isolate* isolate = thread->isolate();
   Dart::thread_pool()->Run(new AllocAndGCTask(isolate, &done_monitor, &done));
   {
     while (true) {
-      isolate->thread_registry()->CheckSafepoint();
+      TransitionVMToBlocked transition(thread);
       MonitorLocker ml(&done_monitor);
       if (done) {
         break;
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 64c7127..be86154 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -15,6 +15,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline");
 DEFINE_FLAG(bool, trace_timeline, false,
             "Trace timeline backend");
@@ -25,6 +27,10 @@
 DEFINE_FLAG(charp, timeline_dir, NULL,
             "Enable all timeline trace streams and output VM global trace "
             "into specified directory.");
+DEFINE_FLAG(charp, timeline_streams, NULL,
+            "Comma separated list of timeline streams to record. "
+            "Valid values: all, API, Compiler, Dart, Debugger, Embedder, "
+            "GC, Isolate, and VM.");
 
 // Implementation notes:
 //
@@ -68,6 +74,56 @@
 //       |TimelineEventRecorder::lock_|
 //
 
+
+// Returns a caller freed array of stream names in FLAG_timeline_streams.
+static MallocGrowableArray<char*>* GetEnabledByDefaultTimelineStreams() {
+  MallocGrowableArray<char*>* result = new MallocGrowableArray<char*>();
+  if (FLAG_timeline_streams == NULL) {
+    // Nothing set.
+    return result;
+  }
+  char* save_ptr;  // Needed for strtok_r.
+  // strtok modifies arg 1 so we make a copy of it.
+  char* streams = strdup(FLAG_timeline_streams);
+  char* token = strtok_r(streams, ",", &save_ptr);
+  while (token != NULL) {
+    result->Add(strdup(token));
+    token = strtok_r(NULL, ",", &save_ptr);
+  }
+  free(streams);
+  return result;
+}
+
+
+// Frees the result of |GetEnabledByDefaultTimelineStreams|.
+static void FreeEnabledByDefaultTimelineStreams(
+    MallocGrowableArray<char*>* streams) {
+  if (streams == NULL) {
+    return;
+  }
+  for (intptr_t i = 0; i < streams->length(); i++) {
+    free((*streams)[i]);
+  }
+  delete streams;
+}
+
+
+// Returns true if |streams| contains |stream| or "all". Not case sensitive.
+static bool HasStream(MallocGrowableArray<char*>* streams, const char* stream) {
+  if ((FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline) {
+    return true;
+  }
+  for (intptr_t i = 0; i < streams->length(); i++) {
+    const char* checked_stream = (*streams)[i];
+    if ((strstr(checked_stream, "all") != NULL) ||
+        (strstr(checked_stream, stream) != NULL)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+
 void Timeline::InitOnce() {
   ASSERT(recorder_ == NULL);
   // Default to ring recorder being enabled.
@@ -80,31 +136,42 @@
   } else if (use_ring_recorder) {
     recorder_ = new TimelineEventRingRecorder();
   }
-  vm_stream_ = new TimelineStream();
-  vm_stream_->Init("VM", EnableStreamByDefault("VM"), NULL);
-  vm_api_stream_ = new TimelineStream();
-  vm_api_stream_->Init("API",
-                       EnableStreamByDefault("API"),
-                       &stream_API_enabled_);
+  enabled_streams_ = GetEnabledByDefaultTimelineStreams();
+  vm_stream_.Init("VM", HasStream(enabled_streams_, "VM"), NULL);
+  vm_api_stream_.Init("API",
+                      HasStream(enabled_streams_, "API"),
+                      &stream_API_enabled_);
   // Global overrides.
 #define ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT(name, not_used)                   \
-  stream_##name##_enabled_ = EnableStreamByDefault(#name);
+  stream_##name##_enabled_ = HasStream(enabled_streams_, #name);
   ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT)
 #undef ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT
 }
 
 
+void Timeline::SetVMStreamEnabled(bool enabled) {
+  vm_stream_.set_enabled(enabled);
+}
+
+
 void Timeline::Shutdown() {
   ASSERT(recorder_ != NULL);
   if (FLAG_timeline_dir != NULL) {
     recorder_->WriteTo(FLAG_timeline_dir);
   }
+  // Disable global streams.
+  vm_stream_.set_enabled(false);
+  vm_api_stream_.set_enabled(false);
+#define ISOLATE_TIMELINE_STREAM_DISABLE(name, not_used)                   \
+  stream_##name##_enabled_ = false;
+  ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DISABLE)
+#undef ISOLATE_TIMELINE_STREAM_DISABLE
   delete recorder_;
   recorder_ = NULL;
-  delete vm_stream_;
-  vm_stream_ = NULL;
-  delete vm_api_stream_;
-  vm_api_stream_ = NULL;
+  if (enabled_streams_ != NULL) {
+    FreeEnabledByDefaultTimelineStreams(enabled_streams_);
+    enabled_streams_ = NULL;
+  }
 }
 
 
@@ -113,21 +180,27 @@
 }
 
 
-bool Timeline::EnableStreamByDefault(const char* stream_name) {
-  // TODO(johnmccutchan): Allow for command line control over streams.
-  return (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline;
+void Timeline::SetupIsolateStreams(Isolate* isolate) {
+  if (!FLAG_support_timeline) {
+    return;
+  }
+#define ISOLATE_TIMELINE_STREAM_INIT(name, enabled_by_default)                 \
+  isolate->Get##name##Stream()->Init(                                          \
+      #name,                                                                   \
+      (enabled_by_default || HasStream(enabled_streams_, #name)),              \
+      Timeline::Stream##name##EnabledFlag());
+  ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_INIT);
+#undef ISOLATE_TIMELINE_STREAM_INIT
 }
 
 
 TimelineStream* Timeline::GetVMStream() {
-  ASSERT(vm_stream_ != NULL);
-  return vm_stream_;
+  return &vm_stream_;
 }
 
 
 TimelineStream* Timeline::GetVMApiStream() {
-  ASSERT(vm_api_stream_ != NULL);
-  return vm_api_stream_;
+  return &vm_api_stream_;
 }
 
 
@@ -153,6 +226,38 @@
 }
 
 
+void Timeline::PrintFlagsToJSON(JSONStream* js) {
+  JSONObject obj(js);
+  obj.AddProperty("type", "TimelineFlags");
+  TimelineEventRecorder* recorder = Timeline::recorder();
+  if (recorder == NULL) {
+    obj.AddProperty("recorderName", "null");
+  } else {
+    obj.AddProperty("recorderName", recorder->name());
+  }
+  {
+    JSONArray availableStreams(&obj, "availableStreams");
+#define ADD_STREAM_NAME(name, not_used)                                        \
+    availableStreams.AddValue(#name);
+ISOLATE_TIMELINE_STREAM_LIST(ADD_STREAM_NAME);
+#undef ADD_STREAM_NAME
+    availableStreams.AddValue("VM");
+  }
+  {
+    JSONArray recordedStreams(&obj, "recordedStreams");
+#define ADD_RECORDED_STREAM_NAME(name, not_used)                               \
+    if (stream_##name##_enabled_) {                                            \
+      recordedStreams.AddValue(#name);                                         \
+    }
+ISOLATE_TIMELINE_STREAM_LIST(ADD_RECORDED_STREAM_NAME);
+#undef ADD_RECORDED_STREAM_NAME
+    if (vm_stream_.enabled()) {
+      recordedStreams.AddValue("VM");
+    }
+  }
+}
+
+
 void Timeline::Clear() {
   TimelineEventRecorder* recorder = Timeline::recorder();
   if (recorder == NULL) {
@@ -164,8 +269,9 @@
 
 
 TimelineEventRecorder* Timeline::recorder_ = NULL;
-TimelineStream* Timeline::vm_stream_ = NULL;
-TimelineStream* Timeline::vm_api_stream_ = NULL;
+TimelineStream Timeline::vm_stream_;
+TimelineStream Timeline::vm_api_stream_;
+MallocGrowableArray<char*>* Timeline::enabled_streams_ = NULL;
 
 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default)          \
   bool Timeline::stream_##name##_enabled_ = enabled_by_default;
@@ -191,12 +297,14 @@
 
 
 void TimelineEvent::Reset() {
-  set_event_type(kNone);
+  state_ = 0;
   thread_ = OSThread::kInvalidThreadId;
   isolate_id_ = ILLEGAL_PORT;
   category_ = "";
   label_ = NULL;
   FreeArguments();
+  set_pre_serialized_json(false);
+  set_event_type(kNone);
 }
 
 
@@ -368,7 +476,7 @@
 void TimelineEvent::Init(EventType event_type,
                          const char* label) {
   ASSERT(label != NULL);
-  set_event_type(event_type);
+  state_ = 0;
   timestamp0_ = 0;
   timestamp1_ = 0;
   OSThread* os_thread = OSThread::Current();
@@ -382,6 +490,8 @@
   }
   label_ = label;
   FreeArguments();
+  set_pre_serialized_json(false);
+  set_event_type(event_type);
 }
 
 
@@ -417,6 +527,9 @@
 
 
 void TimelineEvent::PrintJSON(JSONStream* stream) const {
+  if (!FLAG_support_service) {
+    return;
+  }
   if (pre_serialized_json()) {
     // Event has already been serialized into JSON- just append the
     // raw data.
@@ -662,6 +775,9 @@
 TimelineDurationScope::TimelineDurationScope(TimelineStream* stream,
                                              const char* label)
     : TimelineEventScope(stream, label) {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   timestamp_ = OS::GetCurrentMonotonicMicros();
 }
 
@@ -670,11 +786,17 @@
                                              TimelineStream* stream,
                                              const char* label)
     : TimelineEventScope(thread, stream, label) {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   timestamp_ = OS::GetCurrentMonotonicMicros();
 }
 
 
 TimelineDurationScope::~TimelineDurationScope() {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   if (!ShouldEmitEvent()) {
     return;
   }
@@ -694,6 +816,9 @@
 TimelineBeginEndScope::TimelineBeginEndScope(TimelineStream* stream,
                                              const char* label)
     : TimelineEventScope(stream, label) {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   EmitBegin();
 }
 
@@ -702,22 +827,32 @@
                                              TimelineStream* stream,
                                              const char* label)
     : TimelineEventScope(thread, stream, label) {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   EmitBegin();
 }
 
 
 TimelineBeginEndScope::~TimelineBeginEndScope() {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   EmitEnd();
 }
 
 
 void TimelineBeginEndScope::EmitBegin() {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   if (!ShouldEmitEvent()) {
     return;
   }
   TimelineEvent* event = stream()->StartEvent();
   if (event == NULL) {
     // Stream is now disabled.
+    set_enabled(false);
     return;
   }
   ASSERT(event != NULL);
@@ -728,12 +863,16 @@
 
 
 void TimelineBeginEndScope::EmitEnd() {
+  if (!FLAG_support_timeline) {
+    return;
+  }
   if (!ShouldEmitEvent()) {
     return;
   }
   TimelineEvent* event = stream()->StartEvent();
   if (event == NULL) {
     // Stream is now disabled.
+    set_enabled(false);
     return;
   }
   ASSERT(event != NULL);
@@ -773,6 +912,9 @@
 
 
 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
+  if (!FLAG_support_service) {
+    return;
+  }
   OSThreadIterator it;
   while (it.HasNext()) {
     OSThread* thread = it.Next();
@@ -866,6 +1008,9 @@
 
 
 void TimelineEventRecorder::WriteTo(const char* directory) {
+  if (!FLAG_support_service) {
+    return;
+  }
   Dart_FileOpenCallback file_open = Isolate::file_open_callback();
   Dart_FileWriteCallback file_write = Isolate::file_write_callback();
   Dart_FileCloseCallback file_close = Isolate::file_close_callback();
@@ -963,6 +1108,9 @@
 void TimelineEventRingRecorder::PrintJSONEvents(
     JSONArray* events,
     TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   MutexLocker ml(&lock_);
   intptr_t block_offset = FindOldestBlockIndex();
   if (block_offset == -1) {
@@ -989,6 +1137,9 @@
 
 void TimelineEventRingRecorder::PrintJSON(JSONStream* js,
                                           TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "_Timeline");
   {
@@ -1001,6 +1152,9 @@
 
 void TimelineEventRingRecorder::PrintTraceEvent(JSONStream* js,
                                                 TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONArray events(js);
   PrintJSONEvents(&events, filter);
 }
@@ -1074,6 +1228,9 @@
 
 void TimelineEventStreamingRecorder::PrintJSON(JSONStream* js,
                                                TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "_Timeline");
   {
@@ -1086,6 +1243,9 @@
 void TimelineEventStreamingRecorder::PrintTraceEvent(
     JSONStream* js,
     TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONArray events(js);
 }
 
@@ -1110,6 +1270,9 @@
 
 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js,
                                              TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONObject topLevel(js);
   topLevel.AddProperty("type", "_Timeline");
   {
@@ -1123,6 +1286,9 @@
 void TimelineEventEndlessRecorder::PrintTraceEvent(
     JSONStream* js,
     TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   JSONArray events(js);
   PrintJSONEvents(&events, filter);
 }
@@ -1157,17 +1323,38 @@
   return head_;
 }
 
+static int TimelineEventBlockCompare(TimelineEventBlock* const* a,
+                                     TimelineEventBlock* const* b) {
+  return (*a)->LowerTimeBound() - (*b)->LowerTimeBound();
+}
+
 
 void TimelineEventEndlessRecorder::PrintJSONEvents(
     JSONArray* events,
     TimelineEventFilter* filter) {
+  if (!FLAG_support_service) {
+    return;
+  }
   MutexLocker ml(&lock_);
+  // Collect all interesting blocks.
+  MallocGrowableArray<TimelineEventBlock*> blocks(8);
   TimelineEventBlock* current = head_;
   while (current != NULL) {
-    if (!filter->IncludeBlock(current)) {
-      current = current->next();
-      continue;
+    if (filter->IncludeBlock(current)) {
+      blocks.Add(current);
     }
+    current = current->next();
+  }
+  // Bail early.
+  if (blocks.length() == 0) {
+    return;
+  }
+  // Sort the interesting blocks so that blocks with earlier events are
+  // outputted first.
+  blocks.Sort(TimelineEventBlockCompare);
+  // Output blocks in sorted order.
+  for (intptr_t block_idx = 0; block_idx < blocks.length(); block_idx++) {
+    current = blocks[block_idx];
     intptr_t length = current->length();
     for (intptr_t i = 0; i < length; i++) {
       TimelineEvent* event = current->At(i);
@@ -1177,7 +1364,6 @@
         events->AddValue(event);
       }
     }
-    current = current->next();
   }
 }
 
@@ -1325,4 +1511,6 @@
   return r;
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index d0c43e0..6dfc8d2 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -46,7 +46,7 @@
   // Access the global recorder. Not thread safe.
   static TimelineEventRecorder* recorder();
 
-  static bool EnableStreamByDefault(const char* stream_name);
+  static void SetupIsolateStreams(Isolate* isolate);
 
   static TimelineStream* GetVMStream();
 
@@ -57,6 +57,9 @@
 
   static void Clear();
 
+  // Print information about streams to JSON.
+  static void PrintFlagsToJSON(JSONStream* json);
+
 #define ISOLATE_TIMELINE_STREAM_FLAGS(name, not_used)                          \
   static const bool* Stream##name##EnabledFlag() {                             \
     return &stream_##name##_enabled_;                                          \
@@ -66,11 +69,13 @@
   }
   ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_FLAGS)
 #undef ISOLATE_TIMELINE_STREAM_FLAGS
+  static void SetVMStreamEnabled(bool enabled);
 
  private:
   static TimelineEventRecorder* recorder_;
-  static TimelineStream* vm_stream_;
-  static TimelineStream* vm_api_stream_;
+  static TimelineStream vm_stream_;
+  static TimelineStream vm_api_stream_;
+  static MallocGrowableArray<char*>* enabled_streams_;
 
 #define ISOLATE_TIMELINE_STREAM_DECLARE_FLAG(name, not_used)                   \
   static bool stream_##name##_enabled_;
@@ -94,7 +99,6 @@
   // Keep in sync with StateBits below.
   enum EventType {
     kNone,
-    kSerializedJSON,  // Events from Dart code.
     kBegin,
     kEnd,
     kDuration,
@@ -283,9 +287,9 @@
     kNextBit = 5,
   };
 
-  class EventTypeField : public BitField<EventType, kEventTypeBit, 4> {};
+  class EventTypeField : public BitField<uword, EventType, kEventTypeBit, 4> {};
   class PreSerializedJSON :
-      public BitField<bool, kPreSerializedJSON, 1> {};
+      public BitField<uword, bool, kPreSerializedJSON, 1> {};
 
   int64_t timestamp0_;
   int64_t timestamp1_;
@@ -345,6 +349,7 @@
   const bool* globally_enabled_;
 };
 
+#ifndef PRODUCT
 #define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, suffix, function)       \
   TimelineDurationScope tds(thread,                                            \
                             thread->isolate()->GetCompilerStream(),            \
@@ -356,7 +361,9 @@
         "function",                                                            \
         function.ToLibNamePrefixedQualifiedCString());                         \
   }
-
+#else
+#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, suffix, function)
+#endif  // !PRODUCT
 
 // See |TimelineDurationScope| and |TimelineBeginEndScope|.
 class TimelineEventScope : public StackResource {
@@ -387,6 +394,10 @@
     return enabled_;
   }
 
+  void set_enabled(bool enabled) {
+    enabled_ = enabled;
+  }
+
   const char* label() const {
     return label_;
   }
@@ -530,7 +541,6 @@
   void Finish();
 
   friend class Thread;
-  friend class ThreadRegistry;
   friend class TimelineEventRecorder;
   friend class TimelineEventRingRecorder;
   friend class TimelineEventEndlessRecorder;
@@ -612,7 +622,7 @@
   // Interface method(s) which must be implemented.
   virtual void PrintJSON(JSONStream* js, TimelineEventFilter* filter) = 0;
   virtual void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) = 0;
-
+  virtual const char* name() const = 0;
   int64_t GetNextAsyncId();
 
   void FinishBlock(TimelineEventBlock* block);
@@ -656,6 +666,9 @@
 
   void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
   void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
+  const char* name() const {
+    return "ring";
+  }
 
  protected:
   TimelineEvent* StartEvent();
@@ -687,6 +700,10 @@
   // reference to |event| as it may be freed as soon as this function returns.
   virtual void StreamEvent(TimelineEvent* event) = 0;
 
+  const char* name() const {
+    return "streaming";
+  }
+
  protected:
   TimelineEventBlock* GetNewBlockLocked() {
     return NULL;
@@ -711,6 +728,10 @@
   void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
   void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
 
+  const char* name() const {
+    return "endless";
+  }
+
  protected:
   TimelineEvent* StartEvent();
   void CompleteEvent(TimelineEvent* event);
diff --git a/runtime/vm/timeline_analysis.cc b/runtime/vm/timeline_analysis.cc
index 8a7c6fb..5360d29 100644
--- a/runtime/vm/timeline_analysis.cc
+++ b/runtime/vm/timeline_analysis.cc
@@ -10,6 +10,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 DECLARE_FLAG(bool, trace_timeline_analysis);
 DECLARE_FLAG(bool, timing);
 
@@ -629,4 +631,6 @@
             MicrosecondsToMilliseconds(pause_info->max_exclusive_micros()));
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index 2d9bb57..01d0c6a 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -15,6 +15,8 @@
 
 namespace dart {
 
+#ifndef PRODUCT
+
 class TimelineRecorderOverride : public ValueObject {
  public:
   explicit TimelineRecorderOverride(TimelineEventRecorder* new_recorder)
@@ -343,12 +345,12 @@
   TimelineTestHelper::FakeThreadEvent(block_1_2, 1, "B2");
   TimelineTestHelper::FakeThreadEvent(block_1_2, 1, "B3");
   // Sleep to ensure timestamps differ.
-  OS::Sleep(1);
+  OS::Sleep(32);
   TimelineTestHelper::FakeThreadEvent(block_1_0, 1, "A1");
-  OS::Sleep(1);
+  OS::Sleep(32);
   TimelineTestHelper::FakeThreadEvent(block_1_1, 1, "C1");
   TimelineTestHelper::FakeThreadEvent(block_1_1, 1, "C2");
-  OS::Sleep(1);
+  OS::Sleep(32);
 
   // Add events to each block for thread 2.
   TimelineTestHelper::FakeThreadEvent(block_2_0, 2, "A");
@@ -453,7 +455,7 @@
 
   // Emit the earlier event into block_1.
   TimelineTestHelper::FakeThreadEvent(block_1, 2, "Alpha", &stream);
-  OS::Sleep(1);
+  OS::Sleep(32);
   // Emit the later event into block_0.
   TimelineTestHelper::FakeThreadEvent(block_0, 2, "Beta", &stream);
 
@@ -854,4 +856,6 @@
   TimelineTestHelper::Clear(recorder);
 }
 
+#endif  // !PRODUCT
+
 }  // namespace dart
diff --git a/runtime/vm/timer.h b/runtime/vm/timer.h
index e4ee890..f3b15fa 100644
--- a/runtime/vm/timer.h
+++ b/runtime/vm/timer.h
@@ -12,8 +12,6 @@
 
 namespace dart {
 
-class JSONObject;
-
 // Timer class allows timing of specific operations in the VM.
 class Timer : public ValueObject {
  public:
diff --git a/runtime/vm/token.cc b/runtime/vm/token.cc
index 75872e5..b6a34ce 100644
--- a/runtime/vm/token.cc
+++ b/runtime/vm/token.cc
@@ -77,5 +77,4 @@
   return (token == kBIT_NOT) || (token == kNEGATE);
 }
 
-
 }  // namespace dart
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index a1018f8..6ddf17b 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -6,6 +6,7 @@
 #define VM_TOKEN_H_
 
 #include "platform/assert.h"
+#include "vm/allocation.h"
 
 namespace dart {
 
@@ -193,7 +194,6 @@
   KW(kWHILE, "while", 0, kKeyword)                                             \
   KW(kWITH, "with", 0, kKeyword) /* == kLastKeyword */
 
-
 class String;
 
 class Token {
@@ -328,7 +328,6 @@
   static const Attribute attributes_[];
 };
 
-
 }  // namespace dart
 
 #endif  // VM_TOKEN_H_
diff --git a/runtime/vm/token_position.cc b/runtime/vm/token_position.cc
new file mode 100644
index 0000000..a6490cd
--- /dev/null
+++ b/runtime/vm/token_position.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/token_position.h"
+
+#include "vm/object.h"
+
+namespace dart {
+
+
+TokenPosition TokenPosition::SnapshotDecode(int32_t value) {
+  return TokenPosition(static_cast<intptr_t>(value));
+}
+
+
+int32_t TokenPosition::SnapshotEncode() {
+  return static_cast<int32_t>(value_);
+}
+
+
+bool TokenPosition::IsSynthetic() const {
+  if (value_ >= kMinSourcePos) {
+    return false;
+  }
+  if (value_ < kLast.value()) {
+    return true;
+  }
+  return false;
+}
+
+
+#define DEFINE_VALUES(name, value)                                             \
+const TokenPosition TokenPosition::k##name = TokenPosition(value);
+  SENTINEL_TOKEN_DESCRIPTORS(DEFINE_VALUES);
+#undef DEFINE_VALUES
+const TokenPosition TokenPosition::kMinSource =
+    TokenPosition(kMinSourcePos);
+
+const TokenPosition TokenPosition::kMaxSource =
+    TokenPosition(kMaxSourcePos);
+
+
+const char* TokenPosition::ToCString() const {
+  switch (value_) {
+#define DEFINE_CASE(name, value)                                               \
+    case value: return #name;
+    SENTINEL_TOKEN_DESCRIPTORS(DEFINE_CASE);
+#undef DEFINE_CASE
+    default: {
+      Zone* zone = Thread::Current()->zone();
+      ASSERT(zone != NULL);
+      if (IsSynthetic()) {
+        // TODO(johnmccutchan): Print synthetic positions differently.
+        return FromSynthetic().ToCString();
+      } else {
+        return OS::SCreate(zone, "%d", value_);
+      }
+    }
+  }
+}
+
+}  // namespace dart
diff --git a/runtime/vm/token_position.h b/runtime/vm/token_position.h
new file mode 100644
index 0000000..c964716
--- /dev/null
+++ b/runtime/vm/token_position.h
@@ -0,0 +1,208 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_TOKEN_POSITION_H_
+#define VM_TOKEN_POSITION_H_
+
+#include "platform/utils.h"
+#include "vm/allocation.h"
+
+namespace dart {
+
+// The token space is organized as follows:
+//
+// Sentinel values start at -1 and move towards negative infinity:
+// kNoSourcePos                -> -1
+// ClassifyingTokenPositions 1 -> -1 - 1
+// ClassifyingTokenPositions N -> -1 - N
+//
+// Synthetically created AstNodes are given real source positions but encoded
+// as negative numbers from [kSmiMin32, -1 - N]. For example:
+//
+// A source position of 0 in a synthetic AstNode would be encoded as -2 - N.
+// A source position of 1 in a synthetic AstNode would be encoded as -3 - N.
+//
+// All other AstNodes are given real source positions encoded as positive
+// integers.
+//
+// This organization allows for ~1 billion token positions.
+
+#define SENTINEL_TOKEN_DESCRIPTORS(V)                                          \
+    V(NoSource, -1)                                                            \
+    V(Box, -2)                                                                 \
+    V(ParallelMove, -3)                                                        \
+    V(TempMove, -4)                                                            \
+    V(Constant, -5)                                                            \
+    V(PushArgument, -6)                                                        \
+    V(ControlFlow, -7)                                                         \
+    V(Context, -8)                                                             \
+    V(MethodExtractor, -9)                                                     \
+    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
+// by the profiler.
+class TokenPosition {
+ public:
+  TokenPosition()
+      : value_(kNoSource.value()) {
+  }
+
+  explicit TokenPosition(intptr_t value)
+      : value_(value) {
+  }
+
+  bool operator==(const TokenPosition& b) const {
+    return value() == b.value();
+  }
+
+  bool operator!=(const TokenPosition& b) const {
+    return !(*this == b);
+  }
+
+  bool operator<(const TokenPosition& b) const {
+    // TODO(johnmccutchan): Assert that this is a source position.
+    return value() < b.value();
+  }
+
+  bool operator>(const TokenPosition& b) const {
+    // TODO(johnmccutchan): Assert that this is a source position.
+    return b < *this;
+  }
+
+  bool operator<=(const TokenPosition& b) {
+    // TODO(johnmccutchan): Assert that this is a source position.
+    return !(*this > b);
+  }
+
+  bool operator>=(const TokenPosition& b) {
+    // TODO(johnmccutchan): Assert that this is a source position.
+    return !(*this < b);
+  }
+
+  static const intptr_t kMaxSentinelDescriptors = 64;
+
+#define DECLARE_VALUES(name, value)                                            \
+  static const TokenPosition k##name;
+  SENTINEL_TOKEN_DESCRIPTORS(DECLARE_VALUES);
+#undef DECLARE_VALUES
+  static const TokenPosition kMinSource;
+  static const TokenPosition kMaxSource;
+
+  // Decode from a snapshot.
+  static TokenPosition SnapshotDecode(int32_t value);
+
+  // Encode for writing into a snapshot.
+  int32_t SnapshotEncode();
+
+  // Increment the token position.
+  TokenPosition Next() {
+    ASSERT(IsReal());
+    value_++;
+    return *this;
+  }
+
+  // The raw value.
+  // TODO(johnmccutchan): Make this private.
+  intptr_t value() const {
+    return value_;
+  }
+
+  // Return the source position.
+  intptr_t Pos() const {
+    if (IsSynthetic()) {
+      return FromSynthetic().Pos();
+    }
+    return value_;
+  }
+
+  // Token position constants.
+  static const intptr_t kNoSourcePos = -1;
+  static const intptr_t kMinSourcePos = 0;
+  static const intptr_t kMaxSourcePos = kSmiMax32 - kMaxSentinelDescriptors - 2;
+
+  // Is |this| a classifying sentinel source position?
+  // Classifying positions are used by the profiler to group instructions whose
+  // cost isn't naturally attributable to a source location.
+  bool IsClassifying() const {
+    return (value_ >= kBox.value()) && (value_ <= kLast.value());
+  }
+
+  // Is |this| the no source position sentinel?
+  bool IsNoSource() const {
+    return *this == kNoSource;
+  }
+
+  // Is |this| a synthetic source position?
+  // Synthetic source positions are used by the profiler to attribute ticks to a
+  // pieces of source, but ignored by the debugger as potential breakpoints.
+  bool IsSynthetic() const;
+
+  // Is |this| a real source position?
+  bool IsReal() const {
+    return value_ >= kMinSourcePos;
+  }
+
+  // Is |this| a source position?
+  bool IsSourcePosition() const {
+    return IsReal() || IsNoSource() || IsSynthetic();
+  }
+
+  // Is |this| a debug pause source position?
+  bool IsDebugPause() const {
+    // Sanity check some values here.
+    ASSERT(kNoSource.value() == kNoSourcePos);
+    ASSERT(kLast.value() < kNoSource.value());
+    ASSERT(kLast.value() > -kMaxSentinelDescriptors);
+    return IsReal();
+  }
+
+  // Convert |this| into a synthetic source position. Sentinel values remain
+  // unchanged.
+  TokenPosition ToSynthetic() const {
+    const intptr_t value = value_;
+    if (IsClassifying() || IsNoSource()) {
+      return *this;
+    }
+    if (IsSynthetic()) {
+      return *this;
+    }
+    const TokenPosition synthetic_value =
+        TokenPosition((kLast.value() - 1) - value);
+    ASSERT(synthetic_value.IsSynthetic());
+    ASSERT(synthetic_value.value() < kLast.value());
+    return synthetic_value;
+  }
+
+  // Convert |this| from a synthetic source position. Sentinel values remain
+  // unchanged.
+  TokenPosition FromSynthetic() const {
+    const intptr_t synthetic_value = value_;
+    if (IsClassifying() || IsNoSource()) {
+      return *this;
+    }
+    if (!IsSynthetic()) {
+      return *this;
+    }
+    const TokenPosition value =
+        TokenPosition(-synthetic_value + (kLast.value() - 1));
+    ASSERT(!value.IsSynthetic());
+    return value;
+  }
+
+  const char* ToCString() const;
+
+ private:
+  int32_t value_;
+
+  DISALLOW_ALLOCATION();
+};
+
+}  // namespace dart
+
+#endif  // VM_TOKEN_POSITION_H_
diff --git a/runtime/vm/trace_buffer.cc b/runtime/vm/trace_buffer.cc
deleted file mode 100644
index 2022e49..0000000
--- a/runtime/vm/trace_buffer.cc
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/isolate.h"
-#include "vm/json_stream.h"
-#include "vm/object.h"
-#include "vm/os.h"
-#include "vm/trace_buffer.h"
-
-namespace dart {
-
-TraceBuffer::TraceBuffer(Isolate* isolate, intptr_t capacity)
-    : isolate_(isolate), ring_capacity_(capacity) {
-  ring_cursor_ = 0;
-  ring_ = reinterpret_cast<TraceBufferEntry*>(
-      calloc(ring_capacity_, sizeof(TraceBufferEntry)));  // NOLINT
-}
-
-
-TraceBuffer::~TraceBuffer() {
-  ASSERT(ring_ != NULL);
-  Clear();
-  free(ring_);
-  if (isolate_ != NULL) {
-    isolate_->set_trace_buffer(NULL);
-    isolate_ = NULL;
-  }
-}
-
-
-void TraceBuffer::Init(Isolate* isolate, intptr_t capacity) {
-  TraceBuffer* trace_buffer = new TraceBuffer(isolate, capacity);
-  isolate->set_trace_buffer(trace_buffer);
-}
-
-
-void TraceBuffer::Clear() {
-  for (intptr_t i = 0; i < ring_capacity_; i++) {
-    TraceBufferEntry& entry = ring_[i];
-    entry.micros = 0;
-    free(entry.message);
-    entry.message = NULL;
-    entry.message_is_escaped = false;
-  }
-  ring_cursor_ = 0;
-}
-
-
-void TraceBuffer::Fill(TraceBufferEntry* entry, int64_t micros,
-                       char* msg, bool msg_is_escaped) {
-  if (entry->message != NULL) {
-    // Recycle TraceBufferEntry.
-    free(entry->message);
-  }
-  entry->message = msg;
-  entry->message_is_escaped = msg_is_escaped;
-  entry->micros = micros;
-}
-
-
-void TraceBuffer::AppendTrace(int64_t micros, char* msg, bool msg_is_escaped) {
-  const intptr_t index = ring_cursor_;
-  TraceBufferEntry* trace_entry = &ring_[index];
-  Fill(trace_entry, micros, msg, msg_is_escaped);
-  ring_cursor_ = RingIndex(ring_cursor_ + 1);
-}
-
-
-void TraceBuffer::Trace(int64_t micros, const char* msg, bool msg_is_escaped) {
-  ASSERT(msg != NULL);
-  char* message_copy = strdup(msg);
-  AppendTrace(micros, message_copy, msg_is_escaped);
-}
-
-
-void TraceBuffer::Trace(const char* msg, bool msg_is_escaped) {
-  Trace(OS::GetCurrentTimeMicros(), msg, msg_is_escaped);
-}
-
-
-void TraceBuffer::TraceF(const char* format, ...) {
-  const int64_t micros = OS::GetCurrentTimeMicros();
-  va_list args;
-  va_start(args, format);
-  const intptr_t len = OS::VSNPrint(NULL, 0, format, args);
-  va_end(args);
-  char* p = reinterpret_cast<char*>(malloc(len+1));
-  va_start(args, format);
-  const intptr_t len2 = OS::VSNPrint(p, len+1, format, args);
-  va_end(args);
-  ASSERT(len == len2);
-  AppendTrace(micros, p);
-}
-
-
-void TraceBuffer::PrintToJSONStream(JSONStream* stream) const {
-  JSONObject json_trace_buffer(stream);
-  json_trace_buffer.AddProperty("type", "TraceBuffer");
-  // TODO(johnmccutchan): Send cursor position in response.
-  JSONArray json_trace_buffer_array(&json_trace_buffer, "members");
-  // Scan forward until we find the first entry which isn't empty.
-  // TODO(johnmccutchan): Accept cursor start position as input.
-  intptr_t start = -1;
-  for (intptr_t i = 0; i < ring_capacity_; i++) {
-    intptr_t index = RingIndex(i + ring_cursor_);
-    if (!ring_[index].empty()) {
-      start = index;
-      break;
-    }
-  }
-  // No messages in trace buffer.
-  if (start == -1) {
-    return;
-  }
-  for (intptr_t i = 0; i < ring_capacity_; i++) {
-    intptr_t index = RingIndex(start + i);
-    const TraceBufferEntry& entry = ring_[index];
-    if (entry.empty()) {
-      // Empty entry, stop.
-      break;
-    }
-    JSONObject trace_entry(&json_trace_buffer_array);
-    trace_entry.AddProperty("type", "TraceBufferEntry");
-    double seconds = static_cast<double>(entry.micros) /
-                     static_cast<double>(kMicrosecondsPerSecond);
-    trace_entry.AddProperty("time", seconds);
-    if (entry.message_is_escaped) {
-      trace_entry.AddPropertyNoEscape("message", entry.message);
-    } else {
-      trace_entry.AddProperty("message", entry.message);
-    }
-  }
-}
-
-}  // namespace dart
diff --git a/runtime/vm/trace_buffer.h b/runtime/vm/trace_buffer.h
deleted file mode 100644
index 4c3c74c..0000000
--- a/runtime/vm/trace_buffer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef VM_TRACE_BUFFER_H_
-#define VM_TRACE_BUFFER_H_
-
-#include "platform/assert.h"
-#include "platform/globals.h"
-#include "vm/json_stream.h"
-
-namespace dart {
-
-class JSONStream;
-class Script;
-
-struct TraceBufferEntry {
-  int64_t micros;
-  char* message;
-  bool message_is_escaped;
-  bool empty() const {
-    return message == NULL;
-  }
-};
-
-class TraceBuffer {
- public:
-  static const intptr_t kDefaultCapacity = 1024;
-
-  static void Init(Isolate* isolate, intptr_t capacity = kDefaultCapacity);
-
-  ~TraceBuffer();
-
-  void Clear();
-
-  // Internally message is copied.
-  void Trace(int64_t micros, const char* msg, bool msg_is_escaped = false);
-  // Internally message is copied.
-  void Trace(const char* msg, bool msg_is_escaped = false);
-  void TraceF(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
-
-  void PrintToJSONStream(JSONStream* stream) const;
-
-  // Accessors for testing.
-  TraceBufferEntry* At(intptr_t i) const { return &ring_[RingIndex(i)]; }
-  intptr_t Length() const { return ring_cursor_; }
-
- private:
-  TraceBuffer(Isolate* isolate, intptr_t capacity);
-  void Cleanup();
-  void Fill(TraceBufferEntry* entry, int64_t micros,
-            char* msg, bool msg_is_escaped = false);
-  void AppendTrace(int64_t micros, char* msg, bool msg_is_escaped = false);
-
-  Isolate* isolate_;
-  TraceBufferEntry* ring_;
-  const intptr_t ring_capacity_;
-  intptr_t ring_cursor_;
-
-  intptr_t RingIndex(intptr_t i) const {
-    return i % ring_capacity_;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(TraceBuffer);
-};
-
-
-}  // namespace dart
-
-#endif  // VM_TRACE_BUFFER_H_
diff --git a/runtime/vm/trace_buffer_test.cc b/runtime/vm/trace_buffer_test.cc
deleted file mode 100644
index f85941f..0000000
--- a/runtime/vm/trace_buffer_test.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/assert.h"
-#include "vm/globals.h"
-#include "vm/json_stream.h"
-#include "vm/trace_buffer.h"
-#include "vm/unit_test.h"
-
-namespace dart {
-
-TEST_CASE(TraceBufferEmpty) {
-  Isolate* isolate = Isolate::Current();
-  TraceBuffer::Init(isolate, 3);
-  TraceBuffer* trace_buffer = isolate->trace_buffer();
-  {
-    JSONStream js;
-    trace_buffer->PrintToJSONStream(&js);
-    EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":[]}", js.ToCString());
-  }
-  delete trace_buffer;
-}
-
-
-TEST_CASE(TraceBufferClear) {
-  Isolate* isolate = Isolate::Current();
-  TraceBuffer::Init(isolate, 3);
-  TraceBuffer* trace_buffer = isolate->trace_buffer();
-  trace_buffer->Trace(kMicrosecondsPerSecond * 1, "abc");
-  trace_buffer->Clear();
-  {
-    JSONStream js;
-    trace_buffer->PrintToJSONStream(&js);
-    EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":[]}", js.ToCString());
-  }
-  delete trace_buffer;
-}
-
-
-TEST_CASE(TraceBufferTrace) {
-  Isolate* isolate = Isolate::Current();
-  TraceBuffer::Init(isolate, 3);
-  TraceBuffer* trace_buffer = isolate->trace_buffer();
-
-  trace_buffer->Trace(kMicrosecondsPerSecond * 1, "abc");
-  {
-    JSONStream js;
-    trace_buffer->PrintToJSONStream(&js);
-    EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":["
-                 "{\"type\":\"TraceBufferEntry\",\"time\":1.000000,"
-                 "\"message\":\"abc\"}]}", js.ToCString());
-  }
-  trace_buffer->Trace(kMicrosecondsPerSecond * 2, "def");
-  {
-    JSONStream js;
-    trace_buffer->PrintToJSONStream(&js);
-    EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":["
-                 "{\"type\":\"TraceBufferEntry\",\"time\":1.000000,"
-                 "\"message\":\"abc\"},"
-                 "{\"type\":\"TraceBufferEntry\",\"time\":2.000000,"
-                 "\"message\":\"def\"}]}", js.ToCString());
-  }
-  trace_buffer->Trace(kMicrosecondsPerSecond * 3, "ghi");
-  {
-    JSONStream js;
-    trace_buffer->PrintToJSONStream(&js);
-    EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":["
-                 "{\"type\":\"TraceBufferEntry\",\"time\":1.000000,"
-                 "\"message\":\"abc\"},"
-                 "{\"type\":\"TraceBufferEntry\",\"time\":2.000000,"
-                 "\"message\":\"def\"},"
-                 "{\"type\":\"TraceBufferEntry\",\"time\":3.000000,"
-                 "\"message\":\"ghi\"}]}", js.ToCString());
-  }
-  // This will overwrite the first Trace.
-  trace_buffer->Trace(kMicrosecondsPerSecond * 4, "jkl");
-  {
-    JSONStream js;
-    trace_buffer->PrintToJSONStream(&js);
-    EXPECT_STREQ("{\"type\":\"TraceBuffer\",\"members\":["
-                 "{\"type\":\"TraceBufferEntry\",\"time\":2.000000,"
-                 "\"message\":\"def\"},"
-                 "{\"type\":\"TraceBufferEntry\",\"time\":3.000000,"
-                 "\"message\":\"ghi\"},"
-                 "{\"type\":\"TraceBufferEntry\",\"time\":4.000000,"
-                 "\"message\":\"jkl\"}]}", js.ToCString());
-  }
-  delete trace_buffer;
-}
-
-
-TEST_CASE(TraceBufferTraceF) {
-  Isolate* isolate = Isolate::Current();
-  TraceBuffer::Init(isolate, 3);
-  TraceBuffer* trace_buffer = isolate->trace_buffer();
-  trace_buffer->TraceF("foo %d %s", 99, "bar");
-  {
-    JSONStream js;
-    trace_buffer->PrintToJSONStream(&js);
-    EXPECT_SUBSTRING("foo 99 bar", js.ToCString());
-  }
-  delete trace_buffer;
-}
-
-}  // namespace dart
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 2861fab..de0f09c 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -8,8 +8,10 @@
 
 #include "bin/builtin.h"
 #include "bin/dartutils.h"
+#include "bin/isolate_data.h"
 
 #include "platform/globals.h"
+
 #include "vm/assembler.h"
 #include "vm/ast_printer.h"
 #include "vm/compiler.h"
@@ -25,8 +27,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, disassemble);
-
 TestCaseBase* TestCaseBase::first_ = NULL;
 TestCaseBase* TestCaseBase::tail_ = NULL;
 
@@ -49,6 +49,21 @@
   }
 }
 
+
+Dart_Isolate TestCase::CreateIsolate(const uint8_t* buffer, const char* name) {
+  bin::IsolateData* isolate_data = new bin::IsolateData(name, NULL, NULL);
+  char* err;
+  Dart_Isolate isolate = Dart_CreateIsolate(
+      name, NULL, buffer, NULL, isolate_data, &err);
+  if (isolate == NULL) {
+    OS::Print("Creation of isolate failed '%s'\n", err);
+    free(err);
+  }
+  EXPECT(isolate != NULL);
+  return isolate;
+}
+
+
 static const char* kPackageScheme = "package:";
 
 static bool IsPackageSchemeURL(const char* url_name) {
@@ -56,12 +71,11 @@
   return (strncmp(url_name, kPackageScheme, kPackageSchemeLen) == 0);
 }
 
-static Dart_Handle ResolvePackageUri(Dart_Handle builtin_lib,
-                                     const char* uri_chars) {
+static Dart_Handle ResolvePackageUri(const char* uri_chars) {
   const int kNumArgs = 1;
   Dart_Handle dart_args[kNumArgs];
   dart_args[0] = DartUtils::NewString(uri_chars);
-  return Dart_Invoke(builtin_lib,
+  return Dart_Invoke(DartUtils::BuiltinLib(),
                      DartUtils::NewString("_filePathFromUri"),
                      kNumArgs,
                      dart_args);
@@ -88,10 +102,6 @@
     return result;
   }
 
-  Dart_Handle builtin_lib =
-      Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
-  DART_CHECK_VALID(builtin_lib);
-
   bool is_dart_scheme_url = DartUtils::IsDartSchemeURL(url_chars);
   bool is_io_library = DartUtils::IsDartIOLibURL(library_url_string);
   if (tag == Dart_kCanonicalizeUrl) {
@@ -105,7 +115,7 @@
     if (Dart_IsError(library_url)) {
       return library_url;
     }
-    return DartUtils::ResolveUri(library_url, url, builtin_lib);
+    return DartUtils::ResolveUri(library_url, url);
   }
   if (is_dart_scheme_url) {
     ASSERT(tag == Dart_kImportTag);
@@ -113,7 +123,7 @@
     if (DartUtils::IsDartIOLibURL(url_chars)) {
       return Builtin::LoadAndCheckLibrary(Builtin::kIOLibrary);
     } else if (DartUtils::IsDartBuiltinLibURL(url_chars)) {
-      return builtin_lib;
+      return Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
     } else {
       return DartUtils::NewError("Do not know how to load '%s'", url_chars);
     }
@@ -127,7 +137,7 @@
                            0, 0);
   }
   if (IsPackageSchemeURL(url_chars)) {
-    Dart_Handle resolved_uri = ResolvePackageUri(builtin_lib, url_chars);
+    Dart_Handle resolved_uri = ResolvePackageUri(url_chars);
     DART_CHECK_VALID(resolved_uri);
     url_chars = NULL;
     Dart_Handle result = Dart_StringToCString(resolved_uri, &url_chars);
@@ -200,12 +210,15 @@
 void AssemblerTest::Assemble() {
   const String& function_name = String::ZoneHandle(Symbols::New(name_));
   const Class& cls = Class::ZoneHandle(
-      Class::New(function_name, Script::Handle(), 0));
+      Class::New(function_name,
+                 Script::Handle(),
+                 TokenPosition::kMinSource));
   const Library& lib = Library::ZoneHandle(Library::New(function_name));
   cls.set_library(lib);
   Function& function = Function::ZoneHandle(
       Function::New(function_name, RawFunction::kRegularFunction,
-                    true, false, false, false, false, cls, 0));
+                    true, false, false, false, false, cls,
+                    TokenPosition::kMinSource));
   code_ = Code::FinalizeCode(function, assembler_);
   if (FLAG_disassemble) {
     OS::Print("Code for test '%s' {\n", name_);
@@ -220,7 +233,7 @@
 
 CodeGenTest::CodeGenTest(const char* name)
   : function_(Function::ZoneHandle()),
-    node_sequence_(new SequenceNode(0,
+    node_sequence_(new SequenceNode(TokenPosition::kMinSource,
                                     new LocalScope(NULL, 0, 0))),
     default_parameter_values_(new ZoneGrowableArray<const Instance*> ()) {
   ASSERT(name != NULL);
@@ -228,10 +241,11 @@
   // Add function to a class and that class to the class dictionary so that
   // frame walking can be used.
   const Class& cls = Class::ZoneHandle(
-       Class::New(function_name, Script::Handle(), 0));
+       Class::New(function_name, Script::Handle(),
+                  TokenPosition::kMinSource));
   function_ = Function::New(
       function_name, RawFunction::kRegularFunction,
-      true, false, false, false, false, cls, 0);
+      true, false, false, false, false, cls, TokenPosition::kMinSource);
   function_.set_result_type(Type::Handle(Type::DynamicType()));
   const Array& functions = Array::Handle(Array::New(1));
   functions.SetAt(0, function_);
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index a8b063a..defaea6 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -27,8 +27,29 @@
   static const dart::TestCase kRegister##name(Dart_Test##name, #name);         \
   void Dart_Test##name()
 
+// The VM_TEST_CASE macro is used for tests that need an isolate and zone
+// in order to test its functionality. This macro is used for tests that
+// are implemented using the VM code directly and do not use the Dart API
+// for calling into the VM. The safepoint execution state of threads using
+// this macro is transitioned from kThreadInNative to kThreadInVM.
+#define VM_TEST_CASE(name)                                                     \
+  static void Dart_TestHelper##name(Thread* thread);                           \
+  UNIT_TEST_CASE(name)                                                         \
+  {                                                                            \
+    TestIsolateScope __test_isolate__;                                         \
+    Thread* __thread__ = Thread::Current();                                    \
+    ASSERT(__thread__->isolate() == __test_isolate__.isolate());               \
+    TransitionNativeToVM transition(__thread__);                               \
+    StackZone __zone__(__thread__);                                            \
+    HandleScope __hs__(__thread__);                                            \
+    Dart_TestHelper##name(__thread__);                                         \
+  }                                                                            \
+  static void Dart_TestHelper##name(Thread* thread)
+
 // The TEST_CASE macro is used for tests that need an isolate and zone
-// in order to test its functionality.
+// in order to test its functionality. This macro is used for tests that
+// are implemented using the Dart API for calling into the VM. The safepoint
+// execution state of threads using this macro remains kThreadNative.
 #define TEST_CASE(name)                                                        \
   static void Dart_TestHelper##name(Thread* thread);                           \
   UNIT_TEST_CASE(name)                                                         \
@@ -57,7 +78,7 @@
 // C++ callee-saved registers are not preserved. Arguments may be passed in.
 #define ASSEMBLER_TEST_RUN(name, test)                                         \
   static void AssemblerTestRun##name(AssemblerTest* test);                     \
-  TEST_CASE(name) {                                                            \
+  VM_TEST_CASE(name) {                                                         \
     Assembler __assembler__;                                                   \
     AssemblerTest test(""#name, &__assembler__);                               \
     AssemblerTestGenerate##name(test.assembler());                             \
@@ -80,7 +101,7 @@
 // Pass the name of test and the expected results as RawObject.
 #define CODEGEN_TEST_RUN(name, expected)                                       \
   static void CodeGenTestRun##name(const Function& function);                  \
-  TEST_CASE(name) {                                                            \
+  VM_TEST_CASE(name) {                                                         \
     CodeGenTest __test__(""#name);                                             \
     CodeGenTestGenerate##name(&__test__);                                      \
     __test__.Compile();                                                        \
@@ -100,7 +121,7 @@
 // and evaluate its result.
 #define CODEGEN_TEST_RAW_RUN(name, function)                                   \
   static void CodeGenTestRun##name(const Function& function);                  \
-  TEST_CASE(name) {                                                            \
+  VM_TEST_CASE(name) {                                                         \
     CodeGenTest __test__(""#name);                                             \
     CodeGenTestGenerate##name(&__test__);                                      \
     __test__.Compile();                                                        \
@@ -113,7 +134,7 @@
 // The first one may reference the Function object generated by the second one.
 #define CODEGEN_TEST2_RUN(name1, name2, expected)                              \
   static void CodeGenTestRun##name1(const Function& function);                 \
-  TEST_CASE(name1) {                                                           \
+  VM_TEST_CASE(name1) {                                                        \
     /* Generate code for name2 */                                              \
     CodeGenTest __test2__(""#name2);                                           \
     CodeGenTestGenerate##name2(&__test2__);                                    \
@@ -285,18 +306,7 @@
   virtual void Run();
 
  private:
-  static Dart_Isolate CreateIsolate(const uint8_t* buffer,
-                                    const char* name) {
-    char* err;
-    Dart_Isolate isolate = Dart_CreateIsolate(
-        name, NULL, buffer, NULL, NULL, &err);
-    if (isolate == NULL) {
-      OS::Print("Creation of isolate failed '%s'\n", err);
-      free(err);
-    }
-    EXPECT(isolate != NULL);
-    return isolate;
-  }
+  static Dart_Isolate CreateIsolate(const uint8_t* buffer, const char* name);
 
   RunEntry* const run_;
 };
diff --git a/runtime/vm/virtual_memory.cc b/runtime/vm/virtual_memory.cc
index 1ad6c06..1372545 100644
--- a/runtime/vm/virtual_memory.cc
+++ b/runtime/vm/virtual_memory.cc
@@ -28,8 +28,7 @@
 }
 
 
-VirtualMemory* VirtualMemory::ForInstructionsSnapshot(void* pointer,
-                                                      uword size) {
+VirtualMemory* VirtualMemory::ForExternalPage(void* pointer, uword size) {
   // Memory for precompilated instructions was allocated by the embedder, so
   // create a VirtualMemory without allocating.
   MemoryRegion region(pointer, size);
diff --git a/runtime/vm/virtual_memory.h b/runtime/vm/virtual_memory.h
index 53ba57d..270d3cf 100644
--- a/runtime/vm/virtual_memory.h
+++ b/runtime/vm/virtual_memory.h
@@ -71,7 +71,7 @@
 
   bool embedder_allocated() const { return embedder_allocated_; }
 
-  static VirtualMemory* ForInstructionsSnapshot(void* pointer, uword size);
+  static VirtualMemory* ForExternalPage(void* pointer, uword size);
 
  private:
   static VirtualMemory* ReserveInternal(intptr_t size);
diff --git a/runtime/vm/virtual_memory_android.cc b/runtime/vm/virtual_memory_android.cc
index 0e0c1b2..16aa834 100644
--- a/runtime/vm/virtual_memory_android.cc
+++ b/runtime/vm/virtual_memory_android.cc
@@ -13,6 +13,8 @@
 #include "platform/assert.h"
 #include "platform/utils.h"
 
+#include "vm/isolate.h"
+
 namespace dart {
 
 // standard MAP_FAILED causes "error: use of old-style cast" as it
@@ -80,6 +82,8 @@
 
 
 bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
+  ASSERT(Thread::Current()->IsMutatorThread() ||
+         Isolate::Current()->mutator_thread()->IsAtSafepoint());
   uword start_address = reinterpret_cast<uword>(address);
   uword end_address = start_address + size;
   uword page_address = Utils::RoundDown(start_address, PageSize());
diff --git a/runtime/vm/virtual_memory_linux.cc b/runtime/vm/virtual_memory_linux.cc
index 275c0c6..0228f68 100644
--- a/runtime/vm/virtual_memory_linux.cc
+++ b/runtime/vm/virtual_memory_linux.cc
@@ -13,6 +13,8 @@
 #include "platform/assert.h"
 #include "platform/utils.h"
 
+#include "vm/isolate.h"
+
 namespace dart {
 
 // standard MAP_FAILED causes "error: use of old-style cast" as it
@@ -79,6 +81,8 @@
 
 
 bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
+  ASSERT(Thread::Current()->IsMutatorThread() ||
+         Isolate::Current()->mutator_thread()->IsAtSafepoint());
   uword start_address = reinterpret_cast<uword>(address);
   uword end_address = start_address + size;
   uword page_address = Utils::RoundDown(start_address, PageSize());
diff --git a/runtime/vm/virtual_memory_macos.cc b/runtime/vm/virtual_memory_macos.cc
index f28da35..484ad78 100644
--- a/runtime/vm/virtual_memory_macos.cc
+++ b/runtime/vm/virtual_memory_macos.cc
@@ -13,6 +13,8 @@
 #include "platform/assert.h"
 #include "platform/utils.h"
 
+#include "vm/isolate.h"
+
 namespace dart {
 
 // standard MAP_FAILED causes "error: use of old-style cast" as it
@@ -80,6 +82,8 @@
 
 
 bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
+  ASSERT(Thread::Current()->IsMutatorThread() ||
+         Isolate::Current()->mutator_thread()->IsAtSafepoint());
   uword start_address = reinterpret_cast<uword>(address);
   uword end_address = start_address + size;
   uword page_address = Utils::RoundDown(start_address, PageSize());
diff --git a/runtime/vm/virtual_memory_win.cc b/runtime/vm/virtual_memory_win.cc
index dd154ac..2584613 100644
--- a/runtime/vm/virtual_memory_win.cc
+++ b/runtime/vm/virtual_memory_win.cc
@@ -10,6 +10,8 @@
 #include "platform/assert.h"
 #include "vm/os.h"
 
+#include "vm/isolate.h"
+
 namespace dart {
 
 uword VirtualMemory::page_size_ = 0;
@@ -63,6 +65,8 @@
 
 
 bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
+  ASSERT(Thread::Current()->IsMutatorThread() ||
+         Isolate::Current()->mutator_thread()->IsAtSafepoint());
   uword start_address = reinterpret_cast<uword>(address);
   uword end_address = start_address + size;
   uword page_address = Utils::RoundDown(start_address, PageSize());
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index b3df320..0f857b3 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -74,29 +74,10 @@
           'sources/' : [
             ['exclude', 'gdbjit.cc'],
           ],
-       }],
-       ['dart_vtune_support==0', {
-          'sources/' : [
-            ['exclude', 'vtune\\.(cc|h)$'],
-          ],
-       }],
-       ['dart_vtune_support==1', {
-          'include_dirs': ['<(dart_vtune_root)/include'],
-          'defines': ['DART_VTUNE_SUPPORT'],
-          'link_settings': {
-            'conditions': [
-              ['OS=="linux"', {
-                 'libraries': ['-ljitprofiling'],
-              }],
-              ['OS=="win"', {
-                 'libraries': ['-ljitprofiling.lib'],
-              }],
-            ],
-          },
-        }]],
+       }]],
     },
     {
-      'target_name': 'libdart_vm_precompiled',
+      'target_name': 'libdart_vm_precompiled_runtime',
       'type': 'static_library',
       'toolsets':['host', 'target'],
       'includes': [
@@ -112,7 +93,7 @@
         '..',
       ],
       'defines': [
-        'DART_PRECOMPILED',
+        'DART_PRECOMPILED_RUNTIME',
       ],
       'conditions': [
         ['OS=="linux"', {
@@ -137,26 +118,51 @@
           'sources/' : [
             ['exclude', 'gdbjit.cc'],
           ],
-       }],
-       ['dart_vtune_support==0', {
-          'sources/' : [
-            ['exclude', 'vtune\\.(cc|h)$'],
-          ],
-       }],
-       ['dart_vtune_support==1', {
-          'include_dirs': ['<(dart_vtune_root)/include'],
-          'defines': ['DART_VTUNE_SUPPORT'],
+       }]],
+    },
+    {
+      'target_name': 'libdart_vm_noopt',
+      'type': 'static_library',
+      'toolsets':['host', 'target'],
+      'includes': [
+        'vm_sources.gypi',
+        '../platform/platform_headers.gypi',
+        '../platform/platform_sources.gypi',
+      ],
+      'sources/': [
+        # Exclude all _test.[cc|h] files.
+        ['exclude', '_test\\.(cc|h)$'],
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'defines': [
+        'DART_PRECOMPILER',
+      ],
+      'conditions': [
+        ['OS=="linux"', {
           'link_settings': {
-            'conditions': [
-              ['OS=="linux"', {
-                 'libraries': ['-ljitprofiling'],
-              }],
-              ['OS=="win"', {
-                 'libraries': ['-ljitprofiling.lib'],
-              }],
+            'libraries': [
+              '-lpthread',
+              '-lrt',
+              '-ldl',
             ],
           },
-        }]],
+        }],
+        ['OS=="android" and _toolset=="host"', {
+          'link_settings': {
+            'libraries': [
+              '-lpthread',
+              '-lrt',
+              '-ldl',
+            ],
+          },
+        }],
+        ['OS=="win"', {
+          'sources/' : [
+            ['exclude', 'gdbjit.cc'],
+          ],
+       }]],
     },
     {
       'target_name': 'libdart_vm_nosnapshot',
@@ -176,6 +182,7 @@
       ],
       'defines': [
         'DART_NO_SNAPSHOT',
+        'DART_PRECOMPILER',
       ],
       'conditions': [
         ['OS=="linux"', {
@@ -200,26 +207,7 @@
           'sources/' : [
             ['exclude', 'gdbjit.cc'],
           ],
-       }],
-       ['dart_vtune_support==0', {
-          'sources/' : [
-            ['exclude', 'vtune\\.(cc|h)$'],
-          ],
-       }],
-       ['dart_vtune_support==1', {
-          'include_dirs': ['<(dart_vtune_root)/include'],
-          'defines': ['DART_VTUNE_SUPPORT'],
-          'link_settings': {
-            'conditions': [
-              ['OS=="linux"', {
-                 'libraries': ['-ljitprofiling'],
-              }],
-              ['OS=="win"', {
-                 'libraries': ['-ljitprofiling.lib'],
-              }],
-            ],
-          },
-        }]],
+       }]],
     },
     {
       'target_name': 'libdart_lib_nosnapshot',
@@ -317,6 +305,32 @@
       ],
     },
     {
+      'target_name': 'libdart_lib_precompiled_runtime',
+      'type': 'static_library',
+      'toolsets':['host', 'target'],
+      'includes': [
+        '../lib/async_sources.gypi',
+        '../lib/collection_sources.gypi',
+        '../lib/core_sources.gypi',
+        '../lib/developer_sources.gypi',
+        '../lib/internal_sources.gypi',
+        '../lib/isolate_sources.gypi',
+        '../lib/math_sources.gypi',
+        '../lib/mirrors_sources.gypi',
+        '../lib/typed_data_sources.gypi',
+        '../lib/vmservice_sources.gypi',
+      ],
+      'sources': [
+        'bootstrap_nocore.cc',
+      ],
+      'defines': [
+        'DART_PRECOMPILED_RUNTIME',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+    },
+    {
       'target_name': 'generate_async_cc_file',
       'type': 'none',
       'toolsets':['host'],
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index aa1ee40..ee08b98 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -9,6 +9,8 @@
     'allocation.cc',
     'allocation.h',
     'allocation_test.cc',
+    'aot_optimizer.cc',
+    'aot_optimizer.h',
     'assembler.cc',
     'assembler.h',
     'assembler_arm.cc',
@@ -63,6 +65,8 @@
     'bootstrap.h',
     'bootstrap_natives.cc',
     'bootstrap_natives.h',
+    'branch_optimizer.cc',
+    'branch_optimizer.h',
     'cha.cc',
     'cha.h',
     'cha_test.cc',
@@ -142,9 +146,6 @@
     'debugger_ia32.cc',
     'debugger_mips.cc',
     'debugger_x64.cc',
-    'debuginfo.h',
-    'debuginfo_android.cc',
-    'debuginfo_linux.cc',
     'deferred_objects.cc',
     'deferred_objects.h',
     'deopt_instructions.cc',
@@ -160,11 +161,11 @@
     'double_conversion.cc',
     'double_conversion.h',
     'double_internals.h',
-    'elfgen.h',
     'exceptions.cc',
     'exceptions.h',
     'exceptions_test.cc',
     'find_code_object_test.cc',
+    'flag_list.h',
     'flags.cc',
     'flags.h',
     'flags_test.cc',
@@ -184,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',
@@ -198,10 +197,6 @@
     'gc_marker.h',
     'gc_sweeper.cc',
     'gc_sweeper.h',
-    'gdbjit_android.cc',
-    'gdbjit_android.h',
-    'gdbjit_linux.cc',
-    'gdbjit_linux.h',
     'globals.h',
     'growable_array.h',
     'growable_array_test.cc',
@@ -253,11 +248,14 @@
     'isolate.cc',
     'isolate.h',
     'isolate_test.cc',
+    'jit_optimizer.cc',
+    'jit_optimizer.h',
     'json_stream.h',
     'json_stream.cc',
     'json_test.cc',
     'locations.cc',
     'locations.h',
+    'lockers.cc',
     'lockers.h',
     'log_test.cc',
     'log.cc',
@@ -305,6 +303,7 @@
     'object_id_ring.h',
     'object_id_ring_test.cc',
     'object_mips_test.cc',
+    'object_service.cc',
     'object_set.h',
     'object_store.cc',
     'object_store.h',
@@ -350,6 +349,8 @@
     'raw_object.cc',
     'raw_object.h',
     'raw_object_snapshot.cc',
+    'redundancy_elimination.cc',
+    'redundancy_elimination.h',
     'regexp.cc',
     'regexp.h',
     'regexp_assembler.cc',
@@ -369,7 +370,6 @@
     'regexp_test.cc',
     'report.cc',
     'report.h',
-    'report_test.cc',
     'resolver.cc',
     'resolver.h',
     'resolver_test.cc',
@@ -384,6 +384,8 @@
     'runtime_entry_mips.cc',
     'runtime_entry.cc',
     'runtime_entry_x64.cc',
+    'safepoint.cc',
+    'safepoint.h',
     'scanner.cc',
     'scanner.h',
     'scanner_test.cc',
@@ -472,9 +474,8 @@
     'timer.h',
     'token.cc',
     'token.h',
-    'trace_buffer.cc',
-    'trace_buffer.h',
-    'trace_buffer_test.cc',
+    'token_position.cc',
+    'token_position.h',
     'unibrow.cc',
     'unibrow.h',
     'unibrow-inl.h',
@@ -498,8 +499,6 @@
     'virtual_memory_test.cc',
     'virtual_memory_win.cc',
     'visitor.h',
-    'vtune.cc',
-    'vtune.h',
     'weak_code.cc',
     'weak_code.h',
     'weak_table.cc',
diff --git a/runtime/vm/vtune.cc b/runtime/vm/vtune.cc
deleted file mode 100644
index 57e065a..0000000
--- a/runtime/vm/vtune.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/vtune.h"
-
-#include <jitprofiling.h>
-
-#include "platform/assert.h"
-
-namespace dart {
-
-bool VTuneCodeObserver::IsActive() const {
-  return (iJIT_IsProfilingActive() == iJIT_SAMPLING_ON);
-}
-
-
-void VTuneCodeObserver::Notify(const char* name,
-                               uword base,
-                               uword prologue_offset,
-                               uword size,
-                               bool optimized) {
-  ASSERT(IsActive());
-  iJIT_Method_Load jmethod;
-  memset(&jmethod, 0, sizeof(jmethod));
-  jmethod.method_id = iJIT_GetNewMethodID();
-  jmethod.method_name = const_cast<char*>(name);
-  jmethod.method_load_address = reinterpret_cast<void*>(base);
-  jmethod.method_size = size;
-  iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &jmethod);
-}
-
-}  // namespace dart
diff --git a/runtime/vm/vtune.h b/runtime/vm/vtune.h
deleted file mode 100644
index 4f62aff..0000000
--- a/runtime/vm/vtune.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef VM_VTUNE_H_
-#define VM_VTUNE_H_
-
-#include "vm/code_observers.h"
-
-namespace dart {
-
-#if defined(DART_VTUNE_SUPPORT)
-class VTuneCodeObserver : public CodeObserver {
- public:
-  virtual bool IsActive() const;
-
-  virtual void Notify(const char* name,
-                      uword base,
-                      uword prologue_offset,
-                      uword size,
-                      bool optimized);
-};
-#endif
-
-
-}  // namespace dart
-
-#endif  // VM_VTUNE_H_
diff --git a/runtime/vm/weak_code.cc b/runtime/vm/weak_code.cc
index 7c817d0..eb04d1f 100644
--- a/runtime/vm/weak_code.cc
+++ b/runtime/vm/weak_code.cc
@@ -8,7 +8,6 @@
 
 #include "vm/code_generator.h"
 #include "vm/code_patcher.h"
-#include "vm/compiler.h"
 #include "vm/object.h"
 #include "vm/stack_frame.h"
 
@@ -67,7 +66,7 @@
   if (code_objects.IsNull()) {
     return;
   }
-  ASSERT(Compiler::allow_recompilation());
+  ASSERT(!FLAG_precompiled_mode);
   UpdateArrayTo(Object::null_array());
   // Disable all code on stack.
   Code& code = Code::Handle();
@@ -101,11 +100,9 @@
     } else if (owner.IsClass()) {
       Class& cls = Class::Handle();
       cls ^= owner.raw();
-      OS::Print("Skipping code owned by class %s\n", cls.ToCString());
       cls.DisableAllocationStub();
       continue;
     } else if (owner.IsNull()) {
-      OS::Print("Skipping code owned by null: ");
       code.Print();
       continue;
     }
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index 4f9a484..dc17044 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -13,10 +13,6 @@
 
 namespace dart {
 
-DEFINE_DEBUG_FLAG(bool, trace_zones,
-                  false, "Traces allocation sizes in the zone.");
-
-
 // Zone segments represent chunks of memory: They have starting
 // address encoded in the this pointer and a size in bytes. They are
 // chained together to form the backing storage for an expanding zone.
@@ -115,7 +111,6 @@
 
 
 uword Zone::AllocateExpand(intptr_t size) {
-#if defined(DEBUG)
   ASSERT(size >= 0);
   if (FLAG_trace_zones) {
     OS::PrintErr("*** Expanding zone 0x%" Px "\n",
@@ -127,7 +122,6 @@
   ASSERT(Utils::IsAligned(size, kAlignment));
   intptr_t free_size = (limit_ - position_);
   ASSERT(free_size <  size);
-#endif
 
   // First check to see if we should just chain it as a large segment.
   intptr_t max_size = Utils::RoundDown(kSegmentSize - sizeof(Segment),
@@ -150,14 +144,12 @@
 
 
 uword Zone::AllocateLargeSegment(intptr_t size) {
-#if defined(DEBUG)
   ASSERT(size >= 0);
   // Make sure the requested size is already properly aligned and that
   // there isn't enough room in the Zone to satisfy the request.
   ASSERT(Utils::IsAligned(size, kAlignment));
   intptr_t free_size = (limit_ - position_);
   ASSERT(free_size <  size);
-#endif
 
   // Create a new large segment and chain it up.
   ASSERT(Utils::IsAligned(sizeof(Segment), kAlignment));
@@ -192,7 +184,6 @@
 }
 
 
-#if defined(DEBUG)
 void Zone::DumpZoneSizes() {
   intptr_t size = 0;
   for (Segment* s = large_segments_; s != NULL; s = s->next()) {
@@ -202,7 +193,6 @@
                " Total = %" Pd " Large Segments = %" Pd "\n",
                reinterpret_cast<intptr_t>(this), SizeInBytes(), size);
 }
-#endif
 
 
 void Zone::VisitObjectPointers(ObjectPointerVisitor* visitor) {
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 2008ee9..dc7b25c 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -13,8 +13,6 @@
 
 namespace dart {
 
-DECLARE_DEBUG_FLAG(bool, trace_zones);
-
 // Zones support very fast allocation of small chunks of memory. The
 // chunks cannot be deallocated individually, but instead zones
 // support deallocating all chunks in one fast operation.
@@ -86,11 +84,9 @@
   }
 
   ~Zone() {  // Delete all memory associated with the zone.
-#if defined(DEBUG)
     if (FLAG_trace_zones) {
       DumpZoneSizes();
     }
-#endif
     DeleteAll();
   }
 
@@ -134,10 +130,8 @@
 #endif
   }
 
-#if defined(DEBUG)
   // Dump the current allocated sizes in the zone object.
   void DumpZoneSizes();
-#endif
 
   // Overflow check (FATAL) for array length.
   template <class ElementType>
@@ -186,13 +180,11 @@
  public:
   // Create an empty zone and set is at the current zone for the Thread.
   explicit StackZone(Thread* thread) : StackResource(thread), zone_() {
-#ifdef DEBUG
     if (FLAG_trace_zones) {
       OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n",
                    reinterpret_cast<intptr_t>(this),
                    reinterpret_cast<intptr_t>(&zone_));
     }
-#endif
     zone_.Link(thread->zone());
     thread->set_zone(&zone_);
   }
@@ -201,13 +193,11 @@
   ~StackZone() {
     ASSERT(thread()->zone() == &zone_);
     thread()->set_zone(zone_.previous_);
-#ifdef DEBUG
     if (FLAG_trace_zones) {
       OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n",
                    reinterpret_cast<intptr_t>(this),
                    reinterpret_cast<intptr_t>(&zone_));
     }
-#endif
   }
 
   // Compute the total size of this zone. This includes wasted space that is
diff --git a/runtime/vm/zone_test.cc b/runtime/vm/zone_test.cc
index dceddbf..9ddf276 100644
--- a/runtime/vm/zone_test.cc
+++ b/runtime/vm/zone_test.cc
@@ -10,8 +10,6 @@
 
 namespace dart {
 
-DECLARE_DEBUG_FLAG(bool, trace_zones);
-
 UNIT_TEST_CASE(AllocateZone) {
 #if defined(DEBUG)
   FLAG_trace_zones = true;
diff --git a/samples/samples.status b/samples/samples.status
index 480d3f3..d9739f4 100644
--- a/samples/samples.status
+++ b/samples/samples.status
@@ -24,5 +24,5 @@
 [ $arch == simarm64 ]
 *: Skip
 
-[ $runtime == dart_precompiled ]
+[ $noopt || $runtime == dart_precompiled || $runtime == dart_product ]
 sample_extension: RuntimeError # Platform.executable
diff --git a/sdk/bin/dart2js b/sdk/bin/dart2js
index 988a6fe..248ab07 100755
--- a/sdk/bin/dart2js
+++ b/sdk/bin/dart2js
@@ -52,17 +52,41 @@
 
 DART2JS="$DART_ROOT/pkg/compiler/lib/src/dart2js.dart"
 
-if [ -z "$DART_CONFIGURATION" ];
-then
-  DART_CONFIGURATION="ReleaseX64"
+if [[ `uname` == 'Darwin' ]]; then
+  OUT_DIR="$DART_ROOT/xcodebuild/"
+else
+  OUT_DIR="$DART_ROOT/out/"
 fi
 
-if [[ `uname` == 'Darwin' ]]; then
-  BUILD_DIR="$DART_ROOT/xcodebuild/$DART_CONFIGURATION"
-else
-  BUILD_DIR="$DART_ROOT/out/$DART_CONFIGURATION"
+if [ -z "$DART_CONFIGURATION" ];
+then
+  DIRS=$( ls "$OUT_DIR" )
+  # list of possible configurations in decreasing desirability
+  CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
+    "ReleaseARM"    "ReleaseARM64"    "ReleaseARMV5TE"    "ReleaseMIPS"
+    "DebugARM"      "DebugARM64"      "DebugARMV5TE"      "DebugMIPS")
+  DART_CONFIGURATION="None"
+  for CONFIG in ${CONFIGS[*]}
+  do
+    for DIR in $DIRS;
+    do
+      if [ "$CONFIG" = "$DIR" ];
+      then
+        # choose most desirable configuration that is available and break
+        DART_CONFIGURATION="$DIR"
+        break 2
+      fi
+    done
+  done
+  if [ "$DART_CONFIGURATION" = "None" ]
+  then
+    echo "No valid dart configuration found in $OUT_DIR"
+    exit 1
+  fi
 fi
 
+BUILD_DIR="$OUT_DIR$DART_CONFIGURATION"
+
 PACKAGE_ROOT="$BUILD_DIR/packages/"
 
 exec "$DART" "${EXTRA_VM_OPTIONS[@]}" "--package-root=$PACKAGE_ROOT" "$DART2JS" "${EXTRA_OPTIONS[@]}" "$@"
diff --git a/sdk/lib/_internal/js_runtime/lib/async_patch.dart b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
index 4d91d79..20cd748 100644
--- a/sdk/lib/_internal/js_runtime/lib/async_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
@@ -255,7 +255,7 @@
 /// is done, schedules [asyncBody] again.
 ///
 /// If the async* function wants to do an await it calls this function with
-/// [object] not and [IterationMarker].
+/// [object] not an [IterationMarker].
 ///
 /// If [object] is not a [Future], it is wrapped in a `Future.value`.
 /// The [asyncBody] is called on completion of the future (see [asyncHelper].
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index dfed0df..b5ad1e8 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -106,37 +106,61 @@
 // Patch for Expando implementation.
 @patch
 class Expando<T> {
+  static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
+
+  // Incremented to make unique keys.
+  static int _keyCount = 0;
+
+  // Stores either a JS WeakMap or a "unique" string key.
+  final Object _jsWeakMapOrKey;
+
   @patch
-  Expando([String name]) : this.name = name;
+  Expando([String name])
+      : this.name = name,
+        _jsWeakMapOrKey = JS('bool', 'typeof WeakMap == "function"')
+            ? JS('=Object|Null', 'new WeakMap()')
+            : _createKey();
 
   @patch
   T operator[](Object object) {
-    var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
-    return (values == null) ? null : Primitives.getProperty(values, _getKey());
+    if (_jsWeakMapOrKey is! String) {
+      _checkType(object);  // WeakMap doesn't check on reading, only writing.
+      return JS('', '#.get(#)', _jsWeakMapOrKey, object);
+    }
+    return _getFromObject(_jsWeakMapOrKey, object);
   }
 
   @patch
   void operator[]=(Object object, T value) {
+    if (_jsWeakMapOrKey is! String) {
+      JS('void', '#.set(#, #)', _jsWeakMapOrKey, object, value);
+    } else {
+      _setOnObject(_jsWeakMapOrKey, object, value);
+    }
+  }
+
+  static Object _getFromObject(String key, Object object) {
+    var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
+    return (values == null) ? null : Primitives.getProperty(values, key);
+  }
+
+  static void _setOnObject(String key, Object object, Object value) {
     var values = Primitives.getProperty(object, _EXPANDO_PROPERTY_NAME);
     if (values == null) {
       values = new Object();
       Primitives.setProperty(object, _EXPANDO_PROPERTY_NAME, values);
     }
-    Primitives.setProperty(values, _getKey(), value);
+    Primitives.setProperty(values, key, value);
   }
 
-  String _getKey() {
-    String key = Primitives.getProperty(this, _KEY_PROPERTY_NAME);
-    if (key == null) {
-      key = "expando\$key\$${_keyCount++}";
-      Primitives.setProperty(this, _KEY_PROPERTY_NAME, key);
+  static String _createKey() => "expando\$key\$${_keyCount++}";
+
+  static _checkType(object) {
+    if (object == null || object is bool || object is num || object is String) {
+      throw new ArgumentError.value(object,
+          "Expandos are not allowed on strings, numbers, booleans or null");
     }
-    return key;
   }
-
-  static const String _KEY_PROPERTY_NAME = 'expando\$key';
-  static const String _EXPANDO_PROPERTY_NAME = 'expando\$values';
-  static int _keyCount = 0;
 }
 
 @patch
@@ -316,20 +340,11 @@
   static int _now() => Primitives.timerTicks();
 }
 
-class _ListConstructorSentinel extends JSInt {
-  const _ListConstructorSentinel();
-}
-
 // Patch for List implementation.
 @patch
 class List<E> {
   @patch
-  factory List([int length = const _ListConstructorSentinel()]) {
-    if (length == const _ListConstructorSentinel()) {
-      return new JSArray<E>.emptyGrowable();
-    }
-    return new JSArray<E>.fixed(length);
-  }
+  factory List([int length]) = JSArray<E>.list;
 
   @patch
   factory List.filled(int length, E fill, {bool growable: false}) {
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index 78e53b1..004127b 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.dart
@@ -4,6 +4,11 @@
 
 part of _interceptors;
 
+class _Growable {
+  const _Growable();
+}
+const _ListConstructorSentinel = const _Growable();
+
 /**
  * The interceptor class for [List]. The compiler recognizes this
  * class as an interceptor, and changes references to [:this:] to
@@ -14,6 +19,16 @@
 
   const JSArray();
 
+  // This factory constructor is the redirection target of the List() factory
+  // constructor. [length] has no type to permit the sentinel value.
+  factory JSArray.list([length = _ListConstructorSentinel]) {
+    if (_ListConstructorSentinel == length) {
+      return new JSArray<E>.emptyGrowable();
+    }
+    return new JSArray<E>.fixed(length);
+  }
+
+
   /**
    * Returns a fresh JavaScript Array, marked as fixed-length.
    *
@@ -21,7 +36,8 @@
    */
   factory JSArray.fixed(int length)  {
     // Explicit type test is necessary to guard against JavaScript conversions
-    // in unchecked mode.
+    // in unchecked mode, and against `new Array(null)` which creates a single
+    // element Array containing `null`.
     if (length is !int) {
       throw new ArgumentError.value(length, "length", "is not an integer");
     }
diff --git a/sdk/lib/async/broadcast_stream_controller.dart b/sdk/lib/async/broadcast_stream_controller.dart
index 6f4ddab..a926f1d 100644
--- a/sdk/lib/async/broadcast_stream_controller.dart
+++ b/sdk/lib/async/broadcast_stream_controller.dart
@@ -23,7 +23,7 @@
   // TODO(lrn): Use the _state field on _ControllerSubscription to
   // also store this state. Requires that the subscription implementation
   // does not assume that it's use of the state integer is the only use.
-  int _eventState;
+  int _eventState = 0;  // Initialized to help dart2js type inference.
 
   _BroadcastSubscriptionLink _next;
   _BroadcastSubscriptionLink _previous;
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 48f968f..9fd0ca1 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -225,7 +225,7 @@
     _Future result = new _Future<T>();
     new Timer(duration, () {
       try {
-        result._complete(computation == null ? null : computation());
+        result._complete(computation?.call());
       } catch (e, s) {
         _completeWithErrorCallback(result, e, s);
       }
@@ -546,11 +546,12 @@
    * If this future does not complete before `timeLimit` has passed,
    * the [onTimeout] action is executed instead, and its result (whether it
    * returns or throws) is used as the result of the returned future.
+   * The [onTimeout] function must return a [T] or a `Future<T>`.
    *
    * If `onTimeout` is omitted, a timeout will cause the returned future to
    * complete with a [TimeoutException].
    */
-  Future timeout(Duration timeLimit, {onTimeout()});
+  Future<T> timeout(Duration timeLimit, {onTimeout()});
 }
 
 /**
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index 68dbbc0..ad72431 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.dart
@@ -680,9 +680,9 @@
     }
   }
 
-  Future timeout(Duration timeLimit, {onTimeout()}) {
+  Future<T> timeout(Duration timeLimit, {onTimeout()}) {
     if (_isComplete) return new _Future.immediate(this);
-    _Future result = new _Future();
+    _Future result = new _Future<T>();
     Timer timer;
     if (onTimeout == null) {
       timer = new Timer(timeLimit, () {
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index c2b6c68..b69c6fc 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -325,6 +325,10 @@
    * two arguments it is called with the stack trace (which could be `null` if
    * the stream itself received an error without stack trace).
    * Otherwise it is called with just the error object.
+   * If [onError] is omitted, any errors on the stream are considered unhandled,
+   * and will be passed to the current [Zone]'s error handler.
+   * By default unhandled async errors are treated
+   * as if they were uncaught top-level errors.
    *
    * If this stream closes, the [onDone] handler is called.
    *
@@ -1374,20 +1378,24 @@
  */
 abstract class StreamSubscription<T> {
   /**
-   * Cancels this subscription. It will no longer receive events.
+   * Cancels this subscription.
    *
-   * May return a future which completes when the stream is done cleaning up.
-   * This can be used if the stream needs to release some resources
-   * that are needed for a following operation,
-   * for example a file being read, that should be deleted afterwards.
-   * In that case, the file may not be able to be deleted successfully
-   * until the returned future has completed.
+   * After this call, the subscription no longer receives events.
    *
-   * The future will be completed with a `null` value.
+   * The stream may need to shut down the source of events and clean up after
+   * the subscription is canceled.
+   *
+   * Returns a future that is completed once the stream has finished
+   * its cleanup. May also return `null` if no cleanup was necessary.
+   *
+   * Typically, futures are returned when the stream needs to release resources.
+   * For example, a stream might need to close an open file (as an asynchronous
+   * operation). If the listener wants to delete the file after having
+   * canceled the subscription, it must wait for the cleanup future to complete.
+   *
+   * A returned future completes with a `null` value.
    * If the cleanup throws, which it really shouldn't, the returned future
-   * will be completed with that error.
-   *
-   * Returns `null` if there is no need to wait.
+   * completes with that error.
    */
   Future cancel();
 
@@ -1487,7 +1495,7 @@
 class StreamView<T> extends Stream<T> {
   final Stream<T> _stream;
 
-  StreamView(this._stream);
+  const StreamView(Stream<T> stream) : _stream = stream, super._internal();
 
   bool get isBroadcast => _stream.isBroadcast;
 
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index c8a2465..cd69f44 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -68,9 +68,16 @@
    * If [sync] is true, the returned stream controller is a
    * [SynchronousStreamController], and must be used with the care
    * and attention necessary to not break the [Stream] contract.
+   * See [Completer.sync] for some explanations on when a synchronous
+   * dispatching can be used.
+   * If in doubt, keep the controller non-sync.
    *
-   * The controller will buffer all incoming events until the subscriber is
-   * registered.
+   * A Stream should be inert until a subscriber starts listening on it (using
+   * the [onListen] callback to start producing events). Streams should not
+   * leak resources (like websockets) when no user ever listens on the stream.
+   *
+   * The controller buffers all incoming events until a subscriber is
+   * registered, but this feature should only be used in rare circumstances.
    *
    * The [onPause] function is called when the stream becomes
    * paused. [onResume] is called when the stream resumed.
@@ -100,6 +107,12 @@
    * The [Stream] returned by [stream] is a broadcast stream.
    * It can be listened to more than once.
    *
+   * A Stream should be inert until a subscriber starts listening on it (using
+   * the [onListen] callback to start producing events). Streams should not
+   * leak resources (like websockets) when no user ever listens on the stream.
+   *
+   * Broadcast streams do not buffer events when there is no listener.
+   *
    * The controller distributes any events to all currently subscribed
    * listeners at the time when [add], [addError] or [close] is called.
    * It is not allowed to call `add`, `addError`, or `close` before a previous
@@ -116,6 +129,9 @@
    * The returned stream controller is a [SynchronousStreamController],
    * and must be used with the care and attention necessary to not break
    * the [Stream] contract.
+   * See [Completer.sync] for some explanations on when a synchronous
+   * dispatching can be used.
+   * If in doubt, keep the controller non-sync.
    *
    * If [sync] is false, the event will always be fired at a later time,
    * after the code adding the event has completed.
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index d84f01b..5cc4d88 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -135,33 +135,21 @@
               Map zoneValues): null
   }) {
     return new ZoneSpecification(
-      handleUncaughtError: handleUncaughtError != null
-                           ? handleUncaughtError
-                           : other.handleUncaughtError,
-      run: run != null ? run : other.run,
-      runUnary: runUnary != null ? runUnary : other.runUnary,
-      runBinary: runBinary != null ? runBinary : other.runBinary,
-      registerCallback: registerCallback != null
-                        ? registerCallback
-                        : other.registerCallback,
-      registerUnaryCallback: registerUnaryCallback != null
-                         ? registerUnaryCallback
-                         : other.registerUnaryCallback,
-      registerBinaryCallback: registerBinaryCallback != null
-                         ? registerBinaryCallback
-                         : other.registerBinaryCallback,
-      errorCallback: errorCallback != null
-                         ? errorCallback
-                         : other.errorCallback,
-      scheduleMicrotask: scheduleMicrotask != null
-                         ? scheduleMicrotask
-                         : other.scheduleMicrotask,
-      createTimer : createTimer != null ? createTimer : other.createTimer,
-      createPeriodicTimer: createPeriodicTimer != null
-                           ? createPeriodicTimer
-                           : other.createPeriodicTimer,
-      print : print != null ? print : other.print,
-      fork: fork != null ? fork : other.fork);
+      handleUncaughtError: handleUncaughtError ?? other.handleUncaughtError,
+      run: run ?? other.run,
+      runUnary: runUnary ?? other.runUnary,
+      runBinary: runBinary ?? other.runBinary,
+      registerCallback: registerCallback ?? other.registerCallback,
+      registerUnaryCallback: registerUnaryCallback ??
+                             other.registerUnaryCallback,
+      registerBinaryCallback: registerBinaryCallback ??
+                              other.registerBinaryCallback,
+      errorCallback: errorCallback ?? other.errorCallback,
+      scheduleMicrotask: scheduleMicrotask ?? other.scheduleMicrotask,
+      createTimer : createTimer ?? other.createTimer,
+      createPeriodicTimer: createPeriodicTimer ?? other.createPeriodicTimer,
+      print : print ?? other.print,
+      fork: fork ?? other.fork);
   }
 
   HandleUncaughtErrorHandler get handleUncaughtError;
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index 02e4b71..64586d3 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -175,10 +175,11 @@
 
   Iterable<E> where(bool test(E element)) => new WhereIterable<E>(this, test);
 
-  Iterable map(f(E element)) => new MappedListIterable(this, f);
+  Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(E element)) =>
+      new MappedListIterable/*<E, T>*/(this, f);
 
-  Iterable expand(Iterable f(E element)) =>
-      new ExpandIterable<E, dynamic>(this, f);
+  Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(E element)) =>
+      new ExpandIterable<E, dynamic/*=T*/>(this, f);
 
   E reduce(E combine(E previousValue, E element)) {
     int length = this.length;
@@ -193,7 +194,8 @@
     return value;
   }
 
-  fold(var initialValue, combine(var previousValue, E element)) {
+  dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
+               dynamic/*=T*/ combine(var/*=T*/ previousValue, E element)) {
     var value = initialValue;
     int length = this.length;
     for (int i = 0; i < length; i++) {
diff --git a/sdk/lib/convert/base64.dart b/sdk/lib/convert/base64.dart
index 66c1f0c..eb7519a 100644
--- a/sdk/lib/convert/base64.dart
+++ b/sdk/lib/convert/base64.dart
@@ -270,7 +270,7 @@
 class _AsciiBase64EncoderSink extends _Base64EncoderSink {
   final _Base64Encoder _encoder = new _BufferCachingBase64Encoder();
 
-  final ChunkedConversionSink<String> _sink;
+  final Sink<String> _sink;
 
   _AsciiBase64EncoderSink(this._sink);
 
@@ -684,7 +684,7 @@
 
 class _Base64DecoderSink extends StringConversionSinkBase {
   /** Output sink */
-  final ChunkedConversionSink<List<int>> _sink;
+  final Sink<List<int>> _sink;
   final _Base64Decoder _decoder = new _Base64Decoder();
 
   _Base64DecoderSink(this._sink);
diff --git a/sdk/lib/convert/line_splitter.dart b/sdk/lib/convert/line_splitter.dart
index 0af2f2f..b5ec32b 100644
--- a/sdk/lib/convert/line_splitter.dart
+++ b/sdk/lib/convert/line_splitter.dart
@@ -57,6 +57,9 @@
     }
     return new _LineSplitterSink(sink);
   }
+
+  // Override the base-class' bind, to provide a better type.
+  Stream<String> bind(Stream<String> stream) => super.bind(stream);
 }
 
 // TODO(floitsch): deal with utf8.
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index 28ece3f..b5614af 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -545,7 +545,7 @@
    * * `HH` are hours in the range 00 to 23,
    * * `mm` are minutes in the range 00 to 59,
    * * `ss` are seconds in the range 00 to 59 (no leap seconds),
-   * * `mmm` are microseconds in the range 000 to 999, and
+   * * `mmm` are milliseconds in the range 000 to 999, and
    * * `uuu` are microseconds in the range 001 to 999. If [microsecond] equals
    *   0, then this part is omitted.
    *
diff --git a/sdk/lib/core/regexp.dart b/sdk/lib/core/regexp.dart
index 0d92345..09874c4 100644
--- a/sdk/lib/core/regexp.dart
+++ b/sdk/lib/core/regexp.dart
@@ -28,6 +28,10 @@
  *     RegExp exp = new RegExp(r"(\w+)");
  *     String str = "Parse my string";
  *     Iterable<Match> matches = exp.allMatches(str);
+ * 
+ * Note the use of a _raw string_ (a string prefixed with `r`)
+ * in the example above. Use a raw string to treat each character in a string
+ * as a literal character.
  */
 abstract class RegExp implements Pattern {
   /**
diff --git a/sdk/lib/core/set.dart b/sdk/lib/core/set.dart
index 2c6b524..984c416 100644
--- a/sdk/lib/core/set.dart
+++ b/sdk/lib/core/set.dart
@@ -88,9 +88,25 @@
   bool contains(Object value);
 
   /**
-   * Adds [value] into the set. Returns `true` if [value] was added to the set.
+   * Adds [value] to the set.
    *
-   * If [value] already exists, the set is not changed and `false` is returned.
+   * Returns `true` if [value] (or an equal value) was not yet in the set.
+   * Otherwise returns `false` and the set is not changed.
+   *
+   * Example:
+   *
+   *     var set = new Set();
+   *     var time1 = new DateTime.fromMillisecondsSinceEpoch(0);
+   *     var time2 = new DateTime.fromMillisecondsSinceEpoch(0);
+   *     // time1 and time2 are equal, but not identical.
+   *     Expect.isTrue(time1 == time2);
+   *     Expect.isFalse(identical(time1, time2));
+   *     set.add(time1);  // => true.
+   *     // A value equal to time2 exists already in the set, and the call to
+   *     // add doesn't change the set.
+   *     set.add(time2);  // => false.
+   *     Expect.isTrue(set.length == 1);
+   *     Expect.isTrue(identical(time1, set.first));
    */
   bool add(E value);
 
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index e4a31aa..a1a5b5d 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -76,6 +76,7 @@
    * Cache the computed return value of [queryParameters].
    */
   Map<String, String> _queryParameters;
+  Map<String, List<String>> _queryParameterLists;
 
   /// Internal non-verifying constructor. Only call with validated arguments.
   Uri._internal(this.scheme,
@@ -116,39 +117,46 @@
    * default port.
    *
    * If any of `userInfo`, `host` or `port` are provided,
-   * the URI will have an autority according to [hasAuthority].
+   * the URI has an autority according to [hasAuthority].
    *
    * The path component is set through either [path] or
-   * [pathSegments]. When [path] is used, it should be a valid URI path,
+   * [pathSegments].
+   * When [path] is used, it should be a valid URI path,
    * but invalid characters, except the general delimiters ':/@[]?#',
    * will be escaped if necessary.
    * When [pathSegments] is used, each of the provided segments
    * is first percent-encoded and then joined using the forward slash
-   * separator. The percent-encoding of the path segments encodes all
+   * separator.
+   *
+   * The percent-encoding of the path segments encodes all
    * characters except for the unreserved characters and the following
    * list of characters: `!$&'()*+,;=:@`. If the other components
-   * calls for an absolute path a leading slash `/` is prepended if
+   * necessitate an absolute path, a leading slash `/` is prepended if
    * not already there.
    *
-   * The query component is set through either [query] or
-   * [queryParameters]. When [query] is used the provided string should
-   * be a valid URI query, but invalid characters other than general delimiters,
+   * The query component is set through either [query] or [queryParameters].
+   * When [query] is used, the provided string should be a valid URI query,
+   * but invalid characters, other than general delimiters,
    * will be escaped if necessary.
    * When [queryParameters] is used the query is built from the
    * provided map. Each key and value in the map is percent-encoded
-   * and joined using equal and ampersand characters. The
-   * percent-encoding of the keys and values encodes all characters
-   * except for the unreserved characters.
+   * and joined using equal and ampersand characters.
+   * A value in the map must be either a string, or an [Iterable] of strings,
+   * where the latter corresponds to multiple values for the same key.
+   *
+   * The percent-encoding of the keys and values encodes all characters
+   * except for the unreserved characters, and replaces spaces with `+`.
    * If `query` is the empty string, it is equivalent to omitting it.
    * To have an actual empty query part,
    * use an empty list for `queryParameters`.
-   * If both `query` and `queryParameters` are omitted or `null`, the
-   * URI will have no query part.
+   *
+   * If both `query` and `queryParameters` are omitted or `null`,
+   * the URI has no query part.
    *
    * The fragment component is set through [fragment].
    * It should be a valid URI fragment, but invalid characters other than
-   * general delimiters, will be escaped if necessary.
-   * If `fragment` is omitted or `null`, the URI will have no fragment part.
+   * general delimiters, are escaped if necessary.
+   * If `fragment` is omitted or `null`, the URI has no fragment part.
    */
   factory Uri({String scheme : "",
                String userInfo : "",
@@ -157,7 +165,7 @@
                String path,
                Iterable<String> pathSegments,
                String query,
-               Map<String, String> queryParameters,
+               Map<String, dynamic> queryParameters,
                String fragment}) {
     scheme = _makeScheme(scheme, 0, _stringOrNullLength(scheme));
     userInfo = _makeUserInfo(userInfo, 0, _stringOrNullLength(userInfo));
@@ -207,7 +215,7 @@
    *
    * The `userInfo`, `host` and `port` components are set from the
    * [authority] argument. If `authority` is `null` or empty,
-   * the created `Uri` will have no authority, and will not be directly usable
+   * the created `Uri` has no authority, and isn't directly usable
    * as an HTTP URL, which must have a non-empty host.
    *
    * The `path` component is set from the [unencodedPath]
@@ -1104,23 +1112,53 @@
    * Returns the URI query split into a map according to the rules
    * specified for FORM post in the [HTML 4.01 specification section
    * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
-   * Each key and value in the returned map has been decoded. If there is no
-   * query the empty map is returned.
+   * Each key and value in the returned map has been decoded.
+   * If there is no query the empty map is returned.
    *
    * Keys in the query string that have no value are mapped to the
    * empty string.
+   * If a key occurs more than once in the query string, it is mapped to
+   * an arbitrary choice of possible value.
+   * The [queryParametersAll] getter can provide a map
+   * that maps keys to all of their values.
    *
-   * The returned map is unmodifiable and will throw [UnsupportedError] on any
-   * calls that would mutate it.
+   * The returned map is unmodifiable.
    */
   Map<String, String> get queryParameters {
     if (_queryParameters == null) {
-      _queryParameters = new UnmodifiableMapView(splitQueryString(query));
+      _queryParameters =
+          new UnmodifiableMapView<String, String>(splitQueryString(query));
     }
     return _queryParameters;
   }
 
   /**
+   * Returns the URI query split into a map according to the rules
+   * specified for FORM post in the [HTML 4.01 specification section
+   * 17.13.4](http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4 "HTML 4.01 section 17.13.4").
+   * Each key and value in the returned map has been decoded. If there is no
+   * query the empty map is returned.
+   *
+   * Keys are mapped to lists of their values. If a key occurs only once,
+   * its value is a singleton list. If a key occurs with no value, the
+   * empty string is used as the value for that occurrence.
+   *
+   * The returned map and the lists it contains are unmodifiable.
+   */
+  Map<String, List<String>> get queryParametersAll {
+    if (_queryParameterLists == null) {
+      Map queryParameterLists = _splitQueryStringAll(query);
+      for (var key in queryParameterLists.keys) {
+        queryParameterLists[key] =
+            new List<String>.unmodifiable(queryParameterLists[key]);
+      }
+      _queryParameterLists =
+          new Map<String, List<String>>.unmodifiable(queryParameterLists);
+    }
+    return _queryParameterLists;
+  }
+
+  /**
    * Returns a URI where the path has been normalized.
    *
    * A normalized path does not contain `.` segments or non-leading `..`
@@ -1344,17 +1382,27 @@
     if (query != null) return _normalize(query, start, end, _queryCharTable);
 
     var result = new StringBuffer();
-    var first = true;
-    queryParameters.forEach((key, value) {
-      if (!first) {
-        result.write("&");
-      }
-      first = false;
+    var separator = "";
+
+    void writeParameter(String key, String value) {
+      result.write(separator);
+      separator = "&";
       result.write(Uri.encodeQueryComponent(key));
-      if (value != null && !value.isEmpty) {
+      if (value != null && value.isNotEmpty) {
         result.write("=");
         result.write(Uri.encodeQueryComponent(value));
       }
+    }
+
+    queryParameters.forEach((key, value) {
+      if (value == null || value is String) {
+        writeParameter(key, value);
+      } else {
+        Iterable values = value;
+        for (String value in values) {
+          writeParameter(key, value);
+        }
+      }
     });
     return result.toString();
   }
@@ -2156,6 +2204,46 @@
     });
   }
 
+  static List _createList() => [];
+
+  static Map _splitQueryStringAll(
+      String query, {Encoding encoding: UTF8}) {
+    Map result = {};
+    int i = 0;
+    int start = 0;
+    int equalsIndex = -1;
+
+    void parsePair(int start, int equalsIndex, int end) {
+      String key;
+      String value;
+      if (start == end) return;
+      if (equalsIndex < 0) {
+        key =  _uriDecode(query, start, end, encoding, true);
+        value = "";
+      } else {
+        key = _uriDecode(query, start, equalsIndex, encoding, true);
+        value = _uriDecode(query, equalsIndex + 1, end, encoding, true);
+      }
+      result.putIfAbsent(key, _createList).add(value);
+    }
+
+    const int _equals = 0x3d;
+    const int _ampersand = 0x26;
+    while (i < query.length) {
+      int char = query.codeUnitAt(i);
+      if (char == _equals) {
+        if (equalsIndex < 0) equalsIndex = i;
+      } else if (char == _ampersand) {
+        parsePair(start, equalsIndex, i);
+        start = i + 1;
+        equalsIndex = -1;
+      }
+      i++;
+    }
+    parsePair(start, equalsIndex, i);
+    return result;
+  }
+
   /**
    * Parse the [host] as an IP version 4 (IPv4) address, returning the address
    * as a list of 4 bytes in network byte order (big endian).
diff --git a/sdk/lib/developer/developer_sources.gypi b/sdk/lib/developer/developer_sources.gypi
index 0c4333a..5bdfe3d 100644
--- a/sdk/lib/developer/developer_sources.gypi
+++ b/sdk/lib/developer/developer_sources.gypi
@@ -5,9 +5,9 @@
 {
   'sources': [
     'developer.dart',
+    # The above file needs to be first if additional parts are added to the lib.
     'extension.dart',
     'profiler.dart',
     'timeline.dart',
-    # The above file needs to be first if additional parts are added to the lib.
   ],
 }
diff --git a/sdk/lib/developer/extension.dart b/sdk/lib/developer/extension.dart
index 309dca2..75737f6 100644
--- a/sdk/lib/developer/extension.dart
+++ b/sdk/lib/developer/extension.dart
@@ -4,21 +4,38 @@
 
 part of dart.developer;
 
+/// A response to a service protocol extension RPC.
+///
+/// If the RPC was successful, use [ServiceExtensionResponse.result], otherwise
+/// use [ServiceExtensionResponse.error].
 class ServiceExtensionResponse {
   final String _result;
   final int _errorCode;
   final String _errorDetail;
 
-  ServiceExtensionResponse.result(this._result)
-      : _errorCode = null,
+  /// Creates a successful to a service protocol extension RPC.
+  ///
+  /// Requires [result] to be a JSON object encoded as a string. When forming
+  /// the JSON-RPC message [result] will be inlined directly.
+  ServiceExtensionResponse.result(String result)
+      : _result = result,
+        _errorCode = null,
         _errorDetail = null {
     if (_result is! String) {
       throw new ArgumentError.value(_result, "result", "Must be a String");
     }
   }
 
-  ServiceExtensionResponse.error(this._errorCode, this._errorDetail)
-      : _result = null {
+  /// Creates an error response to a service protocol extension RPC.
+  ///
+  /// Requires [errorCode] to be [invalidParams] or between [extensionErrorMin]
+  /// and [extensionErrorMax]. Requires [errorDetail] to be a JSON object
+  /// encoded as a string. When forming the JSON-RPC message [errorDetail] will
+  /// be inlined directly.
+  ServiceExtensionResponse.error(int errorCode, String errorDetail)
+      : _result = null,
+        _errorCode = errorCode,
+        _errorDetail = errorDetail {
     _validateErrorCode(_errorCode);
     if (_errorDetail is! String) {
       throw new ArgumentError.value(_errorDetail,
@@ -28,13 +45,23 @@
   }
 
   /// Invalid method parameter(s) error code.
-  static const kInvalidParams = -32602;
+  @deprecated static const kInvalidParams = invalidParams;
   /// Generic extension error code.
-  static const kExtensionError = -32000;
+  @deprecated static const kExtensionError = extensionError;
   /// Maximum extension provided error code.
-  static const kExtensionErrorMax = -32000;
+  @deprecated static const kExtensionErrorMax = extensionErrorMax;
   /// Minimum extension provided error code.
-  static const kExtensionErrorMin = -32016;
+  @deprecated static const kExtensionErrorMin = extensionErrorMin;
+
+  /// Invalid method parameter(s) error code.
+  static const invalidParams = -32602;
+  /// Generic extension error code.
+  static const extensionError = -32000;
+  /// Maximum extension provided error code.
+  static const extensionErrorMax = -32000;
+  /// Minimum extension provided error code.
+  static const extensionErrorMin = -32016;
+
 
   static String _errorCodeMessage(int errorCode) {
     _validateErrorCode(errorCode);
@@ -48,11 +75,11 @@
     if (errorCode is! int) {
       throw new ArgumentError.value(errorCode, "errorCode", "Must be an int");
     }
-    if (errorCode == kInvalidParams) {
+    if (errorCode == invalidParams) {
       return;
     }
-    if ((errorCode >= kExtensionErrorMin) &&
-        (errorCode <= kExtensionErrorMax)) {
+    if ((errorCode >= extensionErrorMin) &&
+        (errorCode <= extensionErrorMax)) {
       return;
     }
     throw new ArgumentError.value(errorCode, "errorCode", "Out of range");
@@ -90,14 +117,27 @@
 
 /// Register a [ServiceExtensionHandler] that will be invoked in this isolate
 /// for [method]. *NOTE*: Service protocol extensions must be registered
-/// in each isolate and users of extensions must always specify a target
-/// isolate.
+/// in each isolate.
+///
+/// *NOTE*: [method] must begin with 'ext.' and you should use the following
+/// structure to avoid conflicts with other packages: 'ext.package.command'.
+/// That is, immediately following the 'ext.' prefix, should be the registering
+/// package name followed by another period ('.') and then the command name.
+/// For example: 'ext.dart.io.getOpenFiles'.
+///
+/// Because service extensions are isolate specific, clients using extensions
+/// must always include an 'isolateId' parameter with each RPC.
 void registerExtension(String method, ServiceExtensionHandler handler) {
   if (method is! String) {
     throw new ArgumentError.value(method,
                                   'method',
                                   'Must be a String');
   }
+  if (!method.startsWith('ext.')) {
+    throw new ArgumentError.value(method,
+                                  'method',
+                                  'Must begin with ext.');
+  }
   if (_lookupExtension(method) != null) {
     throw new ArgumentError('Extension already registered: $method');
   }
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 88d2b88..25dce9d 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -15416,7 +15416,7 @@
   @DomName('Event.currentTarget')
   @DocsEditable()
   @Creates('Null')
-  @Returns('EventTarget|=Object')
+  @Returns('EventTarget|=Object|Null')
   final dynamic _get_currentTarget;
 
   @DomName('Event.defaultPrevented')
@@ -15451,7 +15451,7 @@
   @DomName('Event.target')
   @DocsEditable()
   @Creates('Node')
-  @Returns('EventTarget|=Object')
+  @Returns('EventTarget|=Object|Null')
   final dynamic _get_target;
 
   @DomName('Event.timeStamp')
@@ -22962,7 +22962,7 @@
   @DomName('MouseEvent.relatedTarget')
   @DocsEditable()
   @Creates('Node')
-  @Returns('EventTarget|=Object')
+  @Returns('EventTarget|=Object|Null')
   final dynamic _get_relatedTarget;
 
   @JSName('screenX')
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 3ef584b..c306d5b 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -126,9 +126,9 @@
   '_DOMWindowCrossFrame': () => _DOMWindowCrossFrame,
   // FIXME: Move these to better locations.
   'DateTime': () => DateTime,
-  'JsObject': () => js.JsObjectImpl,
-  'JsFunction': () => js.JsFunctionImpl,
-  'JsArray': () => js.JsArrayImpl,
+  'JsObject': () => js.JsObject,
+  'JsFunction': () => js.JsFunction,
+  'JsArray': () => js.JsArray,
   'AbstractWorker': () => AbstractWorker,
   'Animation': () => Animation,
   'AnimationEffect': () => AnimationEffect,
@@ -1128,7 +1128,7 @@
   } else if (runtimeType == TemplateElement) {
     // Data binding with a Dart class.
     tag = element.attributes['is'];
-  } else if (runtimeType == js.JsObjectImpl) {
+  } else if (runtimeType == js.JsObject) {
     // It's a Polymer core element (written in JS).
     // Make sure it's an element anything else we can ignore.
     if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
@@ -1141,7 +1141,7 @@
       }
     }
   } else {
-    throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
+    throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObject.');
   }
 
   return tag;
@@ -1149,15 +1149,9 @@
 
 /// An abstract class for all DOM objects we wrap in dart:html and related
 ///  libraries.
-///
-/// ** Internal Use Only **
 @Deprecated("Internal Use Only")
-class DartHtmlDomObject {
-
-  /// The underlying JS DOM object.
-  @Deprecated("Internal Use Only")
-  js.JsObject blink_jsObject;
-
+class DartHtmlDomObject extends js.JSObject {
+  DartHtmlDomObject() : super.internal();
 }
 
 @Deprecated("Internal Use Only")
@@ -1173,24 +1167,6 @@
   }
 }
 
-// TODO(terry): Manage JS interop JsFunctions for each listener used for add/
-//              removeEventListener.  These JsFunctions will leak look at
-//              fixing with weak-refs in C++.  The key are the hashcodes of the
-//              user's this (this is needed for futures) and listener function.
-Map<int, Map<int, js.JsFunction>> _knownListeners = {};
-
-@Deprecated("Internal Use Only")
-js.JsFunction wrap_event_listener(theObject, Function listener) {
-  var thisHashCode = theObject.hashCode;
-  var listenerHashCode = identityHashCode(listener);
-
-  _knownListeners.putIfAbsent(thisHashCode, () => new Map<int, js.JsFunction>());
-  _knownListeners[thisHashCode].putIfAbsent(listenerHashCode, () =>
-    new js.JsFunction.withThis((theObject, event) => listener(wrap_jso(event))));
-
-  return _knownListeners[thisHashCode][listenerHashCode];
-}
-
 @Deprecated("Internal Use Only")
 Map<String, dynamic> convertNativeObjectToDartMap(js.JsObject jsObject) {
   var result = new Map();
@@ -1279,9 +1255,7 @@
     return new AnchorElement._internalWrap();
   }
 
-  factory AnchorElement._internalWrap() {
-    return new AnchorElement.internal_();
-  }
+  external factory AnchorElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnchorElement.internal_() : super.internal_();
@@ -1474,9 +1448,7 @@
     return new Animation._internalWrap();
   }
 
-  factory Animation._internalWrap() {
-    return new Animation.internal_();
-  }
+  external factory Animation._internalWrap();
 
   @Deprecated("Internal Use Only")
   Animation.internal_() : super.internal_();
@@ -1535,9 +1507,7 @@
     return new AnimationEvent._internalWrap();
   }
 
-  factory AnimationEvent._internalWrap() {
-    return new AnimationEvent.internal_();
-  }
+  external factory AnimationEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnimationEvent.internal_() : super.internal_();
@@ -1642,9 +1612,7 @@
     return new AnimationPlayer._internalWrap();
   }
 
-  factory AnimationPlayer._internalWrap() {
-    return new AnimationPlayer.internal_();
-  }
+  external factory AnimationPlayer._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnimationPlayer.internal_() : super.internal_();
@@ -1744,9 +1712,7 @@
     return new AnimationPlayerEvent._internalWrap();
   }
 
-  factory AnimationPlayerEvent._internalWrap() {
-    return new AnimationPlayerEvent.internal_();
-  }
+  external factory AnimationPlayerEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnimationPlayerEvent.internal_() : super.internal_();
@@ -1916,9 +1882,7 @@
     return new ApplicationCache._internalWrap();
   }
 
-  factory ApplicationCache._internalWrap() {
-    return new ApplicationCache.internal_();
-  }
+  external factory ApplicationCache._internalWrap();
 
   @Deprecated("Internal Use Only")
   ApplicationCache.internal_() : super.internal_();
@@ -2028,9 +1992,7 @@
     return new ApplicationCacheErrorEvent._internalWrap();
   }
 
-  factory ApplicationCacheErrorEvent._internalWrap() {
-    return new ApplicationCacheErrorEvent.internal_();
-  }
+  external factory ApplicationCacheErrorEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   ApplicationCacheErrorEvent.internal_() : super.internal_();
@@ -2090,9 +2052,7 @@
     return new AreaElement._internalWrap();
   }
 
-  factory AreaElement._internalWrap() {
-    return new AreaElement.internal_();
-  }
+  external factory AreaElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AreaElement.internal_() : super.internal_();
@@ -2252,9 +2212,7 @@
     return new AudioElement._internalWrap();
   }
 
-  factory AudioElement._internalWrap() {
-    return new AudioElement.internal_();
-  }
+  external factory AudioElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AudioElement.internal_() : super.internal_();
@@ -2358,9 +2316,7 @@
     return new AudioTrackList._internalWrap();
   }
 
-  factory AudioTrackList._internalWrap() {
-    return new AudioTrackList.internal_();
-  }
+  external factory AudioTrackList._internalWrap();
 
   @Deprecated("Internal Use Only")
   AudioTrackList.internal_() : super.internal_();
@@ -2408,9 +2364,7 @@
     return new AutocompleteErrorEvent._internalWrap();
   }
 
-  factory AutocompleteErrorEvent._internalWrap() {
-    return new AutocompleteErrorEvent.internal_();
-  }
+  external factory AutocompleteErrorEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   AutocompleteErrorEvent.internal_() : super.internal_();
@@ -2444,9 +2398,7 @@
     return new BRElement._internalWrap();
   }
 
-  factory BRElement._internalWrap() {
-    return new BRElement.internal_();
-  }
+  external factory BRElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   BRElement.internal_() : super.internal_();
@@ -2517,9 +2469,7 @@
     return new BaseElement._internalWrap();
   }
 
-  factory BaseElement._internalWrap() {
-    return new BaseElement.internal_();
-  }
+  external factory BaseElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   BaseElement.internal_() : super.internal_();
@@ -2569,9 +2519,7 @@
     return new BatteryManager._internalWrap();
   }
 
-  factory BatteryManager._internalWrap() {
-    return new BatteryManager.internal_();
-  }
+  external factory BatteryManager._internalWrap();
 
   @Deprecated("Internal Use Only")
   BatteryManager.internal_() : super.internal_();
@@ -2613,9 +2561,7 @@
     return new BeforeUnloadEvent._internalWrap();
   }
 
-  factory BeforeUnloadEvent._internalWrap() {
-    return new BeforeUnloadEvent.internal_();
-  }
+  external factory BeforeUnloadEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   BeforeUnloadEvent.internal_() : super.internal_();
@@ -2899,9 +2845,7 @@
     return new BodyElement._internalWrap();
   }
 
-  factory BodyElement._internalWrap() {
-    return new BodyElement.internal_();
-  }
+  external factory BodyElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   BodyElement.internal_() : super.internal_();
@@ -3002,9 +2946,7 @@
     return new ButtonElement._internalWrap();
   }
 
-  factory ButtonElement._internalWrap() {
-    return new ButtonElement.internal_();
-  }
+  external factory ButtonElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ButtonElement.internal_() : super.internal_();
@@ -3147,9 +3089,7 @@
     return new CDataSection._internalWrap();
   }
 
-  factory CDataSection._internalWrap() {
-    return new CDataSection.internal_();
-  }
+  external factory CDataSection._internalWrap();
 
   @Deprecated("Internal Use Only")
   CDataSection.internal_() : super.internal_();
@@ -3305,9 +3245,7 @@
     return new CanvasElement._internalWrap();
   }
 
-  factory CanvasElement._internalWrap() {
-    return new CanvasElement.internal_();
-  }
+  external factory CanvasElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   CanvasElement.internal_() : super.internal_();
@@ -4377,9 +4315,7 @@
     return new CharacterData._internalWrap();
   }
 
-  factory CharacterData._internalWrap() {
-    return new CharacterData.internal_();
-  }
+  external factory CharacterData._internalWrap();
 
   @Deprecated("Internal Use Only")
   CharacterData.internal_() : super.internal_();
@@ -4483,9 +4419,7 @@
     return new CircularGeofencingRegion._internalWrap();
   }
 
-  factory CircularGeofencingRegion._internalWrap() {
-    return new CircularGeofencingRegion.internal_();
-  }
+  external factory CircularGeofencingRegion._internalWrap();
 
   @Deprecated("Internal Use Only")
   CircularGeofencingRegion.internal_() : super.internal_();
@@ -4536,9 +4470,7 @@
     return new CloseEvent._internalWrap();
   }
 
-  factory CloseEvent._internalWrap() {
-    return new CloseEvent.internal_();
-  }
+  external factory CloseEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   CloseEvent.internal_() : super.internal_();
@@ -4583,9 +4515,7 @@
     return new Comment._internalWrap();
   }
 
-  factory Comment._internalWrap() {
-    return new Comment.internal_();
-  }
+  external factory Comment._internalWrap();
 
   @Deprecated("Internal Use Only")
   Comment.internal_() : super.internal_();
@@ -4622,9 +4552,7 @@
     return new CompositionEvent._internalWrap();
   }
 
-  factory CompositionEvent._internalWrap() {
-    return new CompositionEvent.internal_();
-  }
+  external factory CompositionEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   CompositionEvent.internal_() : super.internal_();
@@ -4673,9 +4601,7 @@
     return new Console._internalWrap();
   }
 
-  factory Console._internalWrap() {
-    return new Console.internal_();
-  }
+  external factory Console._internalWrap();
 
   @Deprecated("Internal Use Only")
   Console.internal_() : super.internal_();
@@ -4858,9 +4784,7 @@
     return new ContentElement._internalWrap();
   }
 
-  factory ContentElement._internalWrap() {
-    return new ContentElement.internal_();
-  }
+  external factory ContentElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ContentElement.internal_() : super.internal_();
@@ -5207,9 +5131,7 @@
     return new CssCharsetRule._internalWrap();
   }
 
-  factory CssCharsetRule._internalWrap() {
-    return new CssCharsetRule.internal_();
-  }
+  external factory CssCharsetRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssCharsetRule.internal_() : super.internal_();
@@ -5247,9 +5169,7 @@
     return new CssFilterRule._internalWrap();
   }
 
-  factory CssFilterRule._internalWrap() {
-    return new CssFilterRule.internal_();
-  }
+  external factory CssFilterRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssFilterRule.internal_() : super.internal_();
@@ -5279,9 +5199,7 @@
     return new CssFontFaceRule._internalWrap();
   }
 
-  factory CssFontFaceRule._internalWrap() {
-    return new CssFontFaceRule.internal_();
-  }
+  external factory CssFontFaceRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssFontFaceRule.internal_() : super.internal_();
@@ -5311,9 +5229,7 @@
     return new CssImportRule._internalWrap();
   }
 
-  factory CssImportRule._internalWrap() {
-    return new CssImportRule.internal_();
-  }
+  external factory CssImportRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssImportRule.internal_() : super.internal_();
@@ -5352,9 +5268,7 @@
     return new CssKeyframeRule._internalWrap();
   }
 
-  factory CssKeyframeRule._internalWrap() {
-    return new CssKeyframeRule.internal_();
-  }
+  external factory CssKeyframeRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssKeyframeRule.internal_() : super.internal_();
@@ -5396,9 +5310,7 @@
     return new CssKeyframesRule._internalWrap();
   }
 
-  factory CssKeyframesRule._internalWrap() {
-    return new CssKeyframesRule.internal_();
-  }
+  external factory CssKeyframesRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssKeyframesRule.internal_() : super.internal_();
@@ -5459,9 +5371,7 @@
     return new CssMediaRule._internalWrap();
   }
 
-  factory CssMediaRule._internalWrap() {
-    return new CssMediaRule.internal_();
-  }
+  external factory CssMediaRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssMediaRule.internal_() : super.internal_();
@@ -5503,9 +5413,7 @@
     return new CssPageRule._internalWrap();
   }
 
-  factory CssPageRule._internalWrap() {
-    return new CssPageRule.internal_();
-  }
+  external factory CssPageRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssPageRule.internal_() : super.internal_();
@@ -8940,9 +8848,7 @@
     return new CssStyleRule._internalWrap();
   }
 
-  factory CssStyleRule._internalWrap() {
-    return new CssStyleRule.internal_();
-  }
+  external factory CssStyleRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssStyleRule.internal_() : super.internal_();
@@ -8980,9 +8886,7 @@
     return new CssStyleSheet._internalWrap();
   }
 
-  factory CssStyleSheet._internalWrap() {
-    return new CssStyleSheet.internal_();
-  }
+  external factory CssStyleSheet._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssStyleSheet.internal_() : super.internal_();
@@ -9044,9 +8948,7 @@
     return new CssSupportsRule._internalWrap();
   }
 
-  factory CssSupportsRule._internalWrap() {
-    return new CssSupportsRule.internal_();
-  }
+  external factory CssSupportsRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssSupportsRule.internal_() : super.internal_();
@@ -9089,9 +8991,7 @@
     return new CssViewportRule._internalWrap();
   }
 
-  factory CssViewportRule._internalWrap() {
-    return new CssViewportRule.internal_();
-  }
+  external factory CssViewportRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   CssViewportRule.internal_() : super.internal_();
@@ -9155,9 +9055,7 @@
     return new CustomEvent._internalWrap();
   }
 
-  factory CustomEvent._internalWrap() {
-    return new CustomEvent.internal_();
-  }
+  external factory CustomEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   CustomEvent.internal_() : super.internal_();
@@ -9195,9 +9093,7 @@
     return new DListElement._internalWrap();
   }
 
-  factory DListElement._internalWrap() {
-    return new DListElement.internal_();
-  }
+  external factory DListElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   DListElement.internal_() : super.internal_();
@@ -9237,9 +9133,7 @@
     return new DataListElement._internalWrap();
   }
 
-  factory DataListElement._internalWrap() {
-    return new DataListElement.internal_();
-  }
+  external factory DataListElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   DataListElement.internal_() : super.internal_();
@@ -9524,9 +9418,7 @@
     return new DedicatedWorkerGlobalScope._internalWrap();
   }
 
-  factory DedicatedWorkerGlobalScope._internalWrap() {
-    return new DedicatedWorkerGlobalScope.internal_();
-  }
+  external factory DedicatedWorkerGlobalScope._internalWrap();
 
   @Deprecated("Internal Use Only")
   DedicatedWorkerGlobalScope.internal_() : super.internal_();
@@ -9688,9 +9580,7 @@
     return new DetailsElement._internalWrap();
   }
 
-  factory DetailsElement._internalWrap() {
-    return new DetailsElement.internal_();
-  }
+  external factory DetailsElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   DetailsElement.internal_() : super.internal_();
@@ -9777,9 +9667,7 @@
     return new DeviceLightEvent._internalWrap();
   }
 
-  factory DeviceLightEvent._internalWrap() {
-    return new DeviceLightEvent.internal_();
-  }
+  external factory DeviceLightEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   DeviceLightEvent.internal_() : super.internal_();
@@ -9812,9 +9700,7 @@
     return new DeviceMotionEvent._internalWrap();
   }
 
-  factory DeviceMotionEvent._internalWrap() {
-    return new DeviceMotionEvent.internal_();
-  }
+  external factory DeviceMotionEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   DeviceMotionEvent.internal_() : super.internal_();
@@ -9869,9 +9755,7 @@
     return new DeviceOrientationEvent._internalWrap();
   }
 
-  factory DeviceOrientationEvent._internalWrap() {
-    return new DeviceOrientationEvent.internal_();
-  }
+  external factory DeviceOrientationEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   DeviceOrientationEvent.internal_() : super.internal_();
@@ -9961,9 +9845,7 @@
     return new DialogElement._internalWrap();
   }
 
-  factory DialogElement._internalWrap() {
-    return new DialogElement.internal_();
-  }
+  external factory DialogElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   DialogElement.internal_() : super.internal_();
@@ -10061,9 +9943,7 @@
     return new DirectoryEntry._internalWrap();
   }
 
-  factory DirectoryEntry._internalWrap() {
-    return new DirectoryEntry.internal_();
-  }
+  external factory DirectoryEntry._internalWrap();
 
   @Deprecated("Internal Use Only")
   DirectoryEntry.internal_() : super.internal_();
@@ -10234,9 +10114,7 @@
     return new DivElement._internalWrap();
   }
 
-  factory DivElement._internalWrap() {
-    return new DivElement.internal_();
-  }
+  external factory DivElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   DivElement.internal_() : super.internal_();
@@ -10319,9 +10197,7 @@
     return new Document._internalWrap();
   }
 
-  factory Document._internalWrap() {
-    return new Document.internal_();
-  }
+  external factory Document._internalWrap();
 
   @Deprecated("Internal Use Only")
   Document.internal_() : super.internal_();
@@ -11258,9 +11134,7 @@
     return new DocumentFragment._internalWrap();
   }
 
-  factory DocumentFragment._internalWrap() {
-    return new DocumentFragment.internal_();
-  }
+  external factory DocumentFragment._internalWrap();
 
   @Deprecated("Internal Use Only")
   DocumentFragment.internal_() : super.internal_();
@@ -11390,12 +11264,7 @@
     return new DomException._internalWrap();
   }
 
-  @Deprecated("Internal Use Only")
-  js.JsObject blink_jsObject;
-
-  factory DomException._internalWrap() {
-    return new DomException.internal_();
-  }
+  external factory DomException._internalWrap();
 
   @Deprecated("Internal Use Only")
   DomException.internal_() { }
@@ -11539,9 +11408,7 @@
     return new DomMatrix._internalWrap();
   }
 
-  factory DomMatrix._internalWrap() {
-    return new DomMatrix.internal_();
-  }
+  external factory DomMatrix._internalWrap();
 
   @Deprecated("Internal Use Only")
   DomMatrix.internal_() : super.internal_();
@@ -12122,9 +11989,7 @@
     return new DomPoint._internalWrap();
   }
 
-  factory DomPoint._internalWrap() {
-    return new DomPoint.internal_();
-  }
+  external factory DomPoint._internalWrap();
 
   @Deprecated("Internal Use Only")
   DomPoint.internal_() : super.internal_();
@@ -12411,9 +12276,7 @@
     return new DomSettableTokenList._internalWrap();
   }
 
-  factory DomSettableTokenList._internalWrap() {
-    return new DomSettableTokenList.internal_();
-  }
+  external factory DomSettableTokenList._internalWrap();
 
   @Deprecated("Internal Use Only")
   DomSettableTokenList.internal_() : super.internal_();
@@ -15593,9 +15456,7 @@
     return new Element._internalWrap();
   }
 
-  factory Element._internalWrap() {
-    return new Element.internal_();
-  }
+  external factory Element._internalWrap();
 
   @Deprecated("Internal Use Only")
   Element.internal_() : super.internal_();
@@ -16481,9 +16342,7 @@
     return new EmbedElement._internalWrap();
   }
 
-  factory EmbedElement._internalWrap() {
-    return new EmbedElement.internal_();
-  }
+  external factory EmbedElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   EmbedElement.internal_() : super.internal_();
@@ -16770,9 +16629,7 @@
     return new ErrorEvent._internalWrap();
   }
 
-  factory ErrorEvent._internalWrap() {
-    return new ErrorEvent.internal_();
-  }
+  external factory ErrorEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   ErrorEvent.internal_() : super.internal_();
@@ -17060,9 +16917,7 @@
     return new EventSource._internalWrap();
   }
 
-  factory EventSource._internalWrap() {
-    return new EventSource.internal_();
-  }
+  external factory EventSource._internalWrap();
 
   @Deprecated("Internal Use Only")
   EventSource.internal_() : super.internal_();
@@ -17257,11 +17112,11 @@
 
   void _addEventListener([String type, EventListener listener, bool useCapture]) {
     if (useCapture != null) {
-      _blink.BlinkEventTarget.instance.addEventListener_Callback_3_(unwrap_jso(this), type, wrap_event_listener(this, listener), useCapture);
+      _blink.BlinkEventTarget.instance.addEventListener_Callback_3_(unwrap_jso(this), type, unwrap_jso(js.allowInterop(listener)), useCapture);
       return;
     }
     if (listener != null) {
-      _blink.BlinkEventTarget.instance.addEventListener_Callback_2_(unwrap_jso(this), type, wrap_event_listener(this, listener));
+      _blink.BlinkEventTarget.instance.addEventListener_Callback_2_(unwrap_jso(this), type, unwrap_jso(js.allowInterop(listener)));
       return;
     }
     if (type != null) {
@@ -17278,11 +17133,11 @@
   
   void _removeEventListener([String type, EventListener listener, bool useCapture]) {
     if (useCapture != null) {
-      _blink.BlinkEventTarget.instance.removeEventListener_Callback_3_(unwrap_jso(this), type, _knownListeners[this.hashCode][identityHashCode(listener)], useCapture);
+      _blink.BlinkEventTarget.instance.removeEventListener_Callback_3_(unwrap_jso(this), type, unwrap_jso(js.allowInterop(listener)), useCapture);
       return;
     }
     if (listener != null) {
-      _blink.BlinkEventTarget.instance.removeEventListener_Callback_2_(unwrap_jso(this), type, _knownListeners[this.hashCode][identityHashCode(listener)]);
+      _blink.BlinkEventTarget.instance.removeEventListener_Callback_2_(unwrap_jso(this), type, unwrap_jso(js.allowInterop(listener)));
       return;
     }
     if (type != null) {
@@ -17314,9 +17169,7 @@
     return new ExtendableEvent._internalWrap();
   }
 
-  factory ExtendableEvent._internalWrap() {
-    return new ExtendableEvent.internal_();
-  }
+  external factory ExtendableEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   ExtendableEvent.internal_() : super.internal_();
@@ -17354,9 +17207,7 @@
     return new FederatedCredential._internalWrap();
   }
 
-  factory FederatedCredential._internalWrap() {
-    return new FederatedCredential.internal_();
-  }
+  external factory FederatedCredential._internalWrap();
 
   @Deprecated("Internal Use Only")
   FederatedCredential.internal_() : super.internal_();
@@ -17388,9 +17239,7 @@
     return new FetchEvent._internalWrap();
   }
 
-  factory FetchEvent._internalWrap() {
-    return new FetchEvent.internal_();
-  }
+  external factory FetchEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   FetchEvent.internal_() : super.internal_();
@@ -17436,9 +17285,7 @@
     return new FieldSetElement._internalWrap();
   }
 
-  factory FieldSetElement._internalWrap() {
-    return new FieldSetElement.internal_();
-  }
+  external factory FieldSetElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FieldSetElement.internal_() : super.internal_();
@@ -17518,9 +17365,7 @@
     return new File._internalWrap();
   }
 
-  factory File._internalWrap() {
-    return new File.internal_();
-  }
+  external factory File._internalWrap();
 
   @Deprecated("Internal Use Only")
   File.internal_() : super.internal_();
@@ -17580,9 +17425,7 @@
     return new FileEntry._internalWrap();
   }
 
-  factory FileEntry._internalWrap() {
-    return new FileEntry.internal_();
-  }
+  external factory FileEntry._internalWrap();
 
   @Deprecated("Internal Use Only")
   FileEntry.internal_() : super.internal_();
@@ -17644,9 +17487,7 @@
     return new FileError._internalWrap();
   }
 
-  factory FileError._internalWrap() {
-    return new FileError.internal_();
-  }
+  external factory FileError._internalWrap();
 
   @Deprecated("Internal Use Only")
   FileError.internal_() : super.internal_();
@@ -17882,9 +17723,7 @@
     return new FileReader._internalWrap();
   }
 
-  factory FileReader._internalWrap() {
-    return new FileReader.internal_();
-  }
+  external factory FileReader._internalWrap();
 
   @Deprecated("Internal Use Only")
   FileReader.internal_() : super.internal_();
@@ -18136,9 +17975,7 @@
     return new FileWriter._internalWrap();
   }
 
-  factory FileWriter._internalWrap() {
-    return new FileWriter.internal_();
-  }
+  external factory FileWriter._internalWrap();
 
   @Deprecated("Internal Use Only")
   FileWriter.internal_() : super.internal_();
@@ -18249,9 +18086,7 @@
     return new FocusEvent._internalWrap();
   }
 
-  factory FocusEvent._internalWrap() {
-    return new FocusEvent.internal_();
-  }
+  external factory FocusEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   FocusEvent.internal_() : super.internal_();
@@ -18424,9 +18259,7 @@
     return new FontFaceSet._internalWrap();
   }
 
-  factory FontFaceSet._internalWrap() {
-    return new FontFaceSet.internal_();
-  }
+  external factory FontFaceSet._internalWrap();
 
   @Deprecated("Internal Use Only")
   FontFaceSet.internal_() : super.internal_();
@@ -18509,9 +18342,7 @@
     return new FontFaceSetLoadEvent._internalWrap();
   }
 
-  factory FontFaceSetLoadEvent._internalWrap() {
-    return new FontFaceSetLoadEvent.internal_();
-  }
+  external factory FontFaceSetLoadEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   FontFaceSetLoadEvent.internal_() : super.internal_();
@@ -18597,9 +18428,7 @@
     return new FormElement._internalWrap();
   }
 
-  factory FormElement._internalWrap() {
-    return new FormElement.internal_();
-  }
+  external factory FormElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FormElement.internal_() : super.internal_();
@@ -18837,9 +18666,7 @@
     return new GamepadEvent._internalWrap();
   }
 
-  factory GamepadEvent._internalWrap() {
-    return new GamepadEvent.internal_();
-  }
+  external factory GamepadEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   GamepadEvent.internal_() : super.internal_();
@@ -19662,9 +19489,7 @@
     return new HRElement._internalWrap();
   }
 
-  factory HRElement._internalWrap() {
-    return new HRElement.internal_();
-  }
+  external factory HRElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   HRElement.internal_() : super.internal_();
@@ -19719,9 +19544,7 @@
     return new HashChangeEvent._internalWrap();
   }
 
-  factory HashChangeEvent._internalWrap() {
-    return new HashChangeEvent.internal_();
-  }
+  external factory HashChangeEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   HashChangeEvent.internal_() : super.internal_();
@@ -19766,9 +19589,7 @@
     return new HeadElement._internalWrap();
   }
 
-  factory HeadElement._internalWrap() {
-    return new HeadElement.internal_();
-  }
+  external factory HeadElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   HeadElement.internal_() : super.internal_();
@@ -19894,9 +19715,7 @@
     return new HeadingElement._internalWrap();
   }
 
-  factory HeadingElement._internalWrap() {
-    return new HeadingElement.internal_();
-  }
+  external factory HeadingElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   HeadingElement.internal_() : super.internal_();
@@ -20086,9 +19905,7 @@
     return new HtmlDocument._internalWrap();
   }
 
-  factory HtmlDocument._internalWrap() {
-    return new HtmlDocument.internal_();
-  }
+  external factory HtmlDocument._internalWrap();
 
   @Deprecated("Internal Use Only")
   HtmlDocument.internal_() : super.internal_();
@@ -20888,9 +20705,7 @@
     return new HtmlElement._internalWrap();
   }
 
-  factory HtmlElement._internalWrap() {
-    return new HtmlElement.internal_();
-  }
+  external factory HtmlElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   HtmlElement.internal_() : super.internal_();
@@ -21309,9 +21124,7 @@
     return new HtmlFormControlsCollection._internalWrap();
   }
 
-  factory HtmlFormControlsCollection._internalWrap() {
-    return new HtmlFormControlsCollection.internal_();
-  }
+  external factory HtmlFormControlsCollection._internalWrap();
 
   @Deprecated("Internal Use Only")
   HtmlFormControlsCollection.internal_() : super.internal_();
@@ -21345,9 +21158,7 @@
     return new HtmlHtmlElement._internalWrap();
   }
 
-  factory HtmlHtmlElement._internalWrap() {
-    return new HtmlHtmlElement.internal_();
-  }
+  external factory HtmlHtmlElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   HtmlHtmlElement.internal_() : super.internal_();
@@ -21379,9 +21190,7 @@
     return new HtmlOptionsCollection._internalWrap();
   }
 
-  factory HtmlOptionsCollection._internalWrap() {
-    return new HtmlOptionsCollection.internal_();
-  }
+  external factory HtmlOptionsCollection._internalWrap();
 
   @Deprecated("Internal Use Only")
   HtmlOptionsCollection.internal_() : super.internal_();
@@ -21791,9 +21600,7 @@
     return new HttpRequest._internalWrap();
   }
 
-  factory HttpRequest._internalWrap() {
-    return new HttpRequest.internal_();
-  }
+  external factory HttpRequest._internalWrap();
 
   @Deprecated("Internal Use Only")
   HttpRequest.internal_() : super.internal_();
@@ -22204,9 +22011,7 @@
     return new HttpRequestEventTarget._internalWrap();
   }
 
-  factory HttpRequestEventTarget._internalWrap() {
-    return new HttpRequestEventTarget.internal_();
-  }
+  external factory HttpRequestEventTarget._internalWrap();
 
   @Deprecated("Internal Use Only")
   HttpRequestEventTarget.internal_() : super.internal_();
@@ -22284,9 +22089,7 @@
     return new HttpRequestUpload._internalWrap();
   }
 
-  factory HttpRequestUpload._internalWrap() {
-    return new HttpRequestUpload.internal_();
-  }
+  external factory HttpRequestUpload._internalWrap();
 
   @Deprecated("Internal Use Only")
   HttpRequestUpload.internal_() : super.internal_();
@@ -22316,9 +22119,7 @@
     return new IFrameElement._internalWrap();
   }
 
-  factory IFrameElement._internalWrap() {
-    return new IFrameElement.internal_();
-  }
+  external factory IFrameElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   IFrameElement.internal_() : super.internal_();
@@ -22527,9 +22328,7 @@
     return new ImageElement._internalWrap();
   }
 
-  factory ImageElement._internalWrap() {
-    return new ImageElement.internal_();
-  }
+  external factory ImageElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ImageElement.internal_() : super.internal_();
@@ -22729,9 +22528,7 @@
     return new InputElement._internalWrap();
   }
 
-  factory InputElement._internalWrap() {
-    return new InputElement.internal_();
-  }
+  external factory InputElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   InputElement.internal_() : super.internal_();
@@ -23751,9 +23548,7 @@
     return new InputMethodContext._internalWrap();
   }
 
-  factory InputMethodContext._internalWrap() {
-    return new InputMethodContext.internal_();
-  }
+  external factory InputMethodContext._internalWrap();
 
   @Deprecated("Internal Use Only")
   InputMethodContext.internal_() : super.internal_();
@@ -23803,9 +23598,7 @@
     return new InstallEvent._internalWrap();
   }
 
-  factory InstallEvent._internalWrap() {
-    return new InstallEvent.internal_();
-  }
+  external factory InstallEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   InstallEvent.internal_() : super.internal_();
@@ -23857,9 +23650,7 @@
     return new KeyboardEvent._internalWrap();
   }
 
-  factory KeyboardEvent._internalWrap() {
-    return new KeyboardEvent.internal_();
-  }
+  external factory KeyboardEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   KeyboardEvent.internal_() : super.internal_();
@@ -23958,9 +23749,7 @@
     return new KeygenElement._internalWrap();
   }
 
-  factory KeygenElement._internalWrap() {
-    return new KeygenElement.internal_();
-  }
+  external factory KeygenElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   KeygenElement.internal_() : super.internal_();
@@ -24072,9 +23861,7 @@
     return new LIElement._internalWrap();
   }
 
-  factory LIElement._internalWrap() {
-    return new LIElement.internal_();
-  }
+  external factory LIElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   LIElement.internal_() : super.internal_();
@@ -24118,9 +23905,7 @@
     return new LabelElement._internalWrap();
   }
 
-  factory LabelElement._internalWrap() {
-    return new LabelElement.internal_();
-  }
+  external factory LabelElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   LabelElement.internal_() : super.internal_();
@@ -24172,9 +23957,7 @@
     return new LegendElement._internalWrap();
   }
 
-  factory LegendElement._internalWrap() {
-    return new LegendElement.internal_();
-  }
+  external factory LegendElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   LegendElement.internal_() : super.internal_();
@@ -24212,9 +23995,7 @@
     return new LinkElement._internalWrap();
   }
 
-  factory LinkElement._internalWrap() {
-    return new LinkElement.internal_();
-  }
+  external factory LinkElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   LinkElement.internal_() : super.internal_();
@@ -24340,9 +24121,7 @@
     return new LocalCredential._internalWrap();
   }
 
-  factory LocalCredential._internalWrap() {
-    return new LocalCredential.internal_();
-  }
+  external factory LocalCredential._internalWrap();
 
   @Deprecated("Internal Use Only")
   LocalCredential.internal_() : super.internal_();
@@ -24518,9 +24297,7 @@
     return new MapElement._internalWrap();
   }
 
-  factory MapElement._internalWrap() {
-    return new MapElement.internal_();
-  }
+  external factory MapElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MapElement.internal_() : super.internal_();
@@ -24572,9 +24349,7 @@
     return new MediaController._internalWrap();
   }
 
-  factory MediaController._internalWrap() {
-    return new MediaController.internal_();
-  }
+  external factory MediaController._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaController.internal_() : super.internal_();
@@ -24793,9 +24568,7 @@
     return new MediaElement._internalWrap();
   }
 
-  factory MediaElement._internalWrap() {
-    return new MediaElement.internal_();
-  }
+  external factory MediaElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaElement.internal_() : super.internal_();
@@ -25279,9 +25052,7 @@
     return new MediaKeyEvent._internalWrap();
   }
 
-  factory MediaKeyEvent._internalWrap() {
-    return new MediaKeyEvent.internal_();
-  }
+  external factory MediaKeyEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaKeyEvent.internal_() : super.internal_();
@@ -25337,9 +25108,7 @@
     return new MediaKeyMessageEvent._internalWrap();
   }
 
-  factory MediaKeyMessageEvent._internalWrap() {
-    return new MediaKeyMessageEvent.internal_();
-  }
+  external factory MediaKeyMessageEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaKeyMessageEvent.internal_() : super.internal_();
@@ -25375,9 +25144,7 @@
     return new MediaKeyNeededEvent._internalWrap();
   }
 
-  factory MediaKeyNeededEvent._internalWrap() {
-    return new MediaKeyNeededEvent.internal_();
-  }
+  external factory MediaKeyNeededEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaKeyNeededEvent.internal_() : super.internal_();
@@ -25414,9 +25181,7 @@
     return new MediaKeySession._internalWrap();
   }
 
-  factory MediaKeySession._internalWrap() {
-    return new MediaKeySession.internal_();
-  }
+  external factory MediaKeySession._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaKeySession.internal_() : super.internal_();
@@ -25596,9 +25361,7 @@
     return new MediaQueryList._internalWrap();
   }
 
-  factory MediaQueryList._internalWrap() {
-    return new MediaQueryList.internal_();
-  }
+  external factory MediaQueryList._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaQueryList.internal_() : super.internal_();
@@ -25646,9 +25409,7 @@
     return new MediaQueryListEvent._internalWrap();
   }
 
-  factory MediaQueryListEvent._internalWrap() {
-    return new MediaQueryListEvent.internal_();
-  }
+  external factory MediaQueryListEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaQueryListEvent.internal_() : super.internal_();
@@ -25694,9 +25455,7 @@
     return new MediaSource._internalWrap();
   }
 
-  factory MediaSource._internalWrap() {
-    return new MediaSource.internal_();
-  }
+  external factory MediaSource._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaSource.internal_() : super.internal_();
@@ -25811,9 +25570,7 @@
     return new MediaStream._internalWrap();
   }
 
-  factory MediaStream._internalWrap() {
-    return new MediaStream.internal_();
-  }
+  external factory MediaStream._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaStream.internal_() : super.internal_();
@@ -25913,9 +25670,7 @@
     return new MediaStreamEvent._internalWrap();
   }
 
-  factory MediaStreamEvent._internalWrap() {
-    return new MediaStreamEvent.internal_();
-  }
+  external factory MediaStreamEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaStreamEvent.internal_() : super.internal_();
@@ -25981,9 +25736,7 @@
     return new MediaStreamTrack._internalWrap();
   }
 
-  factory MediaStreamTrack._internalWrap() {
-    return new MediaStreamTrack.internal_();
-  }
+  external factory MediaStreamTrack._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaStreamTrack.internal_() : super.internal_();
@@ -26078,9 +25831,7 @@
     return new MediaStreamTrackEvent._internalWrap();
   }
 
-  factory MediaStreamTrackEvent._internalWrap() {
-    return new MediaStreamTrackEvent.internal_();
-  }
+  external factory MediaStreamTrackEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaStreamTrackEvent.internal_() : super.internal_();
@@ -26179,9 +25930,7 @@
     return new MenuElement._internalWrap();
   }
 
-  factory MenuElement._internalWrap() {
-    return new MenuElement.internal_();
-  }
+  external factory MenuElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MenuElement.internal_() : super.internal_();
@@ -26234,9 +25983,7 @@
     return new MenuItemElement._internalWrap();
   }
 
-  factory MenuItemElement._internalWrap() {
-    return new MenuItemElement.internal_();
-  }
+  external factory MenuItemElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MenuItemElement.internal_() : super.internal_();
@@ -26367,9 +26114,7 @@
     return new MessageEvent._internalWrap();
   }
 
-  factory MessageEvent._internalWrap() {
-    return new MessageEvent.internal_();
-  }
+  external factory MessageEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MessageEvent.internal_() : super.internal_();
@@ -26377,8 +26122,12 @@
 
   @DomName('MessageEvent.data')
   @DocsEditable()
-  Object get data => wrap_jso(_blink.BlinkMessageEvent.instance.data_Getter_(unwrap_jso(this)));
-  
+  // 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.
+  dynamic get data => convertNativeToDart_SerializedScriptValue(
+      _blink.BlinkMessageEvent.instance.data_Getter_(unwrap_jso(this)));
+
   @DomName('MessageEvent.lastEventId')
   @DocsEditable()
   @Unstable()
@@ -26427,9 +26176,7 @@
     return new MessagePort._internalWrap();
   }
 
-  factory MessagePort._internalWrap() {
-    return new MessagePort.internal_();
-  }
+  external factory MessagePort._internalWrap();
 
   @Deprecated("Internal Use Only")
   MessagePort.internal_() : super.internal_();
@@ -26476,9 +26223,7 @@
     return new MetaElement._internalWrap();
   }
 
-  factory MetaElement._internalWrap() {
-    return new MetaElement.internal_();
-  }
+  external factory MetaElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MetaElement.internal_() : super.internal_();
@@ -26592,9 +26337,7 @@
     return new MeterElement._internalWrap();
   }
 
-  factory MeterElement._internalWrap() {
-    return new MeterElement.internal_();
-  }
+  external factory MeterElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MeterElement.internal_() : super.internal_();
@@ -26704,9 +26447,7 @@
     return new MidiAccess._internalWrap();
   }
 
-  factory MidiAccess._internalWrap() {
-    return new MidiAccess.internal_();
-  }
+  external factory MidiAccess._internalWrap();
 
   @Deprecated("Internal Use Only")
   MidiAccess.internal_() : super.internal_();
@@ -26757,9 +26498,7 @@
     return new MidiConnectionEvent._internalWrap();
   }
 
-  factory MidiConnectionEvent._internalWrap() {
-    return new MidiConnectionEvent.internal_();
-  }
+  external factory MidiConnectionEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MidiConnectionEvent.internal_() : super.internal_();
@@ -26801,9 +26540,7 @@
     return new MidiInput._internalWrap();
   }
 
-  factory MidiInput._internalWrap() {
-    return new MidiInput.internal_();
-  }
+  external factory MidiInput._internalWrap();
 
   @Deprecated("Internal Use Only")
   MidiInput.internal_() : super.internal_();
@@ -26896,9 +26633,7 @@
     return new MidiMessageEvent._internalWrap();
   }
 
-  factory MidiMessageEvent._internalWrap() {
-    return new MidiMessageEvent.internal_();
-  }
+  external factory MidiMessageEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MidiMessageEvent.internal_() : super.internal_();
@@ -26934,9 +26669,7 @@
     return new MidiOutput._internalWrap();
   }
 
-  factory MidiOutput._internalWrap() {
-    return new MidiOutput.internal_();
-  }
+  external factory MidiOutput._internalWrap();
 
   @Deprecated("Internal Use Only")
   MidiOutput.internal_() : super.internal_();
@@ -27043,9 +26776,7 @@
     return new MidiPort._internalWrap();
   }
 
-  factory MidiPort._internalWrap() {
-    return new MidiPort.internal_();
-  }
+  external factory MidiPort._internalWrap();
 
   @Deprecated("Internal Use Only")
   MidiPort.internal_() : super.internal_();
@@ -27235,9 +26966,7 @@
     return new ModElement._internalWrap();
   }
 
-  factory ModElement._internalWrap() {
-    return new ModElement.internal_();
-  }
+  external factory ModElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ModElement.internal_() : super.internal_();
@@ -27299,9 +27028,7 @@
     return new MouseEvent._internalWrap();
   }
 
-  factory MouseEvent._internalWrap() {
-    return new MouseEvent.internal_();
-  }
+  external factory MouseEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   MouseEvent.internal_() : super.internal_();
@@ -28118,9 +27845,7 @@
     return new NetworkInformation._internalWrap();
   }
 
-  factory NetworkInformation._internalWrap() {
-    return new NetworkInformation.internal_();
-  }
+  external factory NetworkInformation._internalWrap();
 
   @Deprecated("Internal Use Only")
   NetworkInformation.internal_() : super.internal_();
@@ -28420,9 +28145,7 @@
     return new Node._internalWrap();
   }
 
-  factory Node._internalWrap() {
-    return new Node.internal_();
-  }
+  external factory Node._internalWrap();
 
   @Deprecated("Internal Use Only")
   Node.internal_() : super.internal_();
@@ -29026,9 +28749,7 @@
     return new Notification._internalWrap();
   }
 
-  factory Notification._internalWrap() {
-    return new Notification.internal_();
-  }
+  external factory Notification._internalWrap();
 
   @Deprecated("Internal Use Only")
   Notification.internal_() : super.internal_();
@@ -29146,9 +28867,7 @@
     return new OListElement._internalWrap();
   }
 
-  factory OListElement._internalWrap() {
-    return new OListElement.internal_();
-  }
+  external factory OListElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   OListElement.internal_() : super.internal_();
@@ -29212,9 +28931,7 @@
     return new ObjectElement._internalWrap();
   }
 
-  factory ObjectElement._internalWrap() {
-    return new ObjectElement.internal_();
-  }
+  external factory ObjectElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ObjectElement.internal_() : super.internal_();
@@ -29343,9 +29060,7 @@
     return new OptGroupElement._internalWrap();
   }
 
-  factory OptGroupElement._internalWrap() {
-    return new OptGroupElement.internal_();
-  }
+  external factory OptGroupElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   OptGroupElement.internal_() : super.internal_();
@@ -29397,9 +29112,7 @@
     return new OptionElement._internalWrap();
   }
 
-  factory OptionElement._internalWrap() {
-    return new OptionElement.internal_();
-  }
+  external factory OptionElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   OptionElement.internal_() : super.internal_();
@@ -29486,9 +29199,7 @@
     return new OutputElement._internalWrap();
   }
 
-  factory OutputElement._internalWrap() {
-    return new OutputElement.internal_();
-  }
+  external factory OutputElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   OutputElement.internal_() : super.internal_();
@@ -29585,9 +29296,7 @@
     return new OverflowEvent._internalWrap();
   }
 
-  factory OverflowEvent._internalWrap() {
-    return new OverflowEvent.internal_();
-  }
+  external factory OverflowEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   OverflowEvent.internal_() : super.internal_();
@@ -29639,9 +29348,7 @@
     return new PageTransitionEvent._internalWrap();
   }
 
-  factory PageTransitionEvent._internalWrap() {
-    return new PageTransitionEvent.internal_();
-  }
+  external factory PageTransitionEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   PageTransitionEvent.internal_() : super.internal_();
@@ -29675,9 +29382,7 @@
     return new ParagraphElement._internalWrap();
   }
 
-  factory ParagraphElement._internalWrap() {
-    return new ParagraphElement.internal_();
-  }
+  external factory ParagraphElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ParagraphElement.internal_() : super.internal_();
@@ -29714,9 +29419,7 @@
     return new ParamElement._internalWrap();
   }
 
-  factory ParamElement._internalWrap() {
-    return new ParamElement.internal_();
-  }
+  external factory ParamElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ParamElement.internal_() : super.internal_();
@@ -29925,9 +29628,7 @@
     return new Performance._internalWrap();
   }
 
-  factory Performance._internalWrap() {
-    return new Performance.internal_();
-  }
+  external factory Performance._internalWrap();
 
   @Deprecated("Internal Use Only")
   Performance.internal_() : super.internal_();
@@ -30087,9 +29788,7 @@
     return new PerformanceMark._internalWrap();
   }
 
-  factory PerformanceMark._internalWrap() {
-    return new PerformanceMark.internal_();
-  }
+  external factory PerformanceMark._internalWrap();
 
   @Deprecated("Internal Use Only")
   PerformanceMark.internal_() : super.internal_();
@@ -30117,9 +29816,7 @@
     return new PerformanceMeasure._internalWrap();
   }
 
-  factory PerformanceMeasure._internalWrap() {
-    return new PerformanceMeasure.internal_();
-  }
+  external factory PerformanceMeasure._internalWrap();
 
   @Deprecated("Internal Use Only")
   PerformanceMeasure.internal_() : super.internal_();
@@ -30201,9 +29898,7 @@
     return new PerformanceResourceTiming._internalWrap();
   }
 
-  factory PerformanceResourceTiming._internalWrap() {
-    return new PerformanceResourceTiming.internal_();
-  }
+  external factory PerformanceResourceTiming._internalWrap();
 
   @Deprecated("Internal Use Only")
   PerformanceResourceTiming.internal_() : super.internal_();
@@ -30395,9 +30090,7 @@
     return new PictureElement._internalWrap();
   }
 
-  factory PictureElement._internalWrap() {
-    return new PictureElement.internal_();
-  }
+  external factory PictureElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   PictureElement.internal_() : super.internal_();
@@ -30584,9 +30277,7 @@
     return new PluginPlaceholderElement._internalWrap();
   }
 
-  factory PluginPlaceholderElement._internalWrap() {
-    return new PluginPlaceholderElement.internal_();
-  }
+  external factory PluginPlaceholderElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   PluginPlaceholderElement.internal_() : super.internal_();
@@ -30637,9 +30328,7 @@
     return new PopStateEvent._internalWrap();
   }
 
-  factory PopStateEvent._internalWrap() {
-    return new PopStateEvent.internal_();
-  }
+  external factory PopStateEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   PopStateEvent.internal_() : super.internal_();
@@ -30743,9 +30432,7 @@
     return new PreElement._internalWrap();
   }
 
-  factory PreElement._internalWrap() {
-    return new PreElement.internal_();
-  }
+  external factory PreElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   PreElement.internal_() : super.internal_();
@@ -30778,9 +30465,7 @@
     return new Presentation._internalWrap();
   }
 
-  factory Presentation._internalWrap() {
-    return new Presentation.internal_();
-  }
+  external factory Presentation._internalWrap();
 
   @Deprecated("Internal Use Only")
   Presentation.internal_() : super.internal_();
@@ -30807,9 +30492,7 @@
     return new ProcessingInstruction._internalWrap();
   }
 
-  factory ProcessingInstruction._internalWrap() {
-    return new ProcessingInstruction.internal_();
-  }
+  external factory ProcessingInstruction._internalWrap();
 
   @Deprecated("Internal Use Only")
   ProcessingInstruction.internal_() : super.internal_();
@@ -30852,9 +30535,7 @@
     return new ProgressElement._internalWrap();
   }
 
-  factory ProgressElement._internalWrap() {
-    return new ProgressElement.internal_();
-  }
+  external factory ProgressElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ProgressElement.internal_() : super.internal_();
@@ -30914,9 +30595,7 @@
     return new ProgressEvent._internalWrap();
   }
 
-  factory ProgressEvent._internalWrap() {
-    return new ProgressEvent.internal_();
-  }
+  external factory ProgressEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   ProgressEvent.internal_() : super.internal_();
@@ -30955,9 +30634,7 @@
     return new PushEvent._internalWrap();
   }
 
-  factory PushEvent._internalWrap() {
-    return new PushEvent.internal_();
-  }
+  external factory PushEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   PushEvent.internal_() : super.internal_();
@@ -31067,9 +30744,7 @@
     return new QuoteElement._internalWrap();
   }
 
-  factory QuoteElement._internalWrap() {
-    return new QuoteElement.internal_();
-  }
+  external factory QuoteElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   QuoteElement.internal_() : super.internal_();
@@ -31399,9 +31074,7 @@
     return new RelatedEvent._internalWrap();
   }
 
-  factory RelatedEvent._internalWrap() {
-    return new RelatedEvent.internal_();
-  }
+  external factory RelatedEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   RelatedEvent.internal_() : super.internal_();
@@ -31443,9 +31116,7 @@
     return new ResourceProgressEvent._internalWrap();
   }
 
-  factory ResourceProgressEvent._internalWrap() {
-    return new ResourceProgressEvent.internal_();
-  }
+  external factory ResourceProgressEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   ResourceProgressEvent.internal_() : super.internal_();
@@ -31517,9 +31188,7 @@
     return new RtcDataChannel._internalWrap();
   }
 
-  factory RtcDataChannel._internalWrap() {
-    return new RtcDataChannel.internal_();
-  }
+  external factory RtcDataChannel._internalWrap();
 
   @Deprecated("Internal Use Only")
   RtcDataChannel.internal_() : super.internal_();
@@ -31661,9 +31330,7 @@
     return new RtcDataChannelEvent._internalWrap();
   }
 
-  factory RtcDataChannelEvent._internalWrap() {
-    return new RtcDataChannelEvent.internal_();
-  }
+  external factory RtcDataChannelEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   RtcDataChannelEvent.internal_() : super.internal_();
@@ -31705,9 +31372,7 @@
     return new RtcDtmfSender._internalWrap();
   }
 
-  factory RtcDtmfSender._internalWrap() {
-    return new RtcDtmfSender.internal_();
-  }
+  external factory RtcDtmfSender._internalWrap();
 
   @Deprecated("Internal Use Only")
   RtcDtmfSender.internal_() : super.internal_();
@@ -31773,9 +31438,7 @@
     return new RtcDtmfToneChangeEvent._internalWrap();
   }
 
-  factory RtcDtmfToneChangeEvent._internalWrap() {
-    return new RtcDtmfToneChangeEvent.internal_();
-  }
+  external factory RtcDtmfToneChangeEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   RtcDtmfToneChangeEvent.internal_() : super.internal_();
@@ -31870,9 +31533,7 @@
     return new RtcIceCandidateEvent._internalWrap();
   }
 
-  factory RtcIceCandidateEvent._internalWrap() {
-    return new RtcIceCandidateEvent.internal_();
-  }
+  external factory RtcIceCandidateEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   RtcIceCandidateEvent.internal_() : super.internal_();
@@ -32012,9 +31673,7 @@
     return new RtcPeerConnection._internalWrap();
   }
 
-  factory RtcPeerConnection._internalWrap() {
-    return new RtcPeerConnection.internal_();
-  }
+  external factory RtcPeerConnection._internalWrap();
 
   @Deprecated("Internal Use Only")
   RtcPeerConnection.internal_() : super.internal_();
@@ -32436,9 +32095,7 @@
     return new ScreenOrientation._internalWrap();
   }
 
-  factory ScreenOrientation._internalWrap() {
-    return new ScreenOrientation.internal_();
-  }
+  external factory ScreenOrientation._internalWrap();
 
   @Deprecated("Internal Use Only")
   ScreenOrientation.internal_() : super.internal_();
@@ -32493,9 +32150,7 @@
     return new ScriptElement._internalWrap();
   }
 
-  factory ScriptElement._internalWrap() {
-    return new ScriptElement.internal_();
-  }
+  external factory ScriptElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ScriptElement.internal_() : super.internal_();
@@ -32603,9 +32258,7 @@
     return new SecurityPolicyViolationEvent._internalWrap();
   }
 
-  factory SecurityPolicyViolationEvent._internalWrap() {
-    return new SecurityPolicyViolationEvent.internal_();
-  }
+  external factory SecurityPolicyViolationEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   SecurityPolicyViolationEvent.internal_() : super.internal_();
@@ -32673,9 +32326,7 @@
     return new SelectElement._internalWrap();
   }
 
-  factory SelectElement._internalWrap() {
-    return new SelectElement.internal_();
-  }
+  external factory SelectElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   SelectElement.internal_() : super.internal_();
@@ -33137,9 +32788,7 @@
     return new ServiceWorkerGlobalScope._internalWrap();
   }
 
-  factory ServiceWorkerGlobalScope._internalWrap() {
-    return new ServiceWorkerGlobalScope.internal_();
-  }
+  external factory ServiceWorkerGlobalScope._internalWrap();
 
   @Deprecated("Internal Use Only")
   ServiceWorkerGlobalScope.internal_() : super.internal_();
@@ -33207,9 +32856,7 @@
     return new ServiceWorkerRegistration._internalWrap();
   }
 
-  factory ServiceWorkerRegistration._internalWrap() {
-    return new ServiceWorkerRegistration.internal_();
-  }
+  external factory ServiceWorkerRegistration._internalWrap();
 
   @Deprecated("Internal Use Only")
   ServiceWorkerRegistration.internal_() : super.internal_();
@@ -33267,9 +32914,7 @@
     return new ShadowElement._internalWrap();
   }
 
-  factory ShadowElement._internalWrap() {
-    return new ShadowElement.internal_();
-  }
+  external factory ShadowElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ShadowElement.internal_() : super.internal_();
@@ -33311,9 +32956,7 @@
     return new ShadowRoot._internalWrap();
   }
 
-  factory ShadowRoot._internalWrap() {
-    return new ShadowRoot.internal_();
-  }
+  external factory ShadowRoot._internalWrap();
 
   @Deprecated("Internal Use Only")
   ShadowRoot.internal_() : super.internal_();
@@ -33439,9 +33082,7 @@
     return new SharedWorker._internalWrap();
   }
 
-  factory SharedWorker._internalWrap() {
-    return new SharedWorker.internal_();
-  }
+  external factory SharedWorker._internalWrap();
 
   @Deprecated("Internal Use Only")
   SharedWorker.internal_() : super.internal_();
@@ -33493,9 +33134,7 @@
     return new SharedWorkerGlobalScope._internalWrap();
   }
 
-  factory SharedWorkerGlobalScope._internalWrap() {
-    return new SharedWorkerGlobalScope.internal_();
-  }
+  external factory SharedWorkerGlobalScope._internalWrap();
 
   @Deprecated("Internal Use Only")
   SharedWorkerGlobalScope.internal_() : super.internal_();
@@ -33534,9 +33173,7 @@
     return new SourceBuffer._internalWrap();
   }
 
-  factory SourceBuffer._internalWrap() {
-    return new SourceBuffer.internal_();
-  }
+  external factory SourceBuffer._internalWrap();
 
   @Deprecated("Internal Use Only")
   SourceBuffer.internal_() : super.internal_();
@@ -33639,9 +33276,7 @@
     return new SourceBufferList._internalWrap();
   }
 
-  factory SourceBufferList._internalWrap() {
-    return new SourceBufferList.internal_();
-  }
+  external factory SourceBufferList._internalWrap();
 
   @Deprecated("Internal Use Only")
   SourceBufferList.internal_() : super.internal_();
@@ -33725,9 +33360,7 @@
     return new SourceElement._internalWrap();
   }
 
-  factory SourceElement._internalWrap() {
-    return new SourceElement.internal_();
-  }
+  external factory SourceElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   SourceElement.internal_() : super.internal_();
@@ -33867,9 +33500,7 @@
     return new SpanElement._internalWrap();
   }
 
-  factory SpanElement._internalWrap() {
-    return new SpanElement.internal_();
-  }
+  external factory SpanElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   SpanElement.internal_() : super.internal_();
@@ -34182,9 +33813,7 @@
     return new SpeechRecognition._internalWrap();
   }
 
-  factory SpeechRecognition._internalWrap() {
-    return new SpeechRecognition.internal_();
-  }
+  external factory SpeechRecognition._internalWrap();
 
   @Deprecated("Internal Use Only")
   SpeechRecognition.internal_() : super.internal_();
@@ -34363,9 +33992,7 @@
     return new SpeechRecognitionError._internalWrap();
   }
 
-  factory SpeechRecognitionError._internalWrap() {
-    return new SpeechRecognitionError.internal_();
-  }
+  external factory SpeechRecognitionError._internalWrap();
 
   @Deprecated("Internal Use Only")
   SpeechRecognitionError.internal_() : super.internal_();
@@ -34402,9 +34029,7 @@
     return new SpeechRecognitionEvent._internalWrap();
   }
 
-  factory SpeechRecognitionEvent._internalWrap() {
-    return new SpeechRecognitionEvent.internal_();
-  }
+  external factory SpeechRecognitionEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   SpeechRecognitionEvent.internal_() : super.internal_();
@@ -34492,9 +34117,7 @@
     return new SpeechSynthesis._internalWrap();
   }
 
-  factory SpeechSynthesis._internalWrap() {
-    return new SpeechSynthesis.internal_();
-  }
+  external factory SpeechSynthesis._internalWrap();
 
   @Deprecated("Internal Use Only")
   SpeechSynthesis.internal_() : super.internal_();
@@ -34554,9 +34177,7 @@
     return new SpeechSynthesisEvent._internalWrap();
   }
 
-  factory SpeechSynthesisEvent._internalWrap() {
-    return new SpeechSynthesisEvent.internal_();
-  }
+  external factory SpeechSynthesisEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   SpeechSynthesisEvent.internal_() : super.internal_();
@@ -34672,9 +34293,7 @@
     return new SpeechSynthesisUtterance._internalWrap();
   }
 
-  factory SpeechSynthesisUtterance._internalWrap() {
-    return new SpeechSynthesisUtterance.internal_();
-  }
+  external factory SpeechSynthesisUtterance._internalWrap();
 
   @Deprecated("Internal Use Only")
   SpeechSynthesisUtterance.internal_() : super.internal_();
@@ -35016,9 +34635,7 @@
     return new StorageEvent._internalWrap();
   }
 
-  factory StorageEvent._internalWrap() {
-    return new StorageEvent.internal_();
-  }
+  external factory StorageEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   StorageEvent.internal_() : super.internal_();
@@ -35192,9 +34809,7 @@
     return new StyleElement._internalWrap();
   }
 
-  factory StyleElement._internalWrap() {
-    return new StyleElement.internal_();
-  }
+  external factory StyleElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   StyleElement.internal_() : super.internal_();
@@ -35358,9 +34973,7 @@
     return new TableCaptionElement._internalWrap();
   }
 
-  factory TableCaptionElement._internalWrap() {
-    return new TableCaptionElement.internal_();
-  }
+  external factory TableCaptionElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TableCaptionElement.internal_() : super.internal_();
@@ -35396,9 +35009,7 @@
     return new TableCellElement._internalWrap();
   }
 
-  factory TableCellElement._internalWrap() {
-    return new TableCellElement.internal_();
-  }
+  external factory TableCellElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TableCellElement.internal_() : super.internal_();
@@ -35462,9 +35073,7 @@
     return new TableColElement._internalWrap();
   }
 
-  factory TableColElement._internalWrap() {
-    return new TableColElement.internal_();
-  }
+  external factory TableColElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TableColElement.internal_() : super.internal_();
@@ -35526,9 +35135,7 @@
     return new TableElement._internalWrap();
   }
 
-  factory TableElement._internalWrap() {
-    return new TableElement.internal_();
-  }
+  external factory TableElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TableElement.internal_() : super.internal_();
@@ -35644,9 +35251,7 @@
     return new TableRowElement._internalWrap();
   }
 
-  factory TableRowElement._internalWrap() {
-    return new TableRowElement.internal_();
-  }
+  external factory TableRowElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TableRowElement.internal_() : super.internal_();
@@ -35710,9 +35315,7 @@
     return new TableSectionElement._internalWrap();
   }
 
-  factory TableSectionElement._internalWrap() {
-    return new TableSectionElement.internal_();
-  }
+  external factory TableSectionElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TableSectionElement.internal_() : super.internal_();
@@ -35765,9 +35368,7 @@
     return new TemplateElement._internalWrap();
   }
 
-  factory TemplateElement._internalWrap() {
-    return new TemplateElement.internal_();
-  }
+  external factory TemplateElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TemplateElement.internal_() : super.internal_();
@@ -35822,9 +35423,7 @@
     return new Text._internalWrap();
   }
 
-  factory Text._internalWrap() {
-    return new Text.internal_();
-  }
+  external factory Text._internalWrap();
 
   @Deprecated("Internal Use Only")
   Text.internal_() : super.internal_();
@@ -35867,9 +35466,7 @@
     return new TextAreaElement._internalWrap();
   }
 
-  factory TextAreaElement._internalWrap() {
-    return new TextAreaElement.internal_();
-  }
+  external factory TextAreaElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextAreaElement.internal_() : super.internal_();
@@ -36114,9 +35711,7 @@
     return new TextEvent._internalWrap();
   }
 
-  factory TextEvent._internalWrap() {
-    return new TextEvent.internal_();
-  }
+  external factory TextEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextEvent.internal_() : super.internal_();
@@ -36250,9 +35845,7 @@
     return new TextTrack._internalWrap();
   }
 
-  factory TextTrack._internalWrap() {
-    return new TextTrack.internal_();
-  }
+  external factory TextTrack._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextTrack.internal_() : super.internal_();
@@ -36361,9 +35954,7 @@
     return new TextTrackCue._internalWrap();
   }
 
-  factory TextTrackCue._internalWrap() {
-    return new TextTrackCue.internal_();
-  }
+  external factory TextTrackCue._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextTrackCue.internal_() : super.internal_();
@@ -36541,9 +36132,7 @@
     return new TextTrackList._internalWrap();
   }
 
-  factory TextTrackList._internalWrap() {
-    return new TextTrackList.internal_();
-  }
+  external factory TextTrackList._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextTrackList.internal_() : super.internal_();
@@ -36813,9 +36402,7 @@
     return new TitleElement._internalWrap();
   }
 
-  factory TitleElement._internalWrap() {
-    return new TitleElement.internal_();
-  }
+  external factory TitleElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TitleElement.internal_() : super.internal_();
@@ -36982,9 +36569,7 @@
     return new TouchEvent._internalWrap();
   }
 
-  factory TouchEvent._internalWrap() {
-    return new TouchEvent.internal_();
-  }
+  external factory TouchEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   TouchEvent.internal_() : super.internal_();
@@ -37151,9 +36736,7 @@
     return new TrackElement._internalWrap();
   }
 
-  factory TrackElement._internalWrap() {
-    return new TrackElement.internal_();
-  }
+  external factory TrackElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TrackElement.internal_() : super.internal_();
@@ -37263,9 +36846,7 @@
     return new TrackEvent._internalWrap();
   }
 
-  factory TrackEvent._internalWrap() {
-    return new TrackEvent.internal_();
-  }
+  external factory TrackEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   TrackEvent.internal_() : super.internal_();
@@ -37295,9 +36876,7 @@
     return new TransitionEvent._internalWrap();
   }
 
-  factory TransitionEvent._internalWrap() {
-    return new TransitionEvent.internal_();
-  }
+  external factory TransitionEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   TransitionEvent.internal_() : super.internal_();
@@ -37428,9 +37007,7 @@
     return new UIEvent._internalWrap();
   }
 
-  factory UIEvent._internalWrap() {
-    return new UIEvent.internal_();
-  }
+  external factory UIEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   UIEvent.internal_() : super.internal_();
@@ -37519,9 +37096,7 @@
     return new UListElement._internalWrap();
   }
 
-  factory UListElement._internalWrap() {
-    return new UListElement.internal_();
-  }
+  external factory UListElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   UListElement.internal_() : super.internal_();
@@ -37553,9 +37128,7 @@
     return new UnknownElement._internalWrap();
   }
 
-  factory UnknownElement._internalWrap() {
-    return new UnknownElement.internal_();
-  }
+  external factory UnknownElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   UnknownElement.internal_() : super.internal_();
@@ -38015,9 +37588,7 @@
     return new VideoElement._internalWrap();
   }
 
-  factory VideoElement._internalWrap() {
-    return new VideoElement.internal_();
-  }
+  external factory VideoElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   VideoElement.internal_() : super.internal_();
@@ -38232,9 +37803,7 @@
     return new VideoTrackList._internalWrap();
   }
 
-  factory VideoTrackList._internalWrap() {
-    return new VideoTrackList.internal_();
-  }
+  external factory VideoTrackList._internalWrap();
 
   @Deprecated("Internal Use Only")
   VideoTrackList.internal_() : super.internal_();
@@ -38303,9 +37872,7 @@
     return new VttCue._internalWrap();
   }
 
-  factory VttCue._internalWrap() {
-    return new VttCue.internal_();
-  }
+  external factory VttCue._internalWrap();
 
   @Deprecated("Internal Use Only")
   VttCue.internal_() : super.internal_();
@@ -38677,9 +38244,7 @@
     return new WebSocket._internalWrap();
   }
 
-  factory WebSocket._internalWrap() {
-    return new WebSocket.internal_();
-  }
+  external factory WebSocket._internalWrap();
 
   @Deprecated("Internal Use Only")
   WebSocket.internal_() : super.internal_();
@@ -38851,9 +38416,7 @@
     return new WheelEvent._internalWrap();
   }
 
-  factory WheelEvent._internalWrap() {
-    return new WheelEvent.internal_();
-  }
+  external factory WheelEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   WheelEvent.internal_() : super.internal_();
@@ -39193,9 +38756,7 @@
     return new Window._internalWrap();
   }
 
-  factory Window._internalWrap() {
-    return new Window.internal_();
-  }
+  external factory Window._internalWrap();
 
   @Deprecated("Internal Use Only")
   Window.internal_() : super.internal_();
@@ -40663,9 +40224,7 @@
     return new Worker._internalWrap();
   }
 
-  factory Worker._internalWrap() {
-    return new Worker.internal_();
-  }
+  external factory Worker._internalWrap();
 
   @Deprecated("Internal Use Only")
   Worker.internal_() : super.internal_();
@@ -40714,9 +40273,7 @@
     return new WorkerConsole._internalWrap();
   }
 
-  factory WorkerConsole._internalWrap() {
-    return new WorkerConsole.internal_();
-  }
+  external factory WorkerConsole._internalWrap();
 
   @Deprecated("Internal Use Only")
   WorkerConsole.internal_() : super.internal_();
@@ -40754,9 +40311,7 @@
     return new WorkerGlobalScope._internalWrap();
   }
 
-  factory WorkerGlobalScope._internalWrap() {
-    return new WorkerGlobalScope.internal_();
-  }
+  external factory WorkerGlobalScope._internalWrap();
 
   @Deprecated("Internal Use Only")
   WorkerGlobalScope.internal_() : super.internal_();
@@ -41194,9 +40749,7 @@
     return new XmlDocument._internalWrap();
   }
 
-  factory XmlDocument._internalWrap() {
-    return new XmlDocument.internal_();
-  }
+  external factory XmlDocument._internalWrap();
 
   @Deprecated("Internal Use Only")
   XmlDocument.internal_() : super.internal_();
@@ -41337,9 +40890,7 @@
     return new _Attr._internalWrap();
   }
 
-  factory _Attr._internalWrap() {
-    return new _Attr.internal_();
-  }
+  external factory _Attr._internalWrap();
 
   @Deprecated("Internal Use Only")
   _Attr.internal_() : super.internal_();
@@ -41404,9 +40955,7 @@
     return new _CSSPrimitiveValue._internalWrap();
   }
 
-  factory _CSSPrimitiveValue._internalWrap() {
-    return new _CSSPrimitiveValue.internal_();
-  }
+  external factory _CSSPrimitiveValue._internalWrap();
 
   @Deprecated("Internal Use Only")
   _CSSPrimitiveValue.internal_() : super.internal_();
@@ -41434,9 +40983,7 @@
     return new _CSSUnknownRule._internalWrap();
   }
 
-  factory _CSSUnknownRule._internalWrap() {
-    return new _CSSUnknownRule.internal_();
-  }
+  external factory _CSSUnknownRule._internalWrap();
 
   @Deprecated("Internal Use Only")
   _CSSUnknownRule.internal_() : super.internal_();
@@ -41912,9 +41459,7 @@
     return new _CssValueList._internalWrap();
   }
 
-  factory _CssValueList._internalWrap() {
-    return new _CssValueList.internal_();
-  }
+  external factory _CssValueList._internalWrap();
 
   @Deprecated("Internal Use Only")
   _CssValueList.internal_() : super.internal_();
@@ -42028,9 +41573,7 @@
     return new _DirectoryEntrySync._internalWrap();
   }
 
-  factory _DirectoryEntrySync._internalWrap() {
-    return new _DirectoryEntrySync.internal_();
-  }
+  external factory _DirectoryEntrySync._internalWrap();
 
   @Deprecated("Internal Use Only")
   _DirectoryEntrySync.internal_() : super.internal_();
@@ -42087,9 +41630,7 @@
     return new _DocumentType._internalWrap();
   }
 
-  factory _DocumentType._internalWrap() {
-    return new _DocumentType.internal_();
-  }
+  external factory _DocumentType._internalWrap();
 
   @Deprecated("Internal Use Only")
   _DocumentType.internal_() : super.internal_();
@@ -42138,9 +41679,7 @@
     return new _DomRect._internalWrap();
   }
 
-  factory _DomRect._internalWrap() {
-    return new _DomRect.internal_();
-  }
+  external factory _DomRect._internalWrap();
 
   @Deprecated("Internal Use Only")
   _DomRect.internal_() : super.internal_();
@@ -42239,9 +41778,7 @@
     return new _FileEntrySync._internalWrap();
   }
 
-  factory _FileEntrySync._internalWrap() {
-    return new _FileEntrySync.internal_();
-  }
+  external factory _FileEntrySync._internalWrap();
 
   @Deprecated("Internal Use Only")
   _FileEntrySync.internal_() : super.internal_();
@@ -42457,9 +41994,7 @@
     return new _HTMLAppletElement._internalWrap();
   }
 
-  factory _HTMLAppletElement._internalWrap() {
-    return new _HTMLAppletElement.internal_();
-  }
+  external factory _HTMLAppletElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _HTMLAppletElement.internal_() : super.internal_();
@@ -42493,9 +42028,7 @@
     return new _HTMLDirectoryElement._internalWrap();
   }
 
-  factory _HTMLDirectoryElement._internalWrap() {
-    return new _HTMLDirectoryElement.internal_();
-  }
+  external factory _HTMLDirectoryElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _HTMLDirectoryElement.internal_() : super.internal_();
@@ -42529,9 +42062,7 @@
     return new _HTMLFontElement._internalWrap();
   }
 
-  factory _HTMLFontElement._internalWrap() {
-    return new _HTMLFontElement.internal_();
-  }
+  external factory _HTMLFontElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _HTMLFontElement.internal_() : super.internal_();
@@ -42565,9 +42096,7 @@
     return new _HTMLFrameElement._internalWrap();
   }
 
-  factory _HTMLFrameElement._internalWrap() {
-    return new _HTMLFrameElement.internal_();
-  }
+  external factory _HTMLFrameElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _HTMLFrameElement.internal_() : super.internal_();
@@ -42599,9 +42128,7 @@
     return new _HTMLFrameSetElement._internalWrap();
   }
 
-  factory _HTMLFrameSetElement._internalWrap() {
-    return new _HTMLFrameSetElement.internal_();
-  }
+  external factory _HTMLFrameSetElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _HTMLFrameSetElement.internal_() : super.internal_();
@@ -42644,9 +42171,7 @@
     return new _HTMLMarqueeElement._internalWrap();
   }
 
-  factory _HTMLMarqueeElement._internalWrap() {
-    return new _HTMLMarqueeElement.internal_();
-  }
+  external factory _HTMLMarqueeElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _HTMLMarqueeElement.internal_() : super.internal_();
@@ -42686,9 +42211,7 @@
     return new _MutationEvent._internalWrap();
   }
 
-  factory _MutationEvent._internalWrap() {
-    return new _MutationEvent.internal_();
-  }
+  external factory _MutationEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   _MutationEvent.internal_() : super.internal_();
@@ -42885,9 +42408,7 @@
     return new _RadioNodeList._internalWrap();
   }
 
-  factory _RadioNodeList._internalWrap() {
-    return new _RadioNodeList.internal_();
-  }
+  external factory _RadioNodeList._internalWrap();
 
   @Deprecated("Internal Use Only")
   _RadioNodeList.internal_() : super.internal_();
@@ -42965,9 +42486,7 @@
     return new _Request._internalWrap();
   }
 
-  factory _Request._internalWrap() {
-    return new _Request.internal_();
-  }
+  external factory _Request._internalWrap();
 
   @Deprecated("Internal Use Only")
   _Request.internal_() : super.internal_();
@@ -43058,9 +42577,7 @@
     return new _Response._internalWrap();
   }
 
-  factory _Response._internalWrap() {
-    return new _Response.internal_();
-  }
+  external factory _Response._internalWrap();
 
   @Deprecated("Internal Use Only")
   _Response.internal_() : super.internal_();
@@ -43085,9 +42602,7 @@
     return new _ServiceWorker._internalWrap();
   }
 
-  factory _ServiceWorker._internalWrap() {
-    return new _ServiceWorker.internal_();
-  }
+  external factory _ServiceWorker._internalWrap();
 
   @Deprecated("Internal Use Only")
   _ServiceWorker.internal_() : super.internal_();
@@ -43320,9 +42835,7 @@
     return new _WebKitCSSFilterValue._internalWrap();
   }
 
-  factory _WebKitCSSFilterValue._internalWrap() {
-    return new _WebKitCSSFilterValue.internal_();
-  }
+  external factory _WebKitCSSFilterValue._internalWrap();
 
   @Deprecated("Internal Use Only")
   _WebKitCSSFilterValue.internal_() : super.internal_();
@@ -43390,9 +42903,7 @@
     return new _WebKitCSSTransformValue._internalWrap();
   }
 
-  factory _WebKitCSSTransformValue._internalWrap() {
-    return new _WebKitCSSTransformValue.internal_();
-  }
+  external factory _WebKitCSSTransformValue._internalWrap();
 
   @Deprecated("Internal Use Only")
   _WebKitCSSTransformValue.internal_() : super.internal_();
@@ -43534,9 +43045,7 @@
     return new _XMLHttpRequestProgressEvent._internalWrap();
   }
 
-  factory _XMLHttpRequestProgressEvent._internalWrap() {
-    return new _XMLHttpRequestProgressEvent.internal_();
-  }
+  external factory _XMLHttpRequestProgressEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   _XMLHttpRequestProgressEvent.internal_() : super.internal_();
@@ -47719,7 +47228,7 @@
         throw new UnsupportedError('$tag is not registered.');
       }
       jsObject = unwrap_jso(element);
-    } else if (element.runtimeType == js.JsObjectImpl) {
+    } else if (element.runtimeType == js.JsObject) {
       // It's a Polymer core element (written in JS).
       jsObject = element;
     } else if (isNativeElementExtension) {
@@ -47731,7 +47240,7 @@
     } else if (tag != null && element.localName != tag) {
       throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
     } else if (tag == null) {
-      throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
+      throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObject.');
     }
 
     // Remember Dart class to tagName for any upgrading done in wrap_jso.
@@ -48924,8 +48433,7 @@
     return [
         "inspect",
         (o) {
-          host.callMethod("inspect", [o]);
-          return o;
+          return host.callMethod("_inspect", [unwrap_jso(o)]);
         },
         "dir",
         window().console.dir,
diff --git a/sdk/lib/html/html_common/conversions.dart b/sdk/lib/html/html_common/conversions.dart
index 0dca4d3..de0d423 100644
--- a/sdk/lib/html/html_common/conversions.dart
+++ b/sdk/lib/html/html_common/conversions.dart
@@ -266,7 +266,7 @@
 // Conversions for ContextAttributes.
 //
 // On Firefox, the returned ContextAttributes is a plain object.
-class _TypedContextAttributes implements gl.ContextAttributes {
+class ContextAttributes {
   bool alpha;
   bool antialias;
   bool depth;
@@ -275,21 +275,16 @@
   bool stencil;
   bool failIfMajorPerformanceCaveat;
 
-  _TypedContextAttributes(this.alpha, this.antialias, this.depth,
+  ContextAttributes(this.alpha, this.antialias, this.depth,
       this.failIfMajorPerformanceCaveat, this.premultipliedAlpha,
       this.preserveDrawingBuffer, this.stencil);
 }
 
-gl.ContextAttributes convertNativeToDart_ContextAttributes(
-    nativeContextAttributes) {
-  if (nativeContextAttributes is gl.ContextAttributes) {
-    return nativeContextAttributes;
-  }
-
+convertNativeToDart_ContextAttributes(nativeContextAttributes) {
   // On Firefox the above test fails because ContextAttributes is a plain
   // object so we create a _TypedContextAttributes.
 
-  return new _TypedContextAttributes(
+  return new ContextAttributes(
       JS('var', '#.alpha', nativeContextAttributes),
       JS('var', '#.antialias', nativeContextAttributes),
       JS('var', '#.depth', nativeContextAttributes),
diff --git a/sdk/lib/html/html_common/conversions_dartium.dart b/sdk/lib/html/html_common/conversions_dartium.dart
index 2403387..90fe55d 100644
--- a/sdk/lib/html/html_common/conversions_dartium.dart
+++ b/sdk/lib/html/html_common/conversions_dartium.dart
@@ -97,6 +97,31 @@
   return jsObject;
 }
 
+// Creates a Dart class to allow members of the Map to be fetched (as if getters exist).
+// TODO(terry): Need to use package:js but that's a problem in dart:html. Talk to
+//              Jacob about how to do this properly using dart:js.
+class _ReturnedDictionary {
+  Map _values;
+
+  noSuchMethod(Invocation invocation) {
+    var key = MirrorSystem.getName(invocation.memberName);
+    if (invocation.isGetter) {
+      return _values[key];
+    } else if (invocation.isSetter && key.endsWith('=')) {
+      key = key.substring(0, key.length-1);
+      _values[key] = invocation.positionalArguments[0];
+    }
+  }
+
+  Map get toMap => _values;
+
+  _ReturnedDictionary(Map value): _values = value != null ? value : {};
+}
+
+// Helper function to wrapped a returned dictionary from blink to a Dart looking
+// class.
+convertNativeDictionaryToDartDictionary(Map values) => new _ReturnedDictionary(values);
+
 // Conversion function place holder (currently not used in dart2js or dartium).
 List convertDartToNative_StringArray(List<String> input) => input;
 
@@ -126,9 +151,14 @@
     }
 
     if (jsObject is js.JsArray) {
-      var wrappingList = new DartHtmlWrappingList(jsObject);
-      js.setDartHtmlWrapperFor(jsObject, wrappingList);
-      return wrappingList;
+      wrapper = new js.JSArray.create(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrapper);
+      return wrapper;
+    }
+    if (jsObject is js.JsFunction) {
+      wrapper = new js.JSFunction.create(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrapper);
+      return wrapper;
     }
 
     // Try the most general type conversions on it.
@@ -144,14 +174,15 @@
     if (constructor == null) {
       // Perfectly valid case for JavaScript objects where __proto__ has
       // intentionally been set to null.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
+      js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
       return jsObject;
     }
     var jsTypeName = js.JsNative.getProperty(constructor, 'name');
     if (jsTypeName is! String || jsTypeName.length == 0) {
       // Not an html type.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
+      wrapper = new js.JSObject.create(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrapper);
+      return wrapper;
     }
 
     var dartClass_instance;
@@ -204,12 +235,11 @@
 
     // TODO(jacobr): cache that this is not a dart:html JS class.
     return dartClass_instance;
-  } catch(e, stacktrace){
+  } catch (e, stacktrace) {
     if (interop_checks) {
-      if (e is DebugAssertException)
-        window.console.log("${e.message}\n ${stacktrace}");
-      else
-        window.console.log("${stacktrace}");
+      if (e is DebugAssertException) window.console
+          .log("${e.message}\n ${stacktrace}");
+      else window.console.log("${stacktrace}");
     }
   }
 
@@ -236,31 +266,30 @@
       return wrapper;
     }
 
-    // TODO(jacobr): auomatically wrapping JsArray here is fundamentally broken
-    // as it hijacks adding custom methods on JS Array classes as part of the
-    // new typed DartJsInterop.
-    // To make this work we really need to make DartHtmlWrappingList extend
-    // JsArrayImpl. Fixing this issue needs to be part of a broader refactor
-    // that allows calling custom typed JS interop methods on all dart:html
-    // classes.
     if (jsObject is js.JsArray) {
-      var wrappingList = new DartHtmlWrappingList(jsObject);
-      js.setDartHtmlWrapperFor(jsObject, wrappingList);
-      return wrappingList;
+      wrapper = new js.JSArray.create(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrapper);
+      return wrapper;
+    }
+    if (jsObject is js.JsFunction) {
+      wrapper = new js.JSFunction.create(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrapper);
+      return wrapper;
     }
 
     var constructor = js.JsNative.getProperty(jsObject, 'constructor');
     if (constructor == null) {
       // Perfectly valid case for JavaScript objects where __proto__ has
       // intentionally been set to null.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
+      js.setDartHtmlWrapperFor(jsObject, new js.JSObject.create(jsObject));
       return jsObject;
     }
     var jsTypeName = js.JsNative.getProperty(constructor, 'name');
     if (jsTypeName is! String || jsTypeName.length == 0) {
       // Not an html type.
-      js.setDartHtmlWrapperFor(jsObject, jsObject);
-      return jsObject;
+      wrapper = new js.JSObject.create(jsObject);
+      js.setDartHtmlWrapperFor(jsObject, wrapper);
+      return wrapper;
     }
 
     var func = getHtmlCreateFunction(jsTypeName);
@@ -270,13 +299,14 @@
       js.setDartHtmlWrapperFor(jsObject, dartClass_instance);
       return dartClass_instance;
     }
-    return jsObject;
-  } catch(e, stacktrace){
+    wrapper = new js.JSObject.create(jsObject);
+    js.setDartHtmlWrapperFor(jsObject, wrapper);
+    return wrapper;
+  } catch (e, stacktrace) {
     if (interop_checks) {
-      if (e is DebugAssertException)
-        window.console.log("${e.message}\n ${stacktrace}");
-      else
-        window.console.log("${stacktrace}");
+      if (e is DebugAssertException) window.console
+          .log("${e.message}\n ${stacktrace}");
+      else window.console.log("${stacktrace}");
     }
   }
 
@@ -333,7 +363,7 @@
   } else if (runtimeType == TemplateElement) {
     // Data binding with a Dart class.
     tag = element.attributes['is'];
-  } else if (runtimeType == js.JsObjectImpl) {
+  } else if (runtimeType == js.JsObject) {
     // It's a Polymer core element (written in JS).
     // Make sure it's an element anything else we can ignore.
     if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
@@ -347,7 +377,8 @@
       }
     }
   } else {
-    throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
+    throw new UnsupportedError(
+        'Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObject.');
   }
 
   var entry = _knownCustomElements[tag];
@@ -378,19 +409,3 @@
   }
   return null;
 }
-
-/**
- * Wraps a JsArray and will call wrap_jso on its entries.
- */
-class DartHtmlWrappingList extends ListBase implements NativeFieldWrapperClass2 {
-  DartHtmlWrappingList(this.blink_jsObject);
-
-  final js.JsArray blink_jsObject;
-
-  operator [](int index) => wrap_jso_no_SerializedScriptvalue(js.JsNative.getArrayIndex(blink_jsObject, index));
-
-  operator []=(int index, value) => blink_jsObject[index] = value;
-
-  int get length => blink_jsObject.length;
-  int set length(int newLength) => blink_jsObject.length = newLength;
-}
diff --git a/sdk/lib/html/html_common/html_common.dart b/sdk/lib/html/html_common/html_common.dart
index c2e1644..0509f6f 100644
--- a/sdk/lib/html/html_common/html_common.dart
+++ b/sdk/lib/html/html_common/html_common.dart
@@ -9,6 +9,7 @@
 import 'dart:html';
 import 'dart:js' as js;
 import 'dart:_internal' show WhereIterable;
+import 'dart:mirrors';
 import 'dart:nativewrappers';
 import 'dart:typed_data';
 import 'dart:web_gl' as gl;
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 4ab3e30..36b35e3 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -247,9 +247,7 @@
     return new CursorWithValue._internalWrap();
   }
 
-  factory CursorWithValue._internalWrap() {
-    return new CursorWithValue.internal_();
-  }
+  external factory CursorWithValue._internalWrap();
 
   @Deprecated("Internal Use Only")
   CursorWithValue.internal_() : super.internal_();
@@ -365,9 +363,7 @@
     return new Database._internalWrap();
   }
 
-  factory Database._internalWrap() {
-    return new Database.internal_();
-  }
+  external factory Database._internalWrap();
 
   @Deprecated("Internal Use Only")
   Database.internal_() : super.internal_();
@@ -1126,9 +1122,7 @@
     return new OpenDBRequest._internalWrap();
   }
 
-  factory OpenDBRequest._internalWrap() {
-    return new OpenDBRequest.internal_();
-  }
+  external factory OpenDBRequest._internalWrap();
 
   @Deprecated("Internal Use Only")
   OpenDBRequest.internal_() : super.internal_();
@@ -1185,9 +1179,7 @@
     return new Request._internalWrap();
   }
 
-  factory Request._internalWrap() {
-    return new Request.internal_();
-  }
+  external factory Request._internalWrap();
 
   @Deprecated("Internal Use Only")
   Request.internal_() : super.internal_();
@@ -1300,9 +1292,7 @@
     return new Transaction._internalWrap();
   }
 
-  factory Transaction._internalWrap() {
-    return new Transaction.internal_();
-  }
+  external factory Transaction._internalWrap();
 
   @Deprecated("Internal Use Only")
   Transaction.internal_() : super.internal_();
@@ -1364,9 +1354,7 @@
     return new VersionChangeEvent._internalWrap();
   }
 
-  factory VersionChangeEvent._internalWrap() {
-    return new VersionChangeEvent.internal_();
-  }
+  external factory VersionChangeEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   VersionChangeEvent.internal_() : super.internal_();
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 5dd559c..0d0bc9e 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -595,9 +595,9 @@
       // We need to make sure that these are always awailable from the
       // observatory even if no files (or sockets for the socket ones) are
       // open.
-      registerExtension('__getOpenFiles',
+      registerExtension('ext.dart.io.getOpenFiles',
                         _FileResourceInfo.getOpenFiles);
-      registerExtension('__getFileByID',
+      registerExtension('ext.dart.io.getFileByID',
                         _FileResourceInfo.getFileInfoMapByID);
       _connectedResourceHandler = true;
     }
diff --git a/sdk/lib/io/io_resource_info.dart b/sdk/lib/io/io_resource_info.dart
index 1a18fc9..9267084 100644
--- a/sdk/lib/io/io_resource_info.dart
+++ b/sdk/lib/io/io_resource_info.dart
@@ -112,7 +112,7 @@
   }
 
   static Future<ServiceExtensionResponse> getOpenFiles(function, params) {
-    assert(function == '__getOpenFiles');
+    assert(function == 'ext.dart.io.getOpenFiles');
     var data = {'type': '_openfiles', 'data': getOpenFilesList()};
     var json = JSON.encode(data);
     return new Future.value(new ServiceExtensionResponse.result(json));
@@ -182,7 +182,7 @@
 
   static Future<ServiceExtensionResponse> getStartedProcesses(
       String function, Map<String, String> params) {
-    assert(function == '__getProcesses');
+    assert(function == 'ext.dart.io.getProcesses');
     var data = {'type': '_startedprocesses', 'data': getStartedProcessesList()};
     var json = JSON.encode(data);
     return new Future.value(new ServiceExtensionResponse.result(json));
@@ -264,7 +264,7 @@
   }
 
   static Future<ServiceExtensionResponse> getOpenSockets(function, params) {
-    assert(function == '__getOpenSockets');
+    assert(function == 'ext.dart.io.getOpenSockets');
     var data = {'type': '_opensockets', 'data': getOpenSocketsList()};
     var json = JSON.encode(data);
     return new Future.value(new ServiceExtensionResponse.result(json));
diff --git a/sdk/lib/io/iolib_sources.gypi b/sdk/lib/io/io_sources.gypi
similarity index 91%
rename from sdk/lib/io/iolib_sources.gypi
rename to sdk/lib/io/io_sources.gypi
index ad2110f..10a6bf4 100644
--- a/sdk/lib/io/iolib_sources.gypi
+++ b/sdk/lib/io/io_sources.gypi
@@ -4,6 +4,8 @@
 
 {
   'sources': [
+    'io.dart',
+    # The above file needs to be first if additional parts are added to the lib.
     'bytes_builder.dart',
     'common.dart',
     'crypto.dart',
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index 326597f..d881ce5 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.dart
@@ -181,20 +181,20 @@
   static List<String> get executableArguments => _Platform.executableArguments;
 
   /**
-   * Returns the value of the --package-root flag passed to the executable
+   * Returns the value of the `--package-root` flag passed to the executable
    * used to run the script in this isolate.  This is the directory in which
    * Dart packages are looked up.
    *
-   * If there is no --package-root flag, then null is returned.
+   * If there is no `--package-root` flag, `null` is returned.
    */
   static String get packageRoot => _Platform.packageRoot;
 
 /**
- * Returns the value of the --packages flag passed to the executable
- * used to run the script in this isolate.  This is the configuration which
+ * Returns the value of the `--packages` flag passed to the executable
+ * used to run the script in this isolate. This is the configuration which
  * specifies how Dart packages are looked up.
  *
- * If there is no --packages flag, then the null is returned.
+ * If there is no `--packages` flag, `null` is returned.
  */
   static String get packageConfig => _Platform.packageConfig;
 
diff --git a/sdk/lib/io/security_context.dart b/sdk/lib/io/security_context.dart
index 48e8111..86dfc96 100644
--- a/sdk/lib/io/security_context.dart
+++ b/sdk/lib/io/security_context.dart
@@ -8,16 +8,12 @@
  * The object containing the certificates to trust when making
  * a secure client connection, and the certificate chain and
  * private key to serve from a secure server.
- * 
+ *
  * The [SecureSocket]  and [SecureServer] classes take a SecurityContext
  * as an argument to their connect and bind methods.
  *
- * Certificates and keys can be added to a SecurityContext from PEM files
- * on the disk.  A PEM file contains one or more base-64 encoded DER-serialized
- * ASN1 objects, surrounded with delimiter strings like
- * "-----BEGIN CERTIFICATE -----" and "-----END CERTIFICATE-----".
- * Distinguished encoding rules (DER) is a canonical binary serialization
- * of ASN1 objects into an octet string.
+ * Certificates and keys can be added to a SecurityContext from either PEM
+ * or PKCS12 containers.
  */
 abstract class SecurityContext {
   external factory SecurityContext();
@@ -35,50 +31,99 @@
 
   /**
    * Sets the private key for a server certificate or client certificate.
+   *
    * A secure connection using this SecurityContext will use this key with
    * the server or client certificate to sign and decrypt messages.
-   * [keyFile] is a PEM 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 usePrivateKey(String keyFile, {String password});
+  void usePrivateKey(String file, {String password});
+
+  /**
+   * Sets the private key for a server certificate or client certificate.
+   *
+   * Like [usePrivateKey], but takes the contents of the file as a list
+   * of bytes.
+   */
+  void usePrivateKeyBytes(List<int> keyBytes, {String password});
 
   /**
    * Sets the set of trusted X509 certificates used by [SecureSocket]
    * client connections, when connecting to a secure server.
    *
-   * There are two ways to set a set of trusted certificates, with a single
-   * PEM file, or with a directory containing individual PEM files for
-   * certificates.
+   * [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.
    *
-   * [file] is an optional PEM file containing X509 certificates, usually
-   * root certificates from certificate authorities.
-   *
-   * [directory] is an optional directory containing PEM files.  The directory
-   * must also have filesystem links added, which link extra filenames based
-   * on the hash of a certificate's distinguished name (DN) to the file
-   * containing that certificate. OpenSSL contains a tool called c_rehash
-   * to create these links in a directory.
+   * NB: This function calls [ReadFileAsBytesSync], and will block on file IO.
+   * Prefer using [setTrustedCertificatesBytes].
    */
-  void setTrustedCertificates({String file, String directory});
+  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 [setTrustedCertificates] but takes the contents of the file.
+   */
+  void setTrustedCertificatesBytes(List<int> certBytes, {String password});
 
   /**
    * Sets the chain of X509 certificates served by [SecureServer]
    * when making secure connections, including the server certificate.
-   * [file] is an PEM file containing X509 certificates, starting with
+   *
+   * [file] is a PEM or PKCS12 file containing X509 certificates, starting with
    * the root authority and intermediate authorities forming the signed
    * chain to the server certificate, and ending with the server certificate.
-   * The private key for the server certificate is set by [usePrivateKey].
+   * 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. 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 useCertificateChain(String file);
+  void useCertificateChain(String file, {String password});
+
+  /**
+   * Sets the chain of X509 certificates served by [SecureServer]
+   * when making secure connections, including the server certificate.
+   *
+   * Like [useCertificateChain] but takes the contents of the file.
+   */
+  void useCertificateChainBytes(List<int> chainBytes, {String password});
+
+  /**
+   * Sets the list of authority names that a [SecureServer] will advertise
+   * as accepted when requesting a client certificate from a connecting
+   * client.
+   *
+   * [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. 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 setClientAuthorities(String file, {String password});
 
   /**
    * Sets the list of authority names that a [SecureServer] will advertise
    * as accepted, when requesting a client certificate from a connecting
-   * client.  [file] is a PEM file containing the accepted signing authority
-   * certificates - the authority names are extracted from the certificates.
+   * client.
+   *
+   * Like [setClientAuthority] but takes the contents of the file.
    */
-  void setClientAuthorities(String file);
+  void setClientAuthoritiesBytes(List<int> authCertBytes, {String password});
 
   /**
    * Sets the list of application-level protocols supported by a client
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index ce2c5a2..d2b1f39 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -101,6 +101,26 @@
 @Deprecated("Internal Use Only")
 final bool CHECK_JS_INVOCATIONS = true;
 
+final String _DART_RESERVED_NAME_PREFIX = r'JS$';
+
+String _stripReservedNamePrefix(String name) =>
+    name.startsWith(_DART_RESERVED_NAME_PREFIX)
+        ? name.substring(_DART_RESERVED_NAME_PREFIX.length)
+        : name;
+
+_buildArgs(Invocation invocation) {
+  if (invocation.namedArguments.isEmpty) {
+    return invocation.positionalArguments;
+  } else {
+    var varArgs = new Map<String, Object>();
+    invocation.namedArguments.forEach((symbol, val) {
+      varArgs[mirrors.MirrorSystem.getName(symbol)] = val;
+    });
+    return invocation.positionalArguments.toList()
+      ..add(maybeWrapTypedInterop(new JsObject.jsify(varArgs)));
+  }
+}
+
 final _allowedMethods = new Map<Symbol, _DeclarationSet>();
 final _allowedGetters = new Map<Symbol, _DeclarationSet>();
 final _allowedSetters = new Map<Symbol, _DeclarationSet>();
@@ -292,6 +312,20 @@
 
 bool _hasJsName(mirrors.DeclarationMirror mirror) => _getJsName(mirror) != null;
 
+bool hasDomName(mirrors.DeclarationMirror mirror) {
+  var location = mirror.location;
+  if (location == null || location.sourceUri.scheme != 'dart') return false;
+  for (var annotation in mirror.metadata) {
+    if (mirrors.MirrorSystem.getName(annotation.type.simpleName) == "DomName") {
+      // We can't make sure the annotation is in dart: as Dartium believes it
+      // is file://dart/sdk/lib/html/html_common/metadata.dart
+      // instead of a proper dart: location.
+      return true;
+    }
+  }
+  return false;
+}
+
 _getJsMemberName(mirrors.DeclarationMirror mirror) {
   var name = _getJsName(mirror);
   return name == null || name.isEmpty ? _getDeclarationName(mirror) : name;
@@ -304,7 +338,7 @@
     assert(name.endsWith("="));
     name = name.substring(0, name.length - 1);
   }
-  return name;
+  return _stripReservedNamePrefix(name);
 }
 
 final _JS_LIBRARY_PREFIX = "js_library";
@@ -347,16 +381,20 @@
   }
   sb.write(" ");
   if (declaration.isGetter) {
-    sb.write("get $name => ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(${_accessJsPath(path)});");
+    sb.write(
+        "get $name => ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(${_accessJsPath(path)});");
   } else if (declaration.isSetter) {
-    sb.write("set $name(v) => ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(${_accessJsPathSetter(path)});");
+    sb.write("set $name(v) {\n"
+        "  ${_JS_LIBRARY_PREFIX}.safeForTypedInterop(v);\n"
+        "  return ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(${_accessJsPathSetter(path)});\n"
+        "}\n");
   } else {
     sb.write("$name(");
     bool hasOptional = false;
     int i = 0;
     var args = <String>[];
     for (var p in declaration.parameters) {
-      assert(!p.isNamed); // XXX throw
+      assert(!p.isNamed); // TODO(jacobr): throw.
       assert(!p.hasDefaultValue);
       if (i > 0) {
         sb.write(", ");
@@ -377,8 +415,11 @@
       sb.write("]");
     }
     // TODO(jacobr):
-    sb.write(") => ");
-    sb.write('${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(');
+    sb.write(") {\n");
+    for (var arg in args) {
+      sb.write("  ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($arg);\n");
+    }
+    sb.write("  return ${_JS_LIBRARY_PREFIX}.maybeWrapTypedInterop(");
     if (declaration.isConstructor) {
       sb.write("new ${_JS_LIBRARY_PREFIX}.JsObject(");
     }
@@ -391,6 +432,7 @@
       sb.write(".takeWhile((i) => i != ${_UNDEFINED_VAR}).toList()");
     }
     sb.write("));");
+    sb.write("}\n");
   }
   sb.write("\n");
 }
@@ -399,7 +441,7 @@
   // This try-catch block is a workaround for BUG:24834.
   try {
     return mirror.isExternal;
-  } catch (e) { }
+  } catch (e) {}
   return false;
 }
 
@@ -416,195 +458,106 @@
         }
       } else if (declaration is mirrors.ClassMirror) {
         mirrors.ClassMirror clazz = declaration;
-        if (_hasJsName(clazz)) {
+        var isDom = hasDomName(clazz);
+        var isJsInterop = _hasJsName(clazz);
+        if (isDom || isJsInterop) {
           // TODO(jacobr): verify class implements JavaScriptObject.
-          String jsClassName = _getJsMemberName(clazz);
           var className = mirrors.MirrorSystem.getName(clazz.simpleName);
+          var classNameImpl = '${className}Impl';
           var sbPatch = new StringBuffer();
-          jsInterfaceTypes.add(clazz);
-          clazz.declarations.forEach((name, declaration) {
-            if (declaration is! mirrors.MethodMirror ||
-                !_isExternal(declaration)) return;
-            if (declaration.isFactoryConstructor && _isAnonymousClass(clazz)) {
-              sbPatch.write("  factory ${className}(");
-              int i = 0;
-              var args = <String>[];
-              for (var p in declaration.parameters) {
-                args.add(mirrors.MirrorSystem.getName(p.simpleName));
-                i++;
-              }
-              if (args.isNotEmpty) {
-                sbPatch
-                  ..write('{')
-                  ..write(
-                      args.map((name) => '$name:${_UNDEFINED_VAR}').join(", "))
-                  ..write('}');
-              }
-              sbPatch.write(") {\n"
+          if (isJsInterop) {
+            String jsClassName = _getJsMemberName(clazz);
+
+            jsInterfaceTypes.add(clazz);
+            clazz.declarations.forEach((name, declaration) {
+              if (declaration is! mirrors.MethodMirror ||
+                  !_isExternal(declaration)) return;
+              if (declaration.isFactoryConstructor &&
+                  _isAnonymousClass(clazz)) {
+                sbPatch.write("  factory ${className}(");
+                int i = 0;
+                var args = <String>[];
+                for (var p in declaration.parameters) {
+                  args.add(mirrors.MirrorSystem.getName(p.simpleName));
+                  i++;
+                }
+                if (args.isNotEmpty) {
+                  sbPatch
+                    ..write('{')
+                    ..write(args
+                        .map((name) => '$name:${_UNDEFINED_VAR}')
+                        .join(", "))
+                    ..write('}');
+                }
+                sbPatch.write(") {\n"
                     "    var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});\n");
-              i = 0;
-              for (var p in declaration.parameters) {
-                assert(p.isNamed); // XXX throw
-                var name = args[i];
-                var jsName = mirrors.MirrorSystem.getName(p.simpleName);
-                // XXX apply name conversion rules.
+                i = 0;
+                for (var p in declaration.parameters) {
+                  assert(p.isNamed); // TODO(jacobr): throw.
+                  var name = args[i];
+                  var jsName = _stripReservedNamePrefix(
+                      mirrors.MirrorSystem.getName(p.simpleName));
+                  sbPatch.write("    if($name != ${_UNDEFINED_VAR}) {\n"
+                      "      ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($name);\n"
+                      "      ret['$jsName'] = $name;\n"
+                      "    }\n");
+                  i++;
+                }
+
                 sbPatch.write(
-                    "    if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\n");
-                i++;
+                    "    return new ${_JS_LIBRARY_PREFIX}.JSObject.create(ret);\n"
+                    "  }\n");
+              } else if (declaration.isConstructor ||
+                  declaration.isFactoryConstructor) {
+                sbPatch.write("  ");
+                addMemberHelper(
+                    declaration,
+                    (jsLibraryName != null && jsLibraryName.isNotEmpty)
+                        ? "${jsLibraryName}.${jsClassName}"
+                        : jsClassName,
+                    sbPatch,
+                    isStatic: true,
+                    memberName: className);
               }
+            });
 
-              sbPatch.write("    return ret;\n"
-                  "  }\n");
-            } else if (declaration.isConstructor ||
-                declaration.isFactoryConstructor) {
-              sbPatch.write("  ");
-              addMemberHelper(
-                  declaration,
-                  (jsLibraryName != null && jsLibraryName.isNotEmpty)
-                      ? "${jsLibraryName}.${jsClassName}"
-                      : jsClassName,
-                  sbPatch,
-                  isStatic: true,
-                  memberName: className);
-            }
-          });
-
-          clazz.staticMembers.forEach((memberName, member) {
-            if (_isExternal(member)) {
-              sbPatch.write("  ");
-              addMemberHelper(
-                  member,
-                  (jsLibraryName != null && jsLibraryName.isNotEmpty)
-                      ? "${jsLibraryName}.${jsClassName}"
-                      : jsClassName,
-                  sbPatch,
-                  isStatic: true);
-            }
-          });
-          var typeVariablesClause = '';
-          if (!clazz.typeVariables.isEmpty) {
-            typeVariablesClause =
-                '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
+            clazz.staticMembers.forEach((memberName, member) {
+              if (_isExternal(member)) {
+                sbPatch.write("  ");
+                addMemberHelper(
+                    member,
+                    (jsLibraryName != null && jsLibraryName.isNotEmpty)
+                        ? "${jsLibraryName}.${jsClassName}"
+                        : jsClassName,
+                    sbPatch,
+                    isStatic: true);
+              }
+            });
+          }
+          if (isDom) {
+            sbPatch.write("  factory ${className}._internalWrap() => "
+                "new ${classNameImpl}.internal_();\n");
           }
           if (sbPatch.isNotEmpty) {
+            var typeVariablesClause = '';
+            if (!clazz.typeVariables.isEmpty) {
+              typeVariablesClause =
+                  '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
+            }
             sb.write("""
 patch class $className$typeVariablesClause {
 $sbPatch
 }
 """);
-          }
-        }
-      }
-    });
-    if (sb.isNotEmpty) {
-      staticCodegen
-        ..add(uri.toString())
-        ..add("${uri}_js_interop_patch.dart")
-        ..add("""
-import 'dart:js' as ${_JS_LIBRARY_PREFIX};
-
-/**
- * Placeholder object for cases where we need to determine exactly how many
- * args were passed to a function.
- */
-const ${_UNDEFINED_VAR} = const Object();
-
-${sb}
-""");
-    }
-  });
-
-  return staticCodegen;
-}
-
-List<String> _generateExternalMethods2() {
-  var staticCodegen = <String>[];
-  mirrors.currentMirrorSystem().libraries.forEach((uri, library) {
-    var sb = new StringBuffer();
-    String jsLibraryName = _getJsName(library);
-    library.declarations.forEach((name, declaration) {
-      var isExternal = _isExternal(declaration);
-      if (declaration is mirrors.MethodMirror) {
-        if (isExternal && (_hasJsName(declaration) || jsLibraryName != null)) {
-          addMemberHelper(declaration, jsLibraryName, sb);
-        }
-      } else if (declaration is mirrors.ClassMirror) {
-        mirrors.ClassMirror clazz = declaration;
-        if (_hasJsName(clazz)) {
-          // TODO(jacobr): verify class implements JavaScriptObject.
-          String jsClassName = _getJsMemberName(clazz);
-          var className = mirrors.MirrorSystem.getName(clazz.simpleName);
-          var sbPatch = new StringBuffer();
-          jsInterfaceTypes.add(clazz);
-          clazz.declarations.forEach((name, declaration) {
-            if (declaration is! mirrors.MethodMirror ||
-                !declaration.isAbstract ||
-                !isExternal) return;
-            if (_hasLiteralAnnotation(declaration) &&
-                declaration.isFactoryConstructor) {
-              sbPatch.write("  factory ${className}({");
-              int i = 0;
-              var args = <String>[];
-              for (var p in declaration.parameters) {
-                assert(p.isNamed); // XXX throw
-                args.add(mirrors.MirrorSystem.getName(p.simpleName));
-                i++;
-              }
-              sbPatch
-                ..write(
-                    args.map((name) => '$name:${_UNDEFINED_VAR}').join(", "))
-                ..write("}) {\n"
-                    "    var ret = new ${_JS_LIBRARY_PREFIX}.JsObject.jsify({});\n");
-              i = 0;
-              for (var p in declaration.parameters) {
-                assert(p.isNamed); // XXX throw
-                var name = args[i];
-                var jsName = mirrors.MirrorSystem.getName(p.simpleName);
-                // XXX apply name conversion rules.
-                sbPatch.write(
-                    "    if($name != ${_UNDEFINED_VAR}) ret['$jsName'] = $name;\n");
-                i++;
-              }
-
-              sbPatch.write("    return ret;\n"
-                  "  }\n");
-            } else if (declaration.isConstructor ||
-                declaration.isFactoryConstructor) {
-              sbPatch.write("  ");
-              addMemberHelper(
-                  declaration,
-                  (jsLibraryName != null && jsLibraryName.isNotEmpty)
-                      ? "${jsLibraryName}.${jsClassName}"
-                      : jsClassName,
-                  sbPatch,
-                  isStatic: true,
-                  memberName: className);
-            }
-          });
-
-          clazz.staticMembers.forEach((memberName, member) {
-            if (_isExternal(member)) {
-              sbPatch.write("  ");
-              addMemberHelper(
-                  member,
-                  (jsLibraryName != null && jsLibraryName.isNotEmpty)
-                      ? "${jsLibraryName}.${jsClassName}"
-                      : jsClassName,
-                  sbPatch,
-                  isStatic: true);
-            }
-          });
-          var typeVariablesClause = '';
-          if (!clazz.typeVariables.isEmpty) {
-            typeVariablesClause =
-                '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
-          }
-          if (sbPatch.isNotEmpty) {
-            sb.write("""
-patch class $className$typeVariablesClause {
-$sbPatch
+            if (isDom) {
+              sb.write("""
+class $classNameImpl$typeVariablesClause extends $className implements ${_JS_LIBRARY_PREFIX}.JSObjectInterfacesDom {
+  ${classNameImpl}.internal_() : super.internal_();
+  get runtimeType => $className;
+  toString() => super.toString();
 }
 """);
+            }
           }
         }
       }
@@ -631,9 +584,9 @@
 }
 
 /**
- * Generates a part file defining source code for JsObjectImpl and related
- * classes. This calass is needed so that type checks for all registered JavaScript
- * interop classes pass.
+ * Generates part files defining source code for JSObjectImpl, all DOM classes
+ * classes. This codegen  is needed so that type checks for all registered
+ * JavaScript interop classes pass.
  */
 List<String> _generateInteropPatchFiles() {
   var ret = _generateExternalMethods();
@@ -643,7 +596,10 @@
 
   var implements = <String>[];
   var implementsArray = <String>[];
+  var implementsDom = <String>[];
   var listMirror = mirrors.reflectType(List);
+  var functionMirror = mirrors.reflectType(Function);
+  var jsObjectMirror = mirrors.reflectType(JSObject);
 
   for (var typeMirror in jsInterfaceTypes) {
     mirrors.LibraryMirror libraryMirror = typeMirror.owner;
@@ -665,8 +621,25 @@
       libraryPrefixes[libraryMirror] = prefixName;
     }
     var isArray = typeMirror.isSubtypeOf(listMirror);
-    (isArray ? implementsArray : implements).add(
-        '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}');
+    var isFunction = typeMirror.isSubtypeOf(functionMirror);
+    var isJSObject = typeMirror.isSubtypeOf(jsObjectMirror);
+    var fullName =
+        '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}';
+    (isArray ? implementsArray : implements).add(fullName);
+    if (!isArray && !isFunction && !isJSObject) {
+      // For DOM classes we need to be a bit more conservative at tagging them
+      // as implementing JS inteorp classes risks strange unintended
+      // consequences as unrleated code may have instanceof checks.  Checking
+      // for isJSObject ensures we do not accidentally pull in existing
+      // dart:html classes as they all have JSObject as a base class.
+      // Note that methods from these classes can still be called on a
+      // dart:html instance but checked mode type checks will fail. This is
+      // not ideal but is better than causing strange breaks in existing
+      // code that uses dart:html.
+      // TODO(jacobr): consider throwing compile time errors if @JS classes
+      // extend JSObject as that case cannot be safely handled in Dartium.
+      implementsDom.add(fullName);
+    }
   }
   libraryPrefixes.forEach((libraryMirror, prefix) {
     sb.writeln('import "${libraryMirror.uri}" as $prefix;');
@@ -674,20 +647,51 @@
   buildImplementsClause(classes) =>
       classes.isEmpty ? "" : "implements ${classes.join(', ')}";
   var implementsClause = buildImplementsClause(implements);
+  var implementsClauseDom = buildImplementsClause(implementsDom);
   // TODO(jacobr): only certain classes need to be implemented by
   // JsFunctionImpl.
   var allTypes = []..addAll(implements)..addAll(implementsArray);
   sb.write('''
-class JsObjectImpl extends JsObject $implementsClause {
-  JsObjectImpl.internal() : super.internal();
+class JSObjectImpl extends JSObject $implementsClause {
+  JSObjectImpl.internal() : super.internal();
 }
 
-class JsFunctionImpl extends JsFunction $implementsClause {
-  JsFunctionImpl.internal() : super.internal();
+class JSFunctionImpl extends JSFunction $implementsClause {
+  JSFunctionImpl.internal() : super.internal();
 }
 
-class JsArrayImpl<E> extends JsArray<E> ${buildImplementsClause(implementsArray)} {
-  JsArrayImpl.internal() : super.internal();
+class JSArrayImpl extends JSArray ${buildImplementsClause(implementsArray)} {
+  JSArrayImpl.internal() : super.internal();
+}
+
+// Interfaces that are safe to slam on all DOM classes.
+// Adding implementsClause would be risky as it could contain Function which
+// is likely to break a lot of instanceof checks.
+abstract class JSObjectInterfacesDom $implementsClauseDom {
+}
+
+patch class JSObject {
+  factory JSObject.create(JsObject jsObject) {
+    var ret = new JSObjectImpl.internal()..blink_jsObject = jsObject;
+    jsObject._dartHtmlWrapper = ret;
+    return ret;
+  }
+}
+
+patch class JSFunction {
+  factory JSFunction.create(JsObject jsObject) {
+    var ret = new JSFunctionImpl.internal()..blink_jsObject = jsObject;
+    jsObject._dartHtmlWrapper = ret;
+    return ret;
+  }
+}
+
+patch class JSArray {
+  factory JSArray.create(JsObject jsObject) {
+    var ret = new JSArrayImpl.internal()..blink_jsObject = jsObject;
+    jsObject._dartHtmlWrapper = ret;
+    return ret;
+  }
 }
 
 _registerAllJsInterfaces() {
@@ -695,7 +699,7 @@
 }
 
 ''');
-  ret..addAll(["dart:js", "JsInteropImpl.dart", sb.toString()]);
+  ret..addAll(["dart:js", "JSInteropImpl.dart", sb.toString()]);
   return ret;
 }
 
@@ -870,8 +874,7 @@
 }
 
 @Deprecated("Internal Use Only")
-maybeWrapTypedInterop(o) =>
-    html_common.wrap_jso_no_SerializedScriptvalue(o);
+maybeWrapTypedInterop(o) => html_common.wrap_jso_no_SerializedScriptvalue(o);
 
 _maybeWrap(o) {
   var wrapped = html_common.wrap_jso_no_SerializedScriptvalue(o);
@@ -910,7 +913,7 @@
  */
 @Deprecated("Internal Use Only")
 unwrap_jso(dartClass_instance) {
-  if (dartClass_instance is html.DartHtmlDomObject &&
+  if (dartClass_instance is JSObject &&
       dartClass_instance is! JsObject) return dartClass_instance.blink_jsObject;
   else return dartClass_instance;
 }
@@ -946,19 +949,6 @@
   static JsObject _create(JsFunction constructor, arguments)
       native "JsObject_constructorCallback";
 
-  _buildArgs(Invocation invocation) {
-    if (invocation.namedArguments.isEmpty) {
-      return invocation.positionalArguments;
-    } else {
-      var varArgs = new Map<String, Object>();
-      invocation.namedArguments.forEach((symbol, val) {
-        varArgs[mirrors.MirrorSystem.getName(symbol)] = val;
-      });
-      return invocation.positionalArguments.toList()
-        ..add(new JsObject.jsify(varArgs));
-    }
-  }
-
   /**
    * Constructs a [JsObject] that proxies a native Dart object; _for expert use
    * only_.
@@ -1099,13 +1089,28 @@
     }
   }
 
+  _callMethod(String name, List args) native "JsObject_callMethod";
+}
+
+/// Base class for all JS objects used through dart:html and typed JS interop.
+@Deprecated("Internal Use Only")
+class JSObject {
+  JSObject.internal() {}
+  external factory JSObject.create(JsObject jsObject);
+
+  @Deprecated("Internal Use Only")
+  JsObject blink_jsObject;
+
+  String toString() => blink_jsObject.toString();
+
   noSuchMethod(Invocation invocation) {
     throwError() {
-      throw new NoSuchMethodError(this, invocation.memberName,
-          invocation.positionalArguments, invocation.namedArguments);
+      super.noSuchMethod(invocation);
     }
 
-    String name = mirrors.MirrorSystem.getName(invocation.memberName);
+    String name = _stripReservedNamePrefix(
+        mirrors.MirrorSystem.getName(invocation.memberName));
+    argsSafeForTypedInterop(invocation.positionalArguments);
     if (invocation.isGetter) {
       if (CHECK_JS_INVOCATIONS) {
         var matches = _allowedGetters[invocation.memberName];
@@ -1113,8 +1118,8 @@
             !_allowedMethods.containsKey(invocation.memberName)) {
           throwError();
         }
-        var ret = this[name];
-        if (matches != null && matches._checkReturnType(ret)) return ret;
+        var ret = maybeWrapTypedInterop(blink_jsObject._operator_getter(name));
+        if (matches != null) return ret;
         if (ret is Function ||
             (ret is JsFunction /* shouldn't be needed in the future*/) &&
                 _allowedMethods.containsKey(
@@ -1122,7 +1127,7 @@
         throwError();
       } else {
         // TODO(jacobr): should we throw if the JavaScript object doesn't have the property?
-        return maybeWrapTypedInterop(this._operator_getter(name));
+        return maybeWrapTypedInterop(blink_jsObject._operator_getter(name));
       }
     } else if (invocation.isSetter) {
       if (CHECK_JS_INVOCATIONS) {
@@ -1132,7 +1137,7 @@
       }
       assert(name.endsWith("="));
       name = name.substring(0, name.length - 1);
-      return maybeWrapTypedInterop(_operator_setter(
+      return maybeWrapTypedInterop(blink_jsObject._operator_setter(
           name, invocation.positionalArguments.first));
     } else {
       // TODO(jacobr): also allow calling getters that look like functions.
@@ -1142,15 +1147,61 @@
         if (matches == null ||
             !matches.checkInvocation(invocation)) throwError();
       }
-      var ret = maybeWrapTypedInterop(this._callMethod(name, _buildArgs(invocation)));
+      var ret = maybeWrapTypedInterop(
+          blink_jsObject._callMethod(name, _buildArgs(invocation)));
       if (CHECK_JS_INVOCATIONS) {
-        if (!matches._checkReturnType(ret)) throwError();
+        if (!matches._checkReturnType(ret)) {
+          html.window.console.error("Return value for method: ${name} is "
+              "${ret.runtimeType} which is inconsistent with all typed "
+              "JS interop definitions for method ${name}.");
+        }
       }
       return ret;
     }
   }
+}
 
-  _callMethod(String name, List args) native "JsObject_callMethod";
+@Deprecated("Internal Use Only")
+class JSArray extends JSObject with ListMixin {
+  JSArray.internal() : super.internal();
+  external factory JSArray.create(JsObject jsObject);
+  operator [](int index) =>
+      maybeWrapTypedInterop(JsNative.getArrayIndex(blink_jsObject, index));
+
+  operator []=(int index, value) => blink_jsObject[index] = value;
+
+  int get length => blink_jsObject.length;
+  int set length(int newLength) => blink_jsObject.length = newLength;
+}
+
+@Deprecated("Internal Use Only")
+class JSFunction extends JSObject implements Function {
+  JSFunction.internal() : super.internal();
+
+  external factory JSFunction.create(JsObject jsObject);
+
+  call(
+      [a1 = _UNDEFINED,
+      a2 = _UNDEFINED,
+      a3 = _UNDEFINED,
+      a4 = _UNDEFINED,
+      a5 = _UNDEFINED,
+      a6 = _UNDEFINED,
+      a7 = _UNDEFINED,
+      a8 = _UNDEFINED,
+      a9 = _UNDEFINED,
+      a10 = _UNDEFINED]) {
+    return maybeWrapTypedInterop(blink_jsObject
+        .apply(_stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10])));
+  }
+
+  noSuchMethod(Invocation invocation) {
+    if (invocation.isMethod && invocation.memberName == #call) {
+      return maybeWrapTypedInterop(
+          blink_jsObject.apply(_buildArgs(invocation)));
+    }
+    return super.noSuchMethod(invocation);
+  }
 }
 
 // JavaScript interop methods that do not automatically wrap to dart:html types.
@@ -1185,7 +1236,7 @@
 /**
  * Proxies a JavaScript Function object.
  */
-class JsFunction extends JsObject implements Function {
+class JsFunction extends JsObject {
   JsFunction.internal() : super.internal();
 
   /**
@@ -1203,27 +1254,6 @@
 
   dynamic _apply(List args, {thisArg}) native "JsFunction_apply";
 
-  call([a1 = _UNDEFINED,
-        a2 = _UNDEFINED,
-        a3 = _UNDEFINED,
-        a4 = _UNDEFINED,
-        a5 = _UNDEFINED,
-        a6 = _UNDEFINED,
-        a7 = _UNDEFINED,
-        a8 = _UNDEFINED,
-        a9 = _UNDEFINED,
-        a10 = _UNDEFINED]) {
-    return apply(
-        _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
-  }
-
-  noSuchMethod(Invocation invocation) {
-    if (invocation.isMethod && invocation.memberName == #call) {
-      return apply(_buildArgs(invocation));
-    }
-    return super.noSuchMethod(invocation);
-  }
-
   /**
    * Internal only version of apply which uses debugger proxies of Dart objects
    * rather than opaque handles. This method is private because it cannot be
@@ -1349,6 +1379,39 @@
     args.takeWhile((i) => i != _UNDEFINED).toList();
 
 /**
+ * Check that that if [arg] is a [Function] it is safe to pass to JavaScript.
+ * To make a function safe, call [allowInterop] or [allowInteropCaptureThis].
+ */
+@Deprecated("Internal Use Only")
+safeForTypedInterop(arg) {
+  if (CHECK_JS_INVOCATIONS && arg is Function && arg is! JSFunction) {
+    throw new ArgumentError(
+        "Attempt to pass Function '$arg' to JavaScript via without calling allowInterop or allowInteropCaptureThis");
+  }
+}
+
+/**
+ * Check that that if any elements of [args] are [Function] it is safe to pass
+ * to JavaScript. To make a function safe, call [allowInterop] or
+ * [allowInteropCaptureThis].
+ */
+@Deprecated("Internal Use Only")
+void argsSafeForTypedInterop(Iterable args) {
+  for (var arg in args) {
+    safeForTypedInterop(arg);
+  }
+}
+
+List _stripAndWrapArgs(Iterable args) {
+  var ret = [];
+  for (var arg in args) {
+    if (arg == _UNDEFINED) break;
+    ret.add(maybeWrapTypedInterop(arg));
+  }
+  return ret;
+}
+
+/**
  * Returns a method that can be called with an arbitrary number (for n less
  * than 11) of arguments without violating Dart type checks.
  */
@@ -1366,9 +1429,89 @@
     jsFunction._applyDebuggerOnly(
         _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
 
-// The allowInterop method is a no-op in Dartium.
-// TODO(jacobr): tag methods so we can throw if a Dart method is passed to
-// JavaScript using the new interop without calling allowInterop.
+/// This helper is purely a hack so we can reuse JsFunction.withThis even when
+/// we don't care about passing JS "this". In an ideal world we would implement
+/// helpers in C++ that directly implement allowInterop and
+/// allowInteropCaptureThis.
+class _CreateDartFunctionForInteropIgnoreThis implements Function {
+  Function _fn;
+
+  _CreateDartFunctionForInteropIgnoreThis(this._fn);
+
+  call(
+      [ignoredThis = _UNDEFINED,
+      a1 = _UNDEFINED,
+      a2 = _UNDEFINED,
+      a3 = _UNDEFINED,
+      a4 = _UNDEFINED,
+      a5 = _UNDEFINED,
+      a6 = _UNDEFINED,
+      a7 = _UNDEFINED,
+      a8 = _UNDEFINED,
+      a9 = _UNDEFINED,
+      a10 = _UNDEFINED]) {
+    var ret = Function.apply(
+        _fn, _stripAndWrapArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
+    safeForTypedInterop(ret);
+    return ret;
+  }
+
+  noSuchMethod(Invocation invocation) {
+    if (invocation.isMethod && invocation.memberName == #call) {
+      // Named arguments not yet supported.
+      if (invocation.namedArguments.isNotEmpty) return;
+      var ret = Function.apply(
+          _fn, _stripAndWrapArgs(invocation.positionalArguments.skip(1)));
+      // TODO(jacobr): it would be nice to check that the return value is safe
+      // for interop but we don't want to break existing addEventListener users.
+      // safeForTypedInterop(ret);
+      safeForTypedInterop(ret);
+      return ret;
+    }
+    return super.noSuchMethod(invocation);
+  }
+}
+
+/// See comment for [_CreateDartFunctionForInteropIgnoreThis].
+/// This Function exists purely because JsObject doesn't have the DOM type
+/// conversion semantics we want for JS typed interop.
+class _CreateDartFunctionForInterop implements Function {
+  Function _fn;
+
+  _CreateDartFunctionForInterop(this._fn);
+
+  call(
+      [a1 = _UNDEFINED,
+      a2 = _UNDEFINED,
+      a3 = _UNDEFINED,
+      a4 = _UNDEFINED,
+      a5 = _UNDEFINED,
+      a6 = _UNDEFINED,
+      a7 = _UNDEFINED,
+      a8 = _UNDEFINED,
+      a9 = _UNDEFINED,
+      a10 = _UNDEFINED]) {
+    var ret = Function.apply(
+        _fn, _stripAndWrapArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
+    safeForTypedInterop(ret);
+    return ret;
+  }
+
+  noSuchMethod(Invocation invocation) {
+    if (invocation.isMethod && invocation.memberName == #call) {
+      // Named arguments not yet supported.
+      if (invocation.namedArguments.isNotEmpty) return;
+      var ret = Function.apply(
+          _fn, _stripAndWrapArgs(invocation.positionalArguments));
+      safeForTypedInterop(ret);
+      return ret;
+    }
+    return super.noSuchMethod(invocation);
+  }
+}
+
+/// Cached JSFunction associated with the Dart Function.
+Expando<JSFunction> _interopExpando = new Expando<JSFunction>();
 
 /// Returns a wrapper around function [f] that can be called from JavaScript
 /// using the package:js Dart-JavaScript interop.
@@ -1381,9 +1524,25 @@
 /// JavaScript. We may remove the need to call this method completely in the
 /// future if Dart2Js is refactored so that its function calling conventions
 /// are more compatible with JavaScript.
-Function allowInterop(Function f) => f;
+JSFunction allowInterop(Function f) {
+  if (f is JSFunction) {
+    // The function is already a JSFunction... no need to do anything.
+    return f;
+  } else {
+    var ret = _interopExpando[f];
+    if (ret == null) {
+      // TODO(jacobr): we could optimize this.
+      ret = new JSFunction.create(new JsFunction.withThis(
+          new _CreateDartFunctionForInteropIgnoreThis(f)));
+      _interopExpando[f] = ret;
+    }
+    return ret;
+  }
+}
 
-Expando<JsFunction> _interopCaptureThisExpando = new Expando<JsFunction>();
+/// Cached JSFunction associated with the Dart function when "this" is
+/// captured.
+Expando<JSFunction> _interopCaptureThisExpando = new Expando<JSFunction>();
 
 /// Returns a [Function] that when called from JavaScript captures its 'this'
 /// binding and calls [f] with the value of this passed as the first argument.
@@ -1391,8 +1550,8 @@
 ///
 /// See the documention for [allowInterop]. This method should only be used with
 /// package:js Dart-JavaScript interop.
-Function allowInteropCaptureThis(Function f) {
-  if (f is JsFunction) {
+JSFunction allowInteropCaptureThis(Function f) {
+  if (f is JSFunction) {
     // Behavior when the function is already a JS function is unspecified.
     throw new ArgumentError(
         "Function is already a JS function so cannot capture this.");
@@ -1400,7 +1559,9 @@
   } else {
     var ret = _interopCaptureThisExpando[f];
     if (ret == null) {
-      ret = new JsFunction.withThis(f);
+      // TODO(jacobr): we could optimize this.
+      ret = new JSFunction.create(
+          new JsFunction.withThis(new _CreateDartFunctionForInterop(f)));
       _interopCaptureThisExpando[f] = ret;
     }
     return ret;
diff --git a/sdk/lib/rules.gni b/sdk/lib/rules.gni
new file mode 100644
index 0000000..0aa80f8
--- /dev/null
+++ b/sdk/lib/rules.gni
@@ -0,0 +1,52 @@
+# Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+# This build rule will copy the source for one Dart SDK library.
+#
+# Required arguments:
+#   sdk_lib_name
+#       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/$sdk_lib_name/.
+#
+template("dart_sdk_lib_copy") {
+  assert(defined(invoker.sdk_lib_name))
+  if (defined(invoker.dart_root)) {
+    dart_root = rebase_path(invoker.dart_root)
+  } 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 =
+      rebase_path("tools/gypi_to_gn.py", "", dart_root)
+  # The name of the SDK library being copied.
+  lib_name = invoker.sdk_lib_name
+  # The path to the libraries source directory.
+  lib_path = rebase_path(lib_name, "", dart_sdk_sdk_lib_path)
+  # The path to the sources gypi.
+  lib_sources_gypi = lib_name + "_sources.gypi"
+  # Get the contents of the gypi file.
+  sdk_lib_sources_gypi =
+      exec_script(dart_sdk_tools_gypi_to_gn_path,
+                  [rebase_path(lib_sources_gypi, "", lib_path)],
+                  "scope",
+                  [rebase_path(lib_sources_gypi, "", lib_path)])
+  copy(target_name) {
+    sources = rebase_path(sdk_lib_sources_gypi.sources, "", lib_path)
+    outputs = [ "$destination/$lib_name/{{source_file_part}}" ]
+  }
+}
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index c093cab..7795952 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -349,9 +349,7 @@
     return new AElement._internalWrap();
   }
 
-  factory AElement._internalWrap() {
-    return new AElement.internal_();
-  }
+  external factory AElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AElement.internal_() : super.internal_();
@@ -399,9 +397,7 @@
     return new AltGlyphElement._internalWrap();
   }
 
-  factory AltGlyphElement._internalWrap() {
-    return new AltGlyphElement.internal_();
-  }
+  external factory AltGlyphElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AltGlyphElement.internal_() : super.internal_();
@@ -550,9 +546,7 @@
     return new AnimateElement._internalWrap();
   }
 
-  factory AnimateElement._internalWrap() {
-    return new AnimateElement.internal_();
-  }
+  external factory AnimateElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnimateElement.internal_() : super.internal_();
@@ -595,9 +589,7 @@
     return new AnimateMotionElement._internalWrap();
   }
 
-  factory AnimateMotionElement._internalWrap() {
-    return new AnimateMotionElement.internal_();
-  }
+  external factory AnimateMotionElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnimateMotionElement.internal_() : super.internal_();
@@ -640,9 +632,7 @@
     return new AnimateTransformElement._internalWrap();
   }
 
-  factory AnimateTransformElement._internalWrap() {
-    return new AnimateTransformElement.internal_();
-  }
+  external factory AnimateTransformElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnimateTransformElement.internal_() : super.internal_();
@@ -1158,9 +1148,7 @@
     return new AnimationElement._internalWrap();
   }
 
-  factory AnimationElement._internalWrap() {
-    return new AnimationElement.internal_();
-  }
+  external factory AnimationElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnimationElement.internal_() : super.internal_();
@@ -1245,9 +1233,7 @@
     return new CircleElement._internalWrap();
   }
 
-  factory CircleElement._internalWrap() {
-    return new CircleElement.internal_();
-  }
+  external factory CircleElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   CircleElement.internal_() : super.internal_();
@@ -1296,9 +1282,7 @@
     return new ClipPathElement._internalWrap();
   }
 
-  factory ClipPathElement._internalWrap() {
-    return new ClipPathElement.internal_();
-  }
+  external factory ClipPathElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ClipPathElement.internal_() : super.internal_();
@@ -1339,9 +1323,7 @@
     return new DefsElement._internalWrap();
   }
 
-  factory DefsElement._internalWrap() {
-    return new DefsElement.internal_();
-  }
+  external factory DefsElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   DefsElement.internal_() : super.internal_();
@@ -1378,9 +1360,7 @@
     return new DescElement._internalWrap();
   }
 
-  factory DescElement._internalWrap() {
-    return new DescElement.internal_();
-  }
+  external factory DescElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   DescElement.internal_() : super.internal_();
@@ -1413,9 +1393,7 @@
     return new DiscardElement._internalWrap();
   }
 
-  factory DiscardElement._internalWrap() {
-    return new DiscardElement.internal_();
-  }
+  external factory DiscardElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   DiscardElement.internal_() : super.internal_();
@@ -1452,9 +1430,7 @@
     return new EllipseElement._internalWrap();
   }
 
-  factory EllipseElement._internalWrap() {
-    return new EllipseElement.internal_();
-  }
+  external factory EllipseElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   EllipseElement.internal_() : super.internal_();
@@ -1511,9 +1487,7 @@
     return new FEBlendElement._internalWrap();
   }
 
-  factory FEBlendElement._internalWrap() {
-    return new FEBlendElement.internal_();
-  }
+  external factory FEBlendElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEBlendElement.internal_() : super.internal_();
@@ -1613,9 +1587,7 @@
     return new FEColorMatrixElement._internalWrap();
   }
 
-  factory FEColorMatrixElement._internalWrap() {
-    return new FEColorMatrixElement.internal_();
-  }
+  external factory FEColorMatrixElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEColorMatrixElement.internal_() : super.internal_();
@@ -1711,9 +1683,7 @@
     return new FEComponentTransferElement._internalWrap();
   }
 
-  factory FEComponentTransferElement._internalWrap() {
-    return new FEComponentTransferElement.internal_();
-  }
+  external factory FEComponentTransferElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEComponentTransferElement.internal_() : super.internal_();
@@ -1773,9 +1743,7 @@
     return new FECompositeElement._internalWrap();
   }
 
-  factory FECompositeElement._internalWrap() {
-    return new FECompositeElement.internal_();
-  }
+  external factory FECompositeElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FECompositeElement.internal_() : super.internal_();
@@ -1892,9 +1860,7 @@
     return new FEConvolveMatrixElement._internalWrap();
   }
 
-  factory FEConvolveMatrixElement._internalWrap() {
-    return new FEConvolveMatrixElement.internal_();
-  }
+  external factory FEConvolveMatrixElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEConvolveMatrixElement.internal_() : super.internal_();
@@ -2022,9 +1988,7 @@
     return new FEDiffuseLightingElement._internalWrap();
   }
 
-  factory FEDiffuseLightingElement._internalWrap() {
-    return new FEDiffuseLightingElement.internal_();
-  }
+  external factory FEDiffuseLightingElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEDiffuseLightingElement.internal_() : super.internal_();
@@ -2108,9 +2072,7 @@
     return new FEDisplacementMapElement._internalWrap();
   }
 
-  factory FEDisplacementMapElement._internalWrap() {
-    return new FEDisplacementMapElement.internal_();
-  }
+  external factory FEDisplacementMapElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEDisplacementMapElement.internal_() : super.internal_();
@@ -2214,9 +2176,7 @@
     return new FEDistantLightElement._internalWrap();
   }
 
-  factory FEDistantLightElement._internalWrap() {
-    return new FEDistantLightElement.internal_();
-  }
+  external factory FEDistantLightElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEDistantLightElement.internal_() : super.internal_();
@@ -2268,9 +2228,7 @@
     return new FEFloodElement._internalWrap();
   }
 
-  factory FEFloodElement._internalWrap() {
-    return new FEFloodElement.internal_();
-  }
+  external factory FEFloodElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEFloodElement.internal_() : super.internal_();
@@ -2334,9 +2292,7 @@
     return new FEFuncAElement._internalWrap();
   }
 
-  factory FEFuncAElement._internalWrap() {
-    return new FEFuncAElement.internal_();
-  }
+  external factory FEFuncAElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEFuncAElement.internal_() : super.internal_();
@@ -2380,9 +2336,7 @@
     return new FEFuncBElement._internalWrap();
   }
 
-  factory FEFuncBElement._internalWrap() {
-    return new FEFuncBElement.internal_();
-  }
+  external factory FEFuncBElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEFuncBElement.internal_() : super.internal_();
@@ -2426,9 +2380,7 @@
     return new FEFuncGElement._internalWrap();
   }
 
-  factory FEFuncGElement._internalWrap() {
-    return new FEFuncGElement.internal_();
-  }
+  external factory FEFuncGElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEFuncGElement.internal_() : super.internal_();
@@ -2472,9 +2424,7 @@
     return new FEFuncRElement._internalWrap();
   }
 
-  factory FEFuncRElement._internalWrap() {
-    return new FEFuncRElement.internal_();
-  }
+  external factory FEFuncRElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEFuncRElement.internal_() : super.internal_();
@@ -2518,9 +2468,7 @@
     return new FEGaussianBlurElement._internalWrap();
   }
 
-  factory FEGaussianBlurElement._internalWrap() {
-    return new FEGaussianBlurElement.internal_();
-  }
+  external factory FEGaussianBlurElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEGaussianBlurElement.internal_() : super.internal_();
@@ -2600,9 +2548,7 @@
     return new FEImageElement._internalWrap();
   }
 
-  factory FEImageElement._internalWrap() {
-    return new FEImageElement.internal_();
-  }
+  external factory FEImageElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEImageElement.internal_() : super.internal_();
@@ -2674,9 +2620,7 @@
     return new FEMergeElement._internalWrap();
   }
 
-  factory FEMergeElement._internalWrap() {
-    return new FEMergeElement.internal_();
-  }
+  external factory FEMergeElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEMergeElement.internal_() : super.internal_();
@@ -2740,9 +2684,7 @@
     return new FEMergeNodeElement._internalWrap();
   }
 
-  factory FEMergeNodeElement._internalWrap() {
-    return new FEMergeNodeElement.internal_();
-  }
+  external factory FEMergeNodeElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEMergeNodeElement.internal_() : super.internal_();
@@ -2786,9 +2728,7 @@
     return new FEMorphologyElement._internalWrap();
   }
 
-  factory FEMorphologyElement._internalWrap() {
-    return new FEMorphologyElement.internal_();
-  }
+  external factory FEMorphologyElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEMorphologyElement.internal_() : super.internal_();
@@ -2877,9 +2817,7 @@
     return new FEOffsetElement._internalWrap();
   }
 
-  factory FEOffsetElement._internalWrap() {
-    return new FEOffsetElement.internal_();
-  }
+  external factory FEOffsetElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEOffsetElement.internal_() : super.internal_();
@@ -2955,9 +2893,7 @@
     return new FEPointLightElement._internalWrap();
   }
 
-  factory FEPointLightElement._internalWrap() {
-    return new FEPointLightElement.internal_();
-  }
+  external factory FEPointLightElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FEPointLightElement.internal_() : super.internal_();
@@ -3013,9 +2949,7 @@
     return new FESpecularLightingElement._internalWrap();
   }
 
-  factory FESpecularLightingElement._internalWrap() {
-    return new FESpecularLightingElement.internal_();
-  }
+  external factory FESpecularLightingElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FESpecularLightingElement.internal_() : super.internal_();
@@ -3095,9 +3029,7 @@
     return new FESpotLightElement._internalWrap();
   }
 
-  factory FESpotLightElement._internalWrap() {
-    return new FESpotLightElement.internal_();
-  }
+  external factory FESpotLightElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FESpotLightElement.internal_() : super.internal_();
@@ -3173,9 +3105,7 @@
     return new FETileElement._internalWrap();
   }
 
-  factory FETileElement._internalWrap() {
-    return new FETileElement.internal_();
-  }
+  external factory FETileElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FETileElement.internal_() : super.internal_();
@@ -3243,9 +3173,7 @@
     return new FETurbulenceElement._internalWrap();
   }
 
-  factory FETurbulenceElement._internalWrap() {
-    return new FETurbulenceElement.internal_();
-  }
+  external factory FETurbulenceElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FETurbulenceElement.internal_() : super.internal_();
@@ -3357,9 +3285,7 @@
     return new FilterElement._internalWrap();
   }
 
-  factory FilterElement._internalWrap() {
-    return new FilterElement.internal_();
-  }
+  external factory FilterElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   FilterElement.internal_() : super.internal_();
@@ -3500,9 +3426,7 @@
     return new ForeignObjectElement._internalWrap();
   }
 
-  factory ForeignObjectElement._internalWrap() {
-    return new ForeignObjectElement.internal_();
-  }
+  external factory ForeignObjectElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ForeignObjectElement.internal_() : super.internal_();
@@ -3558,9 +3482,7 @@
     return new GElement._internalWrap();
   }
 
-  factory GElement._internalWrap() {
-    return new GElement.internal_();
-  }
+  external factory GElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   GElement.internal_() : super.internal_();
@@ -3593,9 +3515,7 @@
     return new GeometryElement._internalWrap();
   }
 
-  factory GeometryElement._internalWrap() {
-    return new GeometryElement.internal_();
-  }
+  external factory GeometryElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   GeometryElement.internal_() : super.internal_();
@@ -3638,9 +3558,7 @@
     return new GraphicsElement._internalWrap();
   }
 
-  factory GraphicsElement._internalWrap() {
-    return new GraphicsElement.internal_();
-  }
+  external factory GraphicsElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   GraphicsElement.internal_() : super.internal_();
@@ -3732,9 +3650,7 @@
     return new ImageElement._internalWrap();
   }
 
-  factory ImageElement._internalWrap() {
-    return new ImageElement.internal_();
-  }
+  external factory ImageElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ImageElement.internal_() : super.internal_();
@@ -4021,9 +3937,7 @@
     return new LineElement._internalWrap();
   }
 
-  factory LineElement._internalWrap() {
-    return new LineElement.internal_();
-  }
+  external factory LineElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   LineElement.internal_() : super.internal_();
@@ -4076,9 +3990,7 @@
     return new LinearGradientElement._internalWrap();
   }
 
-  factory LinearGradientElement._internalWrap() {
-    return new LinearGradientElement.internal_();
-  }
+  external factory LinearGradientElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   LinearGradientElement.internal_() : super.internal_();
@@ -4131,9 +4043,7 @@
     return new MarkerElement._internalWrap();
   }
 
-  factory MarkerElement._internalWrap() {
-    return new MarkerElement.internal_();
-  }
+  external factory MarkerElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MarkerElement.internal_() : super.internal_();
@@ -4238,9 +4148,7 @@
     return new MaskElement._internalWrap();
   }
 
-  factory MaskElement._internalWrap() {
-    return new MaskElement.internal_();
-  }
+  external factory MaskElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MaskElement.internal_() : super.internal_();
@@ -4435,9 +4343,7 @@
     return new MetadataElement._internalWrap();
   }
 
-  factory MetadataElement._internalWrap() {
-    return new MetadataElement.internal_();
-  }
+  external factory MetadataElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   MetadataElement.internal_() : super.internal_();
@@ -4628,9 +4534,7 @@
     return new PathElement._internalWrap();
   }
 
-  factory PathElement._internalWrap() {
-    return new PathElement.internal_();
-  }
+  external factory PathElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathElement.internal_() : super.internal_();
@@ -4889,9 +4793,7 @@
     return new PathSegArcAbs._internalWrap();
   }
 
-  factory PathSegArcAbs._internalWrap() {
-    return new PathSegArcAbs.internal_();
-  }
+  external factory PathSegArcAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegArcAbs.internal_() : super.internal_();
@@ -4974,9 +4876,7 @@
     return new PathSegArcRel._internalWrap();
   }
 
-  factory PathSegArcRel._internalWrap() {
-    return new PathSegArcRel.internal_();
-  }
+  external factory PathSegArcRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegArcRel.internal_() : super.internal_();
@@ -5059,9 +4959,7 @@
     return new PathSegClosePath._internalWrap();
   }
 
-  factory PathSegClosePath._internalWrap() {
-    return new PathSegClosePath.internal_();
-  }
+  external factory PathSegClosePath._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegClosePath.internal_() : super.internal_();
@@ -5088,9 +4986,7 @@
     return new PathSegCurvetoCubicAbs._internalWrap();
   }
 
-  factory PathSegCurvetoCubicAbs._internalWrap() {
-    return new PathSegCurvetoCubicAbs.internal_();
-  }
+  external factory PathSegCurvetoCubicAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegCurvetoCubicAbs.internal_() : super.internal_();
@@ -5165,9 +5061,7 @@
     return new PathSegCurvetoCubicRel._internalWrap();
   }
 
-  factory PathSegCurvetoCubicRel._internalWrap() {
-    return new PathSegCurvetoCubicRel.internal_();
-  }
+  external factory PathSegCurvetoCubicRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegCurvetoCubicRel.internal_() : super.internal_();
@@ -5242,9 +5136,7 @@
     return new PathSegCurvetoCubicSmoothAbs._internalWrap();
   }
 
-  factory PathSegCurvetoCubicSmoothAbs._internalWrap() {
-    return new PathSegCurvetoCubicSmoothAbs.internal_();
-  }
+  external factory PathSegCurvetoCubicSmoothAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegCurvetoCubicSmoothAbs.internal_() : super.internal_();
@@ -5303,9 +5195,7 @@
     return new PathSegCurvetoCubicSmoothRel._internalWrap();
   }
 
-  factory PathSegCurvetoCubicSmoothRel._internalWrap() {
-    return new PathSegCurvetoCubicSmoothRel.internal_();
-  }
+  external factory PathSegCurvetoCubicSmoothRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegCurvetoCubicSmoothRel.internal_() : super.internal_();
@@ -5364,9 +5254,7 @@
     return new PathSegCurvetoQuadraticAbs._internalWrap();
   }
 
-  factory PathSegCurvetoQuadraticAbs._internalWrap() {
-    return new PathSegCurvetoQuadraticAbs.internal_();
-  }
+  external factory PathSegCurvetoQuadraticAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegCurvetoQuadraticAbs.internal_() : super.internal_();
@@ -5425,9 +5313,7 @@
     return new PathSegCurvetoQuadraticRel._internalWrap();
   }
 
-  factory PathSegCurvetoQuadraticRel._internalWrap() {
-    return new PathSegCurvetoQuadraticRel.internal_();
-  }
+  external factory PathSegCurvetoQuadraticRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegCurvetoQuadraticRel.internal_() : super.internal_();
@@ -5486,9 +5372,7 @@
     return new PathSegCurvetoQuadraticSmoothAbs._internalWrap();
   }
 
-  factory PathSegCurvetoQuadraticSmoothAbs._internalWrap() {
-    return new PathSegCurvetoQuadraticSmoothAbs.internal_();
-  }
+  external factory PathSegCurvetoQuadraticSmoothAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegCurvetoQuadraticSmoothAbs.internal_() : super.internal_();
@@ -5531,9 +5415,7 @@
     return new PathSegCurvetoQuadraticSmoothRel._internalWrap();
   }
 
-  factory PathSegCurvetoQuadraticSmoothRel._internalWrap() {
-    return new PathSegCurvetoQuadraticSmoothRel.internal_();
-  }
+  external factory PathSegCurvetoQuadraticSmoothRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegCurvetoQuadraticSmoothRel.internal_() : super.internal_();
@@ -5576,9 +5458,7 @@
     return new PathSegLinetoAbs._internalWrap();
   }
 
-  factory PathSegLinetoAbs._internalWrap() {
-    return new PathSegLinetoAbs.internal_();
-  }
+  external factory PathSegLinetoAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegLinetoAbs.internal_() : super.internal_();
@@ -5621,9 +5501,7 @@
     return new PathSegLinetoHorizontalAbs._internalWrap();
   }
 
-  factory PathSegLinetoHorizontalAbs._internalWrap() {
-    return new PathSegLinetoHorizontalAbs.internal_();
-  }
+  external factory PathSegLinetoHorizontalAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegLinetoHorizontalAbs.internal_() : super.internal_();
@@ -5658,9 +5536,7 @@
     return new PathSegLinetoHorizontalRel._internalWrap();
   }
 
-  factory PathSegLinetoHorizontalRel._internalWrap() {
-    return new PathSegLinetoHorizontalRel.internal_();
-  }
+  external factory PathSegLinetoHorizontalRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegLinetoHorizontalRel.internal_() : super.internal_();
@@ -5695,9 +5571,7 @@
     return new PathSegLinetoRel._internalWrap();
   }
 
-  factory PathSegLinetoRel._internalWrap() {
-    return new PathSegLinetoRel.internal_();
-  }
+  external factory PathSegLinetoRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegLinetoRel.internal_() : super.internal_();
@@ -5740,9 +5614,7 @@
     return new PathSegLinetoVerticalAbs._internalWrap();
   }
 
-  factory PathSegLinetoVerticalAbs._internalWrap() {
-    return new PathSegLinetoVerticalAbs.internal_();
-  }
+  external factory PathSegLinetoVerticalAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegLinetoVerticalAbs.internal_() : super.internal_();
@@ -5777,9 +5649,7 @@
     return new PathSegLinetoVerticalRel._internalWrap();
   }
 
-  factory PathSegLinetoVerticalRel._internalWrap() {
-    return new PathSegLinetoVerticalRel.internal_();
-  }
+  external factory PathSegLinetoVerticalRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegLinetoVerticalRel.internal_() : super.internal_();
@@ -5930,9 +5800,7 @@
     return new PathSegMovetoAbs._internalWrap();
   }
 
-  factory PathSegMovetoAbs._internalWrap() {
-    return new PathSegMovetoAbs.internal_();
-  }
+  external factory PathSegMovetoAbs._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegMovetoAbs.internal_() : super.internal_();
@@ -5975,9 +5843,7 @@
     return new PathSegMovetoRel._internalWrap();
   }
 
-  factory PathSegMovetoRel._internalWrap() {
-    return new PathSegMovetoRel.internal_();
-  }
+  external factory PathSegMovetoRel._internalWrap();
 
   @Deprecated("Internal Use Only")
   PathSegMovetoRel.internal_() : super.internal_();
@@ -6024,9 +5890,7 @@
     return new PatternElement._internalWrap();
   }
 
-  factory PatternElement._internalWrap() {
-    return new PatternElement.internal_();
-  }
+  external factory PatternElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   PatternElement.internal_() : super.internal_();
@@ -6241,9 +6105,7 @@
     return new PolygonElement._internalWrap();
   }
 
-  factory PolygonElement._internalWrap() {
-    return new PolygonElement.internal_();
-  }
+  external factory PolygonElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   PolygonElement.internal_() : super.internal_();
@@ -6288,9 +6150,7 @@
     return new PolylineElement._internalWrap();
   }
 
-  factory PolylineElement._internalWrap() {
-    return new PolylineElement.internal_();
-  }
+  external factory PolylineElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   PolylineElement.internal_() : super.internal_();
@@ -6437,9 +6297,7 @@
     return new RadialGradientElement._internalWrap();
   }
 
-  factory RadialGradientElement._internalWrap() {
-    return new RadialGradientElement.internal_();
-  }
+  external factory RadialGradientElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   RadialGradientElement.internal_() : super.internal_();
@@ -6562,9 +6420,7 @@
     return new RectElement._internalWrap();
   }
 
-  factory RectElement._internalWrap() {
-    return new RectElement.internal_();
-  }
+  external factory RectElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   RectElement.internal_() : super.internal_();
@@ -6679,9 +6535,7 @@
     return new ScriptElement._internalWrap();
   }
 
-  factory ScriptElement._internalWrap() {
-    return new ScriptElement.internal_();
-  }
+  external factory ScriptElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ScriptElement.internal_() : super.internal_();
@@ -6733,9 +6587,7 @@
     return new SetElement._internalWrap();
   }
 
-  factory SetElement._internalWrap() {
-    return new SetElement.internal_();
-  }
+  external factory SetElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   SetElement.internal_() : super.internal_();
@@ -6775,9 +6627,7 @@
     return new StopElement._internalWrap();
   }
 
-  factory StopElement._internalWrap() {
-    return new StopElement.internal_();
-  }
+  external factory StopElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   StopElement.internal_() : super.internal_();
@@ -6935,9 +6785,7 @@
     return new StyleElement._internalWrap();
   }
 
-  factory StyleElement._internalWrap() {
-    return new StyleElement.internal_();
-  }
+  external factory StyleElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   StyleElement.internal_() : super.internal_();
@@ -7416,9 +7264,7 @@
     return new SvgElement._internalWrap();
   }
 
-  factory SvgElement._internalWrap() {
-    return new SvgElement.internal_();
-  }
+  external factory SvgElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   SvgElement.internal_() : super.internal_();
@@ -7771,9 +7617,7 @@
     return new SvgSvgElement._internalWrap();
   }
 
-  factory SvgSvgElement._internalWrap() {
-    return new SvgSvgElement.internal_();
-  }
+  external factory SvgSvgElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   SvgSvgElement.internal_() : super.internal_();
@@ -7974,9 +7818,7 @@
     return new SwitchElement._internalWrap();
   }
 
-  factory SwitchElement._internalWrap() {
-    return new SwitchElement.internal_();
-  }
+  external factory SwitchElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   SwitchElement.internal_() : super.internal_();
@@ -8013,9 +7855,7 @@
     return new SymbolElement._internalWrap();
   }
 
-  factory SymbolElement._internalWrap() {
-    return new SymbolElement.internal_();
-  }
+  external factory SymbolElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   SymbolElement.internal_() : super.internal_();
@@ -8060,9 +7900,7 @@
     return new TSpanElement._internalWrap();
   }
 
-  factory TSpanElement._internalWrap() {
-    return new TSpanElement.internal_();
-  }
+  external factory TSpanElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TSpanElement.internal_() : super.internal_();
@@ -8126,9 +7964,7 @@
     return new TextContentElement._internalWrap();
   }
 
-  factory TextContentElement._internalWrap() {
-    return new TextContentElement.internal_();
-  }
+  external factory TextContentElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextContentElement.internal_() : super.internal_();
@@ -8221,9 +8057,7 @@
     return new TextElement._internalWrap();
   }
 
-  factory TextElement._internalWrap() {
-    return new TextElement.internal_();
-  }
+  external factory TextElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextElement.internal_() : super.internal_();
@@ -8256,9 +8090,7 @@
     return new TextPathElement._internalWrap();
   }
 
-  factory TextPathElement._internalWrap() {
-    return new TextPathElement.internal_();
-  }
+  external factory TextPathElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextPathElement.internal_() : super.internal_();
@@ -8331,9 +8163,7 @@
     return new TextPositioningElement._internalWrap();
   }
 
-  factory TextPositioningElement._internalWrap() {
-    return new TextPositioningElement.internal_();
-  }
+  external factory TextPositioningElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TextPositioningElement.internal_() : super.internal_();
@@ -8390,9 +8220,7 @@
     return new TitleElement._internalWrap();
   }
 
-  factory TitleElement._internalWrap() {
-    return new TitleElement.internal_();
-  }
+  external factory TitleElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   TitleElement.internal_() : super.internal_();
@@ -8708,9 +8536,7 @@
     return new UseElement._internalWrap();
   }
 
-  factory UseElement._internalWrap() {
-    return new UseElement.internal_();
-  }
+  external factory UseElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   UseElement.internal_() : super.internal_();
@@ -8767,9 +8593,7 @@
     return new ViewElement._internalWrap();
   }
 
-  factory ViewElement._internalWrap() {
-    return new ViewElement.internal_();
-  }
+  external factory ViewElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   ViewElement.internal_() : super.internal_();
@@ -8931,9 +8755,7 @@
     return new ZoomEvent._internalWrap();
   }
 
-  factory ZoomEvent._internalWrap() {
-    return new ZoomEvent.internal_();
-  }
+  external factory ZoomEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   ZoomEvent.internal_() : super.internal_();
@@ -8980,9 +8802,7 @@
     return new _GradientElement._internalWrap();
   }
 
-  factory _GradientElement._internalWrap() {
-    return new _GradientElement.internal_();
-  }
+  external factory _GradientElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _GradientElement.internal_() : super.internal_();
@@ -9047,9 +8867,7 @@
     return new _SVGAltGlyphDefElement._internalWrap();
   }
 
-  factory _SVGAltGlyphDefElement._internalWrap() {
-    return new _SVGAltGlyphDefElement.internal_();
-  }
+  external factory _SVGAltGlyphDefElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGAltGlyphDefElement.internal_() : super.internal_();
@@ -9082,9 +8900,7 @@
     return new _SVGAltGlyphItemElement._internalWrap();
   }
 
-  factory _SVGAltGlyphItemElement._internalWrap() {
-    return new _SVGAltGlyphItemElement.internal_();
-  }
+  external factory _SVGAltGlyphItemElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGAltGlyphItemElement.internal_() : super.internal_();
@@ -9117,9 +8933,7 @@
     return new _SVGComponentTransferFunctionElement._internalWrap();
   }
 
-  factory _SVGComponentTransferFunctionElement._internalWrap() {
-    return new _SVGComponentTransferFunctionElement.internal_();
-  }
+  external factory _SVGComponentTransferFunctionElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGComponentTransferFunctionElement.internal_() : super.internal_();
@@ -9154,9 +8968,7 @@
     return new _SVGCursorElement._internalWrap();
   }
 
-  factory _SVGCursorElement._internalWrap() {
-    return new _SVGCursorElement.internal_();
-  }
+  external factory _SVGCursorElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGCursorElement.internal_() : super.internal_();
@@ -9197,9 +9009,7 @@
     return new _SVGFEDropShadowElement._internalWrap();
   }
 
-  factory _SVGFEDropShadowElement._internalWrap() {
-    return new _SVGFEDropShadowElement.internal_();
-  }
+  external factory _SVGFEDropShadowElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGFEDropShadowElement.internal_() : super.internal_();
@@ -9239,9 +9049,7 @@
     return new _SVGFontElement._internalWrap();
   }
 
-  factory _SVGFontElement._internalWrap() {
-    return new _SVGFontElement.internal_();
-  }
+  external factory _SVGFontElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGFontElement.internal_() : super.internal_();
@@ -9274,9 +9082,7 @@
     return new _SVGFontFaceElement._internalWrap();
   }
 
-  factory _SVGFontFaceElement._internalWrap() {
-    return new _SVGFontFaceElement.internal_();
-  }
+  external factory _SVGFontFaceElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGFontFaceElement.internal_() : super.internal_();
@@ -9309,9 +9115,7 @@
     return new _SVGFontFaceFormatElement._internalWrap();
   }
 
-  factory _SVGFontFaceFormatElement._internalWrap() {
-    return new _SVGFontFaceFormatElement.internal_();
-  }
+  external factory _SVGFontFaceFormatElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGFontFaceFormatElement.internal_() : super.internal_();
@@ -9344,9 +9148,7 @@
     return new _SVGFontFaceNameElement._internalWrap();
   }
 
-  factory _SVGFontFaceNameElement._internalWrap() {
-    return new _SVGFontFaceNameElement.internal_();
-  }
+  external factory _SVGFontFaceNameElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGFontFaceNameElement.internal_() : super.internal_();
@@ -9379,9 +9181,7 @@
     return new _SVGFontFaceSrcElement._internalWrap();
   }
 
-  factory _SVGFontFaceSrcElement._internalWrap() {
-    return new _SVGFontFaceSrcElement.internal_();
-  }
+  external factory _SVGFontFaceSrcElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGFontFaceSrcElement.internal_() : super.internal_();
@@ -9414,9 +9214,7 @@
     return new _SVGFontFaceUriElement._internalWrap();
   }
 
-  factory _SVGFontFaceUriElement._internalWrap() {
-    return new _SVGFontFaceUriElement.internal_();
-  }
+  external factory _SVGFontFaceUriElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGFontFaceUriElement.internal_() : super.internal_();
@@ -9453,9 +9251,7 @@
     return new _SVGGlyphElement._internalWrap();
   }
 
-  factory _SVGGlyphElement._internalWrap() {
-    return new _SVGGlyphElement.internal_();
-  }
+  external factory _SVGGlyphElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGGlyphElement.internal_() : super.internal_();
@@ -9486,9 +9282,7 @@
     return new _SVGGlyphRefElement._internalWrap();
   }
 
-  factory _SVGGlyphRefElement._internalWrap() {
-    return new _SVGGlyphRefElement.internal_();
-  }
+  external factory _SVGGlyphRefElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGGlyphRefElement.internal_() : super.internal_();
@@ -9528,9 +9322,7 @@
     return new _SVGHKernElement._internalWrap();
   }
 
-  factory _SVGHKernElement._internalWrap() {
-    return new _SVGHKernElement.internal_();
-  }
+  external factory _SVGHKernElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGHKernElement.internal_() : super.internal_();
@@ -9564,9 +9356,7 @@
     return new _SVGMPathElement._internalWrap();
   }
 
-  factory _SVGMPathElement._internalWrap() {
-    return new _SVGMPathElement.internal_();
-  }
+  external factory _SVGMPathElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGMPathElement.internal_() : super.internal_();
@@ -9602,9 +9392,7 @@
     return new _SVGMissingGlyphElement._internalWrap();
   }
 
-  factory _SVGMissingGlyphElement._internalWrap() {
-    return new _SVGMissingGlyphElement.internal_();
-  }
+  external factory _SVGMissingGlyphElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGMissingGlyphElement.internal_() : super.internal_();
@@ -9641,9 +9429,7 @@
     return new _SVGVKernElement._internalWrap();
   }
 
-  factory _SVGVKernElement._internalWrap() {
-    return new _SVGVKernElement.internal_();
-  }
+  external factory _SVGVKernElement._internalWrap();
 
   @Deprecated("Internal Use Only")
   _SVGVKernElement.internal_() : super.internal_();
diff --git a/sdk/lib/vmservice/asset.dart b/sdk/lib/vmservice/asset.dart
index 8155e8a..b8f6c20 100644
--- a/sdk/lib/vmservice/asset.dart
+++ b/sdk/lib/vmservice/asset.dart
@@ -59,6 +59,17 @@
   String toString() => '$name ($mimeType)';
 }
 
+HashMap<String, Asset> _assets;
+HashMap<String, Asset> get assets {
+  if (_assets == null) {
+    try {
+      _assets = Asset.request();
+    } catch (e) {
+      print('Could not load Observatory assets: $e');
+    }
+  }
+  return _assets;
+}
 
 class _ByteStream {
   final Uint8List bytes;
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index fa7790f..445f5d5 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -21,8 +21,6 @@
 final RawReceivePort isolateLifecyclePort = new RawReceivePort();
 final RawReceivePort scriptLoadPort = new RawReceivePort();
 
-typedef ShutdownCallback();
-
 // These must be kept in sync with the declarations in vm/json_stream.h.
 const kInvalidParams = -32602;
 const kInternalError = -32603;
@@ -62,6 +60,23 @@
   return JSON.encode(response);
 }
 
+const shortDelay = const Duration(milliseconds: 10);
+
+/// Called when the server should be started.
+typedef Future ServerStartCallback();
+
+/// Called when the server should be stopped.
+typedef Future ServerStopCallback();
+
+/// Called when the service is exiting.
+typedef Future CleanupCallback();
+
+/// Hooks that are setup by the embedder.
+class VMServiceEmbedderHooks {
+  static ServerStartCallback serverStart;
+  static ServerStopCallback serverStop;
+  static CleanupCallback cleanup;
+}
 
 class VMService extends MessageRouter {
   static VMService _instance;
@@ -75,8 +90,6 @@
   /// A port used to receive events from the VM.
   final RawReceivePort eventPort;
 
-  ShutdownCallback onShutdown;
-
   void _addClient(Client client) {
     assert(client.streams.isEmpty);
     clients.add(client);
@@ -115,19 +128,26 @@
     }
   }
 
-  void _exit() {
+  Future _exit() async {
+    // Stop the server.
+    if (VMServiceEmbedderHooks.serverStop != null) {
+      await VMServiceEmbedderHooks.serverStop();
+    }
+
+    // Close receive ports.
     isolateLifecyclePort.close();
     scriptLoadPort.close();
+
     // Create a copy of the set as a list because client.disconnect() will
     // alter the connected clients set.
     var clientsList = clients.toList();
     for (var client in clientsList) {
       client.disconnect();
     }
-    // Call embedder shutdown hook after the internal shutdown.
-    if (onShutdown != null) {
-      onShutdown();
+    if (VMServiceEmbedderHooks.cleanup != null) {
+      await VMServiceEmbedderHooks.cleanup();
     }
+    // Notify the VM that we have exited.
     _onExit();
   }
 
@@ -156,13 +176,8 @@
     print('Internal vm-service error: ignoring illegal message: $message');
   }
 
-  void _notSupported(_) {
-    throw new UnimplementedError('Service script loading not supported.');
-  }
-
   VMService._internal()
       : eventPort = isolateLifecyclePort {
-    scriptLoadPort.handler = _notSupported;
     eventPort.handler = messageHandler;
   }
 
@@ -174,17 +189,6 @@
     return _instance;
   }
 
-  void _clientCollection(Message message) {
-    var members = [];
-    var result = {};
-    clients.forEach((client) {
-      members.add(client.toJson());
-    });
-    result['type'] = 'ClientList';
-    result['members'] = members;
-    message.setResponse(JSON.encode(result));
-  }
-
   bool _isAnyClientSubscribed(String streamId) {
     for (var client in clients) {
       if (client.streams.contains(streamId)) {
@@ -293,10 +297,6 @@
       return message.response;
     }
     // TODO(turnidge): Update to json rpc.  BEFORE SUBMIT.
-    if ((message.path.length == 1) && (message.path[0] == 'clients')) {
-      _clientCollection(message);
-      return message.response;
-    }
     if (message.method == '_getCrashDump') {
       return _getCrashDump(message);
     }
@@ -323,12 +323,20 @@
   service.runningIsolates.isolateStartup(port_id, sp, name);
 }
 
+/// Notify the VM that the service is running.
 external void _onStart();
 
+/// Notify the VM that the service is no longer running.
 external void _onExit();
 
+/// Notify the VM that the server's address has changed.
+external void onServerAddressChange(String address);
+
+/// Subscribe to a service stream.
 external bool _vmListenStream(String streamId);
 
+/// Cancel a subscription to a service stream.
 external void _vmCancelStream(String streamId);
 
+/// Get the bytes to the tar archive.
 external Uint8List _requestAssets();
diff --git a/sdk/lib/web_audio/dartium/web_audio_dartium.dart b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
index cc99534..7a3a9c4 100644
--- a/sdk/lib/web_audio/dartium/web_audio_dartium.dart
+++ b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
@@ -104,9 +104,7 @@
     return new AnalyserNode._internalWrap();
   }
 
-  factory AnalyserNode._internalWrap() {
-    return new AnalyserNode.internal_();
-  }
+  external factory AnalyserNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   AnalyserNode.internal_() : super.internal_();
@@ -262,9 +260,7 @@
     return new AudioBufferSourceNode._internalWrap();
   }
 
-  factory AudioBufferSourceNode._internalWrap() {
-    return new AudioBufferSourceNode.internal_();
-  }
+  external factory AudioBufferSourceNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   AudioBufferSourceNode.internal_() : super.internal_();
@@ -375,9 +371,7 @@
     return new AudioContext._internalWrap();
   }
 
-  factory AudioContext._internalWrap() {
-    return new AudioContext.internal_();
-  }
+  external factory AudioContext._internalWrap();
 
   @Deprecated("Internal Use Only")
   AudioContext.internal_() : super.internal_();
@@ -542,9 +536,7 @@
     return new AudioDestinationNode._internalWrap();
   }
 
-  factory AudioDestinationNode._internalWrap() {
-    return new AudioDestinationNode.internal_();
-  }
+  external factory AudioDestinationNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   AudioDestinationNode.internal_() : super.internal_();
@@ -632,9 +624,7 @@
     return new AudioNode._internalWrap();
   }
 
-  factory AudioNode._internalWrap() {
-    return new AudioNode.internal_();
-  }
+  external factory AudioNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   AudioNode.internal_() : super.internal_();
@@ -788,9 +778,7 @@
     return new AudioProcessingEvent._internalWrap();
   }
 
-  factory AudioProcessingEvent._internalWrap() {
-    return new AudioProcessingEvent.internal_();
-  }
+  external factory AudioProcessingEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   AudioProcessingEvent.internal_() : super.internal_();
@@ -831,9 +819,7 @@
     return new AudioSourceNode._internalWrap();
   }
 
-  factory AudioSourceNode._internalWrap() {
-    return new AudioSourceNode.internal_();
-  }
+  external factory AudioSourceNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   AudioSourceNode.internal_() : super.internal_();
@@ -861,9 +847,7 @@
     return new BiquadFilterNode._internalWrap();
   }
 
-  factory BiquadFilterNode._internalWrap() {
-    return new BiquadFilterNode.internal_();
-  }
+  external factory BiquadFilterNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   BiquadFilterNode.internal_() : super.internal_();
@@ -919,9 +903,7 @@
     return new ChannelMergerNode._internalWrap();
   }
 
-  factory ChannelMergerNode._internalWrap() {
-    return new ChannelMergerNode.internal_();
-  }
+  external factory ChannelMergerNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   ChannelMergerNode.internal_() : super.internal_();
@@ -949,9 +931,7 @@
     return new ChannelSplitterNode._internalWrap();
   }
 
-  factory ChannelSplitterNode._internalWrap() {
-    return new ChannelSplitterNode.internal_();
-  }
+  external factory ChannelSplitterNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   ChannelSplitterNode.internal_() : super.internal_();
@@ -979,9 +959,7 @@
     return new ConvolverNode._internalWrap();
   }
 
-  factory ConvolverNode._internalWrap() {
-    return new ConvolverNode.internal_();
-  }
+  external factory ConvolverNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   ConvolverNode.internal_() : super.internal_();
@@ -1025,9 +1003,7 @@
     return new DelayNode._internalWrap();
   }
 
-  factory DelayNode._internalWrap() {
-    return new DelayNode.internal_();
-  }
+  external factory DelayNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   DelayNode.internal_() : super.internal_();
@@ -1059,9 +1035,7 @@
     return new DynamicsCompressorNode._internalWrap();
   }
 
-  factory DynamicsCompressorNode._internalWrap() {
-    return new DynamicsCompressorNode.internal_();
-  }
+  external factory DynamicsCompressorNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   DynamicsCompressorNode.internal_() : super.internal_();
@@ -1113,9 +1087,7 @@
     return new GainNode._internalWrap();
   }
 
-  factory GainNode._internalWrap() {
-    return new GainNode.internal_();
-  }
+  external factory GainNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   GainNode.internal_() : super.internal_();
@@ -1147,9 +1119,7 @@
     return new MediaElementAudioSourceNode._internalWrap();
   }
 
-  factory MediaElementAudioSourceNode._internalWrap() {
-    return new MediaElementAudioSourceNode.internal_();
-  }
+  external factory MediaElementAudioSourceNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaElementAudioSourceNode.internal_() : super.internal_();
@@ -1182,9 +1152,7 @@
     return new MediaStreamAudioDestinationNode._internalWrap();
   }
 
-  factory MediaStreamAudioDestinationNode._internalWrap() {
-    return new MediaStreamAudioDestinationNode.internal_();
-  }
+  external factory MediaStreamAudioDestinationNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaStreamAudioDestinationNode.internal_() : super.internal_();
@@ -1216,9 +1184,7 @@
     return new MediaStreamAudioSourceNode._internalWrap();
   }
 
-  factory MediaStreamAudioSourceNode._internalWrap() {
-    return new MediaStreamAudioSourceNode.internal_();
-  }
+  external factory MediaStreamAudioSourceNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   MediaStreamAudioSourceNode.internal_() : super.internal_();
@@ -1250,9 +1216,7 @@
     return new OfflineAudioCompletionEvent._internalWrap();
   }
 
-  factory OfflineAudioCompletionEvent._internalWrap() {
-    return new OfflineAudioCompletionEvent.internal_();
-  }
+  external factory OfflineAudioCompletionEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   OfflineAudioCompletionEvent.internal_() : super.internal_();
@@ -1290,9 +1254,7 @@
     return new OfflineAudioContext._internalWrap();
   }
 
-  factory OfflineAudioContext._internalWrap() {
-    return new OfflineAudioContext.internal_();
-  }
+  external factory OfflineAudioContext._internalWrap();
 
   @Deprecated("Internal Use Only")
   OfflineAudioContext.internal_() : super.internal_();
@@ -1331,9 +1293,7 @@
     return new OscillatorNode._internalWrap();
   }
 
-  factory OscillatorNode._internalWrap() {
-    return new OscillatorNode.internal_();
-  }
+  external factory OscillatorNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   OscillatorNode.internal_() : super.internal_();
@@ -1414,9 +1374,7 @@
     return new PannerNode._internalWrap();
   }
 
-  factory PannerNode._internalWrap() {
-    return new PannerNode.internal_();
-  }
+  external factory PannerNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   PannerNode.internal_() : super.internal_();
@@ -1561,9 +1519,7 @@
     return new ScriptProcessorNode._internalWrap();
   }
 
-  factory ScriptProcessorNode._internalWrap() {
-    return new ScriptProcessorNode.internal_();
-  }
+  external factory ScriptProcessorNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   ScriptProcessorNode.internal_() : super.internal_();
@@ -1613,9 +1569,7 @@
     return new WaveShaperNode._internalWrap();
   }
 
-  factory WaveShaperNode._internalWrap() {
-    return new WaveShaperNode.internal_();
-  }
+  external factory WaveShaperNode._internalWrap();
 
   @Deprecated("Internal Use Only")
   WaveShaperNode.internal_() : super.internal_();
diff --git a/sdk/lib/web_gl/dartium/web_gl_dartium.dart b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
index 1fdf4c7..707af2d 100644
--- a/sdk/lib/web_gl/dartium/web_gl_dartium.dart
+++ b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
@@ -824,9 +824,7 @@
     return new ContextEvent._internalWrap();
   }
 
-  factory ContextEvent._internalWrap() {
-    return new ContextEvent.internal_();
-  }
+  external factory ContextEvent._internalWrap();
 
   @Deprecated("Internal Use Only")
   ContextEvent.internal_() : super.internal_();
diff --git a/tests/benchmark_smoke/benchmark_smoke.status b/tests/benchmark_smoke/benchmark_smoke.status
index a83fd89..46f821f 100644
--- a/tests/benchmark_smoke/benchmark_smoke.status
+++ b/tests/benchmark_smoke/benchmark_smoke.status
@@ -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.
 
-[ ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 *: Skip
 
 [ $compiler == dart2js && $runtime == none ]
diff --git a/tests/co19/co19-analyzer2.status b/tests/co19/co19-analyzer2.status
index 3c67e8e..4ea29a4 100644
--- a/tests/co19/co19-analyzer2.status
+++ b/tests/co19/co19-analyzer2.status
@@ -66,8 +66,6 @@
 
 
 Language/Expressions/Method_Invocation/Cascaded_Invocations/syntax_t19: MissingStaticWarning
-Language/Statements/For/For_Loop/execution_t07: MissingStaticWarning
-Language/Statements/For/For_Loop/execution_t08: MissingStaticWarning
 Language/Statements/Switch/last_statement_t03: MissingStaticWarning
 Language/Statements/Assert/type_t04: MissingStaticWarning
 
@@ -288,7 +286,6 @@
 Language/Types/Interface_Types/subtype_t22: StaticWarning # co19 issue 745
 Language/Types/Interface_Types/subtype_t24: StaticWarning # co19 issue 745
 Language/Statements/Assert/type_t07: StaticWarning # Issue 23663
-Language/Statements/Assert/execution_t08: StaticWarning # Issue 23663
 
 # isProtocolHandlerRegistered and unregisterProtocolHandler don't exist
 LayoutTests/fast/dom/navigatorcontentutils/is-protocol-handler-registered_t01: Skip # Please triage this failure.
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 81419e9..f6e0f6d 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -46,11 +46,11 @@
 LibTest/isolate/ReceivePort/asBroadcastStream_A02_t01: Fail # co19 issue 687
 LibTest/async/Stream/asBroadcastStream_A02_t01: Fail # co19 issue 687
 
-LibTest/core/Symbol/Symbol_A01_t04: RuntimeError # co19-roll r607: Please triage this failure
+LibTest/core/Symbol/Symbol_A01_t04: RuntimeError # Issue 25804
 
-Language/Classes/same_name_type_variable_t01: Pass, MissingCompileTimeError, Fail # co19-roll r623: Please triage this failure
-Language/Classes/same_name_type_variable_t04: Pass, MissingCompileTimeError, Fail # co19-roll r623: Please triage this failure
-Language/Classes/same_name_type_variable_t07: Pass, MissingCompileTimeError, Fail # co19-roll r623: Please triage this failure
+Language/Classes/same_name_type_variable_t01: Pass, MissingCompileTimeError, Fail # Issue 14513
+Language/Classes/same_name_type_variable_t04: Pass, MissingCompileTimeError, Fail # Issue 14513
+Language/Classes/same_name_type_variable_t07: Pass, MissingCompileTimeError, Fail # Issue 14513
 
 LibTest/math/acos_A01_t01: PASS, FAIL, OK # co19 issue 44
 LibTest/math/asin_A01_t01: PASS, FAIL, OK # co19 issue 44
@@ -100,6 +100,6 @@
 ### CHECKED MODE FAILURES ###
 
 [ $compiler != dart2analyzer && $checked ]
-LibTest/collection/DoubleLinkedQueue/removeFirst_A01_t01: RuntimeError # co19-roll r607: Please triage this failure
-LibTest/collection/LinkedList/LinkedList_A01_t01: RuntimeError # co19-roll r623: Please triage this failure
+LibTest/collection/DoubleLinkedQueue/removeFirst_A01_t01: RuntimeError # co19 issue 22
+LibTest/collection/LinkedList/LinkedList_A01_t01: RuntimeError # co19 issue 23
 LibTest/collection/LinkedList/lastWhere_A02_t01: RuntimeError # co19 issue 737
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index a5781a6..8ee4e6d 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -149,8 +149,8 @@
 LibTest/core/List/getRange_A03_t01: RuntimeError, OK # Tests that fail because they use the legacy try-catch syntax. co19 issue 184.
 LibTest/core/List/removeAt_A02_t01: RuntimeError # Issue 1533
 LibTest/core/List/sort_A01_t06: Slow, Pass # Slow tests that needs extra time to finish.
-LibTest/core/double/INFINITY_A01_t04: RuntimeError # Please triage this failure.
-LibTest/core/double/NEGATIVE_INFINITY_A01_t04: RuntimeError # Please triage this failure.
+LibTest/core/double/INFINITY_A01_t04: RuntimeError # Expected to fail because double.INFINITY is int.
+LibTest/core/double/NEGATIVE_INFINITY_A01_t04: RuntimeError # Expected to fail because double.NEGATIVE_INFINITY is int.
 LibTest/core/int/hashCode_A01_t01: RuntimeError, OK # co19 issue 308
 LibTest/core/int/isEven_A01_t01: RuntimeError, OK # co19 issue 277
 LibTest/core/int/isOdd_A01_t01: RuntimeError, OK # co19 issue 277
@@ -609,6 +609,7 @@
 LibTest/typed_data/Uint8ClampedList/map_A02_t01: Pass, Slow # Please triage this failure.
 
 [ $compiler == dart2js && $runtime == chrome ]
+
 LayoutTests/fast/alignment/parse-align-items_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/alignment/parse-align-self_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/alignment/parse-justify-self_t01: RuntimeError # Please triage this failure
@@ -618,10 +619,9 @@
 LayoutTests/fast/animation/request-animation-frame-timestamps-advance_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/animation/request-animation-frame-timestamps_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/animation/request-animation-frame-within-callback_t01: Skip # Times out. Please triage this failure
-LayoutTests/fast/backgrounds/repeat/parsing-background-repeat_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/backgrounds/multiple-backgrounds-computed-style_t01: RuntimeError # co19 issue 14
-LayoutTests/fast/borders/border-radius-child_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/backgrounds/repeat/parsing-background-repeat_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/borders/border-width-percent_t01: RuntimeError # Issue 25155
 LayoutTests/fast/canvas/2d.fillText.gradient_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/2d.text.draw.fill.maxWidth.gradient_t01: RuntimeError # Please triage this failure
@@ -631,7 +631,9 @@
 LayoutTests/fast/canvas/alpha_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-arc-negative-radius_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-as-image-incremental-repaint_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/canvas/canvas-as-image_t01: RuntimeError # co19 issue 19
 LayoutTests/fast/canvas/canvas-blending-text_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/canvas-css-crazy_t01: RuntimeError # co19 issue 19
 LayoutTests/fast/canvas/canvas-currentTransform_t01: RuntimeError # Feature is behind a flag.
 LayoutTests/fast/canvas/canvas-empty-image-pattern_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-getImageData-invalid_t01: RuntimeError # Please triage this failure
@@ -646,14 +648,18 @@
 LayoutTests/fast/canvas/canvas-putImageData_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-resize-after-paint_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/canvas/canvas-scale-drawImage-shadow_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/crash-set-font_t01: RuntimeError # co19 issue 19
 LayoutTests/fast/canvas/draw-custom-focus-ring_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/getPutImageDataPairTest_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/setWidthResetAfterForcedRender_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/canvas/webgl/bad-arguments-test_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/buffer-data-array-buffer_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-lost-restored_t01: Pass, Timeout # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-lost_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/copy-tex-image-and-sub-image-2d_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/css-webkit-canvas-repaint_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/css-webkit-canvas_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/framebuffer-bindings-unaffected-on-resize_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/framebuffer-test_t01: RuntimeError # Please triage this failure
@@ -687,7 +693,7 @@
 LayoutTests/fast/canvas/webgl/webgl-depth-texture_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/webgl-layer-update_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/css-generated-content/hit-test-generated-content_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/css-generated-content/malformed-url_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css-generated-content/malformed-url_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/css-generated-content/pseudo-animation-before-onload_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css-generated-content/pseudo-animation-display_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/css-generated-content/pseudo-animation_t01: Pass, RuntimeError # Please triage this failure
@@ -735,6 +741,7 @@
 LayoutTests/fast/css-grid-layout/percent-padding-margin-resolution-grid-item_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css-grid-layout/percent-resolution-grid-item_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css-grid-layout/place-cell-by-index_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css-intrinsic-dimensions/multicol_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/MarqueeLayoutTest_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/add-remove-stylesheets-at-once-minimal-recalc-style_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/aspect-ratio-inheritance_t01: Pass, RuntimeError # Please triage this failure
@@ -742,10 +749,8 @@
 LayoutTests/fast/css/auto-min-size_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/background-position-serialize_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/background-serialize_t01: RuntimeError # https://github.com/dart-lang/co19/issues/14
-LayoutTests/fast/css/css-selector-text_t01: RuntimeError # co19 Issue 15
-LayoutTests/fast/css/css-escaped-identifier_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/checked-pseudo-selector_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/collapsed-whitespace-reattach-in-style-recalc_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/computed-offset-with-zoom_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/content-language-case-insensitivity_t01: RuntimeError # Issue 23506
 LayoutTests/fast/css/content-language-dynamically-added_t01: RuntimeError # Issue 23506
 LayoutTests/fast/css/content-language-dynamically-removed_t01: RuntimeError # Issue 23506
@@ -756,18 +761,21 @@
 LayoutTests/fast/css/content/content-normal_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/counters/complex-before_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/counters/counter-cssText_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/css-escaped-identifier_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/css-properties-case-insensitive_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/css-selector-text_t01: RuntimeError # co19 Issue 15
 LayoutTests/fast/css/css3-nth-tokens-style_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/cssText-shorthand_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/csstext-of-content-string_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/css/cursor-parsing_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/cursor-parsing-image-set_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/cursor-parsing-quirks_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/cursor-parsing_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/deprecated-flexbox-auto-min-size_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/ex-unit-with-no-x-height_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/first-child-display-change-inverse_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/focus-display-block-inline_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-face-cache-bug_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/css/font-face-insert-link_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-face-multiple-ranges-for-unicode-range_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-face-unicode-range-load_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-face-unicode-range-monospace_t01: Pass, RuntimeError # Please triage this failure
@@ -824,9 +832,10 @@
 LayoutTests/fast/css/stylesheet-enable-first-alternate-on-load-sheet_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/stylesheet-enable-second-alternate-link_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/transform-origin-parsing_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/css/unicode-bidi-computed-value_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/url-with-multi-byte-unicode-escape_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css/webkit-keyframes-errors_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/word-break-user-modify-allowed-values_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/url-with-multi-byte-unicode-escape_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-color_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-line_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-style_t01: RuntimeError # Please triage this failure
@@ -835,7 +844,6 @@
 LayoutTests/fast/css3-text/css3-text-indent/getComputedStyle/getComputedStyle-text-indent_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css3-text/css3-text-justify/getComputedStyle/getComputedStyle-text-justify_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/52776_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/click-method-on-html-element_t01: RuntimeError # Issue 25155
 LayoutTests/fast/dom/DOMException/XPathException_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/DOMImplementation/createDocument-namespace-err_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Document/CaretRangeFromPoint/basic_t01: RuntimeError # Please triage this failure
@@ -845,6 +853,7 @@
 LayoutTests/fast/dom/Document/CaretRangeFromPoint/replace-element_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Document/createElementNS-namespace-err_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Element/attribute-uppercase_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/Element/getBoundingClientRect-getClientRects-relative-to-viewport_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Element/getClientRects_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Element/setAttributeNS-namespace-err_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLAnchorElement/remove-href-from-focused-anchor_t01: Skip # Times out. Please triage this failure
@@ -873,10 +882,10 @@
 LayoutTests/fast/dom/HTMLLinkElement/link-beforeload-recursive_t01: Skip # Times out. Please triage this failure
 LayoutTests/fast/dom/HTMLLinkElement/resolve-url-on-insertion_t01: RuntimeError # Issue 18010
 LayoutTests/fast/dom/HTMLObjectElement/beforeload-set-text-crash_t01: Skip # Times out. Please triage this failure
+LayoutTests/fast/dom/HTMLObjectElement/form/test1_t01: RuntimeError # Issue 25155
 LayoutTests/fast/dom/HTMLObjectElement/set-type-to-null-crash_t01: RuntimeError # Issue 25155
 LayoutTests/fast/dom/HTMLOptionElement/collection-setter-getter_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLOutputElement/dom-settable-token-list_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/HTMLObjectElement/form/test1_t01: RuntimeError # Issue 25155
 LayoutTests/fast/dom/HTMLScriptElement/async-false-inside-async-false-load_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLScriptElement/async-inline-script_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLScriptElement/async-onbeforeload_t01: RuntimeError # Please triage this failure
@@ -885,7 +894,6 @@
 LayoutTests/fast/dom/HTMLScriptElement/remove-in-beforeload_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLScriptElement/remove-source_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLScriptElement/script-set-src_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/dom/HTMLSelectElement/selected-index-preserved-when-option-text-changes_t01: RuntimeError # Issue 18127
 LayoutTests/fast/dom/HTMLTemplateElement/custom-element-wrapper-gc_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLTemplateElement/innerHTML_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/HTMLTemplateElement/ownerDocumentXHTML_t01: RuntimeError # Please triage this failure
@@ -917,6 +925,7 @@
 LayoutTests/fast/dom/background-shorthand-csstext_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/blur-contenteditable_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/click-method-on-html-element_t01: RuntimeError # Issue 25155
 LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/css-selectorText_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/custom/document-register-basic_t01: RuntimeError # Dartium JSInterop failure
@@ -939,6 +948,7 @@
 LayoutTests/fast/dom/navigatorcontentutils/register-protocol-handler_t01: Skip # API not supported.
 LayoutTests/fast/dom/navigatorcontentutils/unregister-protocol-handler_t01: Skip # API not supported.
 LayoutTests/fast/dom/object-plugin-hides-properties_t01: RuntimeError # Issue 25155
+LayoutTests/fast/dom/offset-position-writing-modes_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/option-properties_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/partial-layout-overlay-scrollbars_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/set-innerHTML_t01: RuntimeError # Please triage this failure
@@ -1057,8 +1067,9 @@
 LayoutTests/fast/inline/out-of-flow-objects-and-whitespace-after-empty-inline_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/inline/parent-inline-element-padding-contributes-width_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/inline/positioned-element-padding-contributes-width_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/innerHTML/javascript-url_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/innerHTML/innerHTML-uri-resolution_t01: RuntimeError # co19 issue 14
+LayoutTests/fast/innerHTML/innerHTML-uri-resolution_t01: RuntimeError # co19 issue 14
+LayoutTests/fast/innerHTML/javascript-url_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/layers/normal-flow-hit-test_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/layers/zindex-hit-test_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/loader/about-blank-hash-change_t01: Skip # Times out. Please triage this failure
@@ -1068,7 +1079,6 @@
 LayoutTests/fast/loader/scroll-position-restored-on-back_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/loader/scroll-position-restored-on-reload-at-load-event_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/loader/stateobjects/replacestate-in-onunload_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/innerHTML/innerHTML-uri-resolution_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/masking/parsing-clip-path-iri_t01: RuntimeError # co19 issue 14
 LayoutTests/fast/masking/parsing-clip-path-shape_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/masking/parsing-mask-source-type_t01: RuntimeError # Please triage this failure
@@ -1086,7 +1096,6 @@
 LayoutTests/fast/multicol/hit-test-end-of-column-with-line-height_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/multicol/hit-test-end-of-column_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/multicol/hit-test-float_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/multicol/hit-test-gap-between-pages-flipped_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/multicol/hit-test-gap-between-pages_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/multicol/newmulticol/balance-images_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/multicol/newmulticol/balance-maxheight_t01: RuntimeError # Please triage this failure
@@ -1100,6 +1109,7 @@
 LayoutTests/fast/multicol/vertical-rl/image-inside-nested-blocks-with-border_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/multicol/widows_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/overflow/replaced-child-100percent-height-inside-fixed-container-with-overflow-auto_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/overflow/scrollbar-restored_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/parser/foster-parent-adopted_t02: RuntimeError # Please triage this failure
 LayoutTests/fast/parser/fragment-parser-doctype_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/parser/innerhtml-with-prefixed-elements_t01: RuntimeError # Please triage this failure
@@ -1131,7 +1141,6 @@
 LayoutTests/fast/sub-pixel/cssom-subpixel-precision_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/sub-pixel/float-containing-block-with-margin_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/sub-pixel/replaced-element-baseline_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/sub-pixel/table-rows-have-stable-height_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/table/anonymous-table-section-removed_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/table/caption-orthogonal-writing-mode-sizing_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/table/col-width-span-expand_t01: RuntimeError # Please triage this failure
@@ -1191,6 +1200,7 @@
 LayoutTests/fast/url/segments_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/url/standard-url_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/writing-mode/auto-sizing-orthogonal-flows_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/writing-mode/flipped-blocks-hit-test-overflow-scroll_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/writing-mode/flipped-blocks-hit-test-overflow_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/writing-mode/positionForPoint_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/writing-mode/table-hit-test_t01: RuntimeError # Please triage this failure
@@ -1323,10 +1333,10 @@
 WebPlatformTest/custom-elements/concepts/type_A03_t01: RuntimeError # Please triage this failure
 WebPlatformTest/custom-elements/concepts/type_A05_t01: RuntimeError # Please triage this failure
 WebPlatformTest/custom-elements/concepts/type_A06_t01: RuntimeError # Please triage this failure
-WebPlatformTest/custom-elements/instantiating/createElement_A02_t01: RuntimeError # Issue 25155
-WebPlatformTest/custom-elements/instantiating/createElement_A03_t01: RuntimeError # Issue 25155
 WebPlatformTest/custom-elements/instantiating/createElementNS_A02_t01: RuntimeError # Issue 25155
 WebPlatformTest/custom-elements/instantiating/createElementNS_A03_t01: RuntimeError # Issue 25155
+WebPlatformTest/custom-elements/instantiating/createElement_A02_t01: RuntimeError # Issue 25155
+WebPlatformTest/custom-elements/instantiating/createElement_A03_t01: RuntimeError # Issue 25155
 WebPlatformTest/custom-elements/instantiating/isAttribute_A01_t01: RuntimeError # Issue 25155
 WebPlatformTest/custom-elements/instantiating/isAttribute_A01_t02: RuntimeError # Issue 25155
 WebPlatformTest/dom/EventTarget/dispatchEvent_A02_t01: RuntimeError # Please triage this failure
@@ -1377,7 +1387,6 @@
 WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/TextTrack/cues_t01: Skip # Times out. Please triage this failure
 WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/TextTrack/mode_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/attributes-common-to-form-controls/formaction_t01: RuntimeError # Please triage this failure
-WebPlatformTest/html/semantics/forms/textfieldselection/selection_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/textfieldselection/textfieldselection-setRangeText_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange_t01: Pass, RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/the-button-element/button-validation_t01: RuntimeError # Please triage this failure
@@ -1399,7 +1408,6 @@
 WebPlatformTest/html/semantics/forms/the-input-element/time_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/the-input-element/time_t02: RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/the-input-element/type-change-state_t01: RuntimeError # Please triage this failure
-WebPlatformTest/html/semantics/forms/the-input-element/url_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/the-input-element/valueMode_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/the-input-element/week_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/semantics/forms/the-meter-element/meter_t01: RuntimeError # Please triage this failure
@@ -1467,9 +1475,9 @@
 WebPlatformTest/shadow-dom/shadow-trees/lower-boundary-encapsulation/test-004_t01: RuntimeError # Please triage this failure
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-002_t01: RuntimeError # Please triage this failure
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/ownerdocument-002_t01: RuntimeError # Please triage this failure
-WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-009_t01: RuntimeError # Please triage this failure
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-005_t01: RuntimeError # Issue 25155
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-007_t01: RuntimeError # Issue 25155
+WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-009_t01: RuntimeError # Please triage this failure
 WebPlatformTest/webstorage/event_constructor_t01: RuntimeError # Please triage this failure
 WebPlatformTest/webstorage/event_constructor_t02: RuntimeError # Please triage this failure
 
@@ -1564,7 +1572,6 @@
 LayoutTests/fast/canvas/webgl/array-bounds-clamping_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/attrib-location-length-limits_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/buffer-bind-test_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/buffer-data-array-buffer_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/canvas-2d-webgl-texture_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/canvas-resize-crash_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/canvas-test_t01: RuntimeError # Please triage this failure
@@ -1572,8 +1579,6 @@
 LayoutTests/fast/canvas/webgl/compressed-tex-image_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-destroyed-crash_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/context-lost-restored_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/css-webkit-canvas-repaint_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/css-webkit-canvas_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/draw-arrays-out-of-bounds_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/draw-elements-out-of-bounds_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/draw-webgl-to-canvas-2d_t01: RuntimeError # Please triage this failure
@@ -1643,9 +1648,11 @@
 LayoutTests/fast/text/text-combine-shrink-to-fit_t01: RuntimeError # Please triage this failure
 
 [ $compiler == dart2js && $runtime == chrome && $system != linux ]
+LayoutTests/fast/multicol/hit-test-gap-between-pages-flipped_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Issue 24398
 
 [ $compiler == dart2js && $runtime == chrome && $system == linux]
+LayoutTests/fast/text/international/combining-marks-position_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
 
 [ $compiler == dart2js && $runtime == ff ]
@@ -1942,9 +1949,6 @@
 LayoutTests/fast/css/first-child-display-change-inverse_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/focus-display-block-inline_t01: Pass, RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-face-insert-link_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/css/font-face-unicode-range-load_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/font-face-unicode-range-monospace_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css/font-face-unicode-range-overlap-load_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-family-trailing-bracket-gunk_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-property-priority_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/css/font-shorthand-from-longhands_t01: RuntimeError # Please triage this failure
@@ -2981,7 +2985,6 @@
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.getElementsByName-namespace_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.getElementsByName-newelements_t01: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.title_t01: RuntimeError # Please triage this failure
-WebPlatformTest/html/dom/documents/dom-tree-accessors/document.title_t03: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.title_t07: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/nameditem_t02: RuntimeError # Please triage this failure
 WebPlatformTest/html/dom/documents/dom-tree-accessors/nameditem_t05: RuntimeError # Please triage this failure
@@ -3160,8 +3163,6 @@
 [ $compiler == dart2js && $runtime == ff && $system != windows ]
 LayoutTests/fast/canvas/canvas-resetTransform_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/canvas-setTransform_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/drawImage-with-negative-source-destination_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/HTMLAnchorElement/set-href-attribute-pathname_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/xpath/4XPath/Core/test_parser_t01: RuntimeError # Dartium JSInterop failure
 LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
 
@@ -9616,21 +9617,8 @@
 WebPlatformTest/webstorage/storage_local_setitem_quotaexceedederr_t01: Skip # Times out. Please triage this failure
 
 [ $compiler == dart2js && $cps_ir ]
-Language/Statements/Labels/scope_t04: Crash # (switch (i){L:case 0:flag=true;break;case 2:continue L;}): continue to a labeled switch case
-Language/Statements/Continue/label_t12: Crash # (switch (2){L:case 1:flag=true;break;case 2:continue L;}): continue to a labeled switch case
-Language/Statements/Continue/label_t13: Crash # (switch (2){case 2:continue L;L:case 1:flag=true;}): continue to a labeled switch case
-Language/Types/Interface_Types/subtype_t39: RuntimeError # Please triage this failure.
+Language/Types/Interface_Types/subtype_t09: Crash # Pending static: JSArray
 LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Timeout
-LibTest/core/Invocation/isAccessor_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
 LibTest/core/Invocation/isGetter_A01_t01: RuntimeError # Please triage this failure.
-LibTest/core/Invocation/isGetter_A01_t02: RuntimeError # Please triage this failure.
-LibTest/core/Invocation/isMethod_A01_t02: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
-LibTest/core/Invocation/isSetter_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
 LibTest/core/Invocation/isSetter_A01_t02: RuntimeError # Please triage this failure.
-LibTest/core/Invocation/memberName_A01_t01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
-LibTest/core/Invocation/namedArguments_A01_t01: RuntimeError # Please triage this failure.
-LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError # Please triage this failure.
-LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # Please triage this failure.
-LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # Please triage this failure.
-LibTest/core/double/INFINITY_A01_t04: Pass # Please triage this failure.
-LibTest/core/double/NEGATIVE_INFINITY_A01_t04: Pass # Please triage this failure.
+LibTest/core/Invocation/memberName_A01_t01: RuntimeError # Expect.equals(expected: <Symbol("bar=")>, actual: <Symbol("bar")>) fails.
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index f97f79d..eb9b059 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -6,36 +6,138 @@
 *: Skip # running co19 tests on content_shell would make our dartium cycle-times very long
 
 [ $compiler == none && $runtime == dartium && $system == macos ]
-LayoutTests/fast/writing-mode/broken-ideographic-font_t01: Skip # Timing out on the bots. Please triage this failure.
 LayoutTests/fast/css-generated-content/pseudo-animation-before-onload_t01: Skip # Depends on animation timing, commented as known to be flaky in test.  Will not fix.
-LayoutTests/fast/writing-mode/vertical-inline-block-hittest_t01: Pass, RuntimeError # Issue 21605
+LayoutTests/fast/writing-mode/broken-ideographic-font_t01: Skip # Timing out on the bots. Please triage this failure.
 LayoutTests/fast/writing-mode/flipped-blocks-hit-test-overflow_t01: Pass, RuntimeError # Issue 21605
+LayoutTests/fast/writing-mode/vertical-inline-block-hittest_t01: Pass, RuntimeError # Issue 21605
 
 [ $compiler == none && $runtime == dartium && $system == windows ]
 LayoutTests/fast/writing-mode/vertical-inline-block-hittest_t01: Pass, RuntimeError # Issue 21605
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-002_t01: RuntimeError # Please triage this failure.
 
-[ $compiler == none && $runtime == dartium ]
-LayoutTests/fast/dom/custom/document-register-basic_t01: RuntimeError # Bad test can't register HtmlElement.
-LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Dartium JSInterop failure
-LayoutTests/fast/dom/navigatorcontentutils/is-protocol-handler-registered_t01: RuntimeError # Dartium JSInterop failure
-LayoutTests/fast/dom/navigatorcontentutils/unregister-protocol-handler_t01: RuntimeError # Dartium JSInterop failure
-LayoutTests/fast/events/remove-event-listener_t01: RuntimeError # Dartium JSInterop failure
-LayoutTests/fast/xpath/4XPath/Core/test_parser_t01: RuntimeError # Dartium JSInterop failure
-LayoutTests/fast/xpath/attr-namespace_t01: RuntimeError # Dartium JsInterop failure
-LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
-LayoutTests/fast/xpath/py-dom-xpath/axes_t01: RuntimeError # Dartium JSInterop failure
-WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t01: Pass, RuntimeError # Flaky with Dartium JsInterop. Seems like timing issues in the test.
-LibTest/html/IFrameElement/IFrameElement.created_A01_t01: RuntimeError # Issue 24568
-LibTest/html/Window/requestFileSystem_A02_t01: Skip # Issue 24585.
-LibTest/html/Window/document_A01_t01: Skip # accesses window.document from a cross-frame window
-WebPlatformTest/html/browsers/browsing-the-web/read-text/load-text-plain_t01: Skip # accesses window.document from a cross-frame window
-WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-002_t01: Pass, Fail # https://github.com/dart-lang/co19/issues/12
+[ $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.
 
 [ $compiler == none && $runtime == dartium && $checked ]
+Language/Errors_and_Warnings/static_warning_t01: RuntimeError # Please triage this failure.
+Language/Errors_and_Warnings/static_warning_t02: RuntimeError # Please triage this failure.
+Language/Errors_and_Warnings/static_warning_t03: RuntimeError # Please triage this failure.
+Language/Errors_and_Warnings/static_warning_t04: RuntimeError # Please triage this failure.
+Language/Errors_and_Warnings/static_warning_t05: RuntimeError # Please triage this failure.
+Language/Errors_and_Warnings/static_warning_t06: RuntimeError # Please triage this failure.
+LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/webgl/oes-vertex-array-object_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/webgl/read-pixels-test_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/css-tables_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-absolutes_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-blocks_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-column-flex-items_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-flex-items_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-replaced-absolutes_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/multicol_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/tables_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/width-shrinks-avoid-floats_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css/box-sizing-border-box-dynamic-padding-border-update_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/display-inline-block-scrollbar_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/fixed-width-intrinsic-width-excludes-scrollbars_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/style-scoped/style-scoped-scoping-nodes-different-order_t01: RuntimeError # Dartium JSInterop failure
+LayoutTests/fast/dom/HTMLDialogElement/top-layer-position-relative_t01: RuntimeError # Please triage this failure.
+LayoutTests/fast/dom/HTMLDialogElement/top-layer-position-static_t01: RuntimeError # Please triage this failure.
+LayoutTests/fast/dom/HTMLLabelElement/form/test1_t01: RuntimeError # co19-roll r722: Please triage this failure.
+LayoutTests/fast/dom/HTMLTableElement/insert-row_t01: RuntimeError # co19-roll r722: Please triage this failure.
+LayoutTests/fast/dom/custom/type-extensions_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/shadow/shadowhost-keyframes_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
+LayoutTests/fast/filesystem/file-writer-abort_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/file-writer-events_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-copy_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-get-entry_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-get-metadata_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-get-parent_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-move_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-read-directory_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-remove_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-restricted-chars_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-restricted-names_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/filesystem/op-restricted-unicode_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/flexbox/flexing-overflow-scroll-item_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/flexbox/intrinsic-min-width-applies-with-fixed-width_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/forms/select-list-box-mouse-focus_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/html/article-element_t01: RuntimeError # co19-roll r706.  Please triage this failure.
+LayoutTests/fast/html/aside-element_t01: RuntimeError # co19-roll r706.  Please triage this failure.
+LayoutTests/fast/inline/empty-inline-before-collapsed-space_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/innerHTML/innerHTML-svg-read_t01: RuntimeError, Pass # co19-roll r706.  Please triage this failure.
+LayoutTests/fast/lists/list-style-position-inside_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/lists/marker-preferred-margins_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/multicol/fixed-column-percent-logical-height-orthogonal-writing-mode_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/multicol/vertical-lr/image-inside-nested-blocks-with-border_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/replaced/available-height-for-content_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/replaced/computed-image-width-with-percent-height-and-fixed-ancestor-vertical-lr_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/replaced/computed-image-width-with-percent-height-and-fixed-ancestor_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/replaced/computed-image-width-with-percent-height-inside-table-cell-and-fixed-ancestor-vertical-lr_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/replaced/computed-image-width-with-percent-height-inside-table-cell-and-fixed-ancestor_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/shapes/parsing/parsing-shape-image-threshold_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/shapes/parsing/parsing-shape-margin_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/shapes/parsing/parsing-shape-outside_t01: RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/table/absolute-table-percent-lengths_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/css-table-width_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/fixed-table-layout-width-change_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/html-table-width-max-width-constrained_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/margins-flipped-text-direction_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/min-max-width-preferred-size_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/nested-tables-with-div-offset_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/switch-table-layout-dynamic-cells_t01: RuntimeError # co19 issue 11.
+LayoutTests/fast/table/switch-table-layout-dynamic-cells_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/switch-table-layout-multiple-section_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/switch-table-layout_t01: RuntimeError # co19 issue 11.
+LayoutTests/fast/table/switch-table-layout_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/table/table-width-exceeding-max-width_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/text/line-break-after-inline-latin1_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/url/trivial-segments_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/url/trivial_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/xpath/invalid-resolver_t01: RuntimeError # https://github.com/dart-lang/co19/issues/21
+LayoutTests/fast/xpath/xpath-result-eventlistener-crash_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LibTest/html/Node/ownerDocument_A01_t01: RuntimeError # co19-roll r722: Issue 18251
+WebPlatformTest/DOMEvents/approved/Propagation.path.target.removed_t01: RuntimeError # co19-roll r738: Please triage this failure.
+WebPlatformTest/custom-elements/instantiating/createElementNS_A05_t01: RuntimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/custom-elements/instantiating/createElement_A05_t01: RuntimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/html-templates/parsing-html-templates/clearing-the-stack-back-to-a-given-context/clearing-stack-back-to-a-table-body-context_t01: RuntimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/html-templates/parsing-html-templates/clearing-the-stack-back-to-a-given-context/clearing-stack-back-to-a-table-context_t01: RuntimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/html-templates/parsing-html-templates/clearing-the-stack-back-to-a-given-context/clearing-stack-back-to-a-table-row-context_t01: RuntimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/html/dom/elements/global-attributes/dataset-enumeration_t01: RuntimeError # co19-roll r738: Please triage this failure.
+WebPlatformTest/html/semantics/forms/textfieldselection/selection_t01: RuntimeError # co19-roll r738: Please triage this failure.
+WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/ownerdocument-001_t01: RuntimeError # co19-roll r722: Please triage this failure.
 
-[ $compiler == none && ($runtime == dartium || $runtime == ContentShellOnAndroid) ]
+[ $compiler == none && $runtime == dartium ]
+Language/Classes/Constructors/Generative_Constructors/execution_t03: Fail, OK
 Language/Classes/Constructors/Generative_Constructors/final_variables_t01: Pass, Fail #: Please triage this failure.
 Language/Classes/Getters/type_object_t01: RuntimeError # Please triage this failure.
 Language/Classes/Getters/type_object_t02: RuntimeError # Please triage this failure.
@@ -75,8 +177,12 @@
 Language/Classes/deсlarations_t34: Skip # Times out. Please triage this failure.
 Language/Expressions/Instance_Creation/Const/abstract_class_t01: Fail # Issue 22007
 Language/Expressions/Instance_Creation/Const/abstract_class_t03: Fail # Issue 22007
+Language/Expressions/Instance_Creation/New/execution_t04: Fail, OK
+Language/Expressions/Instance_Creation/New/execution_t06: Fail, OK
 Language/Expressions/Property_Extraction/Named_Constructor_Extraction/not_class_t01: RuntimeError # Please triage this failure.
 Language/Expressions/Spawning_an_Isolate/new_isolate_t01: RuntimeError, OK  # Uses Isolate.spawn.
+Language/Libraries_and_Scripts/Exports/reexport_t01: fail # Dart issue 12916
+Language/Libraries_and_Scripts/Exports/reexport_t02: fail # Dart issue 12916
 Language/Libraries_and_Scripts/Imports/namespace_changes_t10: RuntimeError # Please triage this failure.
 Language/Libraries_and_Scripts/Parts/compilation_t02: Skip # Please triage this failure.
 Language/Libraries_and_Scripts/Parts/syntax_t05: Skip # Times out flakily. Issue 20881
@@ -91,6 +197,12 @@
 Language/Metadata/before_variable_t01: RuntimeError # Please triage this failure.
 Language/Mixins/not_object_superclass_t01: Fail # Please triage this failure.
 Language/Mixins/reference_to_super_t01: Fail # Please triage this failure.
+Language/Statements/Assert/execution_t02: skip # co19 issue 734
+Language/Statements/Assert/execution_t03: skip # co19 issue 734
+Language/Statements/Assert/type_t02: skip # co19 issue 734
+Language/Statements/Assert/type_t05: skip # co19 issue 734
+Language/Statements/Labels/syntax_t03: fail # Dart issue 2238
+Language/Statements/Switch/syntax_t02: fail # Dart issue 12908
 LayoutTests/fast/alignment/parse-align-items_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/alignment/parse-align-self_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/alignment/parse-justify-self_t01: RuntimeError # co19-roll r761: Please triage this failure.
@@ -102,8 +214,10 @@
 LayoutTests/fast/canvas/2d.text.draw.fill.maxWidth.negative_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/2d.text.draw.fill.maxWidth.veryLarge_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/2d.text.draw.fill.maxWidth.verySmall_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/alpha_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/canvas/canvas-arc-negative-radius_t01: Skip # Times out. co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/canvas-blending-text_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/canvas-currentTransform_t01: RuntimeError # Feature is behind a flag in Chrome
 LayoutTests/fast/canvas/canvas-empty-image-pattern_t01: RuntimeError # co19-roll r761: Please triage this failure.
 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.
@@ -113,27 +227,124 @@
 LayoutTests/fast/canvas/draw-custom-focus-ring_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/drawImage-with-broken-image_t01: Timeout, Pass # co19-roll r761: Please triage this failure.
 LayoutTests/fast/canvas/getPutImageDataPairTest_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/webgl/bad-arguments-test_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/webgl/WebGLContextEvent_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/array-bounds-clamping_t01: RuntimeError # Issue 25653
+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/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/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-lost_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/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/draw-webgl-to-canvas-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-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/gl-object-get-calls_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/webgl/incorrect-context-object-behaviour_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/webgl/error-reporting_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/framebuffer-bindings-unaffected-on-resize_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/framebuffer-bindings-unaffected-on-resize_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/framebuffer-test_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/framebuffer-test_t01: RuntimeError # Issue 20, 22026
+LayoutTests/fast/canvas/webgl/functions-returning-strings_t01: Pass, RuntimeError # Issue 22026
+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-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-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-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/invalid-UTF-16_t01: Pass, 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: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/webgl/null-object-behaviour_t01: Pass, RuntimeError # Issue 20, 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.
+LayoutTests/fast/canvas/webgl/oes-element-index-uint_t01: RuntimeError # Issue 22026
+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/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.
+LayoutTests/fast/canvas/webgl/renderer-and-vendor-strings_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/shader-precision-format_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-array-buffer-view_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-array-buffer-view_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgb565_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgb565_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgba4444_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgba4444_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgba5551_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgba5551_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgb565_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgb565_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba4444_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba4444_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba5551_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba5551_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgb565_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgb565_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba4444_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba4444_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba5551_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba5551_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgb565_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgb565_t01: Skip # Issue 20540
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba4444_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba4444_t01: Skip # Issue 20540
+LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-video-rgba5551_t01: RuntimeError # Please triage this failure
 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-webgl_t01: RuntimeError # Issue 25653
+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/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/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
 LayoutTests/fast/canvas/webgl/uniform-location_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/webgl/uninitialized-test_t01: RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/uninitialized-test_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/viewport-unchanged-upon-resize_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/webgl-composite-modes-repaint_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/webgl-composite-modes_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/webgl-depth-texture_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/webgl-depth-texture_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/canvas/webgl/webgl-exceptions_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/webgl-large-texture_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/webgl-layer-update_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/webgl-specific_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/webgl-texture-binding-preserved_t01: RuntimeError # Issue 25653
+LayoutTests/fast/canvas/webgl/webgl-unprefixed-context-id_t01: Pass, RuntimeError # Issue 22026
+LayoutTests/fast/canvas/webgl/webgl-viewport-parameters-preserved_t01: Pass, RuntimeError # Issue 22026
 LayoutTests/fast/css-generated-content/bug91547_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/css-generated-content/hit-test-generated-content_t01: Skip # co19 issue 732.
 LayoutTests/fast/css-generated-content/malformed-url_t01: RuntimeError # co19-roll r786: Please triage this failure.
@@ -183,18 +394,35 @@
 LayoutTests/fast/css-grid-layout/percent-padding-margin-resolution-grid-item_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css-grid-layout/percent-resolution-grid-item_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css-grid-layout/place-cell-by-index_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-replaced-absolutes_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-replaced-absolutes_t01: Timeout # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/MarqueeLayoutTest_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/add-remove-stylesheets-at-once-minimal-recalc-style_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/aspect-ratio-inheritance_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/aspect-ratio-parsing-tests_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/auto-min-size_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/background-position-serialize_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/checked-pseudo-selector_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/collapsed-whitespace-reattach-in-style-recalc_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/collapsed-whitespace-reattach-in-style-recalc_t01: Skip # co19 issue 732.
 LayoutTests/fast/css/computed-offset-with-zoom_t01: Skip # co19 issue 732.
+LayoutTests/fast/css/content-language-case-insensitivity_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/content-language-dynamically-added_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/content-language-dynamically-removed_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/content-language-mapped-to-webkit-locale_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/content-language-multiple_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/content-language-no-content_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/content/content-none_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/content/content-normal_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/counters/complex-before_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/counters/counter-cssText_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/css-properties-case-insensitive_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/css3-nth-tokens-style_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/cssText-shorthand_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/csstext-of-content-string_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/cursor-parsing-quirks_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/deprecated-flexbox-auto-min-size_t01: Pass, RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/ex-unit-with-no-x-height_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/first-child-display-change-inverse_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/focus-display-block-inline_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/font-face-cache-bug_t01: RuntimeError # co19-roll r761: Please triage this failure.
@@ -202,9 +430,17 @@
 LayoutTests/fast/css/font-face-multiple-ranges-for-unicode-range_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css/font-face-unicode-range-load_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/font-face-unicode-range-overlap-load_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/font-shorthand-from-longhands_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/fontfaceset-events_t01: Pass, RuntimeError # Issue 23433
 LayoutTests/fast/css/fontfaceset-loadingdone_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/getComputedStyle/computed-style-font_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/getComputedStyle/computed-style-properties_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/getComputedStyle/counterIncrement-without-counter_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/getPropertyValue-columns_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/html-attr-case-sensitivity_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/id-or-class-before-stylesheet_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/image-set-setting_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/important-js-override_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/inherit-initial-shorthand-values_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/invalid-predefined-color_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/link-alternate-stylesheet-1_t01: RuntimeError # co19-roll r761: Please triage this failure.
@@ -213,24 +449,32 @@
 LayoutTests/fast/css/link-alternate-stylesheet-4_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/link-alternate-stylesheet-5_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/media-query-recovery_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/nested-at-rules_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/parse-color-int-or-percent-crash_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/parsing-at-rule-recovery_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/parsing-css-allowed-string-characters_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/css/parsing-css-nth-child_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/parsing-page-rule_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/parsing-selector-error-recovery_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/parsing-text-rendering_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/pseudo-any_t01: RuntimeError, Pass # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/pseudo-target-indirect-sibling-001_t01: Skip # Times out. co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/pseudo-target-indirect-sibling-002_t01: Skip # Times out. co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/pseudo-valid-unapplied_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/readonly-pseudoclass-opera-001_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/readonly-pseudoclass-opera-002_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/readonly-pseudoclass-opera-003_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/readonly-pseudoclass-opera-004_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/readonly-pseudoclass-opera-005_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/sticky/parsing-position-sticky_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/string-quote-binary_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/style-element-process-crash_t01: Skip # Times out. co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/style-scoped/style-scoped-nested_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css/style-scoped/style-scoped-with-dom-operation_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css/style-scoped/style-scoped-with-important-rule_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css/stylesheet-enable-first-alternate-on-load-sheet_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css/stylesheet-enable-second-alternate-link_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/css/transform-origin-parsing_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/css/webkit-keyframes-errors_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last-inherited_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last_t01: RuntimeError # co19-roll r786: Please triage this failure.
@@ -241,7 +485,6 @@
 LayoutTests/fast/css3-text/css3-text-indent/getComputedStyle/getComputedStyle-text-indent-inherited_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css3-text/css3-text-indent/getComputedStyle/getComputedStyle-text-indent_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/css3-text/css3-text-justify/getComputedStyle/getComputedStyle-text-justify_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/dom/52776_t01: RuntimeError # Please triage this failure.
 LayoutTests/fast/dom/DOMImplementation/createDocument-namespace-err_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LayoutTests/fast/dom/Document/CaretRangeFromPoint/basic_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LayoutTests/fast/dom/Document/CaretRangeFromPoint/caretRangeFromPoint-in-strict-mode-wtih-checkbox_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
@@ -265,7 +508,6 @@
 LayoutTests/fast/dom/HTMLDialogElement/dialog-scrolled-viewport_t01: RuntimeError # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/HTMLDialogElement/dialog-show-modal_t01: RuntimeError, Pass # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/HTMLDialogElement/inert-node-is-unfocusable_t01: RuntimeError # co19-roll r722: Please triage this failure.
-LayoutTests/fast/dom/HTMLDialogElement/inert-node-is-unselectable_t01: RuntimeError # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/HTMLDialogElement/multiple-centered-dialogs_t01: RuntimeError # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/HTMLDialogElement/non-anchored-dialog-positioning_t01: RuntimeError # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/HTMLDialogElement/show-modal-focusing-steps_t01: RuntimeError # co19-roll r722: Please triage this failure.
@@ -285,7 +527,6 @@
 LayoutTests/fast/dom/HTMLLinkElement/resolve-url-on-insertion_t01: RuntimeError # co19-roll r722: Issue 18010
 LayoutTests/fast/dom/HTMLObjectElement/beforeload-set-text-crash_t01: Skip # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/HTMLOptionElement/collection-setter-getter_t01: RuntimeError # co19-roll r722: Please triage this failure.
-LayoutTests/fast/dom/HTMLOutputElement/dom-settable-token-list_t01: RuntimeError # Issue 18931
 LayoutTests/fast/dom/HTMLScriptElement/async-false-inside-async-false-load_t01: RuntimeError # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/HTMLScriptElement/async-inline-script_t01: RuntimeError # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/HTMLScriptElement/async-onbeforeload_t01: RuntimeError # co19-roll r722: Please triage this failure.
@@ -303,40 +544,43 @@
 LayoutTests/fast/dom/Node/fragment-mutation_t01: RuntimeError # Please triage this failure.
 LayoutTests/fast/dom/Node/initial-values_t01: RuntimeError # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/Range/bug-19527_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/insertNode-empty-fragment-crash_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/mutation_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/range-constructor_t01: RuntimeError # Please triage this failure.
 LayoutTests/fast/dom/Range/range-created-during-remove-children_t01: RuntimeError, Pass # co19-roll r722: Please triage this failure.
 LayoutTests/fast/dom/Range/range-detached-exceptions_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/range-expand_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/range-insertNode-separate-endContainer_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/Range/range-insertNode-splittext_t01: RuntimeError # Please triage this failure.
+LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Dartium JSInterop failure
 LayoutTests/fast/dom/StyleSheet/discarded-sheet-owner-null_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/dom/Window/window-resize-contents_t01: Pass, RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/Window/window-resize_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/Window/window-scroll-arguments_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/anchor-without-content_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/attribute-namespaces-get-set_t01: RuntimeError # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/background-shorthand-csstext_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/dom/blur-contenteditable_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/css-cached-import-rule_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/dom/css-innerHTML_t01: RuntimeError # Test is incorrect.
+LayoutTests/fast/dom/css-selectorText_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/dom/cssTarget-crash_t01: Skip # Test reloads itself. Issue 18558.
+LayoutTests/fast/dom/custom/document-register-basic_t01: RuntimeError # Bad test can't register HtmlElement.
 LayoutTests/fast/dom/custom/document-register-svg-extends_t01: RuntimeError # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/custom/element-names_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/dom/dataset-xhtml_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/dataset_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/document-importNode-arguments_t01: RuntimeError # Please triage this failure.
 LayoutTests/fast/dom/empty-hash-and-search_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/dom/focus-contenteditable_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/fragment-activation-focuses-target_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/dom/getElementsByClassName/011_t01: RuntimeError # Chrome 39 roll. Please triage this failure
 LayoutTests/fast/dom/horizontal-scrollbar-in-rtl-doesnt-fire-onscroll_t01: RuntimeError # co19-roll r738: Please triage this failure.
-LayoutTests/fast/dom/horizontal-scrollbar-in-rtl_t01: RuntimeError # Please triage this failure.
 LayoutTests/fast/dom/horizontal-scrollbar-when-dir-change_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/location-hash_t01: Pass, RuntimeError # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/navigatorcontentutils/is-protocol-handler-registered_t01: RuntimeError # Dartium JSInterop failure
+LayoutTests/fast/dom/navigatorcontentutils/unregister-protocol-handler_t01: RuntimeError # Dartium JSInterop failure
 LayoutTests/fast/dom/option-properties_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/partial-layout-overlay-scrollbars_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/set-innerHTML_t01: RuntimeError # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/shadow/content-reprojection-fallback-crash_t01: RuntimeError # Dartium 45 roll. Issue 25754
+LayoutTests/fast/dom/shadow/event-path_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/dom/shadow/form-in-shadow_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/dom/shadow/no-renderers-for-light-children_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/shadow/pseudoclass-update-checked-option_t01: RuntimeError # co19-roll r738: Please triage this failure.
@@ -345,7 +589,9 @@
 LayoutTests/fast/dom/shadow/pseudoclass-update-enabled-optgroup_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/shadow/pseudoclass-update-enabled-option_t01: RuntimeError # co19-roll r738: Please triage this failure.
 LayoutTests/fast/dom/shadow/shadow-content-crash_t01: RuntimeError # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/shadow/shadow-disable_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/dom/shadow/shadow-removechild-and-blur-event_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
+LayoutTests/fast/dom/shadow/shadow-root-js-api_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/dynamic/crash-generated-counter_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/dynamic/crash-generated-image_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/dynamic/crash-generated-quote_t01: RuntimeError # co19-roll r786: Please triage this failure.
@@ -353,9 +599,12 @@
 LayoutTests/fast/dynamic/insertAdjacentElement_t01: Skip # Timeout. co19-roll r786: Please triage this failure.
 LayoutTests/fast/dynamic/insertAdjacentHTML_t01: Pass, RuntimeError # co19 issue 11.
 LayoutTests/fast/dynamic/recursive-layout_t01: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/encoding/css-charset-dom_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/events/add-event-without-document_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/events/change-overflow-on-overflow-change_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/events/change-overflow-on-overflow-change_t01: Timeout # Dartium 45 roll. Issue 25754
 LayoutTests/fast/events/clipboard-clearData_t01: Skip # Timeout. co19-roll r786: Please triage this failure.
+LayoutTests/fast/events/clipboard-dataTransferItemList-remove_t01: RuntimeError # Issue 22532
 LayoutTests/fast/events/clipboard-dataTransferItemList_t01: Skip # Timeout. co19-roll r786: Please triage this failure.
 LayoutTests/fast/events/div-focus_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/events/document-elementFromPoint_t01: RuntimeError # co19-roll r786: Please triage this failure.
@@ -370,12 +619,14 @@
 LayoutTests/fast/events/mutation-during-replace-child-2_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/events/mutation-during-replace-child_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/events/nested-event-remove-node-crash_t01: Skip # Flaky timeout. co19-roll r786: Please triage this failure.
+LayoutTests/fast/events/overflowchanged-event-raf-timing_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/events/scoped/editing-commands_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/events/scroll-event-does-not-bubble_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/events/tabindex-removal-from-focused-element_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/exclusions/parsing/parsing-wrap-flow_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/exclusions/parsing/parsing-wrap-through_t01: RuntimeError # co19-roll r786: Please triage this failure.
 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/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.
@@ -391,6 +642,7 @@
 LayoutTests/fast/filesystem/read-directory-many_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/filesystem/simple-readonly_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/HTMLOptionElement_selected2_t01: Skip # Times out. co19-roll r801: Please triage this failure.
+LayoutTests/fast/forms/ValidityState-customError_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/forms/autofocus-focus-only-once_t01: Skip # Times out. co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/autofocus-input-css-style-change_t01: Skip # Times out. co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/autofocus-opera-007_t01: Skip # Times out. co19-roll r801: Please triage this failure.
@@ -402,6 +654,7 @@
 LayoutTests/fast/forms/date-multiple-fields/date-multiple-fields-onblur-setvalue-onfocusremoved_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/datetimelocal-multiple-fields/datetimelocal-multiple-fields-change-layout-by-value_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/datetimelocal/datetimelocal-interactive-validation-required_t01: Skip # Test reloads itself. Issue 18558.
+LayoutTests/fast/forms/file/file-input-capture_t01: RuntimeError # Experimental feature not exposed in Chrome yet
 LayoutTests/fast/forms/focus-style-pending_t01: Skip # Times out. co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/focus_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/form-submission-create-crash_t01: Skip # Test reloads itself. Issue 18558.
@@ -412,6 +665,8 @@
 LayoutTests/fast/forms/formmethod-attribute-input-html_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/forms/input-appearance-elementFromPoint_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/input-hit-test-border_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/forms/input-inputmode_t01: RuntimeError # Experimental feature not exposed in Chrome yet
+LayoutTests/fast/forms/input-value-sanitization_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/forms/input-width-height-attributes-without-renderer-loaded-image_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/listbox-select-all_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/listbox-selection-2_t01: RuntimeError # co19-roll r801: Please triage this failure.
@@ -433,9 +688,11 @@
 LayoutTests/fast/forms/submit-form-with-dirname-attribute_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/forms/submit-nil-value-field-assert_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/submit-nil-value-field-assert_t01: Skip # Test reloads itself. Issue 18558.
+LayoutTests/fast/forms/textarea-paste-newline_t01: Pass, RuntimeError # Issue 23433
 LayoutTests/fast/forms/textarea-scrollbar-height_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/forms/textarea-submit-crash_t01: Skip # Test reloads itself. Issue 18558.
 LayoutTests/fast/forms/textfield-focus-out_t01: Skip # Times out. co19-roll r801: Please triage this failure.
+LayoutTests/fast/forms/validationMessage_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/html/adjacent-html-context-element_t01:RuntimeError # co19 issue 11.
 LayoutTests/fast/html/hidden-attr_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LayoutTests/fast/html/imports/import-element-removed-flag_t01: RuntimeError # co19-roll r706.  Please triage this failure.
@@ -456,6 +713,7 @@
 LayoutTests/fast/inline/positioned-element-padding-contributes-width_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/inline/reattach-inlines-in-anonymous-blocks-with-out-of-flow-siblings_t01: RuntimeError # co19 issue 11.
 LayoutTests/fast/innerHTML/innerHTML-special-elements_t01: RuntimeError # co19 issue 11.
+LayoutTests/fast/innerHTML/javascript-url_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/layers/normal-flow-hit-test_t01: RuntimeError # co19 issue 11.
 LayoutTests/fast/layers/normal-flow-hit-test_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/layers/zindex-hit-test_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
@@ -468,6 +726,7 @@
 LayoutTests/fast/loader/hashchange-event-properties_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/loader/loadInProgress_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/loader/onhashchange-attribute-listeners_t01: Skip # Times out. co19-roll r801: Please triage this failure.
+LayoutTests/fast/loader/onload-policy-ignore-for-frame_t01: Timeout # Dartium 45 roll. Issue 25754
 LayoutTests/fast/loader/scroll-position-restored-on-back_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/loader/scroll-position-restored-on-reload-at-load-event_t01: Skip # Times out. co19-roll r801: Please triage this failure.
 LayoutTests/fast/loader/stateobjects/replacestate-in-onunload_t01: RuntimeError # co19-roll r801: Please triage this failure.
@@ -479,13 +738,12 @@
 LayoutTests/fast/mediastream/RTCPeerConnection-AddRemoveStream_t01: Skip # Issue 22111
 LayoutTests/fast/mediastream/RTCPeerConnection-AddRemoveStream_t01: Skip # Passes on Safari, Issue 23475 # co19 issue 11.
 LayoutTests/fast/mediastream/getusermedia_t01: Skip # co19 issue 738
-LayoutTests/fast/multicol/balance-short-trailing-empty-block_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/multicol/balance-trailing-border_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/multicol/balance-trailing-border_t02: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/multicol/balance-unbreakable_t01: Pass, RuntimeError # co19 issue 11.
 LayoutTests/fast/multicol/break-after-always-bottom-margin_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/multicol/break-properties_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/multicol/column-width-zero_t01: Pass, RuntimeError # co19 issue 11.
+LayoutTests/fast/multicol/columns-shorthand-parsing_t02: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/multicol/cssom-view_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/multicol/fixed-column-percent-logical-height-orthogonal-writing-mode_t01: RuntimeError # co19 issue 11.
 LayoutTests/fast/multicol/flipped-blocks-hit-test_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
@@ -524,7 +782,6 @@
 LayoutTests/fast/multicol/vertical-rl/image-inside-nested-blocks-with-border_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/multicol/widows_t01: Pass, RuntimeError # co19 issue 11.
 LayoutTests/fast/multicol/widows_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/multicol/widows_t02: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/multicol/zeroColumnCount_t01: RuntimeError # co19 issue 11.
 LayoutTests/fast/overflow/child-100percent-height-inside-fixed-container-with-overflow-auto_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/overflow/child-100percent-height-inside-fixed-container-with-overflow-auto_t01: RuntimeError # co19 issue 11.
@@ -547,9 +804,12 @@
 LayoutTests/fast/replaced/computed-image-width-with-percent-height-inside-table-cell-and-fixed-ancestor_t01: RuntimeError, Pass # Spurious intermittent pass # co19 issue 11.
 LayoutTests/fast/replaced/container-width-zero_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/replaced/iframe-with-percentage-height-within-table-with-anonymous-table-cell_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
+LayoutTests/fast/replaced/iframe-with-percentage-height-within-table-with-anonymous-table-cell_t01: RuntimeError # Dartium 45 roll. Issue 25754
 LayoutTests/fast/replaced/iframe-with-percentage-height-within-table-with-anonymous-table-cell_t01: RuntimeError, Pass # Spurious intermittent pass. # co19 issue 11.
+LayoutTests/fast/replaced/iframe-with-percentage-height-within-table-with-anonymous-table-cell_t01: Timeout # Dartium 45 roll. Issue 25754
 LayoutTests/fast/replaced/iframe-with-percentage-height-within-table-with-table-cell-ignore-height_t01: RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/replaced/iframe-with-percentage-height-within-table-with-table-cell-ignore-height_t01: RuntimeError, Pass # Spurious intermittent pass # co19 issue 11.
+LayoutTests/fast/replaced/iframe-with-percentage-height-within-table-with-table-cell-ignore-height_t01: Timeout # Dartium 45 roll. Issue 25754
 LayoutTests/fast/replaced/preferred-widths_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
 LayoutTests/fast/replaced/table-percent-height-text-controls_t01: RuntimeError # co19 issue 11.
 LayoutTests/fast/replaced/table-percent-height_t01: RuntimeError # co19-roll r801: Please triage this failure.
@@ -636,7 +896,6 @@
 LayoutTests/fast/text/font-ligatures-linebreak-word_t01: Skip # co19 issue 11.
 LayoutTests/fast/text/font-ligatures-linebreak_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/text/glyph-reordering_t01: Pass, RuntimeError # This is a false pass. The font gets sanitized, so whether it works or not probably depends on default sizes. # co19 issue 11.
-LayoutTests/fast/text/international/cjk-segmentation_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/text/international/complex-text-rectangle_t01: Skip # co19 issue 732.
 LayoutTests/fast/text/international/iso-8859-8_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/text/international/listbox-width-rtl_t01: RuntimeError # co19 issue 11.
@@ -716,14 +975,17 @@
 LayoutTests/fast/xpath/4XPath/Core/test_core_functions_t02: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/xpath/4XPath/Core/test_node_test_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/xpath/4XPath/Core/test_node_test_t02: RuntimeError # co19-roll r786: Please triage this failure.
+LayoutTests/fast/xpath/4XPath/Core/test_parser_t01: RuntimeError # Dartium JSInterop failure
 LayoutTests/fast/xpath/ambiguous-operators_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/xpath/attr-namespace_t01: RuntimeError # Dartium JsInterop failure
 LayoutTests/fast/xpath/attr-namespace_t02: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/xpath/ensure-null-namespace_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/xpath/implicit-node-args_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/xpath/invalid-resolver_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/xpath/node-name-case-sensitivity_t01: RuntimeError # co19-roll r761: Please triage this failure.
 LayoutTests/fast/xpath/node-name-case-sensitivity_t02: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/xpath/position_t01: RuntimeError # co19-roll r761: Please triage this failure.
+LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Dartium JSInterop failure
+LayoutTests/fast/xpath/py-dom-xpath/axes_t01: RuntimeError # Dartium JSInterop failure
 LayoutTests/fast/xpath/py-dom-xpath/data_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/xpath/py-dom-xpath/expressions_t01: RuntimeError # co19-roll r786: Please triage this failure.
 LayoutTests/fast/xpath/py-dom-xpath/paths_t01: RuntimeError # co19-roll r786: Please triage this failure.
@@ -735,7 +997,15 @@
 LibTest/collection/ListBase/ListBase_class_A01_t01: Skip # co19-roll r722: Please triage this failure.
 LibTest/collection/ListMixin/ListMixin_class_A01_t01: Skip # co19-roll r722: Please triage this failure.
 LibTest/collection/ListMixin/ListMixin_class_A01_t02: Skip # co19-roll r722: Please triage this failure.
+LibTest/core/DateTime/parse_A01_t02: Skip # Times out. Please triage this failure.
+LibTest/core/DateTime/parse_A03_t01: fail # Issue 12514
+LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t01: Fail # Issue 22200
+LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t05: Fail # Issue 22200
+LibTest/core/RegExp/Pattern_semantics/firstMatch_NonEmptyClassRanges_A01_t06: Fail # Issue 22200
+LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # Issue 13596
+LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # Issue 13596
 LibTest/core/int/operator_left_shift_A01_t02: Pass, Fail # Please triage this failure.
+LibTest/core/int/toRadixString_A01_t01: Fail # co19 issue 492
 LibTest/html/CanvasRenderingContext2D/addEventListener_A01_t03: RuntimeError # co19-roll r722: Please triage this failure.
 LibTest/html/CanvasRenderingContext2D/addEventListener_A01_t06: RuntimeError # co19-roll r722: Please triage this failure.
 LibTest/html/Document/childNodes_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
@@ -749,7 +1019,6 @@
 LibTest/html/Element/focus_A01_t01: Skip # co19-roll r706.  Please triage this failure.
 LibTest/html/Element/getAttributeNS_A01_t01: RuntimeError # co19-roll r706.  Issue 16395
 LibTest/html/Element/getAttributeNS_A01_t02: RuntimeError # Please triage this failure.
-LibTest/html/Element/getClientRects_A01_t02: RuntimeError # co19-roll r706.  Issue 16575
 LibTest/html/Element/getNamespacedAttributes_A01_t01: RuntimeError # co19-roll r706.  Issue 16395
 LibTest/html/Element/isContentEditable_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/Element/isContentEditable_A02_t01: RuntimeError # co19-roll r706.  Please triage this failure.
@@ -766,6 +1035,7 @@
 LibTest/html/HttpRequestUpload/onLoadEnd_A01_t01: Skip # co19-roll r706.  Please triage this failure.
 LibTest/html/HttpRequestUpload/onLoadStart_A01_t01: Skip # co19-roll r706.  Please triage this failure.
 LibTest/html/HttpRequestUpload/onLoad_A01_t01: Skip # co19-roll r706.  Please triage this failure.
+LibTest/html/IFrameElement/IFrameElement.created_A01_t01: RuntimeError # Issue 24568
 LibTest/html/IFrameElement/appendHtml_A01_t01: Pass, RuntimeError # Issue 23462
 LibTest/html/IFrameElement/appendHtml_A01_t01: RuntimeError # Issue 23462
 LibTest/html/IFrameElement/appendHtml_A01_t02: Pass, RuntimeError # Issue 23462
@@ -781,7 +1051,6 @@
 LibTest/html/IFrameElement/createShadowRoot_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/IFrameElement/enteredView_A01_t01: Skip # co19-roll r706.  Please triage this failure.
 LibTest/html/IFrameElement/focus_A01_t01: Skip # co19-roll r706.  Please triage this failure.
-LibTest/html/IFrameElement/getClientRects_A01_t02: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/IFrameElement/getNamespacedAttributes_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/IFrameElement/innerHtml_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/IFrameElement/isContentEditable_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
@@ -798,7 +1067,7 @@
 LibTest/html/Node/nodes_A01_t02: RuntimeError # co19-roll r722: Please triage this failure.
 LibTest/html/Node/parent_A01_t01: RuntimeError # co19-roll r722: Please triage this failure.
 LibTest/html/Node/previousNode_A01_t01: RuntimeError # co19-roll r722: Please triage this failure.
-LibTest/html/Window/close_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
+LibTest/html/Window/document_A01_t01: Skip # accesses window.document from a cross-frame window
 LibTest/html/Window/find_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/find_A03_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/find_A06_t01: RuntimeError # co19-roll r706.  Please triage this failure.
@@ -806,6 +1075,7 @@
 LibTest/html/Window/moveTo_A02_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/postMessage_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/requestFileSystem_A01_t02: RuntimeError,Pass # co19-roll r722: Please triage this failure.
+LibTest/html/Window/requestFileSystem_A02_t01: Skip # Issue 24585.
 LibTest/html/Window/resizeBy_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/html/Window/resizeTo_A01_t01: RuntimeError # co19-roll r706.  Please triage this failure.
 LibTest/isolate/Isolate/spawnUri_A01_t01: RuntimeError # Dart issue 15974
@@ -814,12 +1084,15 @@
 LibTest/isolate/Isolate/spawnUri_A01_t04: RuntimeError # Dart issue 15974
 LibTest/isolate/Isolate/spawnUri_A01_t05: RuntimeError # Dart issue 15974
 LibTest/isolate/Isolate/spawnUri_A02_t01: RuntimeError # Dart issue 15974
+LibTest/isolate/Isolate/spawnUri_A02_t02: Skip # Dart issue 15974
+LibTest/isolate/Isolate/spawnUri_A02_t03: Skip # Dart issue 15974
 LibTest/isolate/Isolate/spawnUri_A02_t04: Skip # Dart issue 15974
 LibTest/isolate/Isolate/spawn_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/Isolate/spawn_A01_t02: RuntimeError, OK  # Uses Isolate.spawn.
-LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/Isolate/spawn_A01_t03: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/Isolate/spawn_A01_t04: RuntimeError, OK  # Uses Isolate.spawn.
+LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError, OK  # Uses Isolate.spawn.
+LibTest/isolate/Isolate/spawn_A02_t02: RuntimeError # Dart issue 15617
 LibTest/isolate/RawReceivePort/RawReceivePort_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/RawReceivePort/RawReceivePort_A01_t02: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/RawReceivePort/close_A01_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
@@ -828,11 +1101,18 @@
 LibTest/isolate/ReceivePort/any_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/any_A01_t02: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/asBroadcastStream_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
+LibTest/isolate/ReceivePort/asBroadcastStream_A01_t02: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
 LibTest/isolate/ReceivePort/asBroadcastStream_A01_t03: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/asBroadcastStream_A01_t04: RuntimeError, OK  # Uses Isolate.spawn.
+LibTest/isolate/ReceivePort/asBroadcastStream_A02_t01: RuntimeError # Issue 13921
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t02: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t03: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
 LibTest/isolate/ReceivePort/asBroadcastStream_A04_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/asBroadcastStream_A04_t02: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/asBroadcastStream_A04_t03: RuntimeError, OK  # Uses Isolate.spawn.
+LibTest/isolate/ReceivePort/close_A01_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/close_A02_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
 LibTest/isolate/ReceivePort/contains_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/distinct_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/distinct_A01_t02: RuntimeError, OK  # Uses Isolate.spawn.
@@ -865,6 +1145,7 @@
 LibTest/isolate/ReceivePort/reduce_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/reduce_A01_t02: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/reduce_A01_t03: RuntimeError, OK  # Uses Isolate.spawn.
+LibTest/isolate/ReceivePort/sendPort_A01_t01: RuntimeError # Issue 13921
 LibTest/isolate/ReceivePort/singleWhere_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/singleWhere_A02_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/single_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
@@ -881,14 +1162,6 @@
 LibTest/isolate/ReceivePort/transform_A01_t02: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/where_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/ReceivePort/where_A01_t02: RuntimeError, OK  # Uses Isolate.spawn.
-LibTest/isolate/ReceivePort/asBroadcastStream_A01_t02: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
-LibTest/isolate/ReceivePort/asBroadcastStream_A02_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t02: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t03: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
-LibTest/isolate/ReceivePort/close_A01_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
-LibTest/isolate/ReceivePort/close_A02_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
-LibTest/isolate/ReceivePort/sendPort_A01_t01: RuntimeError # Issue 13921
 LibTest/isolate/SendPort/send_A01_t01: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/SendPort/send_A01_t02: RuntimeError, OK  # Uses Isolate.spawn.
 LibTest/isolate/SendPort/send_A01_t03: RuntimeError, OK  # Uses Isolate.spawn.
@@ -945,6 +1218,7 @@
 WebPlatformTest/html-templates/parsing-html-templates/creating-an-element-for-the-token/template-owner-document_t01: RuntimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/html/browsers/browsing-the-web/read-media/pageload-image_t01: RuntimeError # co19-roll r738: Please triage this failure.
 WebPlatformTest/html/browsers/browsing-the-web/read-media/pageload-video_t01: RuntimeError # co19-roll r738: Please triage this failure.
+WebPlatformTest/html/browsers/browsing-the-web/read-text/load-text-plain_t01: Skip # accesses window.document from a cross-frame window
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.body-getter_t01: RuntimeError # co19-roll r738: Please triage this failure.
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.body-setter_t01: RuntimeError # co19-roll r738: Please triage this failure.
 WebPlatformTest/html/dom/documents/dom-tree-accessors/document.getElementsByName-case_t01: RuntimeError # co19 issue 11.
@@ -970,6 +1244,7 @@
 WebPlatformTest/html/semantics/embedded-content/media-elements/interfaces/TextTrack/mode_t01: RuntimeError # co19-roll r738: Please triage this failure.
 WebPlatformTest/html/semantics/forms/attributes-common-to-form-controls/formAction_document_address_t01: RuntimeError # co19-roll r738: Please triage this failure.
 WebPlatformTest/html/semantics/forms/attributes-common-to-form-controls/formaction_t01: RuntimeError # co19-roll r738: Please triage this failure.
+WebPlatformTest/html/semantics/forms/textfieldselection/selection_t01: RuntimeError # Dartium 45 roll. Issue 25754
 WebPlatformTest/html/semantics/forms/textfieldselection/textfieldselection-setRangeText_t01: RuntimeError # co19-roll r738: Please triage this failure.
 WebPlatformTest/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.  Pass on macos.
 WebPlatformTest/html/semantics/forms/the-button-element/button-validation_t01: RuntimeError # co19-roll r738: Please triage this failure.
@@ -1038,8 +1313,11 @@
 WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-element-interface/attributes/test-004_t01: RuntimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-element-interface/attributes/test-004_t02: RuntimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-element-interface/methods/elements-001_t01: RuntimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/shadow-dom/elements-and-dom-objects/extensions-to-event-interface/event-path-001_t01: RuntimeError # Dartium 45 roll. Issue 25754
 WebPlatformTest/shadow-dom/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-005_t01: RuntimeError # Please triage this failure.
 WebPlatformTest/shadow-dom/elements-and-dom-objects/shadowroot-object/shadowroot-attributes/test-006_t01: RuntimeError # Please triage this failure.
+WebPlatformTest/shadow-dom/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-002_t01: RuntimeError # Dartium 45 roll. Issue 25754
+WebPlatformTest/shadow-dom/elements-and-dom-objects/shadowroot-object/shadowroot-methods/test-005_t01: RuntimeError # Dartium 45 roll. Issue 25754
 WebPlatformTest/shadow-dom/elements-and-dom-objects/the-content-html-element/test-004_t01: RuntimeError # Please triage this failure.
 WebPlatformTest/shadow-dom/elements-and-dom-objects/the-content-html-element/test-004_t02: RuntimeError # Please triage this failure.
 WebPlatformTest/shadow-dom/elements-and-dom-objects/the-content-html-element/test-006_t01: RuntimeError # co19-roll r722: Please triage this failure.
@@ -1052,9 +1330,11 @@
 WebPlatformTest/shadow-dom/events/event-retargeting/test-001_t01: RuntimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/events/event-retargeting/test-002_t01: RuntimeError # Not clear that any of this works. Also suppressed in dart2js
 WebPlatformTest/shadow-dom/events/event-retargeting/test-004_t01: RuntimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t01: Pass, RuntimeError # Flaky with Dartium JsInterop. Seems like timing issues in the test.
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t02: Skip # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t05: Skip # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-001_t06: Skip # co19-roll r722: Please triage this failure.
+WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-002_t01: Pass, Fail # https://github.com/dart-lang/co19/issues/12
 WebPlatformTest/shadow-dom/events/retargeting-focus-events/test-003_t01: RuntimeError, Pass # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/events/retargeting-relatedtarget/test-003_t01: RuntimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/html-elements-and-their-shadow-trees/test-001_t01: RuntimeError # co19-roll r722: Please triage this failure.
@@ -1064,258 +1344,10 @@
 WebPlatformTest/shadow-dom/shadow-trees/distributed-pseudo-element/test-001_t01: RuntimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/shadow-trees/distributed-pseudo-element/test-002_t01: RuntimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/shadow-trees/lower-boundary-encapsulation/test-004_t01: RuntimeError # co19-roll r722: Please triage this failure.
+WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/dom-tree-accessors-002_t01: RuntimeError # Dartium 45 roll. Issue 25754
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/ownerdocument-002_t01: RuntimeError # co19-roll r722: Please triage this failure.
 WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/test-009_t01: RuntimeError # Please triage this failure.
 WebPlatformTest/webstorage/event_constructor_t01: RuntimeError # co19-roll r761: Please triage this failure.
 WebPlatformTest/webstorage/event_constructor_t02: RuntimeError # co19-roll r761: Please triage this failure.
-WebPlatformTest/webstorage/event_local_key_t01: RuntimeError # co19-roll r761: Please triage this failure.
-WebPlatformTest/webstorage/event_session_key_t01: RuntimeError # co19-roll r761: Please triage this failure.
 WebPlatformTest/webstorage/storage_local_setitem_quotaexceedederr_t01: Skip # Times out flakily. co19-roll r761: Please triage this failure.
 WebPlatformTest/webstorage/storage_session_setitem_quotaexceedederr_t01: Skip # Times out flakily. co19-roll r761: Please triage this failure.
-
-[ $compiler == none && ($runtime == dartium || $runtime == ContentShellOnAndroid ) && $checked ]
-Language/Errors_and_Warnings/static_warning_t01: RuntimeError # Please triage this failure.
-Language/Errors_and_Warnings/static_warning_t02: RuntimeError # Please triage this failure.
-Language/Errors_and_Warnings/static_warning_t03: RuntimeError # Please triage this failure.
-Language/Errors_and_Warnings/static_warning_t04: RuntimeError # Please triage this failure.
-Language/Errors_and_Warnings/static_warning_t05: RuntimeError # Please triage this failure.
-Language/Errors_and_Warnings/static_warning_t06: RuntimeError # Please triage this failure.
-LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/webgl/oes-vertex-array-object_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/webgl/read-pixels-test_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/css-tables_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-absolutes_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-blocks_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-column-flex-items_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-flex-items_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/intrinsic-sized-replaced-absolutes_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/multicol_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/tables_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/width-shrinks-avoid-floats_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/css/box-sizing-border-box-dynamic-padding-border-update_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/css/display-inline-block-scrollbar_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/css/fixed-width-intrinsic-width-excludes-scrollbars_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/dom/HTMLDialogElement/top-layer-position-relative_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/HTMLDialogElement/top-layer-position-static_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/HTMLLabelElement/form/test1_t01: RuntimeError # co19-roll r722: Please triage this failure.
-LayoutTests/fast/dom/HTMLTableElement/insert-row_t01: RuntimeError # co19-roll r722: Please triage this failure.
-LayoutTests/fast/dom/custom/type-extensions_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
-LayoutTests/fast/dom/shadow/shadowhost-keyframes_t01: RuntimeError, Pass # co19-roll r738: Please triage this failure.
-LayoutTests/fast/filesystem/file-writer-abort_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/file-writer-events_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-copy_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-get-entry_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-get-metadata_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-get-parent_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-move_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-read-directory_t01: Pass, RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-remove_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-restricted-chars_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-restricted-names_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/filesystem/op-restricted-unicode_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/flexbox/flexing-overflow-scroll-item_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/flexbox/intrinsic-min-width-applies-with-fixed-width_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/forms/select-list-box-mouse-focus_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/html/article-element_t01: RuntimeError # co19-roll r706.  Please triage this failure.
-LayoutTests/fast/html/aside-element_t01: RuntimeError # co19-roll r706.  Please triage this failure.
-LayoutTests/fast/inline/empty-inline-before-collapsed-space_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/innerHTML/innerHTML-svg-read_t01: RuntimeError, Pass # co19-roll r706.  Please triage this failure.
-LayoutTests/fast/lists/list-style-position-inside_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/lists/marker-preferred-margins_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/multicol/fixed-column-percent-logical-height-orthogonal-writing-mode_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/multicol/vertical-lr/image-inside-nested-blocks-with-border_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/replaced/available-height-for-content_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/replaced/computed-image-width-with-percent-height-and-fixed-ancestor-vertical-lr_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/replaced/computed-image-width-with-percent-height-and-fixed-ancestor_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/replaced/computed-image-width-with-percent-height-inside-table-cell-and-fixed-ancestor-vertical-lr_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/replaced/computed-image-width-with-percent-height-inside-table-cell-and-fixed-ancestor_t01: Pass, RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/shapes/parsing/parsing-shape-image-threshold_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/shapes/parsing/parsing-shape-margin_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/shapes/parsing/parsing-shape-outside_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/table/absolute-table-percent-lengths_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/css-table-width_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/fixed-table-layout-width-change_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/html-table-width-max-width-constrained_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/margins-flipped-text-direction_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/min-max-width-preferred-size_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/nested-tables-with-div-offset_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/switch-table-layout-dynamic-cells_t01: RuntimeError # co19 issue 11.
-LayoutTests/fast/table/switch-table-layout-dynamic-cells_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/switch-table-layout-multiple-section_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/switch-table-layout_t01: RuntimeError # co19 issue 11.
-LayoutTests/fast/table/switch-table-layout_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/table/table-width-exceeding-max-width_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/text/line-break-after-inline-latin1_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/url/trivial-segments_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/url/trivial_t01: RuntimeError # co19-roll r786: Please triage this failure.
-LayoutTests/fast/xpath/xpath-result-eventlistener-crash_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LibTest/html/Node/ownerDocument_A01_t01: RuntimeError # co19-roll r722: Issue 18251
-WebPlatformTest/DOMEvents/approved/Propagation.path.target.removed_t01: RuntimeError # co19-roll r738: Please triage this failure.
-WebPlatformTest/custom-elements/instantiating/createElementNS_A05_t01: RuntimeError # co19-roll r722: Please triage this failure.
-WebPlatformTest/custom-elements/instantiating/createElement_A05_t01: RuntimeError # co19-roll r722: Please triage this failure.
-WebPlatformTest/html-templates/parsing-html-templates/clearing-the-stack-back-to-a-given-context/clearing-stack-back-to-a-table-body-context_t01: RuntimeError # co19-roll r722: Please triage this failure.
-WebPlatformTest/html-templates/parsing-html-templates/clearing-the-stack-back-to-a-given-context/clearing-stack-back-to-a-table-context_t01: RuntimeError # co19-roll r722: Please triage this failure.
-WebPlatformTest/html-templates/parsing-html-templates/clearing-the-stack-back-to-a-given-context/clearing-stack-back-to-a-table-row-context_t01: RuntimeError # co19-roll r722: Please triage this failure.
-WebPlatformTest/html/dom/elements/global-attributes/dataset-enumeration_t01: RuntimeError # co19-roll r738: Please triage this failure.
-WebPlatformTest/html/semantics/forms/textfieldselection/selection_t01: RuntimeError # co19-roll r738: Please triage this failure.
-WebPlatformTest/shadow-dom/shadow-trees/upper-boundary-encapsulation/ownerdocument-001_t01: RuntimeError # co19-roll r722: Please triage this failure.
-
-[ $compiler == none && ($runtime == dartium || $runtime == ContentShellOnAndroid) && $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.
-
-[ $compiler == none && $runtime == ContentShellOnAndroid ]
-LayoutTests/fast/canvas/canvas-composite-text-alpha_t01: RuntimeError #  Please triage this failure.
-LayoutTests/fast/canvas/canvas-scale-drawImage-shadow_t01: RuntimeError, Pass #  Please triage this failure.
-LayoutTests/fast/canvas/canvas-scale-fillPath-shadow_t01: RuntimeError, Pass #  Please triage this failure.
-LayoutTests/fast/canvas/canvas-scale-fillRect-shadow_t01: Skip # Times out.  Please triage this failure.
-LayoutTests/fast/canvas/canvas-scale-shadowBlur_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-scale-strokePath-shadow_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-strokePath-alpha-shadow_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-strokePath-gradient-shadow_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-strokeRect-alpha-shadow_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-strokeRect-gradient-shadow_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-transforms-fillRect-shadow_t01: RuntimeError, Pass #  Please triage this failure.
-LayoutTests/fast/canvas/webgl/canvas-test_t01: RuntimeError, Pass #  Please triage this failure.
-LayoutTests/fast/canvas/webgl/webgl-large-texture_t01: Skip # Times out flakily.  Please triage this failure.
-LayoutTests/fast/css-generated-content/bug-106384_t01: Skip # Times out.  Please triage this failure.
-LayoutTests/fast/css-generated-content/empty-first-letter-with-columns-crash_t01: Skip # Times out.  Please triage this failure.
-LayoutTests/fast/css-generated-content/hit-test-generated-content_t01: RuntimeError #  Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/css-tables_t01: RuntimeError #  Please triage this failure.
-LayoutTests/fast/css-intrinsic-dimensions/tables_t01: RuntimeError #  Please triage this failure.
-LayoutTests/fast/css/getComputedStyle/computed-style-select-overflow_t01: RuntimeError #  Please triage this failure.
-LayoutTests/fast/css/vertical-align-length-copy-bug_t01: RuntimeError #  Please triage this failure.
-LayoutTests/fast/dom/HTMLElement/innerHTML-selection-crash_t01: Skip # Times out.  Please triage this failure.
-LayoutTests/fast/dom/HTMLLinkElement/prefetch-beforeload_t01: Pass, RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/jsDevicePixelRatio_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/partial-layout-non-overlay-scrollbars_t01: Pass, RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/partial-layout-overlay-scrollbars_t01: Pass, RuntimeError # Please triage this failure.
-LayoutTests/fast/dom/shadow/shadowdom-for-input-type-change_t01: RuntimeError # Please triage this failure.
-LayoutTests/fast/filesystem/file-writer-abort-continue_t01: Skip # Times out.  Please triage this failure.
-LayoutTests/fast/forms/activate-and-disabled-elements_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/forms/plaintext-mode-1_t01: RuntimeError # co19-roll r801: Please triage this failure.
-LayoutTests/fast/forms/selection-direction_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/forms/text-set-value-crash_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/forms/textarea-paste-newline_t01: RuntimeError # co19-roll r801 : Please triage this failure.
-LayoutTests/fast/inline/continuation-inlines-inserted-in-reverse-after-block_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/inline/fixed-pos-moves-with-abspos-inline-parent_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/inline/fixed-pos-moves-with-abspos-parent-relative-ancestor_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/inline/fixed-pos-moves-with-abspos-parent_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/inline/inline-relative-offset-boundingbox_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/inline/out-of-flow-objects-and-whitespace-after-empty-inline_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/inline/parent-inline-element-padding-contributes-width_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/layers/negative-scroll-positions_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/loader/loadInProgress_t01: Skip # Times out. Please triage this failure.
-LayoutTests/fast/table/table-rowspan-height-distribution-in-rows_t02: Skip # Times out. Please triage this failure.
-LayoutTests/fast/text-autosizing/text-removal_t01: RuntimeError #  Please triage this failure.
-LayoutTests/fast/text/international/listbox-width-rtl_t01: RuntimeError #  Please triage this failure.
-LayoutTests/fast/transforms/scrollIntoView-transformed_t01: RuntimeError #  Please triage this failure.
-LibTest/collection/ListBase/ListBase_class_A01_t02: Skip # Times out flakily. Issue 20956
-LibTest/core/DateTime/parse_A01_t02: Skip # Times out. Please triage this failure.
-LibTest/core/List/List_class_A01_t02: Skip # Times out flakily. Issue 20956
-LibTest/html/Element/getBoundingClientRect_A01_t02: RuntimeError # Issue 19127.
-LibTest/html/Window/animationFrame_A01_t01: Skip # Times out.  Please triage this failure.
-LibTest/math/log_A01_t01: Pass, Fail # co19 issue 44.
-
-[ $compiler == none && $runtime == dartium ]
-LayoutTests/fast/canvas/webgl/webgl-depth-texture_t01: RuntimeError # co19-roll r761: Please triage this failure.
-LayoutTests/fast/canvas/webgl/WebGLContextEvent_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/array-bounds-clamping_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/attrib-location-length-limits_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/buffer-bind-test_t01: 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 22026
-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-destroyed-crash_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/context-lost-restored_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/css-webkit-canvas-repaint_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/css-webkit-canvas_t01: 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/error-reporting_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/framebuffer-bindings-unaffected-on-resize_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/framebuffer-object-attachment_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/framebuffer-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/functions-returning-strings_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/get-active-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-bind-attrib-location-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-enable-enum-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-enum-tests_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-get-calls_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-getshadersource_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-getstring_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-pixelstorei_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/gl-teximage_t01: RuntimeError # Issue 22026
-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: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/glsl-conformance_t01: RuntimeError # Issue 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: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/invalid-passed-params_t01: RuntimeError # Issue 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/oes-element-index-uint_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/oes-vertex-array-object_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/point-size_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/program-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/read-pixels-pack-alignment_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/read-pixels-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/renderer-and-vendor-strings_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/shader-precision-format_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-array-buffer-view_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgb565_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgba4444_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas-rgba5551_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-canvas_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgb565_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba4444_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data-rgba5551_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-data_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgb565_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba4444_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image-rgba5551_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-and-uniform-binding-bugs_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-image-webgl_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-input-validation_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-sub-image-2d-bad-args_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-sub-image-2d_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/tex-sub-image-cube-maps_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/texImage2DImageDataTest_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/texImageTest_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/texture-active-bind_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/texture-bindings-uneffected-on-resize_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/texture-color-profile_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/texture-complete_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/texture-npot_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/texture-transparent-pixels-initialized_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/uniform-location-length-limits_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/uninitialized-test_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/viewport-unchanged-upon-resize_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-composite-modes-repaint_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-composite-modes_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-exceptions_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-large-texture_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-layer-update_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-specific_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-texture-binding-preserved_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-unprefixed-context-id_t01: RuntimeError # Issue 22026
-LayoutTests/fast/canvas/webgl/webgl-viewport-parameters-preserved_t01: RuntimeError # Issue 22026
-LayoutTests/fast/css/fontfaceset-events_t01: Pass, RuntimeError # Issue 23433
-LayoutTests/fast/events/clipboard-dataTransferItemList-remove_t01: RuntimeError # Issue 22532
-LayoutTests/fast/forms/textarea-paste-newline_t01: Pass, RuntimeError # Issue 23433
-LayoutTests/fast/canvas/canvas-currentTransform_t01: RuntimeError # Feature is behind a flag in Chrome
-LayoutTests/fast/files/blob-close-revoke_t01: RuntimeError # Experimental feature not exposed anywhere yet
-LayoutTests/fast/forms/file/file-input-capture_t01: RuntimeError # Experimental feature not exposed in Chrome yet
-LayoutTests/fast/forms/input-inputmode_t01: RuntimeError # Experimental feature not exposed in Chrome yet
-
-[ $compiler == none && ($runtime == dartium || $runtime == ContentShellOnAndroid) && $system != windows ]
-LayoutTests/fast/css/font-face-unicode-range-monospace_t01: RuntimeError # co19-roll r761: Please triage this failure.
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index a11b526..0fc268d 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -3,7 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 
-[ ($compiler == none || $compiler == precompiler) && (($runtime == vm || $runtime == dart_precompiled) || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 
 # Failures ok in tests below. VM moves super initializer to end of list.
 Language/Classes/Constructors/Generative_Constructors/execution_t03: Fail, OK
@@ -43,7 +43,7 @@
 LibTest/core/Symbol/Symbol_A01_t03: RuntimeError # Issue 13596
 LibTest/core/Symbol/Symbol_A01_t05: RuntimeError # Issue 13596
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 LibTest/typed_data/Float32x4/reciprocalSqrt_A01_t01: Pass, Fail # co19 issue 599
 LibTest/typed_data/Float32x4/reciprocal_A01_t01: Pass, Fail # co19 issue 599
 Language/Expressions/Instance_Creation/Const/abstract_class_t01: MissingCompileTimeError # Issue 22007
@@ -52,52 +52,52 @@
 Language/Libraries_and_Scripts/Imports/invalid_uri_t02: Fail
 Language/Libraries_and_Scripts/Exports/invalid_uri_t02: Fail
 Language/Libraries_and_Scripts/Parts/syntax_t06: Fail
-
-[ ($runtime == vm || $runtime == dart_precompiled) ]
 LibTest/math/MutableRectangle/MutableRectangle.fromPoints_A01_t01: Pass, RuntimeError # co19-roll r607: Please triage this failure
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && $mode == debug ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $mode == debug ]
 LibTest/core/List/List_class_A01_t02: Pass, Slow
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ($arch != x64 && $arch != simarm64) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && ($arch != x64 && $arch != simarm64 && $arch != arm64) ]
 LibTest/core/int/operator_left_shift_A01_t02: Fail # co19 issue 129
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && $arch == mips ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == mips ]
 LibTest/core/double/toInt_A01_t01: Fail
+
+[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ($arch == mips || $arch == arm64) ]
 # These tests take too much memory (300 MB) for our 1 GB test machine.
 # co19 issue 673. http://code.google.com/p/co19/issues/detail?id=673
 LibTest/core/List/List_class_A01_t02: Skip # co19 issue 673
 LibTest/collection/ListMixin/ListMixin_class_A01_t02: Skip # co19 issue 673
 LibTest/collection/ListBase/ListBase_class_A01_t02: Skip # co19 issue 673
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && $arch == mips && $mode == debug ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == mips && $mode == debug ]
 LibTest/isolate/Isolate/spawnUri_A01_t04: Crash, Pass # Issue 17440
 LibTest/isolate/Isolate/spawn_A01_t04: Crash, Pass # Issue 17440
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ($arch == simarm || $arch == simarmv5te || $arch == simmips || $arch == simarm64) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && ($arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simmips || $arch == simarm64) ]
 LibTest/core/Uri/Uri_A06_t03: Skip  # Timeout
 LibTest/collection/ListMixin/ListMixin_class_A01_t01: Skip  # Timeout
 LibTest/collection/ListBase/ListBase_class_A01_t01: Skip  # Timeout
 LibTest/collection/ListMixin/ListMixin_class_A01_t02: Skip  # Timeout
 LibTest/collection/ListBase/ListBase_class_A01_t02: Skip  # Timeout
 
-[ ($compiler == none || $compiler == precompiler) && $system == windows ]
+[ $system == windows ]
 LibTest/collection/ListMixin/ListMixin_class_A01_t02: Pass, Slow
 LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Slow
 
-[ ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 LibTest/isolate/Isolate/spawn_A02_t01: Skip # co19 issue 667
 LibTest/html/*: SkipByDesign # dart:html not supported on VM.
 LayoutTests/fast/*: SkipByDesign # DOM not supported on VM.
 WebPlatformTest/*: SkipByDesign # dart:html not supported on VM.
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug && $builder_tag == asan ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $mode == debug && $builder_tag == asan ]
 Language/Types/Interface_Types/subtype_t27: Skip  # Issue 21174.
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $arch == arm ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == arm ]
 LibTest/typed_data/Float32x4/operator_multiplication_A01_t01: Fail # Dart issue 24416
 
-[ ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 # co19 update Sep 29, 2015 (3ed795ea02e022ef19c77cf1b6095b7c8f5584d0)
 Language/Classes/Getters/type_object_t01: RuntimeError # Please triage this failure
 Language/Classes/Getters/type_object_t02: RuntimeError # Please triage this failure
@@ -135,10 +135,7 @@
 Language/Mixins/not_object_superclass_t01: MissingCompileTimeError # Please triage this failure
 Language/Mixins/reference_to_super_t01: MissingCompileTimeError # Please triage this failure
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug ]
-Language/Mixins/Mixin_Application/wrong_type_t02: Crash # Please triage this failure
-
-[ ($runtime == vm || $runtime == dart_precompiled) && $checked ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $checked ]
 Language/Errors_and_Warnings/static_warning_t01: RuntimeError # Please triage this failure
 Language/Errors_and_Warnings/static_warning_t02: RuntimeError # Please triage this failure
 Language/Errors_and_Warnings/static_warning_t03: RuntimeError # Please triage this failure
@@ -146,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
@@ -155,7 +153,26 @@
 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.
+LibTest/typed_data/Float32x4List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Float64List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Int16List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Int32List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Int64List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Int8List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Uint16List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Uint32List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Uint64List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Uint8ClampedList/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
+LibTest/typed_data/Uint8List/runtimeType_A01_t01: Fail,OK  # Expects exact type name.
diff --git a/tests/compiler/dart2js/class_set_test.dart b/tests/compiler/dart2js/class_set_test.dart
index d88745d..71fbd97 100644
--- a/tests/compiler/dart2js/class_set_test.dart
+++ b/tests/compiler/dart2js/class_set_test.dart
@@ -17,7 +17,14 @@
 import 'package:compiler/src/world.dart';
 
 void main() {
-  asyncTest(() => TypeEnvironment.create(r"""
+  asyncTest(() async {
+    await testIterators();
+    await testForEach();
+  });
+}
+
+testIterators() async {
+  var env = await TypeEnvironment.create(r"""
       ///        A
       ///       / \
       ///      B   C
@@ -42,305 +49,536 @@
         new G();
       }
       """,
-      useMockCompiler: false).then((env) {
-    World world = env.compiler.world;
+      useMockCompiler: false);
+  World world = env.compiler.world;
 
-    ClassElement A = env.getElement("A");
-    ClassElement B = env.getElement("B");
-    ClassElement C = env.getElement("C");
-    ClassElement D = env.getElement("D");
-    ClassElement E = env.getElement("E");
-    ClassElement F = env.getElement("F");
-    ClassElement G = env.getElement("G");
+  ClassElement A = env.getElement("A");
+  ClassElement B = env.getElement("B");
+  ClassElement C = env.getElement("C");
+  ClassElement D = env.getElement("D");
+  ClassElement E = env.getElement("E");
+  ClassElement F = env.getElement("F");
+  ClassElement G = env.getElement("G");
 
-    void checkClass(ClassElement cls,
-                    {bool directlyInstantiated: false,
-                     bool indirectlyInstantiated: false}) {
-      ClassHierarchyNode node = world.getClassHierarchyNode(cls);
-      Expect.isNotNull(node, "Expected ClassHierarchyNode for $cls.");
-      Expect.equals(
-          directlyInstantiated || indirectlyInstantiated,
-          node.isInstantiated,
-          "Unexpected `isInstantiated` on ClassHierarchyNode for $cls.");
-      Expect.equals(
-          directlyInstantiated,
-          node.isDirectlyInstantiated,
-          "Unexpected `isDirectlyInstantiated` on ClassHierarchyNode for "
-          "$cls.");
-      Expect.equals(
-          indirectlyInstantiated,
-          node.isIndirectlyInstantiated,
-          "Unexpected `isIndirectlyInstantiated` on ClassHierarchyNode for "
-          "$cls.");
+  void checkClass(ClassElement cls,
+                  {bool directlyInstantiated: false,
+                   bool indirectlyInstantiated: false}) {
+    ClassHierarchyNode node = world.getClassHierarchyNode(cls);
+    Expect.isNotNull(node, "Expected ClassHierarchyNode for $cls.");
+    Expect.equals(
+        directlyInstantiated || indirectlyInstantiated,
+        node.isInstantiated,
+        "Unexpected `isInstantiated` on ClassHierarchyNode for $cls.");
+    Expect.equals(
+        directlyInstantiated,
+        node.isDirectlyInstantiated,
+        "Unexpected `isDirectlyInstantiated` on ClassHierarchyNode for "
+        "$cls.");
+    Expect.equals(
+        indirectlyInstantiated,
+        node.isIndirectlyInstantiated,
+        "Unexpected `isIndirectlyInstantiated` on ClassHierarchyNode for "
+        "$cls.");
+  }
+
+
+  checkClass(A, directlyInstantiated: true, indirectlyInstantiated: true);
+  checkClass(B, indirectlyInstantiated: true);
+  checkClass(C, directlyInstantiated: true, indirectlyInstantiated: true);
+  checkClass(D, directlyInstantiated: true);
+  checkClass(E, directlyInstantiated: true);
+  checkClass(F, directlyInstantiated: true);
+  checkClass(G, directlyInstantiated: true);
+
+  ClassHierarchyNodeIterator iterator;
+
+  void checkState(
+      ClassElement root,
+      {ClassElement currentNode,
+       List<List<ClassElement>> stack}) {
+
+    ClassElement classOf(ClassHierarchyNode node) {
+      return node != null ? node.cls : null;
     }
 
-
-    checkClass(A, directlyInstantiated: true, indirectlyInstantiated: true);
-    checkClass(B, indirectlyInstantiated: true);
-    checkClass(C, directlyInstantiated: true, indirectlyInstantiated: true);
-    checkClass(D, directlyInstantiated: true);
-    checkClass(E, directlyInstantiated: true);
-    checkClass(F, directlyInstantiated: true);
-    checkClass(G, directlyInstantiated: true);
-
-    ClassHierarchyNodeIterator iterator;
-
-    void checkState(
-        ClassElement root,
-        {ClassElement currentNode,
-         List<List<ClassElement>> stack}) {
-
-      ClassElement classOf(ClassHierarchyNode node) {
-        return node != null ? node.cls : null;
-      }
-
-      List<ClassElement> classesOf(Link<ClassHierarchyNode> link) {
-        if (link == null) return null;
-        return link.map(classOf).toList();
-      }
-
-      ClassElement foundRoot = iterator.root.cls;
-      ClassElement foundCurrentNode = classOf(iterator.currentNode);
-      List<ClassElement> foundStack = classesOf(iterator.stack);
-
-      StringBuffer sb = new StringBuffer();
-      sb.write('{\n root: $foundRoot');
-      sb.write('\n currentNode: $foundCurrentNode');
-      sb.write('\n stack: $foundStack\n}');
-
-      Expect.equals(root, foundRoot,
-          "Expected root $root in $sb.");
-      if (currentNode == null) {
-        Expect.isNull(iterator.currentNode,
-            "Unexpected non-null currentNode in $sb.");
-      } else {
-        Expect.isNotNull(foundCurrentNode,
-            "Expected non-null currentNode ${currentNode} in $sb.");
-        Expect.equals(currentNode, foundCurrentNode,
-            "Expected currentNode $currentNode in $sb.");
-      }
-      if (stack == null) {
-        Expect.isNull(foundStack,
-            "Unexpected non-null stack in $sb.");
-      } else {
-        Expect.isNotNull(foundStack,
-            "Expected non-null stack ${stack} in $sb.");
-        Expect.listEquals(stack, foundStack,
-            "Expected stack ${stack}, "
-            "found ${foundStack} in $sb.");
-      }
+    List<ClassElement> classesOf(Link<ClassHierarchyNode> link) {
+      if (link == null) return null;
+      return link.map(classOf).toList();
     }
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(G),
-        ClassHierarchyNode.ALL).iterator;
-    checkState(G, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(G, currentNode: G, stack: []);
-    Expect.equals(G, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(G, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+    ClassElement foundRoot = iterator.root.cls;
+    ClassElement foundCurrentNode = classOf(iterator.currentNode);
+    List<ClassElement> foundStack = classesOf(iterator.stack);
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(G),
-        ClassHierarchyNode.ALL,
-        includeRoot: false).iterator;
-    checkState(G, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(G, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+    StringBuffer sb = new StringBuffer();
+    sb.write('{\n root: $foundRoot');
+    sb.write('\n currentNode: $foundCurrentNode');
+    sb.write('\n stack: $foundStack\n}');
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(C),
-        ClassHierarchyNode.ALL).iterator;
-    checkState(C, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(C, currentNode: C, stack: [E, F, G]);
-    Expect.equals(C, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(C, currentNode: E, stack: [F, G]);
-    Expect.equals(E, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(C, currentNode: F, stack: [G]);
-    Expect.equals(F, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(C, currentNode: G, stack: []);
-    Expect.equals(G, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(C, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+    Expect.equals(root, foundRoot,
+        "Expected root $root in $sb.");
+    if (currentNode == null) {
+      Expect.isNull(iterator.currentNode,
+          "Unexpected non-null currentNode in $sb.");
+    } else {
+      Expect.isNotNull(foundCurrentNode,
+          "Expected non-null currentNode ${currentNode} in $sb.");
+      Expect.equals(currentNode, foundCurrentNode,
+          "Expected currentNode $currentNode in $sb.");
+    }
+    if (stack == null) {
+      Expect.isNull(foundStack,
+          "Unexpected non-null stack in $sb.");
+    } else {
+      Expect.isNotNull(foundStack,
+          "Expected non-null stack ${stack} in $sb.");
+      Expect.listEquals(stack, foundStack,
+          "Expected stack ${stack}, "
+          "found ${foundStack} in $sb.");
+    }
+  }
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(D),
-        ClassHierarchyNode.ALL).iterator;
-    checkState(D, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(D, currentNode: D, stack: []);
-    Expect.equals(D, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(D, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(G),
+      ClassHierarchyNode.ALL).iterator;
+  checkState(G, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(G, currentNode: G, stack: []);
+  Expect.equals(G, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(G, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(B),
-        ClassHierarchyNode.ALL).iterator;
-    checkState(B, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(B, currentNode: B, stack: [D]);
-    Expect.equals(B, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(B, currentNode: D, stack: []);
-    Expect.equals(D, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(B, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(G),
+      ClassHierarchyNode.ALL,
+      includeRoot: false).iterator;
+  checkState(G, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(G, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(B),
-        ClassHierarchyNode.ALL,
-        includeRoot: false).iterator;
-    checkState(B, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(B, currentNode: D, stack: []);
-    Expect.equals(D, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(B, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(C),
+      ClassHierarchyNode.ALL).iterator;
+  checkState(C, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(C, currentNode: C, stack: [E, F, G]);
+  Expect.equals(C, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(C, currentNode: E, stack: [F, G]);
+  Expect.equals(E, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(C, currentNode: F, stack: [G]);
+  Expect.equals(F, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(C, currentNode: G, stack: []);
+  Expect.equals(G, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(C, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(B),
-        new EnumSet<Instantiation>.fromValues(<Instantiation>[
-            Instantiation.DIRECTLY_INSTANTIATED,
-            Instantiation.UNINSTANTIATED])).iterator;
-    checkState(B, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(B, currentNode: D, stack: []);
-    Expect.equals(D, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(B, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(D),
+      ClassHierarchyNode.ALL).iterator;
+  checkState(D, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(D, currentNode: D, stack: []);
+  Expect.equals(D, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(D, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(A),
-        ClassHierarchyNode.ALL).iterator;
-    checkState(A, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: A, stack: [C, B]);
-    Expect.equals(A, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: C, stack: [E, F, G, B]);
-    Expect.equals(C, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: E, stack: [F, G, B]);
-    Expect.equals(E, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: F, stack: [G, B]);
-    Expect.equals(F, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: G, stack: [B]);
-    Expect.equals(G, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: B, stack: [D]);
-    Expect.equals(B, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: D, stack: []);
-    Expect.equals(D, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(A, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(B),
+      ClassHierarchyNode.ALL).iterator;
+  checkState(B, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(B, currentNode: B, stack: [D]);
+  Expect.equals(B, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(B, currentNode: D, stack: []);
+  Expect.equals(D, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(B, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(A),
-        ClassHierarchyNode.ALL,
-        includeRoot: false).iterator;
-    checkState(A, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: C, stack: [E, F, G, B]);
-    Expect.equals(C, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: E, stack: [F, G, B]);
-    Expect.equals(E, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: F, stack: [G, B]);
-    Expect.equals(F, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: G, stack: [B]);
-    Expect.equals(G, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: B, stack: [D]);
-    Expect.equals(B, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: D, stack: []);
-    Expect.equals(D, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(A, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(B),
+      ClassHierarchyNode.ALL,
+      includeRoot: false).iterator;
+  checkState(B, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(B, currentNode: D, stack: []);
+  Expect.equals(D, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(B, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(A),
-        new EnumSet<Instantiation>.fromValues(<Instantiation>[
-            Instantiation.DIRECTLY_INSTANTIATED,
-            Instantiation.UNINSTANTIATED])).iterator;
-    checkState(A, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: A, stack: [C, B]);
-    Expect.equals(A, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: C, stack: [E, F, G, B]);
-    Expect.equals(C, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: E, stack: [F, G, B]);
-    Expect.equals(E, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: F, stack: [G, B]);
-    Expect.equals(F, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: G, stack: [B]);
-    Expect.equals(G, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: D, stack: []);
-    Expect.equals(D, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(A, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(B),
+      new EnumSet<Instantiation>.fromValues(<Instantiation>[
+          Instantiation.DIRECTLY_INSTANTIATED,
+          Instantiation.UNINSTANTIATED])).iterator;
+  checkState(B, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(B, currentNode: D, stack: []);
+  Expect.equals(D, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(B, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
 
-    iterator = new ClassHierarchyNodeIterable(
-        world.getClassHierarchyNode(A),
-        new EnumSet<Instantiation>.fromValues(<Instantiation>[
-            Instantiation.DIRECTLY_INSTANTIATED,
-            Instantiation.UNINSTANTIATED]),
-        includeRoot: false).iterator;
-    checkState(A, currentNode: null, stack: null);
-    Expect.isNull(iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: C, stack: [E, F, G, B]);
-    Expect.equals(C, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: E, stack: [F, G, B]);
-    Expect.equals(E, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: F, stack: [G, B]);
-    Expect.equals(F, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: G, stack: [B]);
-    Expect.equals(G, iterator.current);
-    Expect.isTrue(iterator.moveNext());
-    checkState(A, currentNode: D, stack: []);
-    Expect.equals(D, iterator.current);
-    Expect.isFalse(iterator.moveNext());
-    checkState(A, currentNode: null, stack: []);
-    Expect.isNull(iterator.current);
-  }));
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(A),
+      ClassHierarchyNode.ALL).iterator;
+  checkState(A, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: A, stack: [C, B]);
+  Expect.equals(A, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: C, stack: [E, F, G, B]);
+  Expect.equals(C, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: E, stack: [F, G, B]);
+  Expect.equals(E, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: F, stack: [G, B]);
+  Expect.equals(F, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: G, stack: [B]);
+  Expect.equals(G, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: B, stack: [D]);
+  Expect.equals(B, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: D, stack: []);
+  Expect.equals(D, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(A, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
+
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(A),
+      ClassHierarchyNode.ALL,
+      includeRoot: false).iterator;
+  checkState(A, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: C, stack: [E, F, G, B]);
+  Expect.equals(C, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: E, stack: [F, G, B]);
+  Expect.equals(E, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: F, stack: [G, B]);
+  Expect.equals(F, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: G, stack: [B]);
+  Expect.equals(G, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: B, stack: [D]);
+  Expect.equals(B, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: D, stack: []);
+  Expect.equals(D, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(A, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
+
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(A),
+      new EnumSet<Instantiation>.fromValues(<Instantiation>[
+          Instantiation.DIRECTLY_INSTANTIATED,
+          Instantiation.UNINSTANTIATED])).iterator;
+  checkState(A, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: A, stack: [C, B]);
+  Expect.equals(A, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: C, stack: [E, F, G, B]);
+  Expect.equals(C, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: E, stack: [F, G, B]);
+  Expect.equals(E, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: F, stack: [G, B]);
+  Expect.equals(F, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: G, stack: [B]);
+  Expect.equals(G, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: D, stack: []);
+  Expect.equals(D, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(A, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
+
+  iterator = new ClassHierarchyNodeIterable(
+      world.getClassHierarchyNode(A),
+      new EnumSet<Instantiation>.fromValues(<Instantiation>[
+          Instantiation.DIRECTLY_INSTANTIATED,
+          Instantiation.UNINSTANTIATED]),
+      includeRoot: false).iterator;
+  checkState(A, currentNode: null, stack: null);
+  Expect.isNull(iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: C, stack: [E, F, G, B]);
+  Expect.equals(C, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: E, stack: [F, G, B]);
+  Expect.equals(E, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: F, stack: [G, B]);
+  Expect.equals(F, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: G, stack: [B]);
+  Expect.equals(G, iterator.current);
+  Expect.isTrue(iterator.moveNext());
+  checkState(A, currentNode: D, stack: []);
+  Expect.equals(D, iterator.current);
+  Expect.isFalse(iterator.moveNext());
+  checkState(A, currentNode: null, stack: []);
+  Expect.isNull(iterator.current);
 }
 
+testForEach() async {
+  var env = await TypeEnvironment.create(r"""
+      ///        A
+      ///       / \
+      ///      B   C
+      ///     /   /|\
+      ///    D   E F G
+      ///         / \
+      ///         H I
+      ///
+      class A implements X {}
+      class B extends A {}
+      class C extends A {}
+      class D extends B {}
+      class E extends C {}
+      class F extends C implements B {}
+      class G extends C implements D {}
+      class H extends F {}
+      class I extends F {}
+      class X {}
+      """,
+        mainSource: r"""
+      main() {
+        new A();
+        new C();
+        new D();
+        new E();
+        new F();
+        new G();
+        new H();
+        new I();
+      }
+      """,
+      useMockCompiler: false);
+  World world = env.compiler.world;
+
+  ClassElement A = env.getElement("A");
+  ClassElement B = env.getElement("B");
+  ClassElement C = env.getElement("C");
+  ClassElement D = env.getElement("D");
+  ClassElement E = env.getElement("E");
+  ClassElement F = env.getElement("F");
+  ClassElement G = env.getElement("G");
+  ClassElement H = env.getElement("H");
+  ClassElement I = env.getElement("I");
+  ClassElement X = env.getElement("X");
+
+  void checkForEachSubclass(ClassElement cls, List<ClassElement> expected) {
+    ClassSet classSet = world.getClassSet(cls);
+    List<ClassElement> visited = <ClassElement>[];
+    classSet.forEachSubclass((ClassElement cls) {
+      visited.add(cls);
+    }, ClassHierarchyNode.ALL);
+
+    Expect.listEquals(expected, visited,
+        "Unexpected classes on $cls.forEachSubclass:\n"
+        "Actual: $visited, expected: $expected\n$classSet");
+
+    visited = <ClassElement>[];
+    classSet.forEachSubclass((ClassElement cls) {
+      visited.add(cls);
+      return ForEach.CONTINUE;
+    }, ClassHierarchyNode.ALL);
+
+    Expect.listEquals(expected, visited,
+        "Unexpected classes on $cls.forEachSubclass:\n"
+        "Actual: $visited, expected: $expected\n$classSet");
+  }
+
+  checkForEachSubclass(A, [A, B, D, C, G, F, I, H, E]);
+  checkForEachSubclass(B, [B, D]);
+  checkForEachSubclass(C, [C, G, F, I, H, E]);
+  checkForEachSubclass(D, [D]);
+  checkForEachSubclass(E, [E]);
+  checkForEachSubclass(F, [F, I, H]);
+  checkForEachSubclass(G, [G]);
+  checkForEachSubclass(H, [H]);
+  checkForEachSubclass(I, [I]);
+  checkForEachSubclass(X, [X]);
+
+  void checkForEachSubtype(ClassElement cls, List<ClassElement> expected) {
+    ClassSet classSet = world.getClassSet(cls);
+    List<ClassElement> visited = <ClassElement>[];
+    classSet.forEachSubtype((ClassElement cls) {
+      visited.add(cls);
+    }, ClassHierarchyNode.ALL);
+
+    Expect.listEquals(expected, visited,
+        "Unexpected classes on $cls.forEachSubtype:\n"
+        "Actual: $visited, expected: $expected\n$classSet");
+
+    visited = <ClassElement>[];
+    classSet.forEachSubtype((ClassElement cls) {
+      visited.add(cls);
+      return ForEach.CONTINUE;
+    }, ClassHierarchyNode.ALL);
+
+    Expect.listEquals(expected, visited,
+        "Unexpected classes on $cls.forEachSubtype:\n"
+        "Actual: $visited, expected: $expected\n$classSet");
+  }
+
+  checkForEachSubtype(A, [A, B, D, C, G, F, I, H, E]);
+  checkForEachSubtype(B, [B, D, F, I, H, G]);
+  checkForEachSubtype(C, [C, G, F, I, H, E]);
+  checkForEachSubtype(D, [D, G]);
+  checkForEachSubtype(E, [E]);
+  checkForEachSubtype(F, [F, I, H]);
+  checkForEachSubtype(G, [G]);
+  checkForEachSubtype(H, [H]);
+  checkForEachSubtype(I, [I]);
+  checkForEachSubtype(X, [X, A, B, D, C, G, F, I, H, E]);
+
+  void checkForEach(
+      ClassElement cls,
+      List<ClassElement> expected,
+      {ClassElement stop,
+       List<ClassElement> skipSubclasses: const <ClassElement>[],
+       bool forEachSubtype: false,
+       EnumSet<Instantiation> mask}) {
+
+    if (mask == null) {
+      mask = ClassHierarchyNode.ALL;
+    }
+
+    ClassSet classSet = world.getClassSet(cls);
+    List<ClassElement> visited = <ClassElement>[];
+
+    ForEach visit(ClassElement cls) {
+      visited.add(cls);
+      if (cls == stop) {
+        return ForEach.STOP;
+      } else if (skipSubclasses.contains(cls)) {
+        return ForEach.SKIP_SUBCLASSES;
+      }
+      return ForEach.CONTINUE;
+    }
+
+    if (forEachSubtype) {
+      classSet.forEachSubtype(visit, mask);
+    } else {
+      classSet.forEachSubclass(visit, mask);
+    }
+
+    Expect.listEquals(expected, visited,
+        "Unexpected classes on $cls."
+        "forEach${forEachSubtype ? 'Subtype' : 'Subclass'} "
+        "(stop:$stop, skipSubclasses:$skipSubclasses):\n"
+        "Actual: $visited, expected: $expected\n$classSet");
+  }
+
+  checkForEach(A, [A, B, D, C, G, F, I, H, E]);
+  checkForEach(A, [A], stop: A);
+  checkForEach(A, [A, B, C, G, F, I, H, E], skipSubclasses: [B]);
+  checkForEach(A, [A, B, C], skipSubclasses: [B, C]);
+  checkForEach(A, [A, B, C, G], stop: G, skipSubclasses: [B]);
+
+  checkForEach(B, [B, D, F, I, H, G], forEachSubtype: true);
+  checkForEach(B, [B, D], stop: D, forEachSubtype: true);
+  checkForEach(B, [B, D, F, G], skipSubclasses: [F], forEachSubtype: true);
+  checkForEach(B, [B, F, I, H, G], skipSubclasses: [B], forEachSubtype: true);
+  checkForEach(B, [B, D, F, I, H, G], skipSubclasses: [D], forEachSubtype: true);
+
+  checkForEach(X, [X, A, B, D, C, G, F, I, H, E], forEachSubtype: true);
+  checkForEach(X, [X, A, B, D], stop: D, forEachSubtype: true);
+  checkForEach(X, [X, A, B, D, C, G, F, E],
+      skipSubclasses: [F], forEachSubtype: true);
+  checkForEach(X, [X, A, B, D, C, G, F, I, H, E],
+      skipSubclasses: [X], forEachSubtype: true);
+  checkForEach(X, [X, A, B, D, C, G, F, I, H, E],
+      skipSubclasses: [D], forEachSubtype: true);
+  checkForEach(X, [A, D, C, G, F, I, H, E],
+      forEachSubtype: true,
+      mask: ClassHierarchyNode.DIRECTLY_INSTANTIATED);
+  checkForEach(X, [A, B, D, C, G, F, I, H, E],
+      forEachSubtype: true,
+      mask: ClassHierarchyNode.INSTANTIATED);
+
+  void checkAny(
+      ClassElement cls,
+      List<ClassElement> expected,
+      {ClassElement find,
+       bool expectedResult,
+       bool anySubtype: false}) {
+    ClassSet classSet = world.getClassSet(cls);
+    List<ClassElement> visited = <ClassElement>[];
+
+    bool visit(ClassElement cls) {
+      visited.add(cls);
+      return cls == find;
+    }
+
+    bool result;
+    if (anySubtype) {
+      result = classSet.anySubtype(visit, ClassHierarchyNode.ALL);
+    } else {
+      result = classSet.anySubclass(visit, ClassHierarchyNode.ALL);
+    }
+
+    Expect.equals(expectedResult, result,
+        "Unexpected result on $cls."
+        "any${anySubtype ? 'Subtype' : 'Subclass'} "
+        "(find:$find).");
+
+    Expect.listEquals(expected, visited,
+        "Unexpected classes on $cls."
+        "any${anySubtype ? 'Subtype' : 'Subclass'} "
+        "(find:$find):\n"
+        "Actual: $visited, expected: $expected\n$classSet");
+  }
+
+  checkAny(A, [A, B, D, C, G, F, I, H, E], expectedResult: false);
+  checkAny(A, [A], find: A, expectedResult: true);
+  checkAny(A, [A, B, D, C, G, F, I], find: I, expectedResult: true);
+
+  checkAny(B, [B, D, F, I, H, G], anySubtype: true, expectedResult: false);
+  checkAny(B, [B, D, F, I, H, G],
+      find: A, anySubtype: true, expectedResult: false);
+  checkAny(B, [B, D],
+      find: D, anySubtype: true, expectedResult: true);
+  checkAny(B, [B, D, F, I],
+      find: I, anySubtype: true, expectedResult: true);
+
+  checkAny(X, [X, A, B, D, C, G, F, I, H, E],
+      anySubtype: true, expectedResult: false);
+  checkAny(X, [X, A],
+      find: A, anySubtype: true, expectedResult: true);
+  checkAny(X, [X, A, B, D],
+      find: D, anySubtype: true, expectedResult: true);
+  checkAny(X, [X, A, B, D, C, G, F, I],
+      find: I, anySubtype: true, expectedResult: true);
+}
diff --git a/tests/compiler/dart2js/cps_ir/closures_16_test.dart b/tests/compiler/dart2js/cps_ir/closures_16_test.dart
new file mode 100644
index 0000000..6b359ec
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/closures_16_test.dart
@@ -0,0 +1,15 @@
+// ---- AUTO-GENERATED -------------------
+// This file was autogenerated by running:
+//
+//     dart path/to/up_to_date_test.dart update
+//
+// Do not edit this file by hand.
+// ---------------------------------------
+
+library tests.compiler.dart2js.cps_ir.closures_16.dart;
+
+import 'runner.dart';
+
+main(args) {
+  runTest("closures_16.dart", update: args.length > 0 && args[0] == "update");
+}
diff --git a/tests/compiler/dart2js/cps_ir/constructor_15_test.dart b/tests/compiler/dart2js/cps_ir/constructor_15_test.dart
new file mode 100644
index 0000000..d745e08
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/constructor_15_test.dart
@@ -0,0 +1,15 @@
+// ---- AUTO-GENERATED -------------------
+// This file was autogenerated by running:
+//
+//     dart path/to/up_to_date_test.dart update
+//
+// Do not edit this file by hand.
+// ---------------------------------------
+
+library tests.compiler.dart2js.cps_ir.constructor_15.dart;
+
+import 'runner.dart';
+
+main(args) {
+  runTest("constructor_15.dart", update: args.length > 0 && args[0] == "update");
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_1.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_1.js
index 758c03c..be268f4 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_1.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$sub$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$sub$n(x, y);
+  P.print(x - y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_10.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_10.js
index 8679a25..9c4c3f3 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_10.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_10.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$gt$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$gt$n(x, y);
+  P.print(x > y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_11.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_11.js
index b5ff041a..23f5fca 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_11.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_11.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$lt$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$lt$n(x, y);
+  P.print(x < y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_12.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_12.js
index 525a5d00..0fd94d2 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_12.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_12.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$ge$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$ge$n(x, y);
+  P.print(x >= y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_13.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_13.js
index f434bb7..481395c 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_13.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_13.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$le$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$le$n(x, y);
+  P.print(x <= y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_19.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_19.js
index c614b75..5125dcb 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_19.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_19.js
@@ -10,12 +10,14 @@
 // }
 
 function() {
-  var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0 = typeof y === "number";
-  P.print(J.$div$n(x, 2));
+  var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
+  if (typeof x !== "number")
+    return x.$div();
+  P.print(x / 2);
   P.print(true);
-  P.print(v0);
-  if (!v0)
-    throw H.wrapException(H.argumentErrorValue(y));
+  P.print(typeof y === "number");
+  if (typeof y !== "number")
+    return H.iae(y);
   P.print(x + y);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_2.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_2.js
index 33c7bf9..0de632e 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_2.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$div$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$div$n(x, y);
+  P.print(x / y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_20.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_20.js
index 915d2371..13b3053 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_20.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_20.js
@@ -10,12 +10,14 @@
 // }
 
 function() {
-  var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0 = typeof y === "number";
-  P.print(J.$div$n(x, 2));
+  var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
+  if (typeof x !== "number")
+    return x.$div();
+  P.print(x / 2);
   P.print(true);
-  P.print(v0);
-  if (!v0)
-    throw H.wrapException(H.argumentErrorValue(y));
+  P.print(typeof y === "number");
+  if (typeof y !== "number")
+    return H.iae(y);
   P.print(x * y);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js
index 589d358..26cfc95 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_21.js
@@ -10,21 +10,15 @@
 // }
 
 function() {
-  var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0 = typeof y === "number";
-  P.print(J.$div$n(x, 2));
+  var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null), v0;
+  if (typeof x !== "number")
+    return x.$div();
+  P.print(x / 2);
   P.print(true);
+  v0 = typeof y === "number";
   P.print(v0);
   if (!v0)
     throw H.wrapException(H.argumentErrorValue(y));
-  if (x < y)
-    v0 = -1;
-  else if (x > y)
-    v0 = 1;
-  else if (x === y) {
-    v0 = x === 0;
-    v0 = v0 ? (y === 0 ? 1 / y < 0 : y < 0) === (v0 ? 1 / x < 0 : x < 0) ? 0 : (v0 ? 1 / x < 0 : x < 0) ? -1 : 1 : 0;
-  } else
-    v0 = isNaN(x) ? isNaN(y) ? 0 : 1 : -1;
-  P.print(v0);
+  P.print(x < y ? -1 : x > y ? 1 : x === y ? x === 0 ? 1 / x < 0 === (y === 0 ? 1 / y < 0 : y < 0) ? 0 : 1 / x < 0 ? -1 : 1 : 0 : isNaN(x) ? isNaN(y) ? 0 : 1 : -1);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_7.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_7.js
index 6e152f7..cb58cd3 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_7.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_7.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$and$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$and$n(x, y);
+  P.print((x & y) >>> 0);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_8.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_8.js
index 438d6dc7..7c0109d 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_8.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_8.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$or$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$or$n(x, y);
+  P.print((x | y) >>> 0);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_9.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_9.js
index 43418b5..c1c6bec 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_9.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_9.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$xor$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$xor$n(x, y);
+  P.print((x ^ y) >>> 0);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_1.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_1.js
index 758c03c..be268f4 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_1.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$sub$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$sub$n(x, y);
+  P.print(x - y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_10.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_10.js
index b5ff041a..23f5fca 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_10.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_10.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$lt$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$lt$n(x, y);
+  P.print(x < y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_11.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_11.js
index 8679a25..9c4c3f3 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_11.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_11.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$gt$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$gt$n(x, y);
+  P.print(x > y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_12.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_12.js
index f434bb7..481395c 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_12.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_12.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$le$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$le$n(x, y);
+  P.print(x <= y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_13.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_13.js
index 525a5d00..0fd94d2 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_13.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_13.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$ge$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$ge$n(x, y);
+  P.print(x >= y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_2.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_2.js
index 33c7bf9..0de632e 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_2.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$div$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$div$n(x, y);
+  P.print(x / y);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_7.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_7.js
index 6e152f7..cb58cd3 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_7.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_7.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$and$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$and$n(x, y);
+  P.print((x & y) >>> 0);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_8.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_8.js
index 438d6dc7..7c0109d 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_8.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_8.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$or$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$or$n(x, y);
+  P.print((x | y) >>> 0);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_9.js b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_9.js
index 43418b5..c1c6bec 100644
--- a/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_9.js
+++ b/tests/compiler/dart2js/cps_ir/expected/argument_refinement_num_9.js
@@ -13,7 +13,9 @@
   var x = P.int_parse("1233", null, null), y = P.int_parse("1234", null, null);
   P.print(typeof x === "number");
   P.print(typeof y === "number");
-  P.print(J.$xor$n(x, y));
+  if (typeof x !== "number" || typeof y !== "number")
+    return J.$xor$n(x, y);
+  P.print((x ^ y) >>> 0);
   P.print(true);
   P.print(true);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_1.js b/tests/compiler/dart2js/cps_ir/expected/basic_1.js
index 1cf4ed5..f8384d4 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_1.js
@@ -15,13 +15,13 @@
 // }
 
 function() {
-  var l = [1, 2, 3], m = P.LinkedHashMap_LinkedHashMap$_literal(["s", 1]);
+  var l = [1, 2, 3], m = P.LinkedHashMap__makeLiteral(["s", 1]);
   P.print("()");
   P.print("(true)");
   P.print("(1)");
-  P.print("(" + P.IterableBase_iterableToFullString([1, 2, 3], "[", "]") + ")");
-  P.print("(" + P.Maps_mapToString(P.LinkedHashMap_LinkedHashMap$_literal(["s", 1])) + ")");
+  P.print("(" + H.S([1, 2, 3]) + ")");
+  P.print("(" + P.Maps_mapToString(P.LinkedHashMap__makeLiteral(["s", 1])) + ")");
   P.print("(1)");
-  P.print("(" + P.IterableBase_iterableToFullString(l, "[", "]") + ")");
+  P.print("(" + H.S(l) + ")");
   P.print("(" + P.Maps_mapToString(m) + ")");
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_10.js b/tests/compiler/dart2js/cps_ir/expected/basic_10.js
index cfd6571..745bc50 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_10.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_10.js
@@ -4,7 +4,7 @@
 // }
 
 function() {
-  var v0 = Date.now() < Date.now(), line = v0 ? "true" : false === v0 ? "false" : String(v0);
+  var line = H.S(Date.now() < Date.now());
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_11.js b/tests/compiler/dart2js/cps_ir/expected/basic_11.js
index 5f26f1c..68995ca 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_11.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_11.js
@@ -3,14 +3,13 @@
 // main() { foo(); }
 
 function() {
-  var line = "" + 42;
   if (typeof dartPrint == "function")
-    dartPrint(line);
+    dartPrint("42");
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
+    console.log("42");
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
+      throw "Unable to print message: " + String("42");
+    print("42");
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_12.js b/tests/compiler/dart2js/cps_ir/expected/basic_12.js
index 084681f..ac9e1d3 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_12.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_12.js
@@ -3,7 +3,7 @@
 // main() { print(foo); }
 
 function() {
-  var v0 = $.foo, line = v0 === 0 ? 1 / v0 < 0 ? "-0.0" : "" + v0 : "" + v0;
+  var line = H.S($.foo);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_13.js b/tests/compiler/dart2js/cps_ir/expected/basic_13.js
index 218ba31..e8db598 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_13.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_13.js
@@ -3,14 +3,13 @@
 // main() { foo; }
 
 function() {
-  var line = "" + 42;
   if (typeof dartPrint == "function")
-    dartPrint(line);
+    dartPrint("42");
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
+    console.log("42");
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
+      throw "Unable to print message: " + String("42");
+    print("42");
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_14.js b/tests/compiler/dart2js/cps_ir/expected/basic_14.js
index a42876b..068816d 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_14.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_14.js
@@ -3,15 +3,14 @@
 // main() { print(foo = 42); }
 
 function() {
-  var line = "" + 42;
   $.foo = 42;
   if (typeof dartPrint == "function")
-    dartPrint(line);
+    dartPrint("42");
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
+    console.log("42");
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
+      throw "Unable to print message: " + String("42");
+    print("42");
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_15.js b/tests/compiler/dart2js/cps_ir/expected/basic_15.js
index ea86609..92ba7b0 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_15.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_15.js
@@ -3,14 +3,13 @@
 // main() { foo = 42; }
 
 function() {
-  var line = "" + 42;
   if (typeof dartPrint == "function")
-    dartPrint(line);
+    dartPrint("42");
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
+    console.log("42");
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
+      throw "Unable to print message: " + String("42");
+    print("42");
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_4.js b/tests/compiler/dart2js/cps_ir/expected/basic_4.js
index 68f024f..8ce632a 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_4.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_4.js
@@ -3,15 +3,14 @@
 // main() { return foo(); }
 
 function() {
-  var line = "" + 42;
   if (typeof dartPrint == "function")
-    dartPrint(line);
+    dartPrint("42");
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
+    console.log("42");
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
+      throw "Unable to print message: " + String("42");
+    print("42");
   }
   return 42;
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/basic_9.js b/tests/compiler/dart2js/cps_ir/expected/basic_9.js
index b47ad6a..c23788a 100644
--- a/tests/compiler/dart2js/cps_ir/expected/basic_9.js
+++ b/tests/compiler/dart2js/cps_ir/expected/basic_9.js
@@ -5,14 +5,14 @@
 // }
 
 function() {
-  var res = "Instance of '" + H.Primitives_objectTypeName(V.C$()) + "'";
+  var line = "Instance of '" + H.Primitives_objectTypeName(V.C$()) + "'";
   if (typeof dartPrint == "function")
-    dartPrint(res);
+    dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(res);
+    console.log(line);
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(res);
-    print(res);
+      throw "Unable to print message: " + String(line);
+    print(line);
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_10.js b/tests/compiler/dart2js/cps_ir/expected/closures_10.js
index a628815..64e5e31 100644
--- a/tests/compiler/dart2js/cps_ir/expected/closures_10.js
+++ b/tests/compiler/dart2js/cps_ir/expected/closures_10.js
@@ -8,7 +8,7 @@
 // }
 
 function() {
-  var line = H.S(new V.A_b_closure(V.A$()).call$0());
+  var line = H.S(V.A$().a$0());
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_15.js b/tests/compiler/dart2js/cps_ir/expected/closures_15.js
index 46c7d38..cf37dd2 100644
--- a/tests/compiler/dart2js/cps_ir/expected/closures_15.js
+++ b/tests/compiler/dart2js/cps_ir/expected/closures_15.js
@@ -13,5 +13,5 @@
 function(x) {
   V.Foo$();
   P.print("getter");
-  P.print(new V.Foo_getter_closure().call$1(123));
+  P.print(123);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_16.js b/tests/compiler/dart2js/cps_ir/expected/closures_16.js
new file mode 100644
index 0000000..e589971
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/expected/closures_16.js
@@ -0,0 +1,17 @@
+// Expectation for test: 
+// class Foo {
+//   get getter {
+//     print('getter');
+//     return (x) { try { return x; } finally { } };  // Inhibit inlining.
+//   }
+// }
+// main(x) {
+//   // Getter may or may not be inlined.
+//   var notTearOff = new Foo().getter;
+//   // Closure is not inlined.
+//   print(notTearOff(123));
+// }
+
+function(x) {
+  P.print(V.Foo$().get$getter().call$1(123));
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_5.js b/tests/compiler/dart2js/cps_ir/expected/closures_5.js
index 959b14a..3c61ff5 100644
--- a/tests/compiler/dart2js/cps_ir/expected/closures_5.js
+++ b/tests/compiler/dart2js/cps_ir/expected/closures_5.js
@@ -7,7 +7,7 @@
 // }
 
 function() {
-  var _captured_x_0 = 122 + 1, line = _captured_x_0 === 0 ? 1 / _captured_x_0 < 0 ? "-0.0" : "" + _captured_x_0 : "" + _captured_x_0;
+  var line = H.S(122 + 1);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/closures_7.js b/tests/compiler/dart2js/cps_ir/expected/closures_7.js
index 4a16c92..62f16ad 100644
--- a/tests/compiler/dart2js/cps_ir/expected/closures_7.js
+++ b/tests/compiler/dart2js/cps_ir/expected/closures_7.js
@@ -10,7 +10,7 @@
 // }
 
 function() {
-  var _captured_x_0 = 122 + 1, line = _captured_x_0 === 0 ? 1 / _captured_x_0 < 0 ? "-0.0" : "" + _captured_x_0 : "" + _captured_x_0;
+  var line = H.S(122 + 1);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_1.js b/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_1.js
index 92a1969..9043a3f 100644
--- a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_1.js
@@ -5,14 +5,13 @@
 // }
 
 function() {
-  var line = "" + 65;
   if (typeof dartPrint == "function")
-    dartPrint(line);
+    dartPrint("65");
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
+    console.log("65");
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
+      throw "Unable to print message: " + String("65");
+    print("65");
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js b/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
index 73e278b..4fdd8a2 100644
--- a/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/codeUnitAt_2.js
@@ -11,13 +11,12 @@
 // }
 
 function() {
-  var v0 = "ABC".length, sum = 0, i = 0;
-  for (; i < v0; sum += "ABC".charCodeAt(i), ++i)
+  var sum = 0, i = 0;
+  for (; i < 3; sum += "ABC".charCodeAt(i), ++i)
     ;
   P.print(sum);
-  v0 = "Hello".length;
   sum = 0;
-  for (i = 0; i < v0; sum += "Hello".charCodeAt(i), ++i)
+  for (i = 0; i < 5; sum += "Hello".charCodeAt(i), ++i)
     ;
   P.print(sum);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_1.js b/tests/compiler/dart2js/cps_ir/expected/constructor_1.js
index 21493c2..6afa3a3 100644
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/constructor_1.js
@@ -12,7 +12,7 @@
 // }
 
 function() {
-  var line = 1 === 0 ? 1 / 1 < 0 ? "-0.0" : "" + 1 : "" + 1;
+  var line = H.S(1);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_11.js b/tests/compiler/dart2js/cps_ir/expected/constructor_11.js
index 9c0d6d0..3221867 100644
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_11.js
+++ b/tests/compiler/dart2js/cps_ir/expected/constructor_11.js
@@ -9,7 +9,7 @@
 // }
 
 function() {
-  var line = 1 === 0 ? 1 / 1 < 0 ? "-0.0" : "" + 1 : "" + 1;
+  var line = H.S(1);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_13.js b/tests/compiler/dart2js/cps_ir/expected/constructor_13.js
index 074cf69..a95670c 100644
--- a/tests/compiler/dart2js/cps_ir/expected/constructor_13.js
+++ b/tests/compiler/dart2js/cps_ir/expected/constructor_13.js
@@ -9,14 +9,14 @@
 // }
 
 function() {
-  var res = "Instance of '" + H.Primitives_objectTypeName(new V.Foo(5)) + "'";
+  var line = "Instance of '" + H.Primitives_objectTypeName(new V.Foo(5)) + "'";
   if (typeof dartPrint == "function")
-    dartPrint(res);
+    dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(res);
+    console.log(line);
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(res);
-    print(res);
+      throw "Unable to print message: " + String(line);
+    print(line);
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/constructor_15.js b/tests/compiler/dart2js/cps_ir/expected/constructor_15.js
new file mode 100644
index 0000000..22c0973
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/expected/constructor_15.js
@@ -0,0 +1,19 @@
+// Expectation for test: 
+// // Method to test: generative_constructor(A#)
+// class A {
+//   var x, y, z;
+//   A(x, y) {
+//     this.x = x;
+//     this.y = y;
+//     this.z = this.x / 2;
+//   }
+// }
+// 
+// main() {
+//   print(new A(123, 'sdf').y);
+//   try {} finally {} // Do not inline into main.
+// }
+
+function(x, y) {
+  return new V.A(x, y, x / 2);
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js
index 950d594..7fd9aff 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_1.js
@@ -4,6 +4,6 @@
 // }
 
 function() {
-  while (true)
+  for (;;)
     ;
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js
index 79c2ddd..3cb9718 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_2.js
@@ -1,5 +1,5 @@
 // Expectation for test: 
-// foo(a) { print(a); return a; }
+// foo(a) { try { print(a); } finally { return a; } }
 // 
 // main() {
 //   while (true) {
@@ -14,20 +14,14 @@
 // }
 
 function() {
-  L1:
-    while (true)
-      L0:
-        while (true)
-          while (true) {
-            P.print(true);
-            if (false) {
-              P.print(1);
-              continue L0;
-            }
-            P.print(false);
-            if (false) {
-              P.print(2);
-              continue L1;
-            }
+  L0:
+    for (;;)
+      for (;;) {
+        while (V.foo(true))
+          if (V.foo(false)) {
+            P.print(2);
+            continue L0;
           }
+        P.print(1);
+      }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js
index 514ed7b..f7c0900 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_3.js
@@ -1,5 +1,5 @@
 // Expectation for test: 
-// foo(a) { print(a); return a; }
+// foo(a) { try { print(a); } finally { return a; } }
 // 
 // main() {
 //   for (int i = 0; foo(true); i = foo(i)) {
@@ -10,17 +10,11 @@
 // }
 
 function() {
-  while (true) {
-    P.print(true);
-    if (true === true) {
-      P.print(1);
-      P.print(false);
-      if (false !== true) {
-        P.print(0);
-        continue;
-      }
-    }
-    P.print(2);
-    return null;
+  var i = 0;
+  for (; V.foo(true) === true; i = V.foo(i)) {
+    P.print(1);
+    if (V.foo(false) === true)
+      break;
   }
+  P.print(2);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js
index 00099d0..dae4cc7 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_4.js
@@ -1,5 +1,5 @@
 // Expectation for test: 
-// foo(a) { print(a); return a; }
+// foo(a) { try { print(a); } finally { return a; } }
 // 
 // main() {
 //  foo(false);
@@ -12,8 +12,7 @@
 // }
 
 function() {
-  P.print(false);
-  P.print(true);
-  true ? P.print(1) : P.print(2);
+  V.foo(false);
+  V.foo(true) ? P.print(1) : P.print(2);
   P.print(3);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js b/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js
index 78c0641..0f28201 100644
--- a/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js
+++ b/tests/compiler/dart2js/cps_ir/expected/control_flow_5.js
@@ -1,5 +1,5 @@
 // Expectation for test: 
-// foo(a) { print(a); return a; }
+// foo(a) { try { print(a); } finally { return a; } }
 // 
 // main() {
 //  foo(false);
@@ -14,9 +14,8 @@
 // }
 
 function() {
-  P.print(false);
-  P.print(true);
-  if (true) {
+  V.foo(false);
+  if (V.foo(true)) {
     P.print(1);
     P.print(1);
   } else {
diff --git a/tests/compiler/dart2js/cps_ir/expected/gvn_1.js b/tests/compiler/dart2js/cps_ir/expected/gvn_1.js
index 1307a74..5e14c5c 100644
--- a/tests/compiler/dart2js/cps_ir/expected/gvn_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/gvn_1.js
@@ -45,7 +45,7 @@
   for (; k < 10; sum += i + v0[v1], ++k)
     if (v1 < 0 || v1 >= 10)
       return H.ioore(v0, v1);
-  line = sum === 0 ? 1 / sum < 0 ? "-0.0" : "" + sum : "" + sum;
+  line = H.S(sum);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/interceptors_1.js b/tests/compiler/dart2js/cps_ir/expected/interceptors_1.js
index ed58ff0..a8df9d1 100644
--- a/tests/compiler/dart2js/cps_ir/expected/interceptors_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/interceptors_1.js
@@ -7,14 +7,13 @@
 // }
 
 function() {
-  var line = "" + 4;
   if (typeof dartPrint == "function")
-    dartPrint(line);
+    dartPrint("4");
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
+    console.log("4");
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
+      throw "Unable to print message: " + String("4");
+    print("4");
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/literals_1.js b/tests/compiler/dart2js/cps_ir/expected/literals_1.js
index ef654f5..d70ebf8 100644
--- a/tests/compiler/dart2js/cps_ir/expected/literals_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/literals_1.js
@@ -14,7 +14,7 @@
   P.print([1]);
   P.print([1, 2]);
   P.print([1, [1, 2]]);
-  P.print(P.LinkedHashMap_LinkedHashMap$_empty());
-  P.print(P.LinkedHashMap_LinkedHashMap$_literal([1, 2]));
-  P.print(P.LinkedHashMap_LinkedHashMap$_literal([[1, 2], [3, 4]]));
+  P.print(P.LinkedHashMap__makeEmpty());
+  P.print(P.LinkedHashMap__makeLiteral([1, 2]));
+  P.print(P.LinkedHashMap__makeLiteral([[1, 2], [3, 4]]));
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_1.js b/tests/compiler/dart2js/cps_ir/expected/operators2_1.js
index 5e39b1e..71a1da5 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_1.js
@@ -1,11 +1,12 @@
 // Expectation for test: 
+// // Method to test: function(foo)
 // foo(a, b) => ((a & 0xff0000) >> 1) & b;
 // main() {
+//   print(foo.toString());
 //   print(foo(123, 234));
 //   print(foo(0, 2));
 // }
 
-function() {
-  P.print((123 & 16711680) >>> 1 & 234);
-  P.print((0 & 16711680) >>> 1 & 2);
+function(a, b) {
+  return (a & 16711680) >>> 1 & b;
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_2.js b/tests/compiler/dart2js/cps_ir/expected/operators2_2.js
index 8d6d52d..7858649 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_2.js
@@ -1,11 +1,12 @@
 // Expectation for test: 
+// // Method to test: function(foo)
 // foo(a) => ~a;
 // main() {
+//   print(foo.toString());
 //   print(foo(1));
 //   print(foo(10));
 // }
 
-function() {
-  P.print(~1 >>> 0);
-  P.print(~10 >>> 0);
+function(a) {
+  return ~a >>> 0;
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_3.js b/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
index ff5d25d..0ec8440 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_3.js
@@ -1,12 +1,14 @@
 // Expectation for test: 
 // // Method to test: function(foo)
-// foo(a) => a % 13;
+// import 'package:expect/expect.dart';
+// 
+// @NoInline() foo(a) => a % 13;
+// 
 // main() {
 //   print(foo(5));
 //   print(foo(-100));
 // }
 
 function(a) {
-  var result = a % 13;
-  return result === 0 ? 0 : result > 0 ? result : 13 < 0 ? result - 13 : result + 13;
+  return C.JSInt_methods.$mod(a, 13);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_6.js b/tests/compiler/dart2js/cps_ir/expected/operators2_6.js
index 79fe43a..d9cfe87 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_6.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_6.js
@@ -1,11 +1,14 @@
 // Expectation for test: 
 // // Method to test: function(foo)
-// foo(a) => a ~/ 13;
+// import 'package:expect/expect.dart';
+// 
+// @NoInline() foo(a) => a ~/ 13;
+// 
 // main() {
 //   print(foo(5));
 //   print(foo(-100));
 // }
 
 function(a) {
-  return (a | 0) === a && (13 | 0) === 13 ? a / 13 | 0 : C.JSNumber_methods.toInt$0(a / 13);
+  return C.JSInt_methods.$tdiv(a, 13);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_7.js b/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
index 837393f..403b831 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_7.js
@@ -1,11 +1,15 @@
 // Expectation for test: 
-// foo(a) => a ~/ 13;
+// // Method to test: function(foo)
+// import 'package:expect/expect.dart';
+// 
+// @NoInline() foo(a) => a ~/ 13;
+// 
 // main() {
+//   print(foo.toString());
 //   print(foo(5));
 //   print(foo(100));
 // }
 
-function() {
-  P.print(5 / 13 | 0);
-  P.print(100 / 13 | 0);
+function(a) {
+  return a / 13 | 0;
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators2_8.js b/tests/compiler/dart2js/cps_ir/expected/operators2_8.js
index 2f1ce60..b322ba0 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators2_8.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators2_8.js
@@ -1,11 +1,14 @@
 // Expectation for test: 
 // // Method to test: function(foo)
-// foo(a) => a ~/ 13;
+// import 'package:expect/expect.dart';
+// 
+// @NoInline() foo(a) => a ~/ 13;
+// 
 // main() {
 //   print(foo(5));
 //   print(foo(8000000000));
 // }
 
 function(a) {
-  return (a | 0) === a && (13 | 0) === 13 ? a / 13 | 0 : C.JSNumber_methods.toInt$0(a / 13);
+  return C.JSInt_methods.$tdiv(a, 13);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_4.js b/tests/compiler/dart2js/cps_ir/expected/operators_4.js
index f86a490..65acae6 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators_4.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators_4.js
@@ -6,18 +6,12 @@
 function() {
   var v0 = $.x + 1, line;
   $.x = v0;
-  L0: {
-    if (v0 > 10) {
-      $.x = v0 = $.x + 1;
-      if (v0 > 10) {
-        line = "true";
-        break L0;
-      }
-      v0 = false;
-    } else
-      v0 = false;
-    line = false === v0 ? "false" : String(v0);
-  }
+  if (v0 > 10) {
+    $.x = v0 = $.x + 1;
+    v0 = v0 > 10;
+  } else
+    v0 = false;
+  line = H.S(v0);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_5.js b/tests/compiler/dart2js/cps_ir/expected/operators_5.js
index 3ff812c..df02418 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators_5.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators_5.js
@@ -6,16 +6,13 @@
 function() {
   var v0 = $.x + 1, line;
   $.x = v0;
-  L0: {
-    if (!(v0 > 10)) {
-      $.x = v0 = $.x + 1;
-      if (!(v0 > 10)) {
-        line = false === false ? "false" : String(false);
-        break L0;
-      }
-    }
-    line = "true";
+  if (v0 > 10)
+    v0 = true;
+  else {
+    $.x = v0 = $.x + 1;
+    v0 = v0 > 10;
   }
+  line = H.S(v0);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_7.js b/tests/compiler/dart2js/cps_ir/expected/operators_7.js
index b81aaa9..9b278bf 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators_7.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators_7.js
@@ -10,15 +10,14 @@
 // }
 
 function() {
-  var line = "" + 6;
   V.Foo$();
   if (typeof dartPrint == "function")
-    dartPrint(line);
+    dartPrint("6");
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
+    console.log("6");
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
+      throw "Unable to print message: " + String("6");
+    print("6");
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/operators_8.js b/tests/compiler/dart2js/cps_ir/expected/operators_8.js
index 3f1c27e..908c5f3 100644
--- a/tests/compiler/dart2js/cps_ir/expected/operators_8.js
+++ b/tests/compiler/dart2js/cps_ir/expected/operators_8.js
@@ -6,16 +6,16 @@
 // }
 
 function() {
-  var list = [1, 2, 3], res;
+  var list = [1, 2, 3], line;
   list[1] = 6;
-  res = P.IterableBase_iterableToFullString(list, "[", "]");
+  line = H.S(list);
   if (typeof dartPrint == "function")
-    dartPrint(res);
+    dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(res);
+    console.log(line);
   else if (!(typeof window == "object")) {
     if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(res);
-    print(res);
+      throw "Unable to print message: " + String(line);
+    print(line);
   }
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js b/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js
new file mode 100644
index 0000000..1b8c351
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/expected/optimize_indexers.js
@@ -0,0 +1,43 @@
+// Expectation for test: 
+// // Method to test: function(test)
+// import 'package:expect/expect.dart';
+// 
+// // This example illustrates a case we wish to do better in terms of inlining and
+// // code generation.
+// //
+// // Naively this function would be compiled without inlining Wrapper.[],
+// // JSArray.[] and Wrapper.[]= because:
+// // JSArray.[] is too big (14 nodes)
+// // Wrapper.[] is too big if we force inlining of JSArray (15 nodes)
+// // Wrapper.[]= is even bigger (46 nodes)
+// //
+// // We now do specialization of [] and []= by adding guards and injecting builtin
+// // operators. This made it possible to inline []. We still don't see []= inlined
+// // yet, that might require that we improve the inlining counting heuristics a
+// // bit.
+// @NoInline()
+// test(data, x) {
+//   data[x + 1] = data[x];
+// }
+// 
+// main() {
+//   var wrapper = new Wrapper();
+//   wrapper[33] = wrapper[1]; // make Wrapper.[]= and [] used more than once.
+//   print(test(new Wrapper(), int.parse('2')));
+// }
+// 
+// class Wrapper {
+//   final List arr = <bool>[true, false, false, true];
+//   operator[](int i) => this.arr[i];
+//   operator[]=(int i, v) {
+//     if (i > arr.length - 1) arr.length = i + 1;
+//     return arr[i] = v;
+//   }
+// }
+
+function(data, x) {
+  var v0 = J.$add$ns(x, 1), v1 = data.arr;
+  if (x >>> 0 !== x || x >= v1.length)
+    return H.ioore(v1, x);
+  data.$indexSet(0, v0, v1[x]);
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js b/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js
new file mode 100644
index 0000000..211aec6
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/expected/redundant_condition.js
@@ -0,0 +1,35 @@
+// Expectation for test: 
+// // This test illustrates an opportunity to remove redundant code by
+// // propagating inforamtion after inlining.
+// //
+// // The code below inlines `foo` twice, but we don't propagate that we already
+// // know from the first `foo` that `a` is an int, so the second check can be
+// // removed entirely.
+// 
+// import 'package:expect/expect.dart';
+// 
+// main() {
+//   var a = nextNumber();
+//   action(foo(a));
+//   action(foo(a));
+// }
+// 
+// foo(x) {
+//   if (x is! int) throw "error 1";
+//   return x + 5 % 100;
+// }
+// 
+// @NoInline() @AssumeDynamic()
+// nextNumber() => int.parse('33');
+// 
+// @NoInline()
+// action(v) => print(v);
+
+function() {
+  var a = V.nextNumber();
+  if (typeof a !== "number" || Math.floor(a) !== a)
+    throw H.wrapException("error 1");
+  a += 5;
+  V.action(a);
+  V.action(a);
+}
diff --git a/tests/compiler/dart2js/cps_ir/expected/supercall_1.js b/tests/compiler/dart2js/cps_ir/expected/supercall_1.js
index 4c7ee26..cc601dd 100644
--- a/tests/compiler/dart2js/cps_ir/expected/supercall_1.js
+++ b/tests/compiler/dart2js/cps_ir/expected/supercall_1.js
@@ -1,7 +1,7 @@
 // Expectation for test: 
 // class Base {
 //   m(x) {
-//     print(x+1);
+//     try { print(x+1); } finally { }
 //   }
 // }
 // class Sub extends Base {
@@ -12,15 +12,6 @@
 // }
 
 function() {
-  var line = "" + (100 + 10 + 1);
-  V.Sub$();
-  if (typeof dartPrint == "function")
-    dartPrint(line);
-  else if (typeof console == "object" && typeof console.log != "undefined")
-    console.log(line);
-  else if (!(typeof window == "object")) {
-    if (!(typeof print == "function"))
-      throw "Unable to print message: " + String(line);
-    print(line);
-  }
+  var v0 = V.Sub$();
+  V.Base.prototype.m$1.call(v0, 110);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/supercall_2.js b/tests/compiler/dart2js/cps_ir/expected/supercall_2.js
index 13b1d21..27f6c2b 100644
--- a/tests/compiler/dart2js/cps_ir/expected/supercall_2.js
+++ b/tests/compiler/dart2js/cps_ir/expected/supercall_2.js
@@ -25,5 +25,5 @@
 
 function() {
   var v0 = V.Sub$();
-  V.Base.prototype.$add.call(v0, v0, 10000 + 1);
+  V.Base.prototype.$add.call(v0, v0, 10001);
 }
diff --git a/tests/compiler/dart2js/cps_ir/expected/supercall_3.js b/tests/compiler/dart2js/cps_ir/expected/supercall_3.js
index ffc1752..f45afaf 100644
--- a/tests/compiler/dart2js/cps_ir/expected/supercall_3.js
+++ b/tests/compiler/dart2js/cps_ir/expected/supercall_3.js
@@ -10,7 +10,7 @@
 // }
 
 function() {
-  var line = "" + (10 + V.Sub$().field);
+  var line = H.S(10 + V.Sub$().field);
   if (typeof dartPrint == "function")
     dartPrint(line);
   else if (typeof console == "object" && typeof console.log != "undefined")
diff --git a/tests/compiler/dart2js/cps_ir/input/closures_16.dart b/tests/compiler/dart2js/cps_ir/input/closures_16.dart
new file mode 100644
index 0000000..0d57270
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/input/closures_16.dart
@@ -0,0 +1,12 @@
+class Foo {
+  get getter {
+    print('getter');
+    return (x) { try { return x; } finally { } };  // Inhibit inlining.
+  }
+}
+main(x) {
+  // Getter may or may not be inlined.
+  var notTearOff = new Foo().getter;
+  // Closure is not inlined.
+  print(notTearOff(123));
+}
diff --git a/tests/compiler/dart2js/cps_ir/input/constructor_15.dart b/tests/compiler/dart2js/cps_ir/input/constructor_15.dart
new file mode 100644
index 0000000..898b04f
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/input/constructor_15.dart
@@ -0,0 +1,14 @@
+// Method to test: generative_constructor(A#)
+class A {
+  var x, y, z;
+  A(x, y) {
+    this.x = x;
+    this.y = y;
+    this.z = this.x / 2;
+  }
+}
+
+main() {
+  print(new A(123, 'sdf').y);
+  try {} finally {} // Do not inline into main.
+}
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart
index dd06bed..a7baf52 100644
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart
+++ b/tests/compiler/dart2js/cps_ir/input/control_flow_2.dart
@@ -1,4 +1,4 @@
-foo(a) { print(a); return a; }
+foo(a) { try { print(a); } finally { return a; } }
 
 main() {
   while (true) {
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart
index 51cead4..8335da4 100644
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart
+++ b/tests/compiler/dart2js/cps_ir/input/control_flow_3.dart
@@ -1,4 +1,4 @@
-foo(a) { print(a); return a; }
+foo(a) { try { print(a); } finally { return a; } }
 
 main() {
   for (int i = 0; foo(true); i = foo(i)) {
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart
index 881d8ce..dd9fa9c 100644
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart
+++ b/tests/compiler/dart2js/cps_ir/input/control_flow_4.dart
@@ -1,4 +1,4 @@
-foo(a) { print(a); return a; }
+foo(a) { try { print(a); } finally { return a; } }
 
 main() {
  foo(false);
diff --git a/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart b/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart
index 6efe03c..ee75818 100644
--- a/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart
+++ b/tests/compiler/dart2js/cps_ir/input/control_flow_5.dart
@@ -1,4 +1,4 @@
-foo(a) { print(a); return a; }
+foo(a) { try { print(a); } finally { return a; } }
 
 main() {
  foo(false);
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_1.dart b/tests/compiler/dart2js/cps_ir/input/operators2_1.dart
index 05da19c..38b8f4f 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_1.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_1.dart
@@ -1,5 +1,7 @@
+// Method to test: function(foo)
 foo(a, b) => ((a & 0xff0000) >> 1) & b;
 main() {
+  print(foo.toString());
   print(foo(123, 234));
   print(foo(0, 2));
 }
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_2.dart b/tests/compiler/dart2js/cps_ir/input/operators2_2.dart
index 56bebd9..f38e967 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_2.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_2.dart
@@ -1,5 +1,7 @@
+// Method to test: function(foo)
 foo(a) => ~a;
 main() {
+  print(foo.toString());
   print(foo(1));
   print(foo(10));
 }
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_3.dart b/tests/compiler/dart2js/cps_ir/input/operators2_3.dart
index f1dc5ac..2cd9a53 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_3.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_3.dart
@@ -1,5 +1,8 @@
 // Method to test: function(foo)
-foo(a) => a % 13;
+import 'package:expect/expect.dart';
+
+@NoInline() foo(a) => a % 13;
+
 main() {
   print(foo(5));
   print(foo(-100));
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_6.dart b/tests/compiler/dart2js/cps_ir/input/operators2_6.dart
index 4b763a6..88bd137 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_6.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_6.dart
@@ -1,5 +1,8 @@
 // Method to test: function(foo)
-foo(a) => a ~/ 13;
+import 'package:expect/expect.dart';
+
+@NoInline() foo(a) => a ~/ 13;
+
 main() {
   print(foo(5));
   print(foo(-100));
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_7.dart b/tests/compiler/dart2js/cps_ir/input/operators2_7.dart
index f2c68ee..f8fe827 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_7.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_7.dart
@@ -1,5 +1,10 @@
-foo(a) => a ~/ 13;
+// Method to test: function(foo)
+import 'package:expect/expect.dart';
+
+@NoInline() foo(a) => a ~/ 13;
+
 main() {
+  print(foo.toString());
   print(foo(5));
   print(foo(100));
 }
diff --git a/tests/compiler/dart2js/cps_ir/input/operators2_8.dart b/tests/compiler/dart2js/cps_ir/input/operators2_8.dart
index 05e3bb0..ec9b8b3 100644
--- a/tests/compiler/dart2js/cps_ir/input/operators2_8.dart
+++ b/tests/compiler/dart2js/cps_ir/input/operators2_8.dart
@@ -1,5 +1,8 @@
 // Method to test: function(foo)
-foo(a) => a ~/ 13;
+import 'package:expect/expect.dart';
+
+@NoInline() foo(a) => a ~/ 13;
+
 main() {
   print(foo(5));
   print(foo(8000000000));
diff --git a/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart b/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart
new file mode 100644
index 0000000..8150653
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/input/optimize_indexers.dart
@@ -0,0 +1,35 @@
+// Method to test: function(test)
+import 'package:expect/expect.dart';
+
+// This example illustrates a case we wish to do better in terms of inlining and
+// code generation.
+//
+// Naively this function would be compiled without inlining Wrapper.[],
+// JSArray.[] and Wrapper.[]= because:
+// JSArray.[] is too big (14 nodes)
+// Wrapper.[] is too big if we force inlining of JSArray (15 nodes)
+// Wrapper.[]= is even bigger (46 nodes)
+//
+// We now do specialization of [] and []= by adding guards and injecting builtin
+// operators. This made it possible to inline []. We still don't see []= inlined
+// yet, that might require that we improve the inlining counting heuristics a
+// bit.
+@NoInline()
+test(data, x) {
+  data[x + 1] = data[x];
+}
+
+main() {
+  var wrapper = new Wrapper();
+  wrapper[33] = wrapper[1]; // make Wrapper.[]= and [] used more than once.
+  print(test(new Wrapper(), int.parse('2')));
+}
+
+class Wrapper {
+  final List arr = <bool>[true, false, false, true];
+  operator[](int i) => this.arr[i];
+  operator[]=(int i, v) {
+    if (i > arr.length - 1) arr.length = i + 1;
+    return arr[i] = v;
+  }
+}
diff --git a/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart b/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart
new file mode 100644
index 0000000..913dfc5
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/input/redundant_condition.dart
@@ -0,0 +1,25 @@
+// This test illustrates an opportunity to remove redundant code by
+// propagating inforamtion after inlining.
+//
+// The code below inlines `foo` twice, but we don't propagate that we already
+// know from the first `foo` that `a` is an int, so the second check can be
+// removed entirely.
+
+import 'package:expect/expect.dart';
+
+main() {
+  var a = nextNumber();
+  action(foo(a));
+  action(foo(a));
+}
+
+foo(x) {
+  if (x is! int) throw "error 1";
+  return x + 5 % 100;
+}
+
+@NoInline() @AssumeDynamic()
+nextNumber() => int.parse('33');
+
+@NoInline()
+action(v) => print(v);
diff --git a/tests/compiler/dart2js/cps_ir/input/supercall_1.dart b/tests/compiler/dart2js/cps_ir/input/supercall_1.dart
index 04d5817..0ac95c8d 100644
--- a/tests/compiler/dart2js/cps_ir/input/supercall_1.dart
+++ b/tests/compiler/dart2js/cps_ir/input/supercall_1.dart
@@ -1,6 +1,6 @@
 class Base {
   m(x) {
-    print(x+1);
+    try { print(x+1); } finally { }
   }
 }
 class Sub extends Base {
diff --git a/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart b/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart
new file mode 100644
index 0000000..eaf0b4a
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/optimize_indexers_test.dart
@@ -0,0 +1,15 @@
+// ---- AUTO-GENERATED -------------------
+// This file was autogenerated by running:
+//
+//     dart path/to/up_to_date_test.dart update
+//
+// Do not edit this file by hand.
+// ---------------------------------------
+
+library tests.compiler.dart2js.cps_ir.optimize_indexers.dart;
+
+import 'runner.dart';
+
+main(args) {
+  runTest("optimize_indexers.dart", update: args.length > 0 && args[0] == "update");
+}
diff --git a/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart b/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart
new file mode 100644
index 0000000..e97e0ac
--- /dev/null
+++ b/tests/compiler/dart2js/cps_ir/redundant_condition_test.dart
@@ -0,0 +1,15 @@
+// ---- AUTO-GENERATED -------------------
+// This file was autogenerated by running:
+//
+//     dart path/to/up_to_date_test.dart update
+//
+// Do not edit this file by hand.
+// ---------------------------------------
+
+library tests.compiler.dart2js.cps_ir.redundant_condition.dart;
+
+import 'runner.dart';
+
+main(args) {
+  runTest("redundant_condition.dart", update: args.length > 0 && args[0] == "update");
+}
diff --git a/tests/compiler/dart2js/cps_ir/runner.dart b/tests/compiler/dart2js/cps_ir/runner.dart
index a71bd9a..9f76482 100644
--- a/tests/compiler/dart2js/cps_ir/runner.dart
+++ b/tests/compiler/dart2js/cps_ir/runner.dart
@@ -28,12 +28,30 @@
       .readAsStringSync();
   var expectedFile =
       new File.fromUri(Platform.script.resolve('expected/$outputname'));
-  String expected = expectedFile.existsSync()
-    ? expectedFile.readAsStringSync() : '';
+  String expected = '';
+  if (expectedFile.existsSync()) {
+    expected = expectedFile.readAsStringSync()
+      .replaceAll(new RegExp('^//.*\n', multiLine: true), '')
+      .trim();
+  }
+
   var match = elementNameRegExp.firstMatch(source);
   var elementName = match?.group(1);
 
-  Map files = {TEST_MAIN_FILE: source};
+  Map files = {
+      TEST_MAIN_FILE: source,
+      'package:expect/expect.dart': '''
+          class NoInline {
+            const NoInline();
+          }
+          class TrustTypeAnnotations {
+            const TrustTypeAnnotations();
+          }
+          class AssumeDynamic {
+            const AssumeDynamic();
+          }
+       ''',
+   };
   asyncTest(() async {
     Uri uri = Uri.parse('memory:$TEST_MAIN_FILE');
     String found = null;
@@ -45,14 +63,9 @@
       Expect.isTrue(result.isSuccess);
       CompilerImpl compiler = result.compiler;
       if (expected != null) {
-        String output = elementName == null
+        found = elementName == null
             ? _getCodeForMain(compiler)
             : _getCodeForMethod(compiler, elementName);
-        // Include the input in a comment of the expected file to make it easier
-        // to see the relation between input and output in code reviews.
-        found = '// Expectation for test: \n'
-            '// ${source.trim().replaceAll('\n', '\n// ')}\n\n'
-            '$output\n';
       }
     } catch (e, st) {
       print(e);
@@ -68,12 +81,16 @@
     }
     if (expected != found) {
       if (update) {
-        expectedFile.writeAsStringSync(found);
+        // Include the input in a comment of the expected file to make it easier
+        // to see the relation between input and output in code reviews.
+        String comment = source.trim().replaceAll('\n', '\n// ');
+        expectedFile.writeAsStringSync('// Expectation for test: \n'
+            '// ${comment}\n\n${found}\n');
         print('INFO: $expectedFile was updated');
       } else {
         Expect.fail('Unexpected output for test:\n  '
             '${_formatTest(files).replaceAll('\n', '\n  ')}\n'
-            'Expected:\n  ${expected.replaceAll('\n', '\n  ')}\n'
+            'Expected:\n  ${expected.replaceAll('\n', '\n  ')}\n\n'
             'but found:\n  ${found?.replaceAll('\n', '\n  ')}\n'
             '$regenerateCommand');
       }
@@ -105,7 +122,7 @@
 String _getCodeForMain(CompilerImpl compiler) {
   Element mainFunction = compiler.mainFunction;
   js.Node ast = compiler.enqueuer.codegen.generatedCode[mainFunction];
-  return js.prettyPrint(ast, compiler).getText();
+  return js.prettyPrint(ast, compiler);
 }
 
 String _getCodeForMethod(CompilerImpl compiler,
@@ -125,5 +142,5 @@
   }
 
   js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement];
-  return js.prettyPrint(ast, compiler).getText();
+  return js.prettyPrint(ast, compiler);
 }
diff --git a/tests/compiler/dart2js/cps_ir/update_all.dart b/tests/compiler/dart2js/cps_ir/update_all.dart
index 726f2e4..59c0bc3 100644
--- a/tests/compiler/dart2js/cps_ir/update_all.dart
+++ b/tests/compiler/dart2js/cps_ir/update_all.dart
@@ -79,6 +79,7 @@
   runTest('closures_13.dart', update: true);
   runTest('closures_14.dart', update: true);
   runTest('closures_15.dart', update: true);
+  runTest('closures_16.dart', update: true);
   runTest('closures_2.dart', update: true);
   runTest('closures_3.dart', update: true);
   runTest('closures_4.dart', update: true);
@@ -95,6 +96,7 @@
   runTest('constructor_12.dart', update: true);
   runTest('constructor_13.dart', update: true);
   runTest('constructor_14.dart', update: true);
+  runTest('constructor_15.dart', update: true);
   runTest('constructor_2.dart', update: true);
   runTest('constructor_3.dart', update: true);
   runTest('constructor_4.dart', update: true);
@@ -132,6 +134,8 @@
   runTest('operators_6.dart', update: true);
   runTest('operators_7.dart', update: true);
   runTest('operators_8.dart', update: true);
+  runTest('optimize_indexers.dart', update: true);
+  runTest('redundant_condition.dart', update: true);
   runTest('runtime_types_1.dart', update: true);
   runTest('runtime_types_2.dart', update: true);
   runTest('runtime_types_3.dart', update: true);
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 3d0330e..888e95f 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -49,7 +49,8 @@
 
 # Source information is not correct due to inlining.
 js_backend_cps_ir_source_information_test: Fail
-sourcemaps/source_mapping_operators_test: Fail # Issue 25304 for checked mode, was: Pass, Slow
+sourcemaps/source_mapping_operators_test: Fail, Slow # Issue 25304 for checked mode, was: Pass, Slow
+sourcemaps/source_mapping_invokes_test: Fail, Slow # Issue 25304 for checked mode, was: Pass, Slow
 
 check_elements_invariants_test: Slow, Pass, Timeout # Slow due to inlining in the CPS backend
 
diff --git a/tests/compiler/dart2js/diagnostic_helper.dart b/tests/compiler/dart2js/diagnostic_helper.dart
index 26dac30..c9b19e1 100644
--- a/tests/compiler/dart2js/diagnostic_helper.dart
+++ b/tests/compiler/dart2js/diagnostic_helper.dart
@@ -25,7 +25,7 @@
   CollectedMessage(
       this.message, this.uri, this.begin, this.end, this.text, this.kind);
 
-  MessageKind get messageKind => message.kind;
+  MessageKind get messageKind => message?.kind;
 
   String toString() {
     return '${message != null ? message.kind : ''}'
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
index 2c68f48..781ef91 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_source_information_test.dart
@@ -60,7 +60,7 @@
   }
 
   js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement];
-  return js.prettyPrint(ast, compiler).getText();
+  return js.prettyPrint(ast, compiler);
 }
 
 runTests(List<TestEntry> tests) {
diff --git a/tests/compiler/dart2js/js_parser_statements_test.dart b/tests/compiler/dart2js/js_parser_statements_test.dart
index 2c12440..6c18de3 100644
--- a/tests/compiler/dart2js/js_parser_statements_test.dart
+++ b/tests/compiler/dart2js/js_parser_statements_test.dart
@@ -14,8 +14,7 @@
   jsAst.Node node = js.statement(statement, arguments);
   return MockCompiler.create((MockCompiler compiler) {
     String jsText =
-        jsAst.prettyPrint(node, compiler, allowVariableMinification: false)
-        .getText();
+        jsAst.prettyPrint(node, compiler, allowVariableMinification: false);
 
     Expect.stringEquals(expect.trim(), jsText.trim());
   });
diff --git a/tests/compiler/dart2js/js_parser_test.dart b/tests/compiler/dart2js/js_parser_test.dart
index 4022724..89d51070 100644
--- a/tests/compiler/dart2js/js_parser_test.dart
+++ b/tests/compiler/dart2js/js_parser_test.dart
@@ -15,7 +15,7 @@
     String jsText =
         jsAst.prettyPrint(node,
                           compiler,
-                          allowVariableMinification: false).getText();
+                          allowVariableMinification: false);
     if (expect == "") {
       Expect.stringEquals(expression, jsText);
     } else {
diff --git a/tests/compiler/dart2js/library_env_test.dart b/tests/compiler/dart2js/library_env_test.dart
new file mode 100644
index 0000000..0f0ff6d
--- /dev/null
+++ b/tests/compiler/dart2js/library_env_test.dart
@@ -0,0 +1,152 @@
+// 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.
+
+/// Check that 'dart:' libraries have their corresponding dart.library.X
+/// environment variable set.
+
+import "dart:io";
+
+import "dart:async";
+
+import "memory_source_file_helper.dart";
+
+import "package:async_helper/async_helper.dart";
+
+import 'package:expect/expect.dart' show
+    Expect;
+
+import 'package:compiler/src/elements/elements.dart' show
+    LibraryElement;
+
+import 'package:compiler/src/null_compiler_output.dart' show
+    NullCompilerOutput;
+
+import 'package:compiler/compiler_new.dart' show
+    CompilerInput,
+    CompilerDiagnostics;
+
+import 'package:sdk_library_metadata/libraries.dart' show
+    LibraryInfo;
+
+const clientPlatform = r'''
+[dart-spec]
+spec: 3rd edition.
+
+[features]
+# No extra features
+
+[libraries]
+mock.client: mock1.dart
+mock.shared: mock3.dart
+collection: collection/collection.dart
+html: html/dart2js/html_dart2js.dart
+''';
+
+const serverPlatform = r'''
+[dart-spec]
+spec: 3rd edition.
+
+[features]
+# No extra features
+
+[libraries]
+mock.server: mock2.dart
+mock.shared: mock3.dart
+collection: collection/collection.dart
+io: io/io.dart
+''';
+
+class DummyCompilerInput implements CompilerInput {
+  const DummyCompilerInput();
+
+  readFromUri(uri) async {
+    if (uri.toString().endsWith("dart_client.platform")) {
+      return clientPlatform;
+    } else if (uri.toString().endsWith("dart_server.platform")) {
+      return serverPlatform;
+    } else {
+      throw "should not be needed $uri";
+    }
+  }
+}
+
+class DummyCompilerDiagnostics implements CompilerDiagnostics {
+  const DummyCompilerDiagnostics();
+
+  report(code, uri, begin, end, text, kind) {
+    throw "should not be needed";
+  }
+}
+
+class CustomCompiler extends CompilerImpl {
+  CustomCompiler(
+      options,
+      environment)
+      : super(
+          const DummyCompilerInput(),
+          const NullCompilerOutput(),
+          const DummyCompilerDiagnostics(),
+          Uri.base.resolve("sdk/"),
+          null,
+          options,
+          environment);
+}
+
+runTest() async {
+  var compiler = new CustomCompiler(
+      [],
+      {});
+
+  await compiler.setupSdk();
+
+  // Core libraries are always present.
+  Expect.equals("true", compiler.fromEnvironment("dart.library.collection"));
+  // Non-existing entries in the environment return 'null'.
+  Expect.isNull(compiler.fromEnvironment("not in env"));
+  // Check for client libraries (default if there are no flags to the compiler).
+  Expect.equals("true", compiler.fromEnvironment("dart.library.mock.client"));
+  Expect.equals("true", compiler.fromEnvironment("dart.library.html"));
+  // Check for shared libraries..
+  Expect.equals("true", compiler.fromEnvironment("dart.library.mock.shared"));
+  // Check server libraries are not present.
+  Expect.equals(null, compiler.fromEnvironment("dart.library.mock.server"));
+  Expect.equals(null, compiler.fromEnvironment("dart.library.io"));
+
+  compiler = new CustomCompiler(
+      ['--categories=Server'],
+      {});
+
+  await compiler.setupSdk();
+
+  // Core libraries are always present.
+  Expect.equals("true", compiler.fromEnvironment("dart.library.collection"));
+  // Non-existing entries in the environment return 'null'.
+  Expect.isNull(compiler.fromEnvironment("not in env"));
+  // Check client libraries are not present.
+  Expect.equals(null, compiler.fromEnvironment("dart.library.mock.client"));
+  Expect.equals(null, compiler.fromEnvironment("dart.library.html"));
+  // Check for shared libraries..
+  Expect.equals("true", compiler.fromEnvironment("dart.library.mock.shared"));
+  // Check for server libraries.
+  Expect.equals("true", compiler.fromEnvironment("dart.library.mock.server"));
+  Expect.equals("true", compiler.fromEnvironment("dart.library.io"));
+
+  // Check that user-defined env-variables win.
+  compiler = new CustomCompiler(
+      [],
+      {'dart.library.collection': "false",
+       'dart.library.mock.client': "foo"});
+
+  await compiler.setupSdk();
+
+  Expect.equals("false", compiler.fromEnvironment("dart.library.collection"));
+  Expect.equals("foo", compiler.fromEnvironment("dart.library.mock.client"));
+}
+
+main() {
+  asyncStart();
+  runTest().then((_) {
+    asyncEnd();
+  });
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/message_kind_test.dart b/tests/compiler/dart2js/message_kind_test.dart
index c3954f0..5ba3ec6 100644
--- a/tests/compiler/dart2js/message_kind_test.dart
+++ b/tests/compiler/dart2js/message_kind_test.dart
@@ -13,7 +13,7 @@
 
 main(List<String> arguments) {
   List<MessageTemplate> examples = <MessageTemplate>[];
-  for (MessageKind kind in MessageKind.values) {
+  for (var kind in MessageKind.values) {
     MessageTemplate template = MessageTemplate.TEMPLATES[kind];
     Expect.isNotNull(template, "No template for $kind.");
     Expect.equals(kind, template.kind,
diff --git a/tests/compiler/dart2js/message_span_test.dart b/tests/compiler/dart2js/message_span_test.dart
new file mode 100644
index 0000000..655b814
--- /dev/null
+++ b/tests/compiler/dart2js/message_span_test.dart
@@ -0,0 +1,182 @@
+// 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:async_helper/async_helper.dart';
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/diagnostics/messages.dart';
+import 'package:compiler/src/io/source_file.dart';
+import 'package:expect/expect.dart';
+import 'memory_compiler.dart';
+import 'memory_source_file_helper.dart';
+
+const List<Test> TESTS = const <Test>[
+  const Test('''
+class A { A(b); }
+class B extends A {
+  a() {}
+
+  lot() {}
+
+  of() {}
+
+  var members;
+}
+main() => new B();''',
+  const {
+    MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT: '''
+class B extends A {
+^^^^^^^^^^^^^^^^^'''}),
+
+  const Test('''
+class I {}
+class A { A(b); }
+class B extends A implements I {
+  a() {}
+
+  lot() {}
+
+  of() {}
+
+  var members;
+}
+main() => new B();''',
+  const {
+    MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT: '''
+class B extends A implements I {
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^'''}),
+
+  const Test('''
+class M<T> {}
+class A { A(b); }
+class B extends A with M<int> {
+  a() {}
+
+  lot() {}
+
+  of() {}
+
+  var members;
+}
+main() => new B();''',
+  const {
+    MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT: '''
+class B extends A with M<int> {
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^'''}),
+
+  const Test('''
+class A { A(b); }
+class B
+    extends A {
+  a() {}
+
+  lot() {}
+
+  of() {}
+
+  var members;
+}
+main() => new B();''',
+  const {
+    MessageKind.NO_MATCHING_CONSTRUCTOR_FOR_IMPLICIT: '''
+class B
+    extends A {
+'''}),
+
+  const Test('''
+void foo(int a) {
+  // a
+  // non-empty
+  // body
+}
+main() => foo('');''',
+  const {
+    MessageKind.THIS_IS_THE_METHOD: '''
+void foo(int a) {
+^^^^^^^^^^^^^^^'''}),
+
+  const Test('''
+void foo(int a,
+         int b) {
+  // a
+  // non-empty
+  // body
+}
+main() => foo('', 0);''',
+  const {
+    MessageKind.THIS_IS_THE_METHOD: '''
+void foo(int a,
+         int b) {
+'''}),
+
+  const Test('''
+class A {
+  int foo() {
+    // a
+    // non-empty
+    // body
+  }
+}
+class B extends A {
+  int get foo {
+    // a
+    // non-empty
+    // body
+    return 0;
+  }
+}
+main() => new B();''',
+  const {
+    MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER: '''
+  int get foo {
+  ^^^^^^^^^^^''',
+    MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT: '''
+  int foo() {
+  ^^^^^^^^^'''}),
+];
+
+class Test {
+  final String code;
+  final Map<MessageKind, String> kindToSpan;
+
+  const Test(this.code, this.kindToSpan);
+}
+
+const String MARKER = '---marker---';
+
+main() {
+  asyncTest(() async {
+    var cachedCompiler;
+    for (Test test in TESTS) {
+      DiagnosticCollector collector = new DiagnosticCollector();
+      CompilationResult result = await runCompiler(
+          memorySourceFiles: {'main.dart': test.code},
+          options: [Flags.analyzeOnly],
+          diagnosticHandler: collector,
+          cachedCompiler: cachedCompiler);
+      cachedCompiler = result.compiler;
+      MemorySourceFileProvider provider = cachedCompiler.provider;
+      Map<MessageKind, String> kindToSpan =
+          new Map<MessageKind, String>.from(test.kindToSpan);
+      for (CollectedMessage message in collector.messages) {
+        String expectedSpanText = kindToSpan[message.messageKind];
+        if (expectedSpanText != null) {
+          SourceFile sourceFile = provider.getSourceFile(message.uri);
+          String locationMessage =
+              sourceFile.getLocationMessage(MARKER, message.begin, message.end);
+          // Remove `filename:line:column:` and message.
+          String strippedLocationMessage = locationMessage.substring(
+              locationMessage.indexOf(MARKER) + MARKER.length + 1);
+          Expect.equals(expectedSpanText, strippedLocationMessage,
+              "Unexpected span for ${message.messageKind} in\n${test.code}"
+              "\nExpected:${expectedSpanText.codeUnits}"
+              "\nActual  :${strippedLocationMessage.codeUnits}");
+          kindToSpan.remove(message.messageKind);
+        }
+      }
+      kindToSpan.forEach((MessageKind kind, _) {
+        Expect.fail("Missing message kin $kind in\n${test.code}");
+      });
+    }
+  });
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/no_such_method_enabled_test.dart b/tests/compiler/dart2js/no_such_method_enabled_test.dart
index 2f5f9c7..ac8e480 100644
--- a/tests/compiler/dart2js/no_such_method_enabled_test.dart
+++ b/tests/compiler/dart2js/no_such_method_enabled_test.dart
@@ -2,11 +2,12 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:async';
 import 'package:expect/expect.dart';
-import "package:async_helper/async_helper.dart";
+import 'package:async_helper/async_helper.dart';
 import 'compiler_helper.dart';
 
-dummyImplTest() {
+Future dummyImplTest() async {
   String source = """
 class A {
   foo() => 3;
@@ -18,16 +19,15 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isFalse(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isFalse(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest2() {
+Future dummyImplTest2() async {
   String source = """
 class A extends B {
   foo() => 3;
@@ -40,16 +40,15 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isFalse(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isFalse(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest3() {
+Future dummyImplTest3() async {
   String source = """
 class A extends B {
   foo() => 3;
@@ -64,16 +63,15 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isFalse(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isFalse(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest4() {
+Future dummyImplTest4() async {
   String source = """
 class A extends B {
   foo() => 3;
@@ -88,20 +86,19 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isFalse(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-    ClassElement clsB = findElement(compiler, 'B');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
-            clsB.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isFalse(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
+  ClassElement clsB = findElement(compiler, 'B');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
+          clsB.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest5() {
+Future dummyImplTest5() async {
   String source = """
 class A extends B {
   foo() => 3;
@@ -116,20 +113,19 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isTrue(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.throwingImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-    ClassElement clsB = findElement(compiler, 'B');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.throwingImpls.contains(
-            clsB.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isTrue(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.throwingImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
+  ClassElement clsB = findElement(compiler, 'B');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.throwingImpls.contains(
+          clsB.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest6() {
+Future dummyImplTest6() async {
   String source = """
 class A {
   noSuchMethod(x) => 3;
@@ -140,16 +136,15 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isTrue(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.otherImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isTrue(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.otherImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest7() {
+Future dummyImplTest7() async {
   String source = """
 class A {
   noSuchMethod(x, [y]) => super.noSuchMethod(x);
@@ -160,16 +155,15 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isFalse(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isFalse(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.defaultImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest8() {
+Future dummyImplTest8() async {
   String source = """
 class A {
   noSuchMethod(x, [y]) => super.noSuchMethod(x, y);
@@ -180,16 +174,15 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isTrue(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.otherImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isTrue(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.otherImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest9() {
+Future dummyImplTest9() async {
   String source = """
 class A {
   noSuchMethod(x, y) => super.noSuchMethod(x);
@@ -200,16 +193,15 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isTrue(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.otherImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isFalse(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.notApplicableImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest10() {
+Future dummyImplTest10() async {
   String source = """
 class A {
   noSuchMethod(Invocation x) {
@@ -222,16 +214,15 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isTrue(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.throwingImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isTrue(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.throwingImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest11() {
+Future dummyImplTest11() async {
   String source = """
 class A {
   noSuchMethod(Invocation x) {
@@ -245,19 +236,18 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isTrue(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.otherImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.complexNoReturnImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isTrue(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.otherImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.complexNoReturnImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
-dummyImplTest12() {
+Future dummyImplTest12() async {
   String source = """
 class A {
   noSuchMethod(Invocation x) {
@@ -270,29 +260,30 @@
 """;
   Uri uri = new Uri(scheme: 'source');
   var compiler = compilerFor(source, uri);
-  asyncTest(() => compiler.run(uri).then((_) {
-    Expect.isTrue(compiler.backend.enabledNoSuchMethod);
-    ClassElement clsA = findElement(compiler, 'A');
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.otherImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-    Expect.isTrue(
-        compiler.backend.noSuchMethodRegistry.complexReturningImpls.contains(
-            clsA.lookupMember('noSuchMethod')));
-  }));
+  await compiler.run(uri);
+  Expect.isTrue(compiler.backend.enabledNoSuchMethod);
+  ClassElement clsA = findElement(compiler, 'A');
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.otherImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
+  Expect.isTrue(
+      compiler.backend.noSuchMethodRegistry.complexReturningImpls.contains(
+          clsA.lookupMember('noSuchMethod')));
 }
 
 main() {
-  dummyImplTest();
-  dummyImplTest2();
-  dummyImplTest3();
-  dummyImplTest4();
-  dummyImplTest5();
-  dummyImplTest6();
-  dummyImplTest7();
-  dummyImplTest8();
-  dummyImplTest9();
-  dummyImplTest10();
-  dummyImplTest11();
-  dummyImplTest12();
+  asyncTest(() async {
+    await dummyImplTest();
+    await dummyImplTest2();
+    await dummyImplTest3();
+    await dummyImplTest4();
+    await dummyImplTest5();
+    await dummyImplTest6();
+    await dummyImplTest7();
+    await dummyImplTest8();
+    await dummyImplTest9();
+    await dummyImplTest10();
+    await dummyImplTest11();
+    await dummyImplTest12();
+  });
 }
diff --git a/tests/compiler/dart2js/override_inheritance_test.dart b/tests/compiler/dart2js/override_inheritance_test.dart
index 628f625..ef4387f 100644
--- a/tests/compiler/dart2js/override_inheritance_test.dart
+++ b/tests/compiler/dart2js/override_inheritance_test.dart
@@ -1548,7 +1548,6 @@
           }
           class Class extends A {
           }
-          """, warnings: MessageKind.UNIMPLEMENTED_METHOD_ONE,
-               infos: MessageKind.UNIMPLEMENTED_METHOD_CONT),
+          """),
   ]);
 }
diff --git a/tests/compiler/dart2js/proxy_test.dart b/tests/compiler/dart2js/proxy_test.dart
index bdba67f..3a0af23 100644
--- a/tests/compiler/dart2js/proxy_test.dart
+++ b/tests/compiler/dart2js/proxy_test.dart
@@ -15,6 +15,9 @@
 const Map<String, dynamic> TESTS = const {
     'language/proxy_test.dart': null,
     'language/proxy2_test.dart': null,
+    'language/proxy3_test.dart': null,
+    'language/proxy4_test.dart': null,
+    'language/proxy5_test.dart': null,
 };
 
 void main(List<String> args) {
diff --git a/tests/compiler/dart2js/semantic_visitor_test.dart b/tests/compiler/dart2js/semantic_visitor_test.dart
index 72f93e1..5a0e9dd 100644
--- a/tests/compiler/dart2js/semantic_visitor_test.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test.dart
@@ -589,6 +589,7 @@
   VISIT_UNRESOLVED_INVOKE,
   VISIT_UNRESOLVED_SUPER_GET,
   VISIT_UNRESOLVED_SUPER_INVOKE,
+  VISIT_UNRESOLVED_SUPER_SET,
 
   VISIT_BINARY,
   VISIT_INDEX,
diff --git a/tests/compiler/dart2js/semantic_visitor_test_send_data.dart b/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
index a0fd164..51eae03 100644
--- a/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test_send_data.dart
@@ -1308,6 +1308,16 @@
         }
         ''',
         const Visit(VisitKind.VISIT_UNRESOLVED_SUPER_GET)),
+    const Test.clazz(
+            '''
+    class B {
+    }
+    class C extends B {
+      m() => super.o = 42;
+    }
+    ''',
+        const Visit(VisitKind.VISIT_UNRESOLVED_SUPER_SET,
+                    rhs: '42')),
   ],
   'Super properties': const [
     // Super properties
diff --git a/tests/compiler/dart2js/semantic_visitor_test_send_visitor.dart b/tests/compiler/dart2js/semantic_visitor_test_send_visitor.dart
index 0125b43..cdbbe41 100644
--- a/tests/compiler/dart2js/semantic_visitor_test_send_visitor.dart
+++ b/tests/compiler/dart2js/semantic_visitor_test_send_visitor.dart
@@ -1080,6 +1080,17 @@
       Element element,
       arg) {
     visits.add(new Visit(VisitKind.VISIT_UNRESOLVED_SUPER_GET));
+    return super.visitUnresolvedSuperGet(node, element, arg);
+  }
+
+  @override
+  visitUnresolvedSuperSet(
+      Send node,
+      Element element,
+      Node rhs,
+      arg) {
+    visits.add(new Visit(VisitKind.VISIT_UNRESOLVED_SUPER_SET, rhs: rhs));
+    return super.visitUnresolvedSuperSet(node, element, rhs, arg);
   }
 
   @override
diff --git a/tests/compiler/dart2js/sourcemaps/diff.dart b/tests/compiler/dart2js/sourcemaps/diff.dart
new file mode 100644
index 0000000..6fb4468
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/diff.dart
@@ -0,0 +1,444 @@
+// 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 sourcemap.diff;
+
+import 'package:compiler/src/io/source_file.dart';
+
+import 'html_parts.dart';
+import 'output_structure.dart';
+import 'sourcemap_helper.dart';
+
+enum DiffKind {
+  UNMATCHED,
+  MATCHING,
+  IDENTICAL,
+}
+
+/// A list of columns that should align in output.
+class DiffBlock {
+  final DiffKind kind;
+  List<List<HtmlPart>> columns = <List<HtmlPart>>[];
+
+  DiffBlock(this.kind);
+
+  void addColumn(int index, List<HtmlPart> lines) {
+    if (index >= columns.length) {
+      columns.length = index + 1;
+    }
+    columns[index] = lines;
+  }
+
+  List<HtmlPart> getColumn(int index) {
+    List<HtmlPart> lines;
+    if (index < columns.length) {
+      lines = columns[index];
+    }
+    return lines != null ? lines : const <HtmlPart>[];
+  }
+}
+
+
+/// Align the content of [list1] and [list2].
+///
+/// If provided, [range1] and [range2] aligned the subranges of [list1] and
+/// [list2], otherwise the whole lists are aligned.
+///
+/// If provided, [match] determines the equality between members of [list1] and
+/// [list2], otherwise `==` is used.
+///
+/// [handleSkew] is called when a subrange of one list is not found in the
+/// other.
+///
+/// [handleMatched] is called when two indices match up.
+///
+/// [handleUnmatched] is called when two indices don't match up (none are found
+/// in the other list).
+void align(List list1,
+           List list2,
+           {Interval range1,
+            Interval range2,
+            bool match(a, b),
+            void handleSkew(int listIndex, Interval range),
+            void handleMatched(List<int> indices),
+            void handleUnmatched(List<int> indices)}) {
+  if (match == null) {
+    match = (a, b) => a == b;
+  }
+
+  if (range1 == null) {
+    range1 = new Interval(0, list1.length);
+  }
+  if (range2 == null) {
+    range2 = new Interval(0, list2.length);
+  }
+
+  Interval findInOther(
+      List thisLines, Interval thisRange,
+      List otherLines, Interval otherRange) {
+    for (int index = otherRange.from; index < otherRange.to; index++) {
+      if (match(thisLines[thisRange.from], otherLines[index])) {
+        int offset = 1;
+        while (thisRange.from + offset < thisRange.to &&
+               otherRange.from + offset < otherRange.to &&
+               match(thisLines[thisRange.from + offset],
+                     otherLines[otherRange.from + offset])) {
+          offset++;
+        }
+        return new Interval(index, index + offset);
+      }
+    }
+    return null;
+  }
+
+  int start1 = range1.from;
+  int end1 = range1.to;
+  int start2 = range2.from;
+  int end2 = range2.to;
+
+  const int ALIGN1 = -1;
+  const int UNMATCHED = 0;
+  const int ALIGN2 = 1;
+
+  while (start1 < end1 && start2 < end2) {
+    if (match(list1[start1], list2[start2])) {
+      handleMatched([start1++, start2++]);
+    } else {
+      Interval subrange1 = new Interval(start1, end1);
+      Interval subrange2 = new Interval(start2, end2);
+      Interval element2inList1 =
+          findInOther(list1, subrange1, list2, subrange2);
+      Interval element1inList2 =
+          findInOther(list2, subrange2, list1, subrange1);
+      int choice = 0;
+      if (element2inList1 != null) {
+        if (element1inList2 != null) {
+          if (element1inList2.length > 1 && element2inList1.length > 1) {
+            choice =
+                element2inList1.from < element1inList2.from ? ALIGN2 : ALIGN1;
+          } else if (element2inList1.length > 1) {
+            choice = ALIGN2;
+          } else if (element1inList2.length > 1) {
+            choice = ALIGN1;
+          } else {
+            choice =
+                element2inList1.from < element1inList2.from ? ALIGN2 : ALIGN1;
+          }
+        } else {
+          choice = ALIGN2;
+        }
+      } else if (element1inList2 != null) {
+        choice = ALIGN1;
+      }
+      switch (choice) {
+        case ALIGN1:
+          handleSkew(0, new Interval(start1, element1inList2.from));
+          start1 = element1inList2.from;
+          break;
+        case ALIGN2:
+          handleSkew(1, new Interval(start2, element2inList1.from));
+          start2 = element2inList1.from;
+          break;
+        case UNMATCHED:
+          handleUnmatched([start1++, start2++]);
+          break;
+      }
+    }
+  }
+  if (start1 < end1) {
+    handleSkew(0, new Interval(start1, end1));
+  }
+  if (start2 < end2) {
+    handleSkew(1, new Interval(start2, end2));
+  }
+}
+
+/// Create a list of blocks containing the diff of the two output [structures]
+/// and the corresponding Dart code.
+List<DiffBlock> createDiffBlocks(
+    List<OutputStructure> structures,
+    SourceFileManager sourceFileManager) {
+  return new DiffCreator(structures, sourceFileManager).computeBlocks();
+}
+
+class DiffCreator {
+  final List<OutputStructure> structures;
+  final SourceFileManager sourceFileManager;
+
+  List<List<CodeLine>> inputLines;
+
+  List<int> nextInputLine = [0, 0];
+
+  List<DiffBlock> blocks = <DiffBlock>[];
+
+  DiffCreator(List<OutputStructure> structures, this.sourceFileManager)
+      : this.structures = structures,
+        this.inputLines = structures.map((s) => s.lines).toList();
+
+  CodeSource codeSourceFromEntities(Iterable<OutputEntity> entities) {
+    for (OutputEntity entity in entities) {
+      if (entity.codeSource != null) {
+        return entity.codeSource;
+      }
+    }
+    return null;
+  }
+
+  /// Checks that lines are added in sequence without gaps or duplicates.
+  void checkLineInvariant(int index, Interval range) {
+    int expectedLineNo = nextInputLine[index];
+    if (range.from != expectedLineNo) {
+      print('Expected line no $expectedLineNo, found ${range.from}');
+      if (range.from < expectedLineNo) {
+        print('Duplicate lines:');
+        int i = range.from;
+        while (i <= expectedLineNo) {
+          print(inputLines[index][i++].code);
+        }
+      } else {
+        print('Missing lines:');
+        int i = expectedLineNo;
+        while (i <= range.from) {
+          print(inputLines[index][i++].code);
+        }
+      }
+    }
+    nextInputLine[index] = range.to;
+  }
+
+  /// Creates a block containing the code lines in [range] from input number
+  /// [index]. If [codeSource] is provided, the block will contain a
+  /// corresponding Dart code column.
+  void handleSkew(int index, Interval range, [CodeSource codeSource]) {
+    DiffBlock block = new DiffBlock(DiffKind.UNMATCHED);
+    checkLineInvariant(index, range);
+    block.addColumn(index, inputLines[index].sublist(range.from, range.to));
+    if (codeSource != null) {
+      block.addColumn(2,
+          codeLinesFromCodeSource(sourceFileManager, codeSource));
+    }
+    blocks.add(block);
+  }
+
+  /// Create a block containing the code lines in [ranges] from the
+  /// corresponding JavaScript inputs. If [codeSource] is provided, the block
+  /// will contain a corresponding Dart code column.
+  void addLines(DiffKind kind, List<Interval> ranges, [CodeSource codeSource]) {
+    DiffBlock block = new DiffBlock(kind);
+    for (int i = 0; i < ranges.length; i++) {
+      checkLineInvariant(i, ranges[i]);
+      block.addColumn(i, inputLines[i].sublist(ranges[i].from, ranges[i].to));
+    }
+    if (codeSource != null) {
+      block.addColumn(2,
+          codeLinesFromCodeSource(sourceFileManager, codeSource));
+    }
+    blocks.add(block);
+  }
+
+  /// Merge the code lines in [range1] and [range2] of the corresponding input.
+  void addRaw(Interval range1, Interval range2) {
+    match(a, b) => a.code == b.code;
+
+    List<Interval> currentMatchedIntervals;
+    List<Interval> currentUnmatchedIntervals;
+
+    void flushMatching() {
+      if (currentMatchedIntervals != null) {
+        addLines(DiffKind.IDENTICAL, currentMatchedIntervals);
+      }
+      currentMatchedIntervals = null;
+    }
+
+    void flushUnmatched() {
+      if (currentUnmatchedIntervals != null) {
+        addLines(DiffKind.UNMATCHED, currentUnmatchedIntervals);
+      }
+      currentUnmatchedIntervals = null;
+    }
+
+    List<Interval> updateIntervals(List<Interval> current, List<int> indices) {
+      if (current == null) {
+        return [
+          new Interval(indices[0], indices[0] + 1),
+          new Interval(indices[1], indices[1] + 1)];
+      } else {
+        current[0] =
+            new Interval(current[0].from, indices[0] + 1);
+        current[1] =
+            new Interval(current[1].from, indices[1] + 1);
+        return current;
+      }
+    }
+
+    align(
+        inputLines[0],
+        inputLines[1],
+        range1: range1,
+        range2: range2,
+        match: match,
+        handleSkew: (int listIndex, Interval range) {
+          flushMatching();
+          flushUnmatched();
+          handleSkew(listIndex, range);
+        },
+        handleMatched: (List<int> indices) {
+          flushUnmatched();
+          currentMatchedIntervals =
+              updateIntervals(currentMatchedIntervals, indices);
+        },
+        handleUnmatched: (List<int> indices) {
+          flushMatching();
+          currentUnmatchedIntervals =
+              updateIntervals(currentUnmatchedIntervals, indices);
+        });
+
+    flushMatching();
+    flushUnmatched();
+  }
+
+  /// Adds the top level blocks in [childRange] for structure [index].
+  void addBlock(int index, Interval childRange) {
+    addSkewedChildren(index, structures[index], childRange);
+  }
+
+  /// Adds the [entity] from structure [index]. If the [entity] supports child
+  /// entities, these are process individually. Otherwise the lines from
+  /// [entity] are added directly.
+  void addSkewedEntity(int index, OutputEntity entity) {
+    if (entity.canHaveChildren) {
+      handleSkew(index, entity.header);
+      addSkewedChildren(
+          index, entity, new Interval(0, entity.children.length));
+      handleSkew(index, entity.footer);
+    } else {
+      handleSkew(index, entity.interval, codeSourceFromEntities([entity]));
+    }
+  }
+
+  /// Adds the children of [parent] in [childRange] from structure [index].
+  void addSkewedChildren(int index, OutputEntity parent, Interval childRange) {
+    for (int i = childRange.from; i < childRange.to; i++) {
+      addSkewedEntity(index, parent.getChild(i));
+    }
+  }
+
+  /// Adds the members of the [classes] aligned.
+  void addMatchingContainers(List<OutputEntity> classes) {
+    addLines(DiffKind.MATCHING, classes.map((c) => c.header).toList());
+    align(classes[0].children, classes[1].children,
+        match: (a, b) => a.name == b.name,
+        handleSkew: (int listIndex, Interval childRange) {
+          addSkewedChildren(listIndex, classes[listIndex], childRange);
+        },
+        handleMatched: (List<int> indices) {
+          List<BasicEntity> entities =  [
+              classes[0].getChild(indices[0]),
+              classes[1].getChild(indices[1])];
+          if (entities.every((e) => e is Statics)) {
+            addMatchingContainers(entities);
+          } else {
+            addLines(DiffKind.MATCHING,
+                     entities.map((e) => e.interval).toList(),
+                     codeSourceFromEntities(entities));
+          }
+        },
+        handleUnmatched: (List<int> indices) {
+          List<Interval> intervals =  [
+              classes[0].getChild(indices[0]).interval,
+              classes[1].getChild(indices[1]).interval];
+          addLines(DiffKind.UNMATCHED, intervals);
+        });
+    addLines(DiffKind.MATCHING, classes.map((c) => c.footer).toList());
+  }
+
+  /// Adds the library blocks in [indices] from the corresponding
+  /// [OutputStructure]s, aligning their content.
+  void addMatchingBlocks(List<int> indices) {
+    List<LibraryBlock> blocks = [
+      structures[0].getChild(indices[0]),
+      structures[1].getChild(indices[1])];
+
+    addLines(DiffKind.MATCHING, blocks.map((b) => b.header).toList());
+    align(blocks[0].children, blocks[1].children,
+        match: (a, b) => a.name == b.name,
+        handleSkew: (int listIndex, Interval childRange) {
+          addSkewedChildren(
+              listIndex, blocks[listIndex], childRange);
+        },
+        handleMatched: (List<int> indices) {
+          List<BasicEntity> entities =  [
+              blocks[0].getChild(indices[0]),
+              blocks[1].getChild(indices[1])];
+          if (entities.every((e) => e is LibraryClass)) {
+            addMatchingContainers(entities);
+          } else {
+            addLines(
+                DiffKind.MATCHING,
+                entities.map((e) => e.interval).toList(),
+                codeSourceFromEntities(entities));
+          }
+        },
+        handleUnmatched: (List<int> indices) {
+          List<Interval> intervals =  [
+              blocks[0].getChild(indices[0]).interval,
+              blocks[1].getChild(indices[1]).interval];
+          addLines(DiffKind.UNMATCHED, intervals);
+        });
+    addLines(DiffKind.MATCHING, blocks.map((b) => b.footer).toList());
+  }
+
+  /// Adds the lines of the blocks in [indices] from the corresponding
+  /// [OutputStructure]s.
+  void addUnmatchedBlocks(List<int> indices) {
+    List<LibraryBlock> blocks = [
+       structures[0].getChild(indices[0]),
+       structures[1].getChild(indices[1])];
+    addLines(DiffKind.UNMATCHED, [blocks[0].interval, blocks[1].interval]);
+  }
+
+  /// Computes the diff blocks for [OutputStructure]s.
+  List<DiffBlock> computeBlocks() {
+    addRaw(structures[0].header, structures[1].header);
+
+    align(structures[0].children,
+          structures[1].children,
+          match: (a, b) => a.name == b.name,
+          handleSkew: addBlock,
+          handleMatched: addMatchingBlocks,
+          handleUnmatched: addUnmatchedBlocks);
+
+    addRaw(structures[0].footer, structures[1].footer);
+
+    return blocks;
+  }
+}
+
+/// Creates html lines for code lines in [codeSource]. [sourceFileManager] is
+/// used to read that text from the source URIs.
+List<HtmlPart> codeLinesFromCodeSource(
+    SourceFileManager sourceFileManager,
+    CodeSource codeSource) {
+  List<HtmlPart> lines = <HtmlPart>[];
+  SourceFile sourceFile = sourceFileManager.getSourceFile(codeSource.uri);
+  String elementName = codeSource.name;
+  HtmlLine line = new HtmlLine();
+  line.htmlParts.add(new ConstHtmlPart('<span class="comment">'));
+  line.htmlParts.add(new HtmlText(
+      '${elementName}: ${sourceFile.filename}'));
+  line.htmlParts.add(new ConstHtmlPart('</span>'));
+  lines.add(line);
+  if (codeSource.begin != null) {
+    int startLine = sourceFile.getLine(codeSource.begin);
+    int endLine = sourceFile.getLine(codeSource.end);
+    for (int lineNo = startLine; lineNo <= endLine; lineNo++) {
+      String text = sourceFile.getLineText(lineNo);
+      CodeLine codeLine = new CodeLine(lineNo, sourceFile.getOffset(lineNo, 0));
+      codeLine.codeBuffer.write(text);
+      codeLine.htmlParts.add(new HtmlText(text));
+      lines.add(codeLine);
+    }
+  }
+  return lines;
+}
diff --git a/tests/compiler/dart2js/sourcemaps/diff_view.dart b/tests/compiler/dart2js/sourcemaps/diff_view.dart
new file mode 100644
index 0000000..c58a21e
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/diff_view.dart
@@ -0,0 +1,568 @@
+// 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 sourcemap.diff_view;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/diagnostics/invariant.dart';
+import 'package:compiler/src/elements/elements.dart';
+import 'package:compiler/src/io/position_information.dart';
+import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/io/source_file.dart';
+import 'package:compiler/src/js/js.dart' as js;
+import 'package:compiler/src/js/js_debug.dart';
+
+import 'diff.dart';
+import 'html_parts.dart';
+import 'js_tracer.dart';
+import 'output_structure.dart';
+import 'sourcemap_helper.dart';
+import 'sourcemap_html_helper.dart';
+import 'trace_graph.dart';
+
+const String WITH_SOURCE_INFO_STYLE = 'border: solid 1px #FF8080;';
+const String WITHOUT_SOURCE_INFO_STYLE = 'background-color: #8080FF;';
+const String ADDITIONAL_SOURCE_INFO_STYLE = 'border: solid 1px #80FF80;';
+const String UNUSED_SOURCE_INFO_STYLE = 'border: solid 1px #8080FF;';
+
+main(List<String> args) async {
+  DEBUG_MODE = true;
+  String out = 'out.js.diff_view.html';
+  String filename;
+  List<String> currentOptions = [];
+  List<List<String>> optionSegments = [currentOptions];
+  Map<int, String> loadFrom = {};
+  Map<int, String> saveTo = {};
+  int argGroup = 0;
+  bool addAnnotations = true;
+  for (String arg in args) {
+    if (arg == '--') {
+      currentOptions = [];
+      optionSegments.add(currentOptions);
+      argGroup++;
+    } else if (arg == '-h') {
+      addAnnotations = false;
+      print('Hiding annotations');
+    } else if (arg == '-l') {
+      loadFrom[argGroup] = 'out.js.diff$argGroup.json';
+    } else if (arg.startsWith('--load=')) {
+      loadFrom[argGroup] = arg.substring('--load='.length);
+    } else if (arg == '-s') {
+      saveTo[argGroup] = 'out.js.diff$argGroup.json';
+    } else if (arg.startsWith('--save=')) {
+      saveTo[argGroup] = arg.substring('--save='.length);
+    } else if (arg.startsWith('-o')) {
+      out = arg.substring('-o'.length);
+    } else if (arg.startsWith('--out=')) {
+      out = arg.substring('--out='.length);
+    } else if (arg.startsWith('-')) {
+      currentOptions.add(arg);
+    } else {
+      filename = arg;
+    }
+  }
+  List<String> commonArguments = optionSegments[0];
+  List<List<String>> options = <List<String>>[];
+  if (optionSegments.length == 1) {
+    // Use default options; comparing SSA and CPS output using the new
+    // source information strategy.
+    options.add([USE_NEW_SOURCE_INFO]..addAll(commonArguments));
+    options.add([USE_NEW_SOURCE_INFO, Flags.useCpsIr]..addAll(commonArguments));
+  } else if (optionSegments.length == 2) {
+    // Use alternative options for the second output column.
+    options.add(commonArguments);
+    options.add(optionSegments[1]..addAll(commonArguments));
+  } else {
+    // Use specific options for both output columns.
+    options.add(optionSegments[1]..addAll(commonArguments));
+    options.add(optionSegments[2]..addAll(commonArguments));
+  }
+
+  SourceFileManager sourceFileManager = new IOSourceFileManager(Uri.base);
+  List<AnnotatedOutput> outputs = <AnnotatedOutput>[];
+  for (int i = 0; i < 2; i++) {
+    AnnotatedOutput output;
+    if (loadFrom.containsKey(i)) {
+      output = AnnotatedOutput.loadOutput(loadFrom[i]);
+    } else {
+      print('Compiling ${options[i].join(' ')} $filename');
+      CodeLinesResult result = await computeCodeLines(
+          options[i], filename, addAnnotations: addAnnotations);
+      OutputStructure structure = OutputStructure.parse(result.codeLines);
+      computeEntityCodeSources(result, structure);
+      output = new AnnotatedOutput(
+          filename,
+          options[i],
+          structure,
+          result.coverage.getCoverageReport());
+    }
+    if (saveTo.containsKey(i)) {
+      AnnotatedOutput.saveOutput(output, saveTo[i]);
+    }
+    outputs.add(output);
+  }
+
+  List<DiffBlock> blocks = createDiffBlocks(
+      outputs.map((o) => o.structure).toList(),
+      sourceFileManager);
+
+  outputDiffView(
+      out, outputs, blocks, addAnnotations: addAnnotations);
+}
+
+/// Attaches [CodeSource]s to the entities in [structure] using the
+/// element-to-offset in [result].
+void computeEntityCodeSources(
+    CodeLinesResult result, OutputStructure structure) {
+  result.elementMap.forEach((int line, Element element) {
+    OutputEntity entity = structure.getEntityForLine(line);
+    if (entity != null) {
+      entity.codeSource = codeSourceFromElement(element);
+    }
+  });
+}
+
+/// The structured output of a compilation.
+class AnnotatedOutput {
+  final String filename;
+  final List<String> options;
+  final OutputStructure structure;
+  final String coverage;
+
+  AnnotatedOutput(this.filename, this.options, this.structure, this.coverage);
+
+  List<CodeLine> get codeLines => structure.lines;
+
+  Map toJson() {
+    return {
+      'filename': filename,
+      'options': options,
+      'structure': structure.toJson(),
+      'coverage': coverage,
+    };
+  }
+
+  static AnnotatedOutput fromJson(Map json) {
+    String filename = json['filename'];
+    List<String> options = json['options'];
+    OutputStructure structure = OutputStructure.fromJson(json['structure']);
+    String coverage = json['coverage'];
+    return new AnnotatedOutput(filename, options, structure, coverage);
+  }
+
+  static AnnotatedOutput loadOutput(filename) {
+    AnnotatedOutput output = AnnotatedOutput.fromJson(
+        JSON.decode(new File(filename).readAsStringSync()));
+    print('Output loaded from $filename');
+    return output;
+  }
+
+  static void saveOutput(AnnotatedOutput output, String filename) {
+    if (filename != null) {
+      new File(filename).writeAsStringSync(
+          const JsonEncoder.withIndent('  ').convert(output.toJson()));
+      print('Output saved in $filename');
+    }
+  }
+}
+
+void outputDiffView(
+    String out,
+    List<AnnotatedOutput> outputs,
+    List<DiffBlock> blocks,
+    {bool addAnnotations: true}) {
+  assert(outputs[0].filename == outputs[1].filename);
+  bool usePre = true;
+
+  StringBuffer sb = new StringBuffer();
+  sb.write('''
+<html>
+<head>
+<title>Diff for ${outputs[0].filename}</title>
+<style>
+.lineNumber {
+  font-size: smaller;
+  color: #888;
+}
+.comment {
+  font-size: smaller;
+  color: #888;
+  font-family: initial;
+}
+.header {
+  position: fixed;
+  width: 100%;
+  background-color: #FFFFFF;
+  left: 0px;
+  top: 0px;
+  height: 42px;
+  z-index: 1000;
+}
+.header-table {
+  width: 100%;
+  background-color: #400000;
+  color: #FFFFFF;
+  border-spacing: 0px;
+}
+.header-column {
+  width: 34%;
+}
+.legend {
+  padding: 2px;
+}
+.table {
+  position: absolute;
+  left: 0px;
+  top: 42px;
+  width: 100%;
+  border-spacing: 0px;
+}
+.cell {
+  max-width: 500px;
+  overflow-y: hidden;
+  vertical-align: top;
+  border-top: 1px solid #F0F0F0;
+  border-left: 1px solid #F0F0F0;
+''');
+  if (usePre) {
+    sb.write('''
+  overflow-x: hidden;
+  white-space: pre-wrap;
+''');
+  } else {
+    sb.write('''
+  overflow-x: hidden;
+  padding-left: 100px;
+  text-indent: -100px;
+''');
+  }
+  sb.write('''
+  font-family: monospace;
+  padding: 0px;
+}
+.corresponding1 {
+  background-color: #FFFFE0;
+}
+.corresponding2 {
+  background-color: #EFEFD0;
+}
+.identical1 {
+  background-color: #E0F0E0;
+}
+.identical2 {
+  background-color: #C0E0C0;
+}
+.line {
+  padding-left: 7em;
+  text-indent: -7em;
+  margin: 0px;
+}
+.column0 {
+}
+.column1 {
+}
+.column2 {
+}
+</style>
+</head>
+<body>''');
+
+  sb.write('''
+<div class="header">
+<table class="header-table"><tr>
+<td class="header-column">[${outputs[0].options.join(',')}]</td>
+<td class="header-column">[${outputs[1].options.join(',')}]</td>
+<td class="header-column">Dart code</td>
+</tr></table>
+<div class="legend">
+  <span class="identical1">&nbsp;&nbsp;&nbsp;</span> 
+  <span class="identical2">&nbsp;&nbsp;&nbsp;</span>
+  identical blocks
+  <span class="corresponding1">&nbsp;&nbsp;&nbsp;</span>
+  <span class="corresponding2">&nbsp;&nbsp;&nbsp;</span> 
+  corresponding blocks
+''');
+
+  if (addAnnotations) {
+    sb.write('''
+  <span style="$WITH_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span>
+  <span title="'offset with source information' means that source information 
+is available for an offset which is expected to have a source location 
+attached. This offset has source information as intended.">
+  offset with source information</span>
+  <span style="$WITHOUT_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span>
+  <span title="'offset without source information' means that _no_ source 
+information is available for an offset which was expected to have a source 
+location attached. Source information must be found for this offset.">
+  offset without source information</span>
+  <span style="$ADDITIONAL_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span>
+  <span title="'offset with unneeded source information' means that a source 
+location was attached to an offset which was _not_ expected to have a source
+location attached. The source location should be removed from this offset.">
+  offset with unneeded source information</span>
+  <span style="$UNUSED_SOURCE_INFO_STYLE">&nbsp;&nbsp;&nbsp;</span>
+  <span title="'offset with unused source information' means that source 
+information is available for an offset which is _not_ expected to have a source
+location attached. This source information _could_ be used by a parent AST node
+offset that is an 'offset without source information'."> 
+  offset with unused source information</span>
+''');
+  }
+
+  sb.write('''
+</div></div>
+<table class="table">
+''');
+
+  void addCell(String content) {
+    sb.write('''
+<td class="cell"><pre>
+''');
+    sb.write(content);
+    sb.write('''
+</pre></td>
+''');
+  }
+
+  /// Marker to alternate output colors.
+  bool alternating = false;
+
+  List<HtmlPrintContext> printContexts = <HtmlPrintContext>[];
+  for (int i = 0; i < 2; i++) {
+    int lineNoWidth;
+    if (outputs[i].codeLines.isNotEmpty) {
+      lineNoWidth = '${outputs[i].codeLines.last.lineNo + 1}'.length;
+    }
+    printContexts.add(new HtmlPrintContext(lineNoWidth: lineNoWidth));
+  }
+
+  for (DiffBlock block in blocks) {
+    String className;
+    switch (block.kind) {
+      case DiffKind.UNMATCHED:
+        className = 'cell';
+        break;
+      case DiffKind.MATCHING:
+        className = 'cell corresponding${alternating ? '1' : '2'}';
+        alternating = !alternating;
+        break;
+      case DiffKind.IDENTICAL:
+        className = 'cell identical${alternating ? '1' : '2'}';
+        alternating = !alternating;
+        break;
+    }
+    sb.write('<tr>');
+    for (int index = 0; index < 3; index++) {
+      sb.write('''<td class="$className column$index">''');
+      List<HtmlPart> lines = block.getColumn(index);
+      if (lines.isNotEmpty) {
+        for (HtmlPart line in lines) {
+          sb.write('<p class="line">');
+          if (index < printContexts.length) {
+            line.printHtmlOn(sb, printContexts[index]);
+          } else {
+            line.printHtmlOn(sb, new HtmlPrintContext());
+          }
+          sb.write('</p>');
+        }
+      }
+      sb.write('''</td>''');
+    }
+    sb.write('</tr>');
+  }
+
+  sb.write('''</tr><tr>''');
+
+  addCell(outputs[0].coverage);
+  addCell(outputs[1].coverage);
+
+  sb.write('''
+</table>
+</body>
+</html>
+''');
+
+  new File(out).writeAsStringSync(sb.toString());
+  print('Diff generated in $out');
+}
+
+class CodeLinesResult {
+  final List<CodeLine> codeLines;
+  final Coverage coverage;
+  final Map<int, Element> elementMap;
+  final SourceFileManager sourceFileManager;
+
+  CodeLinesResult(this.codeLines, this.coverage,
+      this.elementMap, this.sourceFileManager);
+}
+
+/// Compute [CodeLine]s and [Coverage] for [filename] using the given [options].
+Future<CodeLinesResult> computeCodeLines(
+    List<String> options,
+    String filename,
+    {bool addAnnotations: true}) async {
+  SourceMapProcessor processor = new SourceMapProcessor(filename);
+  SourceMaps sourceMaps =
+      await processor.process(options, perElement: true, forMain: true);
+
+  const int WITH_SOURCE_INFO = 0;
+  const int WITHOUT_SOURCE_INFO = 1;
+  const int ADDITIONAL_SOURCE_INFO = 2;
+  const int UNUSED_SOURCE_INFO = 3;
+
+  SourceMapInfo info = sourceMaps.mainSourceMapInfo;
+
+  List<CodeLine> codeLines;
+  Coverage coverage = new Coverage();
+  List<Annotation> annotations = <Annotation>[];
+
+  void addAnnotation(int id, int offset, String title) {
+    annotations.add(new Annotation(id, offset, title));
+  }
+
+  String code = info.code;
+  TraceGraph graph = createTraceGraph(info, coverage);
+  if (addAnnotations) {
+    Set<js.Node> mappedNodes = new Set<js.Node>();
+
+    void addSourceLocations(
+        int kind, int offset, List<SourceLocation> locations, String prefix) {
+
+      addAnnotation(kind, offset,
+          '${prefix}${locations
+              .where((l) => l != null)
+              .map((l) => l.shortText)
+              .join('\n')}');
+    }
+
+    bool addSourceLocationsForNode(int kind, js.Node node, String prefix) {
+      Map<int, List<SourceLocation>> locations = info.nodeMap[node];
+      if (locations == null || locations.isEmpty) {
+        return false;
+      }
+      locations.forEach(
+          (int offset, List<SourceLocation> locations) {
+        addSourceLocations(kind, offset, locations,
+            '${prefix}\n${truncate(nodeToString(node), 80)}\n');
+      });
+      mappedNodes.add(node);
+      return true;
+    }
+
+
+    for (TraceStep step in graph.steps) {
+      String title = '${step.id}:${step.kind}:${step.offset}';
+      if (!addSourceLocationsForNode(WITH_SOURCE_INFO, step.node, title)) {
+        int offset;
+        if (options.contains(USE_NEW_SOURCE_INFO)) {
+          offset = step.offset.subexpressionOffset;
+        } else {
+          offset = info.jsCodePositions[step.node].startPosition;
+        }
+        if (offset != null) {
+          addAnnotation(WITHOUT_SOURCE_INFO, offset, title);
+        }
+      }
+    }
+    for (js.Node node in info.nodeMap.nodes) {
+      if (!mappedNodes.contains(node)) {
+        addSourceLocationsForNode(ADDITIONAL_SOURCE_INFO, node, '');
+      }
+    }
+    SourceLocationCollector collector = new SourceLocationCollector();
+    info.node.accept(collector);
+    collector.sourceLocations.forEach(
+        (js.Node node, List<SourceLocation> locations) {
+      if (!mappedNodes.contains(node)) {
+        int offset = info.jsCodePositions[node].startPosition;
+        addSourceLocations(UNUSED_SOURCE_INFO, offset, locations, '');
+      }
+    });
+  }
+
+  StringSourceFile sourceFile = new StringSourceFile.fromName(filename, code);
+  Map<int, Element> elementMap = <int, Element>{};
+  sourceMaps.elementSourceMapInfos.forEach(
+      (Element element, SourceMapInfo info) {
+    CodePosition position = info.jsCodePositions[info.node];
+    elementMap[sourceFile.getLine(position.startPosition)] = element;
+  });
+
+  codeLines = convertAnnotatedCodeToCodeLines(
+      code,
+      annotations,
+      colorScheme: new CustomColorScheme(
+        single: (int id) {
+          if (id == WITH_SOURCE_INFO) {
+            return WITH_SOURCE_INFO_STYLE;
+          } else if (id == ADDITIONAL_SOURCE_INFO) {
+            return ADDITIONAL_SOURCE_INFO_STYLE;
+          } else if (id == UNUSED_SOURCE_INFO) {
+            return UNUSED_SOURCE_INFO_STYLE;
+          }
+          return WITHOUT_SOURCE_INFO_STYLE;
+        },
+        multi: (List ids) {
+          if (ids.contains(WITH_SOURCE_INFO)) {
+            return WITH_SOURCE_INFO_STYLE;
+          } else if (ids.contains(ADDITIONAL_SOURCE_INFO)) {
+            return ADDITIONAL_SOURCE_INFO_STYLE;
+          } else if (ids.contains(UNUSED_SOURCE_INFO)) {
+            return UNUSED_SOURCE_INFO_STYLE;
+          }
+          return WITHOUT_SOURCE_INFO_STYLE;
+        }
+      ));
+  return new CodeLinesResult(codeLines, coverage, elementMap,
+      sourceMaps.sourceFileManager);
+}
+
+/// Visitor that computes a map from [js.Node]s to all attached source
+/// locations.
+class SourceLocationCollector extends js.BaseVisitor {
+  Map<js.Node, List<SourceLocation>> sourceLocations =
+      <js.Node, List<SourceLocation>>{};
+
+  @override
+  visitNode(js.Node node) {
+    SourceInformation sourceInformation = node.sourceInformation;
+    if (sourceInformation != null) {
+      sourceLocations[node] = sourceInformation.sourceLocations;
+    }
+    node.visitChildren(this);
+  }
+}
+
+/// Compute a [CodeSource] for source span of [element].
+CodeSource codeSourceFromElement(Element element) {
+  CodeKind kind;
+  Uri uri;
+  String name;
+  int begin;
+  int end;
+  if (element.isLibrary) {
+    LibraryElement library = element;
+    kind = CodeKind.LIBRARY;
+    name = library.libraryOrScriptName;
+    uri = library.entryCompilationUnit.script.resourceUri;
+  } else if (element.isClass) {
+    kind = CodeKind.CLASS;
+    name = element.name;
+    uri = element.compilationUnit.script.resourceUri;
+  } else {
+    AstElement astElement = element.implementation;
+    kind = CodeKind.MEMBER;
+    uri = astElement.compilationUnit.script.resourceUri;
+    name = computeElementNameForSourceMaps(astElement);
+    if (astElement.hasNode) {
+      begin = astElement.node.getBeginToken().charOffset;
+      end = astElement.node.getEndToken().charEnd;
+    }
+  }
+  return new CodeSource(kind, uri, name, begin, end);
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/html_parts.dart b/tests/compiler/dart2js/sourcemaps/html_parts.dart
new file mode 100644
index 0000000..6ddf95e
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/html_parts.dart
@@ -0,0 +1,243 @@
+// 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 sourcemap.html_parts;
+
+import 'sourcemap_html_helper.dart';
+
+class HtmlPrintContext {
+  final int lineNoWidth;
+  final bool usePre;
+
+  HtmlPrintContext({
+    this.lineNoWidth,
+    this.usePre: true});
+}
+
+enum HtmlPartKind {
+  CODE,
+  LINE,
+  CONST,
+  NEWLINE,
+  TEXT,
+  ANCHOR,
+}
+
+abstract class HtmlPart {
+  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {}
+
+  toJson();
+
+  static HtmlPart fromJson(json) {
+    if (json is String) {
+      return new ConstHtmlPart(json);
+    } else {
+      switch (HtmlPartKind.values[json['kind']]) {
+        case HtmlPartKind.LINE:
+          return HtmlLine.fromJson(json);
+        case HtmlPartKind.CODE:
+          return CodeLine.fromJson(json);
+        case HtmlPartKind.CONST:
+          return ConstHtmlPart.fromJson(json);
+        case HtmlPartKind.NEWLINE:
+          return const NewLine();
+        case HtmlPartKind.TEXT:
+          return HtmlText.fromJson(json);
+        case HtmlPartKind.ANCHOR:
+          return AnchorHtmlPart.fromJson(json);
+      }
+    }
+  }
+}
+
+class ConstHtmlPart implements HtmlPart {
+  final String html;
+
+  const ConstHtmlPart(this.html);
+
+  @override
+  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
+    buffer.write(html);
+  }
+
+  toJson() {
+    return {'kind': HtmlPartKind.CONST.index, 'html': html};
+  }
+
+  static ConstHtmlPart fromJson(Map json) {
+    return new ConstHtmlPart(json['html']);
+  }
+}
+
+class NewLine implements HtmlPart {
+  const NewLine();
+
+  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
+    if (context.usePre) {
+      buffer.write('\n');
+    } else {
+      buffer.write('<br/>');
+    }
+  }
+
+  toJson() {
+    return {'kind': HtmlPartKind.NEWLINE.index};
+  }
+}
+
+class HtmlText implements HtmlPart {
+  final String text;
+
+  const HtmlText(this.text);
+
+  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
+    String escaped = escape(text);
+    buffer.write(escaped);
+  }
+
+  toJson() {
+    return {'kind': HtmlPartKind.TEXT.index, 'text': text};
+  }
+
+  static HtmlText fromJson(Map json) {
+    return new HtmlText(json['text']);
+  }
+}
+
+class AnchorHtmlPart implements HtmlPart {
+  final String color;
+  final String name;
+  final String href;
+  final String title;
+  final String onclick;
+  final String onmouseover;
+  final String onmouseout;
+
+  AnchorHtmlPart({
+    this.color,
+    this.name,
+    this.href,
+    this.title,
+    this.onclick,
+    this.onmouseover,
+    this.onmouseout});
+
+  @override
+  void printHtmlOn(StringBuffer buffer, HtmlPrintContext context) {
+    buffer.write('<a');
+    if (href != null) {
+      buffer.write(' href="${href}"');
+    }
+    if (name != null) {
+      buffer.write(' name="${name}"');
+    }
+    if (title != null) {
+      buffer.write(' title="${escape(title)}"');
+    }
+    buffer.write(' style="${color}"');
+    if (onclick != null) {
+      buffer.write(' onclick="${onclick}"');
+    }
+    if (onmouseover != null) {
+      buffer.write(' onmouseover="${onmouseover}"');
+    }
+    if (onmouseout != null) {
+      buffer.write(' onmouseout="${onmouseout}"');
+    }
+    buffer.write('>');
+  }
+
+  toJson() {
+    return {
+      'kind': HtmlPartKind.ANCHOR.index,
+      'color': color,
+      'name': name,
+      'href': href,
+      'title': title,
+      'onclick': onclick,
+      'onmouseover': onmouseover,
+      'onmouseout': onmouseout};
+  }
+
+  static AnchorHtmlPart fromJson(Map json) {
+    return new AnchorHtmlPart(
+        color: json['color'],
+        name: json['name'],
+        href: json['href'],
+        title: json['title'],
+        onclick: json['onclick'],
+        onmouseover: json['onmouseover'],
+        onmouseout: json['onmouseout']);
+  }
+}
+
+class HtmlLine implements HtmlPart {
+  final List<HtmlPart> htmlParts = <HtmlPart>[];
+
+  @override
+  void printHtmlOn(StringBuffer htmlBuffer, HtmlPrintContext context) {
+    for (HtmlPart part in htmlParts) {
+      part.printHtmlOn(htmlBuffer, context);
+    }
+  }
+
+  Map toJson() {
+    return {
+      'kind': HtmlPartKind.LINE.index,
+      'html': htmlParts.map((p) => p.toJson()).toList(),
+    };
+  }
+
+  static CodeLine fromJson(Map json) {
+    HtmlLine line = new HtmlLine();
+    json['html'].forEach((part) => line.htmlParts.add(HtmlPart.fromJson(part)));
+    return line;
+  }
+}
+
+class CodeLine extends HtmlLine {
+  final int lineNo;
+  final int offset;
+  final StringBuffer codeBuffer = new StringBuffer();
+  final List<HtmlPart> htmlParts = <HtmlPart>[];
+  // TODO(johnniwinther): Make annotations serializable.
+  final List<Annotation> annotations = <Annotation>[];
+  String _code;
+
+  CodeLine(this.lineNo, this.offset);
+
+  String get code {
+    if (_code == null) {
+      _code = codeBuffer.toString();
+    }
+    return _code;
+  }
+
+  @override
+  void printHtmlOn(StringBuffer htmlBuffer, HtmlPrintContext context) {
+    htmlBuffer.write(lineNumber(
+        lineNo, width: context.lineNoWidth, useNbsp: !context.usePre));
+    for (HtmlPart part in htmlParts) {
+      part.printHtmlOn(htmlBuffer, context);
+    }
+  }
+
+  Map toJson() {
+    return {
+      'kind': HtmlPartKind.CODE.index,
+      'lineNo': lineNo,
+      'offset': offset,
+      'code': code,
+      'html': htmlParts.map((p) => p.toJson()).toList(),
+    };
+  }
+
+  static CodeLine fromJson(Map json) {
+    CodeLine line = new CodeLine(json['lineNo'], json['offset']);
+    line.codeBuffer.write(json['code']);
+    json['html'].forEach((part) => line.htmlParts.add(HtmlPart.fromJson(part)));
+    return line;
+  }
+}
+
diff --git a/tests/compiler/dart2js/sourcemaps/js_tracer.dart b/tests/compiler/dart2js/sourcemaps/js_tracer.dart
new file mode 100644
index 0000000..4ea4e91
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/js_tracer.dart
@@ -0,0 +1,144 @@
+// 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 sourcemap.js_tracer;
+
+import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/io/position_information.dart';
+import 'package:compiler/src/js/js.dart' as js;
+import 'sourcemap_helper.dart';
+import 'trace_graph.dart';
+
+/// Create a [TraceGraph] for [info] registering usage in [coverage].
+TraceGraph createTraceGraph(SourceMapInfo info, Coverage coverage) {
+  TraceGraph graph = new TraceGraph();
+  TraceListener listener = new StepTraceListener(graph);
+  CodePositionMap codePositions =
+      new CodePositionCoverage(info.jsCodePositions, coverage);
+  JavaScriptTracer tracer = new JavaScriptTracer(
+      codePositions, [new CoverageListener(coverage), listener]);
+  info.node.accept(tracer);
+  return graph;
+}
+
+class StepTraceListener extends TraceListener
+    with NodeToSourceInformationMixin {
+  Map<js.Node, TraceStep> steppableMap = <js.Node, TraceStep>{};
+  final TraceGraph graph;
+
+  StepTraceListener(this.graph);
+
+  @override
+  void onStep(js.Node node, Offset offset, StepKind kind) {
+    SourceInformation sourceInformation = computeSourceInformation(node);
+    SourcePositionKind sourcePositionKind = SourcePositionKind.START;
+    List text = [node];
+    switch (kind) {
+      case StepKind.FUN:
+        sourcePositionKind = SourcePositionKind.INNER;
+        text = ['<exit>'];
+        break;
+      case StepKind.CALL:
+        CallPosition callPosition =
+            CallPosition.getSemanticPositionForCall(node);
+        sourcePositionKind = callPosition.sourcePositionKind;
+        break;
+      case StepKind.NEW:
+      case StepKind.RETURN:
+      case StepKind.BREAK:
+      case StepKind.CONTINUE:
+      case StepKind.THROW:
+      case StepKind.EXPRESSION_STATEMENT:
+        break;
+      case StepKind.IF_CONDITION:
+        js.If ifNode = node;
+        text = ['if(', ifNode.condition, ') ...'];
+        break;
+      case StepKind.FOR_INITIALIZER:
+        js.For forNode = node;
+        text = ['for(', forNode.init, '; ...) ...'];
+        break;
+      case StepKind.FOR_CONDITION:
+        js.For forNode = node;
+        text = ['for(...;', forNode.condition, '; ...) ...'];
+        break;
+      case StepKind.FOR_UPDATE:
+        js.For forNode = node;
+        text = ['for(...; ...', forNode.update, ') ...'];
+        break;
+      case StepKind.WHILE_CONDITION:
+        js.While whileNode = node;
+        text = ['while(', whileNode.condition, ') ...'];
+        break;
+      case StepKind.DO_CONDITION:
+        js.Do doNode = node;
+        text = ['do {... } (', doNode.condition, ')'];
+        break;
+      case StepKind.SWITCH_EXPRESSION:
+        js.Switch switchNode = node;
+        text = ['switch(', switchNode.key, ') ...'];
+        break;
+
+    }
+    createTraceStep(
+        kind,
+        node,
+        offset: offset,
+        sourceLocation: getSourceLocation(
+            sourceInformation, sourcePositionKind),
+        text: text);
+  }
+
+  void createTraceStep(
+      StepKind kind,
+      js.Node node,
+      {Offset offset,
+       List text,
+       String note,
+       SourceLocation sourceLocation}) {
+    int id = steppableMap.length;
+
+    if (text == null) {
+      text = [node];
+    }
+
+    TraceStep step = new TraceStep(
+        kind,
+        id,
+        node,
+        offset,
+        text,
+        sourceLocation);
+    graph.addStep(step);
+
+    steppableMap[node] = step;
+  }
+
+
+  void pushBranch(BranchKind kind, [value]) {
+    var branch;
+    switch (kind) {
+      case BranchKind.CONDITION:
+        branch = value ? 't' : 'f';
+        break;
+      case BranchKind.LOOP:
+        branch = 'l';
+        break;
+      case BranchKind.CATCH:
+        branch = 'c';
+        break;
+      case BranchKind.FINALLY:
+        branch = 'F';
+        break;
+      case BranchKind.CASE:
+        branch = '$value';
+        break;
+    }
+    graph.pushBranch(branch);
+  }
+
+  void popBranch() {
+    graph.popBranch();
+  }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/output_structure.dart b/tests/compiler/dart2js/sourcemaps/output_structure.dart
new file mode 100644
index 0000000..4962ba9
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/output_structure.dart
@@ -0,0 +1,668 @@
+// 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 sourcemap.output_structure;
+
+import 'html_parts.dart' show
+    CodeLine;
+
+// Constants used to identify the subsection of the JavaScript output. These
+// are specifically for the unminified full_emitter output.
+const String HEAD = '  var dart = [';
+const String TAIL = '  }], ';
+const String END = '  setupProgram(dart';
+
+final RegExp TOP_LEVEL_VALUE = new RegExp(r'^    (".+?"):');
+final RegExp TOP_LEVEL_FUNCTION =
+    new RegExp(r'^    ([a-zA-Z0-9_$]+): \[?function');
+final RegExp TOP_LEVEL_CLASS = new RegExp(r'^    ([a-zA-Z0-9_$]+): \[?\{');
+
+final RegExp STATICS = new RegExp(r'^      static:');
+final RegExp MEMBER_VALUE = new RegExp(r'^      (".+?"):');
+final RegExp MEMBER_FUNCTION =
+    new RegExp(r'^      ([a-zA-Z0-9_$]+): \[?function');
+final RegExp MEMBER_OBJECT = new RegExp(r'^      ([a-zA-Z0-9_$]+): \[?\{');
+
+final RegExp STATIC_FUNCTION =
+    new RegExp(r'^        ([a-zA-Z0-9_$]+): \[?function');
+
+/// Subrange of the JavaScript output.
+abstract class OutputEntity {
+  Interval get interval;
+  Interval get header;
+  Interval get footer;
+
+  bool get canHaveChildren => false;
+
+  List<OutputEntity> get children;
+
+  CodeSource codeSource;
+
+  Interval getChildInterval(Interval childIndex) {
+    return new Interval(
+        children[childIndex.from].interval.from,
+        children[childIndex.to - 1].interval.to);
+
+  }
+
+  OutputEntity getChild(int index) {
+    return children[index];
+  }
+
+  accept(OutputVisitor visitor, arg);
+
+  EntityKind get kind;
+
+  Map toJson();
+
+  OutputEntity getEntityForLine(int line);
+}
+
+enum EntityKind {
+  STRUCTURE,
+  LIBRARY,
+  CLASS,
+  TOP_LEVEL_FUNCTION,
+  TOP_LEVEL_VALUE,
+  MEMBER_FUNCTION,
+  MEMBER_OBJECT,
+  MEMBER_VALUE,
+  STATICS,
+  STATIC_FUNCTION,
+}
+
+abstract class OutputVisitor<R, A> {
+  R visitStructure(OutputStructure entity, A arg);
+  R visitLibrary(LibraryBlock entity, A arg);
+  R visitClass(LibraryClass entity, A arg);
+  R visitTopLevelFunction(TopLevelFunction entity, A arg);
+  R visitTopLevelValue(TopLevelValue entity, A arg);
+  R visitMemberObject(MemberObject entity, A arg);
+  R visitMemberFunction(MemberFunction entity, A arg);
+  R visitMemberValue(MemberValue entity, A arg);
+  R visitStatics(Statics entity, A arg);
+  R visitStaticFunction(StaticFunction entity, A arg);
+}
+
+abstract class BaseOutputVisitor<R, A> extends OutputVisitor<R, A> {
+  R visitEntity(OutputEntity entity, A arg) => null;
+
+  R visitStructure(OutputStructure entity, A arg) => visitEntity(entity, arg);
+  R visitLibrary(LibraryBlock entity, A arg) => visitEntity(entity, arg);
+  R visitClass(LibraryClass entity, A arg) => visitEntity(entity, arg);
+
+  R visitMember(BasicEntity entity, A arg) => visitEntity(entity, arg);
+
+  R visitTopLevelMember(BasicEntity entity, A arg) => visitMember(entity, arg);
+
+  R visitTopLevelFunction(TopLevelFunction entity, A arg) {
+    return visitTopLevelMember(entity, arg);
+  }
+
+  R visitTopLevelValue(TopLevelValue entity, A arg) {
+    return visitTopLevelMember(entity, arg);
+  }
+
+  R visitClassMember(BasicEntity entity, A arg) => visitMember(entity, arg);
+
+  R visitMemberObject(MemberObject entity, A arg) {
+    return visitClassMember(entity, arg);
+  }
+
+  R visitMemberFunction(MemberFunction entity, A arg) {
+    return visitClassMember(entity, arg);
+  }
+
+  R visitMemberValue(MemberValue entity, A arg) {
+    return visitClassMember(entity, arg);
+  }
+
+  R visitStatics(Statics entity, A arg) {
+    return visitClassMember(entity, arg);
+  }
+
+  R visitStaticFunction(StaticFunction entity, A arg) {
+    return visitClassMember(entity, arg);
+  }
+}
+
+/// The whole JavaScript output.
+class OutputStructure extends OutputEntity {
+  final List<CodeLine> lines;
+  final int headerEnd;
+  final int footerStart;
+  final List<LibraryBlock> children;
+
+  OutputStructure(
+      this.lines,
+      this.headerEnd,
+      this.footerStart,
+      this.children);
+
+  @override
+  EntityKind get kind => EntityKind.STRUCTURE;
+
+  Interval get interval => new Interval(0, lines.length);
+
+  Interval get header => new Interval(0, headerEnd);
+
+  Interval get footer => new Interval(footerStart, lines.length);
+
+  bool get canHaveChildren => true;
+
+  OutputEntity getEntityForLine(int line) {
+    if (line < headerEnd || line >= footerStart) {
+      return this;
+    }
+    for (LibraryBlock library in children) {
+      if (library.interval.contains(line)) {
+        return library.getEntityForLine(line);
+      }
+    }
+    return null;
+  }
+
+  /// Compute the structure of the JavaScript [lines].
+  static OutputStructure parse(List<CodeLine> lines) {
+
+    int findHeaderStart(List<CodeLine> lines) {
+      int index = 0;
+      for (CodeLine line in lines) {
+        if (line.code.startsWith(HEAD)) {
+          return index;
+        }
+        index++;
+      }
+      return lines.length;
+    }
+
+    int findHeaderEnd(int start, List<CodeLine> lines) {
+      int index = start;
+      for (CodeLine line in lines.skip(start)) {
+        if (line.code.startsWith(END)) {
+          return index;
+        }
+        index++;
+      }
+      return lines.length;
+    }
+
+    String readHeader(CodeLine line) {
+      String code = line.code;
+      String ssaLineHeader;
+      if (code.startsWith(HEAD)) {
+        return code.substring(HEAD.length);
+      } else if (code.startsWith(TAIL)) {
+        return code.substring(TAIL.length);
+      }
+      return null;
+    }
+
+    List<LibraryBlock> computeHeaderMap(
+        List<CodeLine> lines, int start, int end) {
+      List<LibraryBlock> libraryBlocks = <LibraryBlock>[];
+      LibraryBlock current;
+      for (int index = start; index < end; index++) {
+        String header = readHeader(lines[index]);
+        if (header != null) {
+          if (current != null) {
+            current.to = index;
+          }
+          libraryBlocks.add(current = new LibraryBlock(header, index));
+        }
+      }
+      if (current != null) {
+        current.to = end;
+      }
+      return libraryBlocks;
+    }
+
+    int headerEnd = findHeaderStart(lines);
+    int footerStart = findHeaderEnd(headerEnd, lines);
+    List<LibraryBlock> libraryBlocks =
+        computeHeaderMap(lines, headerEnd, footerStart);
+    for (LibraryBlock block in libraryBlocks) {
+      block.preprocess(lines);
+    }
+
+    return new OutputStructure(
+        lines, headerEnd, footerStart, libraryBlocks);
+  }
+
+  accept(OutputVisitor visitor, arg) => visitor.visitStructure(this, arg);
+
+  @override
+  Map toJson() {
+    return {
+      'lines': lines.map((line) => line.toJson()).toList(),
+      'headerEnd': headerEnd,
+      'footerStart': footerStart,
+      'children': children.map((child) => child.toJson()).toList(),
+    };
+  }
+
+  static OutputStructure fromJson(Map json) {
+    List<CodeLine> lines = json['lines'].map(CodeLine.fromJson).toList();
+    int headerEnd = json['headerEnd'];
+    int footerStart = json['footerStart'];
+    List<LibraryBlock> children =
+        json['children'].map(AbstractEntity.fromJson).toList();
+    return new OutputStructure(lines, headerEnd, footerStart, children);
+  }
+}
+
+abstract class AbstractEntity extends OutputEntity {
+  final String name;
+  final int from;
+  int to;
+
+  AbstractEntity(this.name, this.from);
+
+  Interval get interval => new Interval(from, to);
+
+  @override
+  Map toJson() {
+    return {
+      'kind': kind.index,
+      'name': name,
+      'from': from,
+      'to': to,
+      'children': children.map((child) => child.toJson()).toList(),
+      'codeSource': codeSource != null ? codeSource.toJson() : null,
+    };
+  }
+
+  static AbstractEntity fromJson(Map json) {
+    EntityKind kind = EntityKind.values[json['kind']];
+    String name = json['name'];
+    int from = json['from'];
+    int to = json['to'];
+    CodeSource codeSource = CodeSource.fromJson(json['codeSource']);
+
+    switch (kind) {
+      case EntityKind.STRUCTURE:
+        throw new StateError('Unexpected entity kind $kind');
+      case EntityKind.LIBRARY:
+        LibraryBlock lib = new LibraryBlock(name, from)
+          ..to = to
+          ..codeSource = codeSource;
+        json['children'].forEach((child) => lib.children.add(fromJson(child)));
+        return lib;
+      case EntityKind.CLASS:
+        LibraryClass cls = new LibraryClass(name, from)
+            ..to = to
+            ..codeSource = codeSource;
+        json['children'].forEach((child) => cls.children.add(fromJson(child)));
+        return cls;
+      case EntityKind.TOP_LEVEL_FUNCTION:
+        return new TopLevelFunction(name, from)
+            ..to = to
+            ..codeSource = codeSource;
+      case EntityKind.TOP_LEVEL_VALUE:
+        return new TopLevelValue(name, from)
+            ..to = to
+            ..codeSource = codeSource;
+      case EntityKind.MEMBER_FUNCTION:
+        return new MemberFunction(name, from)
+            ..to = to
+            ..codeSource = codeSource;
+      case EntityKind.MEMBER_OBJECT:
+        return new MemberObject(name, from)
+            ..to = to
+            ..codeSource = codeSource;
+      case EntityKind.MEMBER_VALUE:
+        return new MemberValue(name, from)
+            ..to = to
+            ..codeSource = codeSource;
+      case EntityKind.STATICS:
+        Statics statics = new Statics(from)
+            ..to = to
+            ..codeSource = codeSource;
+        json['children'].forEach(
+            (child) => statics.children.add(fromJson(child)));
+        return statics;
+      case EntityKind.STATIC_FUNCTION:
+        return new StaticFunction(name, from)
+            ..to = to
+            ..codeSource = codeSource;
+    }
+  }
+}
+
+/// A block defining the content of a Dart library.
+class LibraryBlock extends AbstractEntity {
+  List<BasicEntity> children = <BasicEntity>[];
+  int get headerEnd => from + 2;
+  int get footerStart => to - 1;
+
+  LibraryBlock(String name, int from) : super(name, from);
+
+  @override
+  EntityKind get kind => EntityKind.LIBRARY;
+
+  Interval get header => new Interval(from, headerEnd);
+
+  Interval get footer => new Interval(footerStart, to);
+
+  bool get canHaveChildren => true;
+
+  void preprocess(List<CodeLine> lines) {
+    int index = headerEnd;
+    BasicEntity current;
+    while (index < footerStart) {
+      String line = lines[index].code;
+      BasicEntity next;
+      Match matchFunction = TOP_LEVEL_FUNCTION.firstMatch(line);
+      if (matchFunction != null) {
+        next = new TopLevelFunction(matchFunction.group(1), index);
+      } else {
+        Match matchClass = TOP_LEVEL_CLASS.firstMatch(line);
+        if (matchClass != null) {
+          next = new LibraryClass(matchClass.group(1), index);
+        } else {
+          Match matchValue = TOP_LEVEL_VALUE.firstMatch(line);
+          if (matchValue != null) {
+            next = new TopLevelValue(matchValue.group(1), index);
+          }
+        }
+      }
+      if (next != null) {
+        if (current != null) {
+          current.to = index;
+        }
+        children.add(current = next);
+      } else if (index == headerEnd) {
+        throw 'Failed to match first library block line:\n$line';
+      }
+
+      index++;
+    }
+    if (current != null) {
+      current.to = footerStart;
+    }
+
+    for (BasicEntity entity in children) {
+      entity.preprocess(lines);
+    }
+  }
+
+  accept(OutputVisitor visitor, arg) => visitor.visitLibrary(this, arg);
+
+  OutputEntity getEntityForLine(int line) {
+    if (line < headerEnd || line >= footerStart) {
+      return this;
+    }
+    for (BasicEntity child in children) {
+      if (child.interval.contains(line)) {
+        return child.getEntityForLine(line);
+      }
+    }
+    return null;
+  }
+}
+
+/// A simple member of a library or class.
+abstract class BasicEntity extends AbstractEntity {
+  BasicEntity(String name, int from) : super(name, from);
+
+  Interval get header => new Interval(from, to);
+
+  Interval get footer => new Interval(to, to);
+
+  List<OutputEntity> get children => const <OutputEntity>[];
+
+  void preprocess(List<CodeLine> lines) {}
+
+  @override
+  OutputEntity getEntityForLine(int line) {
+    if (interval.contains(line)) {
+      return this;
+    }
+    return null;
+  }
+}
+
+class TopLevelFunction extends BasicEntity {
+  TopLevelFunction(String name, int from) : super(name, from);
+
+  @override
+  EntityKind get kind => EntityKind.TOP_LEVEL_FUNCTION;
+
+  accept(OutputVisitor visitor, arg) {
+    return visitor.visitTopLevelFunction(this, arg);
+  }
+}
+
+class TopLevelValue extends BasicEntity {
+  TopLevelValue(String name, int from) : super(name, from);
+
+  @override
+  EntityKind get kind => EntityKind.TOP_LEVEL_VALUE;
+
+  accept(OutputVisitor visitor, arg) {
+    return visitor.visitTopLevelValue(this, arg);
+  }
+}
+
+/// A block defining a Dart class.
+class LibraryClass extends BasicEntity {
+  List<BasicEntity> children = <BasicEntity>[];
+  int get headerEnd => from + 1;
+  int get footerStart => to - 1;
+
+  LibraryClass(String name, int from) : super(name, from);
+
+  @override
+  EntityKind get kind => EntityKind.CLASS;
+
+  Interval get header => new Interval(from, headerEnd);
+
+  Interval get footer => new Interval(footerStart, to);
+
+  bool get canHaveChildren => true;
+
+  void preprocess(List<CodeLine> lines) {
+    int index = headerEnd;
+    BasicEntity current;
+    while (index < footerStart) {
+      String line = lines[index].code;
+      BasicEntity next;
+      Match match = MEMBER_FUNCTION.firstMatch(line);
+      if (match != null) {
+        next = new MemberFunction(match.group(1), index);
+      } else {
+        match = STATICS.firstMatch(line);
+        if (match != null) {
+          next = new Statics(index);
+        } else {
+          match = MEMBER_OBJECT.firstMatch(line);
+          if (match != null) {
+            next = new MemberObject(match.group(1), index);
+          } else {
+            match = MEMBER_VALUE.firstMatch(line);
+            if (match != null) {
+              next = new MemberValue(match.group(1), index);
+            }
+          }
+        }
+      }
+      if (next != null) {
+        if (current != null) {
+          current.to = index;
+        }
+        children.add(current = next);
+      } else if (index == headerEnd) {
+        throw 'Failed to match first library block line:\n$line';
+      }
+
+      index++;
+    }
+    if (current != null) {
+      current.to = footerStart;
+    }
+
+    for (BasicEntity entity in children) {
+      entity.preprocess(lines);
+    }
+  }
+
+  accept(OutputVisitor visitor, arg) => visitor.visitClass(this, arg);
+
+  OutputEntity getEntityForLine(int line) {
+    if (line < headerEnd || line >= footerStart) {
+      return this;
+    }
+    for (BasicEntity child in children) {
+      if (child.interval.contains(line)) {
+        return child.getEntityForLine(line);
+      }
+    }
+    return null;
+  }
+}
+
+/// A block defining static members of a Dart class.
+class Statics extends BasicEntity {
+  List<BasicEntity> children = <BasicEntity>[];
+  int get headerEnd => from + 1;
+  int get footerStart => to - 1;
+
+  Statics(int from) : super('statics', from);
+
+  @override
+  EntityKind get kind => EntityKind.STATICS;
+
+  Interval get header => new Interval(from, headerEnd);
+
+  Interval get footer => new Interval(footerStart, to);
+
+  bool get canHaveChildren => true;
+
+  void preprocess(List<CodeLine> lines) {
+    int index = headerEnd;
+    BasicEntity current;
+    while (index < footerStart) {
+      String line = lines[index].code;
+      BasicEntity next;
+      Match matchFunction = STATIC_FUNCTION.firstMatch(line);
+      if (matchFunction != null) {
+        next = new MemberFunction(matchFunction.group(1), index);
+      }
+      if (next != null) {
+        if (current != null) {
+          current.to = index;
+        }
+        children.add(current = next);
+      } else if (index == headerEnd) {
+        throw 'Failed to match first statics line:\n$line';
+      }
+
+      index++;
+    }
+    if (current != null) {
+      current.to = footerStart;
+    }
+  }
+
+  accept(OutputVisitor visitor, arg) => visitor.visitStatics(this, arg);
+
+  OutputEntity getEntityForLine(int line) {
+    if (line < headerEnd || line >= footerStart) {
+      return this;
+    }
+    for (BasicEntity child in children) {
+      if (child.interval.contains(line)) {
+        return child.getEntityForLine(line);
+      }
+    }
+    return null;
+  }
+}
+
+class MemberFunction extends BasicEntity {
+  MemberFunction(String name, int from) : super(name, from);
+
+  @override
+  EntityKind get kind => EntityKind.MEMBER_FUNCTION;
+
+  accept(OutputVisitor visitor, arg) => visitor.visitMemberFunction(this, arg);
+}
+
+class MemberObject extends BasicEntity {
+  MemberObject(String name, int from) : super(name, from);
+
+  @override
+  EntityKind get kind => EntityKind.MEMBER_OBJECT;
+
+  accept(OutputVisitor visitor, arg) => visitor.visitMemberObject(this, arg);
+}
+
+class MemberValue extends BasicEntity {
+  MemberValue(String name, int from) : super(name, from);
+
+  @override
+  EntityKind get kind => EntityKind.MEMBER_VALUE;
+
+  accept(OutputVisitor visitor, arg) => visitor.visitMemberValue(this, arg);
+}
+
+class StaticFunction extends BasicEntity {
+  StaticFunction(String name, int from) : super(name, from);
+
+  @override
+  EntityKind get kind => EntityKind.STATIC_FUNCTION;
+
+  accept(OutputVisitor visitor, arg) => visitor.visitStaticFunction(this, arg);
+}
+
+class Interval {
+  final int from;
+  final int to;
+
+  const Interval(this.from, this.to);
+
+  int get length => to - from;
+
+  bool contains(int value) {
+    return from <= value && value < to;
+  }
+}
+
+enum CodeKind {
+  LIBRARY,
+  CLASS,
+  MEMBER,
+}
+
+class CodeSource {
+  final CodeKind kind;
+  final Uri uri;
+  final String name;
+  final int begin;
+  final int end;
+
+  CodeSource(this.kind, this.uri, this.name, this.begin, this.end);
+
+  String toString() => '${toJson()}';
+
+  Map toJson() {
+    return {
+      'kind': kind.index,
+      'uri': uri.toString(),
+      'name': name,
+      'begin': begin,
+      'end': end,
+    };
+  }
+
+  static CodeSource fromJson(Map json) {
+    if (json == null) return null;
+    return new CodeSource(
+        CodeKind.values[json['kind']],
+        Uri.parse(json['uri']),
+        json['name'],
+        json['begin'],
+        json['end']);
+  }
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart b/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart
index 5149b87..d935150 100644
--- a/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart
+++ b/tests/compiler/dart2js/sourcemaps/source_mapping_tester.dart
@@ -95,12 +95,12 @@
     List<String> options,
     {bool verbose: true}) async {
   SourceMapProcessor processor = new SourceMapProcessor(filename);
-  List<SourceMapInfo> infoList = await processor.process(
+  SourceMaps sourceMaps = await processor.process(
       ['--csp', '--disable-inlining']
       ..addAll(options),
       verbose: verbose);
   TestResult result = new TestResult(config, filename, processor);
-  for (SourceMapInfo info in infoList) {
+  for (SourceMapInfo info in sourceMaps.elementSourceMapInfos.values) {
     if (info.element.library.isPlatformLibrary) continue;
     result.userInfoList.add(info);
     Iterable<CodePoint> missingCodePoints =
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
index 9cb53e5..019e8be 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_helper.dart
@@ -5,14 +5,17 @@
 library sourcemap.helper;
 
 import 'dart:async';
+import 'dart:io';
 import 'package:compiler/compiler_new.dart';
 import 'package:compiler/src/apiimpl.dart' as api;
 import 'package:compiler/src/null_compiler_output.dart' show NullSink;
 import 'package:compiler/src/elements/elements.dart';
 import 'package:compiler/src/helpers/helpers.dart';
 import 'package:compiler/src/filenames.dart';
+import 'package:compiler/src/io/code_output.dart';
 import 'package:compiler/src/io/source_file.dart';
 import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/io/position_information.dart';
 import 'package:compiler/src/js/js.dart' as js;
 import 'package:compiler/src/js/js_debug.dart';
 import 'package:compiler/src/js/js_source_mapping.dart';
@@ -21,15 +24,51 @@
 import '../memory_compiler.dart';
 import '../output_collector.dart';
 
+class SourceFileSink implements EventSink<String> {
+  final String filename;
+  StringBuffer sb = new StringBuffer();
+  SourceFile sourceFile;
+
+  SourceFileSink(this.filename);
+
+  @override
+  void add(String event) {
+    sb.write(event);
+  }
+
+  @override
+  void addError(errorEvent, [StackTrace stackTrace]) {
+    // Ignore.
+  }
+
+  @override
+  void close() {
+    sourceFile = new StringSourceFile.fromName(filename, sb.toString());
+  }
+}
+
 class OutputProvider implements CompilerOutput {
-  BufferedEventSink jsMapOutput;
+  Map<Uri, SourceFileSink> outputMap = <Uri, SourceFileSink>{};
+
+  SourceFile getSourceFile(Uri uri) {
+    SourceFileSink sink = outputMap[uri];
+    if (sink != null) {
+      return sink.sourceFile;
+    }
+    return null;
+  }
+
+  SourceFileSink createSourceFileSink(String name, String extension) {
+    String filename = '$name.$extension';
+    SourceFileSink sink = new SourceFileSink(filename);
+    Uri uri = Uri.parse(filename);
+    outputMap[uri] = sink;
+    return sink;
+  }
 
   @override
   EventSink<String> createEventSink(String name, String extension) {
-    if (extension == 'js.map') {
-      return jsMapOutput = new BufferedEventSink();
-    }
-    return new NullSink('$name.$extension');
+    return createSourceFileSink(name, extension);
   }
 }
 
@@ -42,11 +81,8 @@
   @override
   EventSink<String> createEventSink(String name, String extension) {
     EventSink<String> output = outputProvider(name, extension);
-    if (extension == 'js.map') {
-      output = new CloningEventSink(
-          [output, jsMapOutput = new BufferedEventSink()]);
-    }
-    return output;
+    return new CloningEventSink(
+        [output, createSourceFileSink(name, extension)]);
   }
 }
 
@@ -56,17 +92,23 @@
 
 class ProviderSourceFileManager implements SourceFileManager {
   final SourceFileProvider sourceFileProvider;
+  final OutputProvider outputProvider;
 
-  ProviderSourceFileManager(this.sourceFileProvider);
+  ProviderSourceFileManager(this.sourceFileProvider, this.outputProvider);
 
   @override
   SourceFile getSourceFile(uri) {
-    return sourceFileProvider.getSourceFile(uri);
+    SourceFile sourceFile = sourceFileProvider.getSourceFile(uri);
+    if (sourceFile == null) {
+      sourceFile = outputProvider.getSourceFile(uri);
+    }
+    return sourceFile;
   }
 }
 
 class RecordingPrintingContext extends LenientPrintingContext {
   CodePositionListener listener;
+  Map<js.Node, CodePosition> codePositions = <js.Node, CodePosition>{};
 
   RecordingPrintingContext(this.listener);
 
@@ -75,11 +117,163 @@
                 int startPosition,
                 int endPosition,
                 int closingPosition) {
+    codePositions[node] =
+        new CodePosition(startPosition, endPosition, closingPosition);
     listener.onPositions(
         node, startPosition, endPosition, closingPosition);
   }
 }
 
+/// A [SourceMapper] that records the source locations on each node.
+class RecordingSourceMapper implements SourceMapper {
+  final SourceMapper sourceMapper;
+  final _LocationRecorder nodeToSourceLocationsMap;
+
+  RecordingSourceMapper(this.sourceMapper, this.nodeToSourceLocationsMap);
+
+  @override
+  void register(js.Node node, int codeOffset, SourceLocation sourceLocation) {
+    nodeToSourceLocationsMap.register(node, codeOffset, sourceLocation);
+    sourceMapper.register(node, codeOffset, sourceLocation);
+  }
+}
+
+/// A wrapper of [SourceInformationProcessor] that records source locations and
+/// code positions.
+class RecordingSourceInformationProcessor
+    implements SourceInformationProcessor {
+  final RecordingSourceInformationStrategy wrapper;
+  final SourceInformationProcessor processor;
+  final CodePositionRecorder codePositions;
+  final LocationMap nodeToSourceLocationsMap;
+
+  RecordingSourceInformationProcessor(
+      this.wrapper,
+      this.processor,
+      this.codePositions,
+      this.nodeToSourceLocationsMap);
+
+  @override
+  void onPositions(js.Node node,
+                   int startPosition,
+                   int endPosition,
+                   int closingPosition) {
+    codePositions.registerPositions(
+        node, startPosition, endPosition, closingPosition);
+    processor.onPositions(node, startPosition, endPosition, closingPosition);
+  }
+
+  @override
+  void process(js.Node node, BufferedCodeOutput code) {
+    processor.process(node, code);
+    wrapper.registerProcess(
+        node, code, codePositions, nodeToSourceLocationsMap);
+  }
+}
+
+/// Information recording for a use of [SourceInformationProcessor].
+class RecordedSourceInformationProcess {
+  final js.Node root;
+  final String code;
+  final CodePositionRecorder codePositions;
+  final LocationMap nodeToSourceLocationsMap;
+
+  RecordedSourceInformationProcess(
+      this.root,
+      this.code,
+      this.codePositions,
+      this.nodeToSourceLocationsMap);
+}
+
+
+/// A wrapper of [JavaScriptSourceInformationStrategy] that records
+/// [RecordedSourceInformationProcess].
+class RecordingSourceInformationStrategy
+    extends JavaScriptSourceInformationStrategy {
+  final JavaScriptSourceInformationStrategy strategy;
+  final Map<RecordedSourceInformationProcess, js.Node> processMap =
+      <RecordedSourceInformationProcess, js.Node>{};
+  final Map<js.Node, RecordedSourceInformationProcess> nodeMap =
+      <js.Node, RecordedSourceInformationProcess>{};
+
+  RecordingSourceInformationStrategy(this.strategy);
+
+  @override
+  SourceInformationBuilder createBuilderForContext(AstElement element) {
+    return strategy.createBuilderForContext(element);
+  }
+
+  @override
+  SourceInformationProcessor createProcessor(SourceMapper sourceMapper) {
+    LocationMap nodeToSourceLocationsMap =
+        new _LocationRecorder();
+    CodePositionRecorder codePositions = new CodePositionRecorder();
+    return new RecordingSourceInformationProcessor(
+        this,
+        strategy.createProcessor(new RecordingSourceMapper(
+            sourceMapper, nodeToSourceLocationsMap)),
+            codePositions, nodeToSourceLocationsMap);
+  }
+
+  void registerProcess(js.Node root,
+                       BufferedCodeOutput code,
+                       CodePositionRecorder codePositions,
+                       LocationMap nodeToSourceLocationsMap) {
+    RecordedSourceInformationProcess subProcess =
+        new RecordedSourceInformationProcess(
+            root, code.getText(), codePositions, nodeToSourceLocationsMap);
+    processMap[subProcess] = root;
+  }
+
+  RecordedSourceInformationProcess subProcessForNode(js.Node node) {
+    return nodeMap.putIfAbsent(node, () {
+      for (RecordedSourceInformationProcess subProcess in processMap.keys) {
+        js.Node root = processMap[subProcess];
+        FindVisitor visitor = new FindVisitor(node);
+        root.accept(visitor);
+        if (visitor.found) {
+          return new RecordedSourceInformationProcess(
+              node,
+              subProcess.code,
+              subProcess.codePositions,
+              new _FilteredLocationMap(
+                  visitor.nodes, subProcess.nodeToSourceLocationsMap));
+        }
+        return null;
+      }
+    });
+  }
+}
+
+/// Visitor that collects all nodes that are within a function. Used by the
+/// [RecordingSourceInformationStrategy] to filter what is recorded in a
+/// [RecordedSourceInformationProcess].
+class FindVisitor extends js.BaseVisitor {
+  final js.Node soughtNode;
+  bool found = false;
+  bool add = false;
+  final Set<js.Node> nodes = new Set<js.Node>();
+
+  FindVisitor(this.soughtNode);
+
+  visitNode(js.Node node) {
+    if (node == soughtNode) {
+      found = true;
+      add = true;
+    }
+    if (add) {
+      nodes.add(node);
+    }
+    node.visitChildren(this);
+    if (node == soughtNode) {
+      add = false;
+    }
+  }
+}
+
+const String USE_NEW_SOURCE_INFO =  '--use-new-source-info';
+const String DISABLE_INLINING = '--disable-inlining';
+
 /// Processor that computes [SourceMapInfo] for the JavaScript compiled for a
 /// given Dart file.
 class SourceMapProcessor {
@@ -110,13 +304,15 @@
   }
 
   /// Computes the [SourceMapInfo] for the compiled elements.
-  Future<List<SourceMapInfo>> process(
+  Future<SourceMaps> process(
       List<String> options,
-      {bool verbose: true}) async {
+      {bool verbose: true,
+       bool perElement: true,
+       bool forMain: false}) async {
     OutputProvider outputProvider = outputToFile
-        ? new OutputProvider()
-        : new CloningOutputProvider(targetUri, sourceMapFileUri);
-    if (options.contains('--use-new-source-info')) {
+        ? new CloningOutputProvider(targetUri, sourceMapFileUri)
+        : new OutputProvider();
+    if (options.contains(USE_NEW_SOURCE_INFO)) {
       if (verbose) print('Using the new source information system.');
       useNewSourceInfo = true;
     }
@@ -125,7 +321,7 @@
         // TODO(johnniwinther): Use [verbose] to avoid showing diagnostics.
         options: ['--out=$targetUri', '--source-map=$sourceMapFileUri']
             ..addAll(options));
-    if (options.contains('--disable-inlining')) {
+    if (options.contains(DISABLE_INLINING)) {
       if (verbose) print('Inlining disabled');
       compiler.disableInlining = true;
     }
@@ -133,53 +329,123 @@
     JavaScriptBackend backend = compiler.backend;
     var handler = compiler.handler;
     SourceFileProvider sourceFileProvider = handler.provider;
-    sourceFileManager = new ProviderSourceFileManager(sourceFileProvider);
+    sourceFileManager = new ProviderSourceFileManager(
+        sourceFileProvider,
+        outputProvider);
+    RecordingSourceInformationStrategy strategy =
+        new RecordingSourceInformationStrategy(backend.sourceInformationStrategy);
+    backend.sourceInformationStrategy = strategy;
     await compiler.run(inputUri);
 
-    List<SourceMapInfo> infoList = <SourceMapInfo>[];
-    backend.generatedCode.forEach((Element element, js.Expression node) {
-      js.JavaScriptPrintingOptions options =
-          new js.JavaScriptPrintingOptions();
-      JavaScriptSourceInformationStrategy sourceInformationStrategy =
-          compiler.backend.sourceInformationStrategy;
-      NodeToSourceLocationsMap nodeMap = new NodeToSourceLocationsMap();
-      SourceInformationProcessor sourceInformationProcessor =
-          sourceInformationStrategy.createProcessor(nodeMap);
-      RecordingPrintingContext printingContext =
-          new RecordingPrintingContext(sourceInformationProcessor);
-      new js.Printer(options, printingContext).visit(node);
-      sourceInformationProcessor.process(node);
-
-      String code = printingContext.getText();
+    SourceMapInfo mainSourceMapInfo;
+    Map<Element, SourceMapInfo> elementSourceMapInfos =
+        <Element, SourceMapInfo>{};
+    if (perElement) {
+      backend.generatedCode.forEach((Element element, js.Expression node) {
+        RecordedSourceInformationProcess subProcess =
+            strategy.subProcessForNode(node);
+        if (subProcess == null) {
+          // TODO(johnniwinther): Find out when this is happening and if it
+          // is benign. (Known to happen for `bool#fromString`)
+          print('No subProcess found for $element');
+          return;
+        }
+        LocationMap nodeMap = subProcess.nodeToSourceLocationsMap;
+        String code = subProcess.code;
+        CodePositionRecorder codePositions = subProcess.codePositions;
+        CodePointComputer visitor =
+            new CodePointComputer(sourceFileManager, code, nodeMap);
+        new JavaScriptTracer(codePositions, [visitor]).apply(node);
+        List<CodePoint> codePoints = visitor.codePoints;
+        elementSourceMapInfos[element] = new SourceMapInfo(
+            element,
+            code,
+            node,
+            codePoints,
+            codePositions,
+            nodeMap);
+      });
+    }
+    if (forMain) {
+      // TODO(johnniwinther): Supported multiple output units.
+      RecordedSourceInformationProcess process = strategy.processMap.keys.first;
+      js.Node node = strategy.processMap[process];
+      String code;
+      LocationMap nodeMap;
+      CodePositionRecorder codePositions;
+      nodeMap = process.nodeToSourceLocationsMap;
+      code = process.code;
+      codePositions = process.codePositions;
       CodePointComputer visitor =
           new CodePointComputer(sourceFileManager, code, nodeMap);
-      visitor.apply(node);
+      new JavaScriptTracer(codePositions, [visitor]).apply(node);
       List<CodePoint> codePoints = visitor.codePoints;
-      infoList.add(new SourceMapInfo(element, code, node, codePoints, nodeMap));
-    });
+      mainSourceMapInfo = new SourceMapInfo(
+          null, code, node,
+          codePoints,
+          codePositions,
+          nodeMap);
+    }
 
-    return infoList;
+    return new SourceMaps(
+        sourceFileManager, mainSourceMapInfo, elementSourceMapInfos);
   }
 }
 
+class SourceMaps {
+  final SourceFileManager sourceFileManager;
+  // TODO(johnniwinther): Supported multiple output units.
+  final SourceMapInfo mainSourceMapInfo;
+  final Map<Element, SourceMapInfo> elementSourceMapInfos;
+
+  SourceMaps(
+      this.sourceFileManager,
+      this.mainSourceMapInfo,
+          this.elementSourceMapInfos);
+}
+
 /// Source mapping information for the JavaScript code of an [Element].
 class SourceMapInfo {
   final String name;
   final Element element;
   final String code;
-  final js.Expression node;
+  final js.Node node;
   final List<CodePoint> codePoints;
-  final NodeToSourceLocationsMap nodeMap;
+  final CodePositionMap jsCodePositions;
+  final LocationMap nodeMap;
 
   SourceMapInfo(
-      Element element, this.code, this.node, this.codePoints, this.nodeMap)
-      : this.name = computeElementNameForSourceMaps(element),
+      Element element,
+      this.code,
+      this.node,
+      this.codePoints,
+      this.jsCodePositions,
+      this.nodeMap)
+      : this.name =
+          element != null ? computeElementNameForSourceMaps(element) : '',
         this.element = element;
+
+  String toString() {
+    return '$name:$element';
+  }
 }
 
 /// Collection of JavaScript nodes with their source mapped target offsets
 /// and source locations.
-class NodeToSourceLocationsMap implements SourceMapper {
+abstract class LocationMap {
+  Iterable<js.Node> get nodes;
+
+  Map<int, List<SourceLocation>> operator[] (js.Node node);
+
+  factory LocationMap.recorder() = _LocationRecorder;
+
+  factory LocationMap.filter(Set<js.Node> nodes, LocationMap map) =
+      _FilteredLocationMap;
+
+}
+
+class _LocationRecorder
+    implements SourceMapper, LocationMap {
   final Map<js.Node, Map<int, List<SourceLocation>>> _nodeMap = {};
 
   @override
@@ -196,11 +462,25 @@
   }
 }
 
+class _FilteredLocationMap implements LocationMap {
+  final Set<js.Node> _nodes;
+  final LocationMap map;
+
+  _FilteredLocationMap(this._nodes, this.map);
+
+  Iterable<js.Node> get nodes => map.nodes.where((n) => _nodes.contains(n));
+
+  Map<int, List<SourceLocation>> operator[] (js.Node node) {
+    return map[node];
+  }
+}
+
+
 /// Visitor that computes the [CodePoint]s for source mapping locations.
-class CodePointComputer extends js.BaseVisitor {
+class CodePointComputer extends TraceListener {
   final SourceFileManager sourceFileManager;
   final String code;
-  final NodeToSourceLocationsMap nodeMap;
+  final LocationMap nodeMap;
   List<CodePoint> codePoints = [];
 
   CodePointComputer(this.sourceFileManager, this.code, this.nodeMap);
@@ -223,11 +503,20 @@
     return line;
   }
 
+  /// Called when [node] defines a step of the given [kind] at the given
+  /// [offset] when the generated JavaScript code.
+  void onStep(js.Node node, Offset offset, StepKind kind) {
+    register('$kind', node);
+  }
+
   void register(String kind, js.Node node, {bool expectInfo: true}) {
 
     String dartCodeFromSourceLocation(SourceLocation sourceLocation) {
       SourceFile sourceFile =
            sourceFileManager.getSourceFile(sourceLocation.sourceUri);
+      if (sourceFile == null) {
+        return sourceLocation.shortText;
+      }
       return sourceFile.getLineText(sourceLocation.line)
           .substring(sourceLocation.column).trim();
     }
@@ -263,57 +552,6 @@
       });
     }
   }
-
-  void apply(js.Node node) {
-    node.accept(this);
-  }
-
-  void visitNode(js.Node node) {
-    register('${node.runtimeType}', node, expectInfo: false);
-    super.visitNode(node);
-  }
-
-  @override
-  void visitNew(js.New node) {
-    node.arguments.forEach(apply);
-    register('New', node);
-  }
-
-  @override
-  void visitReturn(js.Return node) {
-    if (node.value != null) {
-      apply(node.value);
-    }
-    register('Return', node);
-  }
-
-  @override
-  void visitCall(js.Call node) {
-    apply(node.target);
-    node.arguments.forEach(apply);
-    register('Call (${node.target.runtimeType})', node);
-  }
-
-  @override
-  void visitFun(js.Fun node) {
-    node.visitChildren(this);
-    register('Fun', node);
-  }
-
-  @override
-  visitExpressionStatement(js.ExpressionStatement node) {
-    node.visitChildren(this);
-  }
-
-  @override
-  visitBinary(js.Binary node) {
-    node.visitChildren(this);
-  }
-
-  @override
-  visitAccess(js.PropertyAccess node) {
-    node.visitChildren(this);
-  }
 }
 
 /// A JavaScript code point and its mapped dart source location.
@@ -336,3 +574,24 @@
                      'location=$sourceLocation]';
   }
 }
+
+class IOSourceFileManager implements SourceFileManager {
+  final Uri base;
+
+  Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{};
+
+  IOSourceFileManager(this.base);
+
+  SourceFile getSourceFile(var uri) {
+    Uri absoluteUri;
+    if (uri is Uri) {
+      absoluteUri = base.resolveUri(uri);
+    } else {
+      absoluteUri = base.resolve(uri);
+    }
+    return sourceFiles.putIfAbsent(absoluteUri, () {
+      String text = new File.fromUri(absoluteUri).readAsStringSync();
+      return new StringSourceFile.fromUri(absoluteUri, text);
+    });
+  }
+}
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
index 4227fee..3ca926b 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_helper.dart
@@ -8,6 +8,7 @@
 library sourcemap.html.helper;
 
 import 'dart:convert';
+import 'dart:math' as Math;
 
 import 'package:compiler/src/io/source_file.dart';
 import 'package:compiler/src/io/source_information.dart';
@@ -16,6 +17,15 @@
 import 'colors.dart';
 import 'sourcemap_helper.dart';
 import 'sourcemap_html_templates.dart';
+import 'html_parts.dart';
+
+/// Truncate [input] to [length], adding '...' if truncated.
+String truncate(String input, int length) {
+  if (input.length > length) {
+    return '${input.substring(0, length - 3)}...';
+  }
+  return input;
+}
 
 /// Returns the [index]th color for visualization.
 HSV toColor(int index) {
@@ -40,9 +50,15 @@
   return 'linear-gradient(to right, ${startColor.toCss}, ${endColor.toCss})';
 }
 
-/// Return the html for the [index] line number.
-String lineNumber(int index) {
-  return '<span class="lineNumber">${index + 1} </span>';
+/// Return the html for the [index] line number. If [width] is provided, shorter
+/// line numbers will be prefixed with spaces to match the width.
+String lineNumber(int index, {int width, bool useNbsp: false}) {
+  String text = '${index + 1}';
+  String padding = useNbsp ? '&nbsp;' : ' ';
+  if (width != null && text.length < width) {
+    text = (padding * (width - text.length)) + text;
+  }
+  return '<span class="lineNumber">$text$padding</span>';
 }
 
 /// Return the html escaped [text].
@@ -59,6 +75,10 @@
   SourceMapHtmlInfo(this.sourceMapInfo,
                     this.codeProcessor,
                     this.sourceLocationCollection);
+
+  String toString() {
+    return sourceMapInfo.toString();
+  }
 }
 
 /// A collection of source locations.
@@ -84,16 +104,98 @@
   }
 }
 
+abstract class CssColorScheme {
+  String singleLocationToCssColor(var id);
+
+  String multiLocationToCssColor(List ids);
+
+  bool get showLocationAsSpan;
+}
+
+class CustomColorScheme implements CssColorScheme {
+  final bool showLocationAsSpan;
+  final Function single;
+  final Function multi;
+
+  CustomColorScheme(
+      {this.showLocationAsSpan: false,
+       String this.single(var id),
+       String this.multi(List ids)});
+
+  String singleLocationToCssColor(var id) => single != null ? single(id) : null;
+
+  String multiLocationToCssColor(List ids) => multi != null ? multi(ids) : null;
+}
+
+class PatternCssColorScheme implements CssColorScheme {
+  const PatternCssColorScheme();
+
+  bool get showLocationAsSpan => true;
+
+  String singleLocationToCssColor(int index) {
+    return "background:${toPattern(index)};";
+  }
+
+  String multiLocationToCssColor(List<int> indices) {
+
+    StringBuffer sb = new StringBuffer();
+    double delta = 100.0 / (indices.length);
+    double position = 0.0;
+
+    void addColor(String color) {
+      sb.write(', ${color} ${position.toInt()}%');
+      position += delta;
+      sb.write(', ${color} ${position.toInt()}%');
+    }
+
+    for (int index in indices) {
+      addColor('${toColorCss(index)}');
+    }
+    return 'background: linear-gradient(to right${sb}); '
+           'background-size: 10px 10px;';
+  }
+}
+
+class SingleColorScheme implements CssColorScheme {
+  const SingleColorScheme();
+
+  bool get showLocationAsSpan => false;
+
+  String singleLocationToCssColor(int index) {
+    return "background:${toColorCss(index)};";
+  }
+
+  String multiLocationToCssColor(List<int> indices) {
+    StringBuffer sb = new StringBuffer();
+    double delta = 100.0 / (indices.length);
+    double position = 0.0;
+
+    void addColor(String color) {
+      sb.write(', ${color} ${position.toInt()}%');
+      position += delta;
+      sb.write(', ${color} ${position.toInt()}%');
+    }
+
+    for (int index in indices) {
+      addColor('${toColorCss(index)}');
+    }
+    return 'background: linear-gradient(to bottom${sb}); '
+           'background-size: 10px 3px;';
+  }
+}
+
 /// Processor that computes the HTML representation of a block of JavaScript
 /// code and collects the source locations mapped in the code.
 class CodeProcessor {
   int lineIndex = 0;
-  final String onclick;
+  final String name;
   int currentJsSourceOffset = 0;
   final SourceLocationCollection collection;
   final Map<int, List<SourceLocation>> codeLocations = {};
+  final CssColorScheme colorScheme;
 
-  CodeProcessor(this.onclick, this.collection);
+  CodeProcessor(this.name, this.collection,
+      {this.colorScheme: const PatternCssColorScheme()});
 
   void addSourceLocation(int targetOffset, SourceLocation sourceLocation) {
     codeLocations.putIfAbsent(targetOffset, () => []).add(sourceLocation);
@@ -101,100 +203,240 @@
   }
 
   String convertToHtml(String text) {
-    StringBuffer htmlBuffer = new StringBuffer();
-    int offset = 0;
-    int lineIndex = 0;
-    bool pendingSourceLocationsEnd = false;
-    htmlBuffer.write(lineNumber(lineIndex));
-    SourceLocation currentLocation;
-
-    void endCurrentLocation() {
-      if (currentLocation != null) {
-        htmlBuffer.write('</a>');
-      }
-      currentLocation = null;
-    }
-
-    void addSubstring(int until) {
-      if (until <= offset) return;
-
-      String substring = text.substring(offset, until);
-      offset = until;
-      bool first = true;
-      for (String line in substring.split('\n')) {
-        if (!first) {
-          endCurrentLocation();
-          htmlBuffer.write('\n');
-          lineIndex++;
-          htmlBuffer.write(lineNumber(lineIndex));
+    List<Annotation> annotations = <Annotation>[];
+    codeLocations.forEach((int codeOffset, List<SourceLocation> locations) {
+      for (SourceLocation location in locations) {
+        if (location != null) {
+          annotations.add(new Annotation(
+              collection.getIndex(location),
+              codeOffset,
+              location.shortText));
         }
-        htmlBuffer.write(escape(line));
-        first = false;
       }
+    });
+    return convertAnnotatedCodeToHtml(
+        text, annotations, colorScheme: colorScheme,
+        elementScheme: new HighlightLinkScheme(name),
+        windowSize: 3);
+  }
+}
+
+class Annotation {
+  final id;
+  final int codeOffset;
+  final String title;
+
+  Annotation(this.id, this.codeOffset, this.title);
+}
+
+class ElementScheme {
+  const ElementScheme();
+
+  String getName(var id, Set ids) => null;
+  String getHref(var id, Set ids) => null;
+  String onClick(var id, Set ids) => null;
+  String onMouseOver(var id, Set ids) => null;
+  String onMouseOut(var id, Set ids) => null;
+}
+
+class HighlightLinkScheme implements ElementScheme {
+  final String name;
+
+  HighlightLinkScheme(this.name);
+
+  @override
+  String getName(int id, Set<int> indices) {
+    return 'js$id';
+  }
+
+  @override
+  String getHref(int id, Set<int> indices) {
+    return "#${id}";
+  }
+
+  @override
+  String onClick(int id, Set<int> indices) {
+    return "show(\'$name\');";
+  }
+
+  @override
+  String onMouseOut(int id, Set<int> indices) {
+    String onmouseover = indices.map((i) => '\'$i\'').join(',');
+    return "highlight([${onmouseover}]);";
+  }
+
+  @override
+  String onMouseOver(int id, Set<int> indices) {
+    return "highlight([]);";
+  }
+}
+
+String convertAnnotatedCodeToHtml(
+    String code,
+    Iterable<Annotation> annotations,
+    {CssColorScheme colorScheme: const SingleColorScheme(),
+     ElementScheme elementScheme: const ElementScheme(),
+     int windowSize}) {
+  StringBuffer htmlBuffer = new StringBuffer();
+  List<CodeLine> lines = convertAnnotatedCodeToCodeLines(
+      code, annotations,
+      colorScheme: colorScheme,
+      elementScheme: elementScheme,
+      windowSize: windowSize);
+  int lineNoWidth;
+  if (lines.isNotEmpty) {
+    lineNoWidth = '${lines.last.lineNo + 1}'.length;
+  }
+  HtmlPrintContext context = new HtmlPrintContext(lineNoWidth: lineNoWidth);
+  for (CodeLine line in lines) {
+    line.printHtmlOn(htmlBuffer, context);
+  }
+  return htmlBuffer.toString();
+}
+
+List<CodeLine> convertAnnotatedCodeToCodeLines(
+    String code,
+    Iterable<Annotation> annotations,
+    {CssColorScheme colorScheme: const SingleColorScheme(),
+     ElementScheme elementScheme: const ElementScheme(),
+     int windowSize}) {
+
+  List<CodeLine> lines = <CodeLine>[];
+  CodeLine currentLine;
+  int offset = 0;
+  int lineIndex = 0;
+  int firstLine;
+  int lastLine;
+  bool pendingSourceLocationsEnd = false;
+
+  void write(String code, HtmlPart html) {
+    if (currentLine != null) {
+      currentLine.codeBuffer.write(code);
+      currentLine.htmlParts.add(html);
     }
+  }
 
-    void insertSourceLocations(List<SourceLocation> lastSourceLocations) {
-      endCurrentLocation();
+  void startLine(int currentOffset) {
+    lines.add(currentLine = new CodeLine(lines.length, currentOffset));
+  }
 
-      String color;
-      int index;
-      String title;
-      if (lastSourceLocations.length == 1) {
-        SourceLocation sourceLocation = lastSourceLocations.single;
-        if (sourceLocation != null) {
-          index = collection.getIndex(sourceLocation);
-          color = "background:${toPattern(index)};";
-          title = sourceLocation.shortText;
-          currentLocation = sourceLocation;
+  void endCurrentLocation() {
+    if (pendingSourceLocationsEnd) {
+      write('', const ConstHtmlPart('</a>'));
+    }
+    pendingSourceLocationsEnd = false;
+  }
+
+  void addSubstring(int until, {bool isFirst: false, bool isLast: false}) {
+    if (until <= offset) return;
+    if (offset >= code.length) return;
+
+    String substring = code.substring(offset, until);
+    bool first = true;
+
+    if (isLast) {
+      lastLine = lineIndex;
+    }
+    int localOffset = 0;
+    if (isFirst) {
+      startLine(offset + localOffset);
+    }
+    for (String line in substring.split('\n')) {
+      if (!first) {
+        endCurrentLocation();
+        write('', const NewLine());
+        lineIndex++;
+        startLine(offset + localOffset);
+      }
+      if (pendingSourceLocationsEnd && !colorScheme.showLocationAsSpan) {
+        if (line.isNotEmpty) {
+          String before = line.substring(0, 1);
+          write(before, new HtmlText(before));
+          endCurrentLocation();
+          String after = line.substring(1);
+          write(after, new HtmlText(after));
         }
       } else {
-
-        index = collection.getIndex(lastSourceLocations.first);
-        StringBuffer sb = new StringBuffer();
-        double delta = 100.0 / (lastSourceLocations.length);
-        double position = 0.0;
-
-        void addColor(String color) {
-          sb.write(', ${color} ${position.toInt()}%');
-          position += delta;
-          sb.write(', ${color} ${position.toInt()}%');
-        }
-
-        for (SourceLocation sourceLocation in lastSourceLocations) {
-          if (sourceLocation == null) continue;
-          int colorIndex = collection.getIndex(sourceLocation);
-          addColor('${toColorCss(colorIndex)}');
-          currentLocation = sourceLocation;
-        }
-        color = 'background: linear-gradient(to right${sb}); '
-                'background-size: 10px 10px;';
-        title = lastSourceLocations.map((l) => l.shortText).join(',');
+        write(line, new HtmlText(line));
       }
-      if (index != null) {
-        Set<int> indices =
-            lastSourceLocations.map((l) => collection.getIndex(l)).toSet();
-        String onmouseover = indices.map((i) => '\'$i\'').join(',');
-        htmlBuffer.write(
-            '<a name="js$index" href="#${index}" style="$color" title="$title" '
-            'onclick="${onclick}" onmouseover="highlight([${onmouseover}]);"'
-            'onmouseout="highlight([]);">');
-        pendingSourceLocationsEnd = true;
-      }
-      if (lastSourceLocations.last == null) {
-        endCurrentLocation();
-      }
+      first = false;
+      localOffset += line.length + 1;
     }
-
-    for (int targetOffset in codeLocations.keys.toList()..sort()) {
-      List<SourceLocation> sourceLocations = codeLocations[targetOffset];
-      addSubstring(targetOffset);
-      insertSourceLocations(sourceLocations);
+    if (isFirst) {
+      firstLine = lineIndex;
     }
-
-    addSubstring(text.length);
-    endCurrentLocation();
-    return htmlBuffer.toString();
+    offset = until;
   }
+
+  void insertAnnotations(List<Annotation> annotations) {
+    endCurrentLocation();
+
+    String color;
+    var id;
+    String title;
+    if (annotations.length == 1) {
+      Annotation annotation = annotations.single;
+      if (annotation != null) {
+        id = annotation.id;
+        color = colorScheme.singleLocationToCssColor(id);
+        title = annotation.title;
+      }
+    } else {
+      id = annotations.first.id;
+      List ids = [];
+      for (Annotation annotation in annotations) {
+        ids.add(annotation.id);
+      }
+      color = colorScheme.multiLocationToCssColor(ids);
+      title = annotations.map((l) => l.title).join(',');
+    }
+    if (id != null) {
+      Set ids = annotations.map((l) => l.id).toSet();
+      String name = elementScheme.getName(id, ids);
+      String href = elementScheme.getHref(id, ids);
+      String onclick = elementScheme.onClick(id, ids);
+      String onmouseover = elementScheme.onMouseOver(id, ids);
+      String onmouseout = elementScheme.onMouseOut(id, ids);
+      write('', new AnchorHtmlPart(
+          color: color,
+          name: name,
+          href: href,
+          title: title,
+          onclick: onclick,
+          onmouseover: onmouseover,
+          onmouseout: onmouseout));
+      pendingSourceLocationsEnd = true;
+    }
+    currentLine.annotations.addAll(annotations);
+    if (annotations.last == null) {
+      endCurrentLocation();
+    }
+  }
+
+  Map<int, List<Annotation>> annotationMap = <int, List<Annotation>>{};
+  for (Annotation annotation in annotations) {
+    annotationMap.putIfAbsent(annotation.codeOffset, () => <Annotation>[])
+                 .add(annotation);
+  }
+
+  bool first = true;
+  for (int codeOffset in annotationMap.keys.toList()..sort()) {
+    List<Annotation> annotationList = annotationMap[codeOffset];
+    addSubstring(codeOffset, isFirst: first);
+    insertAnnotations(annotationList);
+    first = false;
+  }
+
+  addSubstring(code.length, isFirst: first, isLast: true);
+  endCurrentLocation();
+
+  int start = 0;
+  int end = lines.length - 1;
+  if (windowSize != null) {
+    start = Math.max(firstLine - windowSize, start);
+    end = Math.min(lastLine + windowSize, end);
+  }
+  return lines.sublist(start, end);
 }
 
 /// Computes the HTML representation for a collection of JavaScript code blocks.
@@ -240,10 +482,9 @@
   js.Node node = info.node;
   String code = info.code;
   String name = info.name;
-  String onclick = 'show(\'$name\');';
   SourceLocationCollection subcollection =
       new SourceLocationCollection(collection);
-  CodeProcessor codeProcessor = new CodeProcessor(onclick, subcollection);
+  CodeProcessor codeProcessor = new CodeProcessor(name, subcollection);
   for (js.Node node in info.nodeMap.nodes) {
     info.nodeMap[node].forEach(
         (int targetOffset, List<SourceLocation> sourceLocations) {
@@ -308,10 +549,16 @@
   });
   sourceLocationMap.forEach((Uri uri, Map<int, List<SourceLocation>> uriMap) {
     SourceFile sourceFile = sourceFileManager.getSourceFile(uri);
+    if (sourceFile == null) return;
     StringBuffer codeBuffer = new StringBuffer();
 
     int firstLineIndex;
     int lastLineIndex;
+    List<int> lineIndices = uriMap.keys.toList()..sort();
+    int lineNoWidth;
+    if (lineIndices.isNotEmpty) {
+      lineNoWidth = '${lineIndices.last + windowSize + 1}'.length;
+    }
 
     void flush() {
       if (firstLineIndex != null && lastLineIndex != null) {
@@ -325,7 +572,7 @@
              line < firstLineIndex;
              line++) {
           if (line >= 0) {
-            dartCodeBuffer.write(lineNumber(line));
+            dartCodeBuffer.write(lineNumber(line, width: lineNoWidth));
             dartCodeBuffer.write(sourceFile.getLineText(line));
           }
         }
@@ -334,7 +581,7 @@
              line <= lastLineIndex + windowSize;
              line++) {
           if (line < sourceFile.lines) {
-            dartCodeBuffer.write(lineNumber(line));
+            dartCodeBuffer.write(lineNumber(line, width: lineNoWidth));
             dartCodeBuffer.write(sourceFile.getLineText(line));
           }
         }
@@ -345,7 +592,6 @@
       codeBuffer.clear();
     }
 
-    List<int> lineIndices = uriMap.keys.toList()..sort();
     lineIndices.forEach((int lineIndex) {
       List<SourceLocation> locations = uriMap[lineIndex];
       if (lastLineIndex != null &&
@@ -356,7 +602,7 @@
         firstLineIndex = lineIndex;
       } else {
         for (int line = lastLineIndex + 1; line < lineIndex; line++) {
-          codeBuffer.write(lineNumber(line));
+          codeBuffer.write(lineNumber(line, width: lineNoWidth));
           codeBuffer.write(sourceFile.getLineText(line));
         }
       }
@@ -371,7 +617,7 @@
           end = locations[i + 1].column;
         }
         if (i == 0) {
-          codeBuffer.write(lineNumber(lineIndex));
+          codeBuffer.write(lineNumber(lineIndex, width: lineNoWidth));
           codeBuffer.write(line.substring(0, start));
         }
         codeBuffer.write(
@@ -404,7 +650,7 @@
       '<tr><th>Node kind</th><th>JS code @ offset</th>'
       '<th>Dart code @ mapped location</th><th>file:position:name</th></tr>');
   codePoints.forEach((CodePoint codePoint) {
-    String jsCode = codePoint.jsCode;
+    String jsCode = truncate(codePoint.jsCode, 50);
     if (codePoint.sourceLocation != null) {
       int index = collection.getIndex(codePoint.sourceLocation);
       if (index != null) {
@@ -431,7 +677,8 @@
     if (codePoint.sourceLocation == null) {
       //buffer.write('<td></td>');
     } else {
-      buffer.write('<td class="code">${codePoint.dartCode}</td>');
+      String dartCode = truncate(codePoint.dartCode, 50);
+      buffer.write('<td class="code">${dartCode}</td>');
       buffer.write('<td>${escape(codePoint.sourceLocation.shortText)}</td>');
     }
     buffer.write('</tr>');
diff --git a/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart b/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart
index f4b0f1b..29adff1 100644
--- a/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart
+++ b/tests/compiler/dart2js/sourcemaps/sourcemap_html_templates.dart
@@ -179,6 +179,11 @@
 .code {
   font-family: monospace;
 }
+td,.code {
+  font-family: monospace;
+  max-width: 400px;
+  overflow: hidden;
+}
 </style>
 </head>
 <body>
diff --git a/tests/compiler/dart2js/sourcemaps/trace_graph.dart b/tests/compiler/dart2js/sourcemaps/trace_graph.dart
new file mode 100644
index 0000000..75eec94
--- /dev/null
+++ b/tests/compiler/dart2js/sourcemaps/trace_graph.dart
@@ -0,0 +1,72 @@
+// 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 sourcemap.trace_graph;
+
+import 'dart:collection';
+
+import 'package:compiler/src/io/source_information.dart';
+import 'package:compiler/src/io/position_information.dart';
+import 'package:compiler/src/js/js_debug.dart';
+
+import 'sourcemap_html_helper.dart';
+
+class TraceGraph {
+  List<TraceStep> steps = <TraceStep>[];
+  TraceStep entry;
+  Queue stack = new Queue();
+  Map<int, TraceStep> offsetMap = {};
+
+  void addStep(TraceStep step) {
+    steps.add(step);
+    int offset = step.offset.subexpressionOffset;
+    TraceStep existingStep = offsetMap[offset];
+    if (existingStep != null) {
+      // TODO(johnniwinther): Fix problems with reuse of JS nodes from
+      // templates.
+      if (identical(existingStep.node, step.node)) {
+        print('duplicate node: ${nodeToString(step.node)}');
+      } else {
+        print('duplicate offset: ${offset} : ${nodeToString(step.node)}');
+      }
+      print('  ${existingStep.id}:${existingStep.text}:${existingStep.offset}');
+      print('  ${step.id}:${step.text}:${step.offset}');
+    }
+    offsetMap[offset] = step;
+    step.stack = stack.toList();
+  }
+
+  void pushBranch(branch) {
+    stack.addLast(branch);
+  }
+
+  void popBranch() {
+    stack.removeLast();
+  }
+}
+
+class TraceStep {
+  final kind;
+  final int id;
+  final node;
+  final Offset offset;
+  final List text;
+  final SourceLocation sourceLocation;
+
+  TraceStep next;
+  Map<dynamic, TraceStep> branchMap;
+
+  List stack;
+
+  TraceStep(
+      this.kind,
+      this.id,
+      this.node,
+      this.offset,
+      this.text,
+      [this.sourceLocation]);
+
+  String toString() => '<span style="background:${toColorCss(id)}">$id</span>';
+}
+
diff --git a/tests/compiler/dart2js/type_mask_disjoint_test.dart b/tests/compiler/dart2js/type_mask_disjoint_test.dart
new file mode 100644
index 0000000..90d3f53
--- /dev/null
+++ b/tests/compiler/dart2js/type_mask_disjoint_test.dart
@@ -0,0 +1,187 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'package:compiler/src/types/types.dart';
+
+import 'compiler_helper.dart';
+
+const String CODE = """
+class A {}
+class B extends A {}
+class C extends A {}
+
+class D implements A {}
+
+class E {}
+class F extends E {}
+class G implements E {}
+
+class H {}
+class I implements H {}
+class J extends D implements I {}
+
+class K {}
+class M extends K with A {}
+
+class N extends H with I {}
+
+main() {
+  print([new A(), new B(), new C(), new D(), new E(), new F(), new G(),
+      new H(), new I(), new J(), new K(), new M(), new N()]);
+}
+""";
+
+Uri uri = new Uri(scheme: 'source');
+var compiler = compilerFor(CODE, uri);
+var world = compiler.world;
+
+main() {
+  asyncTest(() => compiler.run(uri).then((_) {
+
+    // Empty
+    check(' ! ', ' ! ');  // both non-null
+    check(' ! ', '   ');  // one non-null
+    check('   ', ' ! ');  // one non-null
+    check('   ', '   ', areDisjoint: false); // null is common
+
+    // Exact
+    check('A!=', 'A!=', areDisjoint: false);
+    check('A!=', 'B!=');
+    check('A!=', 'E!=');
+    check('A =', 'E =', areDisjoint: false); // null is common
+    check('M!=', 'K!=');
+    check('M!=', 'A!=');
+
+    // Exact with subclass
+    check('A!=', 'A!<', areDisjoint: false);
+    check('B!=', 'A!<', areDisjoint: false);
+    check('A!=', 'B!<');
+    check('A!=', 'E!<');
+    check('A =', 'E!<');
+    check('A =', 'E <', areDisjoint: false);
+    check('M!=', 'K!<', areDisjoint: false);
+    check('M!=', 'A!<');
+
+    // Exact with subtype
+    check('A!=', 'A!*', areDisjoint: false);
+    check('B!=', 'A!*', areDisjoint: false);
+    check('A!=', 'B!*');
+    check('A!=', 'E!*');
+    check('A!=', 'I!*');
+    check('J!=', 'H!*', areDisjoint: false);
+    check('M!=', 'K!*', areDisjoint: false);
+    check('M!=', 'A!*', areDisjoint: false);
+
+    // Subclass with subclass
+    check('A!<', 'A!<', areDisjoint: false);
+    check('A!<', 'B!<', areDisjoint: false);
+    check('A!<', 'E!<');
+    check('A!<', 'H!<');
+    check('D!<', 'I!<');
+    check('H!<', 'I!*', areDisjoint: false);
+
+    // Subclass with subtype
+    check('A!<', 'A!*', areDisjoint: false);
+    check('A!<', 'B!*', areDisjoint: false);
+    check('A!<', 'E!*');
+    check('A!<', 'H!*');
+    check('D!<', 'I!*', areDisjoint: false);
+
+    // Subtype with subtype
+    check('A!*', 'A!*', areDisjoint: false);
+    check('A!*', 'B!*', areDisjoint: false);
+    check('A!*', 'E!*');
+    check('A!*', 'H!*', areDisjoint: false);
+    check('D!*', 'I!*', areDisjoint: false);
+
+    // Unions!
+    checkUnions(['B!=', 'C!='], ['A!=']);
+    checkUnions(['B!=', 'C!='], ['A =']);
+    checkUnions(['B!=', 'C ='], ['A ='], areDisjoint: false);
+
+    checkUnions(['B!=', 'C!='], ['A!<'], areDisjoint: false);
+    checkUnions(['B!=', 'C!='], ['B!='], areDisjoint: false);
+    checkUnions(['A!<', 'E!<'], ['C!='], areDisjoint: false);
+    checkUnions(['A!<', 'E!<'], ['F!='], areDisjoint: false);
+
+    checkUnions(['A!=', 'E!='], ['C!=', 'F!=']);
+    checkUnions(['A!=', 'E!='], ['A!=', 'F!='], areDisjoint: false);
+    checkUnions(['B!=', 'E!='], ['A!<', 'F!='], areDisjoint: false);
+    checkUnions(['A!<', 'E!<'], ['C!=', 'F!='], areDisjoint: false);
+    checkUnions(['A!=', 'E!='], ['C!=', 'F!=']);
+  }));
+}
+
+/// Checks the expectation of `isDisjoint` for two mask. Also checks that the
+/// result is consistent with an equivalent (but slower) implementation based on
+/// intersection.
+checkMask(TypeMask m1, TypeMask m2, {areDisjoint: false}) {
+  print('masks: $m1 $m2');
+  Expect.equals(areDisjoint, m1.isDisjoint(m2, world));
+  Expect.equals(areDisjoint, m2.isDisjoint(m1, world));
+  var i1 = m1.intersection(m2, world);
+  Expect.equals(areDisjoint, i1.isEmpty && !i1.isNullable);
+  var i2 = m2.intersection(m1, world);
+  Expect.equals(areDisjoint, i2.isEmpty && !i2.isNullable);
+}
+
+/// Checks the expectation of `isDisjoint` for two mask descriptors (see
+/// [maskOf] for details).
+check(String typeMaskDescriptor1, String typeMaskDescriptor2,
+    {areDisjoint: true}) {
+  print('[$typeMaskDescriptor1] & [$typeMaskDescriptor2]');
+  checkMask(maskOf(typeMaskDescriptor1), maskOf(typeMaskDescriptor2),
+      areDisjoint: areDisjoint);
+}
+
+
+checkUnions(List descriptors1, List descriptors2, {areDisjoint: true}) {
+  print('[$descriptors1] & [$descriptors2]');
+  var m1 = new TypeMask.unionOf(descriptors1.map(maskOf).toList(), world);
+  var m2 = new TypeMask.unionOf(descriptors2.map(maskOf).toList(), world);
+  checkMask(m1, m2, areDisjoint: areDisjoint);
+}
+
+Map _maskCache = {};
+Map _elementCache = {};
+
+/// Parses a descriptor of a flat mask. A descriptor is of the form "AXY" where:
+///   A: either a type T or " " (base class or empty)
+///   X: can be either ! or " " (nullable/nonnullable)
+///   Y: can be either " " (no flag), = (exact), < (subclass), * (subtype)
+///
+/// Examples:
+///   "-! " - empty, non-null
+///   "-  " - null
+///   "Type!=" - non-null exact Type
+///   "Type =" - nullable exact Type
+///   "Type!<" - non-null subclass of Type
+///   "Type!*" - non-null subtype of Type
+TypeMask maskOf(String descriptor) =>
+  _maskCache.putIfAbsent(descriptor, () {
+    Expect.isTrue(descriptor.length >= 3);
+    var type = descriptor.substring(0, descriptor.length - 2);
+    bool isNullable = descriptor[descriptor.length - 2] != '!';
+    bool isExact = descriptor[descriptor.length - 1] == '=';
+    bool isSubclass = descriptor[descriptor.length - 1] == '<';
+    bool isSubtype = descriptor[descriptor.length - 1] == '*';
+
+    if (type == " ") {
+      Expect.isFalse(isExact || isSubclass || isSubtype);
+      return isNullable ? new TypeMask.empty() : new TypeMask.nonNullEmpty();
+    }
+
+    Expect.isTrue(isExact || isSubclass || isSubtype);
+    var element = _elementCache.putIfAbsent(type,
+        () => type == " " ? null : findElement(compiler, type));
+
+    var mask = isExact
+        ? new TypeMask.nonNullExact(element, world)
+        : (isSubclass
+            ? new TypeMask.nonNullSubclass(element, world)
+            : new TypeMask.nonNullSubtype(element, world));
+    return isNullable ? mask.nullable() : mask;
+  });
diff --git a/tests/compiler/dart2js/type_representation_test.dart b/tests/compiler/dart2js/type_representation_test.dart
index 0a2d4e0..ce4f3c8 100644
--- a/tests/compiler/dart2js/type_representation_test.dart
+++ b/tests/compiler/dart2js/type_representation_test.dart
@@ -50,7 +50,7 @@
     }
 
     String stringify(Expression expression) {
-      return prettyPrint(expression, env.compiler).buffer.toString();
+      return prettyPrint(expression, env.compiler);
     }
 
     void expect(DartType type,
diff --git a/tests/compiler/dart2js/type_variable_bound_test.dart b/tests/compiler/dart2js/type_variable_bound_test.dart
index d8a6903..544d664 100644
--- a/tests/compiler/dart2js/type_variable_bound_test.dart
+++ b/tests/compiler/dart2js/type_variable_bound_test.dart
@@ -17,141 +17,136 @@
   });
 }
 
-test(String source, {var errors, var warnings}) {
+Future test(String source, {var errors, var warnings}) async{
   if (errors == null) errors = [];
   if (errors is! List) errors = [errors];
   if (warnings == null) warnings = [];
   if (warnings is! List) warnings = [warnings];
-  asyncTest(() => compile(source).then((compiler) {
-    DiagnosticCollector collector = compiler.diagnosticCollector;
-    Expect.equals(!errors.isEmpty, compiler.compilationFailed);
-    Expect.equals(errors.length, collector.errors.length,
-                  'unexpected error count: ${collector.errors.length} '
-                  'expected ${errors.length}');
-    Expect.equals(warnings.length, collector.warnings.length,
-                  'unexpected warning count: ${collector.warnings.length} '
-                  'expected ${warnings.length}');
+  var compiler = await compile(source);
+  DiagnosticCollector collector = compiler.diagnosticCollector;
+  Expect.equals(!errors.isEmpty, compiler.compilationFailed);
+  Expect.equals(errors.length, collector.errors.length,
+                'unexpected error count: ${collector.errors.length} '
+                'expected ${errors.length}');
+  Expect.equals(warnings.length, collector.warnings.length,
+                'unexpected warning count: ${collector.warnings.length} '
+                'expected ${warnings.length}');
 
-    for (int i = 0 ; i < errors.length ; i++) {
-      Expect.equals(errors[i], collector.errors.elementAt(i).message.kind);
-    }
-    for (int i = 0 ; i < warnings.length ; i++) {
-      Expect.equals(warnings[i], collector.warnings.elementAt(i).message.kind);
-    }
-  }));
+  for (int i = 0 ; i < errors.length ; i++) {
+    Expect.equals(errors[i], collector.errors.elementAt(i).message.kind);
+  }
+  for (int i = 0 ; i < warnings.length ; i++) {
+    Expect.equals(warnings[i], collector.warnings.elementAt(i).message.kind);
+  }
 }
 
-test1() {
-  asyncTest(() => compile(r"""
+Future test1() async {
+  var compiler = await compile(r"""
 class A<T extends T> {}
 
 void main() {
   new A();
 }
-""").then((compiler) {
-    DiagnosticCollector collector = compiler.diagnosticCollector;
-    Expect.isFalse(compiler.compilationFailed);
-    Expect.isTrue(collector.errors.isEmpty,
-                  'unexpected errors: ${collector.errors}');
-    Expect.equals(1, collector.warnings.length,
-                  'expected exactly one warning, but got ${collector.warnings}');
+""");
+  DiagnosticCollector collector = compiler.diagnosticCollector;
+  Expect.isFalse(compiler.compilationFailed);
+  Expect.isTrue(collector.errors.isEmpty,
+                'unexpected errors: ${collector.errors}');
+  Expect.equals(1, collector.warnings.length,
+                'expected exactly one warning, but got ${collector.warnings}');
 
-    print(collector.warnings.elementAt(0));
-    Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
-                  collector.warnings.elementAt(0).message.kind);
-    Expect.equals("T",
-        collector.warnings.elementAt(0).message.arguments['typeVariableName']);
-  }));
+  print(collector.warnings.elementAt(0));
+  Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
+                collector.warnings.elementAt(0).message.kind);
+  Expect.equals("T",
+      collector.warnings.elementAt(0).message.arguments['typeVariableName']);
 }
 
-test2() {
-  asyncTest(() => compile(r"""
+Future test2() async {
+  var compiler = await compile(r"""
 class B<T extends S, S extends T> {}
 
 void main() {
   new B();
 }
-""").then((compiler) {
-    DiagnosticCollector collector = compiler.diagnosticCollector;
-    Expect.isFalse(compiler.compilationFailed);
-    print(collector.errors);
-    Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
-    Expect.equals(2, collector.warnings.length,
-                  'expected exactly two errors, but got ${collector.warnings}');
+""");
+  DiagnosticCollector collector = compiler.diagnosticCollector;
+  Expect.isFalse(compiler.compilationFailed);
+  print(collector.errors);
+  Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
+  Expect.equals(2, collector.warnings.length,
+                'expected exactly two errors, but got ${collector.warnings}');
 
-    Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
-                  collector.warnings.elementAt(0).message.kind);
-    Expect.equals("T",
-        collector.warnings.elementAt(0).message.arguments['typeVariableName']);
+  Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
+                collector.warnings.elementAt(0).message.kind);
+  Expect.equals("T",
+      collector.warnings.elementAt(0).message.arguments['typeVariableName']);
 
-    Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
-                  collector.warnings.elementAt(1).message.kind);
-    Expect.equals("S",
-        collector.warnings.elementAt(1).message.arguments['typeVariableName']);
-  }));
+  Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
+                collector.warnings.elementAt(1).message.kind);
+  Expect.equals("S",
+      collector.warnings.elementAt(1).message.arguments['typeVariableName']);
 }
 
-test3() {
-  asyncTest(() => compile(r"""
+Future test3() async {
+  var compiler = await compile(r"""
 class C<T extends S, S extends U, U extends T> {}
 
 void main() {
   new C();
 }
-""").then((compiler) {
-    DiagnosticCollector collector = compiler.diagnosticCollector;
-    Expect.isFalse(compiler.compilationFailed);
-    print(collector.errors);
-    Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
-    Expect.equals(3, collector.warnings.length,
-                  'expected exactly one error, but got ${collector.warnings}');
+""");
+  DiagnosticCollector collector = compiler.diagnosticCollector;
+  Expect.isFalse(compiler.compilationFailed);
+  print(collector.errors);
+  Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
+  Expect.equals(3, collector.warnings.length,
+                'expected exactly one error, but got ${collector.warnings}');
 
-    Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
-                  collector.warnings.elementAt(0).message.kind);
-    Expect.equals("T",
-        collector.warnings.elementAt(0).message.arguments['typeVariableName']);
+  Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
+                collector.warnings.elementAt(0).message.kind);
+  Expect.equals("T",
+      collector.warnings.elementAt(0).message.arguments['typeVariableName']);
 
-    Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
-                  collector.warnings.elementAt(1).message.kind);
-    Expect.equals("S",
-        collector.warnings.elementAt(1).message.arguments['typeVariableName']);
+  Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
+                collector.warnings.elementAt(1).message.kind);
+  Expect.equals("S",
+      collector.warnings.elementAt(1).message.arguments['typeVariableName']);
 
-    Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
-                  collector.warnings.elementAt(2).message.kind);
-    Expect.equals("U",
-        collector.warnings.elementAt(2).message.arguments['typeVariableName']);
-  }));
+  Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
+                collector.warnings.elementAt(2).message.kind);
+  Expect.equals("U",
+      collector.warnings.elementAt(2).message.arguments['typeVariableName']);
 }
 
-test4() {
-  asyncTest(() => compile(r"""
+Future test4() async {
+  var compiler = await compile(r"""
 class D<T extends S, S extends U, U extends S> {}
 
 void main() {
   new D();
 }
-""").then((compiler) {
-    DiagnosticCollector collector = compiler.diagnosticCollector;
-    Expect.isFalse(compiler.compilationFailed);
-    print(collector.errors);
-    Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
-    Expect.equals(2, collector.warnings.length,
-                  'expected exactly one error, but got ${collector.warnings}');
+""");
+  DiagnosticCollector collector = compiler.diagnosticCollector;
+  Expect.isFalse(compiler.compilationFailed);
+  print(collector.errors);
+  Expect.isTrue(collector.errors.isEmpty, 'unexpected errors');
+  Expect.equals(2, collector.warnings.length,
+                'expected exactly one error, but got ${collector.warnings}');
 
-    Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
-                  collector.warnings.elementAt(0).message.kind);
-    Expect.equals("S",
-        collector.warnings.elementAt(0).message.arguments['typeVariableName']);
+  Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
+                collector.warnings.elementAt(0).message.kind);
+  Expect.equals("S",
+      collector.warnings.elementAt(0).message.arguments['typeVariableName']);
 
-    Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
-                  collector.warnings.elementAt(1).message.kind);
-    Expect.equals("U",
-        collector.warnings.elementAt(1).message.arguments['typeVariableName']);
-  }));
+  Expect.equals(MessageKind.CYCLIC_TYPE_VARIABLE,
+                collector.warnings.elementAt(1).message.kind);
+  Expect.equals("U",
+      collector.warnings.elementAt(1).message.arguments['typeVariableName']);
 }
 
-test5() {
-  test(r"""
+Future test5() {
+  return test(r"""
 class A<T extends num> {}
 
 void main() {
@@ -164,8 +159,8 @@
 """);
 }
 
-test6() {
-  test(r"""
+Future test6() {
+  return test(r"""
 class A<T extends num> {}
 
 void main() {
@@ -174,8 +169,8 @@
 """, warnings: MessageKind.INVALID_TYPE_VARIABLE_BOUND);
 }
 
-test7() {
-  test(r"""
+Future test7() {
+  return test(r"""
 class A<T extends num> {}
 class B<T> extends A<T> {} // Warning produced here.
 
@@ -186,8 +181,8 @@
 """, warnings: MessageKind.INVALID_TYPE_VARIABLE_BOUND);
 }
 
-test8() {
-  test(r"""
+Future test8() {
+  return test(r"""
 class B<T extends B<T>> {}
 class C<T extends B<T>> extends B<T> {}
 class D<T extends C<T>> extends C<T> {}
@@ -213,8 +208,8 @@
 """);
 }
 
-test9() {
-  test(r"""
+Future test9() {
+  return test(r"""
 class B<T extends B<T>> {}
 class C<T extends B<T>> extends B<T> {}
 class D<T extends C<T>> extends C<T> {}
@@ -229,8 +224,8 @@
                 MessageKind.INVALID_TYPE_VARIABLE_BOUND]);
 }
 
-test10() {
-  test(r"""
+Future test10() {
+  return test(r"""
 class A {
   const A();
 }
@@ -246,8 +241,8 @@
 
 // TODO(het): The error is reported twice because both the Dart and JS constant
 // compilers are run on the const constructor, investigate why.
-test11() {
-  test(r"""
+Future test11() {
+  return test(r"""
 class A {
   const A();
 }
@@ -265,15 +260,17 @@
 }
 
 main() {
-  test1();
-  test2();
-  test3();
-  test4();
-  test5();
-  test6();
-  test7();
-  test8();
-  test9();
-  test10();
-  test11();
+  asyncTest(() async {
+    await test1();
+    await test2();
+    await test3();
+    await test4();
+    await test5();
+    await test6();
+    await test7();
+    await test8();
+    await test9();
+    await test10();
+    await test11();
+  });
 }
diff --git a/tests/compiler/dart2js/world_test.dart b/tests/compiler/dart2js/world_test.dart
index 13a0821..0109f8d 100644
--- a/tests/compiler/dart2js/world_test.dart
+++ b/tests/compiler/dart2js/world_test.dart
@@ -7,13 +7,22 @@
 import 'package:expect/expect.dart';
 import 'package:async_helper/async_helper.dart';
 import 'type_test_helper.dart';
+import 'package:compiler/src/common.dart';
 import 'package:compiler/src/elements/elements.dart'
        show Element, ClassElement;
+import 'package:compiler/src/universe/class_set.dart';
 import 'package:compiler/src/world.dart' show ClassWorld;
 
 void main() {
-  asyncTest(() => TypeEnvironment.create(r"""
-      class A {}
+  asyncTest(() async {
+    await testClassSets();
+    await testProperties();
+  });
+}
+
+testClassSets() async {
+  var env = await TypeEnvironment.create(r"""
+      class A implements X {}
       class B {}
       class C_Super extends A {}
       class C extends C_Super {}
@@ -21,6 +30,7 @@
       class E extends B implements A {}
       class F extends Object with A implements B {}
       class G extends Object with A, B {}
+      class X {}
       """,
       mainSource: r"""
       main() {
@@ -33,120 +43,283 @@
         new G();
       }
       """,
-      useMockCompiler: false).then((env) {
-    ClassWorld classWorld = env.compiler.world;
+      useMockCompiler: false);
+  ClassWorld classWorld = env.compiler.world;
 
-    ClassElement Object_ = env.getElement("Object");
-    ClassElement A = env.getElement("A");
-    ClassElement B = env.getElement("B");
-    ClassElement C = env.getElement("C");
-    ClassElement D = env.getElement("D");
-    ClassElement E = env.getElement("E");
-    ClassElement F = env.getElement("F");
-    ClassElement G = env.getElement("G");
+  ClassElement Object_ = env.getElement("Object");
+  ClassElement A = env.getElement("A");
+  ClassElement B = env.getElement("B");
+  ClassElement C = env.getElement("C");
+  ClassElement D = env.getElement("D");
+  ClassElement E = env.getElement("E");
+  ClassElement F = env.getElement("F");
+  ClassElement G = env.getElement("G");
+  ClassElement X = env.getElement("X");
 
-    void check(
-        String property,
-        ClassElement cls,
-        Iterable<ClassElement> foundClasses,
-        List<ClassElement> expectedClasses,
-        {bool exact: true}) {
-      for (ClassElement expectedClass in expectedClasses) {
-        Expect.isTrue(foundClasses.contains(expectedClass),
-            "Expect $expectedClass in '$property' on $cls. "
-            "Found:\n ${foundClasses.join('\n ')}");
+  void checkClasses(
+      String property,
+      ClassElement cls,
+      Iterable<ClassElement> foundClasses,
+      List<ClassElement> expectedClasses,
+      {bool exact: true}) {
+
+    for (ClassElement expectedClass in expectedClasses) {
+      Expect.isTrue(foundClasses.contains(expectedClass),
+          "Expect $expectedClass in '$property' on $cls. "
+          "Found:\n ${foundClasses.join('\n ')}\n"
+          "${env.compiler.world.dump(cls)}");
+    }
+    if (exact) {
+      Expect.equals(expectedClasses.length, foundClasses.length,
+          "Unexpected classes "
+          "${foundClasses.where((c) => !expectedClasses.contains(c))} "
+          "in '$property' on $cls.\n"
+          "${env.compiler.world.dump(cls)}");
+    }
+  }
+
+  void check(
+      String property,
+      ClassElement cls,
+      Iterable<ClassElement> foundClasses,
+      List<ClassElement> expectedClasses,
+      {bool exact: true,
+       void forEach(ClassElement cls, ForEachFunction f),
+       int getCount(ClassElement cls)}) {
+    checkClasses(property, cls, foundClasses, expectedClasses, exact: exact);
+
+    if (forEach != null) {
+      List<ClassElement> visited = <ClassElement>[];
+      forEach(cls, (ClassElement c) {
+        visited.add(c);
+      });
+      checkClasses(
+          'forEach($property)', cls, visited, expectedClasses, exact: exact);
+    }
+
+    if (getCount != null && exact) {
+      int count = getCount(cls);
+      Expect.equals(expectedClasses.length, count,
+          "Unexpected class count in '$property' on $cls.\n"
+          "${env.compiler.world.dump(cls)}");
+    }
+
+  }
+
+  void testSubclasses(
+      ClassElement cls,
+      List<ClassElement> expectedClasses,
+      {bool exact: true}) {
+    check(
+      'subclassesOf',
+      cls,
+      classWorld.subclassesOf(cls),
+      expectedClasses,
+      exact: exact);
+  }
+
+  void testStrictSubclasses(
+      ClassElement cls,
+      List<ClassElement> expectedClasses,
+      {bool exact: true}) {
+    check(
+      'strictSubclassesOf',
+      cls,
+      classWorld.strictSubclassesOf(cls),
+      expectedClasses,
+      exact: exact,
+      forEach: classWorld.forEachStrictSubclassOf,
+      getCount: classWorld.strictSubclassCount);
+  }
+
+  void testStrictSubtypes(
+      ClassElement cls,
+      List<ClassElement> expectedClasses,
+      {bool exact: true}) {
+    check(
+      'strictSubtypesOf',
+      cls,
+      classWorld.strictSubtypesOf(cls),
+      expectedClasses,
+      exact: exact,
+      forEach: classWorld.forEachStrictSubtypeOf,
+      getCount: classWorld.strictSubtypeCount);
+  }
+
+  void testMixinUses(
+      ClassElement cls,
+      List<ClassElement> expectedClasses,
+      {bool exact: true}) {
+    check(
+      'mixinUsesOf',
+      cls,
+      classWorld.mixinUsesOf(cls),
+      expectedClasses,
+      exact: exact);
+  }
+
+  testSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
+  testSubclasses(A, [A, C]);
+  testSubclasses(B, [B, E]);
+  testSubclasses(C, [C]);
+  testSubclasses(D, [D]);
+  testSubclasses(E, [E]);
+  testSubclasses(F, [F]);
+  testSubclasses(G, [G]);
+  testSubclasses(X, []);
+
+  testStrictSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
+  testStrictSubclasses(A, [C]);
+  testStrictSubclasses(B, [E]);
+  testStrictSubclasses(C, []);
+  testStrictSubclasses(D, []);
+  testStrictSubclasses(E, []);
+  testStrictSubclasses(F, []);
+  testStrictSubclasses(G, []);
+  testStrictSubclasses(X, []);
+
+  testStrictSubtypes(Object_, [A, B, C, D, E, F, G], exact: false);
+  testStrictSubtypes(A, [C, D, E, F, G]);
+  testStrictSubtypes(B, [E, F, G]);
+  testStrictSubtypes(C, []);
+  testStrictSubtypes(D, []);
+  testStrictSubtypes(E, []);
+  testStrictSubtypes(F, []);
+  testStrictSubtypes(G, []);
+  testStrictSubtypes(X, [A, C, D, E, F, G]);
+
+  testMixinUses(Object_, []);
+  testMixinUses(A, [F.superclass, G.superclass.superclass]);
+  testMixinUses(B, [G.superclass]);
+  testMixinUses(C, []);
+  testMixinUses(D, []);
+  testMixinUses(E, []);
+  testMixinUses(F, []);
+  testMixinUses(G, []);
+  testMixinUses(X, []);
+}
+
+testProperties() async {
+  var env = await TypeEnvironment.create(r"""
+      class A {}
+      class A1 extends A {}
+      class A2 implements A {}
+      class A3 extends Object with A {}
+
+      class B {}
+      class B1 extends B {}
+      class B2 implements B {}
+      class B3 extends Object with B {}
+
+      class C {}
+      class C1 extends C {}
+      class C2 implements C {}
+      class C3 extends Object with C {}
+
+      class D {}
+      class D1 extends D {}
+      class D2 implements D {}
+      class D3 extends Object with D {}
+
+      class E {}
+      class E1 extends E {}
+      class E2 implements E {}
+      class E3 extends Object with E {}
+
+      class F {}
+      class F1 extends F {}
+      class F2 implements F {}
+      class F3 extends Object with F {}
+
+      class G {}
+      class G1 extends G {}
+      class G2 extends G1 {}
+      class G3 extends G2 implements G {}
+      class G4 extends G2 with G {}
+
+      class H {}
+      class H1 extends H {}
+      class H2 extends H1 {}
+      class H3 extends H2 implements H {}
+      class H4 extends H2 with H {}
+      """,
+      mainSource: r"""
+      main() {
+        new B();
+        new C1();
+        new D2();
+        new E3();
+        new F1();
+        new F2();
+        new G2();
+        new G3();
+        new H4();
       }
-      if (exact) {
-        Expect.equals(expectedClasses.length, foundClasses.length,
-            "Unexpected classes "
-            "${foundClasses.where((c) => !expectedClasses.contains(c))} "
-            "in '$property' on $cls.");
-      }
-    }
+      """,
+      useMockCompiler: false);
+  ClassWorld classWorld = env.compiler.world;
 
-    void testSubclasses(
-        ClassElement cls,
-        List<ClassElement> expectedClasses,
-        {bool exact: true}) {
-      check(
-        'subclassesOf',
-        cls,
-        classWorld.subclassesOf(cls),
-        expectedClasses,
-        exact: exact);
-    }
+  check(String name,
+      {bool hasStrictSubtype,
+       bool hasOnlySubclasses}) {
+    ClassElement cls = env.getElement(name);
+    Expect.equals(hasStrictSubtype, classWorld.hasAnyStrictSubtype(cls),
+        "Unexpected hasAnyStrictSubtype property on $cls.");
+    Expect.equals(hasOnlySubclasses, classWorld.hasOnlySubclasses(cls),
+        "Unexpected hasOnlySubclasses property on $cls.");
+  }
 
-    void testStrictSubclasses(
-        ClassElement cls,
-        List<ClassElement> expectedClasses,
-        {bool exact: true}) {
-      check(
-        'strictSubclassesOf',
-        cls,
-        classWorld.strictSubclassesOf(cls),
-        expectedClasses,
-        exact: exact);
-    }
+  check("Object", hasStrictSubtype: true, hasOnlySubclasses: true);
 
-    void testStrictSubtypes(
-        ClassElement cls,
-        List<ClassElement> expectedClasses,
-        {bool exact: true}) {
-      check(
-        'strictSubtypesOf',
-        cls,
-        classWorld.strictSubtypesOf(cls),
-        expectedClasses,
-        exact: exact);
-    }
+  // No instantiated Ax classes.
+  check("A", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("A1", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("A2", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("A3", hasStrictSubtype: false, hasOnlySubclasses: true);
 
-    void testMixinUses(
-        ClassElement cls,
-        List<ClassElement> expectedClasses,
-        {bool exact: true}) {
-      check(
-        'mixinUsesOf',
-        cls,
-        classWorld.mixinUsesOf(cls),
-        expectedClasses,
-        exact: exact);
-    }
+  // class B instantiated
+  check("B", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("B1", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("B2", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("B3", hasStrictSubtype: false, hasOnlySubclasses: true);
 
-    testSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
-    testSubclasses(A, [A, C]);
-    testSubclasses(B, [B, E]);
-    testSubclasses(C, [C]);
-    testSubclasses(D, [D]);
-    testSubclasses(E, [E]);
-    testSubclasses(F, [F]);
-    testSubclasses(G, [G]);
+  // class C1 extends C instantiated
+  check("C", hasStrictSubtype: true, hasOnlySubclasses: true);
+  check("C1", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("C2", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("C3", hasStrictSubtype: false, hasOnlySubclasses: true);
 
-    testStrictSubclasses(Object_, [A, B, C, D, E, F, G], exact: false);
-    testStrictSubclasses(A, [C]);
-    testStrictSubclasses(B, [E]);
-    testStrictSubclasses(C, []);
-    testStrictSubclasses(D, []);
-    testStrictSubclasses(E, []);
-    testStrictSubclasses(F, []);
-    testStrictSubclasses(G, []);
+  // class D2 implements D instantiated
+  check("D", hasStrictSubtype: true, hasOnlySubclasses: false);
+  check("D1", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("D2", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("D3", hasStrictSubtype: false, hasOnlySubclasses: true);
 
-    testStrictSubtypes(Object_, [A, B, C, D, E, F, G], exact: false);
-    testStrictSubtypes(A, [C, D, E, F, G]);
-    testStrictSubtypes(B, [E, F, G]);
-    testStrictSubtypes(C, []);
-    testStrictSubtypes(D, []);
-    testStrictSubtypes(E, []);
-    testStrictSubtypes(F, []);
-    testStrictSubtypes(G, []);
+  // class E2 extends Object with E instantiated
+  check("E", hasStrictSubtype: true, hasOnlySubclasses: false);
+  check("E1", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("E2", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("E3", hasStrictSubtype: false, hasOnlySubclasses: true);
 
-    testMixinUses(Object_, []);
-    testMixinUses(A, [F.superclass, G.superclass.superclass]);
-    testMixinUses(B, [G.superclass]);
-    testMixinUses(C, []);
-    testMixinUses(D, []);
-    testMixinUses(E, []);
-    testMixinUses(F, []);
-    testMixinUses(G, []);
+  // class F1 extends F instantiated
+  // class F2 implements F instantiated
+  check("F", hasStrictSubtype: true, hasOnlySubclasses: false);
+  check("F1", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("F2", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("F3", hasStrictSubtype: false, hasOnlySubclasses: true);
 
-  }));
+  // class G2 extends G1 extends G instantiated
+  // class G3 extends G2 extends G1 extends G instantiated
+  check("G", hasStrictSubtype: true, hasOnlySubclasses: true);
+  check("G1", hasStrictSubtype: true, hasOnlySubclasses: true);
+  check("G2", hasStrictSubtype: true, hasOnlySubclasses: true);
+  check("G3", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("G4", hasStrictSubtype: false, hasOnlySubclasses: true);
+
+  // class H4 extends H2 with H extends H1 extends H instantiated
+  check("H", hasStrictSubtype: true, hasOnlySubclasses: true);
+  check("H1", hasStrictSubtype: true, hasOnlySubclasses: true);
+  check("H2", hasStrictSubtype: true, hasOnlySubclasses: true);
+  check("H3", hasStrictSubtype: false, hasOnlySubclasses: true);
+  check("H4", hasStrictSubtype: false, hasOnlySubclasses: true);
 }
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 3d00167..1399e79 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -3,7 +3,6 @@
 # BSD-style license that can be found in the LICENSE file.
 
 [ $compiler == dart2js ]
-16407_test: Fail # Issue 16407
 class_test: Fail
 statements_test: Fail
 typed_locals_test: Fail
@@ -59,6 +58,7 @@
 [ $compiler == dart2js && $csp ]
 deferred_fail_and_retry_test: SkipByDesign # Uses eval to simulate failed loading.
 deferred_fail_and_retry_worker_test: SkipByDesign # Uses eval to simulate failed loading.
+deferred_custom_loader_test: SkipByDesign # Issue 25683
 
 [ $compiler == none && $runtime == vm ]
 invalid_annotation_test/01: MissingCompileTimeError, OK # vm is lazy
@@ -68,6 +68,4 @@
 big_allocation_expression_test: Crash # Issue 24635
 
 [ $compiler == dart2js && $cps_ir ]
-16407_test: Pass # Please triage this failure.
 async_stacktrace_test/asyncStar: Crash # (foo()async*{try {tr...  cannot handle sync*/async* functions
-switch_test/none: Crash # (switch (val){foo:ba...  continue to a labeled switch case
diff --git a/tests/compiler/dart2js_extra/deferred_custom_loader_lib.dart b/tests/compiler/dart2js_extra/deferred_custom_loader_lib.dart
new file mode 100644
index 0000000..e863607
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred_custom_loader_lib.dart
@@ -0,0 +1,5 @@
+// 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.
+
+foo() => 499;
diff --git a/tests/compiler/dart2js_extra/deferred_custom_loader_test.dart b/tests/compiler/dart2js_extra/deferred_custom_loader_test.dart
new file mode 100644
index 0000000..4889aca
--- /dev/null
+++ b/tests/compiler/dart2js_extra/deferred_custom_loader_test.dart
@@ -0,0 +1,36 @@
+// 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:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+
+import 'deferred_custom_loader_lib.dart' deferred as def;
+
+void setup() native """
+// In d8 we don't have any way to load the content of the file, so just use
+// the preamble's loader.
+if (!self.dartDeferredLibraryLoader) {
+  self.dartDeferredLibraryLoader = function(uri, success, error) {
+    var req = new XMLHttpRequest();
+    req.addEventListener("load", function() {
+      eval(this.responseText);
+      success();
+    });
+    req.open("GET", uri);
+    req.send();
+  };
+}
+""";
+
+
+runTest() async {
+  setup();
+  await def.loadLibrary();
+  Expect.equals(499, def.foo());
+}
+
+main() {
+  asyncStart();
+  runTest().then((_) => asyncEnd());
+}
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index dfe56d3..3a172de 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -21,6 +21,7 @@
 compute_this_script_test: Skip # Issue 17458
 
 [ $compiler == dart2js && $cps_ir ]
+foreign_test: RuntimeError # Expect.equals(expected: <1234567891011>, actual: <1234567891011>) fails.
 native_exception_test: RuntimeError # Issue 24421
 optimization_hints_test: RuntimeError # Please triage this failure.
 subclassing_constructor_2_test: RuntimeError # Please triage this failure.
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 88b3ccd..52a0522 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -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.
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
+[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
 bool_from_environment2_test: Skip
 bool_from_environment_test: Skip
 from_environment_const_type_test: Skip
@@ -14,55 +14,17 @@
 string_from_environment3_test: Skip
 string_from_environment_test: Skip
 
-[ ($compiler == none || $compiler == precompiler) ]
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) ]
 unicode_test: Fail        # Bug 6706
 compare_to2_test: Fail    # Bug 4018
 
 symbol_test/01: Fail, Pass # bug 11669
 
-# #void should be a valid symbol.
-[ ($compiler == none || $compiler == precompiler) || $compiler == dart2js ]
-symbol_reserved_word_test/02: CompileTimeError # bug 20191
-symbol_reserved_word_test/05: CompileTimeError # bug 20191
-
-[ ($compiler == none || $compiler == precompiler) && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
-symbol_reserved_word_test/02: RuntimeError # bug 20191 / dartium/drt cannot detect CompileTimeErrors
-symbol_reserved_word_test/05: RuntimeError # bug 20191 / dartium/drt cannot detect CompileTimeErrors
-
-# new Symbol('void') should be allowed.
-[ $compiler == dart2js ]
-symbol_reserved_word_test/03: RuntimeError # bug 19972
-int_parse_radix_test/01: Pass, Fail # JS implementations disagree on U+0085 being whitespace.
-int_parse_radix_test/02: Fail # No bigints.
-double_parse_test/01: Pass, Fail # JS implementations disagree on U+0085 being whitespace.
-integer_to_radix_string_test: RuntimeError # issue 22045
-int_modulo_arith_test/bignum: RuntimeError # No bigints.
-int_modulo_arith_test/modPow: RuntimeError # No bigints.
-
-
-# With the exception of 'void', const Symbol() should not accept reserved
-# words.
-[ ($compiler == none || $compiler == precompiler) || $compiler == dart2js ]
-symbol_reserved_word_test/04: MissingCompileTimeError # bug 11669, 19972
-symbol_reserved_word_test/07: MissingCompileTimeError # bug 11669, 19972
-symbol_reserved_word_test/10: MissingCompileTimeError # bug 11669, 19972
-
-[ ($compiler == none || $compiler == precompiler) && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
-symbol_reserved_word_test/04: Fail # bug 11669, 19972 / dartium/drt cannot detect CompileTimeErrors
-symbol_reserved_word_test/07: Fail # bug 11669, 19972 / dartium/drt cannot detect CompileTimeErrors
-symbol_reserved_word_test/10: Fail # bug 11669, 19972 / dartium/drt cannot detect CompileTimeErrors
-
 # With the exception of 'void', new Symbol() should not accept reserved words.
-[ ($compiler == none || $compiler == precompiler) ]
 symbol_reserved_word_test/06: RuntimeError # bug 11669
 symbol_reserved_word_test/09: RuntimeError # bug 11669
 symbol_reserved_word_test/12: RuntimeError # bug 11669
 
-[ ($compiler == none || $compiler == precompiler) && $runtime != dartium && $runtime != drt && $runtime != ContentShellOnAndroid ]
-symbol_test/02: MissingCompileTimeError # bug 11669
-symbol_test/03: MissingCompileTimeError # bug 11669
-
-[ ($compiler == none || $compiler == precompiler) ]
 symbol_test/none: Fail # bug 11669
 symbol_operator_test/03: Fail # bug 11669
 string_case_test/01: Fail # Bug 18061
@@ -70,11 +32,37 @@
 iterable_return_type_test/01: RuntimeError # Issue 13646
 iterable_return_type_test/02: RuntimeError # Issue 13646
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
+# #void should be a valid symbol.
+[ $compiler == none || $compiler == precompiler || $compiler == dart2app || $compiler == dart2js ]
+symbol_reserved_word_test/02: CompileTimeError # bug 20191
+symbol_reserved_word_test/05: CompileTimeError # bug 20191
+
+# With the exception of 'void', const Symbol() should not accept reserved
+# words.
+symbol_reserved_word_test/04: MissingCompileTimeError # bug 11669, 19972
+symbol_reserved_word_test/07: MissingCompileTimeError # bug 11669, 19972
+symbol_reserved_word_test/10: MissingCompileTimeError # bug 11669, 19972
+
+[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
+symbol_reserved_word_test/02: RuntimeError # bug 20191 / dartium/drt cannot detect CompileTimeErrors
+symbol_reserved_word_test/05: RuntimeError # bug 20191 / dartium/drt cannot detect CompileTimeErrors
+symbol_reserved_word_test/04: Fail # bug 11669, 19972 / dartium/drt cannot detect CompileTimeErrors
+symbol_reserved_word_test/07: Fail # bug 11669, 19972 / dartium/drt cannot detect CompileTimeErrors
+symbol_reserved_word_test/10: Fail # bug 11669, 19972 / dartium/drt cannot detect CompileTimeErrors
 main_test: Fail  # Dartium needs to check for both main() and main(args).
 
-[ ($compiler == none || $compiler == precompiler) && $runtime == ContentShellOnAndroid ]
-core_runtime_types_test: Pass, Fail # Issue 20525
+[ $compiler == dart2js ]
+symbol_reserved_word_test/03: RuntimeError # bug 19972, new Symbol('void') should be allowed.
+int_parse_radix_test/01: Pass, Fail # JS implementations disagree on U+0085 being whitespace.
+int_parse_radix_test/02: Fail # No bigints.
+double_parse_test/01: Pass, Fail # JS implementations disagree on U+0085 being whitespace.
+integer_to_radix_string_test: RuntimeError # issue 22045
+int_modulo_arith_test/bignum: RuntimeError # No bigints.
+int_modulo_arith_test/modPow: RuntimeError # No bigints.
+
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $runtime != dartium && $runtime != drt ]
+symbol_test/02: MissingCompileTimeError # bug 11669
+symbol_test/03: MissingCompileTimeError # bug 11669
 
 [ $runtime == ff || $runtime == jsshell ]
 unicode_test: Fail
@@ -124,7 +112,7 @@
 [ $compiler == dart2js && ($runtime == safari || $runtime == safarimobilesim) ]
 string_split_test: RuntimeError # Issue 21431
 
-[ $compiler == dart2js && (($runtime == safari && $builder_tag == mac10_7) || $runtime == safarimobilesim) ]
+[ $compiler == dart2js && $runtime == safarimobilesim ]
 list_test/01: Fail # Safari bug: Array(-2) seen as dead code.
 string_trimlr_test/none: Fail
 
@@ -166,54 +154,49 @@
 [ $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 == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 regexp/global_test: Skip # Timeout. Issue 21709 and 21708
 
-[ $runtime != vm && $compiler != dart2analyzer]
-package_resource_test: RuntimeError # Issue 23825 (not implemented yet).
+[ $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 && $runtime != dart_precompiled && $compiler != dart2analyzer && $cps_ir == false ]
+package_resource_test: RuntimeError # Issue 23825 (not implemented yet).
+
 [ $mode == debug ]
 regexp/pcre_test: Pass, Slow # Timeout. Issue 22008
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $arch == simarmv5te ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == simarmv5te ]
 int_parse_radix_test/*: Pass, Slow
 big_integer_parsed_mul_div_vm_test: Pass, Slow
 
 [ $compiler == dart2js && $cps_ir ]
-data_resource_test: Crash # (await for(var byteSlice in resource.openRead()){streamBytes.addAll(byteSlice);}): await for
-error_stack_trace1_test: Pass # H.unwrapException(...).get$stackTrace is not a function
-growable_list_test: RuntimeError # Typed lists
-iterable_empty_test: RuntimeError # Please triage this failure.
-iterable_return_type_test/none: RuntimeError # Please triage this failure.
-iterable_to_list_test: RuntimeError # Please triage this failure.
-iterable_to_set_test: RuntimeError # Please triage this failure.
-list_filled_type_argument_test: RuntimeError # Please triage this failure.
-list_unmodifiable_test: RuntimeError # Please triage this failure.
-map_values2_test: RuntimeError # Please triage this failure.
-map_values3_test: RuntimeError # Please triage this failure.
-map_values4_test: RuntimeError # Please triage this failure.
-package_resource_test: Crash # (await for(var byteSlice in resource.openRead()){streamBytes.addAll(byteSlice);}): await for
+package_resource_test: Crash # Surprisingly null object in type propagation.
 regexp/pcre_test: Crash # Stack Overflow in LoopHierarchy.
-symbol_operator_test/03: RuntimeError # Issue 24878
-symbol_reserved_word_test/03: Pass # Please triage this failure.
-symbol_reserved_word_test/06: RuntimeError # Please triage this failure.
-symbol_reserved_word_test/09: RuntimeError # Please triage this failure.
-symbol_reserved_word_test/12: RuntimeError # Please triage this failure.
-symbol_test/none: RuntimeError # Please triage this failure.
+core_runtime_types_test: Pass, RuntimeError # Issue 25795.
 
 [ $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 ]
+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/corelib/expando_test.dart b/tests/corelib/expando_test.dart
index d55aecf..a7fb1c4 100644
--- a/tests/corelib/expando_test.dart
+++ b/tests/corelib/expando_test.dart
@@ -18,7 +18,7 @@
       testUnnamedExpando(object);
     }
     for (var object in legal) {
-      Expect.equals(2, visits[object]);
+      Expect.equals(2, visits[object], "$object");
     }
     testIllegal();
     testIdentity();
@@ -65,19 +65,19 @@
   static testIllegal() {
     Expando<int> expando = new Expando<int>();
     Expect.throws(() => expando[null], (exception)
-                  => exception is ArgumentError);
+                  => exception is ArgumentError, "null");
     Expect.throws(() => expando['string'], (exception)
-                  => exception is ArgumentError);
+                  => exception is ArgumentError, "'string'");
     Expect.throws(() => expando['string'], (exception)
-                  => exception is ArgumentError);
+                  => exception is ArgumentError, "'string'");
     Expect.throws(() => expando[42], (exception)
-                  => exception is ArgumentError);
+                  => exception is ArgumentError, "42");
     Expect.throws(() => expando[42.87], (exception)
-                  => exception is ArgumentError);
+                  => exception is ArgumentError, "42.87");
     Expect.throws(() => expando[true], (exception)
-                  => exception is ArgumentError);
+                  => exception is ArgumentError, "true");
     Expect.throws(() => expando[false], (exception)
-                  => exception is ArgumentError);
+                  => exception is ArgumentError, "false");
   }
 
   static testIdentity() {
diff --git a/tests/corelib/uri_parameters_all_test.dart b/tests/corelib/uri_parameters_all_test.dart
new file mode 100644
index 0000000..ea40ad8
--- /dev/null
+++ b/tests/corelib/uri_parameters_all_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:convert';
+
+main() {
+  testAll(["a", "b", "c"]);
+  testAll([""]);
+  testAll(["a"]);
+  testAll(["",""]);
+  testAll(["baz"]);
+
+  testParse("z&y&w&z", {"z": ["", ""], "y": [""], "w": [""]});
+  testParse("x=42&y=42&x=37&y=37", {"x": ["42", "37"], "y": ["42", "37"]});
+  testParse("x&x&x&x&x", {"x": ["", "", "", "", ""]});
+  testParse("x=&&y", {"x": [""], "y": [""]});
+}
+
+testAll(List values) {
+  var uri = new Uri(scheme: "foo", path: "bar",
+                    queryParameters: {"baz": values});
+  var list = uri.queryParametersAll["baz"];
+  Expect.listEquals(values, list);
+}
+
+testParse(query, results) {
+  var uri = new Uri(scheme: "foo", path: "bar", query: query);
+  var params = uri.queryParametersAll;
+  for (var k in results.keys) {
+    Expect.listEquals(results[k], params[k]);
+  }
+  uri = new Uri(scheme: "foo", path: "bar", queryParameters: results);
+  params = uri.queryParametersAll;
+  for (var k in results.keys) {
+    Expect.listEquals(results[k], params[k]);
+  }
+}
diff --git a/tests/html/document_test.dart b/tests/html/document_test.dart
index 7e69c1f..2ed520f 100644
--- a/tests/html/document_test.dart
+++ b/tests/html/document_test.dart
@@ -23,26 +23,6 @@
     expect(new Element.tag('bad_name'), isUnknownElement);
   });
 
-  group('supports_cssCanvasContext', () {
-    test('supports_cssCanvasContext', () {
-      expect(HtmlDocument.supportsCssCanvasContext, true);
-    });
-  });
-
-  group('getCssCanvasContext', () {
-    test('getCssCanvasContext 2d', () {
-      var expectation = HtmlDocument.supportsCssCanvasContext ?
-        returnsNormally : throws;
-
-      expect(() {
-        var context = document.getCssCanvasContext('2d', 'testContext', 10, 20);
-        expect(context is CanvasRenderingContext2D, true);
-        expect(context.canvas.width, 10);
-        expect(context.canvas.height, 20);
-      }, expectation);
-    });
-  });
-
   group('document', () {
     inscrutable = (x) => x;
 
diff --git a/tests/html/html.status b/tests/html/html.status
index cf5e043..1facc17 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -29,6 +29,7 @@
 [ $compiler == dart2js ]
 input_element_test/attributes: Fail # Issue 21555
 wrapping_collections_test: SkipByDesign # Testing an issue that is only relevant to Dartium
+js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue #25759
 
 [ $compiler == dart2js && $checked ]
 js_function_getter_trust_types_test: Skip # --trust-type-annotations incompatible with --checked
@@ -102,11 +103,14 @@
 
 [ $runtime == chrome ]
 touchevent_test/supported: Fail # Touch events are only supported on touch devices
-element_animate_test/omit_timing: RuntimeError # Also timing out on MacOS. Issue 23507
-element_animate_test/timing_dict: RuntimeError # Also timing out on MacOS. Issue 23507
 element_animate_test/simple_timing: RuntimeError # Please triage this failure
 element_types_test/supported_object: RuntimeError # Issue 25155
 element_types_test/supported_embed: RuntimeError # Issue 25155
+svgelement_test/PathElement: RuntimeError # Issue 25665
+
+[ $runtime == chrome && $cps_ir == false ]
+element_animate_test/omit_timing: RuntimeError # Also timing out on MacOS. Issue 23507
+element_animate_test/timing_dict: RuntimeError # Also timing out on MacOS. Issue 23507
 
 [ $runtime == chrome && $system == macos ]
 canvasrenderingcontext2d_test/drawImage_video_element: Skip # Times out. Please triage this failure.
@@ -116,8 +120,11 @@
 transition_event_test/functional: Skip # Times out. Issue 22167
 request_animation_frame_test: Skip # Times out. Issue 22167
 
-[$runtime == drt || $runtime == dartium || $runtime == chrome || $runtime == chromeOnAndroid || $runtime == ContentShellOnAndroid ]
+[$runtime == drt || $runtime == dartium || $runtime == chrome || $runtime == chromeOnAndroid ]
 webgl_1_test: Pass, Fail # Issue 8219
+element_animate_test/omit_timing: RuntimeError # Dartium 45 roll. Issue 25786
+element_animate_test/simple_timing: RuntimeError # Dartium 45 roll. Issue 25786
+element_animate_test/timing_dict: RuntimeError # Dartium 45 roll. Issue 25786
 
 [ $compiler == none && ($runtime == drt || $runtime == dartium) && $system == windows ]
 websql_test: Skip # Issue 4941: stderr contains a backtrace.
@@ -155,7 +162,6 @@
 audiocontext_test/supported: Fail
 crypto_test/supported: Fail
 css_test/supportsPointConversions: Fail
-document_test/supports_cssCanvasContext: Fail
 element_types_test/supported_content: Fail
 element_types_test/supported_details: Fail
 element_types_test/supported_keygen: Fail
@@ -214,7 +220,6 @@
 audiocontext_test/supported: Fail
 crypto_test/supported: Fail
 css_test/supportsPointConversions: Fail
-document_test/supports_cssCanvasContext: Fail
 element_types_test/supported_content: Fail
 element_types_test/supported_details: Fail
 element_types_test/supported_keygen: Fail
@@ -334,7 +339,6 @@
 audiocontext_test/supported: Fail
 crypto_test/supported: Fail
 css_test/supportsPointConversions: Fail
-document_test/supports_cssCanvasContext: Fail
 element_types_test/supported_template: Fail
 indexeddb_1_test/supported: Fail
 indexeddb_1_test/supportsDatabaseNames: Fail
@@ -352,7 +356,6 @@
 
 # Firefox Feature support statuses-
 # All changes should be accompanied by platform support annotation changes.
-document_test/supports_cssCanvasContext: Fail
 element_types_test/supported_details: Fail
 element_types_test/supported_embed: Fail
 element_types_test/supported_keygen: Fail
@@ -366,19 +369,14 @@
 input_element_test/supported_week: Fail
 media_stream_test/supported_MediaStreamEvent: Fail
 media_stream_test/supported_MediaStreamTrackEvent: Fail
-mediasource_test/supported: Fail # Behind a flag as of FF 36
 shadow_dom_test/supported: Fail
 speechrecognition_test/supported: Fail
 touchevent_test/supported: Fail
 websql_test/supported: Fail
 
-[ $compiler == dart2js && $runtime == ff && $system == windows ]
-mediasource_test/supported: Pass
-mediasource_test/functional: RuntimeError # Issue 24838
-
 # 'html' tests import the HTML library, so they only make sense in
 # a browser environment.
-[ $runtime == vm || $runtime == dart_precompiled ]
+[ $runtime == vm || $runtime == dart_precompiled || $runtime == dart_product ]
 *: Skip
 
 [ $compiler == dart2js && ($runtime == drt || $runtime == ff) ]
@@ -386,19 +384,20 @@
 
 [ $compiler == dart2js && $csp && ($runtime == drt || $runtime == safari || $runtime == ff || $runtime == chrome || $runtime == chromeOnAndroid) ]
 # Note: these tests are all injecting scripts by design.  This is not allowed under CSP.
-event_customevent_test: Fail        # Test cannot run under CSP restrictions.
-js_interop_1_test: Skip             # Test cannot run under CSP restrictions (times out).
-js_test: Skip                       # Test cannot run under CSP restrictions (times out).
-js_array_test: Skip                 # Test cannot run under CSP restrictions.
-js_typed_interop_test: Skip         # Test cannot run under CSP restrictions.
-js_function_getter_test: Skip       # Test cannot run under CSP restrictions.
-js_function_getter_trust_types_test: Skip  # Test cannot run under CSP restrictions.
-js_dart_to_string_test: Skip        # Test cannot run under CSP restrictions.
-mirrors_js_typed_interop_test: Skip # Test cannot run under CSP restrictions.
-postmessage_structured_test: Skip   # Test cannot run under CSP restrictions (times out).
+event_customevent_test: SkipByDesign
+js_interop_1_test: SkipByDesign
+js_test: SkipByDesign
+js_array_test: SkipByDesign
+js_typed_interop_test: SkipByDesign
+js_typed_interop_default_arg_test: SkipByDesign
+js_function_getter_test: SkipByDesign
+js_function_getter_trust_types_test: SkipByDesign
+js_dart_to_string_test: SkipByDesign
+mirrors_js_typed_interop_test: SkipByDesign
+postmessage_structured_test: SkipByDesign
 
-[ $compiler == dart2js &&  $runtime == chrome]
-svgelement_test/supported_altGlyph: RuntimeError # Issue 23144
+[ $compiler == dart2js &&  ($runtime == chrome || $runtime == drt) ]
+svgelement_test/supported_altGlyph: RuntimeError # Issue 25787
 
 [ ($runtime == dartium) && ($system == macos || $system == windows || $system == linux)]
 # Desktop operating systems do not support touch events on chrome 34 dartium.
@@ -426,6 +425,23 @@
 typing_test: StaticWarning
 webgl_1_test: StaticWarning
 window_nosuchmethod_test: StaticWarning
+js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue #25759
 
-[ $compiler == dart2js && $cps_ir ]
-resource_http_test: Crash # (await for(var b in r.openRead()){bytes.addAll(b);}): await for
+[ $compiler == dart2js && $cps_ir && $browser ]
+# Custom element support:
+custom/constructor_calls_created_synchronously_test: RuntimeError # Need custom element support #25484
+custom/element_upgrade_test: RuntimeError # Need custom element support #25484
+custom/mirrors_test: RuntimeError # Need custom element support #25484
+custom_elements_23127_test/baseline: RuntimeError # Need custom element support #25484
+custom_elements_23127_test/c2: RuntimeError # Need custom element support #25484
+custom_elements_23127_test/c1t: RuntimeError # Need custom element support #25484
+custom_elements_23127_test/c2t: RuntimeError # Need custom element support #25484
+custom_elements_test/innerHtml: RuntimeError # Need custom element support #25484
+custom_elements_test/register: RuntimeError # Need custom element support #25484
+
+js_typed_interop_side_cast_exp_test: RuntimeError # Corner case in package:js that we might want to remove (See comment in #24978).
+js_typed_interop_test/static_method_tearoff_1: RuntimeError # Tree-shaking a used tear-off (#24978, #25720).
+js_typed_interop_default_arg_test/explicit_argument: RuntimeError # Tree-shaking a used tear-off (#24978, #25720).
+
+# These are raw dart:js tests that fail due to bugs in the CPS IR:
+js_test/Dart_functions: RuntimeError # Tree-shaking an escaping closure #25720
diff --git a/tests/html/input_element_test.dart b/tests/html/input_element_test.dart
index 0a12d0b..9509e02 100644
--- a/tests/html/input_element_test.dart
+++ b/tests/html/input_element_test.dart
@@ -186,9 +186,10 @@
     });
     test('valueSetNullProxy', () {
       final e = new TextInputElement();
-      var list = new List(5);
-      e.value = list[0];
+      e.value = _undefined;
       expect(e.value, '');
     });
   });
 }
+
+var _undefined = (() => new List(5)[0])();
diff --git a/tests/html/js_test.dart b/tests/html/js_test.dart
index 37c73ab..a902d59 100644
--- a/tests/html/js_test.dart
+++ b/tests/html/js_test.dart
@@ -322,7 +322,7 @@
 
   });
 
-  group('new JsObject()', () {
+  group('new_JsObject', () {
 
     test('new Foo()', () {
       var foo = new JsObject(context['Foo'], [42]);
@@ -649,7 +649,7 @@
 
   });
 
-  group('Dart functions', () {
+  group('Dart_functions', () {
     test('invoke Dart callback from JS', () {
       expect(() => context.callMethod('invokeCallback'), throws);
 
@@ -752,7 +752,7 @@
     });
   });
 
-  group('JsObject methods', () {
+  group('JsObject_methods', () {
 
     test('hashCode and ==', () {
       final o1 = context['Object'];
diff --git a/tests/html/js_typed_interop_default_arg_test.dart b/tests/html/js_typed_interop_default_arg_test.dart
new file mode 100644
index 0000000..69a0756
--- /dev/null
+++ b/tests/html/js_typed_interop_default_arg_test.dart
@@ -0,0 +1,58 @@
+// 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.
+
+@JS()
+library js_typed_interop_test;
+
+import 'dart:html';
+
+import 'package:expect/expect.dart' show NoInline;
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+_injectJs() {
+  document.body.append(new ScriptElement()
+    ..type = 'text/javascript'
+    ..innerHtml = r"""
+  var Foo = {
+    get42: function(b) { return arguments.length >= 1 ? b : 42; },
+    get43: function(b) { return arguments.length >= 1 ? b : 43; }
+  };
+""");
+}
+
+@JS()
+class Foo {
+  // Note: it's invalid to provide a default value.
+  external static num get42([num b
+      = 3  /// default_value: compile-time error
+  ]);
+  external static num get43([num b]);
+}
+
+main() {
+  _injectJs();
+  useHtmlConfiguration();
+
+  test('call directly from dart', () {
+    expect(Foo.get42(2), 2);
+    expect(Foo.get42(), 42);
+  });
+
+  test('call tearoff from dart with arg', () {
+    var f = Foo.get42;
+    expect(f(2), 2); /// explicit_argument: ok
+  });
+
+  test('call tearoff from dart with default', () {
+    var f = Foo.get42;
+    // Note: today both SSA and CPS remove the extra argument on static calls,
+    // but they fail to do so on tearoffs.
+    expect(f(), 3); /// default_value: continued
+
+    f = Foo.get43;
+    expect(f(), 43);
+  });
+}
diff --git a/tests/html/js_typed_interop_test.dart b/tests/html/js_typed_interop_test.dart
index 14d931f..431d533 100644
--- a/tests/html/js_typed_interop_test.dart
+++ b/tests/html/js_typed_interop_test.dart
@@ -124,6 +124,7 @@
   external callClosureWithArg1(Function closure, arg1);
   external callClosureWithArg2(Function closure, arg1, arg2);
   external Bar getBar();
+
   external static num multiplyDefault2(num a, [num b]);
 }
 
@@ -277,14 +278,26 @@
     });
   });
 
-  group('static method', () {
-    test('call from dart', () {
+  group('static_method_call', () {
+    test('call directly from dart', () {
       expect(Foo.multiplyDefault2(6, 7), equals(42));
       expect(Foo.multiplyDefault2(6), equals(12));
+    });
+  });
+
+  // Note: these extra groups are added to be able to mark each test
+  // individually in status files. This should be split as separate test files.
+  group('static_method_tearoff_1', () {
+    test('call tearoff from dart', () {
       MultiplyWithDefault tearOffMethod = Foo.multiplyDefault2;
       expect(tearOffMethod(6, 6), equals(36));
+    });
+  });
+
+  group('static_method_tearoff_2', () {
+    test('call tearoff from dart', () {
+      MultiplyWithDefault tearOffMethod = Foo.multiplyDefault2;
       expect(tearOffMethod(6), equals(12));
-      Function untypedTearOff = Foo.multiplyDefault2;
     });
   });
 
diff --git a/tests/html/svgelement_test.dart b/tests/html/svgelement_test.dart
index 5527dcd..1fa7259 100644
--- a/tests/html/svgelement_test.dart
+++ b/tests/html/svgelement_test.dart
@@ -70,12 +70,6 @@
   });
 
   // Unfortunately, because the filtering mechanism in unitttest is a regex done
-  group('supported_altGlyph', () {
-    test('supported', () {
-      expect(svg.AltGlyphElement.supported, true);
-    });
-  });
-
   group('supported_animate', () {
     test('supported', () {
       expect(svg.AnimateElement.supported, true);
@@ -277,8 +271,6 @@
       testConstructor('use', (e) => e is svg.UseElement);
       testConstructor('view', (e) => e is svg.ViewElement);
       // TODO(alanknight): Issue 23144
-      testConstructor('altGlyph', (e) => e is svg.AltGlyphElement,
-          svg.AltGlyphElement.supported, false);
       testConstructor('animate', (e) => e is svg.AnimateElement,
           svg.AnimateElement.supported);
       testConstructor('animateMotion', (e) => e is svg.AnimateMotionElement,
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index e11f91a..953be4d 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -2,17 +2,17 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-[ ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 browser/*: SkipByDesign  # Browser specific tests
 isolate_stress_test: Fail # Issue 12588: This should be able to pass when we have wrapper-less tests.
 
 [ $runtime != vm ]
 checked_test: Skip # Unsupported.
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $arch == mips && $mode == debug ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == mips && $mode == debug ]
 mandel_isolate_test: Skip # Uses 600 MB Ram on our 1 GB test device.
 
-[ ($compiler == none || $compiler == precompiler) ]
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) ]
 compile_time_error_test/01: Skip # Issue 12587
 ping_test: Skip           # Resolve test issues
 ping_pause_test: Skip     # Resolve test issues
@@ -20,9 +20,6 @@
 
 message3_test/int32x4: Crash, Timeout # Issue 21818
 
-[ ($compiler == none) && $runtime == ContentShellOnAndroid ]
-*: Skip # Isolate tests are timing out flakily on Android content_shell.  Issue 19795
-
 [ $compiler == dart2js && $runtime == safarimobilesim ]
 compile_time_error_test/none: Pass, Slow
 
@@ -56,9 +53,6 @@
 browser/issue_12474_test: CompileTimeError # Issue 22529
 enum_const_test/02: RuntimeError # Issue 21817
 
-[ $compiler == dart2js && $cps_ir ]
-isolate_current_test: RuntimeError # Please triage this failure.
-
 [ $compiler == dart2js && $runtime != d8 ]
 error_exit_at_spawn_test: Skip # Issue 23876
 error_at_spawn_test: Skip # Issue 23876
@@ -81,22 +75,14 @@
 [ $compiler == dart2js && $runtime == chromeOnAndroid ]
 unresolved_ports_test: Pass, Timeout # Issue 15610
 
-[ ($compiler == none) && $runtime == drt ]
-spawn_uri_nested_vm_test: Skip # Issue 14463
-
 [ $jscl ]
 spawn_uri_multi_test/none: RuntimeError # Issue 13544
 
-[ ($compiler == none) && $runtime == ContentShellOnAndroid ]
-nested_spawn2_test: Skip # Issue 19127: This test is timing out.
-
-[ ($compiler == none) && ($runtime == dartium || $runtime == ContentShellOnAndroid) ]
-spawn_uri_nested_vm_test: Skip # Issue 14479: This test is timing out.
-
 [ ($compiler == none) && $runtime == dartium && $arch == x64 ]
 isolate/spawn_uri_multi_test/01: Skip # Times out. Issue 24795
 
-[ ($compiler == none) && ( $runtime == dartium || $runtime == drt || $runtime == ContentShellOnAndroid) ]
+[ ($compiler == none) && ( $runtime == dartium || $runtime == drt) ]
+spawn_uri_nested_vm_test: Skip # Issue 14479: This test is timing out. Issue 14463
 typed_message_test: Skip # Issue 13921, 14400
 isolate_stress_test: Skip # Issue 13921 Dom isolates don't support spawnFunction
 object_leak_test: Skip # Issue 13921 Dom isolates don't support spawnFunction
@@ -153,29 +139,33 @@
 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
 
-[ $runtime == dart_precompiled ]
+[ $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
 deferred_in_isolate2_test: Skip # Isolate.spawnUri
 exit_at_spawnuri_test: Skip # Isolate.spawnUri
@@ -190,3 +180,7 @@
 spawn_uri_vm_test: Skip # Isolate.spawnUri
 issue_21398_parent_isolate_test: Skip # Isolate.spawnUri
 error_at_spawnuri_test: Skip # Isolate.spawnUri
+
+[ $runtime == dart_product ]
+spawn_uri_missing_from_isolate_test: Skip # SpawnUri in product mode
+spawn_uri_missing_test: Skip # SpawnUri in product mode
diff --git a/tests/isolate/timer_isolate_test.dart b/tests/isolate/timer_isolate_test.dart
index 7513dad..cb8fcbb 100644
--- a/tests/isolate/timer_isolate_test.dart
+++ b/tests/isolate/timer_isolate_test.dart
@@ -23,18 +23,16 @@
 
 main() {
   test("timer in isolate", () {
-    int startTime;
-    int endTime;
-
+    Stopwatch stopwatch = new Stopwatch();
     ReceivePort port = new ReceivePort();
 
     port.first.then(expectAsync((msg) {
       expect("timer_fired", msg);
-      int endTime = (new DateTime.now()).millisecondsSinceEpoch;
-      expect(endTime - startTime + safetyMargin, greaterThanOrEqualTo(TIMEOUT.inMilliseconds));
+      expect(stopwatch.elapsedMilliseconds + safetyMargin,
+             greaterThanOrEqualTo(TIMEOUT.inMilliseconds));
     }));
 
-    startTime = (new DateTime.now()).millisecondsSinceEpoch;
+    stopwatch.start();
     var remote = Isolate.spawn(createTimer, port.sendPort);
   });
 }
diff --git a/tests/language/accessor_conflict_export2_helper.dart b/tests/language/accessor_conflict_export2_helper.dart
new file mode 100644
index 0000000..a6cf7e0
--- /dev/null
+++ b/tests/language/accessor_conflict_export2_helper.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export "accessor_conflict_setter.dart";
+export "accessor_conflict_getter.dart";
diff --git a/tests/language/accessor_conflict_export2_test.dart b/tests/language/accessor_conflict_export2_test.dart
new file mode 100644
index 0000000..725f8e0
--- /dev/null
+++ b/tests/language/accessor_conflict_export2_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files via a common export.  In this test the setter is imported
+// first.
+
+import "package:expect/expect.dart";
+
+import "accessor_conflict_export2_helper.dart";
+
+main() {
+  getValue = 123;
+  Expect.equals(x, 123);
+  x = 456;
+  Expect.equals(setValue, 456);
+}
diff --git a/tests/language/accessor_conflict_export_helper.dart b/tests/language/accessor_conflict_export_helper.dart
new file mode 100644
index 0000000..ff065ec
--- /dev/null
+++ b/tests/language/accessor_conflict_export_helper.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export "accessor_conflict_getter.dart";
+export "accessor_conflict_setter.dart";
diff --git a/tests/language/accessor_conflict_export_test.dart b/tests/language/accessor_conflict_export_test.dart
new file mode 100644
index 0000000..bac516c
--- /dev/null
+++ b/tests/language/accessor_conflict_export_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files via a common export.  In this test the getter is imported
+// first.
+
+import "package:expect/expect.dart";
+
+import "accessor_conflict_export_helper.dart";
+
+main() {
+  getValue = 123;
+  Expect.equals(x, 123);
+  x = 456;
+  Expect.equals(setValue, 456);
+}
diff --git a/tests/language/accessor_conflict_getter.dart b/tests/language/accessor_conflict_getter.dart
new file mode 100644
index 0000000..5b8d72f
--- /dev/null
+++ b/tests/language/accessor_conflict_getter.dart
@@ -0,0 +1,7 @@
+// 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.
+
+var getValue;
+
+get x => getValue;
diff --git a/tests/language/accessor_conflict_import2_test.dart b/tests/language/accessor_conflict_import2_test.dart
new file mode 100644
index 0000000..99a4007
--- /dev/null
+++ b/tests/language/accessor_conflict_import2_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files.  In this test the setter is imported first.
+
+import "package:expect/expect.dart";
+
+import "accessor_conflict_setter.dart";
+import "accessor_conflict_getter.dart";
+
+main() {
+  getValue = 123;
+  Expect.equals(x, 123);
+  x = 456;
+  Expect.equals(setValue, 456);
+}
diff --git a/tests/language/accessor_conflict_import_prefixed2_test.dart b/tests/language/accessor_conflict_import_prefixed2_test.dart
new file mode 100644
index 0000000..88ab758
--- /dev/null
+++ b/tests/language/accessor_conflict_import_prefixed2_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files.  In this test the setter is imported first.
+
+import "package:expect/expect.dart";
+
+import "accessor_conflict_setter.dart" as p;
+import "accessor_conflict_getter.dart" as p;
+
+main() {
+  p.getValue = 123;
+  Expect.equals(p.x, 123);
+  p.x = 456;
+  Expect.equals(p.setValue, 456);
+}
diff --git a/tests/language/accessor_conflict_import_prefixed_test.dart b/tests/language/accessor_conflict_import_prefixed_test.dart
new file mode 100644
index 0000000..0c286cb
--- /dev/null
+++ b/tests/language/accessor_conflict_import_prefixed_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files.  In this test the getter is imported first.
+
+import "package:expect/expect.dart";
+
+import "accessor_conflict_getter.dart" as p;
+import "accessor_conflict_setter.dart" as p;
+
+main() {
+  p.getValue = 123;
+  Expect.equals(p.x, 123);
+  p.x = 456;
+  Expect.equals(p.setValue, 456);
+}
diff --git a/tests/language/accessor_conflict_import_test.dart b/tests/language/accessor_conflict_import_test.dart
new file mode 100644
index 0000000..0b485ce
--- /dev/null
+++ b/tests/language/accessor_conflict_import_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Verify that a getter and its corresponding setter can be imported from two
+// different files.  In this test the getter is imported first.
+
+import "package:expect/expect.dart";
+
+import "accessor_conflict_getter.dart";
+import "accessor_conflict_setter.dart";
+
+main() {
+  getValue = 123;
+  Expect.equals(x, 123);
+  x = 456;
+  Expect.equals(setValue, 456);
+}
diff --git a/tests/language/accessor_conflict_setter.dart b/tests/language/accessor_conflict_setter.dart
new file mode 100644
index 0000000..9dcf67d
--- /dev/null
+++ b/tests/language/accessor_conflict_setter.dart
@@ -0,0 +1,7 @@
+// 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.
+
+var setValue;
+
+set x(value) { setValue = value; }
diff --git a/tests/language/async_star_no_cancel2_test.dart b/tests/language/async_star_no_cancel2_test.dart
new file mode 100644
index 0000000..fcc82ac
--- /dev/null
+++ b/tests/language/async_star_no_cancel2_test.dart
@@ -0,0 +1,59 @@
+// 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:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+var events = [];
+
+var timer;
+ticker(period) async* {
+  var sc;
+  sc = new StreamController(onListen: () {
+    events.add("listen");
+    timer = new Timer.periodic(period, (_) {
+      sc.add(null);
+    });
+  }, onCancel: () {
+    events.add("cancel");
+    timer.cancel();
+  });
+
+  try {
+    var counter = 0;
+    await for (var tick in sc.stream) {
+      counter++;
+    }
+  } finally {
+    events.add("finally");
+  }
+}
+
+void main() {
+  asyncStart();
+  events.add("main");
+  final subscription =
+      ticker(const Duration(milliseconds: 20)).listen((val) { });
+
+  bool cancelFinished = false;
+  new Timer(const Duration(milliseconds: 100), () async {
+    // Despite the cancel call below, the stream doesn't stop.
+    // The async* function is not blocked at any await (since the inner timer
+    // continuously ticks), but since there/ is no yield-point in the function
+    // it won't cancel.
+    new Timer(const Duration(milliseconds: 30), () {
+      Expect.isFalse(cancelFinished);
+      Expect.listEquals(["main", "listen", "invoke cancel"], events);
+      timer.cancel();
+      asyncEnd();
+    });
+
+    events.add("invoke cancel");
+    await subscription.cancel();
+    // This line should never be reached, since the cancel-future doesn't
+    // complete.
+    cancelFinished = true;
+  });
+}
diff --git a/tests/language/async_star_no_cancel_test.dart b/tests/language/async_star_no_cancel_test.dart
new file mode 100644
index 0000000..82cbe22
--- /dev/null
+++ b/tests/language/async_star_no_cancel_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+var events = [];
+
+ticker() async* {
+  var sc;
+  var sentTickCount = 0;
+  sc = new StreamController(onListen: () {
+    events.add("listen");
+  }, onCancel: () {
+    events.add("cancel");
+  });
+
+  try {
+    var counter = 0;
+    await for (var tick in sc.stream) {
+      counter++;
+    }
+  } finally {
+    events.add("finally");
+  }
+}
+
+void main() {
+  asyncStart();
+  events.add("main");
+  final subscription = ticker().listen((val) { });
+
+  bool cancelFinished = false;
+  // Cancel the subscription.
+  // The async* function is blocked on an `await` (the inner stream) and won't
+  // be able to complete.
+  Timer.run(() {
+    events.add("invoke cancel");
+    subscription.cancel().then((_) => cancelFinished = true);
+  });
+
+  new Timer(const Duration(milliseconds: 100), () {
+    Expect.isFalse(cancelFinished);
+    Expect.listEquals(["main", "listen", "invoke cancel"], events);
+    asyncEnd();
+  });
+}
diff --git a/tests/language/built_in_identifier_prefix_test.dart b/tests/language/built_in_identifier_prefix_test.dart
deleted file mode 100644
index de995c9..0000000
--- a/tests/language/built_in_identifier_prefix_test.dart
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Test that built-in identifiers can be used as library prefixes.
-
-// From The Dart Programming Language Specification, section 11.30
-// "Identifier Reference":
-//
-// "A built-in identifier is one of the identifiers produced by the
-// production BUILT IN IDENTIFIER. It is a compile-time error if a
-// built-in identifier is used as the declared name of a class, type
-// parameter or type alias. It is a compile-time error to use a
-// built-in identifier other than dynamic as a type annotation."
-//
-// Observation: it is not illegal to use a built-in identifier as a library
-// prefix.
-//
-// Observation: it is not legal to use a built-in identifer as a type
-// annotation. A type annotation is not fully defined in the
-// specification, so we assume this means that the grammar production
-// "type" cannot match a built-in identifier. Unfortunately, this
-// doesn't prevent us from using built-in identifiers *in* type
-// annotations. For example, "final abstract foo;" is illegal as
-// "abstract" is used as a type annotation. However, "final
-// abstract<dynamic> foo;" is not illegal because "abstract" is used
-// as a typeName.
-
-import "package:expect/expect.dart";
-import 'built_in_identifier_prefix_library_abstract.dart' as abstract;
-import 'built_in_identifier_prefix_library_as.dart' as as;
-import 'built_in_identifier_prefix_library_dynamic.dart' as dynamic;
-import 'built_in_identifier_prefix_library_export.dart' as export;
-import 'built_in_identifier_prefix_library_external.dart' as external;
-import 'built_in_identifier_prefix_library_factory.dart' as factory;
-import 'built_in_identifier_prefix_library_get.dart' as get;
-import 'built_in_identifier_prefix_library_implements.dart' as implements;
-import 'built_in_identifier_prefix_library_import.dart' as import;
-import 'built_in_identifier_prefix_library_library.dart' as library;
-import 'built_in_identifier_prefix_library_operator.dart' as operator;
-import 'built_in_identifier_prefix_library_part.dart' as part;
-import 'built_in_identifier_prefix_library_set.dart' as set;
-import 'built_in_identifier_prefix_library_static.dart' as static;
-import 'built_in_identifier_prefix_library_typedef.dart' as typedef;
-
-abstract.A _abstract = new abstract.A();
-as.A _as = new as.A();
-dynamic.A _dynamic = new dynamic.A();
-export.A _export = new export.A();
-external.A _external = new external.A();
-factory.A _factory = new factory.A();
-get.A _get = new get.A();
-implements.A _implements = new implements.A();
-import.A _import = new import.A();
-library.A _library = new library.A();
-operator.A _operator = new operator.A();
-part.A _part = new part.A();
-set.A _set = new set.A();
-static.A _static = new static.A();
-typedef.A _typedef = new typedef.A();
-
-abstract<dynamic> generic_abstract = new abstract.A();
-as<dynamic> generic_as = new as.A();
-dynamic<dynamic> generic_dynamic = new dynamic.A();
-export<dynamic> generic_export = new export.A();
-external<dynamic> generic_external = new external.A();
-factory<dynamic> generic_factory = new factory.A();
-get<dynamic> generic_get = new get.A();
-implements<dynamic> generic_implements = new implements.A();
-import<dynamic> generic_import = new import.A();
-library<dynamic> generic_library = new library.A();
-operator<dynamic> generic_operator = new operator.A();
-part<dynamic> generic_part = new part.A();
-set<dynamic> generic_set = new set.A();
-static<dynamic> generic_static = new static.A();
-typedef<dynamic> generic_typedef = new typedef.A();
-
-abstract.B<dynamic> dynamic_B_abstract = new abstract.B();
-as.B<dynamic> dynamic_B_as = new as.B();
-dynamic.B<dynamic> dynamic_B_dynamic = new dynamic.B();
-export.B<dynamic> dynamic_B_export = new export.B();
-external.B<dynamic> dynamic_B_external = new external.B();
-factory.B<dynamic> dynamic_B_factory = new factory.B();
-get.B<dynamic> dynamic_B_get = new get.B();
-implements.B<dynamic> dynamic_B_implements = new implements.B();
-import.B<dynamic> dynamic_B_import = new import.B();
-library.B<dynamic> dynamic_B_library = new library.B();
-operator.B<dynamic> dynamic_B_operator = new operator.B();
-part.B<dynamic> dynamic_B_part = new part.B();
-set.B<dynamic> dynamic_B_set = new set.B();
-static.B<dynamic> dynamic_B_static = new static.B();
-typedef.B<dynamic> dynamic_B_typedef = new typedef.B();
-
-abstract.B<abstract<dynamic>> parameterized_B_abstract = new abstract.B();
-as.B<as<dynamic>> parameterized_B_as = new as.B();
-dynamic.B<dynamic<dynamic>> parameterized_B_dynamic = new dynamic.B();
-export.B<export<dynamic>> parameterized_B_export = new export.B();
-external.B<external<dynamic>> parameterized_B_external = new external.B();
-factory.B<factory<dynamic>> parameterized_B_factory = new factory.B();
-get.B<get<dynamic>> parameterized_B_get = new get.B();
-implements.B<implements<dynamic>> parameterized_B_implements =
-  new implements.B();
-import.B<import<dynamic>> parameterized_B_import = new import.B();
-library.B<library<dynamic>> parameterized_B_library = new library.B();
-operator.B<operator<dynamic>> parameterized_B_operator = new operator.B();
-part.B<part<dynamic>> parameterized_B_part = new part.B();
-set.B<set<dynamic>> parameterized_B_set = new set.B();
-static.B<static<dynamic>> parameterized_B_static = new static.B();
-typedef.B<typedef<dynamic>> parameterized_B_typedef = new typedef.B();
-
-class UseA {
-  abstract.A abstract = new abstract.A();
-  as.A as = new as.A();
-  dynamic.A dynamic = new dynamic.A();
-  export.A export = new export.A();
-  external.A external = new external.A();
-  factory.A factory = new factory.A();
-  get.A get = new get.A();
-  implements.A implements = new implements.A();
-  import.A import = new import.A();
-  library.A library = new library.A();
-  operator.A operator = new operator.A();
-  part.A part = new part.A();
-  set.A set = new set.A();
-  static.A static = new static.A();
-  typedef.A typedef = new typedef.A();
-}
-
-main() {
-  bool assertionsEnabled = false;
-  assert(assertionsEnabled = true);
-
-  Expect.isTrue(_abstract is abstract.A);
-  Expect.isTrue(_as is as.A);
-  Expect.isTrue(_dynamic is dynamic.A);
-  Expect.isTrue(_export is export.A);
-  Expect.isTrue(_external is external.A);
-  Expect.isTrue(_factory is factory.A);
-  Expect.isTrue(_get is get.A);
-  Expect.isTrue(_implements is implements.A);
-  Expect.isTrue(_import is import.A);
-  Expect.isTrue(_library is library.A);
-  Expect.isTrue(_operator is operator.A);
-  Expect.isTrue(_part is part.A);
-  Expect.isTrue(_set is set.A);
-  Expect.isTrue(_static is static.A);
-  Expect.isTrue(_typedef is typedef.A);
-
-  Expect.isTrue(dynamic_B_abstract is abstract.B);
-  Expect.isTrue(dynamic_B_as is as.B);
-  Expect.isTrue(dynamic_B_dynamic is dynamic.B);
-  Expect.isTrue(dynamic_B_export is export.B);
-  Expect.isTrue(dynamic_B_external is external.B);
-  Expect.isTrue(dynamic_B_factory is factory.B);
-  Expect.isTrue(dynamic_B_get is get.B);
-  Expect.isTrue(dynamic_B_implements is implements.B);
-  Expect.isTrue(dynamic_B_import is import.B);
-  Expect.isTrue(dynamic_B_library is library.B);
-  Expect.isTrue(dynamic_B_operator is operator.B);
-  Expect.isTrue(dynamic_B_part is part.B);
-  Expect.isTrue(dynamic_B_set is set.B);
-  Expect.isTrue(dynamic_B_static is static.B);
-  Expect.isTrue(dynamic_B_typedef is typedef.B);
-
-  var x = new UseA();
-  Expect.isTrue(x.abstract is abstract.A);
-  Expect.isTrue(x.as is as.A);
-  Expect.isTrue(x.dynamic is dynamic.A);
-  Expect.isTrue(x.export is export.A);
-  Expect.isTrue(x.external is external.A);
-  Expect.isTrue(x.factory is factory.A);
-  Expect.isTrue(x.get is get.A);
-  Expect.isTrue(x.implements is implements.A);
-  Expect.isTrue(x.import is import.A);
-  Expect.isTrue(x.library is library.A);
-  Expect.isTrue(x.operator is operator.A);
-  Expect.isTrue(x.part is part.A);
-  Expect.isTrue(x.set is set.A);
-  Expect.isTrue(x.static is static.A);
-  Expect.isTrue(x.typedef is typedef.A);
-
-  // Most of the following variables have malformed type annotations.
-  if (assertionsEnabled) return;
-
-  Expect.isTrue(generic_abstract is abstract.A);
-  Expect.isTrue(generic_as is as.A);
-  Expect.isTrue(generic_dynamic is dynamic.A);
-  Expect.isTrue(generic_export is export.A);
-  Expect.isTrue(generic_external is external.A);
-  Expect.isTrue(generic_factory is factory.A);
-  Expect.isTrue(generic_get is get.A);
-  Expect.isTrue(generic_implements is implements.A);
-  Expect.isTrue(generic_import is import.A);
-  Expect.isTrue(generic_library is library.A);
-  Expect.isTrue(generic_operator is operator.A);
-  Expect.isTrue(generic_part is part.A);
-  Expect.isTrue(generic_set is set.A);
-  Expect.isTrue(generic_static is static.A);
-  Expect.isTrue(generic_typedef is typedef.A);
-
-  Expect.isTrue(parameterized_B_abstract is abstract.B);
-  Expect.isTrue(parameterized_B_as is as.B);
-  Expect.isTrue(parameterized_B_dynamic is dynamic.B);
-  Expect.isTrue(parameterized_B_export is export.B);
-  Expect.isTrue(parameterized_B_external is external.B);
-  Expect.isTrue(parameterized_B_factory is factory.B);
-  Expect.isTrue(parameterized_B_get is get.B);
-  Expect.isTrue(parameterized_B_implements is implements.B);
-  Expect.isTrue(parameterized_B_import is import.B);
-  Expect.isTrue(parameterized_B_library is library.B);
-  Expect.isTrue(parameterized_B_operator is operator.B);
-  Expect.isTrue(parameterized_B_part is part.B);
-  Expect.isTrue(parameterized_B_set is set.B);
-  Expect.isTrue(parameterized_B_static is static.B);
-  Expect.isTrue(parameterized_B_typedef is typedef.B);
-}
diff --git a/tests/language/conflicting_type_variable_and_setter_test.dart b/tests/language/conflicting_type_variable_and_setter_test.dart
new file mode 100644
index 0000000..2aca0c3
--- /dev/null
+++ b/tests/language/conflicting_type_variable_and_setter_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class C<D> {
+  void set D(int value) {
+    field = value;
+  }
+
+  int field;
+}
+
+main() {
+  C<int> c = new C<int>();
+  c.D = 1;
+  Expect.equals(c.field, 1);
+}
diff --git a/tests/language/deep_nesting1_negative_test.dart b/tests/language/deep_nesting1_negative_test.dart
new file mode 100644
index 0000000..e85c11c
--- /dev/null
+++ b/tests/language/deep_nesting1_negative_test.dart
@@ -0,0 +1,11 @@
+// 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.
+
+// Deeply nested expression must not crash compiler due to stack overflow.
+
+main() {
+  var x =
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]];
+  print('okay');
+}
diff --git a/tests/language/deep_nesting2_negative_test.dart b/tests/language/deep_nesting2_negative_test.dart
new file mode 100644
index 0000000..cd49a07
--- /dev/null
+++ b/tests/language/deep_nesting2_negative_test.dart
@@ -0,0 +1,10012 @@
+// 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.
+
+// Deeply nested statements must not crash compiler due to stack overflow.
+
+var x = 0;
+
+main() {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  if (x == 0) {
+  }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+  print("survived!");
+}
diff --git a/tests/language/deferred_import_core_test.dart b/tests/language/deferred_import_core_test.dart
new file mode 100644
index 0000000..f3d6644
--- /dev/null
+++ b/tests/language/deferred_import_core_test.dart
@@ -0,0 +1,12 @@
+// 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.
+
+// Nothing in the language spec explicitly prohibits a deferred import of
+// 'dart:core'.  Make sure it doesn't lead to any strange behavior.
+
+import "dart:core" deferred as core;
+
+main() {
+  core.loadLibrary().then((_) => null);
+}
diff --git a/tests/language/deferred_type_dependency_test.dart b/tests/language/deferred_type_dependency_test.dart
index 766834e..dd285c8 100644
--- a/tests/language/deferred_type_dependency_test.dart
+++ b/tests/language/deferred_type_dependency_test.dart
@@ -7,9 +7,10 @@
 
 import "deferred_type_dependency_lib1.dart" deferred as lib1;
 import "deferred_type_dependency_lib2.dart" deferred as lib2;
+import "package:async_helper/async_helper.dart";
 import "package:expect/expect.dart";
 
-main() async {
+runTest() async {
   await lib1.loadLibrary();
   // Split the cases into a multi-test to test each feature separately.
   Expect.isFalse(
@@ -27,4 +28,9 @@
       (lib2.getInstance())
       is! String /// none: ok
   );
-}
\ No newline at end of file
+}
+
+main() {
+  asyncStart();
+  runTest().then((_) => asyncEnd());
+}
diff --git a/tests/language/export_not_shadowed_by_prefix_helper.dart b/tests/language/export_not_shadowed_by_prefix_helper.dart
new file mode 100644
index 0000000..3dcd016
--- /dev/null
+++ b/tests/language/export_not_shadowed_by_prefix_helper.dart
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+export "export_not_shadowed_by_prefix_helper2.dart";
+import "dart:core" as f;
diff --git a/tests/language/export_not_shadowed_by_prefix_helper2.dart b/tests/language/export_not_shadowed_by_prefix_helper2.dart
new file mode 100644
index 0000000..ae2dca5
--- /dev/null
+++ b/tests/language/export_not_shadowed_by_prefix_helper2.dart
@@ -0,0 +1,9 @@
+// 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.
+
+void f() {
+  f_called = true;
+}
+
+bool f_called = false;
diff --git a/tests/language/export_not_shadowed_by_prefix_test.dart b/tests/language/export_not_shadowed_by_prefix_test.dart
new file mode 100644
index 0000000..3af1b48
--- /dev/null
+++ b/tests/language/export_not_shadowed_by_prefix_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that import prefixes within an imported library don't shadow
+// names re-exported by that library.
+
+import "package:expect/expect.dart";
+import "export_not_shadowed_by_prefix_helper.dart";
+
+main() {
+  f();
+  Expect.isTrue(f_called);
+}
diff --git a/tests/language/for_in3_test.dart b/tests/language/for_in3_test.dart
new file mode 100644
index 0000000..75ee485
--- /dev/null
+++ b/tests/language/for_in3_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Dart test for testing that strings aren't iterable.
+
+main() {
+  Expect.throws(() {
+    var chars = [];
+    for (var c in "foo") chars.add(c);
+  }, (e) => e is NoSuchMethodError);
+}
diff --git a/tests/language/issue_25671a_test.dart b/tests/language/issue_25671a_test.dart
new file mode 100644
index 0000000..259b81bd
--- /dev/null
+++ b/tests/language/issue_25671a_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+  noSuchMethod() {                                    /// 01: static type warning
+    throw new Exception(                              /// 01: continued
+        "Wrong noSuchMethod() should not be called"); /// 01: continued
+  }                                                   /// 01: continued
+}
+class C extends A {
+  test() {
+    super.v = 1; /// 01: continued
+  }
+}
+main() {
+  C c = new C();
+  Expect.throws(() => c.test(), (e) => e is NoSuchMethodError); /// 01: continued
+}
diff --git a/tests/language/issue_25671b_test.dart b/tests/language/issue_25671b_test.dart
new file mode 100644
index 0000000..1b08ca6
--- /dev/null
+++ b/tests/language/issue_25671b_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+  noSuchMethod() {                                    /// 01: static type warning
+    throw new Exception(                              /// 01: continued
+        "Wrong noSuchMethod() should not be called"); /// 01: continued
+  }                                                   /// 01: continued
+}
+class C extends Object with A {
+  test() {
+    super.v = 1; /// 01: continued
+  }
+}
+main() {
+  C c = new C();
+  Expect.throws(() => c.test(), (e) => e is NoSuchMethodError); /// 01: continued
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 65a750e..42bb58b 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -5,10 +5,14 @@
 # This directory contains tests that are intended to show the
 # current state of the language.
 
-[ ($compiler == none || $compiler == precompiler) ]
-built_in_identifier_prefix_test: Fail # Issue 6970
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) ]
 tearoff_constructor_basic_test: Skip # Crashes in checked mode -- hausner investigating
-const_qq_test: Fail
+
+# These tests are skipped in the VM because it has "--supermixin"
+# functionality enabled unconditionally.  The tests should be removed
+# once the same is true for analyzer (#24478) and dart2js (#23773)
+mixin_illegal_super_use_test: Skip # Issues 24478 and 23773
+mixin_illegal_superclass_test: Skip # Issues 24478 and 23773
 
 # These bugs refer currently ongoing language discussions.
 constructor5_test: Fail # Issue 6422
@@ -22,6 +26,9 @@
 constructor3_test: Fail, OK
 constructor2_test: Fail, OK
 
+dynamic_prefix_core_test/01: RuntimeError # Issue 12478
+multiline_strings_test: Fail # Issue 23020
+
 # Regular bugs which should be fixed.
 duplicate_export_negative_test: Fail # Issue 6134
 
@@ -38,7 +45,13 @@
 async_star_cancel_while_paused_test: RuntimeError
 async_star_await_pauses_test: Skip # Times out. Issue 23996
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) ]
+accessor_conflict_export2_test: RuntimeError # Issue 25625
+accessor_conflict_import2_test: RuntimeError # Issue 25625
+accessor_conflict_import_prefixed2_test: RuntimeError # Issue 25625
+accessor_conflict_import_prefixed_test: RuntimeError # Issue 25625
+
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
+
 class_keyword_test/02: MissingCompileTimeError # Issue 13627
 unicode_bom_test: Fail # Issue 16067
 vm/debug_break_enabled_vm_test/01: Crash, OK # Expected to hit breakpoint.
@@ -47,15 +60,11 @@
 [ ($compiler == none || $compiler == precompiler) && $checked ]
 type_variable_bounds4_test/01: Fail # Issue 14006
 
-[ ($compiler == none || $compiler == precompiler) ]
-dynamic_prefix_core_test/01: RuntimeError # Issue 12478
-multiline_strings_test: Fail # Issue 23020
-
-[ ($compiler == none || $compiler == precompiler) && (($runtime == vm || $runtime == dart_precompiled) || $runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && (($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) || $runtime == drt || $runtime == dartium) ]
 dynamic_prefix_core_test/none: Fail # Issue 12478
 export_ambiguous_main_negative_test: Fail # Issue 14763
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == dartium || $runtime == ContentShellOnAndroid) && $unchecked ]
+[ $compiler == none && $runtime == dartium && $unchecked ]
 assertion_test: Fail # Issue 14651.
 generic_test: Fail # Issue 14651.
 list_literal4_test: Fail # Issue 14651.
@@ -68,7 +77,7 @@
 type_checks_in_factory_method_test: Fail # Issue 14651.
 vm/type_vm_test: Fail # Issue 14651.
 
-[ ($compiler == none || $compiler == precompiler) && ( $runtime == dartium || $runtime == drt || $runtime == ContentShellOnAndroid) ]
+[ $compiler == none && ($runtime == dartium || $runtime == drt) ]
 issue13474_test: Pass, Fail # Issue 14651.
 config_import_test: Fail # Issue 14651.
 vm/optimized_guarded_field_isolates_test: RuntimeError, OK  # Uses Isolate.spawn.
@@ -81,72 +90,111 @@
 mirror_in_static_init_test: Fail # Issue 22071
 vm/debug_break_enabled_vm_test/*: Skip # Issue 14651.
 
-[ ($compiler == none || $compiler == precompiler) && $runtime == dartium && $system == linux && $arch != x64 ]
+[ $compiler == none && $runtime == dartium && $system == linux && $arch != x64 ]
 issue_22780_test/01 : Pass, Timeout # Issue 24473
 
-[ ($compiler == none || $compiler == precompiler) && $runtime == drt ]
+[ $compiler == none && $runtime == drt ]
 disassemble_test: Pass, Fail # Issue 18122
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && $arch == mips && $checked ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == mips && $checked ]
 generic_instanceof3_test: Pass, Crash # Issue 17440.
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && $arch == mips && $mode == debug ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $arch == mips && $mode == debug ]
 stack_overflow_test: Skip # Crashes. Issue 17440.
 stack_overflow_stacktrace_test: Skip # Crashes. Issue 17440.
 large_class_declaration_test: SkipSlow # Times out. Issue 20352
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == dartium || $runtime == drt || $runtime == ContentShellOnAndroid) && $mode == debug ]
+[ ($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
 
-[ ($compiler == none || $compiler == precompiler) && $runtime == ContentShellOnAndroid ]
-gc_test: SkipSlow # Times out flakily. Issue 20956
-
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == dart_precompiled) && ( $arch == simarm || $arch == arm || $arch == simarmv5te || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && ( $arch == simarm || $arch == arm || $arch == simarmv6 || $arch == armv6 || $arch == simarmv5te || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
 vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
 
-[ ($compiler == none || $compiler == precompiler) && $runtime == dartium ]
+[ $compiler == none && ($runtime == dartium || $runtime == drt) ]
 issue23244_test: Fail # Issue 23244
 
-[ ($compiler == none || $compiler == precompiler) && (($runtime == vm || $runtime == dart_precompiled) || $runtime == drt || $runtime == dartium) && $arch == ia32 ]
+[ ($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: 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
-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
-redirecting_factory_reflection_test: CompileTimeError
-deferred_constraints_constants_test: Skip # multitest gets confused
-vm/type_vm_test: RuntimeError # Expects line and column numbers
+[ $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
 
+[ $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
 regress_23408_test: RuntimeError
-deferred_global_test: RuntimeError
 deferred_inheritance_constraints_test: Skip
 deferred_load_constants_test: Skip # multitest gets confused
-
-deopt_inlined_function_lazy_test: Pass, Crash # Incompatible flag: --deoptimize-alot
 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.
 
 [ $runtime == dart_precompiled ]
+deferred_global_test: RuntimeError # Tries to produce a stack trace.
 ct_const2_test: Pass, Crash # Incompatible flag --compile_all
 hello_dart_test: Pass, Crash # Incompatible flag --compile_all
 
 implicit_closure_test: Pass, Crash # --use_slow_path
+
+deopt_inlined_function_lazy_test: Pass, Crash # Incompatible flag: --deoptimize-alot
+
+[ $runtime == dart_product ]
+# Deferred loading happens eagerly (not sure why this works on precompiled code).
+deferred_static_seperate_test: Skip
+deferred_constraints_type_annotation_test/new_before_load: Skip
+regress_22443_test: Skip
+
+[ $runtime == vm && $mode == product ]
+vm/type_vm_test: Fail,OK  # Expects exact type name.
+
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $browser ]
+# The following tests are supposed to fail.
+library_env_test/has_io_support: RuntimeError, OK
+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_analyzer2.status b/tests/language/language_analyzer2.status
index 5ea3d0a..5e0c4af 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -7,6 +7,9 @@
 # Runtime negative test. No static errors or warnings.
 closure_call_wrong_argument_count_negative_test: skip
 
+deep_nesting1_negative_test: Crash # Issue 25558
+deep_nesting2_negative_test: Crash # Issue 25558
+
 enum_syntax_test/05: Fail # 21649
 enum_syntax_test/06: Fail # 21649
 
@@ -19,7 +22,6 @@
 getter_setter_in_lib_test: Fail # issue 23286
 
 # Test issue 12694 (was analyzer issue), (1) when "abstract" is import prefix using it as type is warning; (2) currently analyzer resolves prefix as field (don't ask)
-built_in_identifier_prefix_test: CompileTimeError # Issue 12694
 
 # TBF: we should check conflicts not only for methods, but for accessors too
 override_field_test/03: fail
@@ -305,11 +307,6 @@
 mixin_invalid_bound_test/none: StaticWarning # legitimate StaticWarning, cannot be annotated
 mixin_invalid_bound2_test/none: StaticWarning # legitimate StaticWarning, cannot be annotated
 mixin_super_bound_test: StaticWarning # legitimate StaticWarning, cannot be annotated
-mixin_super_bound2_test: CompileTimeError # Issue 24478
-mixin_super_test: CompileTimeError # Issue 24478
-mixin_super_2_test: CompileTimeError # Issue 24478
-mixin_super_use_test: CompileTimeError # Issue 24478
-mixin_superclass_test: CompileTimeError # Issue 24478
 named_constructor_test/01: StaticWarning
 named_constructor_test/03: StaticWarning
 named_parameters2_test: StaticWarning
@@ -483,4 +480,40 @@
 # intentionally referring to a variable that's not in scope.
 transitive_private_library_access_test: StaticWarning
 
-const_qq_test: Fail
+conflicting_type_variable_and_setter_test: CompileTimeError # Issue 25525
+
+mixin_supertype_subclass_test/02: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass_test/05: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass2_test/02: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass2_test/05: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass3_test/02: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass3_test/05: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass4_test/01: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass4_test/02: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass4_test/03: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass4_test/04: MissingStaticWarning # Issue 25614
+mixin_supertype_subclass4_test/05: MissingStaticWarning # Issue 25614
+
+mixin_of_mixin_test/01: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/02: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/04: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/05: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/06: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/08: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/09: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/10: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/12: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/13: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/15: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/16: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/17: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/19: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/20: MissingStaticWarning # Issue 25605
+mixin_of_mixin_test/21: MissingStaticWarning # Issue 25605
+
+accessor_conflict_export2_test: StaticWarning # Issue 25624
+accessor_conflict_export_test: StaticWarning # Issue 25624
+accessor_conflict_import2_test: StaticWarning # Issue 25624
+accessor_conflict_import_prefixed2_test: StaticWarning # Issue 25624
+accessor_conflict_import_prefixed_test: StaticWarning # Issue 25624
+accessor_conflict_import_test: StaticWarning # Issue 25624
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 2dbad85..a3327e4 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -4,6 +4,7 @@
 
 [ $compiler == dart2js ]
 getter_setter_in_lib_test: Fail # Issue 23288
+method_name_test: Fail # issue 25574
 
 async_star_cancel_while_paused_test: RuntimeError # Issue 22853
 async_star_await_pauses_test: Fail, Timeout # Issue 22853
@@ -13,11 +14,33 @@
 try_catch_on_syntax_test/10: Fail # Issue 19823
 try_catch_on_syntax_test/11: Fail # Issue 19823
 
+deep_nesting1_negative_test: Crash # Issue 25557
+deep_nesting2_negative_test: Crash # Issue 25557
+
 call_function_apply_test: RuntimeError # Issue 23873
+mixin_supertype_subclass_test: CompileTimeError # Issue 23773
+mixin_supertype_subclass2_test: CompileTimeError # Issue 23773
+mixin_supertype_subclass3_test: CompileTimeError # Issue 23773
+mixin_supertype_subclass4_test: CompileTimeError # Issue 23773
+mixin_of_mixin_test: CompileTimeError # Issue 23773
+
+# The following tests are supposed to fail.
+# 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
+library_env_test/has_no_mirror_support: RuntimeError, OK
+
+accessor_conflict_import2_test: RuntimeError # Issue 25626
+accessor_conflict_import_prefixed2_test: RuntimeError # Issue 25626
+accessor_conflict_import_prefixed_test: RuntimeError # Issue 25626
+accessor_conflict_import_test: RuntimeError # Issue 25626
 
 [ $compiler == dart2js && $runtime == jsshell ]
 await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
 async_star_test: RuntimeError # Jsshell does not provide non-zero timers, Issue 7728
+async_star_no_cancel_test: RuntimeError # Need triage
+async_star_no_cancel2_test: RuntimeError # Need triage
 
 [ $compiler == dart2js && $browser ]
 config_import_test: Fail # Test flag is not passed to the compiler.
@@ -138,7 +161,6 @@
 branch_canonicalization_test: RuntimeError # Issue 638.
 identical_closure2_test: RuntimeError # Issue 1533, Issue 12596
 integer_division_by_zero_test: RuntimeError # Issue 8301
-built_in_identifier_prefix_test: CompileTimeError # Issue 6972
 number_identity2_test: RuntimeError # Issue 12596
 double_int_to_string_test: RuntimeError # Issue 1533
 mint_arithmetic_test: RuntimeError # Issue 1533
@@ -213,46 +235,46 @@
 regress_22443_test: Pass,RuntimeError # Issue 17458
 
 [ $compiler == dart2js && $cps_ir == false ]
+accessor_conflict_export2_test: Crash # Issue 25626
+accessor_conflict_export_test: Crash # Issue 25626
 generic_field_mixin4_test: Crash # Issue 18651
 generic_field_mixin5_test: Crash # Issue 18651
 many_method_calls_test: Crash # Stack overflow in HGraphVisitor.visitPostDominatorTree.visitBasicBlockAndSuccessors
 method_override5_test: RuntimeError # Issue 12809
+super_no_such_method4_test/01: RuntimeError # Issue 25716
+super_no_such_method5_test/01: RuntimeError # Issue 25716
 
 [ $compiler == dart2js && $runtime != drt && $runtime != dartium ]
 issue23244_test: RuntimeError # 23244
 
 [ $compiler == dart2js && $cps_ir ]
+accessor_conflict_export_test: CompileTimeError # Issue 25747
+accessor_conflict_export2_test: CompileTimeError # Issue 25747
 async_await_syntax_test/a03a: Crash # (a03a()async*{}): cannot handle sync*/async* functions
 async_await_syntax_test/a03b: Crash # (a03b()async*{}): cannot handle sync*/async* functions
-async_await_syntax_test/a06a: Crash # (await for(var o in st){}): await for
 async_await_syntax_test/a09a: Crash # (a09a()async*{yield 0;}): cannot handle sync*/async* functions
 async_await_syntax_test/a10a: Crash # (a10a()async*{yield* [] ;}): cannot handle sync*/async* functions
 async_await_syntax_test/a11d: Crash # (get async async*{}): cannot handle sync*/async* functions
 async_await_syntax_test/b03a: Crash # (b03a()async*{}): cannot handle sync*/async* functions
-async_await_syntax_test/b06a: Crash # (await for(var o in st){}): await for
 async_await_syntax_test/b09a: Crash # (b09a()async*{yield 0;}): cannot handle sync*/async* functions
 async_await_syntax_test/b10a: Crash # (b10a()async*{yield* [] ;}): cannot handle sync*/async* functions
 async_await_syntax_test/b11d: Crash # (get async async*{}): cannot handle sync*/async* functions
 async_await_syntax_test/c03a: Crash # (c03a()async*{}): cannot handle sync*/async* functions
-async_await_syntax_test/c06a: Crash # (await for(var o in st){}): await for
 async_await_syntax_test/c09a: Crash # (c09a()async*{yield 0;}): cannot handle sync*/async* functions
 async_await_syntax_test/c10a: Crash # (c10a()async*{yield* [] ;}): cannot handle sync*/async* functions
 async_await_syntax_test/d03a: Crash # (()async*{}): cannot handle sync*/async* functions
-async_await_syntax_test/d06a: Crash # (await for(var o in st){}): await for
 async_await_syntax_test/d09a: Crash # (()async*{yield 0;}): cannot handle sync*/async* functions
 async_await_syntax_test/d10a: Crash # (()async*{yield* [] ;}): cannot handle sync*/async* functions
-async_await_test/02: Crash # (switch (v){label:ca...  continue to a labeled switch case
-async_await_test/03: Crash # (switch (v){label:ca...  continue to a labeled switch case
-async_await_test/none: Crash # (switch (v){label:ca...  continue to a labeled switch case
 async_or_generator_return_type_stacktrace_test/02: Crash # (void badReturnTypeAsyncStar()async*{}): cannot handle sync*/async* functions
 async_return_types_test/nestedFuture: Crash #  cannot handle sync*/async* functions
 async_return_types_test/none: Crash # cannot handle sync*/async* functions
 async_return_types_test/tooManyTypeParameters: Crash # cannot handle sync*/async* functions
 async_return_types_test/wrongReturnType: Crash # cannot handle sync*/async* functions
 async_return_types_test/wrongTypeParameter: Crash # cannot handle sync*/async* functions
-async_star_await_pauses_test: Crash # (await for(var i in ...  await for
 async_star_cancel_and_throw_in_finally_test: Crash # (foo()async*{try {in...  cannot handle sync*/async* functions
 async_star_cancel_while_paused_test: Crash # (f()async*{list.add(...  cannot handle sync*/async* functions
+async_star_no_cancel_test: Crash # (foo()async*{try {in...  cannot handle sync*/async* functions
+async_star_no_cancel2_test: Crash # (foo()async*{try {in...  cannot handle sync*/async* functions
 async_star_regression_2238_test: Crash # (f()async*{label1:label2:yield 0;}): cannot handle sync*/async* functions
 async_star_regression_23116_test: Crash # (Stream<int> foo(Com...  cannot handle sync*/async* functions
 async_star_regression_fisk_test: Crash # (fisk()async*{res.ad...  cannot handle sync*/async* functions
@@ -263,45 +285,25 @@
 asyncstar_throw_in_catch_test: Crash # (foo4(Tracer tracer)...  cannot handle sync*/async* functions
 asyncstar_yield_test: Crash # (Stream<int> foo4()a...  cannot handle sync*/async* functions
 asyncstar_yieldstar_test: Crash # (foo2(Stream subStream)async*{yield* subStream;}): cannot handle sync*/async* functions
-await_for_cancel_test: Crash # (await for(var x in controller.stream){for(int j=0;j<10;j++ ){if(j==5)continue outer;}}): await for
-await_for_test: Crash # (await for(var x in infiniteStream()){i++ ;if(i>10)break;t4.record(x);}): await for
-await_for_use_local_test: Crash # (await for(var v in s){accum+= v;}): await for
 call_closurization_test: RuntimeError # Bad type inference for ".call" tear-off.
-closure_in_constructor_test: RuntimeError # Please triage this failure.
-closures_initializer_test: RuntimeError # Please triage this failure.
-constructor12_test: RuntimeError # Please triage this failure.
-deferred_super_dependency_test/01: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
 field3a_negative_test: Fail # Bogus result from type inference in case of invalid program.
-first_class_types_test: RuntimeError # Please triage this failure.
-generic2_test: RuntimeError # Please triage this failure.
-generic_instanceof_test: RuntimeError # Please triage this failure.
-generic_native_test: RuntimeError # Please triage this failure.
 gc_test: Crash # Internal Error: Pending statics (see above).
-infinite_switch_label_test: Crash # (switch (target){l0:...  continue to a labeled switch case
-instanceof2_test: RuntimeError # Please triage this failure.
-instanceof4_test/01: RuntimeError # Please triage this failure.
+if_null_assignment_static_test/29: Crash # Pending statics: JSArray
+if_null_assignment_static_test/31: Crash # Pending statics: JSArray
+if_null_assignment_static_test/32: Crash # Pending statics: JSArray
+if_null_assignment_static_test/33: Crash # Pending statics: JSArray
+if_null_assignment_static_test/35: Crash # Pending statics: JSArray
 invocation_mirror_test: Crash # (super[37]=42): visitUnresolvedSuperIndexSet
-list_is_test: RuntimeError # Please triage this failure.
-list_test: RuntimeError # Please triage this failure.
-many_generic_instanceof_test: RuntimeError # Please triage this failure.
-nested_switch_label_test: Crash # (switch (target){out...  continue to a labeled switch case
-regress_23500_test/01: Crash # (await for(var c in new Stream.fromIterable([] )){}): await for
-stack_trace_test: Fail # Stack trace not preserved when inlining?
+many_calls_test: Crash # Internal Error: Pending statics (see above).
+mixin_bound_test: RuntimeError # TypeError: Cannot read property 'toString$0' of undefined
 super_call4_test: RuntimeError # Please triage this failure.
-super_getter_setter_test: Crash # Class 'PartialMethodElement' has no instance getter 'initializer'.
+super_getter_setter_test: RuntimeError # Expect.equals(expected: <42>, actual: <null>) fails.
 super_operator_index5_test: Crash # (super[0]=42): visitUnresolvedSuperIndexSet
 super_operator_index7_test: Crash # (super[0]=42): visitUnresolvedSuperIndexSet
 super_operator_index8_test: Crash # (super[f()]=g()): visitUnresolvedSuperIndexSet
 super_operator_index_test/03: Crash # (super[4]=42): visitUnresolvedSuperIndexSet
 super_operator_index_test/05: Crash # (super[4]=42): visitUnresolvedSuperIndexSet
-switch_label2_test: Crash # (switch (target){cas...  continue to a labeled switch case
-switch_label_test: Crash # (switch (animal){cas...  continue to a labeled switch case
-switch_try_catch_test: Crash # (switch (0){_0:case ...  continue to a labeled switch case
-type_variable_closure2_test: RuntimeError # Issue 25309: T lost in List<T>
-type_variable_closure4_test: RuntimeError # T lost in <T,T>{}
-type_variable_field_initializer_closure_test: RuntimeError # Issue 25309: T lost in List<T>
-type_variable_field_initializer_test: RuntimeError # Issue 25309: T lost in List<T>
-type_variable_nested_test: RuntimeError # Issue 25309: T lost in List<T>
+switch8_test: Crash # Pending statics: JSArray
 
 [ $compiler == dart2js && $cps_ir && $host_checked == false ]
 regress_21795_test: Pass, RuntimeError # Due to inlining?
diff --git a/tests/language/library_env_test.dart b/tests/language/library_env_test.dart
new file mode 100644
index 0000000..bbe3b84
--- /dev/null
+++ b/tests/language/library_env_test.dart
@@ -0,0 +1,91 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+main() {
+  const NOT_PRESENT = false;
+
+  Expect.isTrue(const bool.fromEnvironment("dart.library.async"));
+  Expect.isTrue(const bool.fromEnvironment("dart.library.collection"));
+  Expect.isTrue(const bool.fromEnvironment("dart.library.convert"));
+  Expect.isTrue(const bool.fromEnvironment("dart.library.core"));
+  Expect.isTrue(const bool.fromEnvironment("dart.library.typed_data"));
+  Expect.isTrue(const bool.fromEnvironment("dart.library.developer"));
+
+  // Internal libraries should not be exposed.
+  Expect.equals(NOT_PRESENT,
+      const bool.fromEnvironment("dart.library._internal",
+          defaultValue: NOT_PRESENT));
+
+
+  bool hasHtmlSupport;
+  hasHtmlSupport = true;   /// has_html_support: ok
+  hasHtmlSupport = false;  /// has_no_html_support: ok
+
+  if (hasHtmlSupport != null) {
+    bool expectedResult = hasHtmlSupport ? true : NOT_PRESENT;
+
+    Expect.equals(expectedResult,
+        const bool.fromEnvironment("dart.library.html",
+            defaultValue: NOT_PRESENT));
+    Expect.equals(expectedResult,
+        const bool.fromEnvironment("dart.library.indexed_db",
+            defaultValue: NOT_PRESENT));
+    Expect.equals(expectedResult,
+        const bool.fromEnvironment("dart.library.svg",
+            defaultValue: NOT_PRESENT));
+    Expect.equals(expectedResult,
+        const bool.fromEnvironment("dart.library.web_audio",
+            defaultValue: NOT_PRESENT));
+    Expect.equals(expectedResult,
+        const bool.fromEnvironment("dart.library.web_gl",
+            defaultValue: NOT_PRESENT));
+    Expect.equals(expectedResult,
+        const bool.fromEnvironment("dart.library.web_sql",
+            defaultValue: NOT_PRESENT));
+  }
+
+  bool hasIoSupport;
+  hasIoSupport = true;   /// has_io_support: ok
+  hasIoSupport = false;  /// has_no_io_support: ok
+
+  if (hasIoSupport != null) {
+    // Dartium overrides 'dart.library.io' to return "false".
+    // We don't test for the non-existance, but just make sure that
+    // dart.library.io is not set to true.
+    Expect.equals(hasIoSupport,
+        const bool.fromEnvironment("dart.library.io",
+            defaultValue: false));
+  }
+
+  bool hasMirrorSupport;
+  hasMirrorSupport = true;   /// has_mirror_support: ok
+  hasMirrorSupport = false;  /// has_no_mirror_support: ok
+
+  if (hasMirrorSupport != null) {
+    bool expectedResult = hasMirrorSupport ? true : NOT_PRESENT;
+
+    Expect.equals(expectedResult,
+        const bool.fromEnvironment("dart.library.mirrors",
+            defaultValue: NOT_PRESENT));
+  }
+
+  Expect.equals(NOT_PRESENT,
+      const bool.fromEnvironment("dart.library.XYZ",
+          defaultValue: NOT_PRESENT));
+  Expect.equals(NOT_PRESENT,
+      const bool.fromEnvironment("dart.library.Collection",
+          defaultValue: NOT_PRESENT));
+  Expect.equals(NOT_PRESENT,
+      const bool.fromEnvironment("dart.library.converT",
+          defaultValue: NOT_PRESENT));
+  Expect.equals(NOT_PRESENT,
+      const bool.fromEnvironment("dart.library.",
+          defaultValue: NOT_PRESENT));
+  Expect.equals(NOT_PRESENT,
+      const bool.fromEnvironment("dart.library.core ",
+          defaultValue: NOT_PRESENT));
+
+}
diff --git a/tests/language/method_name_test.dart b/tests/language/method_name_test.dart
index b0199cf..ea9c7d2 100644
--- a/tests/language/method_name_test.dart
+++ b/tests/language/method_name_test.dart
@@ -12,6 +12,7 @@
   int get() {return 1;}
   int set() {return 2;}
   int operator() {return 3;}
+  int factory() { return 4; }
 }
 
 // Without return types.
@@ -19,6 +20,7 @@
   get() {return 1;}
   set() {return 2;}
   operator() {return 3;}
+  factory() { return 4; }
 }
 
 main() {
@@ -27,11 +29,13 @@
     Expect.equals(1, a.get());
     Expect.equals(2, a.set());
     Expect.equals(3, a.operator());
+    Expect.equals(4, a.factory());
   }
   {
     B b = new B();
     Expect.equals(1, b.get());
     Expect.equals(2, b.set());
     Expect.equals(3, b.operator());
+    Expect.equals(4, b.factory());
   }
 }
diff --git a/tests/language/mixin_illegal_super_use_test.dart b/tests/language/mixin_illegal_super_use_test.dart
new file mode 100644
index 0000000..7f0d64a
--- /dev/null
+++ b/tests/language/mixin_illegal_super_use_test.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class M {
+}
+
+class P0 {
+  foo() {
+    super.toString();    /// 01: compile-time error
+    super.foo();         /// 02: compile-time error
+    super.bar = 100;     /// 03: compile-time error
+
+    void inner() {
+      super.toString();  /// 04: compile-time error
+      super.foo();       /// 05: compile-time error
+      super.bar = 100;   /// 06: compile-time error
+    }
+    inner();
+
+    (() {
+      super.toString();  /// 07: compile-time error
+      super.foo();       /// 08: compile-time error
+      super.bar = 100;   /// 09: compile-time error
+    })();
+
+    return 42;
+  }
+}
+
+class P1 {
+  bar() {
+    super.toString();    /// 10: compile-time error
+    return 87;
+  }
+
+  // The test method is strategically placed here to try to force the
+  // P1 class and its bar method to be resolved before resolving the
+  // mixin applications.
+  test() {
+    new C();
+    var d = new D();
+    var e = new E();
+    var f = new F();
+    Expect.equals(42, d.foo());
+    Expect.equals(87, e.bar());
+    Expect.equals(99, f.baz());
+  }
+}
+
+class P2 {
+  baz() {
+    super.toString();   /// 11: compile-time error
+    return 99;
+  }
+}
+
+class C = Object with M;
+class D = Object with P0;
+class E = Object with M, P1;
+class F = Object with P2, M;
+
+main() {
+  var p1 = new P1();
+  var p2 = new P2();
+  Expect.equals(87, p1.bar());
+  p1.test();
+  Expect.equals(99, p2.baz());
+}
diff --git a/tests/language/mixin_illegal_superclass_test.dart b/tests/language/mixin_illegal_superclass_test.dart
new file mode 100644
index 0000000..03d2e6a
--- /dev/null
+++ b/tests/language/mixin_illegal_superclass_test.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class S0 { }
+class S1 extends Object { }
+class S2 extends S0 { }
+
+class M0 { }
+class M1 extends Object { }
+class M2 extends M0 { }
+
+class C00 = S0 with M0;
+class C01 = S0 with M1;
+class C02 = S0 with M2;      /// 01: compile-time error
+class C03 = S0 with M0, M1;
+class C04 = S0 with M0, M2;  /// 02: compile-time error
+class C05 = S0 with M2, M0;  /// 03: compile-time error
+class C06 = S0 with M1, M2;  /// 04: compile-time error
+class C07 = S0 with M2, M1;  /// 05: compile-time error
+
+class C10 = S1 with M0;
+class C11 = S1 with M1;
+class C12 = S1 with M2;      /// 06: compile-time error
+class C13 = S1 with M0, M1;
+class C14 = S1 with M0, M2;  /// 07: compile-time error
+class C15 = S1 with M2, M0;  /// 08: compile-time error
+class C16 = S1 with M1, M2;  /// 09: compile-time error
+class C17 = S1 with M2, M1;  /// 10: compile-time error
+
+class C20 = S2 with M0;
+class C21 = S2 with M1;
+class C22 = S2 with M2;      /// 11: compile-time error
+class C23 = S2 with M0, M1;
+class C24 = S2 with M0, M2;  /// 12: compile-time error
+class C25 = S2 with M2, M0;  /// 13: compile-time error
+class C26 = S2 with M1, M2;  /// 14: compile-time error
+class C27 = S2 with M2, M1;  /// 15: compile-time error
+
+class D00 extends S0 with M0 { }
+class D01 extends S0 with M1 { }
+class D02 extends S0 with M2 { }      /// 16: compile-time error
+class D03 extends S0 with M0, M1 { }
+class D04 extends S0 with M0, M2 { }  /// 17: compile-time error
+class D05 extends S0 with M2, M0 { }  /// 18: compile-time error
+class D06 extends S0 with M1, M2 { }  /// 19: compile-time error
+class D07 extends S0 with M2, M1 { }  /// 20: compile-time error
+
+class D10 extends S1 with M0 { }
+class D11 extends S1 with M1 { }
+class D12 extends S1 with M2 { }      /// 21: compile-time error
+class D13 extends S1 with M0, M1 { }
+class D14 extends S1 with M0, M2 { }  /// 22: compile-time error
+class D15 extends S1 with M2, M0 { }  /// 23: compile-time error
+class D16 extends S1 with M1, M2 { }  /// 24: compile-time error
+class D17 extends S1 with M2, M1 { }  /// 25: compile-time error
+
+class D20 extends S2 with M0 { }
+class D21 extends S2 with M1 { }
+class D22 extends S2 with M2 { }      /// 26: compile-time error
+class D23 extends S2 with M0, M1 { }
+class D24 extends S2 with M0, M2 { }  /// 27: compile-time error
+class D25 extends S2 with M2, M0 { }  /// 28: compile-time error
+class D26 extends S2 with M1, M2 { }  /// 29: compile-time error
+class D27 extends S2 with M2, M1 { }  /// 30: compile-time error
+
+main() {
+  new C00();
+  new C01();
+  new C02();  /// 01: continued
+  new C03();
+  new C04();  /// 02: continued
+  new C05();  /// 03: continued
+  new C06();  /// 04: continued
+  new C07();  /// 05: continued
+
+  new C10();
+  new C11();
+  new C12();  /// 06: continued
+  new C13();
+  new C14();  /// 07: continued
+  new C15();  /// 08: continued
+  new C16();  /// 09: continued
+  new C17();  /// 10: continued
+
+  new C20();
+  new C21();
+  new C22();  /// 11: continued
+  new C23();
+  new C24();  /// 12: continued
+  new C25();  /// 13: continued
+  new C26();  /// 14: continued
+  new C27();  /// 15: continued
+
+  new D00();
+  new D01();
+  new D02();  /// 16: continued
+  new D03();
+  new D04();  /// 17: continued
+  new D05();  /// 18: continued
+  new D06();  /// 19: continued
+  new D07();  /// 20: continued
+
+  new D10();
+  new D11();
+  new D12();  /// 21: continued
+  new D13();
+  new D14();  /// 22: continued
+  new D15();  /// 23: continued
+  new D16();  /// 24: continued
+  new D17();  /// 25: continued
+
+  new D20();
+  new D21();
+  new D22();  /// 26: continued
+  new D23();
+  new D24();  /// 27: continued
+  new D25();  /// 28: continued
+  new D26();  /// 29: continued
+  new D27();  /// 30: continued
+}
diff --git a/tests/language/mixin_of_mixin_test.dart b/tests/language/mixin_of_mixin_test.dart
new file mode 100644
index 0000000..005f959
--- /dev/null
+++ b/tests/language/mixin_of_mixin_test.dart
@@ -0,0 +1,59 @@
+// 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.
+// SharedOptions=--supermixin
+
+// Validate the following text from section 12 ("Mixins") of the spec:
+//
+//     "A mixin application of the form S with M; defines a class C ...
+//     ... C declares the same instance members as M ..."
+//
+// This means that if M is itself a mixin application, then things
+// mixed into M are accessible through C.  But if M simply *extends* a
+// mixin application (e.g. because M is declared as `class M extends X
+// with Y { ... }`) then things mixed into the mixin application that
+// M extends are not accessible through C.
+
+class A { a() => null; }
+class B { b() => null; }
+class C { c() => null; }
+class D { d() => null; }
+
+// Note: by a slight abuse of syntax, `class M1 = A with B, C;` effectively
+// means `class M1 = (A with B) with C;`, therefore M1 declares c(), but it
+// merely inherits a() and b().
+class M1 = A with B, C; // declares c()
+
+class M2 extends M1 { m2() => null; }
+class M3 extends A with B, C { m3() => null; }
+class T1 = D with M1; // declares c()
+class T2 = D with M2; // declares m2()
+class T3 = D with M3; // declares m3()
+class T4 extends D with M1 {} // extends a class which declares c()
+class T5 extends D with M2 {} // extends a class which declares m2()
+class T6 extends D with M3 {} // extends a class which declares m3()
+
+main() {
+  new T1().a();  /// 01: static type warning, runtime error
+  new T1().b();  /// 02: static type warning, runtime error
+  new T1().c();  /// 03: ok
+  new T2().a();  /// 04: static type warning, runtime error
+  new T2().b();  /// 05: static type warning, runtime error
+  new T2().c();  /// 06: static type warning, runtime error
+  new T2().m2(); /// 07: ok
+  new T3().a();  /// 08: static type warning, runtime error
+  new T3().b();  /// 09: static type warning, runtime error
+  new T3().c();  /// 10: static type warning, runtime error
+  new T3().m3(); /// 11: ok
+  new T4().a();  /// 12: static type warning, runtime error
+  new T4().b();  /// 13: static type warning, runtime error
+  new T4().c();  /// 14: ok
+  new T5().a();  /// 15: static type warning, runtime error
+  new T5().b();  /// 16: static type warning, runtime error
+  new T5().c();  /// 17: static type warning, runtime error
+  new T5().m2(); /// 18: ok
+  new T6().a();  /// 19: static type warning, runtime error
+  new T6().b();  /// 20: static type warning, runtime error
+  new T6().c();  /// 21: static type warning, runtime error
+  new T6().m3(); /// 22: ok
+}
diff --git a/tests/language/mixin_super_2_test.dart b/tests/language/mixin_super_2_test.dart
index ad86c08..91d68c6 100644
--- a/tests/language/mixin_super_2_test.dart
+++ b/tests/language/mixin_super_2_test.dart
@@ -1,6 +1,7 @@
 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
 
 import "package:expect/expect.dart";
 
diff --git a/tests/language/mixin_super_bound2_test.dart b/tests/language/mixin_super_bound2_test.dart
index c6fcd7a..87e8b7a 100644
--- a/tests/language/mixin_super_bound2_test.dart
+++ b/tests/language/mixin_super_bound2_test.dart
@@ -1,6 +1,7 @@
 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
 
 import "package:expect/expect.dart";
 
diff --git a/tests/language/mixin_super_test.dart b/tests/language/mixin_super_test.dart
index 6a5d5a3..8a4ee98 100644
--- a/tests/language/mixin_super_test.dart
+++ b/tests/language/mixin_super_test.dart
@@ -1,6 +1,7 @@
 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
 
 import "package:expect/expect.dart";
 
diff --git a/tests/language/mixin_super_use_test.dart b/tests/language/mixin_super_use_test.dart
index cd95846..614bb632c 100644
--- a/tests/language/mixin_super_use_test.dart
+++ b/tests/language/mixin_super_use_test.dart
@@ -1,6 +1,7 @@
 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
 
 import "package:expect/expect.dart";
 
diff --git a/tests/language/mixin_superclass_test.dart b/tests/language/mixin_superclass_test.dart
index ade41da..1e658e8 100644
--- a/tests/language/mixin_superclass_test.dart
+++ b/tests/language/mixin_superclass_test.dart
@@ -1,6 +1,7 @@
 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
+// SharedOptions=--supermixin
 
 class S0 { }
 class S1 extends Object { }
diff --git a/tests/language/mixin_supertype_subclass2_test.dart b/tests/language/mixin_supertype_subclass2_test.dart
new file mode 100644
index 0000000..d7ee562
--- /dev/null
+++ b/tests/language/mixin_supertype_subclass2_test.dart
@@ -0,0 +1,30 @@
+// 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.
+// SharedOptions=--supermixin
+
+// Validate the following test from section 12 ("Mixins") of the spec:
+//
+//     "Let M_A be a mixin derived from a class M with direct superclass
+//     S_static.
+//
+//     Let A be an application of M_A.  It is a static warning if the
+//     superclass of A is not a subtype of S_static."
+
+class B {}
+class C {}
+class D {}
+class E extends B with C implements D {}
+class F extends E {}
+class A extends E with M {}
+class M
+  extends B /// 01: ok
+  extends C /// 02: static type warning
+  extends D /// 03: ok
+  extends E /// 04: ok
+  extends F /// 05: static type warning
+  {}
+
+main() {
+  new A();
+}
diff --git a/tests/language/mixin_supertype_subclass3_test.dart b/tests/language/mixin_supertype_subclass3_test.dart
new file mode 100644
index 0000000..7ca889d
--- /dev/null
+++ b/tests/language/mixin_supertype_subclass3_test.dart
@@ -0,0 +1,31 @@
+// 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.
+// SharedOptions=--supermixin
+
+// Validate the following test from section 12 ("Mixins") of the spec:
+//
+//     "Let M_A be a mixin derived from a class M with direct superclass
+//     S_static.
+//
+//     Let A be an application of M_A.  It is a static warning if the
+//     superclass of A is not a subtype of S_static."
+
+// In this test, M is declared as `class M = S_static with G;`.
+
+class B {}
+class C {}
+class D {}
+class E extends B with C implements D {}
+class F extends E {}
+class A
+  = E with M; class M = B with G; class G /// 01: ok
+  = E with M; class M = C with G; class G /// 02: static type warning
+  = E with M; class M = D with G; class G /// 03: ok
+  = E with M; class M = E with G; class G /// 04: ok
+  = E with M; class M = F with G; class G /// 05: static type warning
+  {}
+
+main() {
+  new A();
+}
diff --git a/tests/language/mixin_supertype_subclass4_test.dart b/tests/language/mixin_supertype_subclass4_test.dart
new file mode 100644
index 0000000..e1a501a
--- /dev/null
+++ b/tests/language/mixin_supertype_subclass4_test.dart
@@ -0,0 +1,36 @@
+// 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.
+// SharedOptions=--supermixin
+
+// Validate the following test from section 12 ("Mixins") of the spec:
+//
+//     "Let M_A be a mixin derived from a class M with direct superclass
+//     S_static.
+//
+//     Let A be an application of M_A.  It is a static warning if the
+//     superclass of A is not a subtype of S_static."
+
+// In this test, M is declared as `class M extends ... with G {}`, so
+// `S_static` is the unnamed mixin application `... with G`.  Since this
+// unnamed mixin application can't be derived from, all the cases should yield
+// a warning.
+
+class B {}
+class C {}
+class D {}
+class E extends B with C implements D {}
+class F extends E {}
+class G {}
+class A = E with M;
+class M
+  extends B with G /// 01: static type warning
+  extends C with G /// 02: static type warning
+  extends D with G /// 03: static type warning
+  extends E with G /// 04: static type warning
+  extends F with G /// 05: static type warning
+  {}
+
+main() {
+  new A();
+}
diff --git a/tests/language/mixin_supertype_subclass_test.dart b/tests/language/mixin_supertype_subclass_test.dart
new file mode 100644
index 0000000..70627f6
--- /dev/null
+++ b/tests/language/mixin_supertype_subclass_test.dart
@@ -0,0 +1,30 @@
+// 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.
+// SharedOptions=--supermixin
+
+// Validate the following test from section 12 ("Mixins") of the spec:
+//
+//     "Let M_A be a mixin derived from a class M with direct superclass
+//     S_static.
+//
+//     Let A be an application of M_A.  It is a static warning if the
+//     superclass of A is not a subtype of S_static."
+
+class B {}
+class C {}
+class D {}
+class E extends B with C implements D {}
+class F extends E {}
+class A = E with M;
+class M
+  extends B /// 01: ok
+  extends C /// 02: static type warning
+  extends D /// 03: ok
+  extends E /// 04: ok
+  extends F /// 05: static type warning
+  {}
+
+main() {
+  new A();
+}
diff --git a/tests/language/proxy4_test.dart b/tests/language/proxy4_test.dart
new file mode 100644
index 0000000..a7d44b5
--- /dev/null
+++ b/tests/language/proxy4_test.dart
@@ -0,0 +1,18 @@
+// 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.
+
+// Test for static warnings for member access on classes that inherit a
+// user defined noSuchMethod.
+
+class Mock {
+  noSuchMethod(i) => 42;
+}
+
+abstract class Foo { int foo(); }
+
+class DontWarnMe extends Mock implements Foo {}
+
+main() {
+  print(new DontWarnMe().foo());
+}
\ No newline at end of file
diff --git a/tests/language/proxy5_test.dart b/tests/language/proxy5_test.dart
new file mode 100644
index 0000000..41e63e6
--- /dev/null
+++ b/tests/language/proxy5_test.dart
@@ -0,0 +1,20 @@
+// 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.
+
+// Test for static warnings for member access on classes that inherit a
+// user defined noSuchMethod, even if it is abstract.
+
+import 'package:expect/expect.dart';
+
+abstract class Mock {
+  noSuchMethod(i);
+}
+
+abstract class Foo { int foo(); }
+
+class DontWarnMe extends Mock implements Foo {}
+
+main() {
+  Expect.throws(() => new DontWarnMe().foo());
+}
\ No newline at end of file
diff --git a/tests/language/regress_24567_test.dart b/tests/language/regress_24567_test.dart
new file mode 100644
index 0000000..e72750a
--- /dev/null
+++ b/tests/language/regress_24567_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:math' as math;
+
+class Random { }
+
+typedef F(Random r);
+
+main() {
+  f(Random r) { }
+  g(math.Random r) { }
+  Expect.isTrue(f is F);
+  Expect.isFalse(g is F);
+}
diff --git a/tests/language/regress_24935_test.dart b/tests/language/regress_24935_test.dart
new file mode 100644
index 0000000..53f6f49
--- /dev/null
+++ b/tests/language/regress_24935_test.dart
@@ -0,0 +1,24 @@
+// 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:async';
+
+S() => new Stream.fromIterable([1]);
+
+Future main() async {
+  L: for (var s = 0; s < 10; s++) {
+    await for (var s1 in S()){
+      await for (var s2 in S()){
+        continue L;
+      }
+    }
+  }
+  // Regression check: make sure throwing an exception
+  // after breaking out of the innermost loop does not
+  // crash the VM. In other words, the expected test
+  // outcome is an unhandled exception.
+  throw "ball"; /// 01: runtime error
+}
+
+
diff --git a/tests/language/regress_25550_test.dart b/tests/language/regress_25550_test.dart
new file mode 100644
index 0000000..4a8a7c5
--- /dev/null
+++ b/tests/language/regress_25550_test.dart
@@ -0,0 +1,17 @@
+// 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.
+
+typedef int Adder(int a, int b);
+
+class Mock {
+  noSuchMethod(i) => null;
+}
+
+class MockAdder extends Mock {
+  int call(int a, int b);
+}
+
+main() {
+  Adder adder = new MockAdder();
+}
diff --git a/tests/language/regress_25568_test.dart b/tests/language/regress_25568_test.dart
new file mode 100644
index 0000000..6e18a60
--- /dev/null
+++ b/tests/language/regress_25568_test.dart
@@ -0,0 +1,22 @@
+// 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.
+
+main() {}
+
+class BacklogListEditorState
+    extends AbstractListEditorState<BacklogsState, BacklogListEditorState> {}
+
+class BacklogsState extends MutableEntityState<BacklogsState> {}
+
+abstract class AbstractListEditorState<ES extends ComponentState<ES>,
+    S extends AbstractListEditorState<ES, S>> extends ComponentState<S> {}
+
+abstract class ComponentState<S extends ComponentState<S>> {}
+
+abstract class EntityState<ES extends EntityState<ES>>
+    extends ComponentState<ES> {}
+
+abstract class MutableEntityState<S extends MutableEntityState<S>>
+    extends EntityState<S> implements ComponentState<S> {}
+
diff --git a/tests/language/regress_25609_lib1.dart b/tests/language/regress_25609_lib1.dart
new file mode 100644
index 0000000..98fdb20
--- /dev/null
+++ b/tests/language/regress_25609_lib1.dart
@@ -0,0 +1,10 @@
+// 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 regress_25609_lib1;
+
+import 'regress_25609_lib2.dart';
+
+typedef Bar Foo(int y);
+
diff --git a/tests/language/regress_25609_lib2.dart b/tests/language/regress_25609_lib2.dart
new file mode 100644
index 0000000..d51c061
--- /dev/null
+++ b/tests/language/regress_25609_lib2.dart
@@ -0,0 +1,7 @@
+// 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 regress_25609_lib2;
+
+typedef void Bar(double x);
diff --git a/tests/language/regress_25609_test.dart b/tests/language/regress_25609_test.dart
new file mode 100644
index 0000000..579f1c2
--- /dev/null
+++ b/tests/language/regress_25609_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--error-on-bad-type
+
+import 'regress_25609_lib1.dart';
+
+Foo baz() => null;
+
+main () {
+  baz();
+}
diff --git a/tests/language/regress_25620_test.dart b/tests/language/regress_25620_test.dart
new file mode 100644
index 0000000..7ea9a6f
--- /dev/null
+++ b/tests/language/regress_25620_test.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+typedef Future<T> SyncedExecutionFn<T>(Future<T> fn());
+main() {}
+
diff --git a/tests/language/super_no_such_method1_test.dart b/tests/language/super_no_such_method1_test.dart
new file mode 100644
index 0000000..3ee6151
--- /dev/null
+++ b/tests/language/super_no_such_method1_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+  noSuchMethod(im) => 42;
+}
+
+class B extends A {
+  noSuchMethod(im) => 87;
+
+  foo() => super.foo(); /// 01: static type warning
+}
+
+main() {
+  Expect.equals(42, new B().foo()); /// 01: continued
+}
\ No newline at end of file
diff --git a/tests/language/super_no_such_method2_test.dart b/tests/language/super_no_such_method2_test.dart
new file mode 100644
index 0000000..cbd4621
--- /dev/null
+++ b/tests/language/super_no_such_method2_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+  noSuchMethod(im) => 42;
+}
+
+class B extends A {
+  noSuchMethod(im) => 87;
+
+  get foo => super.foo; /// 01: static type warning
+}
+
+main() {
+  Expect.equals(42, new B().foo); /// 01: continued
+}
\ No newline at end of file
diff --git a/tests/language/super_no_such_method3_test.dart b/tests/language/super_no_such_method3_test.dart
new file mode 100644
index 0000000..864fa78
--- /dev/null
+++ b/tests/language/super_no_such_method3_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+var result;
+
+class A {
+  noSuchMethod(im) {
+    result = 42;
+  }
+}
+
+class B extends A {
+  noSuchMethod(im) {
+    result = 87;
+  }
+
+  set foo(v) => super.foo = v; /// 01: static type warning
+}
+
+main() {
+  new B().foo = 0;           /// 01: continued
+  Expect.equals(42, result); /// 01: continued
+}
\ No newline at end of file
diff --git a/tests/language/super_no_such_method4_test.dart b/tests/language/super_no_such_method4_test.dart
new file mode 100644
index 0000000..7d88a54
--- /dev/null
+++ b/tests/language/super_no_such_method4_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+  noSuchMethod(im) => 42;
+}
+
+class B extends Object with A {
+  noSuchMethod(im) => 87;
+
+  foo() => super.foo(); /// 01: static type warning
+}
+
+main() {
+  Expect.equals(42, new B().foo()); /// 01: continued
+}
\ No newline at end of file
diff --git a/tests/language/super_no_such_method5_test.dart b/tests/language/super_no_such_method5_test.dart
new file mode 100644
index 0000000..fba8087
--- /dev/null
+++ b/tests/language/super_no_such_method5_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+  noSuchMethod(im) => 42;
+}
+
+class B extends Object with A {
+  foo() => super.foo(); /// 01: static type warning
+}
+
+main() {
+  Expect.equals(42, new B().foo()); /// 01: continued
+}
\ No newline at end of file
diff --git a/tests/language/try_finally_regress_25654_test.dart b/tests/language/try_finally_regress_25654_test.dart
new file mode 100644
index 0000000..b510e16
--- /dev/null
+++ b/tests/language/try_finally_regress_25654_test.dart
@@ -0,0 +1,36 @@
+// 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.
+
+// Test break out of try-finally.
+
+import "package:expect/expect.dart";
+
+var count = 0;
+
+test() {
+  L:
+  while (true) {
+    try {
+      break L;
+    } finally {
+      count++;
+    }
+  }
+  throw "ex";
+}
+
+main() {
+  bool caught = false;
+  try {
+    test();
+  } catch (e) {
+    caught = true;
+    Expect.equals(e, "ex");
+  }
+  Expect.isTrue(caught);
+  Expect.equals(1, count);
+}
+
+
+
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index 4016986..3288d18 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -24,5 +24,5 @@
 lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError # Issue 21647
 lib/web_audio/dartium/web_audio_dartium: CompileTimeError # Issue 21647
 lib/svg/dartium/svg_dartium: CompileTimeError # Issue 21647
-lib/_blink/dartium/_blink_dartium: CompileTimeError # Dartium JsInterop roll (js.JsObjectImpl)
-lib/js/dartium/js_dartium: CompileTimeError # Dartium JsInterop roll (js.JsObjectImpl)
+lib/_blink/dartium/_blink_dartium: CompileTimeError # Undefined Creates and Returns classes
+lib/js/dartium/js_dartium: CompileTimeError # Undefined Creates and Returns classes
\ No newline at end of file
diff --git a/tests/lib/async/future_timeout_test.dart b/tests/lib/async/future_timeout_test.dart
index 8209b8b..806b4b4 100644
--- a/tests/lib/async/future_timeout_test.dart
+++ b/tests/lib/async/future_timeout_test.dart
@@ -185,4 +185,14 @@
       expect(s, null);
     }));
   });
+
+  test("timeoutType", () {
+    Completer completer = new Completer<int>();
+    Future timedOut = completer.future.timeout(
+        const Duration(milliseconds: 5));
+    expect(timedOut, new isInstanceOf<Future<int>>());
+    expect(timedOut, isNot(new isInstanceOf<Future<String>>()));
+    timedOut.catchError((_) {});
+    completer.complete(499);
+  });
 }
diff --git a/tests/lib/async/stream_view_test.dart b/tests/lib/async/stream_view_test.dart
new file mode 100644
index 0000000..5b8308a
--- /dev/null
+++ b/tests/lib/async/stream_view_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests the StreamView class.
+
+import "package:expect/expect.dart";
+import "dart:async";
+import "package:async_helper/async_helper.dart";
+
+main() {
+  asyncStart();
+  runTest().whenComplete(asyncEnd);
+}
+
+Future runTest() async {
+  unreachable([a,b]) { throw "UNREACHABLE"; }
+  int tick = 0;
+  ticker() { tick++; }
+
+  asyncStart();
+
+  // Is const constructor.
+  Stream<int> s = const StreamView<int>(const Stream<int>.empty());
+
+  Expect.isFalse(s is Stream<String>);  // Respects type parameter.
+  StreamSubscription<int> sub =
+     s.listen(unreachable, onError: unreachable, onDone: ticker);
+  Expect.isFalse(sub is StreamSubscription<String>);  // Type parameter in sub.
+
+  Stream iterableStream = new Stream.fromIterable([1, 2, 3]);
+  Expect.listEquals([1, 2, 3], await iterableStream.toList());
+
+  asyncEnd();
+}
+
+Future flushMicrotasks() => new Future.delayed(Duration.ZERO);
diff --git a/tests/lib/async/timer_repeat_test.dart b/tests/lib/async/timer_repeat_test.dart
index e963c5a..1ed5139 100644
--- a/tests/lib/async/timer_repeat_test.dart
+++ b/tests/lib/async/timer_repeat_test.dart
@@ -11,16 +11,24 @@
 const int ITERATIONS = 5;
 
 Timer timer;
-int startTime;
+Stopwatch stopwatch = new Stopwatch();
 int iteration;
 
+// Some browsers (Firefox and IE so far) can trigger too early. Add a safety
+// margin. We use identical(1, 1.0) as an easy way to know if the test is
+// compiled by dart2js.
+int get safetyMargin => identical(1, 1.0) ? 100 : 0;
+
 void timeoutHandler(Timer timer) {
-  int endTime = (new DateTime.now()).millisecondsSinceEpoch;
   iteration++;
-  if (iteration < ITERATIONS) {
-    startTime = (new DateTime.now()).millisecondsSinceEpoch;
-  } else {
-    expect(iteration, ITERATIONS);
+  expect(iteration, lessThanOrEqualTo(ITERATIONS));
+  if (iteration == ITERATIONS) {
+    // When we are done with all of the iterations, we expect a
+    // certain amount of time to have passed.  Checking the time on
+    // each iteration doesn't work because the timeoutHandler runs
+    // concurrently with the periodic timer.
+    expect(stopwatch.elapsedMilliseconds + safetyMargin,
+           greaterThanOrEqualTo(ITERATIONS * TIMEOUT.inMilliseconds));
     timer.cancel();
   }
 }
@@ -28,7 +36,7 @@
 main() {
   test("timer_repeat", () {
     iteration = 0;
-    startTime = new DateTime.now().millisecondsSinceEpoch;
+    stopwatch.start();
     timer = new Timer.periodic(TIMEOUT,
         expectAsync(timeoutHandler, count: ITERATIONS));
   });
diff --git a/tests/lib/async/timer_test.dart b/tests/lib/async/timer_test.dart
index fc7ee87..d08754b 100644
--- a/tests/lib/async/timer_test.dart
+++ b/tests/lib/async/timer_test.dart
@@ -11,7 +11,7 @@
 const int DECREASE = 200;
 const int ITERATIONS = 5;
 
-int startTime;
+Stopwatch stopwatch = new Stopwatch();
 int timeout;
 int iteration;
 
@@ -21,13 +21,13 @@
 int get safetyMargin => identical(1, 1.0) ? 100 : 0;
 
 void timeoutHandler() {
-  int endTime = (new DateTime.now()).millisecondsSinceEpoch;
-  expect(endTime - startTime + safetyMargin, greaterThanOrEqualTo(timeout));
+  expect(stopwatch.elapsedMilliseconds + safetyMargin,
+         greaterThanOrEqualTo(timeout));
   if (iteration < ITERATIONS) {
     iteration++;
     timeout = timeout - DECREASE;
     Duration duration = new Duration(milliseconds: timeout);
-    startTime = (new DateTime.now()).millisecondsSinceEpoch;
+    stopwatch.reset();
     new Timer(duration, expectAsync(timeoutHandler));
   }
 }
@@ -37,7 +37,7 @@
     iteration = 0;
     timeout = STARTTIMEOUT;
     Duration duration = new Duration(milliseconds: timeout);
-    startTime = (new DateTime.now()).millisecondsSinceEpoch;
+    stopwatch.start();
     new Timer(duration, expectAsync(timeoutHandler));
   });
 }
diff --git a/tests/lib/convert/base64_test.dart b/tests/lib/convert/base64_test.dart
index ccbed3d..457e330 100644
--- a/tests/lib/convert/base64_test.dart
+++ b/tests/lib/convert/base64_test.dart
@@ -20,6 +20,7 @@
     testRoundtrip(new Uint8List.fromList(list), "Uint8List#${list.length}");
   }
   testErrors();
+  testIssue25577();
 
   // Decoder is lenienet with mixed styles.
   Expect.listEquals([0xfb, 0xff, 0xbf, 0x00], BASE64.decode("-_+/AA%3D="));
@@ -236,3 +237,18 @@
   badEncode(0x100000000);          /// 01: ok
   badEncode(0x10000000000000000);  /// 01: continued
 }
+
+void testIssue25577() {
+  // Regression test for http://dartbug.com/25577
+  // Should not fail in checked mode.
+  StringConversionSink decodeSink =
+      BASE64.decoder.startChunkedConversion(new TestSink<List<int>>());
+  ByteConversionSink encodeSink =
+      BASE64.encoder.startChunkedConversion(new TestSink<String>());
+}
+
+// Implementation of Sink<T> to test type constraints.
+class TestSink<T> implements Sink<T> {
+  void add(T value) {}
+  void close() {}
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index d4cdafe..a8623b4 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -170,7 +170,6 @@
 
 [ $compiler == dart2js && $checked ]
 convert/utf85_test: Pass, Slow # Issue 12029.
-mirrors/list_constructor_test/01: RuntimeError # Issue 19635.
 
 [ $compiler == dart2js ]
 convert/chunked_conversion_utf88_test: Slow, Pass
@@ -186,9 +185,15 @@
 
 # 'js' tests import the dart:js library, so they only make sense in
 # a browser environment.
-[ ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 js/*: Skip
 
+# 'js' tests import the dart:js library, so they only make sense in
+# a browser environment.
+[ $runtime == dart_product ]
+js/*: SkipByDesign
+mirrors/*: SkipByDesign
+
 [ $compiler == dart2js && $minified ]
 mirrors/mirrors_used_get_name_test: RuntimeError
 mirrors/mirrors_used_get_name2_test: RuntimeError
@@ -203,7 +208,7 @@
 async/slow_consumer_test: Pass, Timeout # Issue 22696
 async/catch_errors11_test: Pass, Timeout # Issue 22696
 
-[ $runtime == chrome || $runtime == ff || $runtime == ContentShellOnAndroid ]
+[ $runtime == chrome || $runtime == ff ]
 convert/streamed_conversion_utf8_encode_test: SkipSlow # Times out. Issue 22050
 convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
 convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
@@ -223,19 +228,19 @@
 # TODO(efortuna): Investigate.
 async/timer_test: Fail, Pass
 
-[ ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 async/timer_not_available_test: Fail, OK
 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 == 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
 
 mirrors/mirrors_used*: SkipByDesign # Invalid tests. MirrorsUsed does not have a specification, and dart:mirrors is not required to hide declarations that are not covered by any MirrorsUsed annotation.
 
-[ ($compiler == none || $compiler == precompiler) && ( $runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
+[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
 async/schedule_microtask6_test: Fail # Issue 10910
 async/timer_test: Fail, Pass # Issue 15487
 async/multiple_timer_test: Fail, Pass # Issue 15487
@@ -248,22 +253,13 @@
 mirrors/local_isolate_test: RuntimeError # Issue 12188
 mirrors/deferred_type_test: RuntimeError, OK # Should be CompileTimeError. Issue 22072
 
-[ ($compiler == none || $compiler == precompiler) && $runtime == drt && $system == windows ]
+[ $compiler == none && $runtime == drt && $system == windows ]
 async/multiple_timer_test: Fail, Pass # See Issue 10982
 async/timer_test: Fail, Pass # See Issue 10982
 
-[ ($compiler == none || $compiler == precompiler) && $runtime == drt && $checked ]
+[ $compiler == none && $runtime == drt && $checked ]
 async/slow_consumer_test: Fail, Pass # Dartium JsInterop failure, dartbug.com/24460
 
-[($compiler == none || $compiler == precompiler) && $runtime == ContentShellOnAndroid ]
-async/stream_timeout_test: RuntimeError, Pass # Issue 19127
-async/slow_consumer3_test: SkipSlow # Times out flakily. Issue 20956
-async/slow_consumer2_test: SkipSlow # Times out flakily. Issue 20956
-convert/streamed_conversion_utf8_encode_test: SkipSlow # Times out or passes. Issue 19127
-convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out or passes. Issue 19127
-mirrors/lazy_static_test: SkipSlow # Times out. Issue 19127
-mirrors/mirrors_reader_test: SkipSlow # Times out. Issue 19127
-
 [ $compiler == dart2js && $runtime == safarimobilesim ]
 mirrors/mirrors_reader_test: SkipSlow # Times out. Issue 20806.
 
@@ -292,9 +288,6 @@
 profiler/metrics_test: Fail # Issue 20309
 profiler/metrics_num_test: Fail # Issue 20309
 
-[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
-mirrors/metadata_allowed_values_test/29: Crash # Issue 25287
-
 [ ($compiler == dartanalyzer || $compiler == dart2analyzer) && $checked ]
 mirrors/regress_16321_test/01: MissingCompileTimeError # Issue 16391
 
@@ -305,10 +298,10 @@
 [ $compiler == dart2js && $mode == debug ]
 mirrors/native_class_test: Pass, Slow
 
-[ ($compiler == none || $compiler == precompiler) && $arch == mips ]
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2app) && $arch == mips ]
 async/timer_regress22626_test: Pass, RuntimeError # Issue 22626
 
-[ $arch == simarm || $arch == simarmv5te ]
+[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te ]
 convert/chunked_conversion_utf88_test: Skip  # Pass, Slow Issue 12644.
 convert/utf85_test: Skip  # Pass, Slow Issue 12644.
 
@@ -325,23 +318,23 @@
 [ $mode == debug && $arch == ia32 && $system == windows ]
 convert/streamed_conversion_json_utf8_decode_test: Skip  # Verification OOM.
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug && $arch == x64 && $system == windows ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $mode == debug && $arch == x64 && $system == windows ]
 convert/streamed_conversion_json_utf8_decode_test: Pass, Slow
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $mode == release && $arch == ia32 && $system == windows ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $mode == release && $arch == ia32 && $system == windows ]
 convert/json_test: RuntimeError # Issue 24908
 
-[ $mode == debug && $arch != ia32 && $arch != x64 && $arch != simarm && $arch != simarmv5te ]
+[ $mode == debug && $arch != ia32 && $arch != x64 && $arch != simarm && $arch != simarmv6 && $arch != simarmv5te ]
 convert/streamed_conversion_json_utf8_decode_test: Skip  # Verification not yet implemented.
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug && $builder_tag == asan ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $mode == debug && $builder_tag == asan ]
 mirrors/immutable_collections_test: SkipSlow  # Timeout.
 convert/streamed_conversion_json_utf8_decode_test: Skip  # Timeout.
 
 [ $compiler == dart2js && $cps_ir ]
 async/async_await_zones_test: Crash # (await for(var x in bar().take(100)){sum+= x;}): await for
 async/stream_iterator_test: Crash # (Stream createCancel...  cannot handle sync*/async* functions
-mirrors/symbol_validation_test/none: RuntimeError # Please triage this failure.
+mirrors/parameter_annotation_mirror_test: Pass, Fail # Issue 25501.  Depends on inlining.
 
 [ $compiler == dart2js && $cps_ir && $host_checked ]
 mirrors/circular_factory_redirection_test/02: Crash # Assertion failure: Constant constructor already computed for generative_constructor(A#circular2)
@@ -352,7 +345,14 @@
 [ $compiler != dart2js ]
 async/dart2js_uncaught_error_test: Skip  # JS-integration only test
 
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt && $arch == simarm64 ]
+async/slow_consumer2_test: Pass, RuntimeError # Issue 25726
+
+[ $noopt || $compiler == precompiler ]
 mirrors/*: SkipByDesign
 convert/chunked_conversion_utf88_test: Pass, Timeout
 convert/utf85_test: Pass, Timeout
+
+[ $runtime == vm && $mode == product ]
+mirrors/mirrors_reader_test: Fail,OK  # Expects exact type name.
+
diff --git a/tests/lib/mirrors/constructor_optional_args_test.dart b/tests/lib/mirrors/constructor_optional_args_test.dart
new file mode 100644
index 0000000..f9d9657
--- /dev/null
+++ b/tests/lib/mirrors/constructor_optional_args_test.dart
@@ -0,0 +1,58 @@
+// 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 test.constructor_test;
+
+@MirrorsUsed(targets: const [A])
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class A {
+  factory A([x, y]) = B;
+  factory A.more([x, y]) = B.more;
+  factory A.oneMore(x, [y]) = B.more;
+}
+
+class B implements A {
+  final _x, _y, _z;
+
+  B([x = 'x', y = 'y']) : _x = x, _y = y, _z = null;
+
+  B.more([x = 'x', y = 'y', z = 'z']) : _x = x, _y = y, _z = z;
+
+  toString() => 'B(x=$_x, y=$_y, z=$_z)';
+}
+
+
+main() {
+  var d1 = new A(1);
+  Expect.equals('B(x=1, y=y, z=null)', '$d1', 'direct 1');
+
+  var d2 = new A.more(1);
+  Expect.equals('B(x=1, y=y, z=z)', '$d2', 'direct 2');
+
+  ClassMirror cm = reflectClass(A);
+
+  var v1 = cm.newInstance(const Symbol(''), []).reflectee;
+  var v2 = cm.newInstance(const Symbol(''), [1]).reflectee;
+  var v3 = cm.newInstance(const Symbol(''), [2, 3]).reflectee;
+
+  Expect.equals('B(x=x, y=y, z=null)', '$v1', 'unnamed 1');
+  Expect.equals('B(x=1, y=y, z=null)', '$v2', 'unnamed 2');
+  Expect.equals('B(x=2, y=3, z=null)', '$v3', 'unnamed 3');
+
+  var m1 = cm.newInstance(const Symbol('more'), []).reflectee;
+  var m2 = cm.newInstance(const Symbol('more'), [1]).reflectee;
+  var m3 = cm.newInstance(const Symbol('more'), [2, 3]).reflectee;
+
+  Expect.equals('B(x=x, y=y, z=z)', '$m1', 'more 1');
+  Expect.equals('B(x=1, y=y, z=z)', '$m2', 'more 2');
+  Expect.equals('B(x=2, y=3, z=z)', '$m3', 'more 3');
+
+  var o1 = cm.newInstance(const Symbol('oneMore'), [1]).reflectee;
+  var o2 = cm.newInstance(const Symbol('oneMore'), [2, 3]).reflectee;
+
+  Expect.equals('B(x=1, y=y, z=z)', '$o1', 'oneMore one arg');
+  Expect.equals('B(x=2, y=3, z=z)', '$o2', 'oneMore two args');
+}
diff --git a/tests/standalone/assert_assignable_canon_test.dart b/tests/standalone/assert_assignable_canon_test.dart
new file mode 100644
index 0000000..7c34328
--- /dev/null
+++ b/tests/standalone/assert_assignable_canon_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=--enable-inlining-annotations --optimization-counter-threshold=10 --no-background-compilation
+
+const AlwaysInline = "AlwaysInline";
+const NeverInline = "NeverInline";
+
+abstract class A<T extends A<T>> {
+  @AlwaysInline
+  f(x) => new R<T>(x);
+}
+
+class B extends A<B> {}
+
+class R<T> {
+  @AlwaysInline
+  R(T field);
+}
+
+class C extends B {}
+
+class D extends C {}
+
+// f will be inlined and T=B will be forwarded to AssertAssignable in the
+// R. However B will be wrapped in the TypeRef which breaks runtime TypeCheck
+// function (Instance::IsInstanceOf does not work for TypeRefs).
+@NeverInline
+f(o) => new B().f(o);
+
+main() {
+  final o = new D();
+  for (var i = 0; i < 10; i++) {
+    f(o);
+  }
+}
diff --git a/tests/standalone/fields_may_be_reset_test.dart b/tests/standalone/fields_may_be_reset_test.dart
new file mode 100644
index 0000000..3ab6fc6
--- /dev/null
+++ b/tests/standalone/fields_may_be_reset_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--fields_may_be_reset
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/full_coverage_test.dart b/tests/standalone/full_coverage_test.dart
index 9eab81d..e719d42 100644
--- a/tests/standalone/full_coverage_test.dart
+++ b/tests/standalone/full_coverage_test.dart
@@ -17,6 +17,9 @@
     Platform.script.resolve('../../tools/full-coverage.dart').toFilePath();
 final String packageRoot = Platform.packageRoot;
 final List dartBaseArgs = ['--package-root=${packageRoot}', '--checked',];
+final Stopwatch sw = new Stopwatch();
+
+int elapsed() => sw.elapsedMilliseconds;
 
 // With line numbers starting at 0, the list of hits can be understood as
 // follows:
@@ -88,13 +91,14 @@
 
 generateCoverage(String workingDirectory) {
   for (var coverageProg in coverageTests) {
+    print('[+${elapsed()}ms] Generating data for ${coverageProg["name"]}');
     var progPath = path.join(workingDirectory, coverageProg['name']);
     var script = path.join(progPath, "${coverageProg['name']}.dart");
     var dartArgs = new List.from(dartBaseArgs)
       ..addAll(['--coverage-dir=${progPath}', '${script}']);
     var result = Process.runSync(Platform.executable, dartArgs);
     if (result.exitCode != 0) {
-      print("Coverage generator returned exitCode: ${result.exitCode}.");
+      print("[+${elapsed()}ms] Got exitCode: ${result.exitCode}.");
       print("stderr:\n${result.stderr}\n");
       expect(result.exitCode, 0);
     }
@@ -212,6 +216,7 @@
 
 main() {
   String testingDirectory;
+  sw.start();
 
   setUp(() {
     testingDirectory = prepareEnv();
@@ -220,17 +225,23 @@
   tearDown(() => destroyEnv(testingDirectory));
 
   test('CoverageTests', () {
+    print('[+${elapsed()}ms] Generating coverage data...');
     generateCoverage(testingDirectory);
+    print('[+${elapsed()}ms] Done Generating coverage data.');
 
+    print('[+${elapsed()}ms] Running tests...');
     coverageTests.forEach((cTest) {
       String programDir = path.join(testingDirectory, cTest['name']);
       String programPath = path.join(programDir, "${cTest['name']}.dart");
+      print('[+${elapsed()}ms] Testing lcov for ${cTest["name"]}');
       testCoverage(programDir, programPath,
                    new LcovDescriptor(programPath),
                    new List.from(cTest['expectedHits']));
+      print('[+${elapsed()}ms] Testing pretty print for ${cTest["name"]}');
       testCoverage(programDir, programPath,
                    new PrettyPrintDescriptor(programPath),
                    new List.from(cTest['expectedHits']));
     });
+    print('[+${elapsed()}ms] Done.');
   });
 }
diff --git a/tests/standalone/io/certificates/README b/tests/standalone/io/certificates/README
index 1268432..6ecd518 100644
--- a/tests/standalone/io/certificates/README
+++ b/tests/standalone/io/certificates/README
@@ -8,6 +8,8 @@
 in a bash or sh shell, with the openssl tools installed.  Run the script
 twice to create the untrusted_* files.
 
+PEM files:
+
 server_chain.pem:
   Contains the chain of certificates, from the self-signed
 test certificate authority, through the intermediate CA, to the server
@@ -29,6 +31,40 @@
 to fail because the client does not accept this certificate authority
 
 untrusted_server_key.pem:
-  Contains the private key for the untrusted server certificate 
+  Contains the private key for the untrusted server certificate
 in untrusted_server_chain.pem
 
+*_malformed.pem:
+  Truncated PEM formatted certificates used to test error handling.
+
+PKCS12 files:
+
+server_key.12:
+  Created with:
+  $ openssl pkcs12 -export -inkey server_key.pem -out server_key.p12 -nocerts
+  with password 'dartdart'
+
+server_chain.p12:
+  Created with:
+  $ openssl pkcs12 -export -in server_chain.pem -out server_chain.p12 -nokeys
+  with password 'dartdart'
+
+client1_key.p12:
+  Created with:
+  $ openssl pkcs12 -export -inkey client1_key.pem -out client1_key.p12 -nocerts
+  with password 'dartdart'
+
+client1.p12:
+  Created with:
+  $ openssl pkcs12 -export -in client1.pem -out client1.p12 -nokeys
+  with password 'dartdart'
+
+trusted_certs.p12:
+  Created with:
+  $ openssl pkcs12 -export -in trusted_certs.pem -out trusted_certs.p12 -nokeys
+  with password 'dartdart'
+
+client_authority.p12:
+  Created with:
+  $ openssl pkcs12 -export -in client_authority.pem -out client_authority.p12 -nokeys
+  with password 'dartdart'
diff --git a/tests/standalone/io/certificates/client1.p12 b/tests/standalone/io/certificates/client1.p12
new file mode 100644
index 0000000..8d19d04
--- /dev/null
+++ b/tests/standalone/io/certificates/client1.p12
Binary files differ
diff --git a/tests/standalone/io/certificates/client1_key.p12 b/tests/standalone/io/certificates/client1_key.p12
new file mode 100644
index 0000000..d9cf05b
--- /dev/null
+++ b/tests/standalone/io/certificates/client1_key.p12
Binary files differ
diff --git a/tests/standalone/io/certificates/client1_key_malformed.pem b/tests/standalone/io/certificates/client1_key_malformed.pem
new file mode 100644
index 0000000..33a79bf
--- /dev/null
+++ b/tests/standalone/io/certificates/client1_key_malformed.pem
@@ -0,0 +1,18 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE4jAcBgoqhkiG9w0BDAEBMA4ECF4ZB27y60SWAgIIAASCBMCEL3ZCzfC0q+m+
+B8gM9jQe1JFRD5reAuwK6+3speBS4KE+wjbcyQq09/5UoQu3Dci1WG1nKLB1u0Bk
+w9NuRahWCpvVLzz/GQ6Psesixq3V69zD3N6iMl/XQKymQBwGK51xIkeJO+6Skh2d
++qoyBHINTlKY9+548Zgqu+Z3mI3pGmdhd7hCiamiffDwCLEqRxbXdZdLpC9GpAP5
+HOqXHzN2aZbAGHb1GkHVxskSNzAwlEEZhh4Ibe6o7U65hoL9borewT+gj6sQohI5
+/LHL0P2bVvtRZiwBVPUX8HZWuVYIFb6GEGTTqOofNhNHvHaKUlD8Uxi5/h/Xi8fq
+xpdkjIn7VXj9e+I3TkfiphDtk0+Q+f+UkuPyuzU1PafinPfRK1J6gk+ZqAQHW/sp
+g6GVr2r4PkOrBPsA6jmCnQhs2C4MlZyR2p65qjVutdkKU5NgftW+giK9shgglcza
+38RF8i01THOnD3j+2teM/t/Ziqb2PGWv/bmvhcYqt1aG186Pe3bBCxhh/L7bqNKD
+q7sxDmaDE2pTkfyvh07udarmBQc5gvfXYqwghbqP/n7wizqjeEJgAwwHyi8LLsFV
+XreBQ/8Z2gQwXurrh5WD+7KSgvgopW/oVC8a3++8Hmf5Nkj27lACzoDWTG2/Swah
+O1MmdtPyy/KCbf5ujt2BlXM9D206Rsr6hoO9UZ1s1ohRdJReVGc4NZ4XrVWc4TKT
+gUAFTaHIKgFe/DgLaQn8L8Pqb8B/JfoSgQ74r69S434Kc+EDKui8wnkgso5bqrr1
+M07H9Xo+OtG1D6rma2EUlpoU06CAIcyqNx5fHJ3xfk9GHScQi4U6vEDCAQTNTS65
+I5AOHthZ2kZzfXvP6TF39S5D37NrV7/WJu7ZFaJx3bUGwnS2HYTwjFPABHpVLMwJ
+nBylVJs+h7bCZdBNCWgTytcn1mYMCvXVmrW8VTwBRjUQsy4rgE2wjpZuIM9rx+gZ
+HtNvy5t2RlOSqVKapyvV0ll7qbT1lwGIePxjttiWmNbgbwRBQzjv6FZ1Yo331Fl4
diff --git a/tests/standalone/io/certificates/client_authority.p12 b/tests/standalone/io/certificates/client_authority.p12
new file mode 100644
index 0000000..545282e
--- /dev/null
+++ b/tests/standalone/io/certificates/client_authority.p12
Binary files differ
diff --git a/tests/standalone/io/certificates/client_authority_malformed.pem b/tests/standalone/io/certificates/client_authority_malformed.pem
new file mode 100644
index 0000000..d206dce3
--- /dev/null
+++ b/tests/standalone/io/certificates/client_authority_malformed.pem
@@ -0,0 +1,9 @@
+-----BEGIN CERTIFICATE-----
+MIIDKjCCAhKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9jbGll
+bnRhdXRob3JpdHkwHhcNMTUxMDI3MTAyNjM1WhcNMjUxMDI0MTAyNjM1WjAaMRgw
+FgYDVQQDEw9jbGllbnRhdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCi6wJAs6nppNmTZ3e/wE9l0pAmkMtDONwB9o115XXTG3rmSKfZOxa8
+TFjSn818Pr1OYb9fPdI1Y6x4WY9PELUtQyEBlNcKjwg96vhrP4p2DhqbWsI5nASH
+DSjJsM75bQ7D7qHYzriuAl0Fk1C4LcodRj+5wmErMtvGJG0x06qFbxCCMAJ2kC+h
+SneTN955/YHSXADgxjFlt3s1T0QPnqrr+G7Ro6PrVKLPBulglq7wAeTwrGkPRUt0
+3lDGOSi6i97NbpiXwrGp5XiLUtVCiID6Ro0xKWH4sjJ4JnVjIUG8CQWERc6sFDJM
diff --git a/tests/standalone/io/certificates/server_chain.p12 b/tests/standalone/io/certificates/server_chain.p12
new file mode 100644
index 0000000..1e8c66d
--- /dev/null
+++ b/tests/standalone/io/certificates/server_chain.p12
Binary files differ
diff --git a/tests/standalone/io/certificates/server_chain_malformed1.pem b/tests/standalone/io/certificates/server_chain_malformed1.pem
new file mode 100644
index 0000000..cbbeb55
--- /dev/null
+++ b/tests/standalone/io/certificates/server_chain_malformed1.pem
@@ -0,0 +1,7 @@
+-----BEGIN CERTIFICATE-----
+MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
+cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDI3MTAyNjM1WhcNMjUxMDI0MTAyNjM1
+WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCkg/Qr8RQeLTOSgCkyiEX2ztgkgscX8hKGHEHdvlkmVK3JVEIIwkvu
+/Y9LtHZUia3nPAgqEEbexzTENZjSCcC0V6I2XW/e5tIE3rO0KLZyhtZhN/2SfJ6p
+KbOh0HLr1VtkKJGp1tzUmHW/aZI32pK60ZJ/N917NLPCJpCaL8+wHo3+w3oNqln6
diff --git a/tests/standalone/io/certificates/server_chain_malformed2.pem b/tests/standalone/io/certificates/server_chain_malformed2.pem
new file mode 100644
index 0000000..2c99e78
--- /dev/null
+++ b/tests/standalone/io/certificates/server_chain_malformed2.pem
@@ -0,0 +1,42 @@
+-----BEGIN CERTIFICATE-----
+MIIDZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVpbnRl
+cm1lZGlhdGVhdXRob3JpdHkwHhcNMTUxMDI3MTAyNjM1WhcNMjUxMDI0MTAyNjM1
+WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCkg/Qr8RQeLTOSgCkyiEX2ztgkgscX8hKGHEHdvlkmVK3JVEIIwkvu
+/Y9LtHZUia3nPAgqEEbexzTENZjSCcC0V6I2XW/e5tIE3rO0KLZyhtZhN/2SfJ6p
+KbOh0HLr1VtkKJGp1tzUmHW/aZI32pK60ZJ/N917NLPCJpCaL8+wHo3+w3oNqln6
+oJsfgxy9SUM8Bsc9WMYKMUdqLO1QKs1A5YwqZuO7Mwj+4LY2QDixC7Ua7V9YAPo2
+1SBeLvMCHbYxSPCuxcZ/kDkgax/DF9u7aZnGhMImkwBka0OQFvpfjKtTIuoobTpe
+PAG7MQYXk4RjnjdyEX/9XAQzvNo1CDObAgMBAAGjgbQwgbEwPAYDVR0RBDUwM4IJ
+bG9jYWxob3N0ggkxMjcuMC4wLjGCAzo6MYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAA
+ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSvhJo6taTggJQBukEvMo/PDk8tKTAf
+BgNVHSMEGDAWgBS98L4T5RaIToE3DkBRsoeWPil0eDAOBgNVHQ8BAf8EBAMCA6gw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAHLOt0mL2S4A
+B7vN7KsfQeGlVgZUVlEjem6kqBh4fIzl4CsQuOO8oJ0FlO1z5JAIo98hZinymJx1
+phBVpyGIKakT/etMH0op5evLe9dD36VA3IM/FEv5ibk35iGnPokiJXIAcdHd1zam
+YaTHRAnZET5S03+7BgRTKoRuszhbvuFz/vKXaIAnVNOF4Gf2NUJ/Ax7ssJtRkN+5
+UVxe8TZVxzgiRv1uF6NTr+J8PDepkHCbJ6zEQNudcFKAuC56DN1vUe06gRDrNbVq
+2JHEh4pRfMpdsPCrS5YHBjVq/XHtFHgwDR6g0WTwSUJvDeM4OPQY5f61FB0JbFza
+PkLkXmoIod8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDLjCCAhagAwIBAgIBAjANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAyNzEwMjYzNVoXDTI1MTAyNDEwMjYzNVowIDEeMBwG
+A1UEAwwVaW50ZXJtZWRpYXRlYXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA6GndRFiXk+2q+Ig7ZOWKKGta+is8137qyXz+eVFs5sA0ajMN
+ZBAMWS0TIXw/Yks+y6fEcV/tfv91k1eUN4YXPcoxTdDF97d2hO9wxumeYOMnQeDy
+VZVDKQBZ+jFMeI+VkNpMEdmsLErpZDGob/1dC8tLEuR6RuRR8X6IDGMPOCMw1jLK
+V1bQjPtzqKadTscfjLuKxuLgspJdTrzsu6hdcl1mm8K6CjTY2HNXWxs1yYmwfuQ2
+Z4/8sOMNqFqLjN+ChD7pksTMq7IosqGiJzi2bpd5f44ek/k822Y0ATncJHk4h1Z+
+kZBnW6kgcLna1gDri9heRwSZ+M8T8nlHgIMZIQIDAQABo3sweTASBgNVHRMBAf8E
+CDAGAQH/AgEAMB0GA1UdDgQWBBS98L4T5RaIToE3DkBRsoeWPil0eDAfBgNVHSME
+GDAWgBRxD5DQHTmtpDFKDOiMf5FAi6vfbzAOBgNVHQ8BAf8EBAMCAgQwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEBAD+4KpUeV5mUPw5IG/7w
+eOXnUpeS96XFGuS1JuFo/TbgntPWSPyo+rD4GrPIkUXyoHaMCDd2UBEjyGbBIKlB
+NZA3RJOAEp7DTkLNK4RFn/OEcLwG0J5brL7kaLRO4vwvItVIdZ2XIqzypRQTc0MG
+MmF08zycnSlaN01ryM67AsMhwdHqVa+uXQPo8R8sdFGnZ33yywTYD73FeImXilQ2
+rDnFUVqmrW1fjl0Fi4rV5XI0EQiPrzKvRtmF8ZqjGATPOsRd64cwQX6V+P5hNeIR
+9pba6td7AbNGausHfacRYMyoGJWWWkFPd+7jWOCPqW7Fk1tmBgdB8GzXa3inWIRM
+RUE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
diff --git a/tests/standalone/io/certificates/server_key.p12 b/tests/standalone/io/certificates/server_key.p12
new file mode 100644
index 0000000..2434fb7
--- /dev/null
+++ b/tests/standalone/io/certificates/server_key.p12
Binary files differ
diff --git a/tests/standalone/io/certificates/trusted_certs.p12 b/tests/standalone/io/certificates/trusted_certs.p12
new file mode 100644
index 0000000..167f2e8
--- /dev/null
+++ b/tests/standalone/io/certificates/trusted_certs.p12
Binary files differ
diff --git a/tests/standalone/io/certificates/trusted_certs_malformed.pem b/tests/standalone/io/certificates/trusted_certs_malformed.pem
new file mode 100644
index 0000000..ea26cc7
--- /dev/null
+++ b/tests/standalone/io/certificates/trusted_certs_malformed.pem
@@ -0,0 +1,8 @@
+-----BEGIN CERTIFICATE-----
+MIIC+zCCAeOgAwIBAgIBATANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1yb290
+YXV0aG9yaXR5MB4XDTE1MTAyNzEwMjYzNFoXDTI1MTAyNDEwMjYzNFowGDEWMBQG
+A1UEAwwNcm9vdGF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMl+dcraUM/E7E6zl7+7hK9oUJYXJLnfiMtP/TRFVbH4+2aEN8vXzPbzKdR3
+FfaHczXQTwnTCaYA4u4uSDvSOsFFEfxEwYORsdKmQEM8nGpVX2NVvKsMcGIhh8kh
+ZwJfkMIOcAxmGIHGdMhF8VghonJ8uGiuqktxdfpARq0g3fqIjDHsF9/LpfshUfk9
+wsRyTF0yr90U/dsfnE+u8l7GvVl8j2Zegp0sagAGtLaNv7tP17AibqEGg2yDBrBN
diff --git a/tests/standalone/io/http_proxy_advanced_test.dart b/tests/standalone/io/http_proxy_advanced_test.dart
index aeafaf0..1d2e585 100644
--- a/tests/standalone/io/http_proxy_advanced_test.dart
+++ b/tests/standalone/io/http_proxy_advanced_test.dart
@@ -17,7 +17,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 e5607e9..e2505f3 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -17,7 +17,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 fdd83e3..90c630f 100644
--- a/tests/standalone/io/https_bad_certificate_test.dart
+++ b/tests/standalone/io/https_bad_certificate_test.dart
@@ -16,7 +16,7 @@
 SecurityContext serverContext = new SecurityContext()
   ..useCertificateChain(localFile('certificates/server_chain.pem'))
   ..usePrivateKey(localFile('certificates/server_key.pem'),
-      password: 'dartdart');
+                  password: 'dartdart');
 
 class CustomException {}
 
@@ -31,7 +31,7 @@
   });
 
   SecurityContext goodContext = new SecurityContext()
-    ..setTrustedCertificates(file: 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 24d3978..dc11a45 100644
--- a/tests/standalone/io/https_client_certificate_test.dart
+++ b/tests/standalone/io/https_client_certificate_test.dart
@@ -19,7 +19,7 @@
 // TODO: Specify which client certificate roots to trust.
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'))
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'))
 // TODO: Set a client certificate here.
   ..useCertificateChain(localFile('certificates/server_chain.pem'))
   ..usePrivateKey(localFile('certificates/server_key.pem'),
diff --git a/tests/standalone/io/https_server_test.dart b/tests/standalone/io/https_server_test.dart
index 88a8b2a..3f9bc52 100644
--- a/tests/standalone/io/https_server_test.dart
+++ b/tests/standalone/io/https_server_test.dart
@@ -18,7 +18,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 43f3e53..a556626 100644
--- a/tests/standalone/io/https_unauthorized_test.dart
+++ b/tests/standalone/io/https_unauthorized_test.dart
@@ -21,7 +21,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 63e9cd4..e6c084a 100644
--- a/tests/standalone/io/raw_secure_server_closing_test.dart
+++ b/tests/standalone/io/raw_secure_server_closing_test.dart
@@ -22,7 +22,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 560722f..ba34bed 100644
--- a/tests/standalone/io/raw_secure_server_socket_test.dart
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -22,7 +22,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 void testSimpleBind() {
   asyncStart();
diff --git a/tests/standalone/io/raw_secure_socket_pause_test.dart b/tests/standalone/io/raw_secure_socket_pause_test.dart
index c3bfc43..0073cda 100644
--- a/tests/standalone/io/raw_secure_socket_pause_test.dart
+++ b/tests/standalone/io/raw_secure_socket_pause_test.dart
@@ -21,7 +21,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 9cd54a1..df3994e 100644
--- a/tests/standalone/io/raw_secure_socket_test.dart
+++ b/tests/standalone/io/raw_secure_socket_test.dart
@@ -21,7 +21,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 95ccfca..b3d39f1 100644
--- a/tests/standalone/io/regress_21160_test.dart
+++ b/tests/standalone/io/regress_21160_test.dart
@@ -18,7 +18,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 6a7e93a..610bcdb 100644
--- a/tests/standalone/io/secure_bad_certificate_test.dart
+++ b/tests/standalone/io/secure_bad_certificate_test.dart
@@ -16,7 +16,7 @@
 SecurityContext serverContext = new SecurityContext()
   ..useCertificateChain(localFile('certificates/server_chain.pem'))
   ..usePrivateKey(localFile('certificates/server_key.pem'),
-      password: 'dartdart');
+                  password: 'dartdart');
 
 class CustomException {}
 
@@ -30,7 +30,7 @@
     }, onError: (e) { if (e is! HandshakeException) throw e; });
 
   SecurityContext goodContext = new SecurityContext()
-    ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+    ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
   SecurityContext badContext = new SecurityContext();
   SecurityContext defaultContext = SecurityContext.defaultContext;
 
@@ -81,4 +81,4 @@
       Expect.fail('Unknown expectation $result');
     }
   }
-}
\ No newline at end of file
+}
diff --git a/tests/standalone/io/secure_client_raw_server_test.dart b/tests/standalone/io/secure_client_raw_server_test.dart
index 318edeb..e8cb63d 100644
--- a/tests/standalone/io/secure_client_raw_server_test.dart
+++ b/tests/standalone/io/secure_client_raw_server_test.dart
@@ -21,7 +21,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 b4f3db14..4d928ef 100644
--- a/tests/standalone/io/secure_client_server_test.dart
+++ b/tests/standalone/io/secure_client_server_test.dart
@@ -23,7 +23,8 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(
+      localFile('certificates/trusted_certs.pem'));
 
 
 Future<SecureServerSocket> startEchoServer() {
diff --git a/tests/standalone/io/secure_multiple_client_server_test.dart b/tests/standalone/io/secure_multiple_client_server_test.dart
index 586105d..a0577df 100644
--- a/tests/standalone/io/secure_multiple_client_server_test.dart
+++ b/tests/standalone/io/secure_multiple_client_server_test.dart
@@ -24,7 +24,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 c104dba..6891037 100644
--- a/tests/standalone/io/secure_server_client_certificate_test.dart
+++ b/tests/standalone/io/secure_server_client_certificate_test.dart
@@ -12,26 +12,40 @@
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
-SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChain(localFile('certificates/server_chain.pem'))
-  ..usePrivateKey(localFile('certificates/server_key.pem'),
-      password: 'dartdart')
-  ..setTrustedCertificates(file: localFile('certificates/client_authority.pem'))
-  ..setClientAuthorities(localFile('certificates/client_authority.pem'));
+SecurityContext serverContext(String certType, String password) =>
+  new SecurityContext()
+  ..useCertificateChain(localFile(
+      'certificates/server_chain.$certType'), password: password)
+  ..usePrivateKey(localFile(
+      'certificates/server_key.$certType'), password: password)
+  ..setTrustedCertificates(localFile(
+      'certificates/client_authority.$certType'), password: password)
+  ..setClientAuthorities(localFile(
+      'certificates/client_authority.$certType'), password: password);
 
-SecurityContext clientCertContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'))
-  ..useCertificateChain(localFile('certificates/client1.pem'))
-  ..usePrivateKey(localFile('certificates/client1_key.pem'),
-      password: 'dartdart');
+SecurityContext clientCertContext(String certType, String password) =>
+  new SecurityContext()
+  ..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 = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+SecurityContext clientNoCertContext(String certType, String password) =>
+  new SecurityContext()
+  ..setTrustedCertificates(localFile(
+      'certificates/trusted_certs.$certType'), password: password);
 
-Future testClientCertificate({bool required, bool sendCert}) async {
-  var server = await SecureServerSocket.bind(HOST, 0, serverContext,
-      requestClientCertificate: true, requireClientCertificate: required);
-  var clientContext = sendCert ? clientCertContext : clientNoCertContext;
+Future testClientCertificate(
+    {bool required, bool sendCert, String certType, String password}) async {
+  var server = await SecureServerSocket.bind(HOST, 0,
+      serverContext(certType, password),
+      requestClientCertificate: true,
+      requireClientCertificate: required);
+  var clientContext = sendCert ?
+      clientCertContext(certType, password) :
+      clientNoCertContext(certType, password);
   var clientEndFuture =
       SecureSocket.connect(HOST, server.port, context: clientContext);
   if (required && !sendCert) {
@@ -68,9 +82,22 @@
 main() async {
   asyncStart();
   HOST = (await InternetAddress.lookup("localhost")).first;
-  await testClientCertificate(required: false, sendCert: true);
-  await testClientCertificate(required: true, sendCert: true);
-  await testClientCertificate(required: false, sendCert: false);
-  await testClientCertificate(required: true, sendCert: false);
+  await testClientCertificate(
+      required: false, sendCert: true, certType: 'pem', password: 'dartdart');
+  await testClientCertificate(
+      required: true, sendCert: true, certType: 'pem', password: 'dartdart');
+  await testClientCertificate(
+      required: false, sendCert: false, certType: 'pem', password: 'dartdart');
+  await testClientCertificate(
+      required: true, sendCert: false, certType: 'pem', password: 'dartdart');
+
+  await testClientCertificate(
+      required: false, sendCert: true, certType: 'p12', password: 'dartdart');
+  await testClientCertificate(
+      required: true, sendCert: true, certType: 'p12', password: 'dartdart');
+  await testClientCertificate(
+      required: false, sendCert: false, certType: 'p12', password: 'dartdart');
+  await testClientCertificate(
+      required: true, sendCert: false, certType: 'p12', password: 'dartdart');
   asyncEnd();
 }
diff --git a/tests/standalone/io/secure_server_closing_test.dart b/tests/standalone/io/secure_server_closing_test.dart
index 0677a41..159c6ae4 100644
--- a/tests/standalone/io/secure_server_closing_test.dart
+++ b/tests/standalone/io/secure_server_closing_test.dart
@@ -23,7 +23,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 6ef7f27..d3e2d1c 100644
--- a/tests/standalone/io/secure_server_socket_test.dart
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -23,7 +23,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 8ec99a4..15f2b0b 100644
--- a/tests/standalone/io/secure_session_resume_test.dart
+++ b/tests/standalone/io/secure_session_resume_test.dart
@@ -33,7 +33,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 3ad9112..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()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 SecurityContext serverContext() => new SecurityContext()
   ..useCertificateChain(localFile('certificates/server_chain.pem'))
   ..usePrivateKey(localFile('certificates/server_key.pem'),
-                    password: 'dartdart');
+                  password: 'dartdart');
 
 // Tests that client/server with same protocol can securely establish a
 // connection, negotiate the protocol and can send data to each other.
@@ -67,7 +67,7 @@
 }
 
 void testInvalidArgumentServerContext(List<String> protocols,
-                                      String errorIncludes) { 
+                                      String errorIncludes) {
   Expect.throws(() => serverContext().setAlpnProtocols(protocols, true), (e) {
     Expect.isTrue(e is ArgumentError);
     Expect.isTrue(e.toString().contains(errorIncludes));
@@ -76,7 +76,7 @@
 }
 
 void testInvalidArgumentClientContext(List<String> protocols,
-                                      String errorIncludes) { 
+                                      String errorIncludes) {
   Expect.throws(() => clientContext().setAlpnProtocols(protocols, false), (e) {
     Expect.isTrue(e is ArgumentError);
     Expect.isTrue(e.toString().contains(errorIncludes));
diff --git a/tests/standalone/io/secure_socket_renegotiate_client.dart b/tests/standalone/io/secure_socket_renegotiate_client.dart
index d277012..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()
-  ..setTrustedCertificates(file: 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_test.dart b/tests/standalone/io/secure_socket_test.dart
index 897bd84..1566b5a 100644
--- a/tests/standalone/io/secure_socket_test.dart
+++ b/tests/standalone/io/secure_socket_test.dart
@@ -7,6 +7,7 @@
 // VMOptions=--short_socket_write
 // VMOptions=--short_socket_read --short_socket_write
 
+import "package:async_helper/async_helper.dart";
 import "package:expect/expect.dart";
 import "package:path/path.dart";
 import "dart:async";
@@ -14,19 +15,23 @@
 
 String localFile(path) => Platform.script.resolve(path).toFilePath();
 
-SecurityContext serverContext = new SecurityContext()
-  ..useCertificateChain(localFile('certificates/server_chain.pem'))
-  ..usePrivateKey(localFile('certificates/server_key.pem'),
-                  password: 'dartdart');
+SecurityContext serverContext(String certType, String password) =>
+    new SecurityContext()
+    ..useCertificateChain(localFile('certificates/server_chain.$certType'),
+                          password: password)
+    ..usePrivateKey(localFile('certificates/server_key.$certType'),
+                    password: password);
 
-SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+SecurityContext clientContext(String certType, String password) =>
+    new SecurityContext()
+    ..setTrustedCertificates(localFile('certificates/trusted_certs.$certType'),
+                             password: password);
 
-Future<HttpServer> startServer() {
+Future<HttpServer> startServer(String certType, String password) {
   return HttpServer.bindSecure(
       "localhost",
       0,
-      serverContext,
+      serverContext(certType, password),
       backlog: 5).then((server) {
     server.listen((HttpRequest request) {
       request.listen(
@@ -43,10 +48,11 @@
   });
 }
 
-void main() {
+Future test(String certType, String password) {
   List<int> body = <int>[];
-  startServer().then((server) {
-    SecureSocket.connect("localhost", server.port, context: clientContext)
+  startServer(certType, password).then((server) {
+    SecureSocket.connect(
+        "localhost", server.port, context: clientContext(certType, password))
     .then((socket) {
       socket.write("GET / HTTP/1.0\r\nHost: localhost\r\n\r\n");
       socket.close();
@@ -68,3 +74,10 @@
     });
   });
 }
+
+main() async {
+  asyncStart();
+  await test('pem', 'dartdart');
+  await test('p12', 'dartdart');
+  asyncEnd();
+}
diff --git a/tests/standalone/io/secure_unauthorized_client.dart b/tests/standalone/io/secure_unauthorized_client.dart
index 8677bec..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()
-  ..setTrustedCertificates(file: localFile('certificates/trusted_certs.pem'));
+  ..setTrustedCertificates(localFile('certificates/trusted_certs.pem'));
 
 class ExpectException implements Exception {
   ExpectException(this.message);
diff --git a/tests/standalone/io/security_context_argument_test.dart b/tests/standalone/io/security_context_argument_test.dart
index 5e263f6..e5332ac 100644
--- a/tests/standalone/io/security_context_argument_test.dart
+++ b/tests/standalone/io/security_context_argument_test.dart
@@ -10,31 +10,116 @@
 bool printException(e) { print(e); return true; }
 bool argumentError(e) => e is ArgumentError;
 bool argumentOrTypeError(e) => e is ArgumentError || e is TypeError;
+bool fileSystemException(e) => e is FileSystemException;
 bool tlsException(e) => e is TlsException;
 
 void testUsePrivateKeyArguments() {
     var c = new SecurityContext();
     c.useCertificateChain(localFile('certificates/server_chain.pem'));
+
+    // Wrong password.
     Expect.throws(() => c.usePrivateKey(
-          localFile('certificates/server_key.pem'), password: "dart" * 1000),
+        localFile('certificates/server_key.pem')),
+        tlsException);
+    Expect.throws(() => c.usePrivateKey(
+        localFile('certificates/server_key.pem'), password: "iHackSites"),
+        tlsException);
+    Expect.throws(() => c.usePrivateKey(
+        localFile('certificates/server_key.p12')),
+        tlsException);
+    Expect.throws(() => c.usePrivateKey(
+        localFile('certificates/server_key.p12'), password: "iHackSites"),
+        tlsException);
+    Expect.throws(() => c.setTrustedCertificates(
+        localFile('certificates/server_key.p12')),
+        tlsException);
+    Expect.throws(() => c.setTrustedCertificates(
+        localFile('certificates/server_key.p12'), password: "iHackSites"),
+        tlsException);
+    Expect.throws(() => c.useCertificateChain(
+        localFile('certificates/server_key.p12')),
+        tlsException);
+    Expect.throws(() => c.useCertificateChain(
+        localFile('certificates/server_key.p12'), password: "iHackSites"),
+        tlsException);
+    Expect.throws(() => c.setClientAuthorities(
+        localFile('certificates/server_key.p12')),
         argumentError);
+    Expect.throws(() => c.setClientAuthorities(
+        localFile('certificates/server_key.p12'), password: "iHackSites"),
+        argumentError);
+
+    // File does not exist
     Expect.throws(() => c.usePrivateKey(
-          localFile('certificates/server_key.pem')),
-        tlsException);
-    Expect.throws(() => c.usePrivateKey(
-          localFile('certificates/server_key.pem'), password: "iHackSites"),
-        tlsException);
-    Expect.throws(() => c.usePrivateKey(
-          localFile('certificates/server_key_oops.pem'), password: "dartdart"),
-        tlsException);
+        localFile('certificates/server_key_oops.pem'),
+                  password: "dartdart"),
+        fileSystemException);
+
+    // Wrong type for file name or data
     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.usePrivateKey(
-          localFile('certificates/server_key_oops.pem'), password: 3),
+        localFile('certificates/server_key.pem'), password: "dart" * 1000),
+        argumentError);
+    Expect.throws(() => c.usePrivateKey(
+        localFile('certificates/server_key.p12'), password: "dart" * 1000),
         argumentOrTypeError);
+    Expect.throws(() => c.setTrustedCertificates(
+        localFile('certificates/server_key.p12'), password: "dart" * 1000),
+        argumentOrTypeError);
+    Expect.throws(() => c.useCertificateChain(
+        localFile('certificates/server_key.p12'), password: "dart" * 1000),
+        argumentOrTypeError);
+    Expect.throws(() => c.setClientAuthorities(
+        localFile('certificates/server_key.p12'), password: "dart" * 1000),
+        argumentOrTypeError);
+
+    // Bad password type.
+    Expect.throws(() => c.usePrivateKey(
+        localFile('certificates/server_key.pem'), password: 3),
+        argumentOrTypeError);
+    Expect.throws(() => c.setTrustedCertificatesBytes(
+        localFile('certificates/server_key.pem'), password: 3),
+        argumentOrTypeError);
+    Expect.throws(() => c.useCertificateChainBytes(
+        localFile('certificates/server_key.pem'), password: 3),
+        argumentOrTypeError);
+    Expect.throws(() => c.setClientAuthoritiesBytes(
+        localFile('certificates/server_key.pem'), password: 3),
+        argumentOrTypeError);
+
+    // Empty data.
+    Expect.throws(() => c.usePrivateKeyBytes([], password: 'dartdart'),
+        tlsException);
+    Expect.throws(() => c.setTrustedCertificatesBytes([]), tlsException);
+    Expect.throws(() => c.useCertificateChainBytes([]), tlsException);
+    Expect.throws(() => c.setClientAuthoritiesBytes([]), argumentError);
+
+    // Malformed PEM certs.
+    Expect.throws(() => c.usePrivateKey(
+        localFile('certificates/client1_key_malformed.pem'),
+        password: "dartdart"),
+        tlsException);
+    Expect.throws(() => c.setTrustedCertificates(
+        localFile('certificates/trusted_certs_malformed.pem')),
+        tlsException);
+    Expect.throws(() => c.useCertificateChain(
+        localFile('certificates/server_chain_malformed1.pem')),
+        tlsException);
+    Expect.throws(() => c.useCertificateChain(
+        localFile('certificates/server_chain_malformed2.pem')),
+        tlsException);
+    Expect.throws(() => c.setClientAuthorities(
+        localFile('certificates/client_authority_malformed.pem')),
+        argumentError);
+
     c.usePrivateKey(
         localFile('certificates/server_key.pem'), password: "dartdart");
-}    
+}
 
 void main() {
   testUsePrivateKeyArguments();
diff --git a/tests/standalone/io/sleep_test.dart b/tests/standalone/io/sleep_test.dart
index 795de81..91c6625 100644
--- a/tests/standalone/io/sleep_test.dart
+++ b/tests/standalone/io/sleep_test.dart
@@ -2,15 +2,15 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import "package:expect/expect.dart";
 import "dart:io";
+import "package:unittest/unittest.dart";
 
 test(int milliseconds) {
   var watch = new Stopwatch();
   watch.start();
   sleep(new Duration(milliseconds: milliseconds));
   watch.stop();
-  Expect.isTrue(watch.elapsedMilliseconds + 1 >= milliseconds);
+  expect(watch.elapsedMilliseconds, greaterThanOrEqualTo(milliseconds));
 }
 
 main() {
@@ -18,6 +18,12 @@
   test(1);
   test(10);
   test(100);
-  Expect.throws(() => sleep(new Duration(milliseconds: -1)),
-                (e) => e is ArgumentError);
+  bool sawError = false;
+  try {
+    sleep(new Duration(milliseconds: -1));
+    expect(false, isTrue);  // should not reach here.
+  } on ArgumentError catch(e) {
+    sawError = true;
+  }
+  expect(sawError, isTrue);
 }
diff --git a/tests/standalone/io/socket_upgrade_to_secure_test.dart b/tests/standalone/io/socket_upgrade_to_secure_test.dart
index 5873d00..b4c862b 100644
--- a/tests/standalone/io/socket_upgrade_to_secure_test.dart
+++ b/tests/standalone/io/socket_upgrade_to_secure_test.dart
@@ -15,6 +15,7 @@
 
 InternetAddress HOST;
 String localFile(path) => Platform.script.resolve(path).toFilePath();
+List<int> readLocalFile(path) => (new File(localFile(path))).readAsBytesSync();
 
 SecurityContext serverContext = new SecurityContext()
   ..useCertificateChain(localFile('certificates/server_chain.pem'))
@@ -22,7 +23,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 912b855..e25bc1b 100644
--- a/tests/standalone/io/web_socket_compression_test.dart
+++ b/tests/standalone/io/web_socket_compression_test.dart
@@ -130,6 +130,43 @@
     });
   }
 
+  void testContextSupport({CompressionOptions serverOpts,
+    CompressionOptions clientOpts,
+    int messages}) {
+    asyncStart();
+
+    createServer().then((server) {
+      server.listen((request) {
+        Expect.isTrue(WebSocketTransformer.isUpgradeRequest(request));
+        WebSocketTransformer.upgrade(request, compression: serverOpts)
+                            .then((webSocket) {
+            webSocket.listen((message) {
+              Expect.equals("Hello World", message);
+              webSocket.add(message);
+            });
+        });
+      });
+
+      var url = '${secure ? "wss" : "ws"}://$HOST_NAME:${server.port}/';
+      WebSocket.connect(url, compression: clientOpts).then((websocket) {
+        var i = 1;
+        websocket.listen((message) {
+          Expect.equals("Hello World", message);
+          if (i == messages) {
+            websocket.close();
+            return;
+          }
+          websocket.add("Hello World");
+          i++;
+        }, onDone: () {
+          server.close();
+          asyncEnd();
+        });
+        websocket.add("Hello World");
+      });
+    });
+  }
+
   void testCompressionHeaders() {
     asyncStart();
     createServer().then((server) {
@@ -271,6 +308,31 @@
     // Compression on server but not client.
     testCompressionSupport(server: true);
 
+    // Test Multiple messages with various context takeover configurations.
+    // no context takeover on the server.
+    var serverComp = new CompressionOptions(serverNoContextTakeover: true);
+    testContextSupport(serverOpts: serverComp,
+      clientOpts: serverComp,
+      messages: 5);
+    // no contexttakeover on the client.
+    var clientComp = new CompressionOptions(clientNoContextTakeover: true);
+    testContextSupport(serverOpts: clientComp,
+      clientOpts: clientComp,
+      messages: 5);
+    // no context takeover enabled for both.
+    var compression = new CompressionOptions(serverNoContextTakeover: true,
+                      clientNoContextTakeover: true);
+    testContextSupport(serverOpts: compression,
+      clientOpts: compression,
+      messages: 5);
+    // no context take over for opposing configurations.
+    testContextSupport(serverOpts: serverComp,
+      clientOpts: clientComp,
+      messages: 5);
+    testContextSupport(serverOpts: clientComp,
+      clientOpts: serverComp,
+      messages: 5);
+
     testCompressionHeaders();
     // Chrome headers
     testReturnHeaders('permessage-deflate; client_max_window_bits',
@@ -289,7 +351,7 @@
                       'client_no_context_takeover',
                       'permessage-deflate; client_max_window_bits=15');
     // Enable context Takeover and provide if requested.
-    var compression = new CompressionOptions(clientNoContextTakeover: true,
+    compression = new CompressionOptions(clientNoContextTakeover: true,
         serverNoContextTakeover: true);
     testReturnHeaders('permessage-deflate; client_max_window_bits; '
                       'client_no_context_takeover',
diff --git a/tests/standalone/io/web_socket_error_test.dart b/tests/standalone/io/web_socket_error_test.dart
index cc16bde..42b93d4 100644
--- a/tests/standalone/io/web_socket_error_test.dart
+++ b/tests/standalone/io/web_socket_error_test.dart
@@ -33,7 +33,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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 695b2cd..f7ff673 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -29,7 +29,7 @@
                   password: 'dartdart');
 
 SecurityContext clientContext = new SecurityContext()
-  ..setTrustedCertificates(file: 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/javascript_compatibility_errors_test.dart b/tests/standalone/javascript_compatibility_errors_test.dart
deleted file mode 100644
index 6404a2e..0000000
--- a/tests/standalone/javascript_compatibility_errors_test.dart
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--warn_on_javascript_compatibility --warning_as_error --optimization_counter_threshold=5
-
-import "package:expect/expect.dart";
-
-f(x, y) {
-  // Unoptimized and optimized code.
-  1 is double;  /// 00: ok
-  if (1 is double) { x++; }  /// 01: ok
-  try { 1 as double; } on CastError catch (e) { }  /// 02: ok
-  try { var y = 1 as double; } on CastError catch (e) { }  /// 03: ok
-  1.0 is int;  /// 04: ok
-  if (1.0 is int) { x++; }  /// 05: ok
-  try { 1.0 as int; } on CastError catch (e) { }  /// 06: ok
-  try { var z = 1.0 as int; } on CastError catch (e) { }  /// 07: ok
-
-  x is double;  /// 10: ok
-  if (x is double) { }  /// 11: ok
-  try { x as double; } on CastError catch (e) { }  /// 12: ok
-  try { var z = x as double; } on CastError catch (e) { }  /// 13: ok
-  y is int;  /// 14: ok
-  if (y is int) { }  /// 15: ok
-  try { y as int; } on CastError catch (e) { }  /// 16: ok
-  try { var z = y as int; } on CastError catch (e) { }  /// 17: ok
-
-  // It is a compile-time error if evaluation of a constant object results in
-  // an uncaught exception being thrown, a JavascriptCompatibilityError here.
-  "${1.0}";  /// 20: compile-time error
-  var z = "${1.0}";  /// 21: compile-time error
-
-  (1.0).toString();  /// 22: ok
-  var z = (1.0).toString();  /// 23: ok
-  "$y";  /// 24: ok
-  var z = "$y";  /// 25: ok
-  y.toString();  /// 26: ok
-  var z = y.toString();  /// 27: ok
-
-  var a = "yz";
-  var b = "xyz";
-  b = b.substring(1);
-  if (identical(a, b)) { }  /// 28: ok
-
-  if (identical(x, y)) { }  /// 29: ok
-  if (identical(y, x)) { }  /// 30: ok
-
-  if (x > 10) {
-    // Optimized code.
-    x is double;  /// 40: ok
-    if (x is double) { }  /// 41: ok
-    try { x as double; } on CastError catch (e) { }  /// 42: ok
-    try { var z = x as double; } on CastError catch (e) { }  /// 43: ok
-    y is int;  /// 44: ok
-    if (y is int) { }  /// 45: ok
-    try { y as int; } on CastError catch (e) { }  /// 46: ok
-    try { var z = y as int; } on CastError catch (e) { }  /// 47: ok
-
-    "${1.0}";  /// 50: compile-time error
-    var z = "${1.0}";  /// 51: compile-time error
-
-    (1.0).toString();  /// 52: ok
-    var z = (1.0).toString();  /// 53: ok
-    "$y";  /// 54: ok
-    var z = "$y";  /// 55: ok
-    y.toString();  /// 56: ok
-    var z = y.toString();  /// 57: ok
-
-    var a = "yz";
-    var b = "xyz";
-    b = b.substring(1);
-    if (identical(a, b)) { }  /// 58: ok
-
-    if (identical(x, y)) { }  /// 59: ok
-    if (identical(y, x)) { }  /// 60: ok
-  }
-}
-
-k(x, y) {
-  // Unoptimized and optimized code.
-  1.5 is double;
-  if (1.5 is double) { x++; }
-  try { 1.5 as double; } on CastError catch (e) { }
-  try { var y = 1.5 as double; } on CastError catch (e) { }
-  1.5 is int;
-  if (1.5 is int) { x++; }
-  try { 1.5 as int; } on CastError catch (e) { }
-  try { var z = 1.5 as int; } on CastError catch (e) { }
-
-  1.5 is double;
-  if (1.5 is double) { x++; }
-  try { 1.5 as double; } on CastError catch (e) { }
-  try { var y = 1.5 as double; } on CastError catch (e) { }
-  1.5 is int;
-  if (1.5 is int) { x++; }
-  try { 1.5 as int; } on CastError catch (e) { }
-  try { var z = 1.5 as int; } on CastError catch (e) { }
-
-  x is double;
-  if (x is double) { }
-  try { x as double; } on CastError catch (e) { }
-  try { var z = x as double; } on CastError catch (e) { }
-  y is int;
-  if (y is int) { }
-  try { y as int; } on CastError catch (e) { }
-  try { var z = y as int; } on CastError catch (e) { }
-
-  "${1.5}";
-  var z = "${1.5}";
-  (1.5).toString();
-  z = (1.5).toString();
-  "$y";
-  z = "$y";
-  y.toString();
-  z = y.toString();
-
-  var a = "xyz";
-  var b = "xyz";
-  b = b.substring(1);
-  if (identical(a, b)) { }
-
-  if (identical(x, y)) { }
-  if (identical(y, x)) { }
-
-  if (x > 10) {
-    // Optimized code.
-    x is double;
-    if (x is double) { }
-    try { x as double; } on CastError catch (e) { }
-    try { var z = x as double; } on CastError catch (e) { }
-    y is int;
-    if (y is int) { }
-    try { y as int; } on CastError catch (e) { }
-    try { var z = y as int; } on CastError catch (e) { }
-
-    "${1.5}";
-    var z = "${1.5}";
-    (1.5).toString();
-    z = (1.5).toString();
-    "$y";
-    z = "$y";
-    y.toString();
-    z = y.toString();
-
-    var a = "xyz";
-    var b = "xyz";
-    b = b.substring(1);
-    if (identical(a, b)) { }
-
-    if (identical(x, y)) { }
-    if (identical(y, x)) { }
-  }
-}
-
-g(x, y) => f(x, y);  // Test inlining calls.
-h(x, y) => g(x, y);
-
-// We don't test for _JavascriptCompatibilityError since it's not visible.
-// It should not be visible since it doesn't exist on dart2js.
-bool isJavascriptCompatibilityError(e) =>
-    e is Error && "$e".contains("Javascript Compatibility Error");
-
-main() {
-  // The warning (or error in case of --warning_as_error) is issued at
-  // most once per location.
-  var numWarnings = 0;
-  for (var i = 0; i < 20; i++) {
-    try {
-      h(i, i * 1.0);
-    } catch(e) {
-      Expect.isTrue(isJavascriptCompatibilityError(e));
-      numWarnings++;
-    }
-  }
-  Expect.equals(1, numWarnings);
-  // No warnings (errors) should be issued after this point.
-  for (var i = 0; i < 20; i++) {
-    k(i * 1.0, i);
-    k(i * 1.0, i + 0.5);
-  }
-}
-
diff --git a/tests/standalone/javascript_compatibility_warnings_test.dart b/tests/standalone/javascript_compatibility_warnings_test.dart
deleted file mode 100644
index bb744b1..0000000
--- a/tests/standalone/javascript_compatibility_warnings_test.dart
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--warn_on_javascript_compatibility --no_warning_as_error --optimization_counter_threshold=5
-
-import "package:expect/expect.dart";
-
-f(x, y) {
-  // Unoptimized and optimized code.
-  1 is double;  /// 00: ok
-  if (1 is double) { x++; }  /// 01: ok
-  try { 1 as double; } on CastError catch (e) { }  /// 02: ok
-  try { var y = 1 as double; } on CastError catch (e) { }  /// 03: ok
-  1.0 is int;  /// 04: ok
-  if (1.0 is int) { x++; }  /// 05: ok
-  try { 1.0 as int; } on CastError catch (e) { }  /// 06: ok
-  try { var z = 1.0 as int; } on CastError catch (e) { }  /// 07: ok
-
-  x is double;  /// 10: ok
-  if (x is double) { }  /// 11: ok
-  try { x as double; } on CastError catch (e) { }  /// 12: ok
-  try { var z = x as double; } on CastError catch (e) { }  /// 13: ok
-  y is int;  /// 14: ok
-  if (y is int) { }  /// 15: ok
-  try { y as int; } on CastError catch (e) { }  /// 16: ok
-  try { var z = y as int; } on CastError catch (e) { }  /// 17: ok
-
-  "${1.0}";  /// 20: ok
-  var z = "${1.0}";  /// 21: ok
-  (1.0).toString();  /// 22: ok
-  var z = (1.0).toString();  /// 23: ok
-  "$y";  /// 24: ok
-  var z = "$y";  /// 25: ok
-  y.toString();  /// 26: ok
-  var z = y.toString();  /// 27: ok
-
-  var a = "yz";
-  var b = "xyz";
-  b = b.substring(1);
-  if (identical(a, b)) { }  /// 28: ok
-
-  if (identical(x, y)) { }  /// 29: ok
-  if (identical(y, x)) { }  /// 30: ok
-
-  if (x > 10) {
-    // Optimized code.
-    x is double;  /// 40: ok
-    if (x is double) { }  /// 41: ok
-    try { x as double; } on CastError catch (e) { }  /// 42: ok
-    try { var z = x as double; } on CastError catch (e) { }  /// 43: ok
-    y is int;  /// 44: ok
-    if (y is int) { }  /// 45: ok
-    try { y as int; } on CastError catch (e) { }  /// 46: ok
-    try { var z = y as int; } on CastError catch (e) { }  /// 47: ok
-
-    "${1.0}";  /// 50: ok
-    var z = "${1.0}";  /// 51: ok
-    (1.0).toString();  /// 52: ok
-    var z = (1.0).toString();  /// 53: ok
-    "$y";  /// 54: ok
-    var z = "$y";  /// 55: ok
-    y.toString();  /// 56: ok
-    var z = y.toString();  /// 57: ok
-
-    var a = "yz";
-    var b = "xyz";
-    b = b.substring(1);
-    if (identical(a, b)) { }  /// 58: ok
-
-    if (identical(x, y)) { }  /// 59: ok
-    if (identical(y, x)) { }  /// 60: ok
-  }
-}
-
-g(x, y) => f(x, y);  // Test inlining calls.
-h(x, y) => g(x, y);
-
-main() {
-  for (var i = 0; i < 20; i++) {
-    h(i, i* 1.0);
-  }
-}
-
diff --git a/tests/standalone/javascript_int_overflow_literal_test.dart b/tests/standalone/javascript_int_overflow_literal_test.dart
deleted file mode 100644
index 2d45ef0..0000000
--- a/tests/standalone/javascript_int_overflow_literal_test.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--throw_on_javascript_int_overflow
-
-
-import "package:expect/expect.dart";
-
-int literals() {
-  var okay_literal = 0x20000000000000;
-  var too_big_literal = 0x20000000000001;  /// 01: compile-time error
-  return okay_literal;
-}
-
-main() {
-  Expect.equals(0x20000000000000, literals());
-}
diff --git a/tests/standalone/javascript_int_overflow_test.dart b/tests/standalone/javascript_int_overflow_test.dart
deleted file mode 100644
index 3a5b932..0000000
--- a/tests/standalone/javascript_int_overflow_test.dart
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--throw_on_javascript_int_overflow --optimization_counter_threshold=10 --no-use-osr
-
-
-import "package:expect/expect.dart";
-import 'dart:typed_data';
-
-
-double dti_arg;
-int double_to_int() {
-  return dti_arg.toInt();
-}
-
-
-int ia_arg1;
-int ia_arg2;
-int integer_add() {
-  return ia_arg1 + ia_arg2;
-}
-
-
-int is_arg;
-int integer_shift() {
-  return is_arg << 1;
-}
-
-
-int max_add_throws() {
-  return 0x20000000000000 + 1;
-}
-
-
-int min_sub_throws() {
-  return -0x20000000000000 - 1;
-}
-
-
-int n_arg;
-int negate() {
-  return -n_arg;
-}
-
-
-int max_literal() {
-  return 0x20000000000000;
-}
-
-
-int min_literal() {
-  var min_literal = -0x20000000000000;
-  return min_literal;
-}
-
-
-int doNotThrow1(a, b) {
-  return (a << b) & 0xFFFFFFFF;
-}
-
-int doNotThrow2(a, b) {
-  return (a << b) & 0xFFFFFFFF;
-}
-
-
-int doNotThrow3(a, b) {
-  return (a << b) & 0x7FFFFFFF;
-}
-
-
-int doNotThrow4(a, b) {
-  return (a << b) & 0x7FFFFFFF;
-}
-
-
-// We don't test for the _JavascriptIntegerOverflowError since it's not visible.
-// It should not be visible since it doesn't exist on dart2js.
-bool isJavascriptIntError(e) =>
-    e is Error && "$e".startsWith("Javascript Integer Overflow:");
-
-main() {
-  Expect.equals(0x20000000000000, max_literal());
-  Expect.equals(-0x20000000000000, min_literal());
-
-  // Run the tests once before optimizations.
-  dti_arg = 1.9e17;
-  Expect.throws(double_to_int, isJavascriptIntError);
-
-  ia_arg1 = (1 << 53);
-  ia_arg2 = (1 << 53);
-  Expect.throws(integer_add, isJavascriptIntError);
-
-  n_arg = -0x20000000000000;
-  Expect.equals(0x20000000000000, negate());
-
-  is_arg = (1 << 53);
-  Expect.throws(integer_shift, isJavascriptIntError);
-
-  Expect.throws(max_add_throws, isJavascriptIntError);
-  Expect.throws(min_sub_throws, isJavascriptIntError);
-
-  for (int i = 0; i < 20; i++) {
-    dti_arg = i.toDouble();
-    // Expect.throws calls through the closure, so we have to here, too.
-    var f = double_to_int;
-    Expect.equals(i, f());
-
-    ia_arg1 = i;
-    ia_arg2 = i;
-    f = integer_add;
-    Expect.equals(i + i, f());
-
-    n_arg = i;
-    f = negate;
-    Expect.equals(-i, f());
-
-    is_arg = i;
-    f = integer_shift;
-    Expect.equals(i << 1, f());
-  }
-
-   // The optimized functions should now deoptimize and throw the error.
-  dti_arg = 1.9e17;
-  Expect.throws(double_to_int, isJavascriptIntError);
-
-  ia_arg1 = (1 << 53);
-  ia_arg2 = (1 << 53);
-  Expect.throws(integer_add, isJavascriptIntError);
-
-  n_arg = -0x20000000000000;
-  Expect.equals(0x20000000000000, negate());
-
-  is_arg = (1 << 53);
-  Expect.throws(integer_shift, isJavascriptIntError);
-
-  Expect.throws(max_add_throws, isJavascriptIntError);
-  Expect.throws(min_sub_throws, isJavascriptIntError);
-
-  for (int i = 0; i < 20; i++) {
-    Expect.equals(0xAFAFA000, doNotThrow1(0xFAFAFA, 12));
-    Expect.equals(0x2FAFA000, doNotThrow3(0xFAFAFA, 12));
-    Expect.equals(0xABABA000, doNotThrow2(0xFAFAFAABABA, 12));
-    Expect.equals(0x2BABA000, doNotThrow4(0xFAFAFAABABA, 12));
-  }
-  for (int i = 0; i < 20; i++) {
-    Expect.equals(0xABABA000, doNotThrow1(0xFAFAFAABABA, 12));
-    Expect.equals(0x2BABA000, doNotThrow3(0xFAFAFAABABA, 12));
-  }
-
-}
diff --git a/tests/standalone/link_natives_lazily_test.dart b/tests/standalone/link_natives_lazily_test.dart
new file mode 100644
index 0000000..35a53a1
--- /dev/null
+++ b/tests/standalone/link_natives_lazily_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--link_natives_lazily
+
+main() {
+  print("Okay");
+}
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/no_allow_absolute_addresses_test.dart b/tests/standalone/no_allow_absolute_addresses_test.dart
new file mode 100644
index 0000000..e013c5e
--- /dev/null
+++ b/tests/standalone/no_allow_absolute_addresses_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no_allow_absolute_addresses
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_lazy_dispatchers_test.dart b/tests/standalone/no_lazy_dispatchers_test.dart
new file mode 100644
index 0000000..f45ba1c
--- /dev/null
+++ b/tests/standalone/no_lazy_dispatchers_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no_lazy_dispatchers
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_profiler_test.dart b/tests/standalone/no_profiler_test.dart
new file mode 100644
index 0000000..0b612d1
--- /dev/null
+++ b/tests/standalone/no_profiler_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no_profiler
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_support_ast_printer_test.dart b/tests/standalone/no_support_ast_printer_test.dart
new file mode 100644
index 0000000..bbffe22
--- /dev/null
+++ b/tests/standalone/no_support_ast_printer_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no-support_ast_printer
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_support_coverage_test.dart b/tests/standalone/no_support_coverage_test.dart
new file mode 100644
index 0000000..7bbf602
--- /dev/null
+++ b/tests/standalone/no_support_coverage_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no-support_coverage
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_support_debugger_test.dart b/tests/standalone/no_support_debugger_test.dart
new file mode 100644
index 0000000..fb20c9a
--- /dev/null
+++ b/tests/standalone/no_support_debugger_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no-support_debugger
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_support_disassembler_test.dart b/tests/standalone/no_support_disassembler_test.dart
new file mode 100644
index 0000000..2f0aca0
--- /dev/null
+++ b/tests/standalone/no_support_disassembler_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no_support_disassembler
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_support_il_printer_test.dart b/tests/standalone/no_support_il_printer_test.dart
new file mode 100644
index 0000000..4ebba33
--- /dev/null
+++ b/tests/standalone/no_support_il_printer_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no-support_il_printer
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_support_service_test.dart b/tests/standalone/no_support_service_test.dart
new file mode 100644
index 0000000..2431dbc
--- /dev/null
+++ b/tests/standalone/no_support_service_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no-support_service
+
+main() {
+  print("Okay");
+}
diff --git a/tests/standalone/no_support_timeline_test.dart b/tests/standalone/no_support_timeline_test.dart
new file mode 100644
index 0000000..c15a441
--- /dev/null
+++ b/tests/standalone/no_support_timeline_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--no-support_timeline
+
+main() {
+  print("Okay");
+}
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/precompilation_dart2js_test.dart b/tests/standalone/precompilation_dart2js_test.dart
index 5d3900e..0deafcb 100644
--- a/tests/standalone/precompilation_dart2js_test.dart
+++ b/tests/standalone/precompilation_dart2js_test.dart
@@ -77,7 +77,7 @@
 
     result = Process.runSync(
         cc,
-        [shared, cc_flags, "-o", libname, "precompiled.S"],
+        [shared, cc_flags, "-nostartfiles", "-o", libname, "precompiled.S"],
         workingDirectory: tmp.path);
     if (result.exitCode != 0) {
       print(result.stdout);
@@ -87,7 +87,7 @@
 
     var ld_library_path = new String.fromEnvironment("LD_LIBRARY_PATH");
     ld_library_path = "${ld_library_path}:${tmp.path}";
-    exec = "${dart_executable}_precompiled";
+    exec = "${dart_executable}_precompiled_runtime";
     args = ["--run-precompiled-snapshot", "ignored_script", "--version"];
     print("LD_LIBRARY_PATH=$ld_library_path $exec ${args.join(' ')}");
     result = Process.runSync(exec, args,
diff --git a/tests/standalone/precompilation_test.dart b/tests/standalone/precompilation_test.dart
index 751682e..e65bf17 100644
--- a/tests/standalone/precompilation_test.dart
+++ b/tests/standalone/precompilation_test.dart
@@ -74,7 +74,7 @@
 
     result = Process.runSync(
         cc,
-        [shared, cc_flags, "-o", libname, "precompiled.S"],
+        [shared, cc_flags, "-nostartfiles", "-o", libname, "precompiled.S"],
         workingDirectory: tmp.path);
     if (result.exitCode != 0) {
       print(result.stdout);
@@ -86,7 +86,7 @@
     ld_library_path = "${ld_library_path}:${tmp.path}";
 
     result = Process.runSync(
-       "${dart_executable}_precompiled",
+       "${dart_executable}_precompiled_runtime",
        ["--run-precompiled-snapshot", "ignored_script", "--hello"],
        workingDirectory: tmp.path,
        environment: {"LD_LIBRARY_PATH": ld_library_path});
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 590489e..41f4d09 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -13,21 +13,20 @@
 package/scenarios/empty_packages_file/empty_packages_file_option_test: Fail, OK # CompileTimeErrors intentionally
 package/scenarios/invalid/invalid_package_name_test: RuntimeError, CompileTimeError # Errors intentionally
 package/scenarios/invalid/same_package_twice_test.dart: RuntimeError, CompileTimeError # Errors intentionally
+full_coverage_test: Pass, Slow
 
 
 issue14236_test: Pass # Do not remove this line. It serves as a marker for Issue 14516 comment #4.
 
-javascript_compatibility_errors_test/none: Fail, OK  # Not possible to exclude or annotate with '/// none:'
-
-[ ($runtime != vm && $runtime != dart_precompiled) && ($runtime != drt || $compiler != none)) ]
+[ ($runtime != vm && $runtime != dart_precompiled && $runtime != dart_product) && ($runtime != drt || $compiler != none)) ]
 no_assert_test: Fail, OK # This is testing a vm flag.
 
-[ ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 package/package_isolate_test: Fail # Issue 12474
 io/observatory_test: Fail
 package/scenarios/invalid/same_package_twice_test: Pass # Issue 24119
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $checked ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $checked ]
 # These tests have type errors on purpose.
 io/process_invalid_arguments_test: Fail, OK
 io/directory_invalid_arguments_test: Fail, OK
@@ -40,13 +39,21 @@
 io/file_fuzz_test: Skip
 io/directory_fuzz_test: Skip
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $system == macos ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $system == macos ]
 # This test fails with "Too many open files" on the Mac OS buildbot.
 # This is expected as MacOS by default runs with a very low number
 # of allowed open files ('ulimit -n' says something like 256).
 io/socket_many_connections_test: Skip
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == drt || $runtime == dartium || $runtime == ContentShellOnAndroid) ]
+[ $runtime == vm && $system == linux ]
+# These tests have started timing out and issue 25649 has been filed to
+# investigate, skipping these tests temporarily to get the bots to be
+# green again.
+io/http_proxy_test: Skip
+io/secure_builtin_roots_test: Skip
+
+
+[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
 typed_array_test: RuntimeError, OK  # Uses Isolate.spawn
 typed_array_int64_uint64_test: RuntimeError, OK  # Uses Isolate.spawn
 typed_data_isolate_test: SkipByDesign # This test uses dart:io
@@ -56,17 +63,13 @@
 http_launch_test: Skip
 vmservice/*: SkipByDesign # Do not run standalone vm service tests in browser.
 issue14236_test: Skip # Issue 14236 Script snapshots do not work in the browser.
-javascript_compatibility_errors_test: Skip
-javascript_compatibility_warnings_test: Skip
 oom_error_stacktrace_test: Skip
 out_of_memory_test: Skip
 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 ]
-javascript_int_overflow_literal_test/01: Fail, OK
 issue14236_test: Skip # Analyzer can't handle Script snapshots.
 
 # test issue https://code.google.com/p/dart/issues/detail?id=11518
@@ -97,33 +100,24 @@
 pow_test: Skip # Precision > 53 bits.
 double_smi_comparison_test: Skip # Precision > 53 bits.
 http_launch_test: Skip
-javascript_int_overflow_test: Skip
-javascript_int_overflow_literal_test: Skip
 oom_error_stacktrace_test: RuntimeError, OK # (OOM on JS may produce a stacktrace).
 vmservice/*: Skip # Do not run standalone vm service tests with dart2js.
 issue14236_test: Skip # dart2js does not deal with Script snapshots.
-javascript_compatibility_errors_test: Skip
-javascript_compatibility_warnings_test: Skip
 unboxed_int_converter_test: Skip
 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 && $mode == debug ]
+[ ($runtime == vm || $runtime == dart_product) && $mode == debug ]
 precompilation_dart2js_test: Pass, Slow
 
-[ $runtime == vm && $arch == ia32 ]
-precompilation_test: Skip # Not expected to pass on ia32.
-precompilation_dart2js_test: Skip # Not expected to pass on ia32.
-noopt_test: Skip # Not expected to pass on ia32.
+[ ($runtime == vm || $runtime == dart_product) && $arch == ia32 ]
+precompilation_test: SkipByDesign # Not expected to pass on ia32.
+precompilation_dart2js_test: SkipByDesign # Not expected to pass on ia32.
 
-[ $runtime == vm && $arch == arm ]
-precompilation_test: Skip # Issue 24427
-precompilation_dart2js_test: Skip # Issue 24427
-
-[ $runtime == vm && $arch == mips ]
+[ ($runtime == vm || $runtime == dart_product) && ($arch == mips || $arch == arm || $arch == arm64) ]
+precompilation_test: SkipSlow
 precompilation_dart2js_test: SkipSlow
 
 [ $compiler == dart2js && $jscl ]
@@ -140,13 +134,10 @@
 [ $compiler == dart2js && $browser ]
 *: Skip
 
-[ $arch == simarm || $arch == simarmv5te || $arch == simmips ]
+[ $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simmips ]
 out_of_memory_test: Skip # passes on Mac, crashes on Linux
 oom_error_stacktrace_test: Skip # Fails on Linux
 
-[ $arch == simmips || $arch == mips ]
-javascript_int_overflow_test: Skip # --throw_on_javascript_int_overflow not supported on MIPS.
-
 [ $arch == mips ]
 io/signals_test: Fail # Issue 17440
 io/file_stat_test: Fail # Issue 17440
@@ -161,13 +152,9 @@
 full_coverage_test: SkipSlow # Times out. Issue 20352
 io/http_client_stays_alive_test: Skip # Timing dependent test, MIPS machine too slow.
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == dartium || $runtime == ContentShellOnAndroid) && $unchecked ]
+[ $compiler == none && $runtime == dartium && $unchecked ]
 assert_test: Fail # Issue 14651.
 
-[ ($compiler == none || $compiler == precompiler) && ($runtime == dartium || $runtime == ContentShellOnAndroid) ]
-javascript_int_overflow_literal_test/01: Fail # Issue 14651.
-javascript_int_overflow_test: Fail # Issue 14651.
-
 [ $compiler == none && $runtime == drt ]
 map_literal_oom_test: RuntimeError # Issue 24571
 
@@ -185,8 +172,6 @@
 package/scenarios/packages_file_in_parent/sub/packages_file_in_parent_test: StaticWarning
 typed_data_test: StaticWarning
 typed_data_view_test: StaticWarning
-javascript_compatibility_errors_test: Skip
-javascript_compatibility_warnings_test: Skip
 
 [ $compiler == dart2analyzer ]
 package/package1_test: CompileTimeError
@@ -205,67 +190,109 @@
 verbose_gc_to_bmu_test: Skip
 io/platform_resolved_executable_test/06: RuntimeError  # Issue 23641
 io/process_sync_test: Pass, Timeout  # Issue 24596
+io/sleep_test: Pass, Fail # Issue 25757
 
 [ $arch != ia32 && $arch != x64 && $arch != simarm && $arch != simarmv5te && $mode == debug ]
 verified_mem_test: Skip  # Not yet implemented.
 
-[ ($runtime == vm || $runtime == dart_precompiled) && $mode == debug && $builder_tag == asan ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) && $mode == debug && $builder_tag == asan ]
 full_coverage_test: Skip  # Timeout.
 io/file_lock_test: Skip  # Timeout.
 io/test_runner_test: Skip  # Timeout.
 io/http_client_stays_alive_test: Skip  # Timeout.
 
-[ ($runtime == vm || $runtime == dart_precompiled) ]
+[ ($runtime == vm || $runtime == dart_precompiled || $runtime == dart_product) ]
 # Failures in secure networking while NSS is replaced with BoringSSL
 io/https_client_certificate_test: RuntimeError # Issue 24070
 io/secure_socket_renegotiate_test: RuntimeError
 io/secure_socket_bad_data_test: RuntimeError  # An error in a secure connection just puts a READ_CLOSED on the stream, rather than signaling an error on the stream.
 
-[ ($noopt || $compiler == precompiler) ]
+[ $arch == ia32 ]
+no_allow_absolute_addresses_test: SkipByDesign # Not supported.
+link_natives_lazily_test: SkipByDesign # Not supported.
+
+[ $noopt || $compiler == precompiler ]
+# Stacktraces in precompilation omit inlined frames.
+assert_test: Pass, RuntimeError
+
+[ $noopt || $compiler == precompiler ]
 map_literal_oom_test: Pass, Crash # Issue 24678
-javascript*: SkipByDesign # JS overflow flag unsupported
 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
+io/test_extension_fail_test: Skip # Platform.executable
+io/platform_test: Skip # Platform.executable
+io/code_collection_test: Skip # Platform.executable
+full_coverage_test: Skip # Platform.executable
 
 [ $runtime == dart_precompiled ]
-debugger/*: Skip
-noopt_test: Skip
-precompilation_dart2js_test: Skip
-
-full_coverage_test: RuntimeError # Platform.executable
-http_launch_test: RuntimeError # Platform.executable
-io/addlatexhash_test: RuntimeError # Platform.executable
 io/compile_all_test: Crash # Incompatible flag --compile_all
-io/file_read_special_device_test: RuntimeError # Platform.executable
-io/file_stream_test: RuntimeError # Platform.executable
-io/file_test: RuntimeError # Platform.executable
-io/http_cross_process_test: RuntimeError # Platform.executable
-io/https_unauthorized_test: RuntimeError # Platform.executable
-io/platform_resolved_executable_test: RuntimeError # Platform.resolvedExecutable
-io/skipping_dart2js_compilations_test: RuntimeError # Platform.executable
-io/snapshot_fail_test: RuntimeError # Platform.executable
-io/stdin_sync_test: RuntimeError # Platform.executable
-io/test_extension_fail_test: RuntimeError # Platform.executable
-precompilation_test: RuntimeError # Platform.executable
-standalone/io/file_read_special_device_test: RuntimeError # Platform.executable
-verbose_gc_to_bmu_test: RuntimeError # Platform.executable
-io/http_server_close_response_after_error_test: RuntimeError # Platform.executable
-io/http_client_stays_alive_test: RuntimeError # Platform.executable
-io/print_sync_test: RuntimeError # Platform.executable
-io/signals_test: RuntimeError # Platform.executable
-io/stdio_nonblocking_test: RuntimeError # Platform.executable
-io/regress_7191_test: RuntimeError # Platform.executable
-io/secure_unauthorized_test: RuntimeError # Platform.executable
-io/dart_std_io_pipe_test: RuntimeError # Platform.executable
-io/platform_test: RuntimeError # Platform.executable
-io/socket_cross_process_test: RuntimeError # Platform.executable
-io/test_runner_test: RuntimeError # Platform.executable
-io/file_lock_test: RuntimeError # Platform.executable
-io/code_collection_test: RuntimeError # Platform.executable
-io/file_lock_test: RuntimeError # Platform.executable
-io/code_collection_test: RuntimeError # Platform.executable
-io/raw_socket_cross_process_test: RuntimeError # Platform.executable
-io/test_extension_test: RuntimeError # Platform.executable
-io/regress_7679_test: RuntimeError # Platform.executable
 
-io/process_*: Skip # Most use Platform.executable
\ No newline at end of file
+[ $runtime == dart_product ]
+io/stdout_bad_argument_test: Skip # Test exits and so can't generate snapshot.
+
+[ $runtime == dart_precompiled || $runtime == dart_product ]
+debugger/*: Skip
+precompilation_test: Skip # Platform.executable
+precompilation_dart2js_test: Skip # Platform.executable
+full_coverage_test: Skip # Platform.executable
+http_launch_test: Skip # Platform.executable
+io/addlatexhash_test: Skip # Platform.executable
+io/file_read_special_device_test: Skip # Platform.executable
+io/file_stream_test: Skip # Platform.executable
+io/file_test: Skip # Platform.executable
+io/http_cross_process_test: Skip # Platform.executable
+io/https_unauthorized_test: Skip # Platform.executable
+io/platform_resolved_executable_test: Skip # Platform.resolvedExecutable
+io/skipping_dart2js_compilations_test: Skip # Platform.executable
+io/snapshot_fail_test: Skip # Platform.executable
+io/stdin_sync_test: Skip # Platform.executable
+io/test_extension_fail_test: Skip # Platform.executable
+precompilation_test: Skip # Platform.executable
+io/file_read_special_device_test: Skip # Platform.executable
+verbose_gc_to_bmu_test: Skip # Platform.executable
+io/http_server_close_response_after_error_test: Skip # Platform.executable
+io/http_client_stays_alive_test: Skip # Platform.executable
+io/print_sync_test: Skip # Platform.executable
+io/signals_test: Skip # Platform.executable
+io/stdio_nonblocking_test: Skip # Platform.executable
+io/regress_7191_test: Skip # Platform.executable
+io/secure_unauthorized_test: Skip # Platform.executable
+io/dart_std_io_pipe_test: Skip # Platform.executable
+io/platform_test: Skip # Platform.executable
+io/socket_cross_process_test: Skip # Platform.executable
+io/test_runner_test: Skip # Platform.executable
+io/file_lock_test: Skip # Platform.executable
+io/code_collection_test: Skip # Platform.executable
+io/file_lock_test: Skip # Platform.executable
+io/code_collection_test: Skip # Platform.executable
+io/raw_socket_cross_process_test: Skip # Platform.executable
+io/test_extension_test: Skip # Platform.executable
+io/regress_7679_test: Skip # Platform.executable
+io/process_*: Skip # Most use Platform.executable
+
+# Code coverage is not supported in product mode.
+[ $mode == product ]
+full_coverage_test: SkipByDesign
+
+# Overriding these flags are not supported in product mode.
+[ $mode == product ]
+no_profiler_test: SkipByDesign
+no_support_coverage_test: SkipByDesign
+no_support_debugger_test: SkipByDesign
+no_support_disassembler_test: SkipByDesign
+no_support_il_printer_test: SkipByDesign
+no_support_service_test: SkipByDesign
+no_support_timeline_test: SkipByDesign
+
+# Following tests are skipped on dart_product as package mapping is not supported.
+[ $runtime == dart_product ]
+package/scenarios/packages_file_strange_formatting/mixed_line_ends_test: Skip
+package/scenarios/packages_file_strange_formatting/empty_lines_test: Skip
+package/scenarios/invalid/invalid_utf8_test: Skip
+package/scenarios/invalid/same_package_twice_test: Skip
+package/scenarios/invalid/non_existent_packages_file_test: Skip
+package/scenarios/empty_packages_file/empty_packages_file_noimports_test: Skip
+package/scenarios/packages_option_only/packages_option_only_noimports_test: Skip
+package/scenarios/packages_option_only/packages_option_only_test: Skip
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index bf69360..4ca122e 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -5,8 +5,10 @@
 [ $compiler == dart2js && $host_checked ]
 dummy_compiler_test: Crash # Issue 22809
 
-[ $compiler == dart2js ]
+[ $compiler == dart2js && $host_checked == false ]
 dummy_compiler_test: Slow, Pass
+
+[ $compiler == dart2js ]
 recursive_import_test: Slow, Pass
 source_mirrors_test: Slow, Pass
 
@@ -20,15 +22,5 @@
 [ $compiler == dart2js && $mode == debug ]
 dummy_compiler_test: Slow, Pass
 
-[ ($compiler == none || $compiler == precompiler) && $runtime == ContentShellOnAndroid ]
-dummy_compiler_test: Pass, RuntimeError # Issue 17662
-recursive_import_test: Pass, RuntimeError # Issue 17662
-source_mirrors_test: Pass, RuntimeError # Issue 17662
-
-[ $compiler == dart2js && $cps_ir ]
-dummy_compiler_test: Crash # (switch (function.na...  continue to a labeled switch case
-recursive_import_test: Crash # (switch (function.na...  continue to a labeled switch case
-source_mirrors_test: Crash, Slow # (switch (function.na...  continue to a labeled switch case
-
-[ ($noopt || $compiler == precompiler) ]
+[ $noopt || $compiler == precompiler || $compiler == dart2app ]
 source_mirrors_test: SkipByDesign # Imports dart:mirrors
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 3f481f1..074f02f 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -11,4 +11,5 @@
 !7zip.tar.gz.sha1
 !firefox_jsshell
 !gsutil.tar.gz.sha1
-!clang.tar.gz.sha1
\ No newline at end of file
+!clang.tar.gz.sha1
+!unittest.tar.gz.sha1
diff --git a/third_party/boringssl/boringssl_configurations.gypi b/third_party/boringssl/boringssl_configurations.gypi
index 91c76c1..0a82431 100644
--- a/third_party/boringssl/boringssl_configurations.gypi
+++ b/third_party/boringssl/boringssl_configurations.gypi
@@ -66,6 +66,27 @@
           'GCC_TREAT_WARNINGS_AS_ERRORS': 'NO', # -Werror off
         },
       },
+      # Disable hand-coded assembly routines on ARMv6 and ARMv5TE.
+      'Dart_armv6_Base': {
+        'abstract': 1,
+        'defines': [
+          'OPENSSL_NO_ASM',
+        ],
+      },
+      'Dart_armv5te_Base': {
+        'abstract': 1,
+        'defines': [
+          'OPENSSL_NO_ASM',
+        ],
+      },
+      # TODO(24321): Also disable temporarily on arm64. Reenable after the next
+      # roll.
+      'Dart_arm64_Base': {
+        'abstract': 1,
+        'defines': [
+          'OPENSSL_NO_ASM',
+        ],
+      },
       # When being built for Android nss expects __linux__ to be defined.
       'Dart_Android_Base': {
         'target_conditions': [
@@ -96,4 +117,4 @@
       },
     },
   },
-}
\ No newline at end of file
+}
diff --git a/third_party/pkg/unittest.tar.gz.sha1 b/third_party/pkg/unittest.tar.gz.sha1
new file mode 100644
index 0000000..2a8a5c2
--- /dev/null
+++ b/third_party/pkg/unittest.tar.gz.sha1
@@ -0,0 +1 @@
+fc9b8ccbfbecf20257255d69693d5a50f8692757
\ No newline at end of file
diff --git a/third_party/pkg_tested/pkg_tested.status b/third_party/pkg_tested/pkg_tested.status
index 031b82b..9a58476 100644
--- a/third_party/pkg_tested/pkg_tested.status
+++ b/third_party/pkg_tested/pkg_tested.status
@@ -23,7 +23,7 @@
 pub/test/run/app_can_read_from_stdin_test: Fail # Issue 19448
 pub/test/run/forwards_signal_posix_test: SkipByDesign
 
-[ $runtime == vm && ($mode == debug || $arch == mips || $arch == simmips || $arch == simarm || $arch == simarmv5te || $arch == simarm64 || $builder_tag == asan) ]
+[ $runtime == vm && ($mode == debug || $arch == mips || $arch == simmips || $arch == simarm || $arch == simarmv6 || $arch == simarmv5te || $arch == simarm64 || $builder_tag == asan) ]
 dart_style/test/command_line_test: Skip # The test controller does not take into account that tests take much longer in debug mode or on simulators/mips.
 dart_style/test/formatter_test: Skip # The test controller does not take into account that tests take much longer in debug mode or on simulators/mips.
 
diff --git a/tools/FAKE_COMMITS b/tools/FAKE_COMMITS
index 4a2c46d..63b6b4b 100644
--- a/tools/FAKE_COMMITS
+++ b/tools/FAKE_COMMITS
@@ -16,3 +16,4 @@
 Purple is the new green.
 googlecode back up
 CIT outage - all slaves rebooted
+Authentication failure flake - rerun all bots
diff --git a/tools/VERSION b/tools/VERSION
index 12583a9..b3d3a07 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -25,7 +25,7 @@
 #
 CHANNEL stable
 MAJOR 1
-MINOR 14
-PATCH 2
+MINOR 15
+PATCH 0
 PRERELEASE 0
 PRERELEASE_PATCH 0
diff --git a/tools/bots/bot_utils.py b/tools/bots/bot_utils.py
index 53bd1ca..1e2ce69 100644
--- a/tools/bots/bot_utils.py
+++ b/tools/bots/bot_utils.py
@@ -115,6 +115,12 @@
     return '/'.join([self.sdk_directory(revision),
       self.sdk_zipfilename(system, arch, mode)])
 
+  def unstripped_filepath(self, revision, system, arch):
+    return '/'.join([self._variant_directory('unstripped', revision),
+                     system,
+                     arch,
+                     self.unstripped_filename(system)])
+
   def dartium_variant_zipfilepath(self, revision, name, system, arch, mode):
     return '/'.join([self.dartium_directory(revision),
       self.dartium_variant_zipfilename(name, system, arch, mode)])
@@ -186,6 +192,9 @@
     return 'dartsdk-%s-%s-%s.zip' % (
         SYSTEM_RENAMES[system], ARCH_RENAMES[arch], mode)
 
+  def unstripped_filename(self, system):
+    return 'dart.exe' if system.startswith('win') else 'dart'
+
   def dartium_variant_zipfilename(self, name, system, arch, mode):
     assert name in ['chromedriver', 'dartium', 'content_shell']
     assert mode in Mode.ALL_MODES
@@ -199,13 +208,11 @@
     self.channel = channel
     self.bucket = 'gs://dartlang-api-docs'
 
-  def docs_dirpath(self, revision):
-    assert len('%s' % revision) > 0
-    return '%s/channels/%s/%s' % (self.bucket, self.channel, revision)
-
   def dartdocs_dirpath(self, revision):
     assert len('%s' % revision) > 0
-    return '%s/gen-dartdocs/%s' % (self.bucket, revision)
+    if self.channel == Channel.BLEEDING_EDGE:
+      return '%s/gen-dartdocs/builds/%s' % (self.bucket, revision)
+    return '%s/gen-dartdocs/%s/%s' % (self.bucket, self.channel, revision)
 
   def docs_latestpath(self, revision):
     assert len('%s' % revision) > 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index a784a03..581d762 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -143,9 +143,8 @@
   if system.startswith('win'):
     system = 'windows'
 
-  # We have both 10.8 and 10.7 bots, functionality is the same.
-  if system == 'mac10.7' or system == 'mac10.8' or system == 'mac10.9':
-    builder_tag = system.replace('.', '_')
+  # We have both 10.8 and 10.9 bots, functionality is the same.
+  if system == 'mac10.8' or system == 'mac10.9':
     system = 'mac'
 
   if (system == 'windows' and platform.system() != 'Windows') or (
diff --git a/tools/bots/cross-vm.py b/tools/bots/cross-vm.py
index 9fd751f..9865547 100644
--- a/tools/bots/cross-vm.py
+++ b/tools/bots/cross-vm.py
@@ -47,7 +47,7 @@
       with bot.BuildStep('Create build tarball'):
         run(['tar', '-cjf', tarball, '--exclude=**/obj',
              '--exclude=**/obj.host', '--exclude=**/obj.target',
-             '--exclude=**/*analyzer*', 'out/', 'tools/testing/bin/'])
+             '--exclude=**/*analyzer*', 'out/'])
 
       with bot.BuildStep('Upload build tarball'):
         uri = "%s/%s" % (GCS_BUCKET, tarball)
diff --git a/tools/bots/dart_sdk.py b/tools/bots/dart_sdk.py
index 7952885..00e7d35 100644
--- a/tools/bots/dart_sdk.py
+++ b/tools/bots/dart_sdk.py
@@ -88,9 +88,25 @@
     DartArchiveFile(sdk32_zip, path32, checksum_files=True)
     DartArchiveFile(sdk64_zip, path64, checksum_files=True)
 
+def DartArchiveUnstrippedBinaries():
+  namer = bot_utils.GCSNamer(CHANNEL, bot_utils.ReleaseType.RAW)
+  revision = utils.GetArchiveVersion()
+  binary = namer.unstripped_filename(BUILD_OS)
+  ia32_binary = os.path.join(bot_utils.DART_DIR,
+                             utils.GetBuildRoot(BUILD_OS, 'release', 'ia32'),
+                             binary)
+  x64_binary = os.path.join(bot_utils.DART_DIR,
+                            utils.GetBuildRoot(BUILD_OS, 'release', 'x64'),
+                            binary)
+  gs_ia32_path = namer.unstripped_filepath(revision, BUILD_OS, 'ia32')
+  gs_x64_path = namer.unstripped_filepath(revision, BUILD_OS, 'x64')
+  DartArchiveFile(ia32_binary, gs_ia32_path)
+  DartArchiveFile(x64_binary, gs_x64_path)
+
 def CreateUploadSDK():
   BuildSDK()
   CreateUploadSDKZips()
+  DartArchiveUnstrippedBinaries()
 
 def CreateUploadAPIDocs():
   dartdoc_dir =  os.path.join(bot_utils.DART_DIR,
diff --git a/tools/build.py b/tools/build.py
index dac178f..62717d7 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -48,15 +48,15 @@
   result = optparse.OptionParser(usage=usage)
   result.add_option("-m", "--mode",
       help='Build variants (comma-separated).',
-      metavar='[all,debug,release]',
+      metavar='[all,debug,release,product]',
       default='debug')
   result.add_option("-v", "--verbose",
       help='Verbose output.',
       default=False, action="store_true")
   result.add_option("-a", "--arch",
       help='Target architectures (comma-separated).',
-      metavar='[all,ia32,x64,simarm,arm,simarmv5te,armv5te,simmips,mips'
-              ',simarm64,arm64,]',
+      metavar='[all,ia32,x64,simarm,arm,simarmv6,armv6,simarmv5te,armv5te,'
+              'simmips,mips,simarm64,arm64,]',
       default=utils.GuessArchitecture())
   result.add_option("--os",
     help='Target OSs (comma-separated).',
@@ -90,19 +90,19 @@
   if options.arch == 'all':
     options.arch = 'ia32,x64,simarm,simmips,simarm64'
   if options.mode == 'all':
-    options.mode = 'release,debug'
+    options.mode = 'debug,release,product'
   if options.os == 'all':
     options.os = 'host,android'
   options.mode = options.mode.split(',')
   options.arch = options.arch.split(',')
   options.os = options.os.split(',')
   for mode in options.mode:
-    if not mode in ['debug', 'release']:
+    if not mode in ['debug', 'release', 'product']:
       print "Unknown mode %s" % mode
       return False
   for arch in options.arch:
-    archs = ['ia32', 'x64', 'simarm', 'arm', 'simarmv5te', 'armv5te', 'simmips',
-             'mips', 'simarm64', 'arm64',]
+    archs = ['ia32', 'x64', 'simarm', 'arm', 'simarmv6', 'armv6',
+             'simarmv5te', 'armv5te', 'simmips', 'mips', 'simarm64', 'arm64',]
     if not arch in archs:
       print "Unknown arch %s" % arch
       return False
@@ -119,7 +119,7 @@
         print ("Cross-compilation to %s is not supported on host os %s."
                % (os_name, HOST_OS))
         return False
-      if not arch in ['ia32', 'arm', 'armv5te', 'arm64', 'mips']:
+      if not arch in ['ia32', 'arm', 'armv6', 'armv5te', 'arm64', 'mips']:
         print ("Cross-compilation to %s is not supported for architecture %s."
                % (os_name, arch))
         return False
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 5cf2b1a..0d72c9d 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -44,6 +44,10 @@
 # ......dart_shared.platform
 # ......dart2dart.platform
 # ......_internal/
+#.........spec.sum
+#.........strong.sum
+# ......analysis_server/
+# ......analyzer/
 # ......async/
 # ......collection/
 # ......convert/
@@ -137,7 +141,13 @@
     copyfile(join(snapshots, snapshot),
              join(sdk_root, 'bin', 'snapshots', snapshot))
 
-def CopyDartdocResources(home,sdk_root):
+def CopyAnalyzerSources(home, lib_dir):
+  for library in ['analyzer', 'analysis_server']:
+    copytree(join(home, 'pkg', library), join(lib_dir, library),
+             ignore=ignore_patterns('*.svn', 'doc', '*.py', '*.gypi', '*.sh',
+                                    '.gitignore', 'packages'))
+
+def CopyDartdocResources(home, sdk_root):
   RESOURCE_DIR = join(sdk_root, 'bin', 'snapshots', 'resources')
   DARTDOC = join(RESOURCE_DIR, 'dartdoc')
 
@@ -149,7 +159,13 @@
   PACKAGES_FILE = join(DARTDOC, '.packages')
   packages_file = open(PACKAGES_FILE, 'w')
   packages_file.write('dartdoc:.')
-  packages_file.close() 
+  packages_file.close()
+
+def CopyAnalysisSummaries(snapshots, lib):
+  copyfile(join(snapshots, 'spec.sum'),
+           join(lib, '_internal', 'spec.sum'))
+  copyfile(join(snapshots, 'strong.sum'),
+           join(lib, '_internal', 'strong.sum'))
 
 
 def Main():
@@ -282,8 +298,11 @@
 
   # Copy dart2js/pub.
   CopyDartScripts(HOME, SDK_tmp)
+
   CopySnapshots(SNAPSHOT, SDK_tmp)
   CopyDartdocResources(HOME, SDK_tmp)
+  CopyAnalyzerSources(HOME, LIB)
+  CopyAnalysisSummaries(SNAPSHOT, LIB)
 
   # Write the 'version' file
   version = utils.GetVersion()
diff --git a/tools/create_tarball.py b/tools/create_tarball.py
index 462bd9d..887bc86 100755
--- a/tools/create_tarball.py
+++ b/tools/create_tarball.py
@@ -40,8 +40,7 @@
 versiondir = ''
 
 # Ignore Git/SVN files, checked-in binaries, backup files, etc..
-ignoredPaths = ['tools/testing/bin',
-                'tools/sdks',
+ignoredPaths = ['tools/sdks',
                 'third_party/7zip', 'third_party/android_tools',
                 'third_party/clang', 'third_party/d8',
                 'third_party/firefox_jsshell']
diff --git a/tools/dartium/archive.py b/tools/dartium/archive.py
index 5f8bae8..973731d 100755
--- a/tools/dartium/archive.py
+++ b/tools/dartium/archive.py
@@ -21,7 +21,7 @@
   CONTENTSHELL_FILES = ['content_shell', 'content_shell.pak', 'fonts.conf',
                         'libffmpegsumo.so', 'libosmesa.so', 'lib',
                         'icudtl.dat', 'AHEM____.TTF', 'GardinerModBug.ttf',
-                        'GardinerModCat.ttf']
+                        'GardinerModCat.ttf', 'natives_blob.bin']
   CHROMEDRIVER_FILES = ['chromedriver']
 elif HOST_OS == 'win':
   # TODO: provide proper list.
diff --git a/tools/dartium/test.py b/tools/dartium/test.py
index d879d6e..0f16b41 100755
--- a/tools/dartium/test.py
+++ b/tools/dartium/test.py
@@ -183,8 +183,7 @@
     'arch': options.arch,
   }
 
-  test_script = os.path.join(srcpath, 'webkit', 'tools', 'layout_tests',
-                             'run_webkit_tests.py')
+  test_script = os.path.join(srcpath, 'third_party', 'WebKit', 'Tools', 'Scripts', 'run-webkit-tests')
 
   errors = False
   for component in components:
diff --git a/tools/dartium/update_deps.py b/tools/dartium/update_deps.py
index 6e27437..3370a24 100755
--- a/tools/dartium/update_deps.py
+++ b/tools/dartium/update_deps.py
@@ -41,8 +41,9 @@
 ########################################################################
 
 BRANCH_CURRENT="dart/dartium"
-BRANCH_NEXT="dart/dartium"
-BRANCH_MULTIVM="dart/multivm"
+BRANCH_NEXT="dart/2454_1"
+
+# (repo_name, deps_dir, repo_branch, prefix, repos, branch)
 
 TARGETS = {
   'dartium': (
@@ -56,9 +57,9 @@
     ),
   'integration': (
     # TODO(jacobr): what is the git repo for integration if any?
-    'https://dart.googlecode.com/svn/branches/dartium_integration/deps/dartium.deps',
+    'git@github.com:dart-lang/sdk.git',
     'tools/deps/dartium.deps',
-    'origin/master',
+    'origin/integration',
     'dartium',
     # TODO(vsm): Reenable 'chromium'
     ['webkit'],
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index fbb0e6b..0105c11 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -8,13 +8,9 @@
 # Now we need to override some settings and add some new ones.
 
 vars.update({
-  "chromium_url": "http://src.chromium.org/svn",
-  "dartium_base": "http://src.chromium.org",
-  "dartium_chromium_branch": "master",
-  "dartium_chromium_commit": "62a7524d4f71c9e0858d24b0aa1bbff3a2d09bff",
-  "chromium_base_revision": "297060",
-  "dartium_webkit_branch": "/blink/branches/dart/dartium",
-  "dartium_webkit_revision": "202748",
+  "dartium_chromium_commit": "8df9de5a8f073d9c0feadf8d652408807e4a254e",
+  "dartium_webkit_commit": "28b9a6c03797eaecf6c92677cba747eb9df0787c",
+  "chromium_base_revision": "338390",
 
   # We use mirrors of all github repos to guarantee reproducibility and
   # consistency between what users see and what the bots see.
@@ -69,39 +65,19 @@
   "yaml_rev": "@563a5ffd4a800a2897b8f4dd6b19f2a370df2f2b",
   "zlib_rev": "@c3d0a6190f2f8c924a05ab6cc97b8f975bddd33f",
   "web_components_rev": "@0e636b534d9b12c9e96f841e6679398e91a986ec",
-  "WebCore_rev": "@4f90b41b0165f23f412cecdba07b7d81d3fbb5b5",
+  "WebCore_rev": "@a86fe28efadcfc781f836037a80f27e22a5dad17",
 
   "co19_rev": "@3ed795ea02e022ef19c77cf1b6095b7c8f5584d0",
 })
 
-def massage_deps(deps):
-  for key, value in deps.items():
-    if value is None: continue
-
-    if value.startswith('/trunk'):
-      deps[key] = Var("chromium_url") + value
-      continue
-
-    if value.startswith(Var("webkit_trunk")):
-      path, revision = value.split('@') # and svn revision.
-      path = path[len(Var("webkit_trunk")):]  # Strip WebKit repo.
-      value = (Var("dartium_base") + Var("dartium_webkit_branch") + path +
-               '@' + Var("dartium_webkit_revision"))
-      deps[key] = value
-      continue
-
-massage_deps(deps)
-for os_deps in deps_os.values():
-  massage_deps(os_deps)
-
 deps.update({
   "src":
     Var("chromium_git") + "/dart/dartium/src.git" + "@" +
         Var("dartium_chromium_commit"),
 
   "src/third_party/WebKit":
-    Var("dartium_base") + Var("dartium_webkit_branch") + "@" +
-        Var("dartium_webkit_revision"),
+    Var("chromium_git") + "/dart/dartium/blink.git" + "@" +
+        Var("dartium_webkit_commit"),
 
   "src/dart/third_party/pkg/args":
       (Var("github_mirror") % "args") + Var("args_tag"),
@@ -232,20 +208,6 @@
       Var('webkit_revision') + "\\n')" ],
 })
 hooks.append({
-  "name": "checked_in_dart_binaries",
-  "pattern": ".",
-  "action": [
-    "download_from_google_storage",
-    "--no_auth",
-    "--no_resume",
-    "--bucket",
-    "dart-dependencies",
-    "--recursive",
-    "--directory",
-    "src/dart/tools/testing/bin",
-  ],
-})
-hooks.append({
   "name": "checked_in_dart_sdks",
   "pattern": ".",
   "action": [
diff --git a/tools/deps/dartium.deps/DEPS.chromium b/tools/deps/dartium.deps/DEPS.chromium
index c4117a5..4abb484 100644
--- a/tools/deps/dartium.deps/DEPS.chromium
+++ b/tools/deps/dartium.deps/DEPS.chromium
@@ -1,81 +1,76 @@
-# This file is automatically processed to create .DEPS.git which is the file
-# that gclient uses under git.
+# This file is used to manage the dependencies of the Chromium src repo. It is
+# used by gclient to determine what version of each dependency to check out, and
+# where.
 #
-# See http://code.google.com/p/chromium/wiki/UsingGit
-#
-# To test manually, run:
-#   python tools/deps2git/deps2git.py -o .DEPS.git -w <gclientdir>
-# where <gcliendir> is the absolute path to the directory containing the
-# .gclient file (the parent of 'src').
-#
-# Then commit .DEPS.git locally (gclient doesn't like dirty trees) and run
-#   gclient sync
-# Verify the thing happened you wanted. Then revert your .DEPS.git change
-# DO NOT CHECK IN CHANGES TO .DEPS.git upstream. It will be automatically
-# updated by a bot when you modify this one.
+# For more information, please refer to the official documentation:
+#   https://sites.google.com/a/chromium.org/dev/developers/how-tos/get-the-code
 #
 # When adding a new dependency, please update the top-level .gitignore file
 # to list the dependency's destination directory.
+#
+# -----------------------------------------------------------------------------
+# Rolling deps
+# -----------------------------------------------------------------------------
+# All repositories in this file are git-based, using Chromium git mirrors where
+# necessary (e.g., a git mirror is used when the source project is SVN-based).
+# To update the revision that Chromium pulls for a given dependency:
+#
+#  # Create and switch to a new branch
+#  git new-branch depsroll
+#  # Run roll-dep (provided by depot_tools) giving the dep's path and the
+#  # desired SVN revision number (e.g., third_party/foo/bar and a revision such
+#  # number from Subversion)
+#  roll-dep third_party/foo/bar REVISION_NUMBER
+#  # You should now have a modified DEPS file; commit and upload as normal
+#  git commit -a
+#  git cl upload
+
 
 vars = {
   # Use this googlecode_url variable only if there is an internal mirror for it.
   # If you do not know, use the full path while defining your new deps entry.
   'googlecode_url': 'http://%s.googlecode.com/svn',
-  'sourceforge_url': 'http://svn.code.sf.net/p/%(repo)s/code',
-  'llvm_url': 'http://src.chromium.org/llvm-project',
-  'llvm_git': 'https://llvm.googlesource.com',
-  'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d',
-  'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95',
-  'webkit_trunk': 'http://src.chromium.org/blink/trunk',
-  'webkit_revision': '889f35a63b23d86c0f318af9a65a875117811cfd', # from svn revision 182778
+  'webkit_revision': 'abaaf1d0b6b6483140b5dca34e80fc259833ddf7', # from svn revision 198714
   'chromium_git': 'https://chromium.googlesource.com',
-  'chromiumos_git': 'https://chromium.googlesource.com/chromiumos',
-  'pdfium_git': 'https://pdfium.googlesource.com',
-  'skia_git': 'https://skia.googlesource.com',
-  'boringssl_git': 'https://boringssl.googlesource.com',
-  'libvpx_revision': 'efe9712d52c2d216fb3d1ceb508b8148847a7e4b',
+  'libvpx_revision': '96484d320036bbc1e30f1dea232799a3e0517b1d',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': 'b5fae93d72c7b6480f83fd8a7b534cd1fdfcd49a',
+  'skia_revision': 'ea561bf055bb803f4c10ca323ea60a9d94da7956',
   # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling Skia
-  # and V8 without interference from each other.
-  'v8_branch': 'trunk',
-  'v8_revision': '5830436a84f7792f61451af9bccd991d923fe81c', # from svn revision 24223
-  # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling WebRTC
-  # and V8 without interference from each other.
+  # the commit queue can handle CLs rolling V8
+  # and whatever else without interference from each other.
+  'v8_revision': '7f211533faba9dd85708b1394186c7fe99b88392',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
-  'swarming_revision': '79940aeeec0ace78ade0fec27515850268761af5',
+  'swarming_revision': 'b39a448d8522392389b28f6997126a6ab04bfe87',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  "angle_revision": "df647a2a354d5dc9affdd6a982fccb6b95d361b0",
+  'angle_revision': '44897140a2ae07dc5ba88190100179baa6fe7914',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
-  'buildtools_revision': '56bc51aff4175d3fa27dcd0faa2c345ab046c8a5',
+  'buildtools_revision': 'ecc8e253abac3b6186a97573871a084f4c0ca3ae',
   # Three lines of non-changing comments so that
-  # the commit queue can handle CLs rolling PDFIum
+  # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '7a649fe262d77f93ad3213f53e973a7665d95a23',
+  'pdfium_revision': 'cc2323f0d0d626edac4a426097eb38b53ba54848',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
-  'openmax_dl_revision': '79e64bc9243e5ff11822434cf39b9fabefff3bfb',
+  'openmax_dl_revision': '22bb1085a6a0f6f3589a8c3d60ed0a9b82248275',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '01fe820ab957514f6b83e511492de1b3c03649d5',
+  'boringssl_revision': 'de24aadc5bc01130b6a9d25582203bb5308fabe1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nss
   # and whatever else without interference from each other.
-  'nss_revision': '87b96db4268293187d7cf741907a6d5d1d8080e0',
+  'nss_revision': 'aab0d08a298b29407397fbb1c4219f99e99431ed', # from svn revision 295435
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
-  'google_toolbox_for_mac_revision': 'a09526298f9dd1ec49d3b3ac5608d2a257b94cef',
+  'google_toolbox_for_mac_revision': 'ce47a231ea0b238fbe95538e86cc61d74c234be6', # from svn revision 705
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lighttpd
   # and whatever else without interference from each other.
@@ -83,11 +78,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling lss
   # and whatever else without interference from each other.
-  'lss_revision': '952107fa7cea0daaabead28c0e92d579bee517eb',
+  'lss_revision': '6f97298fe3794e92c8c896a6bc06e0b36e4c3de3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'c65c1ed84d500015273d5e72c6ddcebc2a23f9b8', # from svn revision r13797
+  'nacl_revision': 'b3d4cc125348924f727d3b87cee3674a839b54a0',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -96,11 +91,12 @@
   'chromium.googlesource.com',
   'boringssl.googlesource.com',
   'pdfium.googlesource.com',
+  'android.googlesource.com',
 ]
 
 deps = {
   'src/breakpad/src':
-   Var('chromium_git') + '/external/google-breakpad/src.git' + '@' + '35189355da4b65ed5e7692f790c240a9ab347731', # from svn revision 1387
+   Var('chromium_git') + '/external/google-breakpad/src.git' + '@' + '242fb9a38db6ba534b1f7daa341dd4d79171658b', # from svn revision 1471
 
   'src/buildtools':
    Var('chromium_git') + '/chromium/buildtools.git' + '@' +  Var('buildtools_revision'),
@@ -109,10 +105,10 @@
    Var('chromium_git') + '/external/open-vcdiff.git' + '@' + '438f2a5be6d809bc21611a94cd37bfc8c28ceb33', # from svn revision 41
 
   'src/testing/gtest':
-   Var('chromium_git') + '/external/googletest.git' + '@' + '4650552ff637bb44ecf7784060091cbed3252211', # from svn revision 692
+   Var('chromium_git') + '/external/googletest.git' + '@' + '23574bf2333f834ff665f894c97bef8a5b33a0a9', # from svn revision 711
 
   'src/testing/gmock':
-   Var('chromium_git') + '/external/googlemock.git' + '@' + '896ba0e03f520fb9b6ed582bde2bd00847e3c3f2', # from svn revision 485
+   Var('chromium_git') + '/external/googlemock.git' + '@' + '29763965ab52f24565299976b936d1265cb6a271', # from svn revision 501
 
   'src/third_party/angle':
    Var('chromium_git') + '/angle/angle.git' + '@' +  Var('angle_revision'),
@@ -120,47 +116,38 @@
   'src/third_party/colorama/src':
    Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8',
 
+  'src/third_party/crashpad/crashpad':
+   Var('chromium_git') + '/crashpad/crashpad.git' + '@' + '797adb320680a4a8ad39428075cca287e04b111f',
+
   'src/third_party/trace-viewer':
-   Var('chromium_git') + '/external/trace-viewer.git' + '@' + '76a4496033c164d8be9ee8c57f702b0859cb1911',
+   Var('chromium_git') + '/external/trace-viewer.git' + '@' + '4f30209abd53c699c937519f39ce41888f93507b',
 
   'src/third_party/WebKit':
    Var('chromium_git') + '/chromium/blink.git' + '@' +  Var('webkit_revision'),
 
   'src/third_party/icu':
-   Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + 'd2abf6c1e1f986f4a8db0341b8a8c55c55ec1174', # from svn revision 292003
+   Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'c81a1a3989c3b66fa323e9a6ee7418d7c08297af',
 
   'src/third_party/libexif/sources':
    Var('chromium_git') + '/chromium/deps/libexif/sources.git' + '@' + 'ed98343daabd7b4497f97fda972e132e6877c48a',
 
-  'src/third_party/hunspell':
-   Var('chromium_git') + '/chromium/deps/hunspell.git' + '@' + 'c956c0e97af00ef789afb2f64d02c9a5a50e6eb1',
-
   'src/third_party/hunspell_dictionaries':
-   Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '4560bdd463a3500e2334e85c8a0e9e5d5d6774e7',
+   Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'c106afdcec5d3de2622e19f1b3294c47bbd8bd72',
 
   'src/third_party/safe_browsing/testing':
     Var('chromium_git') + '/external/google-safe-browsing/testing.git' + '@' + '9d7e8064f3ca2e45891470c9b5b1dce54af6a9d6',
 
-  'src/third_party/cacheinvalidation/src':
-    Var('chromium_git') + '/external/google-cache-invalidation-api/src.git' + '@' + 'c91bd9d9fed06bf440be64f87b94a2effdb32bc4', # from svn revision 341
-
   'src/third_party/leveldatabase/src':
-    Var('chromium_git') + '/external/leveldb.git' + '@' + '3f77584eb3f9754bbb7079070873ece3f30a1e6b',
-
-  'src/third_party/libc++/trunk':
-   Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' +  Var('libcxx_revision'),
-
-  'src/third_party/libc++abi/trunk':
-   Var('chromium_git') + '/chromium/llvm-project/libcxxabi.git' + '@' +  Var('libcxxabi_revision'),
+    Var('chromium_git') + '/external/leveldb.git' + '@' + '40c17c0b84ac0b791fb434096fd5c05f3819ad55',
 
   'src/third_party/snappy/src':
     Var('chromium_git') + '/external/snappy.git' + '@' + '762bb32f0c9d2f31ba4958c7c0933d22e80c20bf',
 
   'src/tools/grit':
-    Var('chromium_git') + '/external/grit-i18n.git' + '@' + '740badd5e3e44434a9a47b5d16749daac1e8ea80', # from svn revision 176
+    Var('chromium_git') + '/external/grit-i18n.git' + '@' + '1dac9ae64b0224beb1547810933a6f9998d0d55e', # from svn revision 191
 
   'src/tools/gyp':
-    Var('chromium_git') + '/external/gyp.git' + '@' + '46282cedf40ff7fe803be4af357b9d59050f02e4', # from svn revision 1977
+    Var('chromium_git') + '/external/gyp.git' + '@' + '5122240c5e5c4d8da12c543d82b03d6089eb77c5',
 
   'src/tools/swarming_client':
    Var('chromium_git') + '/external/swarming.client.git' + '@' +  Var('swarming_revision'),
@@ -171,21 +158,12 @@
   'src/native_client':
    Var('chromium_git') + '/native_client/src/native_client.git' + '@' + Var('nacl_revision'),
 
-  'src/chrome/test/data/extensions/api_test/permissions/nacl_enabled/bin':
-   Var('chromium_git') + '/native_client/src/native_client/tests/prebuilt.git' + '@' + '3e17365176c94624f46cace174f61834b7f3c35d',
-
   'src/third_party/sfntly/cpp/src':
     Var('chromium_git') + '/external/sfntly/cpp/src.git' + '@' +  Var('sfntly_revision'),
 
   'src/third_party/skia':
    Var('chromium_git') + '/skia.git' + '@' +  Var('skia_revision'),
 
-  'src/third_party/ots':
-    Var('chromium_git') + '/external/ots.git' + '@' + '98897009f3ea8a5fa3e20a4a74977da7aaa8e61a',
-
-  'src/third_party/brotli/src':
-   Var('chromium_git') + '/external/font-compression-reference.git' + '@' + '6cef49677dc4c650ef6e3f56041e0a41803afa8c',
-
   'src/tools/page_cycler/acid3':
    Var('chromium_git') + '/chromium/deps/acid3.git' + '@' + '6be0a66a1ebd7ebc5abc1b2f405a945f6d871521',
 
@@ -199,10 +177,7 @@
     Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0',
 
   'src/third_party/webgl/src':
-   Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'b1a7210dc4034793e34a2149cb571e85700a85f2',
-
-  'src/third_party/swig/Lib':
-   Var('chromium_git') + '/chromium/deps/swig/Lib.git' + '@' + 'f2a695d52e61e6a8d967731434f165ed400f0d69',
+   Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '8986f8bfa84547b1a30a9256ebdd665024d68d71',
 
   'src/third_party/webdriver/pylib':
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
@@ -211,28 +186,25 @@
    Var('chromium_git') + '/chromium/deps/libvpx.git' + '@' +  Var('libvpx_revision'),
 
   'src/third_party/ffmpeg':
-   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '438ff61fe51641665f0ec3bc55e7b416d0aa251a',
+   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'f76066ad9f4aea07a53890b54d24cc22830b9efd',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '40539b82d5a2c9bcf23d078e997ce0368160f5a3',
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'f7c923ddc729dc7f002b0e194ab72b661f932c00', # commit position 9564
 
   'src/third_party/usrsctp/usrsctplib':
-    Var('chromium_git') + '/external/usrsctplib.git' + '@' + '8975bd5397c2ec97f50e0b87b544054e0536bfe1',
+    Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215
 
   'src/third_party/libsrtp':
-   Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '98284c8600c73812ff4716a6ea157d1e11d417dc',
-
-  'src/third_party/speex':
-   Var('chromium_git') + '/chromium/deps/speex.git' + '@' + '5260621c36c227209c7ba64ea71ca3418cf9e2b4',
+   Var('chromium_git') + '/chromium/deps/libsrtp.git' + '@' + '9c53f858cddd4d890e405e91ff3af0b48dfd90e6', # from svn revision 295151
 
   'src/third_party/yasm/source/patched-yasm':
-   Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'c960eb11ccda80b10ed50be39df4f0663b371d1d',
+   Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + '4671120cd8558ce62ee8672ebf3eb6f5216f909b',
 
   'src/third_party/libjpeg_turbo':
-   Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + '034e9a9747e0983bc19808ea70e469bc8342081f',
+   Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'f4631b6ee8b1dbb05e51ae335a7886f9ac598ab6',
 
   'src/third_party/flac':
-   Var('chromium_git') + '/chromium/deps/flac.git' + '@' + '0635a091379d9677f1ddde5f2eec85d0f096f219',
+   Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'c291ce676d2c855f7b2739f00f5c7f7e813813dc',
 
   'src/third_party/pyftpdlib/src':
     Var('chromium_git') + '/external/pyftpdlib.git' + '@' + '2be6d65e31c7ee6320d059f581f05ae8d89d7e45',
@@ -241,38 +213,36 @@
    Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '53545bbfc47f2cddb7038395369a0dcd457c8b34',
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '847b12a225694e10425c8a9b31e0eec028baf841', # commit position 9565
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
 
-  'src/third_party/jsoncpp/source/include':
-    Var('chromium_git') + '/external/jsoncpp/jsoncpp/include.git' + '@' + 'b0dd48e02b6e6248328db78a65b5c601f150c349',
-
-  'src/third_party/jsoncpp/source/src/lib_json':
-    Var('chromium_git') + '/external/jsoncpp/jsoncpp/src/lib_json.git' + '@' + 'a8caa51ba2f80971a45880425bf2ae864a786784',
+  'src/third_party/jsoncpp/source':
+    Var('chromium_git') + '/external/github.com/open-source-parsers/jsoncpp.git' + '@' + 'f572e8e42e22cfcf5ab0aea26574f408943edfa4', # from svn 248
 
   'src/third_party/libyuv':
-    Var('chromium_git') + '/external/libyuv.git' + '@' + '455c66b4375d72984b79249616d0a708ad568894',
+    Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '0e83b64e8879e9469919dc96b5d970c7c5bd05af', # from version 1444
 
   'src/third_party/smhasher/src':
     Var('chromium_git') + '/external/smhasher.git' + '@' + 'e87738e57558e0ec472b2fc3a643b838e5b6e88f',
 
   'src/third_party/libaddressinput/src':
-    Var('chromium_git') + '/external/libaddressinput.git' + '@' + '945d96387a716d0d82b195fa69a5e9a701249517', # from svn revision 334
+    Var('chromium_git') + '/external/libaddressinput.git' + '@' + '5eeeb797e79fa01503fcdcbebdc50036fac023ef',
 
+  # These are all at libphonenumber r728.
   'src/third_party/libphonenumber/src/phonenumbers':
-    Var('chromium_git') + '/external/libphonenumber/cpp/src/phonenumbers.git' + '@' + '8d8b5b3b2035197795d27573d4cf566b5d9ad689',
+    Var('chromium_git') + '/external/libphonenumber/cpp/src/phonenumbers.git' + '@' + '0d6e3e50e17c94262ad1ca3b7d52b11223084bca',
   'src/third_party/libphonenumber/src/test':
-    Var('chromium_git') + '/external/libphonenumber/cpp/test.git' + '@' + '883b7b86541d64b2691f7c0e65facb0b08db73e8',
+    Var('chromium_git') + '/external/libphonenumber/cpp/test.git' + '@' + 'f351a7e007f9c9995494499120bbc361ca808a16',
   'src/third_party/libphonenumber/src/resources':
-    Var('chromium_git') + '/external/libphonenumber/resources.git' + '@' + 'de095548d2ae828a414e01f3951bfefba902b4e4',
+    Var('chromium_git') + '/external/libphonenumber/resources.git' + '@' + 'b6dfdc7952571ff7ee72643cd88c988cbe966396',
 
   'src/tools/deps2git':
    Var('chromium_git') + '/chromium/tools/deps2git.git' + '@' + 'f04828eb0b5acd3e7ad983c024870f17f17b06d9',
 
   'src/third_party/webpagereplay':
-   Var('chromium_git') + '/external/web-page-replay.git' + '@' + '2f7b704b8b567983c040f555d3e46f9766db8e87',
+   Var('chromium_git') + '/external/github.com/chromium/web-page-replay.git' + '@' + '5da5975950daa7b30a6938da73fd0b3200901b0c',
 
   'src/third_party/pywebsocket/src':
     Var('chromium_git') + '/external/pywebsocket/src.git' + '@' + 'cb349e87ddb30ff8d1fa1a89be39cec901f4a29c',
@@ -281,25 +251,25 @@
    Var('chromium_git') + '/chromium/deps/opus.git' + '@' + 'cae696156f1e60006e39821e79a1811ae1933c69',
 
   'src/media/cdm/ppapi/api':
-   Var('chromium_git') + '/chromium/cdm.git' + '@' + '41c8183a3966a17b440dbe606cb2840e1b7ce884',
+   Var('chromium_git') + '/chromium/cdm.git' + '@' + '7377023e384f296cbb27644eb2c485275f1f92e8', # from svn revision 294518
 
   'src/third_party/mesa/src':
-   Var('chromium_git') + '/chromium/deps/mesa.git' + '@' + '457812d99a213dedf1c4cd38018ff48118d0c44f',
+   Var('chromium_git') + '/chromium/deps/mesa.git' + '@' + '071d25db04c23821a12a8b260ab9d96a097402f0',
 
   'src/third_party/cld_2/src':
-    Var('chromium_git') + '/external/cld2.git' + '@' + 'bb5c092e8c02dcc2319c5056aff2182199d51c2f',
-
-  'src/chrome/browser/resources/pdf/html_office':
-    Var('chromium_git') + '/chromium/html-office-public.git' + '@' + 'eeff97614f65e0578529490d44d412032c3d7359',
-
-  'src/third_party/libwebm/source':
-   Var('chromium_git') + '/webm/libwebm.git' + '@' + '0d4cb404ea4195e5e21d04db2c955615535ce62e',
+    Var('chromium_git') + '/external/cld2.git' + '@' + '14d9ef8d4766326f8aa7de54402d1b9c782d4481', # from svn revision 193
 
   'src/third_party/pdfium':
    'https://pdfium.googlesource.com/pdfium.git' + '@' +  Var('pdfium_revision'),
 
   'src/third_party/boringssl/src':
    'https://boringssl.googlesource.com/boringssl.git' + '@' +  Var('boringssl_revision'),
+
+  'src/third_party/py_trace_event/src':
+    Var('chromium_git') + '/external/py_trace_event.git' + '@' + 'dd463ea9e2c430de2b9e53dea57a77b4c3ac9b30',
+
+  'src/third_party/dom_distiller_js/dist':
+    Var('chromium_git') + '/external/github.com/chromium/dom-distiller-dist.git' + '@' + '81e5b59da2a7a0a518b90b5ded58670322c98128',
 }
 
 
@@ -334,9 +304,6 @@
     'src/third_party/nss':
      Var('chromium_git') + '/chromium/deps/nss.git' + '@' + Var('nss_revision'),
 
-    'src/third_party/swig/win':
-     Var('chromium_git') + '/chromium/deps/swig/win.git' + '@' + '986f013ba518541adf5c839811efb35630a31031',
-
     # GNU binutils assembler for x86-32.
     'src/third_party/gnu_binutils':
       Var('chromium_git') + '/native_client/deps/third_party/gnu_binutils.git' + '@' + 'f4003433b61b25666565690caf3d7a7a1a4ec436',
@@ -351,8 +318,15 @@
     # Binaries for nacl sdk.
     'src/third_party/nacl_sdk_binaries':
      Var('chromium_git') + '/chromium/deps/nacl_sdk_binaries.git' + '@' + '759dfca03bdc774da7ecbf974f6e2b84f43699a5',
+
+    # ANGLE uses dEQP for GPU testing
+    'src/third_party/deqp/src':
+     'https://android.googlesource.com/platform/external/deqp@194294e69d44eac48bc1fb063bd607189650aa5e',
   },
   'ios': {
+    'src/ios/third_party/gcdwebserver/src':
+     Var('chromium_git') + '/external/github.com/swisspol/GCDWebServer.git' + '@' + '3d5fd0b8281a7224c057deb2d17709b5bea64836',
+
     'src/third_party/google_toolbox_for_mac/src':
       Var('chromium_git') + '/external/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
 
@@ -360,45 +334,16 @@
      Var('chromium_git') + '/chromium/deps/nss.git' + '@' + Var('nss_revision'),
 
     # class-dump utility to generate header files for undocumented SDKs
-    'src/testing/iossim/third_party/class-dump':
-     Var('chromium_git') + '/chromium/deps/class-dump.git' + '@' + '89bd40883c767584240b4dade8b74e6f57b9bdab',
+    'src/third_party/class-dump/src':
+     Var('chromium_git') + '/external/github.com/nygard/class-dump.git' + '@' + '93e7c6a5419380d89656dcc511dc60d475199b67',
 
     # Code that's not needed due to not building everything
-    'src/build/util/support': None,
-    'src/chrome/test/data/extensions/api_test/permissions/nacl_enabled/bin': None,
     'src/chrome/test/data/perf/canvas_bench': None,
     'src/chrome/test/data/perf/frame_rate/content': None,
-    'src/media/cdm/ppapi/api': None,
     'src/native_client': None,
-    'src/third_party/bidichecker': None,
-    'src/third_party/brotli/src': None,
-    'src/third_party/cld_2/src': None,
     'src/third_party/ffmpeg': None,
     'src/third_party/hunspell_dictionaries': None,
-    'src/third_party/hunspell': None,
-    'src/third_party/libc++/trunk': None,
-    'src/third_party/libc++abi/trunk': None,
-    'src/third_party/libexif/sources': None,
-    'src/third_party/libjpeg_turbo': None,
-    'src/third_party/libsrtp': None,
-    'src/third_party/opus/src': None,
-    'src/third_party/openmax_dl': None,
-    'src/third_party/ots': None,
-    'src/third_party/pymox/src': None,
-    'src/third_party/safe_browsing/testing': None,
-    'src/third_party/scons-2.0.1': None,
-    'src/third_party/sfntly/cpp/src': None,
-    'src/third_party/speex': None,
-    'src/third_party/swig/Lib': None,
-    'src/third_party/usrsctp/usrsctplib': None,
-    'src/third_party/v8-i18n': None,
-    'src/third_party/webdriver/pylib': None,
     'src/third_party/webgl': None,
-    'src/third_party/webpagereplay': None,
-    'src/third_party/WebKit/LayoutTests/w3c/web-platform-tests': None,
-    'src/third_party/WebKit/LayoutTests/w3c/csswg-test': None,
-    'src/third_party/yasm/source/patched-yasm': None,
-    'src/tools/page_cycler/acid3': None,
   },
   'mac': {
     'src/chrome/tools/test/reference_build/chrome_mac':
@@ -414,9 +359,6 @@
     'src/third_party/lighttpd':
      Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'),
 
-    'src/third_party/swig/mac':
-     Var('chromium_git') + '/chromium/deps/swig/mac.git' + '@' + '1b182eef16df2b506f1d710b34df65d55c1ac44e',
-
     # NSS, for SSLClientSocketNSS.
     'src/third_party/nss':
      Var('chromium_git') + '/chromium/deps/nss.git' + '@' + Var('nss_revision'),
@@ -432,58 +374,59 @@
     'src/third_party/xdg-utils':
      Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
 
-    'src/third_party/swig/linux':
-     Var('chromium_git') + '/chromium/deps/swig/linux.git' + '@' + '866b8e0e0e0cfe99ebe608260030916ca0c3f92d',
-
     'src/third_party/lss':
       Var('chromium_git') + '/external/linux-syscall-support/lss.git' + '@' + Var('lss_revision'),
 
     # For Linux and Chromium OS.
     'src/third_party/cros_system_api':
-     Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'f0fc55329fa536195861778a2ddc6115b4a977bc',
+     Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '513f58ccbcecfd4a3d21545f67136090838eaf52',
 
     # Note that this is different from Android's freetype repo.
     'src/third_party/freetype2/src':
-     Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + 'd699c2994ecc178c4ed05ac2086061b2034c2178',
+     Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + '1dd5f5f4a909866f15c92a45c9702bce290a0151',
 
     # Build tools for Chrome OS.
     'src/third_party/chromite':
-     Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8e92d5c24da7967e27ab2498abc2d2f7ac6ec65a',
+     Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e19f83ba227bf1ec0077f5d3a816a415f1dd88d0',
 
     # Dependency of chromite.git.
     'src/third_party/pyelftools':
      Var('chromium_git') + '/chromiumos/third_party/pyelftools.git' + '@' + 'bdc1d380acd88d4bfaf47265008091483b0d614e',
 
-    'src/third_party/undoview':
-     Var('chromium_git') + '/chromium/deps/undoview.git' + '@' + '3ba503e248f3cdbd81b78325a24ece0984637559',
-
     'src/third_party/liblouis/src':
      Var('chromium_git') + '/external/liblouis-github.git' + '@' + '5f9c03f2a3478561deb6ae4798175094be8a26c2',
 
     # Used for embedded builds. CrOS & Linux use the system version.
     'src/third_party/fontconfig/src':
      Var('chromium_git') + '/external/fontconfig.git' + '@' + 'f16c3118e25546c1b749f9823c51827a60aeb5c1',
+
+    'src/third_party/stp/src':
+     Var('chromium_git') + '/external/github.com/stp/stp.git' + '@' + 'fc94a599207752ab4d64048204f0c88494811b62',
   },
   'android': {
     'src/third_party/android_protobuf/src':
-     Var('chromium_git') + '/external/android_protobuf.git' + '@' + '94f522f907e3f34f70d9e7816b947e62fddbb267',
-
-    # Whenever you roll this please also change frameworks/webview in
-    # src/android_webview/buildbot/aosp_manifest.xml to point to the same revision.
-    'src/third_party/android_webview_glue/src':
-     Var('chromium_git') + '/external/android_webview_glue.git' + '@' + 'a1b0248c80f239e2f6476b9f395b27d0ba1eb3cd',
+     Var('chromium_git') + '/external/android_protobuf.git' + '@' + '999188d0dc72e97f7fe08bb756958a2cf090f4e7',
 
     'src/third_party/android_tools':
-     Var('chromium_git') + '/android_tools.git' + '@' + 'd2b86205ff973a3844020feacb35ca6b1d82efbe',
+     Var('chromium_git') + '/android_tools.git' + '@' + '21f4bcbd6cd927e4b4227cfde7d5f13486be1236',
 
     'src/third_party/apache-mime4j':
      Var('chromium_git') + '/chromium/deps/apache-mime4j.git' + '@' + '28cb1108bff4b6cf0a2e86ff58b3d025934ebe3a',
 
+    'src/third_party/appurify-python/src':
+     Var('chromium_git') + '/external/github.com/appurify/appurify-python.git' + '@' + 'ee7abd5c5ae3106f72b2a0b9d2cb55094688e867',
+
+    'src/third_party/cardboard-java/src':
+     Var('chromium_git') + '/external/github.com/googlesamples/cardboard-java.git' + '@' + '08ad25a04f2801bd822c3f2cd28301b68d74aef6',
+
+    'src/third_party/errorprone/lib':
+      Var('chromium_git') + '/chromium/third_party/errorprone.git' + '@' + '6c66e56c0f9d750aef83190466df834f9d6af8ab',
+
     'src/third_party/findbugs':
      Var('chromium_git') + '/chromium/deps/findbugs.git' + '@' + '7f69fa78a6db6dc31866d09572a0e356e921bf12',
 
-    'src/third_party/freetype':
-     Var('chromium_git') + '/chromium/src/third_party/freetype.git' + '@' + 'a2b9955b49034a51dfbc8bf9f4e9d312149cecac',
+    'src/third_party/freetype-android/src':
+     Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + 'e186230678ee8e4ea4ac4797ece8125761e3225a',
 
    'src/third_party/elfutils/src':
      Var('chromium_git') + '/external/elfutils.git' + '@' + '249673729a7e5dbd5de4f3760bdcaa3d23d154d7',
@@ -501,19 +444,32 @@
       Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919',
 
     'src/third_party/junit/src':
-      Var('chromium_git') + '/external/junit.git' + '@' + 'c62e2df8dbecccb1b434d4ba8843b59e90b03266',
+      Var('chromium_git') + '/external/junit.git' + '@' + '45a44647e7306262162e1346b750c3209019f2e1',
+
+    'src/third_party/mockito/src':
+      Var('chromium_git') + '/external/mockito/mockito.git' + '@' + 'ed99a52e94a84bd7c467f2443b475a22fcc6ba8e',
+
+    'src/third_party/robolectric/lib':
+      Var('chromium_git') + '/chromium/third_party/robolectric.git' + '@' + '6b63c99a8b6967acdb42cbed0adb067c80efc810',
+
+    'src/third_party/ub-uiautomator/lib':
+      Var('chromium_git') + '/chromium/third_party/ub-uiautomator.git' + '@' + 'e6f02481bada8bdbdfdd7987dd6e648c44a3adcb',
 
     'src/third_party/lss':
       Var('chromium_git') + '/external/linux-syscall-support/lss.git' + '@' + Var('lss_revision'),
 
-    'src/third_party/eyesfree/src/android/java/src/com/googlecode/eyesfree/braille':
-      Var('chromium_git') + '/external/eyes-free/braille/client/src/com/googlecode/eyesfree/braille.git' + '@' + '77bf6edb0138e3a38a2772248696f130dab45e34',
+    'src/third_party/requests/src':
+      Var('chromium_git') + '/external/github.com/kennethreitz/requests.git' + '@' + 'f172b30356d821d180fa4ecfa3e71c7274a32de4',
+
+    'src/third_party/custom_tabs_client/src':
+      Var('chromium_git') + '/external/github.com/GoogleChrome/custom-tabs-client.git' + '@' + 'ef3ea193af9f4e45dd5094e8b6a952fb213bf11e',
   },
 }
 
 
 include_rules = [
   # Everybody can use some things.
+  # NOTE: THIS HAS TO STAY IN SYNC WITH third_party/DEPS which disallows these.
   '+base',
   '+build',
   '+ipc',
@@ -531,14 +487,11 @@
 # checkdeps.py shouldn't check include paths for files in these dirs:
 skip_child_includes = [
   'breakpad',
-  'delegate_execute',
-  'metro_driver',
   'native_client_sdk',
-  'o3d',
+  'out',
   'sdch',
   'skia',
   'testing',
-  'third_party',
   'v8',
   'win8',
 ]
@@ -563,42 +516,31 @@
     'name': 'nacltools',
     'pattern': '.',
     'action': [
-        'python', 'src/build/download_nacl_toolchains.py',
-        '--exclude', 'arm_trusted',
+        'python',
+        'src/build/download_nacl_toolchains.py',
+        '--mode', 'nacl_core_sdk',
+        'sync', '--extract',
     ],
   },
   {
-    # Downloads an ARM sysroot image to src/arm-sysroot. This image updates
-    # at about the same rate that the chrome build deps change.
-    # This script is a no-op except for linux users who have
-    # target_arch=arm in their GYP_DEFINES.
-    'name': 'sysroot',
+    # This downloads SDK extras and puts them in the
+    # third_party/android_tools/sdk/extras directory on the bots. Developers
+    # need to manually install these packages and accept the ToS.
+    'name': 'sdkextras',
     'pattern': '.',
-    'action': ['python', 'src/build/linux/install-arm-sysroot.py',
-               '--linux-only'],
+    # When adding a new sdk extras package to download, add the package
+    # directory and zip file to .gitignore in third_party/android_tools.
+    'action': ['python', 'src/build/download_sdk_extras.py'],
   },
   {
-    # Downloads the Debian Wheezy sysroot to chrome/installer/linux if needed.
+    # Downloads the current stable linux sysroot to build/linux/ if needed.
     # This sysroot updates at about the same rate that the chrome build deps
     # change. This script is a no-op except for linux users who are doing
-    # official chrome builds.
+    # official chrome builds or cross compiling.
     'name': 'sysroot',
     'pattern': '.',
-    'action': [
-        'python',
-        'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py',
-        '--linux-only',
-        '--arch=amd64'],
-  },
-  {
-    # Same as above, but for 32-bit Linux.
-    'name': 'sysroot',
-    'pattern': '.',
-    'action': [
-        'python',
-        'src/chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py',
-        '--linux-only',
-        '--arch=i386'],
+    'action': ['python', 'src/build/linux/sysroot_scripts/install-sysroot.py',
+               '--running-as-hook'],
   },
   {
     # Update the Windows toolchain if necessary.
@@ -606,6 +548,17 @@
     'pattern': '.',
     'action': ['python', 'src/build/vs_toolchain.py', 'update'],
   },
+  # Pull binutils for linux, enabled debug fission for faster linking /
+  # debugging when used with clang on Ubuntu Precise.
+  # https://code.google.com/p/chromium/issues/detail?id=352046
+  {
+    'name': 'binutils',
+    'pattern': 'src/third_party/binutils',
+    'action': [
+        'python',
+        'src/third_party/binutils/download.py',
+    ],
+  },
   {
     # Pull clang if needed or requested via GYP_DEFINES.
     # Note: On Win, this should run after win_toolchain, as it may use it.
@@ -614,16 +567,14 @@
     'action': ['python', 'src/tools/clang/scripts/update.py', '--if-needed'],
   },
   {
-    # Update LASTCHANGE. This is also run by export_tarball.py in
-    # src/tools/export_tarball - please keep them in sync.
+    # Update LASTCHANGE.
     'name': 'lastchange',
     'pattern': '.',
     'action': ['python', 'src/build/util/lastchange.py',
                '-o', 'src/build/util/LASTCHANGE'],
   },
   {
-    # Update LASTCHANGE.blink. This is also run by export_tarball.py in
-    # src/tools/export_tarball - please keep them in sync.
+    # Update LASTCHANGE.blink.
     'name': 'lastchange',
     'pattern': '.',
     'action': ['python', 'src/build/util/lastchange.py',
@@ -654,17 +605,6 @@
     ],
   },
   {
-    'name': 'gn_linux32',
-    'pattern': '.',
-    'action': [ 'download_from_google_storage',
-                '--no_resume',
-                '--platform=linux*',
-                '--no_auth',
-                '--bucket', 'chromium-gn',
-                '-s', 'src/buildtools/linux32/gn.sha1',
-    ],
-  },
-  {
     'name': 'gn_linux64',
     'pattern': '.',
     'action': [ 'download_from_google_storage',
@@ -709,15 +649,38 @@
                 '-s', 'src/buildtools/linux64/clang-format.sha1',
     ],
   },
-  # Pull binutils for linux, enabled debug fission for faster linking /
-  # debugging when used with clang on Ubuntu Precise.
-  # https://code.google.com/p/chromium/issues/detail?id=352046
+  # Pull luci-go binaries (isolate, swarming) using checked-in hashes.
   {
-    'name': 'binutils',
-    'pattern': 'src/third_party/binutils',
-    'action': [
-        'python',
-        'src/third_party/binutils/download.py',
+    'name': 'luci-go_win',
+    'pattern': '.',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--platform=win32',
+                '--no_auth',
+                '--bucket', 'chromium-luci',
+                '-d', 'src/tools/luci-go/win64',
+    ],
+  },
+  {
+    'name': 'luci-go_mac',
+    'pattern': '.',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--platform=darwin',
+                '--no_auth',
+                '--bucket', 'chromium-luci',
+                '-d', 'src/tools/luci-go/mac64',
+    ],
+  },
+  {
+    'name': 'luci-go_linux',
+    'pattern': '.',
+    'action': [ 'download_from_google_storage',
+                '--no_resume',
+                '--platform=linux*',
+                '--no_auth',
+                '--bucket', 'chromium-luci',
+                '-d', 'src/tools/luci-go/linux64',
     ],
   },
   # Pull eu-strip binaries using checked-in hashes.
@@ -750,7 +713,19 @@
     'action': ['python',
                'src/build/get_syzygy_binaries.py',
                '--output-dir=src/third_party/syzygy/binaries',
-               '--revision=363bc02a09c380b6f5f397606cc0744d85d54a51',
+               '--revision=e50a9822fc8aeb5e7902da5e2940ea135d732e57',
+               '--overwrite',
+    ],
+  },
+  {
+    'name': 'kasko',
+    'pattern': '.',
+    'action': ['python',
+               'src/build/get_syzygy_binaries.py',
+               '--output-dir=src/third_party/kasko',
+               '--revision=283aeaceeb22e2ba40a1753e3cb32454b59cc017',
+               '--resource=kasko.zip',
+               '--resource=kasko_symbols.zip',
                '--overwrite',
     ],
   },
@@ -768,6 +743,40 @@
                 'src/third_party/apache-win32',
     ],
   },
+  # Pull the mojo_shell binary, used for mojo development
+  {
+    'name': 'download_mojo_shell',
+    'pattern': '',
+    'action': [ 'python',
+                'src/third_party/mojo/src/mojo/public/tools/download_shell_binary.py',
+                '--tools-directory=../../../../../../tools',
+              ],
+  },
+  {
+    # Pull sanitizer-instrumented third-party libraries if requested via
+    # GYP_DEFINES.
+    'name': 'instrumented_libraries',
+    'pattern': '\\.sha1',
+    'action': ['python', 'src/third_party/instrumented_libraries/scripts/download_binaries.py'],
+  },
+  {
+    # Ensure that while generating dependencies lists in .gyp files we don't
+    # accidentally reference any .pyc files whose corresponding .py files have
+    # already been deleted.
+    # We should actually try to avoid generating .pyc files, crbug.com/500078.
+    'name': 'remove_stale_pyc_files',
+    'pattern': '.',
+    'action': [
+        'python',
+        'src/tools/remove_stale_pyc_files.py',
+        'src/android_webview/tools',
+        'src/gpu/gles2_conform_support',
+        'src/ppapi',
+        'src/printing',
+        'src/third_party/closure_compiler/build',
+        'src/tools',
+    ],
+  },
   {
     # A change to a .gyp, .gypi, or to GYP itself should run the generator.
     'name': 'gyp',
@@ -786,15 +795,4 @@
         '--running-as-hook',
     ],
   },
-  {
-    # Ensure that we don't accidentally reference any .pyc files whose
-    # corresponding .py files have already been deleted.
-    'name': 'remove_stale_pyc_files',
-    'pattern': 'src/tools/.*\\.py',
-    'action': [
-        'python',
-        'src/tools/remove_stale_pyc_files.py',
-        'src/tools',
-    ],
-  },
 ]
diff --git a/tools/dom/dom.py b/tools/dom/dom.py
index c69d065..1316ab1 100755
--- a/tools/dom/dom.py
+++ b/tools/dom/dom.py
@@ -148,7 +148,7 @@
   print('Browse tests at '
       '\033[94mhttp://localhost:%d/root_build/generated_tests/\033[0m' % port)
   return call([
-    utils.DartBinary(),
+    utils.CheckedInSdkExecutable(),
     os.path.join('tools', 'testing', 'dart', 'http_server.dart'),
     '--port=%d' % port,
     '--crossOriginPort=%d' % (port + 1),
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/new_scripts/dart_utilities.py b/tools/dom/new_scripts/dart_utilities.py
index f67437b..3972783 100644
--- a/tools/dom/new_scripts/dart_utilities.py
+++ b/tools/dom/new_scripts/dart_utilities.py
@@ -156,7 +156,6 @@
 DartUtilities.has_extended_attribute = v8_utilities.has_extended_attribute
 DartUtilities.has_extended_attribute_value = v8_utilities.has_extended_attribute_value
 DartUtilities.measure_as = _measure_as
-DartUtilities.per_context_enabled_function_name = v8_utilities.per_context_enabled_function_name
 DartUtilities.runtime_enabled_function_name = v8_utilities.runtime_enabled_function_name
 DartUtilities.scoped_name = _scoped_name
 DartUtilities.strip_suffix = v8_utilities.strip_suffix
diff --git a/tools/dom/new_scripts/dependency.py b/tools/dom/new_scripts/dependency.py
new file mode 100644
index 0000000..060277e
--- /dev/null
+++ b/tools/dom/new_scripts/dependency.py
@@ -0,0 +1,9 @@
+builder = None
+
+def set_builder(created_builder):
+  global builder;
+  builder = created_builder
+
+def get_interfaces_info():
+  global builder;
+  return builder._info_collector.interfaces_info
diff --git a/tools/dom/scripts/dartdomgenerator.py b/tools/dom/scripts/dartdomgenerator.py
index 5a35903..8194dfc 100755
--- a/tools/dom/scripts/dartdomgenerator.py
+++ b/tools/dom/scripts/dartdomgenerator.py
@@ -45,6 +45,7 @@
 import time
 from dartmetadata import DartMetadata
 from generator import TypeRegistry
+from generate_blink_file import Generate_Blink
 from htmleventgenerator import HtmlEventGenerator
 from htmlrenamer import HtmlRenamer
 from systemhtml import DartLibraryEmitter, Dart2JSBackend,\
@@ -78,8 +79,9 @@
     common_database.Load()
   return common_database
 
-def GenerateFromDatabase(common_database, dart2js_output_dir,
-                         dartium_output_dir, update_dom_metadata=False,
+def GenerateFromDatabase(common_database,
+                         dart2js_output_dir, dartium_output_dir, blink_output_dir,
+                         update_dom_metadata=False,
                          logging_level=logging.WARNING, dart_js_interop=False):
   print '\n ----- Accessing DOM using %s -----\n' % ('dart:js' if dart_js_interop else 'C++')
 
@@ -104,6 +106,7 @@
                              exclude_suppressed = ['WebKit', 'Dart'])
   generator.FixEventTargets(webkit_database)
   generator.AddMissingArguments(webkit_database)
+  generator.CleanupOperationArguments(webkit_database)
 
   emitters = multiemitter.MultiEmitter(logging_level)
   metadata = DartMetadata(
@@ -194,6 +197,14 @@
         webkit_database, dartium_output_dir, type_registry, renamer)
     emitters.Flush()
 
+  if blink_output_dir:
+    print '\nGenerating _blink:\n'
+    start_time = time.time()
+
+    Generate_Blink(blink_output_dir, webkit_database, type_registry)
+
+    print 'Generated _blink in %s seconds' % round(time.time() - start_time, 2)
+
   if update_dom_metadata:
     metadata.Flush()
 
@@ -222,8 +233,8 @@
                     help='Use fremontcut in parallel mode.')
   parser.add_option('--systems', dest='systems',
                     action='store', type='string',
-                    default='htmldart2js,htmldartium',
-                    help='Systems to generate (htmldart2js, htmldartium)')
+                    default='htmldart2js,htmldartium,_blink',
+                    help='Systems to generate (htmldart2js, htmldartium, _blink)')
   parser.add_option('--output-dir', dest='output_dir',
                     action='store', type='string',
                     default=None,
@@ -267,6 +278,9 @@
   dartium_output_dir = None
   if 'htmldartium' in systems:
     dartium_output_dir = os.path.join(output_dir, 'dartium')
+  blink_output_dir = None
+  if '_blink' in systems:
+    blink_output_dir = os.path.join(output_dir, 'dartium')
 
   logging_level = options.logging_level \
     if options.logging == logging.NOTSET else options.logging
@@ -278,8 +292,13 @@
   # Parse the IDL and create the database.
   database = fremontcutbuilder.main(options.parallel, logging_level=logging_level, examine_idls=options.examine_idls)
 
-  GenerateFromDatabase(database, dart2js_output_dir, dartium_output_dir,
-      options.update_dom_metadata, logging_level, options.dart_js_interop)
+  GenerateFromDatabase(database,
+                       dart2js_output_dir,
+                       dartium_output_dir,
+                       blink_output_dir,
+                       options.update_dom_metadata,
+                       logging_level,
+                       options.dart_js_interop)
 
   file_generation_start_time = time.time()
 
@@ -300,6 +319,14 @@
           os.path.join(dartium_output_dir, '%s_dartium.dart' % library_name),
           os.path.join('..', '..', '..', 'sdk', 'lib', library_name, 'dartium'))
 
+  if '_blink' in systems:
+    _logger.info('Generating dartium _blink file.')
+    file_generation_start_time = time.time()
+
+    GenerateSingleFile(
+        os.path.join(dartium_output_dir, '%s_dartium.dart' % '_blink'),
+        os.path.join('..', '..', '..', 'sdk', 'lib', '_blink', 'dartium'))
+
   print '\nGenerating single file %s seconds' % round(time.time() - file_generation_start_time, 2)
 
   end_time = time.time()
diff --git a/tools/dom/scripts/dartgenerator.py b/tools/dom/scripts/dartgenerator.py
index 1b8db33..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')
 
@@ -38,6 +39,10 @@
     if IsRegisteredType(type_name):
       return True
 
+    # References a typedef - normally a union type.
+    if database.HasTypeDef(type_name):
+      return True
+
     if type_name.endswith('?'):
       return self._IsCompoundType(database, type_name[:-len('?')])
 
@@ -240,3 +245,18 @@
 
         if 'ScriptArguments' in call_with:
           operation.arguments.append(ARG)
+
+  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/dartmetadata.py b/tools/dom/scripts/dartmetadata.py
index 3e16cf7..b90a2b3 100644
--- a/tools/dom/scripts/dartmetadata.py
+++ b/tools/dom/scripts/dartmetadata.py
@@ -371,7 +371,7 @@
     ],
 
     'WebGLRenderingContext.getContextAttributes': [
-      "@Creates('ContextAttributes|=Object')",
+      "@Creates('ContextAttributes|Null')",
     ],
 
     'XMLHttpRequest.response': [
diff --git a/tools/dom/scripts/database.py b/tools/dom/scripts/database.py
index fc8b659..7329b22 100755
--- a/tools/dom/scripts/database.py
+++ b/tools/dom/scripts/database.py
@@ -44,6 +44,8 @@
     self._interfaces_to_delete = []
     self._enums = {}
     self._all_dictionaries = {}
+    # TODO(terry): Hack to remember all typedef unions.
+    self._all_type_defs = {}
 
   def Clone(self):
     new_database = Database(self._root_dir)
@@ -52,6 +54,7 @@
         self._interfaces_to_delete)
     new_database._enums = copy.deepcopy(self._enums)
     new_database._all_dictionaries = copy.deepcopy(self._all_dictionaries)
+    new_database._all_type_defs = copy.deepcopy(self._all_type_defs)
 
     return new_database
 
@@ -282,30 +285,59 @@
       res.append(dictionary)
     return res
 
+  def HasTypeDef(self, type_def_name):
+    """Returns True if the typedef is in memory"""
+    return type_def_name in self._all_type_defs
+
+  def GetTypeDef(self, type_def_name):
+    """Returns an IDLTypeDef corresponding to the type_def_name
+    from memory.
+
+    Args:
+      type_def_name -- the name of the typedef.
+    """
+    if type_def_name not in self._all_type_defs:
+      raise RuntimeError('Typedef %s is not loaded' % type_def_name)
+    return self._all_type_defs[type_def_name]
+
+  def AddTypeDef(self, type_def):
+    """Add only a typedef that a unions they map to any (no type)."""
+    type_def_name = type_def.id
+    if type_def_name in self._all_type_defs:
+      raise RuntimeError('Typedef %s already exists' % type_def_name)
+    self._all_type_defs[type_def_name] = type_def
+    print '  Added typedef %s' % type_def_name
+
   def TransitiveSecondaryParents(self, interface, propagate_event_target):
     """Returns a list of all non-primary parents.
 
     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/databasebuilder.py b/tools/dom/scripts/databasebuilder.py
index f61b81b..ceb6eb1 100755
--- a/tools/dom/scripts/databasebuilder.py
+++ b/tools/dom/scripts/databasebuilder.py
@@ -20,9 +20,7 @@
 
 import compiler
 import compute_interfaces_info_individual
-from compute_interfaces_info_individual import compute_info_individual, info_individual
-import compute_interfaces_info_overall
-from compute_interfaces_info_overall import compute_interfaces_info_overall, interfaces_info
+from compute_interfaces_info_individual import InterfaceInfoCollector
 import idl_definitions
 
 from idlnode import *
@@ -132,7 +130,7 @@
         # Create compiler.
         self.idl_compiler = compiler.IdlCompilerDart(self.output_directory,
                                             attrib_file,
-                                            interfaces_info=interfaces_info,
+                                            interfaces_info=provider._info_collector.interfaces_info,
                                             only_if_changed=True)
 
     def format_exception(self, e):
@@ -168,13 +166,15 @@
   def __init__(self, database):
     """DatabaseBuilder is used for importing and merging interfaces into
     the Database"""
+    self._info_collector = InterfaceInfoCollector()
+
     self._database = database
     self._imported_interfaces = []
     self._impl_stmts = []
     self.conditionals_met = set()
 
     # Spin up the new IDL parser.
-    self.build = Build(None)
+    self.build = Build(self)
 
     # Global typedef to mapping.
     self.global_type_defs = monitored.Dict('databasebuilder.global_type_defs', {
@@ -186,13 +186,21 @@
   #              a type name.
   def _resolve_type_defs(self, idl_file):
     for type_node in idl_file.all(IDLType):
+      resolved = False
       type_name = type_node.id
       for typedef in self.global_type_defs:
         seq_name_typedef = 'sequence<%s>' % typedef
         if type_name == typedef:
           type_node.id = self.global_type_defs[typedef]
+          resolved = True
         elif type_name == seq_name_typedef:
           type_node.id = 'sequence<%s>' % self.global_type_defs[typedef]
+          resolved = True
+      if not(resolved):
+        for typedef in idl_file.typeDefs:
+          if type_name == typedef.id:
+            type_node.id = typedef.type.id
+            resolved = True
 
   def _strip_ext_attributes(self, idl_file):
     """Strips unuseful extended attributes."""
@@ -559,11 +567,11 @@
     if not(is_dart_idl):
       start_time = time.time()
 
-      # 2-stage computation: individual, then overall
+    # Compute information for individual files
+    # Information is stored in global variables interfaces_info and
+    # partial_interface_files.
       for file_path in file_paths:
-        compute_info_individual(file_path)
-      info_individuals = [info_individual()]
-      compute_interfaces_info_overall(info_individuals)
+        self._info_collector.collect_info(file_path)
 
       end_time = time.time()
       print 'Compute dependencies %s seconds' % round((end_time - start_time), 2)
@@ -572,7 +580,7 @@
       # file is special in that more than one interface can exist in this file.
       implement_pairs = self._compute_dart_idl_implements(file_paths[0])
 
-      interfaces_info['__dart_idl___'] = {
+      self._info_collector.interfaces_info['__dart_idl___'] = {
         'implement_pairs': implement_pairs,
       }
 
@@ -645,6 +653,10 @@
     for dictionary in idl_file.dictionaries:
       self._database.AddDictionary(dictionary)
 
+    # TODO(terry): Hack to remember all typedef unions they're mapped to any
+    #              - no type.
+    for typedef in idl_file.typeDefs:
+      self._database.AddTypeDef(typedef)
 
   def _is_node_enabled(self, node, idl_defines):
     if not 'Conditional' in node.ext_attrs:
diff --git a/tools/dom/scripts/fremontcutbuilder.py b/tools/dom/scripts/fremontcutbuilder.py
index ed11625..d368470 100755
--- a/tools/dom/scripts/fremontcutbuilder.py
+++ b/tools/dom/scripts/fremontcutbuilder.py
@@ -10,6 +10,7 @@
 import sys
 import time
 import utilities
+import dependency
 
 _logger = logging.getLogger('fremontcutbuilder')
 
@@ -50,6 +51,7 @@
   db.Delete()
 
   builder = databasebuilder.DatabaseBuilder(db)
+  dependency.set_builder(builder)
 
   # TODO(vsm): Move this to a README.
   # This is the Dart SVN revision.
diff --git a/tools/dom/scripts/generate_blink_file.py b/tools/dom/scripts/generate_blink_file.py
new file mode 100644
index 0000000..6f274da
--- /dev/null
+++ b/tools/dom/scripts/generate_blink_file.py
@@ -0,0 +1,331 @@
+#!/usr/bin/python
+#
+# 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.
+
+"""Generates sdk/lib/_blink/dartium/_blink_dartium.dart file."""
+
+import os
+
+from generator import AnalyzeOperation, AnalyzeConstructor
+
+HEADER = """/* 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.
+ *
+ * DO NOT EDIT
+ * Auto-generated _blink library.
+ */
+library dart.dom._blink;
+
+import 'dart:js' as js;
+import 'dart:html' show DomException;
+// This is a place to put custom renames if we need them.
+final resolverMap = {
+};
+
+dynamic resolver(String s) {
+"""
+
+END_RESOLVER = """
+  // Failed to find it, check for custom renames
+  dynamic obj = resolverMap[s];
+  if (obj != null) return obj;
+  throw("No such interface exposed in blink: ${s}");
+}
+
+"""
+
+BLINK_UTILS = """
+// _Utils native entry points
+class Blink_Utils {
+  static window() native "Utils_window";
+
+  static forwardingPrint(message) native "Utils_forwardingPrint";
+
+  static spawnDomUri(uri) native "Utils_spawnDomUri";
+
+  static void spawnDomHelper(Function f, int replyTo) native "Utils_spawnDomHelper";
+
+  static register(document, tag, customType, extendsTagName) native "Utils_register";
+
+  static createElement(document, tagName) native "Utils_createElement";
+
+  static constructElement(element_type, jsObject) native "Utils_constructor_create";
+
+  static initializeCustomElement(element) native "Utils_initializeCustomElement";
+
+  static changeElementWrapper(element, type) native "Utils_changeElementWrapper";
+}
+
+class Blink_DOMWindowCrossFrame {
+  // FIXME: Return to using explicit cross frame entry points after roll to M35
+  static get_history(_DOMWindowCrossFrame) native "Window_history_cross_frame_Getter";
+
+  static get_location(_DOMWindowCrossFrame) native "Window_location_cross_frame_Getter";
+
+  static get_closed(_DOMWindowCrossFrame) native "Window_closed_Getter";
+
+  static get_opener(_DOMWindowCrossFrame) native "Window_opener_Getter";
+
+  static get_parent(_DOMWindowCrossFrame) native "Window_parent_Getter";
+
+  static get_top(_DOMWindowCrossFrame) native "Window_top_Getter";
+
+  static close(_DOMWindowCrossFrame) native "Window_close_Callback";
+
+  static postMessage(_DOMWindowCrossFrame, message, targetOrigin, [messagePorts]) native "Window_postMessage_Callback";
+}
+
+class Blink_HistoryCrossFrame {
+  // _HistoryCrossFrame native entry points
+  static back(_HistoryCrossFrame) native "History_back_Callback";
+
+  static forward(_HistoryCrossFrame) native "History_forward_Callback";
+
+  static go(_HistoryCrossFrame, distance) native "History_go_Callback";
+}
+
+class Blink_LocationCrossFrame {
+  // _LocationCrossFrame native entry points
+  static set_href(_LocationCrossFrame, h) native "Location_href_Setter";
+}
+
+class Blink_DOMStringMap {
+  // _DOMStringMap native entry  points
+  static containsKey(_DOMStringMap, key) native "DOMStringMap_containsKey_Callback";
+
+  static item(_DOMStringMap, key) native "DOMStringMap_item_Callback";
+
+  static setItem(_DOMStringMap, key, value) native "DOMStringMap_setItem_Callback";
+
+  static remove(_DOMStringMap, key) native "DOMStringMap_remove_Callback";
+
+  static get_keys(_DOMStringMap) native "DOMStringMap_getKeys_Callback";
+}
+
+// Calls through JsNative but returns DomException instead of error strings.
+class Blink_JsNative_DomException {
+  static getProperty(js.JsObject o, name) {
+    try {
+      return js.JsNative.getProperty(o, name);
+    } catch (e) {
+      // Re-throw any errors (returned as a string) as a DomException.
+      throw new DomException.jsInterop(e);
+    }
+  }
+
+  static callMethod(js.JsObject o, String method, List args) {
+    try {
+      return js.JsNative.callMethod(o, method, args);
+    } catch (e) {
+      // Re-throw any errors (returned as a string) as a DomException.
+      throw new DomException.jsInterop(e);
+    }
+  }
+}"""
+
+CLASS_DEFINITION = """class Blink%s {
+  static final instance = new Blink%s();
+
+"""
+
+CLASS_DEFINITION_EXTENDS = """class Blink%s extends Blink%s {
+  static final instance = new Blink%s();
+
+"""
+
+#(interface_name)
+CONSTRUCTOR_0 = '  constructorCallback_0_() => new js.JsObject(Blink_JsNative_DomException.getProperty(js.context, "%s"), []);\n\n'
+
+#(argument_count, arguments, interface_name, arguments)
+CONSTRUCTOR_ARGS = '  constructorCallback_%s_(%s) => new js.JsObject(Blink_JsNative_DomException.getProperty(js.context, "%s"), [%s]);\n\n'
+
+#(attribute_name, attribute_name)
+ATTRIBUTE_GETTER = '  %s_Getter_(mthis) => Blink_JsNative_DomException.getProperty(mthis, "%s");\n\n'
+ATTRIBUTE_SETTER = '  %s_Setter_(mthis, __arg_0) => mthis["%s"] = __arg_0;\n\n'
+
+#(operation_name, operationName)
+OPERATION_0 = '  %s_Callback_0_(mthis) => Blink_JsNative_DomException.callMethod(mthis, "%s", []);\n\n'
+
+# getter, setter, deleter and propertyQuery code
+OPERATION_1 = '  $%s_Callback_1_(mthis, __arg_0) => Blink_JsNative_DomException.callMethod(mthis, "%s", [__arg_0]);\n\n'
+OPERATION_2 = '  $%s_Callback_2_(mthis, __arg_0, __arg_1) => Blink_JsNative_DomException.callMethod(mthis, "%s", [__arg_0, __arg_1]);\n\n'
+OPERATION_PQ = '  $%s_Callback_1_(mthis, __arg_0) => mthis[__arg_0];\n\n'
+
+#(operation_name, argument_count, arguments, operation_name, arguments)
+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 = """}
+
+"""
+
+def ConstantOutputOrder(a, b):
+  """Canonical output ordering for constants."""
+  return cmp(a.id, b.id)
+
+def generate_parameter_entries(param_infos):
+    optional_default_args = 0;
+    for argument in param_infos:
+      if argument.is_optional:
+        optional_default_args += 1
+
+    arg_count = len(param_infos)
+    min_arg_count = arg_count - optional_default_args
+    lb = min_arg_count - 2 if min_arg_count > 2 else 0
+    return (lb, arg_count + 1)
+
+constructor_renames = {
+    'RTCPeerConnection': 'webkitRTCPeerConnection',
+    'SpeechRecognition': 'webkitSpeechRecognition',
+}
+
+def rename_constructor(name):
+  return constructor_renames[name] if name in constructor_renames else name
+
+def Generate_Blink(output_dir, database, type_registry):
+  blink_filename = os.path.join(output_dir, '_blink_dartium.dart')
+  blink_file = open(blink_filename, 'w')
+
+  blink_file.write(HEADER);
+
+  interfaces = database.GetInterfaces()
+  for interface in interfaces:
+    name = interface.id
+    resolver_entry = '  if (s == "%s") return Blink%s.instance;\n' % (name, name)
+    blink_file.write(resolver_entry)
+
+  blink_file.write(END_RESOLVER);
+
+  for interface in interfaces:
+    name = interface.id
+
+    if interface.parents and len(interface.parents) > 0 and interface.parents[0].id:
+      extends = interface.parents[0].id
+      class_def = CLASS_DEFINITION_EXTENDS % (name, extends, name)
+    else:
+      class_def = CLASS_DEFINITION % (name, name)
+    blink_file.write(class_def);
+
+    analyzed_constructors = AnalyzeConstructor(interface)
+    if analyzed_constructors:
+      _Emit_Blink_Constructors(blink_file, analyzed_constructors)
+    elif 'Constructor' in interface.ext_attrs:
+      # Zero parameter constructor.
+      blink_file.write(CONSTRUCTOR_0 % rename_constructor(name))
+
+    _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, secondary.attributes)
+      _Process_Operations(blink_file, secondary, secondary.operations)
+
+    blink_file.write(CLASS_DEFINITION_END);
+
+  blink_file.write(BLINK_UTILS)
+
+  blink_file.close()
+
+def _Emit_Blink_Constructors(blink_file, analyzed_constructors):
+  (arg_min_count, arg_max_count) = generate_parameter_entries(analyzed_constructors.param_infos)
+  name = analyzed_constructors.js_name
+  if not(name):
+    name = analyzed_constructors.type_name
+
+  for callback_index in range(arg_min_count, arg_max_count):
+    if callback_index == 0:
+      blink_file.write(CONSTRUCTOR_0 % (rename_constructor(name)))
+    else:
+      arguments = []
+      for i in range(0, callback_index):
+        arguments.append(ARGUMENT_NUM % i)
+      argument_list = ', '.join(arguments)
+      blink_file.write(CONSTRUCTOR_ARGS % (callback_index, argument_list, rename_constructor(name), argument_list))
+
+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:
+      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))
+
+def _Process_Operations(blink_file, interface, operations):
+  analyzeOperations = []
+
+  for operation in sorted(operations, ConstantOutputOrder):
+    if len(analyzeOperations) == 0:
+      analyzeOperations.append(operation)
+    else:
+      if analyzeOperations[0].id == operation.id:
+        # Handle overloads
+        analyzeOperations.append(operation)
+      else:
+        _Emit_Blink_Operation(blink_file, interface, analyzeOperations)
+        analyzeOperations = [operation]
+  if len(analyzeOperations) > 0:
+    _Emit_Blink_Operation(blink_file, interface, analyzeOperations)
+
+def _Emit_Blink_Operation(blink_file, interface, analyzeOperations):
+  analyzed = AnalyzeOperation(interface, analyzeOperations)
+  (arg_min_count, arg_max_count) = generate_parameter_entries(analyzed.param_infos)
+  name = analyzed.js_name
+
+  operation = analyzeOperations[0]
+  if (name.startswith('__') and \
+      ('getter' in operation.specials or \
+       'setter' in operation.specials or \
+       'deleter' in operation.specials)):
+    if name == '__propertyQuery__':
+      blink_file.write(OPERATION_PQ % (name))
+    else:
+      arg_min_count = arg_max_count
+      if arg_max_count == 2:
+        blink_file.write(OPERATION_1 % (name, name))
+      elif arg_max_count == 3:
+        blink_file.write(OPERATION_2 % (name, name))
+      else:
+        print "FATAL ERROR: _blink emitter operator %s.%s" % (interface.id, name)
+        exit
+
+    return
+
+  for callback_index in range(arg_min_count, arg_max_count):
+    if callback_index == 0:
+      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)
+      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 92a5ed0..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',
 
@@ -294,7 +294,6 @@
 
   Returns: An OperationInfo object.
   """
-
   # split operations with optional args into multiple operations
   split_operations = []
   for operation in operations:
@@ -457,7 +456,14 @@
         parameter declaration.
     """
     def FormatParam(param):
-      dart_type = rename_type(param.type_id) if param.type_id else 'dynamic'
+      # Is the type a typedef if so it's a union so it's dynamic.
+      # TODO(terry): This may have to change for dart2js for code shaking the
+      #              return types (unions) needs to be emitted with @create
+      #              annotations and/or with JS('type1|type2',...)
+      if hasattr(rename_type, 'im_self') and rename_type.im_self._database.HasTypeDef(param.type_id):
+        dart_type = 'dynamic'
+      else:
+        dart_type = rename_type(param.type_id) if param.type_id else 'dynamic'
       return (TypeOrNothing(dart_type, param.type_id), param.name)
     required = []
     optional = []
@@ -546,14 +552,10 @@
         if (wrap_unwrap_type_blink(type_id, type_registry)):
           type_is_callback = self.isCallback(type_registry, type_id)
           if (dart_js_interop and type_id == 'EventListener' and
-              (self.name == 'addEventListener')):
+              self.name in ['addEventListener', 'removeEventListener']):
               # Events fired need use a JsFunction not a anonymous closure to
               # insure the event can really be removed.
-              parameters.append('wrap_event_listener(this, %s)' % p.name)
-          elif (dart_js_interop and type_id == 'EventListener' and
-              (self.name == 'removeEventListener')):
-              # Find the JsFunction that corresponds to this Dart function.
-              parameters.append('_knownListeners[this.hashCode][identityHashCode(%s)]' % p.name)
+              parameters.append('unwrap_jso(js.allowInterop(%s))' % p.name)
           elif dart_js_interop and type_id == 'FontFaceSetForEachCallback':
               # forEach is supported in the DOM for FontFaceSet as it iterates
               # over the Javascript Object the callback parameters are also
@@ -720,11 +722,12 @@
     'any set IDBCursor.update': _serialize_SSV,
 
     # postMessage
+    'SerializedScriptValue set': _serialize_SSV,
+    'any set CompositorWorkerGlobalScope.postMessage': _serialize_SSV,
+    'any set DedicatedWorkerGlobalScope.postMessage': _serialize_SSV,
     'any set MessagePort.postMessage': _serialize_SSV,
-    'SerializedScriptValue set Window.postMessage': _serialize_SSV,
-    'SerializedScriptValue set Worker.postMessage': _serialize_SSV,
-    'any set DedicatedWorkerGlobalScope.postMessage' : _serialize_SSV,
-    'SerializedScriptValue set ServiceWorkerClient.postMessage': _serialize_SSV,
+    'any set Window.postMessage': _serialize_SSV,
+    'any set _DOMWindowCrossFrame.postMessage': _serialize_SSV,
 
     '* get CustomEvent.detail':
       Conversion('convertNativeToDart_SerializedScriptValue',
@@ -1261,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'),
@@ -1306,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'),
@@ -1371,6 +1393,9 @@
   def HasInterface(self, type_name):
     return self._database.HasInterface(type_name)
 
+  def HasTypeDef(self, type_def_name):
+    return self._database.HasTypeDef(type_def_name)
+
   def TypeInfo(self, type_name):
     if not type_name in self._cache:
       self._cache[type_name] = self._TypeInfo(type_name)
@@ -1383,7 +1408,11 @@
     match = re.match(r'(?:sequence<([\w ]+)>|(\w+)\[\])$', type_name)
     if match:
       type_data = TypeData('Sequence')
-      item_info = self.TypeInfo(match.group(1) or match.group(2))
+      if self.HasTypeDef(match.group(1) or match.group(2)):
+        # It's a typedef (union)
+        item_info = self.TypeInfo('any')
+      else:
+        item_info = self.TypeInfo(match.group(1) or match.group(2))
       # TODO(vsm): Generalize this code.
       if 'SourceInfo' in type_name:
         type_data.native_type = 'const Vector<RefPtr<SourceInfo> >& '
@@ -1397,8 +1426,23 @@
 
       if self._database.HasInterface(type_name):
         interface = self._database.GetInterface(type_name)
-      else:
+      elif self._database.HasDictionary(type_name):
         interface = self._database.GetDictionary(type_name)
+      elif type_name.startswith('sequence<('):
+        if type_name.find(' or ') != -1:
+          # Union type of sequence is an any type (no type).
+          type_data = TypeData('Sequence')
+          item_info = self.TypeInfo('any')
+          return SequenceIDLTypeInfo(type_name, type_data, item_info)
+      elif type_name.startswith('sequence<sequence<'):
+        # TODO(terry): Cleanup up list of list, etc.
+        type_data = TypeData('Sequence')
+        item_info = self.TypeInfo('any')
+        return SequenceIDLTypeInfo(type_name, type_data, item_info)
+      elif self.HasTypeDef(type_name):
+        # It's a typedef (implied union)
+        return self.TypeInfo('any')
+
       if 'Callback' in interface.ext_attrs:
         return CallbackIDLTypeInfo(type_name, TypeData('Callback',
             self._renamer.DartifyTypeName(type_name)))
@@ -1441,9 +1485,20 @@
     class_name = '%sIDLTypeInfo' % type_data.clazz
     return globals()[class_name](type_name, type_data)
 
+def isList(return_type):
+  return return_type.startswith('List<') if return_type else False
+
+def get_list_type(return_type):
+  # Get the list type NNNN inside of List<NNNN>
+  return return_type[5:-1] if isList(return_type) else return_type
+
 def wrap_unwrap_list_blink(return_type, type_registry):
-    """Return True if the type is a List<Node>"""
-    return return_type.startswith('List<Node>')
+  """Return True if the type is the list type is a blink know
+     type e.g., List<Node>, List<FontFace>, etc."""
+  if isList(return_type):
+    list_type = get_list_type(return_type)
+    if type_registry.HasInterface(list_type):
+      return True;
 
 def wrap_unwrap_type_blink(return_type, type_registry):
     """Returns True if the type is a blink type that requires wrap_jso or
diff --git a/tools/dom/scripts/go.sh b/tools/dom/scripts/go.sh
index c17719f..a830a9b 100755
--- a/tools/dom/scripts/go.sh
+++ b/tools/dom/scripts/go.sh
@@ -18,7 +18,7 @@
 #
 # To generate a subset of systems:
 #
-#   ./go.sh dart2js,htmldart2js
+#   ./go.sh dart2js,htmldartium
 #
 # The following gives a picture of the changes due to 'work'
 #
@@ -29,7 +29,7 @@
 #   ./go.sh
 #   meld ../generated0 ../generated   # compare directories with too
 
-ALLSYSTEMS="htmldart2js,htmldartium"
+ALLSYSTEMS="htmldart2js,htmldartium,_blink"
 SYSTEMS="$ALLSYSTEMS"
 
 if [[ "$1" != "" ]] ; then
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index e7e500f..c944fc3 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -132,6 +132,13 @@
 
     secondary_parents = self._database.TransitiveSecondaryParents(interface,
                           not self._dart_use_blink)
+    remove_duplicate_parents = list(set(secondary_parents))
+    if len(secondary_parents) != len(remove_duplicate_parents):
+      secondary_parents = remove_duplicate_parents
+      parent_list = ", ".join(["  %s" % (parent.id) for parent in secondary_parents])
+      _logger.warn('Interface %s has duplicate parent interfaces %s - ' \
+                   'ignoring duplicates. Please file a bug with the dart:html team.' % (interface.id, parent_list))
+
     for parent_interface in sorted(secondary_parents):
       if isinstance(parent_interface, str):
         continue
@@ -311,6 +318,11 @@
       self.EmitAttribute(attribute, attr_name, read_only)
 
   def AddOperation(self, info, declare_only=False, dart_js_interop=False):
+    # TODO(terry): Hack window has 2 overloaded getter one returns Window and
+    #              and other object (we'll always return Window)?
+    if self._interface.id == "Window" and info.name == '__getter__':
+      info.operations[1].type = info.operations[0].type;
+
     """ Adds an operation to the generated class.
     Arguments:
       info - The operation info of the operation to be added.
@@ -528,7 +540,9 @@
   def _AddConstructor(self,
       constructor_info, factory_name, factory_constructor_name):
     # Hack to ignore the Image constructor used by JavaScript.
-    if ((self._interface.id == 'HTMLImageElement' or self._interface.id == 'Blob')
+    if ((self._interface.id == 'HTMLImageElement' or
+         self._interface.id == 'Blob' or
+         self._interface.id == 'DOMException')
       and not constructor_info.pure_dart_constructor):
       return
 
@@ -850,17 +864,20 @@
         verified_type = temp_type  # verified by assignment in checked mode.
       else:
         converted_arguments.append(info.param_infos[position].name)
-        param_type = self._NarrowInputType(arg.type.id)
-        # Verified by argument checking on entry to the dispatcher.
-
-        verified_type = self._InputType(
-            info.param_infos[position].type_id, info)
-        # The native method does not need an argument type if we know the type.
-        # But we do need the native methods to have correct function types, so
-        # be conservative.
-        if param_type == verified_type:
-          if param_type in ['String', 'num', 'int', 'double', 'bool', 'Object']:
-            param_type = 'dynamic'
+        if self._database.HasTypeDef(arg.type.id):
+          param_type = 'dynamic'
+        else:
+          param_type = self._NarrowInputType(arg.type.id)
+          # Verified by argument checking on entry to the dispatcher.
+  
+          verified_type = self._InputType(
+              info.param_infos[position].type_id, info)
+          # The native method does not need an argument type if we know the type.
+          # But we do need the native methods to have correct function types, so
+          # be conservative.
+          if param_type == verified_type:
+            if param_type in ['String', 'num', 'int', 'double', 'bool', 'Object']:
+              param_type = 'dynamic'
 
       target_parameters.append(
           '%s%s' % (TypeOrNothing(param_type), param_name))
@@ -872,4 +889,8 @@
     if conversion:
       return conversion.input_type
     else:
-      return self._NarrowInputType(type_name) if type_name else 'dynamic'
+      # If typedef it's a union return dynamic.
+      if self._database.HasTypeDef(type_name):
+        return 'dynamic'
+      else:
+        return self._NarrowInputType(type_name) if type_name else 'dynamic'
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 78193a5..addddd9 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -60,7 +60,8 @@
     'SVGSVGElement': 'SvgSvgElement', # Manual to avoid name conflicts.
     'Stream': 'FileStream',
     'StringCallback': '_StringCallback',
-    'WebGLVertexArrayObjectOES': 'VertexArrayObject',
+    'WebGL2RenderingContext': 'RenderingContext2',
+    'WebGL2RenderingContextBase': 'RenderingContextBase2',
     'WindowTimers': '_WindowTimers',
     'XMLHttpRequest': 'HttpRequest',
     'XMLHttpRequestUpload': 'HttpRequestUpload',
@@ -135,6 +136,7 @@
   'WebKitMediaSource',
   'WebKitNotification',
   'WebGLRenderingContextBase',
+  'WebGL2RenderingContextBase',
   'WebKitSourceBuffer',
   'WebKitSourceBufferList',
   'WorkerLocation', # Workers
@@ -176,9 +178,19 @@
 # constructor for dispatch purposes.
 custom_html_constructors = monitored.Set(
     'htmlrenamer.custom_html_constructors', [
+  'CompositionEvent',       # 45 Roll hide default constructor use Dart's custom
+  'CustomEvent',            # 45 Roll hide default constructor use Dart's custom
+  'Event',                  # 45 Roll hide default constructor use Dart's custom
+  'HashChangeEvent',        # 45 Roll hide default constructor use Dart's custom
   'HTMLAudioElement',
   'HTMLOptionElement',
+  'KeyboardEvent',          # 45 Roll hide default constructor use Dart's custom
+  'MessageEvent',           # 45 Roll hide default constructor use Dart's custom
+  'MouseEvent',             # 45 Roll hide default constructor use Dart's custom
   'MutationObserver',
+  'StorageEvent',           # 45 Roll hide default constructor use Dart's custom
+  'UIEvent',                # 45 Roll hide default constructor use Dart's custom
+  'WheelEvent',             # 45 Roll hide default constructor use Dart's custom
 ])
 
 # Members from the standard dom that should not be exposed publicly in dart:html
@@ -252,14 +264,6 @@
   'Element.querySelectorAll',
   # TODO(vsm): These have been converted from int to double in Chrome 36.
   # Special case them so we run on 34, 35, and 36.
-  'Element.offsetLeft',
-  'Element.offsetTop',
-  'Element.offsetWidth',
-  'Element.offsetHeight',
-  'Element.clientLeft',
-  'Element.clientTop',
-  'Element.clientWidth',
-  'Element.clientHeight',
   'Element.scrollLeft',
   'Element.scrollTop',
   'Element.scrollWidth',
@@ -403,6 +407,7 @@
 # Members from the standard dom that exist in the dart:html library with
 # identical functionality but with cleaner names.
 renamed_html_members = monitored.Dict('htmlrenamer.renamed_html_members', {
+    'ConsoleBase.assert': 'assertCondition',
     'CSSKeyframesRule.insertRule': 'appendRule',
     'DirectoryEntry.getDirectory': '_getDirectory',
     'DirectoryEntry.getFile': '_getFile',
@@ -433,8 +438,6 @@
   'AudioContext.createBuffer(ArrayBuffer buffer, boolean mixToMono)':
       'createBufferFromBuffer',
   'CSS.supports(DOMString conditionText)': 'supportsCondition',
-  'CanvasRenderingContext2D.createPattern(HTMLImageElement image, '
-      'DOMString repetitionType)': 'createPatternFromImage',
   'DataTransferItemList.add(File file)': 'addFile',
   'DataTransferItemList.add(DOMString data, DOMString type)': 'addData',
   'FormData.append(DOMString name, Blob value, DOMString filename)':
@@ -485,7 +488,11 @@
   'WebSocket.send(ArrayBuffer data)': 'sendByteBuffer',
   'WebSocket.send(ArrayBufferView data)': 'sendTypedData',
   'WebSocket.send(DOMString data)': 'sendString',
-  'WebSocket.send(Blob data)': 'sendBlob'
+  'WebSocket.send(Blob data)': 'sendBlob',
+  'Window.setInterval(DOMString handler, long timeout, any arguments)': '_setInterval_String',
+  'Window.setTimeout(DOMString handler, long timeout, any arguments)': '_setTimeout_String',
+  'WindowTimers.setInterval(DOMString handler, long timeout, any arguments)': '_setInterval_String',
+  'WindowTimers.setTimeout(DOMString handler, long timeout, any arguments)': '_setTimeout_String',
 })
 
 # Members that have multiple definitions, but their types are identical (only
@@ -552,7 +559,10 @@
     'CanvasRenderingContext2D.setMiterLimit',
     'CanvasRenderingContext2D.setShadow',
     'CanvasRenderingContext2D.setStrokeColor',
+    # Disable the webKit version, imageSmoothingEnabled is exposed.
+    'CanvasRenderingContext2D.webkitImageSmoothingEnabled',
     'CharacterData.remove',
+    'ChildNode.replaceWith',
     'Window.call:blur',
     'Window.call:focus',
     'Window.clientInformation',
@@ -569,6 +579,7 @@
     'Window.webkitRequestAnimationFrame',
     'Document.alinkColor',
     'Document.all',
+    'Document.append',
     'Document.applets',
     'Document.bgColor',
     'Document.clear',
@@ -604,6 +615,7 @@
     'Document.location',
     'Document.on:wheel',
     'Document.open',
+    'Document.prepend',
     'Document.register',
     'Document.set:domain',
     'Document.vlinkColor',
@@ -642,14 +654,24 @@
     'DOMException.VALIDATION_ERR',
     'DOMException.WRONG_DOCUMENT_ERR',
     'Element.accessKey',
+    'Element.append',
     'Element.dataset',
     'Element.get:classList',
     'Element.getAttributeNode',
     'Element.getAttributeNodeNS',
     'Element.getElementsByTagNameNS',
     'Element.innerText',
+    # TODO(terry): All offset* attributes are in both HTMLElement and Element
+    #              (it's a Chrome bug with a FIXME note to correct - sometime).
+    #              Until corrected these Element attributes must be ignored.
+    'Element.offsetParent',
+    'Element.offsetTop',
+    'Element.offsetLeft',
+    'Element.offsetWidth',
+    'Element.offsetHeight',
     'Element.on:wheel',
     'Element.outerText',
+    'Element.prepend',
     'Element.removeAttributeNode',
     'Element.set:outerHTML',
     'Element.setAttributeNode',
@@ -773,6 +795,7 @@
     'HTMLUListElement.type',
     'IDBDatabase.transaction', # We do this in a template without the generated implementation at all.
     'Location.valueOf',
+    'MessageEvent.data',
     'MessageEvent.ports',
     'MessageEvent.webkitInitMessageEvent',
     'MouseEvent.x',
@@ -803,19 +826,15 @@
     'NodeIterator.expandEntityReferences',
     'NodeIterator.filter',
     'NodeList.item',
-    'Performance.webkitClearMarks',
-    'Performance.webkitClearMeasures',
-    'Performance.webkitGetEntries',
-    'Performance.webkitGetEntriesByName',
-    'Performance.webkitGetEntriesByType',
-    'Performance.webkitMark',
-    'Performance.webkitMeasure',
+    'ParentNode.append',
+    'ParentNode.prepend',
     'ShadowRoot.getElementsByTagNameNS',
     'SVGElement.getPresentationAttribute',
     'SVGElementInstance.on:wheel',
     'Touch.get:webkitRadiusX',
     'Touch.get:webkitRadiusY',
     'Touch.get:webkitForce',
+    'Touch.get:webkitRotationAngle',
     'WheelEvent.wheelDelta',
     'WheelEvent.wheelDeltaX',
     'WheelEvent.wheelDeltaY',
@@ -868,6 +887,8 @@
       return html_interface_renames[interface_id]
     return None;
 
+  def isPrivate(self, interface, member):
+    return self._FindMatch(interface, member, '', private_html_members)
 
   def RenameMember(self, interface_name, member_node, member, member_prefix='',
       dartify_name=True):
diff --git a/tools/dom/scripts/idlnode.py b/tools/dom/scripts/idlnode.py
index e09c8c8..2d81988 100755
--- a/tools/dom/scripts/idlnode.py
+++ b/tools/dom/scripts/idlnode.py
@@ -8,12 +8,27 @@
 
 import idl_definitions
 from idl_types import IdlType, IdlNullableType, IdlUnionType, IdlArrayOrSequenceType
-
-from compute_interfaces_info_overall import interfaces_info
-
+import dependency
 
 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",
@@ -363,7 +378,7 @@
           # Special handling for dart.idl we need to remember the interface,
           # since we could have many (not one interface / file). Then build up
           # the IDLImplementsStatement for any implements in dart.idl.
-          interface_info = interfaces_info['__dart_idl___'];
+          interface_info = dependency.get_interfaces_info()['__dart_idl___'];
 
           self.implementsStatements = []
 
@@ -377,10 +392,10 @@
                                                                   implemented_name)
 
             self.implementsStatements.append(implement_statement)
-        elif interface.id in interfaces_info:
-          interface_info = interfaces_info[interface.id]
+        elif interface.id in dependency.get_interfaces_info():
+          interface_info = dependency.get_interfaces_info()[interface.id]
 
-          implements = interface_info['implements_interfaces']
+          implements = interface_info['implements_interfaces'] if interface_info.has_key('implements_interfaces') else []
           if not(blink_interface.is_partial) and len(implements) > 0:
             implementor = new_asts[interface.id].interfaces.get(interface.id)
 
@@ -400,6 +415,18 @@
     # No reason to handle typedef they're already aliased in Blink's AST.
     self.typeDefs = [] if is_blink else self._convert_all(ast, 'TypeDef', IDLTypeDef)
 
+    # Hack to record typedefs that are unions.
+    for typedefName in ast.typedefs:
+      typedef_type = ast.typedefs[typedefName]
+      if isinstance(typedef_type.idl_type, IdlUnionType):
+        self.typeDefs.append(IDLTypeDef(typedef_type))
+      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)
 
   def _createImplementsStatement(self, implementor, implemented_name):
@@ -433,7 +460,7 @@
       # implements is handled by the interface merging step (see the function
       # merge_interface_dependencies).
       for interface in self.interfaces:
-        interface_info = interfaces_info[interface.id]
+        interface_info = get_interfaces_info()[interface.id]
         # TODO(terry): Same handling for implementsStatements as in IDLFile?
         self.implementsStatements = interface_info['implements_interfaces']
     else:
@@ -531,70 +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 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'
+          # 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:
-        # 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):
-        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 ScalarValueString as a DOMString.
-        type_name = type_name.replace('ScalarValueString', 'DOMString', 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))
+        print '>>>> __module__ %s' % ast.__module__
+        raise SyntaxError('Could not parse type %s' % (ast))
 
   def _label_to_type(self, label, ast):
     if label == 'LongLongType':
@@ -635,13 +672,16 @@
   """IDLDictionary node contains members,
   as well as parent references."""
 
-  def __init__(self, ast):
+  def __init__(self, ast, typedefDictionary=False):
     IDLNode.__init__(self, ast)
 
     self.javascript_binding_name = self.id
-    self._convert_ext_attrs(ast)
-    self._convert_constants(ast, self.id)
-
+    if (typedefDictionary):
+        # Dictionary is a typedef to a union.
+        self._convert_ext_attrs(None)
+    else:
+        self._convert_ext_attrs(ast)
+        self._convert_constants(ast, self.id)
 
 class IDLDictionaryMembers(IDLDictNode):
   """IDLDictionaryMembers specialization for a list of FremontCut dictionary values."""
@@ -728,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
@@ -736,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
@@ -754,6 +796,8 @@
           # Handling __propertyQuery__ the extended attribute is:
           # [Custom=PropertyQuery] getter boolean (DOMString name);
           self.id = '__propertyQuery__'
+        elif self.ext_attrs.get('ImplementedAs'):
+          self.id = self.ext_attrs.get('ImplementedAs')
         else:
           self.id = '__getter__'
       elif self.specials == ['setter']:
@@ -818,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/scripts/idlsync.py b/tools/dom/scripts/idlsync.py
index dc49fce..24aae09 100755
--- a/tools/dom/scripts/idlsync.py
+++ b/tools/dom/scripts/idlsync.py
@@ -7,6 +7,7 @@
 import os
 import os.path
 import re
+import requests
 import shutil
 import subprocess
 import sys
@@ -15,9 +16,10 @@
 SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__))
 DART_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, '..', '..', '..'))
 
-# Dartium DEPS file with Chrome and WebKit revisions.
-DEPS = ('http://dart.googlecode.com/svn/branches/'
-        'bleeding_edge/deps/dartium.deps/DEPS')
+# Dartium DEPS file from the DEPS file checked into the dart-lang/sdk integration
+# branch.
+DEPS_GIT = ('https://raw.githubusercontent.com/dart-lang/sdk/'
+            'integration/tools/deps/dartium.deps/DEPS')
 
 # Whitelist of files to keep.
 WHITELIST = [
@@ -29,7 +31,7 @@
     ]
 
 # WebKit / WebCore info.
-CHROME_TRUNK = "http://src.chromium.org"
+CHROME_TRUNK = "https://src.chromium.org"
 WEBKIT_URL_PATTERN = r'"dartium_webkit_branch": "(\S+)",'
 WEBKIT_REV_PATTERN = r'"dartium_webkit_revision": "(\d+)",'
 WEBCORE_SUBPATH = 'Source/core'
@@ -84,7 +86,7 @@
 # DEPS file.
 DEPS_PATTERNS = {
     'webkit': (CHROME_TRUNK, WEBKIT_URL_PATTERN, WEBKIT_REV_PATTERN),
-    'chrome': (CHROME_TRUNK, CHROME_URL_PATTERN, CHROME_REV_PATTERN),
+#    'chrome': (CHROME_TRUNK, CHROME_URL_PATTERN, CHROME_REV_PATTERN),
     }
 
 # List of components to update.
@@ -130,11 +132,9 @@
     print 'FAILED. RET_CODE=%d' % pipe.returncode
     sys.exit(pipe.returncode)
 
-
-def GetDeps():
-  """Returns the DEPS file contents with pinned revision info."""
-  return RunCommand(['svn', 'cat', DEPS])
-
+def GetDepsFromGit():
+  req = requests.get(DEPS_GIT)
+  return req.text
 
 def GetSvnRevision(deps, component):
   """Returns a tuple with the (dartium webkit repo, latest revision)."""
@@ -208,21 +208,15 @@
                     help='WebKit IDL revision to install', default=None)
   parser.add_option('--chrome-revision', '-c', dest='chrome_revision',
                     help='Chrome IDL revision to install', default=None)
-  parser.add_option('--update', '-u', dest='update',
-                    help='IDL to update (webkit | chrome | all)',
-                    default='webkit')
   args, _ = parser.parse_args()
   update = {}
-  if args.update == 'all' or args.update == 'chrome':
-    update['chrome'] = args.chrome_revision
-  if args.update == 'all' or args.update == 'webkit':
-    update['webkit'] = args.webkit_revision
+  update['webkit'] = args.webkit_revision
   return update
 
 
 def main():
-  deps = GetDeps()
   update = ParseOptions()
+  deps = GetDepsFromGit()
   for (component, remote_path, local_path, readme, depth) in UPDATE_LIST:
     if component in update.keys():
       revision = update[component]
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index 24ecbb8..7656695 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -406,7 +406,7 @@
 ]
 
 js_support_checks = dict({
-    'AnimationPlayer': "JS('bool', '!!(document.body.animate)')",
+    'Animation': "JS('bool', '!!(document.body.animate)')",
     'AudioContext': "JS('bool', '!!(window.AudioContext ||"
         " window.webkitAudioContext)')",
     'Crypto':
@@ -614,9 +614,7 @@
     return new {0}._internalWrap();
   }}
 
-  factory {0}._internalWrap() {{
-    return new {0}.internal_();
-  }}
+  external factory {0}._internalWrap();
 
   @Deprecated("Internal Use Only")
   {0}.internal_() : super.internal_();
@@ -707,7 +705,7 @@
     merged_interface = self._interface_type_info.merged_interface()
     if merged_interface:
       self._backend.AddMembers(self._database.GetInterface(merged_interface),
-        not self._backend.ImplementsMergedMembers())
+                               not self._backend.ImplementsMergedMembers())
 
     self._backend.AddMembers(self._interface, False, self._options.dart_js_interop)
     self._backend.AddSecondaryMembers(self._interface)
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 3fc0638..5470993 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -13,287 +13,12 @@
 from idlnode import IDLArgument, IDLAttribute, IDLEnum, IDLMember
 from systemhtml import js_support_checks, GetCallbackInfo, HTML_LIBRARY_NAMES
 
-# TODO(vsm): This logic needs to pulled from the source IDL.  These tables are
-# an ugly workaround.
-_cpp_callback_map = {
-  ('DataTransferItem', 'webkitGetAsEntry'): 'DataTransferItemFileSystem',
-  ('Document', 'fonts'): 'DocumentFontFaceSet',
-  ('Document', 'webkitIsFullScreen'): 'DocumentFullscreen',
-  ('Document', 'webkitFullScreenKeyboardInputAllowed'): 'DocumentFullscreen',
-  ('Document', 'webkitCurrentFullScreenElement'): 'DocumentFullscreen',
-  ('Document', 'webkitCancelFullScreen'): 'DocumentFullscreen',
-  ('Document', 'webkitFullscreenEnabled'): 'DocumentFullscreen',
-  ('Document', 'webkitFullscreenElement'): 'DocumentFullscreen',
-  ('Document', 'webkitExitFullscreen'): 'DocumentFullscreen',
-  ('DOMWindow', 'crypto'): 'DOMWindowCrypto',
-  ('DOMWindow', 'indexedDB'): 'DOMWindowIndexedDatabase',
-  ('DOMWindow', 'speechSynthesis'): 'DOMWindowSpeechSynthesis',
-  ('DOMWindow', 'webkitNotifications'): 'DOMWindowNotifications',
-  ('DOMWindow', 'storage'): 'DOMWindowQuota',
-  ('DOMWindow', 'webkitStorageInfo'): 'DOMWindowQuota',
-  ('DOMWindow', 'openDatabase'): 'DOMWindowWebDatabase',
-  ('DOMWindow', 'webkitRequestFileSystem'): 'DOMWindowFileSystem',
-  ('DOMWindow', 'webkitResolveLocalFileSystemURL'): 'DOMWindowFileSystem',
-  ('DOMWindow', 'atob'): 'DOMWindowBase64',
-  ('DOMWindow', 'btoa'): 'DOMWindowBase64',
-  ('DOMWindow', 'clearTimeout'): 'DOMWindowTimers',
-  ('DOMWindow', 'clearInterval'): 'DOMWindowTimers',
-  ('DOMWindow', 'createImageBitmap'): 'ImageBitmapFactories',
-  ('Element', 'animate'): 'ElementAnimation',
-  ('HTMLInputElement', 'webkitEntries'): 'HTMLInputElementFileSystem',
-  ('HTMLVideoElement', 'getVideoPlaybackQuality'): 'HTMLVideoElementMediaSource',
-  ('Navigator', 'doNotTrack'): 'NavigatorDoNotTrack',
-  ('Navigator', 'geolocation'): 'NavigatorGeolocation',
-  ('Navigator', 'webkitPersistentStorage'): 'NavigatorStorageQuota',
-  ('Navigator', 'webkitTemporaryStorage'): 'NavigatorStorageQuota',
-  ('Navigator', 'registerProtocolHandler'): 'NavigatorContentUtils',
-  ('Navigator', 'unregisterProtocolHandler'): 'NavigatorContentUtils',
-  ('Navigator', 'webkitGetUserMedia'): 'NavigatorMediaStream',
-  ('Navigator', 'webkitGetGamepads'): 'NavigatorGamepad',
-  ('Navigator', 'requestMIDIAccess'): 'NavigatorWebMIDI',
-  ('Navigator', 'vibrate'): 'NavigatorVibration',
-  ('Navigator', 'appName'): 'NavigatorID',
-  ('Navigator', 'appVersion'): 'NavigatorID',
-  ('Navigator', 'appCodeName'): 'NavigatorID',
-  ('Navigator', 'platform'): 'NavigatorID',
-  ('Navigator', 'product'): 'NavigatorID',
-  ('Navigator', 'userAgent'): 'NavigatorID',
-  ('Navigator', 'onLine'): 'NavigatorOnLine',
-  ('Navigator', 'registerServiceWorker'): 'NavigatorServiceWorker',
-  ('Navigator', 'unregisterServiceWorker'): 'NavigatorServiceWorker',
-  ('Navigator', 'maxTouchPoints'): 'NavigatorEvents',
-  ('WorkerGlobalScope', 'crypto'): 'WorkerGlobalScopeCrypto',
-  ('WorkerGlobalScope', 'indexedDB'): 'WorkerGlobalScopeIndexedDatabase',
-  ('WorkerGlobalScope', 'webkitNotifications'): 'WorkerGlobalScopeNotifications',
-  ('WorkerGlobalScope', 'openDatabase'): 'WorkerGlobalScopeWebDatabase',
-  ('WorkerGlobalScope', 'openDatabaseSync'): 'WorkerGlobalScopeWebDatabase',
-  ('WorkerGlobalScope', 'performance'): 'WorkerGlobalScopePerformance',
-  ('WorkerGlobalScope', 'webkitRequestFileSystem'): 'WorkerGlobalScopeFileSystem',
-  ('WorkerGlobalScope', 'webkitRequestFileSystemSync'): 'WorkerGlobalScopeFileSystem',
-  ('WorkerGlobalScope', 'webkitResolveLocalFileSystemURL'): 'WorkerGlobalScopeFileSystem',
-  ('WorkerGlobalScope', 'webkitResolveLocalFileSystemSyncURL'): 'WorkerGlobalScopeFileSystem',
-  ('WorkerGlobalScope', 'atob'): 'DOMWindowBase64',
-  ('WorkerGlobalScope', 'btoa'): 'DOMWindowBase64',
-  ('WorkerGlobalScope', 'clearTimeout'): 'DOMWindowTimers',
-  ('WorkerGlobalScope', 'clearInterval'): 'DOMWindowTimers',
-  ('Document', 'rootElement'): 'SVGDocument',
-  ('Document', 'childElementCount'): 'ParentNode',
-  ('Document', 'firstElementChild'): 'ParentNode',
-  ('Document', 'lastElementChild'): 'ParentNode',
-  ('DocumentFragment', 'childElementCount'): 'ParentNode',
-  ('DocumentFragment', 'firstElementChild'): 'ParentNode',
-  ('DocumentFragment', 'lastElementChild'): 'ParentNode',
-  ('CharacterData', 'nextElementSibling'): 'ChildNode',
-  ('CharacterData', 'previousElementSibling'): 'ChildNode',
-  ('Element', 'childElementCount'): 'ParentNode',
-  ('Element', 'firstElementChild'): 'ParentNode',
-  ('Element', 'lastElementChild'): 'ParentNode',
-  ('Element', 'nextElementSibling'): 'ChildNode',
-  ('Element', 'previousElementSibling'): 'ChildNode',
-  ('SVGAnimationElement', 'requiredExtensions'): 'SVGTests',
-  ('SVGAnimationElement', 'requiredFeatures'): 'SVGTests',
-  ('SVGAnimationElement', 'systemLanguage'): 'SVGTests',
-  ('SVGAnimationElement', 'hasExtension'): 'SVGTests',
-  ('SVGGraphicsElement', 'requiredExtensions'): 'SVGTests',
-  ('SVGGraphicsElement', 'requiredFeatures'): 'SVGTests',
-  ('SVGGraphicsElement', 'systemLanguage'): 'SVGTests',
-  ('SVGGraphicsElement', 'hasExtension'): 'SVGTests',
-  ('SVGPatternElement', 'requiredExtensions'): 'SVGTests',
-  ('SVGPatternElement', 'requiredFeatures'): 'SVGTests',
-  ('SVGPatternElement', 'systemLanguage'): 'SVGTests',
-  ('SVGPatternElement', 'hasExtension'): 'SVGTests',
-  ('SVGUseElement', 'requiredExtensions'): 'SVGTests',
-  ('SVGUseElement', 'requiredFeatures'): 'SVGTests',
-  ('SVGUseElement', 'systemLanguage'): 'SVGTests',
-  ('SVGUseElement', 'hasExtension'): 'SVGTests',
-  ('SVGMaskElement', 'requiredExtensions'): 'SVGTests',
-  ('SVGMaskElement', 'requiredFeatures'): 'SVGTests',
-  ('SVGMaskElement', 'systemLanguage'): 'SVGTests',
-  ('SVGMaskElement', 'hasExtension'): 'SVGTests',
-  ('SVGViewSpec', 'zoomAndPan'): 'SVGZoomAndPan',
-  ('SVGViewSpec', 'setZoomAndPan'): 'SVGZoomAndPan',
-  ('SVGViewElement', 'setZoomAndPan'): 'SVGZoomAndPan',
-  ('SVGSVGElement', 'setZoomAndPan'): 'SVGZoomAndPan',
-  ('Screen', 'orientation'): 'ScreenOrientation',
-  ('Screen', 'lockOrientation'): 'ScreenOrientation',
-  ('Screen', 'unlockOrientation'): 'ScreenOrientation',
-  ('Navigator', 'serviceWorker'): 'NavigatorServiceWorker',
-  ('Navigator', 'storageQuota'): 'NavigatorStorageQuota',
-  ('Navigator', 'isProtocolHandlerRegistered'): 'NavigatorContentUtils',
-  ('SharedWorker', 'workerStart'): 'SharedWorkerPerformance',
-}
-
-_cpp_import_map = {
-  'ImageBitmapFactories' : 'modules/imagebitmap/ImageBitmapFactories',
-  'ScreenOrientation' : 'modules/screen_orientation/ScreenOrientation'
-}
-
-_cpp_overloaded_callback_map = {
-  ('DOMURL', 'createObjectUrlFromSourceCallback'): 'URLMediaSource',
-  ('DOMURL', 'createObjectUrlFromStreamCallback'): 'URLMediaStream',
-  ('DOMURL', '_createObjectUrlFromWebKitSourceCallback'): 'URLMediaSource',
-  ('DOMURL', '_createObjectURL_2Callback'): 'URLMediaSource',
-  ('DOMURL', '_createObjectURL_3Callback'): 'URLMediaStream',
-}
-
-_cpp_partial_map = {}
-
-_cpp_no_auto_scope_list = set([
-  ('Document', 'body', 'Getter'),
-  ('Document', 'getElementById', 'Callback'),
-  ('Document', 'getElementsByName', 'Callback'),
-  ('Document', 'getElementsByTagName', 'Callback'),
-  ('Element', 'getAttribute', 'Callback'),
-  ('Element', 'getAttributeNS', 'Callback'),
-  ('Element', 'id', 'Getter'),
-  ('Element', 'id', 'Setter'),
-  ('Element', 'setAttribute', 'Callback'),
-  ('Element', 'setAttributeNS', 'Callback'),
-  ('Node', 'firstChild', 'Getter'),
-  ('Node', 'lastChild', 'Getter'),
-  ('Node', 'nextSibling', 'Getter'),
-  ('Node', 'previousSibling', 'Getter'),
-  ('Node', 'childNodes', 'Getter'),
-  ('Node', 'nodeType', 'Getter'),
-  ('NodeList', 'length', 'Getter'),
-  ('NodeList', 'item', 'Callback'),
-  ('WebGLRenderingContext', 'drawingBufferHeight', 'Getter'),
-  ('WebGLRenderingContext', 'drawingBufferWidth', 'Getter'),
-  ('WebGLRenderingContext', 'activeTexture', 'Callback'),
-  ('WebGLRenderingContext', 'attachShader', 'Callback'),
-  ('WebGLRenderingContext', 'bindAttribLocation', 'Callback'),
-  ('WebGLRenderingContext', 'bindBuffer', 'Callback'),
-  ('WebGLRenderingContext', 'bindFramebuffer', 'Callback'),
-  ('WebGLRenderingContext', 'bindRenderbuffer', 'Callback'),
-  ('WebGLRenderingContext', 'bindTexture', 'Callback'),
-  ('WebGLRenderingContext', 'blendColor', 'Callback'),
-  ('WebGLRenderingContext', 'blendEquation', 'Callback'),
-  ('WebGLRenderingContext', 'blendEquationSeparate', 'Callback'),
-  ('WebGLRenderingContext', 'blendFunc', 'Callback'),
-  ('WebGLRenderingContext', 'blendFuncSeparate', 'Callback'),
-  ('WebGLRenderingContext', 'checkFramebufferStatus', 'Callback'),
-  ('WebGLRenderingContext', 'clear', 'Callback'),
-  ('WebGLRenderingContext', 'clearColor', 'Callback'),
-  ('WebGLRenderingContext', 'clearDepth', 'Callback'),
-  ('WebGLRenderingContext', 'clearStencil', 'Callback'),
-  ('WebGLRenderingContext', 'colorMask', 'Callback'),
-  ('WebGLRenderingContext', 'compileShader', 'Callback'),
-  ('WebGLRenderingContext', 'compressedTexImage2D', 'Callback'),
-  ('WebGLRenderingContext', 'compressedTexSubImage2D', 'Callback'),
-  ('WebGLRenderingContext', 'copyTexImage2D', 'Callback'),
-  ('WebGLRenderingContext', 'copyTexSubImage2D', 'Callback'),
-  ('WebGLRenderingContext', 'cullFace', 'Callback'),
-  ('WebGLRenderingContext', 'deleteBuffer', 'Callback'),
-  ('WebGLRenderingContext', 'deleteFramebuffer', 'Callback'),
-  ('WebGLRenderingContext', 'deleteProgram', 'Callback'),
-  ('WebGLRenderingContext', 'deleteRenderbuffer', 'Callback'),
-  ('WebGLRenderingContext', 'deleteShader', 'Callback'),
-  ('WebGLRenderingContext', 'deleteTexture', 'Callback'),
-  ('WebGLRenderingContext', 'depthFunc', 'Callback'),
-  ('WebGLRenderingContext', 'depthMask', 'Callback'),
-  ('WebGLRenderingContext', 'depthRange', 'Callback'),
-  ('WebGLRenderingContext', 'detachShader', 'Callback'),
-  ('WebGLRenderingContext', 'disable', 'Callback'),
-  ('WebGLRenderingContext', 'disableVertexAttribArray', 'Callback'),
-  ('WebGLRenderingContext', 'drawArrays', 'Callback'),
-  ('WebGLRenderingContext', 'drawElements', 'Callback'),
-  ('WebGLRenderingContext', 'enable', 'Callback'),
-  ('WebGLRenderingContext', 'enableVertexAttribArray', 'Callback'),
-  ('WebGLRenderingContext', 'finish', 'Callback'),
-  ('WebGLRenderingContext', 'flush', 'Callback'),
-  ('WebGLRenderingContext', 'framebufferRenderbuffer', 'Callback'),
-  ('WebGLRenderingContext', 'framebufferTexture2D', 'Callback'),
-  ('WebGLRenderingContext', 'frontFace', 'Callback'),
-  ('WebGLRenderingContext', 'generateMipmap', 'Callback'),
-  ('WebGLRenderingContext', 'getActiveAttrib', 'Callback'),
-  ('WebGLRenderingContext', 'getActiveUniform', 'Callback'),
-  ('WebGLRenderingContext', 'getAttachedShaders', 'Callback'),
-  ('WebGLRenderingContext', 'getAttribLocation', 'Callback'),
-  ('WebGLRenderingContext', 'hint', 'Callback'),
-  ('WebGLRenderingContext', 'isBuffer', 'Callback'),
-  ('WebGLRenderingContext', 'isContextLost', 'Callback'),
-  ('WebGLRenderingContext', 'isEnabled', 'Callback'),
-  ('WebGLRenderingContext', 'isFramebuffer', 'Callback'),
-  ('WebGLRenderingContext', 'isProgram', 'Callback'),
-  ('WebGLRenderingContext', 'isRenderbuffer', 'Callback'),
-  ('WebGLRenderingContext', 'isShader', 'Callback'),
-  ('WebGLRenderingContext', 'isTexture', 'Callback'),
-  ('WebGLRenderingContext', 'lineWidth', 'Callback'),
-  ('WebGLRenderingContext', 'linkProgram', 'Callback'),
-  ('WebGLRenderingContext', 'pixelStorei', 'Callback'),
-  ('WebGLRenderingContext', 'polygonOffset', 'Callback'),
-  ('WebGLRenderingContext', 'scissor', 'Callback'),
-  ('WebGLRenderingContext', 'stencilFunc', 'Callback'),
-  ('WebGLRenderingContext', 'stencilFuncSeparate', 'Callback'),
-  ('WebGLRenderingContext', 'stencilMask', 'Callback'),
-  ('WebGLRenderingContext', 'stencilMaskSeparate', 'Callback'),
-  ('WebGLRenderingContext', 'stencilOp', 'Callback'),
-  ('WebGLRenderingContext', 'stencilOpSeparate', 'Callback'),
-  ('WebGLRenderingContext', 'uniform1f', 'Callback'),
-  ('WebGLRenderingContext', 'uniform1fv', 'Callback'),
-  ('WebGLRenderingContext', 'uniform1i', 'Callback'),
-  ('WebGLRenderingContext', 'uniform1iv', 'Callback'),
-  ('WebGLRenderingContext', 'uniform2f', 'Callback'),
-  ('WebGLRenderingContext', 'uniform2fv', 'Callback'),
-  ('WebGLRenderingContext', 'uniform2i', 'Callback'),
-  ('WebGLRenderingContext', 'uniform2iv', 'Callback'),
-  ('WebGLRenderingContext', 'uniform3f', 'Callback'),
-  ('WebGLRenderingContext', 'uniform3fv', 'Callback'),
-  ('WebGLRenderingContext', 'uniform3i', 'Callback'),
-  ('WebGLRenderingContext', 'uniform3iv', 'Callback'),
-  ('WebGLRenderingContext', 'uniform4f', 'Callback'),
-  ('WebGLRenderingContext', 'uniform4fv', 'Callback'),
-  ('WebGLRenderingContext', 'uniform4i', 'Callback'),
-  ('WebGLRenderingContext', 'uniform4iv', 'Callback'),
-  ('WebGLRenderingContext', 'uniformMatrix2fv', 'Callback'),
-  ('WebGLRenderingContext', 'uniformMatrix3fv', 'Callback'),
-  ('WebGLRenderingContext', 'uniformMatrix4fv', 'Callback'),
-  ('WebGLRenderingContext', 'useProgram', 'Callback'),
-  ('WebGLRenderingContext', 'validateProgram', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttrib1f', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttrib1fv', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttrib2f', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttrib2fv', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttrib3f', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttrib3fv', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttrib4f', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttrib4fv', 'Callback'),
-  ('WebGLRenderingContext', 'vertexAttribPointer', 'Callback'),
-  ('WebGLRenderingContext', 'viewport', 'Callback'),
-])
 
 # TODO(vsm): This should be recoverable from IDL, but we appear to not
 # track the necessary info.
 _url_utils = ['hash', 'host', 'hostname', 'origin',
               'password', 'pathname', 'port', 'protocol',
               'search', 'username']
-_cpp_static_call_map = {
-  'DOMURL': _url_utils + ['href', 'toString'],
-  'HTMLAnchorElement': _url_utils,
-  'HTMLAreaElement': _url_utils,
-}
-
-def _GetCPPPartialNames(interface):
-  interface_name = interface.ext_attrs.get('ImplementedAs', interface.id)
-  if not _cpp_partial_map:
-    for (type, member) in _cpp_callback_map.keys():
-      if type not in _cpp_partial_map:
-        _cpp_partial_map[type] = set([])
-
-      name_with_path = _cpp_callback_map[(type, member)]
-      if name_with_path in _cpp_import_map:
-        name_with_path = _cpp_import_map[name_with_path]
-      _cpp_partial_map[type].add(name_with_path)
-
-    for (type, member) in _cpp_overloaded_callback_map.keys():
-      if type not in _cpp_partial_map:
-        _cpp_partial_map[type] = set([])
-      _cpp_partial_map[type].add(_cpp_overloaded_callback_map[(type, member)])
-
-  if interface_name in _cpp_partial_map:
-    return _cpp_partial_map[interface_name]
-  else:
-    return set([])
 
 def array_type(data_type):
     matched = re.match(r'([\w\d_\s]+)\[\]', data_type)
@@ -320,19 +45,6 @@
 
   return interface_id
 
-def _GetCPPTypeName(interface_name, callback_name, cpp_name):
-  # TODO(vsm): We need to track the original IDL file name in order to recover
-  # the proper CPP name.
-
-  cpp_tuple = (interface_name, callback_name)
-  if cpp_tuple in _cpp_callback_map:
-    cpp_type_name = _cpp_callback_map[cpp_tuple]
-  elif (interface_name, cpp_name) in _cpp_overloaded_callback_map:
-    cpp_type_name = _cpp_overloaded_callback_map[(interface_name, cpp_name)]
-  else:
-    cpp_type_name = interface_name
-  return cpp_type_name
-
 def DeriveQualifiedName(library_name, name):
     return library_name + "." + name
 
@@ -398,112 +110,7 @@
     return FindConversion(idl_type, 'set', self._interface.id, member)
 
   def GenerateCallback(self, info):
-    if IsPureInterface(self._interface.id) or IsCustomType(self._interface.id):
-      return
-
-    interface = self._interface
-    if interface.parents:
-      supertype = '%sClassId' % interface.parents[0].type.id
-    else:
-      supertype = '-1'
-
-    cpp_impl_includes = set(['"' + partial + '.h"'
-                             for partial in _GetCPPPartialNames(self._interface)])
-    cpp_header_handlers_emitter = emitter.Emitter()
-    cpp_impl_handlers_emitter = emitter.Emitter()
-    class_name = 'Dart%s' % self._interface.id
-    for operation in self._interface.operations:
-      function_name = operation.id
-      return_type = self.SecureOutputType(operation.type.id)
-      parameters = []
-      arguments = []
-      if operation.ext_attrs.get('CallWith') == 'ThisValue':
-        parameters.append('ScriptValue scriptValue')
-      conversion_includes = []
-      for argument in operation.arguments:
-        argument_type_info = self._TypeInfo(argument.type.id)
-        parameters.append('%s %s' % (argument_type_info.parameter_type(),
-                                     argument.id))
-        arguments.append(argument_type_info.to_dart_conversion(argument.id))
-        conversion_includes.extend(argument_type_info.conversion_includes())
-
-      # FIXME(vsm): Handle ThisValue attribute.
-      if (return_type == 'void'):
-        ret = ''
-      else:
-        ret = '        return 0;\n'
-
-      if operation.ext_attrs.get('CallWith') == 'ThisValue':
-        cpp_header_handlers_emitter.Emit(
-            '\n'
-            '    virtual $RETURN_TYPE $FUNCTION($PARAMETERS) {\n'
-            '        DART_UNIMPLEMENTED();\n'
-            '$RET'
-            '    }\n',
-            RETURN_TYPE=return_type,
-            RET=ret,
-            FUNCTION=function_name,
-            PARAMETERS=', '.join(parameters))
-        continue
-
-      cpp_header_handlers_emitter.Emit(
-          '\n'
-          '    virtual $RETURN_TYPE $FUNCTION($PARAMETERS);\n',
-          RETURN_TYPE=return_type,
-          FUNCTION=function_name,
-          PARAMETERS=', '.join(parameters))
-
-      if _IsCustom(operation):
-        continue
-
-      cpp_impl_includes |= set(conversion_includes)
-      arguments_declaration = 'Dart_Handle arguments[] = { %s }' % ', '.join(arguments)
-      if not len(arguments):
-        arguments_declaration = 'Dart_Handle* arguments = 0'
-      if (return_type == 'void'):
-        ret1 = 'return'
-        ret2 = ''
-      else:
-        ret1 = 'return 0'
-        ret2 = ' return'
-      cpp_impl_handlers_emitter.Emit(
-          '\n'
-          '$RETURN_TYPE $CLASS_NAME::$FUNCTION($PARAMETERS)\n'
-          '{\n'
-          '    if (!m_callback.isIsolateAlive())\n'
-          '        $RET1;\n'
-          '    DartIsolateScope scope(m_callback.isolate());\n'
-          '    DartApiScope apiScope;\n'
-          '    $ARGUMENTS_DECLARATION;\n'
-          '   $RET2 m_callback.handleEvent($ARGUMENT_COUNT, arguments);\n'
-          '}\n',
-          RETURN_TYPE=return_type,
-          RET1=ret1,
-          RET2=ret2,
-          CLASS_NAME=class_name,
-          FUNCTION=function_name,
-          PARAMETERS=', '.join(parameters),
-          ARGUMENTS_DECLARATION=arguments_declaration,
-          ARGUMENT_COUNT=len(arguments))
-
-    cpp_header_emitter = self._cpp_library_emitter.CreateHeaderEmitter(
-        self._interface.id,
-        self._renamer.GetLibraryName(self._interface),
-        True)
-    cpp_header_emitter.Emit(
-        self._template_loader.Load('cpp_callback_header.template'),
-        INTERFACE=self._interface.id,
-        HANDLERS=cpp_header_handlers_emitter.Fragments())
-
-    cpp_impl_emitter = self._cpp_library_emitter.CreateSourceEmitter(self._interface.id)
-    cpp_impl_emitter.Emit(
-        self._template_loader.Load('cpp_callback_implementation.template'),
-        INCLUDES=self._GenerateCPPIncludes(cpp_impl_includes),
-        INTERFACE=self._interface.id,
-        SUPER_INTERFACE=supertype,
-        HANDLERS=cpp_impl_handlers_emitter.Fragments(),
-        DART_IMPLEMENTATION_CLASS=self._interface_type_info.implementation_name(),
-        DART_IMPLEMENTATION_LIBRARY_ID='Dart%sLibraryId' % self._renamer.GetLibraryId(self._interface))
+    return None
 
   def ImplementationTemplate(self):
     template = None
@@ -588,10 +195,6 @@
 
     self._cpp_declarations_emitter = emitter.Emitter()
 
-    self._cpp_impl_includes = \
-      set(['"' + partial + '.h"'
-           for partial in _GetCPPPartialNames(self._interface)])
-
     # This is a hack to work around a strange C++ compile error that we weren't
     # able to track down the true cause of.
     if self._interface.id == 'Timing':
@@ -704,16 +307,6 @@
     if 'NamedConstructor' in ext_attrs:
       create_function = 'createForJSConstructor'
     function_expression = '%s::%s' % (self._interface_type_info.native_type(), create_function)
-    self._GenerateNativeCallback(
-        constructor_callback_cpp_name,
-        False,
-        function_expression,
-        self._interface,
-        arguments,
-        self._interface.id,
-        False,
-        'ConstructorRaisesException' in ext_attrs or 'RaisesException' in ext_attrs,
-        True)
 
   def HasSupportCheck(self):
     # Need to omit a support check if it is conditional in JS.
@@ -906,7 +499,7 @@
       self._AddSetter(attribute, html_name)
 
   def _GenerateAutoSetupScope(self, idl_name, native_suffix):
-    return (self._interface.id, idl_name, native_suffix) not in _cpp_no_auto_scope_list
+    return None
 
   def _AddGetter(self, attr, html_name, read_only):
     # Temporary hack to force dart:scalarlist clamped array for ImageData.data.
@@ -914,7 +507,14 @@
     if self._interface.id == 'ImageData' and html_name == 'data':
       html_name = '_data'
     type_info = self._TypeInfo(attr.type.id)
+
     return_type = self.SecureOutputType(attr.type.id, False, False if self._dart_use_blink else True)
+    dictionary_returned = False
+    # Return type for dictionary is any (untyped).
+    if attr.type.id == 'Dictionary':
+      return_type = '';
+      dictionary_returned = True;
+
     parameters = []
     dart_declaration = '%s get %s' % (return_type, html_name)
     is_custom = _IsCustom(attr) and (_IsCustomValue(attr, None) or
@@ -946,7 +546,7 @@
     cpp_callback_name = self._GenerateNativeBinding(attr.id, 1,
         dart_declaration, attr.is_static, return_type, parameters,
         native_suffix, is_custom, auto_scope_setup, native_entry=native_entry,
-        wrap_unwrap_list=wrap_unwrap_list)
+        wrap_unwrap_list=wrap_unwrap_list, dictionary_return=dictionary_returned)
     if is_custom:
       return
 
@@ -972,16 +572,6 @@
     function_expression = self._GenerateWebCoreFunctionExpression(webcore_function_name, attr)
     raises = ('RaisesException' in attr.ext_attrs and
               attr.ext_attrs['RaisesException'] != 'Setter')
-    self._GenerateNativeCallback(
-        cpp_callback_name,
-        True,
-        function_expression,
-        attr,
-        [],
-        attr.type.id,
-        attr.type.nullable,
-        raises,
-        auto_scope_setup)
 
   def _AddSetter(self, attr, html_name):
     return_type = 'void'
@@ -1032,17 +622,6 @@
     function_expression = self._GenerateWebCoreFunctionExpression(webcore_function_name, attr)
     raises = ('RaisesException' in attr.ext_attrs and
               attr.ext_attrs['RaisesException'] != 'Getter')
-    self._GenerateNativeCallback(
-        cpp_callback_name,
-        True,
-        function_expression,
-        attr,
-        [attr],
-        'void',
-        False,
-        raises,
-        auto_scope_setup,
-        generate_custom_element_scope_if_needed=True)
 
   def AddIndexer(self, element_type):
     """Adds all the methods required to complete implementation of List."""
@@ -1184,11 +763,28 @@
       dart_declaration, False, return_type, parameters,
       'Callback', True, False)
 
+  def _ChangePrivateOpMapArgToAny(self, operations):
+    # TODO(terry): Hack to map any operations marked as private to not
+    #              handle converting Map to native (JsObject) the public
+    #              members that call the private method will have done
+    #              conversions.
+    for operation in operations:
+      for arg in operation.arguments:
+        type = arg.type
+        if type.id == 'Dictionary':
+          type.id = 'any'
+
   def EmitOperation(self, info, html_name, dart_js_interop=False):
     """
     Arguments:
       info: An OperationInfo object.
     """
+    if self._renamer.isPrivate(self._interface, info.operations[0].id):
+      # Any private operations with Maps parameters changed to any type.
+      # The public method that delegates to this private operation has already
+      # converted from Map to native (JsObject) e.g., Element.animate.
+      self._ChangePrivateOpMapArgToAny(info.operations)
+
     return_type = self.SecureOutputType(info.type_name, False, False if dart_js_interop else True)
 
     formals = info.ParametersAsDeclaration(self._DartType)
@@ -1197,14 +793,21 @@
                                                   self._type_registry if self._dart_use_blink else None,
                                                   dart_js_interop,
                                                   self)
+
+    operation = info.operations[0]
+
+    dictionary_returned = False
+    # Return type for dictionary is any (untyped).
+    if operation.type.id == 'Dictionary':
+      return_type = '';
+      dictionary_returned = True;
+
     dart_declaration = '%s%s %s(%s)' % (
         'static ' if info.IsStatic() else '',
         return_type,
         html_name,
         formals)
 
-    operation = info.operations[0]
-
     is_custom = _IsCustom(operation)
     has_optional_arguments = any(IsOptional(argument) for argument in operation.arguments)
     needs_dispatcher = not is_custom and (len(info.operations) > 1 or has_optional_arguments)
@@ -1246,7 +849,8 @@
         info.IsStatic(), return_type, parameters,
         native_suffix, is_custom, auto_scope_setup,
         native_entry=native_entry,
-        wrap_unwrap_list=wrap_unwrap_list)
+        wrap_unwrap_list=wrap_unwrap_list,
+        dictionary_return=dictionary_returned)
       if not is_custom:
         self._GenerateOperationNativeCallback(operation, operation.arguments, cpp_callback_name, auto_scope_setup)
     else:
@@ -1317,392 +921,11 @@
     webcore_function_name = operation.ext_attrs.get('ImplementedAs', operation.id)
 
     function_expression = self._GenerateWebCoreFunctionExpression(webcore_function_name, operation, cpp_callback_name)
-    self._GenerateNativeCallback(
-        cpp_callback_name,
-        not operation.is_static,
-        function_expression,
-        operation,
-        arguments,
-        operation.type.id,
-        operation.type.nullable,
-        'RaisesException' in operation.ext_attrs,
-        auto_scope_setup,
-        generate_custom_element_scope_if_needed=True)
-
-  def _GenerateNativeCallback(self,
-      callback_name,
-      needs_receiver,
-      function_expression,
-      node,
-      arguments,
-      return_type,
-      return_type_is_nullable,
-      raises_dom_exception,
-      auto_scope_setup=True,
-      generate_custom_element_scope_if_needed=False):
-
-    ext_attrs = node.ext_attrs
-
-    if self._IsStatic(node.id):
-      needs_receiver = True
-
-    cpp_arguments = []
-    runtime_check = None
-    raises_exceptions = raises_dom_exception or arguments or needs_receiver
-    needs_custom_element_callbacks = False
-
-    # TODO(antonm): unify with ScriptState below.
-    call_with = ext_attrs.get('CallWith', [])
-    if not(isinstance(call_with, list)):
-      call_with = [call_with]
-    constructor_with = ext_attrs.get('ConstructorCallWith', [])
-    if not(isinstance(constructor_with, list)):
-      constructor_with = [constructor_with]
-    call_with = call_with + constructor_with
-
-
-    requires_stack_info = 'ScriptArguments' in call_with or 'ScriptState' in call_with
-    if requires_stack_info:
-      raises_exceptions = True
-      cpp_arguments = ['&state', 'scriptArguments.release()']
-      # WebKit uses scriptArguments to reconstruct last argument, so
-      # it's not needed and should be just removed.
-      arguments = arguments[:-1]
-
-    # TODO(antonm): unify with ScriptState below.
-    requires_script_arguments = (ext_attrs.get('CallWith') == 'ScriptArguments' or
-                                 ext_attrs.get('ConstructorCallWith') == 'ScriptArguments')
-    if requires_script_arguments:
-      raises_exceptions = True
-      cpp_arguments = ['scriptArguments.release()']
-      # WebKit uses scriptArguments to reconstruct last argument, so
-      # it's not needed and should be just removed.
-      arguments = arguments[:-1]
-
-    requires_script_execution_context = (ext_attrs.get('CallWith') == 'ExecutionContext' or
-                                         ext_attrs.get('ConstructorCallWith') == 'ExecutionContext')
-
-    # Hack because our parser misses that these IDL members require an execution
-    # context.
-
-    if (self._interface.id == 'FontFace'
-        and callback_name in ['familySetter', 'featureSettingsSetter', 'stretchSetter',
-                              'styleSetter', 'unicodeRangeSetter', 'variantSetter', 'weightSetter']):
-      requires_script_execution_context = True
-
-    requires_document = ext_attrs.get('ConstructorCallWith') == 'Document'
-
-    if requires_script_execution_context:
-      raises_exceptions = True
-      cpp_arguments = ['context']
-
-    requires_script_state = (ext_attrs.get('CallWith') == 'ScriptState' or
-                             ext_attrs.get('ConstructorCallWith') == 'ScriptState')
-    if requires_script_state:
-      raises_exceptions = True
-      cpp_arguments = ['&state']
-
-    requires_dom_window = 'NamedConstructor' in ext_attrs
-    if requires_dom_window or requires_document:
-      raises_exceptions = True
-      cpp_arguments = ['document']
-
-    if 'ImplementedBy' in ext_attrs:
-      assert needs_receiver
-      self._cpp_impl_includes.add('"%s.h"' % ext_attrs['ImplementedBy'])
-      cpp_arguments.append('receiver')
-
-    if 'Reflect' in ext_attrs:
-      cpp_arguments = [self._GenerateWebCoreReflectionAttributeName(node)]
-
-    if generate_custom_element_scope_if_needed and (ext_attrs.get('CustomElementCallbacks', 'None') != 'None' or 'Reflect' in ext_attrs):
-      self._cpp_impl_includes.add('"core/dom/custom/CustomElementCallbackDispatcher.h"')
-      needs_custom_element_callbacks = True
-
-    if return_type_is_nullable:
-      cpp_arguments = ['isNull']
-
-    v8EnabledPerContext = ext_attrs.get('synthesizedV8EnabledPerContext', ext_attrs.get('V8EnabledPerContext'))
-    v8EnabledAtRuntime = ext_attrs.get('synthesizedV8EnabledAtRuntime', ext_attrs.get('V8EnabledAtRuntime'))
-    assert(not (v8EnabledPerContext and v8EnabledAtRuntime))
-
-    if v8EnabledPerContext:
-      raises_exceptions = True
-      self._cpp_impl_includes.add('"ContextFeatures.h"')
-      self._cpp_impl_includes.add('"DOMWindow.h"')
-      runtime_check = emitter.Format(
-          '        if (!ContextFeatures::$(FEATURE)Enabled(DartUtilities::domWindowForCurrentIsolate()->document())) {\n'
-          '            exception = Dart_NewStringFromCString("Feature $FEATURE is not enabled");\n'
-          '            goto fail;\n'
-          '        }',
-          FEATURE=v8EnabledPerContext)
-
-    if v8EnabledAtRuntime:
-      raises_exceptions = True
-      self._cpp_impl_includes.add('"RuntimeEnabledFeatures.h"')
-      runtime_check = emitter.Format(
-          '        if (!RuntimeEnabledFeatures::$(FEATURE)Enabled()) {\n'
-          '            exception = Dart_NewStringFromCString("Feature $FEATURE is not enabled");\n'
-          '            goto fail;\n'
-          '        }',
-          FEATURE=self._ToWebKitName(v8EnabledAtRuntime))
-
-    body_emitter = self._cpp_definitions_emitter.Emit(
-        '\n'
-        'static void $CALLBACK_NAME(Dart_NativeArguments args)\n'
-        '{\n'
-        '$!BODY'
-        '}\n',
-        CALLBACK_NAME=callback_name)
-
-    if raises_exceptions:
-      body_emitter = body_emitter.Emit(
-          '    Dart_Handle exception = 0;\n'
-          '$!BODY'
-          '\n'
-          'fail:\n'
-          '    Dart_ThrowException(exception);\n'
-          '    ASSERT_NOT_REACHED();\n')
-
-    body_emitter = body_emitter.Emit(
-        '    {\n'
-        '$!BODY'
-        '        return;\n'
-        '    }\n')
-
-    if runtime_check:
-      body_emitter.Emit(
-          '$RUNTIME_CHECK\n',
-          RUNTIME_CHECK=runtime_check)
-
-    if requires_script_execution_context:
-      body_emitter.Emit(
-          '        ExecutionContext* context = DartUtilities::scriptExecutionContext();\n'
-          '        if (!context) {\n'
-          '            exception = Dart_NewStringFromCString("Failed to retrieve a context");\n'
-          '            goto fail;\n'
-          '        }\n\n')
-
-    if requires_script_state:
-      body_emitter.Emit(
-          '        ScriptState* currentState = DartUtilities::currentScriptState();\n'
-          '        if (!currentState) {\n'
-          '            exception = Dart_NewStringFromCString("Failed to retrieve a script state");\n'
-          '            goto fail;\n'
-          '        }\n'
-          '        ScriptState& state = *currentState;\n\n')
-
-    if requires_dom_window or requires_document:
-      self._cpp_impl_includes.add('"DOMWindow.h"')
-
-      body_emitter.Emit(
-          '        DOMWindow* domWindow = DartUtilities::domWindowForCurrentIsolate();\n'
-          '        if (!domWindow) {\n'
-          '            exception = Dart_NewStringFromCString("Failed to fetch domWindow");\n'
-          '            goto fail;\n'
-          '        }\n'
-          '        Document& document = *domWindow->document();\n')
-
-    if needs_receiver:
-      body_emitter.Emit(
-        '        $WEBCORE_CLASS_NAME* receiver = '
-        'DartDOMWrapper::receiverChecked<Dart$INTERFACE>(args, exception);\n'
-        '        if (exception)\n'
-        '            goto fail;\n',
-        WEBCORE_CLASS_NAME=self._interface_type_info.native_type(),
-        INTERFACE=self._interface.id)
-
-    if requires_stack_info:
-      self._cpp_impl_includes.add('"ScriptArguments.h"')
-      body_emitter.Emit(
-          '\n'
-          '        ScriptState* currentState = DartUtilities::currentScriptState();\n'
-          '        if (!currentState) {\n'
-          '            exception = Dart_NewStringFromCString("Failed to retrieve a script state");\n'
-          '            goto fail;\n'
-          '        }\n'
-          '        ScriptState& state = *currentState;\n'
-          '\n'
-          '        Dart_Handle customArgument = Dart_GetNativeArgument(args, $INDEX);\n'
-          '        RefPtr<ScriptArguments> scriptArguments(DartUtilities::createScriptArguments(customArgument, exception));\n'
-          '        if (!scriptArguments)\n'
-          '            goto fail;\n',
-          INDEX=len(arguments) + 1)
-
-    if requires_script_arguments:
-      self._cpp_impl_includes.add('"ScriptArguments.h"')
-      body_emitter.Emit(
-          '\n'
-          '        Dart_Handle customArgument = Dart_GetNativeArgument(args, $INDEX);\n'
-          '        RefPtr<ScriptArguments> scriptArguments(DartUtilities::createScriptArguments(customArgument, exception));\n'
-          '        if (!scriptArguments)\n'
-          '            goto fail;\n',
-          INDEX=len(arguments) + 1)
-
-    if needs_custom_element_callbacks:
-      body_emitter.Emit('        CustomElementCallbackDispatcher::CallbackDeliveryScope deliveryScope;\n');
-
-    # Emit arguments.
-    start_index = 1 if needs_receiver else 0
-    for i, argument in enumerate(arguments):
-      type_info = self._TypeInfo(argument.type.id)
-      self._cpp_impl_includes |= set(type_info.conversion_includes())
-      argument_expression_template, type, cls, function = \
-          type_info.to_native_info(argument, self._interface.id, callback_name)
-
-      def AllowsNull():
-        # TODO(vsm): HTMLSelectElement's indexed setter treats a null as a remove.
-        # We need to handle that.
-        # assert argument.ext_attrs.get('TreatNullAs', 'NullString') == 'NullString'
-        if argument.ext_attrs.get('TreatNullAs') == 'NullString':
-          return True
-
-        if argument.type.nullable:
-          return True
-
-        if isinstance(argument, IDLAttribute):
-          return (argument.type.id == 'DOMString') and \
-              ('Reflect' in argument.ext_attrs)
-
-        if isinstance(argument, IDLArgument):
-          if IsOptional(argument) and not self._IsArgumentOptionalInWebCore(node, argument):
-            return True
-          # argument default to null (e.g., DOMString arg = null).
-          if argument.default_value_is_null:
-            return True
-          if _IsOptionalStringArgumentInInitEventMethod(self._interface, node, argument):
-            return True
-
-        return False
-
-      if AllowsNull():
-        function += 'WithNullCheck'
-
-      argument_name = DartDomNameOfAttribute(argument)
-      if type_info.pass_native_by_ref():
-        invocation_template =\
-            '        $TYPE $ARGUMENT_NAME;\n'\
-            '        $CLS::$FUNCTION(args, $INDEX, $ARGUMENT_NAME, exception);\n'
-      else:
-        if not auto_scope_setup and type_info.native_type() == 'String':
-          invocation_template =\
-              '        $TYPE $ARGUMENT_NAME = $CLS::$FUNCTION(args, $INDEX, exception, false);\n'
-        else:
-          invocation_template =\
-              '        $TYPE $ARGUMENT_NAME = $CLS::$FUNCTION(args, $INDEX, exception);\n'
-      body_emitter.Emit(
-          '\n' +
-          invocation_template +
-          '        if (exception)\n'
-          '            goto fail;\n',
-          TYPE=type,
-          ARGUMENT_NAME=argument_name,
-          CLS=cls,
-          FUNCTION=function,
-          INDEX=start_index + i)
-      self._cpp_impl_includes.add('"%s.h"' % cls)
-      cpp_arguments.append(argument_expression_template % argument_name)
-
-    body_emitter.Emit('\n')
-
-    if 'NeedsUserGestureCheck' in ext_attrs:
-      cpp_arguments.append('DartUtilities::processingUserGesture')
-
-    invocation_emitter = body_emitter
-    if raises_dom_exception:
-      cpp_arguments.append('es')
-      invocation_emitter = body_emitter.Emit(
-        '        DartExceptionState es;\n'
-        '$!INVOCATION'
-        '        if (es.hadException()) {\n'
-        '            exception = DartDOMWrapper::exceptionCodeToDartException(es);\n'
-        '            goto fail;\n'
-        '        }\n')
-
-
-    interface_name = self._interface_type_info.native_type()
-
-    if needs_receiver:
-      # Hack to determine if this came from the _cpp_callback_map.
-      # In this case, the getter is mapped to a static method.
-      if function_expression.startswith('SVGTests::'):
-          cpp_arguments.insert(0, 'receiver')
-      elif (not function_expression.startswith('receiver->') and
-          not function_expression.startswith(interface_name + '::')):
-        if (interface_name in ['DOMWindow', 'Element', 'Navigator', 'WorkerGlobalScope']
-            or (interface_name in ['SVGViewSpec', 'SVGViewElement', 'SVGSVGElement']
-              and callback_name in ['setZoomAndPan', 'zoomAndPanSetter', 'zoomAndPan'])
-            or (interface_name == 'Screen'
-              and callback_name in ['_lockOrientation_1Callback', '_lockOrientation_2Callback', 'unlockOrientation', 'orientation'])):
-          cpp_arguments.insert(0, 'receiver')
-        else:
-          cpp_arguments.append('receiver')
-      elif self._IsStatic(node.id):
-        cpp_arguments.insert(0, 'receiver')
-
-    if interface_name in ['SVGPropertyTearOff<SVGTransform>', 'SVGPropertyTearOff<SVGAngle>', 'SVGMatrixTearOff'] and function_expression.startswith('receiver->'):
-      # This is a horrible hack. I don't know why this one case has to be
-      # special cased.
-      if not (self._interface.id == 'SVGTransformList' and callback_name == 'createSVGTransformFromMatrixCallback'):
-        function_expression = 'receiver->propertyReference().%s' % (function_expression[len('receiver->'):])
-
-    function_call = '%s(%s)' % (function_expression, ', '.join(cpp_arguments))
-    if return_type == 'void':
-      invocation_emitter.Emit(
-        '        $FUNCTION_CALL;\n',
-        FUNCTION_CALL=function_call)
-    else:
-      return_type_info = self._TypeInfo(return_type)
-      self._cpp_impl_includes |= set(return_type_info.conversion_includes())
-
-      if return_type_is_nullable:
-        invocation_emitter.Emit(
-          '        bool isNull = false;\n'
-          '        $NATIVE_TYPE result = $FUNCTION_CALL;\n'
-          '        if (isNull)\n'
-          '            return;\n',
-          NATIVE_TYPE=return_type_info.parameter_type(),
-          FUNCTION_CALL=function_call)
-        value_expression = 'result'
-      else:
-        value_expression = function_call
-
-      # Generate to Dart conversion of C++ value.
-      if return_type_info.dart_type() == 'bool':
-        set_return_value = 'Dart_SetBooleanReturnValue(args, %s)' % (value_expression)
-      elif return_type_info.dart_type() == 'int':
-        if return_type_info.native_type() == 'unsigned':
-          set_return_value = 'DartUtilities::setDartUnsignedReturnValue(args, %s)' % (value_expression)
-        elif return_type_info.native_type() == 'unsigned long long':
-          set_return_value = 'DartUtilities::setDartUnsignedLongLongReturnValue(args, %s)' % (value_expression)
-        else:
-          assert (return_type_info.native_type() == 'int' or return_type_info.native_type() == 'long long')
-          set_return_value = 'DartUtilities::setDartIntegerReturnValue(args, %s)' % (value_expression)
-      elif return_type_info.dart_type() == 'double':
-        set_return_value = 'Dart_SetDoubleReturnValue(args, %s)' % (value_expression)
-      elif return_type_info.dart_type() == 'String':
-        auto_dart_scope='true' if auto_scope_setup else 'false'
-        if ext_attrs and 'TreatReturnedNullStringAs' in ext_attrs:
-          set_return_value = 'DartUtilities::setDartStringReturnValueWithNullCheck(args, %s, %s)' % (value_expression, auto_dart_scope)
-        else:
-          set_return_value = 'DartUtilities::setDartStringReturnValue(args, %s, %s)' % (value_expression, auto_dart_scope)
-      elif return_type_info.dart_type() == 'num' and return_type_info.native_type() == 'double':
-        set_return_value = 'Dart_SetDoubleReturnValue(args, %s)' % (value_expression)
-      else:
-        return_to_dart_conversion = return_type_info.return_to_dart_conversion(
-            value_expression,
-            auto_scope_setup,
-            self._interface.id,
-            ext_attrs)
-        set_return_value = '%s' % (return_to_dart_conversion)
-      invocation_emitter.Emit(
-        '        $RETURN_VALUE;\n',
-        RETURN_VALUE=set_return_value)
 
   def _GenerateNativeBinding(self, idl_name, argument_count, dart_declaration,
       static, return_type, parameters, native_suffix, is_custom,
       auto_scope_setup=True, emit_metadata=True, emit_to_native=False,
-      native_entry=None, wrap_unwrap_list=[]):
+      native_entry=None, wrap_unwrap_list=[], dictionary_return=False):
     metadata = []
     if emit_metadata:
       metadata = self._metadata.GetFormattedMetadata(
@@ -1745,14 +968,19 @@
   $METADATA$DART_DECLARATION => $DART_NAME($ACTUALS);
   '''
             if wrap_unwrap_list and wrap_unwrap_list[0]:
-                emit_jso_template = '''
-  $METADATA$DART_DECLARATION => %s($DART_NAME($ACTUALS));
-  '''
                 if return_type == 'Rectangle':
                     jso_util_method = 'make_dart_rectangle'
                 elif wrap_unwrap_list[0]:
                     jso_util_method = 'wrap_jso'
 
+                if dictionary_return:
+                  emit_jso_template = '''
+  $METADATA$DART_DECLARATION => convertNativeDictionaryToDartDictionary(%s($DART_NAME($ACTUALS)));
+  '''
+                else:
+                  emit_jso_template = '''
+  $METADATA$DART_DECLARATION => %s($DART_NAME($ACTUALS));
+  '''
                 emit_template = emit_jso_template % jso_util_method
 
             if caller_emitter:
@@ -1795,22 +1023,10 @@
     return 'WebCore::%s::%sAttr' % (namespace, attribute_name)
 
   def _IsStatic(self, attribute_name):
-    cpp_type_name = self._interface_type_info.native_type()
-    if cpp_type_name in _cpp_static_call_map:
-      return attribute_name in _cpp_static_call_map[cpp_type_name]
     return False
 
   def _GenerateWebCoreFunctionExpression(self, function_name, idl_node, cpp_callback_name=None):
-    if 'ImplementedBy' in idl_node.ext_attrs:
-      return '%s::%s' % (idl_node.ext_attrs['ImplementedBy'], function_name)
-    cpp_type_name = self._interface_type_info.native_type()
-    impl_type_name = _GetCPPTypeName(cpp_type_name, function_name, cpp_callback_name)
-    if idl_node.is_static or self._IsStatic(idl_node.id):
-      return '%s::%s' % (impl_type_name, function_name)
-    if cpp_type_name == impl_type_name:
-      return '%s%s' % (self._interface_type_info.receiver(), function_name)
-    else:
-      return '%s::%s' % (impl_type_name, function_name)
+    return None
 
   def _IsArgumentOptionalInWebCore(self, operation, argument):
     if not IsOptional(argument):
@@ -1826,7 +1042,7 @@
     return True
 
   def _GenerateCPPIncludes(self, includes):
-    return ''.join(['#include %s\n' % include for include in sorted(includes)])
+    return None
 
   def _ToWebKitName(self, name):
     name = name[0].lower() + name[1:]
diff --git a/tools/dom/src/dartium_CustomElementSupport.dart b/tools/dom/src/dartium_CustomElementSupport.dart
index aec7b4a..e769e88 100644
--- a/tools/dom/src/dartium_CustomElementSupport.dart
+++ b/tools/dom/src/dartium_CustomElementSupport.dart
@@ -44,7 +44,7 @@
         throw new UnsupportedError('$tag is not registered.');
       }
       jsObject = unwrap_jso(element);
-    } else if (element.runtimeType == js.JsObjectImpl) {
+    } else if (element.runtimeType == js.JsObject) {
       // It's a Polymer core element (written in JS).
       jsObject = element;
     } else if (isNativeElementExtension) {
@@ -56,7 +56,7 @@
     } else if (tag != null && element.localName != tag) {
       throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected native Html or Svg element to extend.');
     } else if (tag == null) {
-      throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObjectImpl.');
+      throw new UnsupportedError('Element is incorrect type. Got ${element.runtimeType}, expected HtmlElement/JsObject.');
     }
 
     // Remember Dart class to tagName for any upgrading done in wrap_jso.
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index e9e3720..2aad83f 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -197,7 +197,7 @@
 
   // TODO(vsm): Make this API compatible with spawnUri.  It should also
   // return a Future<Isolate>.
-  static spawnDomUri(String uri) => _blink.Blink_Utils.spawnDomUri(uri);
+  static spawnDomUri(String uri) => wrap_jso(_blink.Blink_Utils.spawnDomUri(uri));
 
   // The following methods were added for debugger integration to make working
   // with the Dart C mirrors API simpler.
@@ -774,7 +774,7 @@
     return [
         "inspect",
         (o) {
-          host.callMethod("inspect", [o]);
+          host.callMethod("_inspect", [unwrap_jso(o)]);
           return o;
         },
         "dir",
@@ -807,10 +807,10 @@
     String extendsTagName) => _blink.Blink_Utils.register(unwrap_jso(document), tag, customType, extendsTagName);
 
   static Element createElement(Document document, String tagName) =>
-    wrap_jso(_blink.Blink_Utils.createElement(unwrap_jso(document), tagName));
+      wrap_jso(_blink.Blink_Utils.createElement(unwrap_jso(document), tagName));
 
   static Element changeElementWrapper(HtmlElement element, Type type) =>
-    _blink.Blink_Utils.changeElementWrapper(unwrap_jso(element), type);
+      wrap_jso(_blink.Blink_Utils.changeElementWrapper(unwrap_jso(element), type));
 }
 
 class _DOMWindowCrossFrame extends DartHtmlDomObject implements
@@ -825,17 +825,18 @@
   _DOMWindowCrossFrame.internal();
 
   // Fields.
-  HistoryBase get history => _blink.Blink_DOMWindowCrossFrame.get_history(this);
-  LocationBase get location => _blink.Blink_DOMWindowCrossFrame.get_location(this);
-  bool get closed => _blink.Blink_DOMWindowCrossFrame.get_closed(this);
-  WindowBase get opener => _blink.Blink_DOMWindowCrossFrame.get_opener(this);
-  WindowBase get parent => _blink.Blink_DOMWindowCrossFrame.get_parent(this);
-  WindowBase get top => _blink.Blink_DOMWindowCrossFrame.get_top(this);
+  HistoryBase get history => wrap_jso(_blink.Blink_DOMWindowCrossFrame.get_history(unwrap_jso(this)));
+  LocationBase get location => wrap_jso(_blink.Blink_DOMWindowCrossFrame.get_location(unwrap_jso(this)));
+  bool get closed => wrap_jso(_blink.Blink_DOMWindowCrossFrame.get_closed(unwrap_jso(this)));
+  WindowBase get opener => wrap_jso(_blink.Blink_DOMWindowCrossFrame.get_opener(unwrap_jso(this)));
+  WindowBase get parent => wrap_jso(_blink.Blink_DOMWindowCrossFrame.get_parent(unwrap_jso(this)));
+  WindowBase get top => wrap_jso(_blink.Blink_DOMWindowCrossFrame.get_top(unwrap_jso(this)));
 
   // Methods.
-  void close() => _blink.Blink_DOMWindowCrossFrame.close(this);
+  void close() => _blink.Blink_DOMWindowCrossFrame.close(unwrap_jso(this));
   void postMessage(/*SerializedScriptValue*/ message, String targetOrigin, [List messagePorts]) =>
-    _blink.Blink_DOMWindowCrossFrame.postMessage(this, message, targetOrigin, messagePorts);
+      _blink.Blink_DOMWindowCrossFrame.postMessage(unwrap_jso(this),
+         convertDartToNative_SerializedScriptValue(message), targetOrigin, messagePorts);
 
   // Implementation support.
   String get typeName => "Window";
@@ -868,9 +869,9 @@
   _HistoryCrossFrame.internal();
 
   // Methods.
-  void back() => _blink.Blink_HistoryCrossFrame.back(this);
-  void forward() => _blink.Blink_HistoryCrossFrame.forward(this);
-  void go(int distance) => _blink.Blink_HistoryCrossFrame.go(this, distance);
+  void back() => _blink.Blink_HistoryCrossFrame.back(unwrap_jso(this));
+  void forward() => _blink.Blink_HistoryCrossFrame.forward(unwrap_jso(this));
+  void go(int distance) => _blink.Blink_HistoryCrossFrame.go(unwrap_jso(this), distance);
 
   // Implementation support.
   String get typeName => "History";
@@ -880,33 +881,12 @@
   _LocationCrossFrame.internal();
 
   // Fields.
-  set href(String h) => _blink.Blink_LocationCrossFrame.set_href(this, h);
+  set href(String h) => _blink.Blink_LocationCrossFrame.set_href(unwrap_jso(this), h);
 
   // Implementation support.
   String get typeName => "Location";
 }
 
-class _DOMStringMap extends DartHtmlDomObject implements Map<String, String> {
-  _DOMStringMap.internal();
-
-  bool containsValue(String value) => Maps.containsValue(this, value);
-  bool containsKey(String key) => _blink.Blink_DOMStringMap.containsKey(this, key);
-  String operator [](String key) => _blink.Blink_DOMStringMap.item(this, key);
-  void operator []=(String key, String value) => _blink.Blink_DOMStringMap.setItem(this, key, value);
-  String putIfAbsent(String key, String ifAbsent()) => Maps.putIfAbsent(this, key, ifAbsent);
-  String remove(String key) => _blink.Blink_DOMStringMap.remove(this, key);
-  void clear() => Maps.clear(this);
-  void forEach(void f(String key, String value)) => Maps.forEach(this, f);
-  Iterable<String> get keys => _blink.Blink_DOMStringMap.get_keys(this);
-  Iterable<String> get values => Maps.getValues(this);
-  int get length => Maps.length(this);
-  bool get isEmpty => Maps.isEmpty(this);
-  bool get isNotEmpty => Maps.isNotEmpty(this);
-  void addAll(Map<String, String> other) {
-    other.forEach((key, value) => this[key] = value);
-  }
-}
-
 // TODO(vsm): Remove DOM isolate code once we have Dartium isolates
 // as workers.  This is only used to support
 // printing and timers in background isolates. As workers they should
diff --git a/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate b/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate
index 2de24a0..fb00675 100644
--- a/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/web_sql_dart2js.darttemplate
@@ -19,7 +19,8 @@
 import 'dart:_internal';
 import 'dart:html';
 import 'dart:html_common';
-import 'dart:_js_helper' show convertDartClosureToJS, Creates, JSName, Native;
+import 'dart:_js_helper' show convertDartClosureToJS, Creates, JSName, Native,
+    JavaScriptIndexingBehavior;
 import 'dart:_foreign_helper' show JS;
 import 'dart:_interceptors' show Interceptor;
 
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index c82e9b5..66a18e0 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -158,9 +158,9 @@
   '_DOMWindowCrossFrame': () => _DOMWindowCrossFrame,
   // FIXME: Move these to better locations.
   'DateTime': () => DateTime,
-  'JsObject': () => js.JsObjectImpl,
-  'JsFunction': () => js.JsFunctionImpl,
-  'JsArray': () => js.JsArrayImpl,
+  'JsObject': () => js.JsObject,
+  'JsFunction': () => js.JsFunction,
+  'JsArray': () => js.JsArray,
 $!TYPE_MAP
 };
 
@@ -373,7 +373,7 @@
   } else if (runtimeType == TemplateElement) {
     // Data binding with a Dart class.
     tag = element.attributes['is'];
-  } else if (runtimeType == js.JsObjectImpl) {
+  } else if (runtimeType == js.JsObject) {
     // It's a Polymer core element (written in JS).
     // Make sure it's an element anything else we can ignore.
     if (element.hasProperty('nodeType') && element['nodeType'] == 1) {
@@ -386,7 +386,7 @@
       }
     }
   } else {
-    throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObjectImpl.');
+    throw new UnsupportedError('Element is incorrect type. Got ${runtimeType}, expected HtmlElement/HtmlTemplate/JsObject.');
   }
 
   return tag;
@@ -394,15 +394,9 @@
 
 /// An abstract class for all DOM objects we wrap in dart:html and related
 ///  libraries.
-///
-/// ** Internal Use Only **
 @Deprecated("Internal Use Only")
-class DartHtmlDomObject {
-
-  /// The underlying JS DOM object.
-  @Deprecated("Internal Use Only")
-  js.JsObject blink_jsObject;
-
+class DartHtmlDomObject extends js.JSObject {
+  DartHtmlDomObject() : super.internal();
 }
 
 @Deprecated("Internal Use Only")
@@ -418,24 +412,6 @@
   }
 }
 
-// TODO(terry): Manage JS interop JsFunctions for each listener used for add/
-//              removeEventListener.  These JsFunctions will leak look at
-//              fixing with weak-refs in C++.  The key are the hashcodes of the
-//              user's this (this is needed for futures) and listener function.
-Map<int, Map<int, js.JsFunction>> _knownListeners = {};
-
-@Deprecated("Internal Use Only")
-js.JsFunction wrap_event_listener(theObject, Function listener) {
-  var thisHashCode = theObject.hashCode;
-  var listenerHashCode = identityHashCode(listener);
-
-  _knownListeners.putIfAbsent(thisHashCode, () => new Map<int, js.JsFunction>());
-  _knownListeners[thisHashCode].putIfAbsent(listenerHashCode, () =>
-    new js.JsFunction.withThis((theObject, event) => listener(wrap_jso(event))));
-
-  return _knownListeners[thisHashCode][listenerHashCode];
-}
-
 @Deprecated("Internal Use Only")
 Map<String, dynamic> convertNativeObjectToDartMap(js.JsObject jsObject) {
   var result = new Map();
diff --git a/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate b/tools/dom/templates/html/impl/impl_CanvasRenderingContext2D.darttemplate
index bd70659..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.
@@ -59,6 +68,14 @@
 $endif
   }
 
+  @DomName('CanvasRenderingContext2D.createPatternFromImage')
+  CanvasPattern createPatternFromImage(ImageElement image, String repetitionType) =>
+$if DART2JS
+    JS('CanvasPattern', '#.createPattern(#, #)', this, image, repetitionType);
+$else
+    createPattern(image, repetitionType);
+$endif
+
   /**
    * Draws an image from a CanvasImageSource to an area of this canvas.
    *
diff --git a/tools/dom/templates/html/impl/impl_DOMException.darttemplate b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
index 9bbae84..498349b 100644
--- a/tools/dom/templates/html/impl/impl_DOMException.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
@@ -52,12 +52,7 @@
     return new DomException._internalWrap();
   }
 
-  @Deprecated("Internal Use Only")
-  js.JsObject blink_jsObject;
-
-  factory DomException._internalWrap() {
-    return new DomException.internal_();
-  }
+  external factory DomException._internalWrap();
 
   @Deprecated("Internal Use Only")
   DomException.internal_() { }
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 03539f5..4b8173b 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -796,7 +796,7 @@
    * on which the method is called, and calls the play() method of the
    * AnimationTimeline object of the document timeline of the node document
    * of the element, passing the newly created AnimationEffect as the argument
-   * to the method. Returns an AnimationPlayer for the effect.
+   * to the method. Returns an Animation for the effect.
    *
    * Examples
    *
@@ -815,7 +815,7 @@
   **/
   @Experimental()
   @SupportedBrowser(SupportedBrowser.CHROME, '36')
-  AnimationPlayer animate(Iterable<Map<String, dynamic>> frames, [timing]) {
+  Animation animate(Iterable<Map<String, dynamic>> frames, [timing]) {
     if (frames is! Iterable || !(frames.every((x) => x is Map))) {
       throw new ArgumentError("The frames parameter should be a List of Maps "
           "with frame information");
@@ -842,7 +842,7 @@
   @DomName('Element.animate')
   @JSName('animate')
   @Experimental() // untriaged
-  AnimationPlayer _animate(Object effect, [timing]) native;
+  Animation _animate(Object effect, [timing]) native;
 $endif
   /**
    * Called by the DOM whenever an attribute on this has been changed.
@@ -1520,6 +1520,10 @@
   }
 
 $if DART2JS
+  @DomName('Element.offsetParent')
+  @DocsEditable()
+  final Element offsetParent;
+
   @DomName('Element.offsetHeight')
   @DocsEditable()
   int get offsetHeight => JS('num', '#.offsetHeight', this).round();
@@ -1536,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();
@@ -1581,42 +1569,29 @@
   int get scrollWidth => JS('num', '#.scrollWidth', this).round();
 
 $else
-  $if JSINTEROP
   // Need to explicitly delegate because Element is no longer abstract for Dartium.
   bool get isContentEditable => _blink.BlinkHTMLElement.instance.isContentEditable_Getter_(unwrap_jso(this));
   void click() => _blink.BlinkHTMLElement.instance.click_Callback_0_(unwrap_jso(this));
 
+  @DomName('Element.offsetParent')
+  @DocsEditable()
+  Element get offsetParent => wrap_jso(_blink.BlinkElement.instance.offsetParent_Getter_(unwrap_jso(this)));
+
   @DomName('Element.offsetHeight')
   @DocsEditable()
-  int get offsetHeight => _blink.BlinkElement.instance.offsetHeight_Getter_(unwrap_jso(this)).round();
+  int get offsetHeight => _blink.BlinkElement.instance.offsetHeight_Getter_(unwrap_jso(this));
 
   @DomName('Element.offsetLeft')
   @DocsEditable()
-  int get offsetLeft => _blink.BlinkElement.instance.offsetLeft_Getter_(unwrap_jso(this)).round();
+  int get offsetLeft => _blink.BlinkElement.instance.offsetLeft_Getter_(unwrap_jso(this));
 
   @DomName('Element.offsetTop')
   @DocsEditable()
-  int get offsetTop => _blink.BlinkElement.instance.offsetTop_Getter_(unwrap_jso(this)).round();
+  int get offsetTop => _blink.BlinkElement.instance.offsetTop_Getter_(unwrap_jso(this));
 
   @DomName('Element.offsetWidth')
   @DocsEditable()
-  int get offsetWidth => _blink.BlinkElement.instance.offsetWidth_Getter_(unwrap_jso(this)).round();
-
-  @DomName('Element.clientHeight')
-  @DocsEditable()
-  int get clientHeight => _blink.BlinkElement.instance.clientHeight_Getter_(unwrap_jso(this)).round();
-
-  @DomName('Element.clientLeft')
-  @DocsEditable()
-  int get clientLeft => _blink.BlinkElement.instance.clientLeft_Getter_(unwrap_jso(this)).round();
-
-  @DomName('Element.clientTop')
-  @DocsEditable()
-  int get clientTop => _blink.BlinkElement.instance.clientTop_Getter_(unwrap_jso(this)).round();
-
-  @DomName('Element.clientWidth')
-  @DocsEditable()
-  int get clientWidth => _blink.BlinkElement.instance.clientWidth_Getter_(unwrap_jso(this)).round();
+  int get offsetWidth => _blink.BlinkElement.instance.offsetWidth_Getter_(unwrap_jso(this));
 
   @DomName('Element.scrollHeight')
   @DocsEditable()
@@ -1641,63 +1616,6 @@
   @DomName('Element.scrollWidth')
   @DocsEditable()
   int get scrollWidth => _blink.BlinkElement.instance.scrollWidth_Getter_(unwrap_jso(this)).round();
-  $else
-  @DomName('Element.offsetHeight')
-  @DocsEditable()
-  int get offsetHeight => _blink.BlinkElement.offsetHeight_Getter(this).round();
-
-  @DomName('Element.offsetLeft')
-  @DocsEditable()
-  int get offsetLeft => _blink.BlinkElement.offsetLeft_Getter(this).round();
-
-  @DomName('Element.offsetTop')
-  @DocsEditable()
-  int get offsetTop => _blink.BlinkElement.offsetTop_Getter(this).round();
-
-  @DomName('Element.offsetWidth')
-  @DocsEditable()
-  int get offsetWidth => _blink.BlinkElement.offsetWidth_Getter(this).round();
-
-  @DomName('Element.clientHeight')
-  @DocsEditable()
-  int get clientHeight => _blink.BlinkElement.clientHeight_Getter(this).round();
-
-  @DomName('Element.clientLeft')
-  @DocsEditable()
-  int get clientLeft => _blink.BlinkElement.clientLeft_Getter(this).round();
-
-  @DomName('Element.clientTop')
-  @DocsEditable()
-  int get clientTop => _blink.BlinkElement.clientTop_Getter(this).round();
-
-  @DomName('Element.clientWidth')
-  @DocsEditable()
-  int get clientWidth => _blink.BlinkElement.clientWidth_Getter(this).round();
-
-  @DomName('Element.scrollHeight')
-  @DocsEditable()
-  int get scrollHeight => _blink.BlinkElement.scrollHeight_Getter(this).round();
-
-  @DomName('Element.scrollLeft')
-  @DocsEditable()
-  int get scrollLeft => _blink.BlinkElement.scrollLeft_Getter(this).round();
-
-  @DomName('Element.scrollLeft')
-  @DocsEditable()
-  set scrollLeft(int value) => _blink.BlinkElement.scrollLeft_Setter(this, value.round());
-
-  @DomName('Element.scrollTop')
-  @DocsEditable()
-  int get scrollTop => _blink.BlinkElement.scrollTop_Getter(this).round();
-
-  @DomName('Element.scrollTop')
-  @DocsEditable()
-  set scrollTop(int value) => _blink.BlinkElement.scrollTop_Setter(this, value.round());
-
-  @DomName('Element.scrollWidth')
-  @DocsEditable()
-  int get scrollWidth => _blink.BlinkElement.scrollWidth_Getter(this).round();
-  $endif
 $endif
 
 $!MEMBERS
diff --git a/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate b/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
index cf3c4e4..fec4341 100644
--- a/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_MessageEvent.darttemplate
@@ -21,11 +21,38 @@
           type, canBubble, cancelable, data, origin, lastEventId, source,
           messagePorts);
     }
-$endif 
+$endif
     var event = document._createEvent("MessageEvent");
     event._initMessageEvent(type, canBubble, cancelable, data, origin,
         lastEventId, source, messagePorts);
     return event;
   }
+
+$if DARTIUM
+  // 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(
+      _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/dom/templates/html/impl/impl_Window.darttemplate b/tools/dom/templates/html/impl/impl_Window.darttemplate
index d891762..0b64409 100644
--- a/tools/dom/templates/html/impl/impl_Window.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Window.darttemplate
@@ -113,7 +113,7 @@
    * for the animation to continue.
    */
   @DomName('Window.requestAnimationFrame')
-  int requestAnimationFrame(RequestAnimationFrameCallback callback) {
+  int requestAnimationFrame(FrameRequestCallback callback) {
     _ensureRequestAnimationFrame();
     return _requestAnimationFrame(_wrapZone(callback));
   }
@@ -132,7 +132,7 @@
   }
 
   @JSName('requestAnimationFrame')
-  int _requestAnimationFrame(RequestAnimationFrameCallback callback) native;
+  int _requestAnimationFrame(FrameRequestCallback callback) native;
 
   @JSName('cancelAnimationFrame')
   void _cancelAnimationFrame(int id) native;
@@ -200,7 +200,7 @@
    * for the animation to continue.
    */
   @DomName('Window.requestAnimationFrame')
-  int requestAnimationFrame(RequestAnimationFrameCallback callback) {
+  int requestAnimationFrame(FrameRequestCallback callback) {
     return _requestAnimationFrame(_wrapZone(callback));
   }
 $endif
diff --git a/tools/gyp/all.gypi b/tools/gyp/all.gypi
index bd03ab0..1e6b313 100644
--- a/tools/gyp/all.gypi
+++ b/tools/gyp/all.gypi
@@ -12,8 +12,6 @@
     'target_arch': 'ia32',
     # Flag that tells us whether to build native support for dart:io.
     'dart_io_support': 1,
-    # Flag controls whether or not frame pointers are enabled.
-    'c_frame_pointers%': 1,
   },
   'conditions': [
     [ 'OS=="linux"', {
diff --git a/tools/gyp/configurations.gypi b/tools/gyp/configurations.gypi
index 5b55362..84237ca 100644
--- a/tools/gyp/configurations.gypi
+++ b/tools/gyp/configurations.gypi
@@ -17,9 +17,11 @@
       ['"<(target_arch)"=="ia32"', { 'dart_target_arch': 'IA32', }],
       ['"<(target_arch)"=="x64"', { 'dart_target_arch': 'X64', }],
       ['"<(target_arch)"=="arm"', { 'dart_target_arch': 'ARM', }],
+      ['"<(target_arch)"=="armv6"', { 'dart_target_arch': 'ARMV6', }],
       ['"<(target_arch)"=="armv5te"', { 'dart_target_arch': 'ARMV5TE', }],
       ['"<(target_arch)"=="arm64"', { 'dart_target_arch': 'ARM64', }],
       ['"<(target_arch)"=="simarm"', { 'dart_target_arch': 'SIMARM', }],
+      ['"<(target_arch)"=="simarmv6"', { 'dart_target_arch': 'SIMARMV6', }],
       ['"<(target_arch)"=="simarmv5te"', { 'dart_target_arch': 'SIMARMV5TE', }],
       ['"<(target_arch)"=="simarm64"', { 'dart_target_arch': 'SIMARM64', }],
       ['"<(target_arch)"=="mips"', { 'dart_target_arch': 'MIPS', }],
@@ -63,6 +65,14 @@
         ]
       },
 
+      'Dart_simarmv6_Base': {
+        'abstract': 1,
+        'defines': [
+          'TARGET_ARCH_ARM',
+          'TARGET_ARCH_ARM_6',
+        ]
+      },
+
       'Dart_simarmv5te_Base': {
         'abstract': 1,
         'defines': [
@@ -78,6 +88,14 @@
         ],
       },
 
+      'Dart_armv6_Base': {
+        'abstract': 1,
+        'defines': [
+          'TARGET_ARCH_ARM',
+          'TARGET_ARCH_ARM_6',
+        ],
+      },
+
       'Dart_armv5te_Base': {
         'abstract': 1,
         'defines': [
@@ -125,6 +143,13 @@
         ],
       },
 
+      'Dart_Product' : {
+        'abstract': 1,
+        'defines' : [
+          'NDEBUG',
+          'PRODUCT',
+        ]
+      },
 
       # Configurations
       'DebugIA32': {
@@ -145,6 +170,15 @@
         ],
       },
 
+      'ProductIA32': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_ia32_Base', 'Dart_Product',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_ia32_Base',
+          'Dart_<(dart_target_os)_Product',
+        ],
+      },
+
       'DebugX64': {
         'inherit_from': [
           'Dart_Base', 'Dart_x64_Base', 'Dart_Debug',
@@ -163,6 +197,15 @@
         ],
       },
 
+      'ProductX64': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_x64_Base', 'Dart_Product',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_x64_Base',
+          'Dart_<(dart_target_os)_Product',
+        ],
+      },
+
       'DebugSIMARM': {
         'inherit_from': [
           'Dart_Base', 'Dart_simarm_Base', 'Dart_Debug',
@@ -184,6 +227,45 @@
         ],
       },
 
+      'ProductSIMARM': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_simarm_Base', 'Dart_Product',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_simarm_Base',
+          'Dart_<(dart_target_os)_Product',
+        ],
+      },
+
+      'DebugSIMARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_simarmv6_Base', 'Dart_Debug',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_simarmv6_Base',
+          'Dart_<(dart_target_os)_Debug',
+        ],
+        'defines': [
+          'DEBUG',
+        ],
+      },
+
+      'ReleaseSIMARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_simarmv6_Base', 'Dart_Release',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_simarmv6_Base',
+          'Dart_<(dart_target_os)_Release',
+        ],
+      },
+
+      'ProductSIMARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_simarmv6_Base', 'Dart_Product',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_simarmv6_Base',
+          'Dart_<(dart_target_os)_Product',
+        ],
+      },
+
       'DebugSIMARMV5TE': {
         'inherit_from': [
           'Dart_Base', 'Dart_simarmv5te_Base', 'Dart_Debug',
@@ -205,6 +287,15 @@
         ],
       },
 
+      'ProductSIMARMV5TE': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_simarmv5te_Base', 'Dart_Product',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_simarmv5te_Base',
+          'Dart_<(dart_target_os)_Product',
+        ],
+      },
+
       'DebugSIMARM64': {
         'inherit_from': [
           'Dart_Base', 'Dart_simarm64_Base', 'Dart_Debug',
@@ -226,6 +317,15 @@
         ],
       },
 
+      'ProductSIMARM64': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_simarm64_Base', 'Dart_Product',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_simarm64_Base',
+          'Dart_<(dart_target_os)_Product',
+        ],
+      },
+
       'DebugSIMMIPS': {
         'inherit_from': [
           'Dart_Base', 'Dart_simmips_Base', 'Dart_Debug',
@@ -247,6 +347,15 @@
         ],
       },
 
+      'ProductSIMMIPS': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_simmips_Base', 'Dart_Product',
+          'Dart_<(dart_target_os)_Base',
+          'Dart_<(dart_target_os)_simmips_Base',
+          'Dart_<(dart_target_os)_Product',
+        ],
+      },
+
 
       # ARM and MIPS hardware configurations are only for Linux and Android.
       'DebugXARM': {
@@ -267,6 +376,15 @@
         ],
       },
 
+      'ProductXARM': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_arm_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_xarm_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
       'DebugARM': {
         'inherit_from': [
           'Dart_Base', 'Dart_arm_Base', 'Dart_Debug',
@@ -285,6 +403,69 @@
         ],
       },
 
+      'ProductARM': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_arm_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_arm_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
+      'DebugXARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_armv6_Base', 'Dart_Debug',
+          'Dart_Linux_Base',
+          'Dart_Linux_xarmv6_Base',
+          'Dart_Linux_Debug',
+        ],
+      },
+
+      'ReleaseXARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_armv6_Base', 'Dart_Release',
+          'Dart_Linux_Base',
+          'Dart_Linux_xarmv6_Base',
+          'Dart_Linux_Release',
+        ],
+      },
+
+      'ProductXARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_armv6_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_xarmv6_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
+      'DebugARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_armv6_Base', 'Dart_Debug',
+          'Dart_Linux_Base',
+          'Dart_Linux_armv6_Base',
+          'Dart_Linux_Debug',
+        ],
+      },
+
+      'ReleaseARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_armv6_Base', 'Dart_Release',
+          'Dart_Linux_Base',
+          'Dart_Linux_armv6_Base',
+          'Dart_Linux_Release',
+        ],
+      },
+
+      'ProductARMV6': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_armv6_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_armv6_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
       'DebugXARMV5TE': {
         'inherit_from': [
           'Dart_Base', 'Dart_armv5te_Base', 'Dart_Debug',
@@ -303,6 +484,15 @@
         ],
       },
 
+      'ProductXARMV5TE': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_armv5te_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_xarmv5te_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
       'DebugARMV5TE': {
         'inherit_from': [
           'Dart_Base', 'Dart_armv5te_Base', 'Dart_Debug',
@@ -321,6 +511,15 @@
         ],
       },
 
+      'ProductARMV5TE': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_armv5te_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_armv5te_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
       'DebugXARM64': {
         'inherit_from': [
           'Dart_Base', 'Dart_arm64_Base', 'Dart_Debug',
@@ -339,6 +538,15 @@
         ],
       },
 
+      'ProductXARM64': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_arm64_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_xarm64_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
       'DebugARM64': {
         'inherit_from': [
           'Dart_Base', 'Dart_arm64_Base', 'Dart_Debug',
@@ -357,6 +565,15 @@
         ],
       },
 
+      'ProductARM64': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_arm64_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_arm64_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
       'DebugXMIPS': {
         'inherit_from': [
           'Dart_Base', 'Dart_mips_Base', 'Dart_Debug',
@@ -375,6 +592,15 @@
         ],
       },
 
+      'ProductXMIPS': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_mips_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_xmips_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
       'DebugMIPS': {
         'inherit_from': [
           'Dart_Base', 'Dart_mips_Base', 'Dart_Debug',
@@ -393,6 +619,15 @@
         ],
       },
 
+      'ProductMIPS': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_mips_Base', 'Dart_Product',
+          'Dart_Linux_Base',
+          'Dart_Linux_mips_Base',
+          'Dart_Linux_Product',
+        ],
+      },
+
       # Android configurations. The configuration names explicitly include
       # 'Android' because we are cross-building from Linux, and, when building
       # the standalone VM, we cannot inspect the gyp built-in 'OS' variable to
@@ -416,6 +651,15 @@
         ],
       },
 
+      'ProductAndroidIA32': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_ia32_Base', 'Dart_Product',
+          'Dart_Android_Base',
+          'Dart_Android_ia32_Base',
+          'Dart_Android_Product',
+        ],
+      },
+
       'DebugAndroidARM': {
         'inherit_from': [
           'Dart_Base', 'Dart_arm_Base', 'Dart_Debug',
@@ -434,6 +678,15 @@
         ],
       },
 
+      'ProductAndroidARM': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_arm_Base', 'Dart_Product',
+          'Dart_Android_Base',
+          'Dart_Android_arm_Base',
+          'Dart_Android_Product',
+        ],
+      },
+
       'DebugAndroidARM64': {
         'inherit_from': [
           'Dart_Base', 'Dart_arm64_Base', 'Dart_Debug',
@@ -452,6 +705,15 @@
         ],
       },
 
+      'ProductAndroidARM64': {
+        'inherit_from': [
+          'Dart_Base', 'Dart_arm64_Base', 'Dart_Product',
+          'Dart_Android_Base',
+          'Dart_Android_arm64_Base',
+          'Dart_Android_Product',
+        ],
+      },
+
       # These targets assume that target_arch is passed in explicitly
       # by the containing project (e.g., chromium).
       'Debug': {
diff --git a/tools/gyp/configurations_android.gypi b/tools/gyp/configurations_android.gypi
index 80ff1c6..0d6133d 100644
--- a/tools/gyp/configurations_android.gypi
+++ b/tools/gyp/configurations_android.gypi
@@ -51,15 +51,8 @@
         'defines': [
           'DEBUG',
         ],
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'cflags': [
-              '-fno-omit-frame-pointer',
-            ],
-            'defines': [
-              'NATIVE_CODE_HAS_FRAME_POINTERS'
-            ],
-          }],
+        'cflags': [
+          '-fno-omit-frame-pointer',
         ],
       },
       'Dart_Android_Release': {
@@ -72,19 +65,26 @@
           '-Os',
         ],
         'cflags': [
+          '-fno-omit-frame-pointer',
           '-fdata-sections',
           '-ffunction-sections',
           '-O3',
         ],
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'cflags': [
-              '-fno-omit-frame-pointer',
-            ],
-            'defines': [
-              'NATIVE_CODE_HAS_FRAME_POINTERS'
-            ],
-          }],
+      },
+      'Dart_Android_Product': {
+        'abstract': 1,
+        'defines': [
+          'NDEBUG',
+          'PRODUCT',
+        ],
+        'cflags!': [
+          '-O2',
+          '-Os',
+        ],
+        'cflags': [
+          '-fdata-sections',
+          '-ffunction-sections',
+          '-O3',
         ],
       },
       'Dart_Android_ia32_Base': {
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index ebaf935..98d28fa 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -40,52 +40,77 @@
 
       'Dart_Linux_ia32_Base': {
         'abstract': 1,
-        'cflags': [ '-m32', '-msse2', '-mfpmath=sse' ],
-        'ldflags': [ '-m32', ],
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'cflags': [
-              # Clang on Linux will still omit frame pointers from leaf
-              # functions unless told otherwise:
-              # (note this flag only works on recent GCC versions.)
-              '-mno-omit-leaf-frame-pointer',
-            ],
-          }],
+        'cflags': [
+          '-m32',
+          '-msse2',
+          '-mfpmath=sse',
+        ],
+        'ldflags': [
+          '-m32',
         ],
       },
 
       'Dart_Linux_x64_Base': {
         'abstract': 1,
-        'cflags': [ '-m64', '-msse2' ],
-        'ldflags': [ '-m64', ],
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'cflags': [
-              # Clang on Linux will still omit frame pointers from leaf
-              # functions unless told otherwise:
-              # (note this flag only works on recent GCC versions.)
-              '-mno-omit-leaf-frame-pointer',
-            ],
-          }],
+        'cflags': [
+          '-m64',
+          '-msse2',
+        ],
+        'ldflags': [
+          '-m64',
         ],
       },
 
       'Dart_Linux_simarm_Base': {
         'abstract': 1,
-        'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
-        'ldflags': [ '-m32', ],
+        'cflags': [
+          '-O3',
+          '-m32',
+          '-msse2',
+          '-mfpmath=sse',
+        ],
+        'ldflags': [
+          '-m32',
+        ],
+      },
+
+      'Dart_Linux_simarmv6_Base': {
+        'abstract': 1,
+        'cflags': [
+          '-O3',
+          '-m32',
+          '-msse2',
+          '-mfpmath=sse',
+        ],
+        'ldflags': [
+          '-m32',
+        ],
       },
 
       'Dart_Linux_simarmv5te_Base': {
         'abstract': 1,
-        'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
-        'ldflags': [ '-m32', ],
+        'cflags': [
+          '-O3',
+          '-m32',
+          '-msse2',
+          '-mfpmath=sse',
+        ],
+        'ldflags': [
+          '-m32',
+        ],
       },
 
       'Dart_Linux_simarm64_Base': {
         'abstract': 1,
-        'cflags': [ '-O3', '-m64', '-msse2', '-mfpmath=sse' ],
-        'ldflags': [ '-m64', ],
+        'cflags': [
+          '-O3',
+          '-m64',
+          '-msse2',
+          '-mfpmath=sse',
+        ],
+        'ldflags': [
+          '-m64',
+        ],
       },
 
       # ARM cross-build
@@ -101,8 +126,14 @@
           ],
         }],
         ['_toolset=="host"', {
-          'cflags': ['-m32', '-msse2', '-mfpmath=sse' ],
-          'ldflags': ['-m32'],
+          'cflags': [
+            '-m32',
+            '-msse2',
+            '-mfpmath=sse',
+          ],
+          'ldflags': [
+            '-m32',
+          ],
         }]]
       },
 
@@ -117,6 +148,41 @@
         ],
       },
 
+      # ARMv6 cross-build
+      'Dart_Linux_xarmv6_Base': {
+        'abstract': 1,
+        'target_conditions': [
+        ['_toolset=="target"', {
+          'cflags': [
+            '-march=armv6',
+            '-mfpu=vfp',
+            '-Wno-psabi', # suppresses va_list warning
+            '-fno-strict-overflow',
+          ],
+        }],
+        ['_toolset=="host"', {
+          'cflags': [
+            '-m32',
+            '-msse2',
+            '-mfpmath=sse',
+          ],
+          'ldflags': [
+            '-m32',
+          ],
+        }]]
+      },
+
+      # ARMv6 native build
+      'Dart_Linux_armv6_Base': {
+        'abstract': 1,
+        'cflags': [
+          '-march=armv6',
+          '-mfpu=vfp',
+          '-Wno-psabi', # suppresses va_list warning
+          '-fno-strict-overflow',
+        ],
+      },
+
       # ARMv5 cross-build
       'Dart_Linux_xarmv5te_Base': {
         'abstract': 1,
@@ -132,8 +198,14 @@
           ],
         }],
         ['_toolset=="host"', {
-          'cflags': ['-m32', '-msse2', '-mfpmath=sse' ],
-          'ldflags': ['-m32'],
+          'cflags': [
+            '-m32',
+            '-msse2',
+            '-mfpmath=sse',
+          ],
+          'ldflags': [
+            '-m32',
+          ],
         }]]
       },
 
@@ -155,24 +227,41 @@
         'abstract': 1,
         'target_conditions': [
         ['_toolset=="target"', {
-          'cflags': [ '-O3', ],
+          'cflags': [
+            '-O3',
+          ],
         }],
         ['_toolset=="host"', {
-          'cflags': ['-O3', '-m64', '-msse2'],
-          'ldflags': ['-m64'],
+          'cflags': [
+            '-O3',
+            '-m64',
+            '-msse2',
+          ],
+          'ldflags': [
+            '-m64',
+          ],
         }]]
       },
 
       # ARM64 native build
       'Dart_Linux_arm64_Base': {
         'abstract': 1,
-        'cflags': [ '-O3', ],
+        'cflags': [
+          '-O3',
+        ],
       },
 
       'Dart_Linux_simmips_Base': {
         'abstract': 1,
-        'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
-        'ldflags': [ '-m32', ],
+        'cflags': [
+          '-O3',
+          '-m32',
+          '-msse2',
+          '-mfpmath=sse',
+        ],
+        'ldflags': [
+          '-m32',
+        ],
       },
 
       # MIPS cross-build
@@ -191,8 +280,15 @@
             ],
           }],
           ['_toolset=="host"',{
-            'cflags': [ '-O3', '-m32', '-msse2', '-mfpmath=sse' ],
-            'ldflags': [ '-m32' ],
+            'cflags': [
+              '-O3',
+              '-m32',
+              '-msse2',
+              '-mfpmath=sse',
+            ],
+            'ldflags': [
+              '-m32',
+            ],
         }]]
       },
 
@@ -208,36 +304,38 @@
 
       'Dart_Linux_Debug': {
         'abstract': 1,
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'cflags': [
-              '-fno-omit-frame-pointer',
-            ],
-            'defines': [
-              'NATIVE_CODE_HAS_FRAME_POINTERS'
-            ],
-          }],
-        ],
         'cflags': [
           '-O<(dart_debug_optimization_level)',
+          '-fno-omit-frame-pointer',
+          # Clang on Linux will still omit frame pointers from leaf
+          # functions unless told otherwise:
+          # (note this flag only works on recent GCC versions.)
+          #'-mno-omit-leaf-frame-pointer',
         ],
       },
 
       'Dart_Linux_Release': {
         'abstract': 1,
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'cflags': [
-              '-fno-omit-frame-pointer',
-            ],
-            'defines': [
-              'NATIVE_CODE_HAS_FRAME_POINTERS'
-            ],
-          }],
-        ],
         'cflags': [
           '-O3',
           '-ffunction-sections',
+          '-fno-omit-frame-pointer',
+          # Clang on Linux will still omit frame pointers from leaf
+          # functions unless told otherwise:
+          # (note this flag only works on recent GCC versions.)
+          #'-mno-omit-leaf-frame-pointer',
+        ],
+        'ldflags': [
+          '-Wl,--gc-sections',
+        ],
+      },
+
+      'Dart_Linux_Product': {
+        'abstract': 1,
+        'cflags': [
+          '-O3',
+          '-ffunction-sections',
+          '-fomit-frame-pointer',
         ],
         'ldflags': [
           '-Wl,--gc-sections',
diff --git a/tools/gyp/configurations_msvs.gypi b/tools/gyp/configurations_msvs.gypi
index 3c859ce..3650127 100644
--- a/tools/gyp/configurations_msvs.gypi
+++ b/tools/gyp/configurations_msvs.gypi
@@ -24,6 +24,9 @@
       'Dart_Win_simarm_Base': {
         'abstract': 1,
       },
+      'Dart_Win_simarmv6_Base': {
+        'abstract': 1,
+      },
       'Dart_Win_simarmv5te_Base': {
         'abstract': 1,
       },
@@ -43,6 +46,7 @@
             'ExceptionHandling': '0',
             'RuntimeTypeInfo': 'false',
             'RuntimeLibrary': '1',  # /MTd - Multi-threaded, static (debug)
+            'OmitFramePointers': 'false',
           },
           'VCLinkerTool': {
             'LinkIncremental': '2',
@@ -55,18 +59,6 @@
             ],
           },
         },
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'msvs_settings': {
-              'VCCLCompilerTool': {
-                'OmitFramePointers': 'false',
-              },
-            },
-            'defines': [
-              'NATIVE_CODE_HAS_FRAME_POINTERS'
-            ],
-          }],
-        ],
         # C4351 warns MSVC follows the C++ specification regarding array
         # initialization in member initializers.  Code that expects the
         # specified behavior should silence this warning.
@@ -85,6 +77,39 @@
             'RuntimeTypeInfo': 'false',
             'StringPooling': 'true',
             'RuntimeLibrary': '0',  # /MT - Multi-threaded, static
+            'OmitFramePointers': 'false',
+          },
+          'VCLinkerTool': {
+            'LinkIncremental': '1',
+            'GenerateDebugInformation': 'true',
+            'OptimizeReferences': '2',
+            'EnableCOMDATFolding': '2',
+            'StackReserveSize': '2097152',
+            'AdditionalDependencies': [
+              'advapi32.lib',
+              'shell32.lib',
+              'dbghelp.lib',
+            ],
+          },
+        },
+        # C4351 warns MSVC follows the C++ specification regarding array
+        # initialization in member initializers.  Code that expects the
+        # specified behavior should silence this warning.
+        'msvs_disabled_warnings': [4351],
+      },
+
+      'Dart_Win_Product': {
+        'abstract': 1,
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'Optimization': '2',
+            'InlineFunctionExpansion': '2',
+            'EnableIntrinsicFunctions': 'true',
+            'FavorSizeOrSpeed': '0',
+            'ExceptionHandling': '0',
+            'RuntimeTypeInfo': 'false',
+            'StringPooling': 'true',
+            'RuntimeLibrary': '0',  # /MT - Multi-threaded, static
           },
           'VCLinkerTool': {
             'LinkIncremental': '1',
@@ -93,24 +118,12 @@
             'EnableCOMDATFolding': '2',
             'StackReserveSize': '2097152',
             'AdditionalDependencies': [
-              'advapi32.lib',
-              'shell32.lib',
-              'dbghelp.lib',
+            'advapi32.lib',
+            'shell32.lib',
+            'dbghelp.lib',
             ],
           },
         },
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'msvs_settings': {
-              'VCCLCompilerTool': {
-                'OmitFramePointers': 'false',
-              },
-            },
-            'defines': [
-              'NATIVE_CODE_HAS_FRAME_POINTERS'
-            ],
-          }],
-        ],
         # C4351 warns MSVC follows the C++ specification regarding array
         # initialization in member initializers.  Code that expects the
         # specified behavior should silence this warning.
diff --git a/tools/gyp/configurations_xcode.gypi b/tools/gyp/configurations_xcode.gypi
index f709727..367f8f2 100644
--- a/tools/gyp/configurations_xcode.gypi
+++ b/tools/gyp/configurations_xcode.gypi
@@ -55,19 +55,6 @@
           'GCC_ENABLE_TRIGRAPHS': 'NO',
           'COMBINE_HIDPI_IMAGES': 'YES',
         },
-        'conditions': [
-          ['c_frame_pointers==1', {
-            'xcode_settings': {
-              'OTHER_CFLAGS': [
-                '-fno-omit-frame-pointer',
-                '-mno-omit-leaf-frame-pointer',
-              ],
-            },
-            'defines': [
-              'NATIVE_CODE_HAS_FRAME_POINTERS',
-            ],
-          }],
-        ],
       },
       'Dart_Macos_ia32_Base': {
         'abstract': 1,
@@ -78,6 +65,9 @@
       'Dart_Macos_simarm_Base': {
         'abstract': 1,
       },
+      'Dart_Macos_simarmv6_Base': {
+        'abstract': 1,
+      },
       'Dart_Macos_simarmv5te_Base': {
         'abstract': 1,
       },
@@ -89,9 +79,30 @@
       },
       'Dart_Macos_Debug': {
         'abstract': 1,
+        'xcode_settings': {
+          'OTHER_CFLAGS': [
+            '-fno-omit-frame-pointer',
+            '-mno-omit-leaf-frame-pointer',
+          ],
+        },
       },
       'Dart_Macos_Release': {
         'abstract': 1,
+        'xcode_settings': {
+          'OTHER_CFLAGS': [
+            '-fno-omit-frame-pointer',
+            '-mno-omit-leaf-frame-pointer',
+          ],
+        },
+      },
+      'Dart_Macos_Product': {
+        'abstract': 1,
+        'xcode_settings': {
+          'OTHER_CFLAGS': [
+            '-fomit-frame-pointer',
+            '-momit-leaf-frame-pointer',
+          ],
+        },
       },
     },
   },
diff --git a/tools/observatory_tool.py b/tools/observatory_tool.py
index a8595dc..4cb5dbf 100755
--- a/tools/observatory_tool.py
+++ b/tools/observatory_tool.py
@@ -29,6 +29,14 @@
 
 usage = """observatory_tool.py [options]"""
 
+def CreateTimestampFile(options):
+  if options.stamp != '':
+    dir_name = os.path.dirname(options.stamp)
+    if dir_name != '':
+      if not os.path.exists(dir_name):
+        os.mkdir(dir_name)
+    open(options.stamp, 'w').close()
+
 def BuildArguments():
   result = argparse.ArgumentParser(usage=usage)
   result.add_argument("--package-root", help="package root", default=None)
@@ -38,6 +46,7 @@
   result.add_argument("--command", help="[get, build, deploy]", default=None)
   result.add_argument("--silent", help="silence all output", default=None)
   result.add_argument("--sdk", help="Use prebuilt sdk", default=None)
+  result.add_argument("--stamp", help="Write a stamp file", default='')
   return result
 
 def ProcessOptions(options, args):
@@ -135,6 +144,8 @@
       # development flow.
       # REMOVE THE FOLLOWING LINE TO USE the dart_bootstrap binary.
       # return False
+    if not silent:
+      print >> sys.stderr, ('Running command "%s"') % (executable + command)
     return subprocess.call(executable + command,
                            stdout=silent_sink if silent else None,
                            stderr=silent_sink if silent else None)
@@ -200,11 +211,17 @@
     options.pub_executable = os.path.abspath(options.pub_executable)
   if (options.pub_snapshot != None):
     options.pub_snapshot = os.path.abspath(options.pub_snapshot)
+  if (options.stamp != ''):
+    options.stamp = os.path.abspath(options.stamp)
   if len(args) == 1:
     args[0] = os.path.abspath(args[0])
   # Pub must be run from the project's root directory.
   ChangeDirectory(options.directory)
-  return ExecuteCommand(options, args)
+  result = ExecuteCommand(options, args)
+  if result == 0:
+    CreateTimestampFile(options)
+  return result
+
 
 if __name__ == '__main__':
   sys.exit(main());
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/precompilation/test_linux.sh b/tools/precompilation/test_linux.sh
index 553dc18b..514ac04 100755
--- a/tools/precompilation/test_linux.sh
+++ b/tools/precompilation/test_linux.sh
@@ -10,6 +10,6 @@
 
 ./out/DebugX64/dart_no_snapshot --gen-precompiled-snapshot --package-root=out/DebugX64/packages/ "$1"
 
-gcc -m64 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
+gcc -nostartfiles -m64 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
 
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart_precompiled --run-precompiled-snapshot not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart_precompiled_runtime --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_linux_simarm.sh b/tools/precompilation/test_linux_simarm.sh
index e61b58b..bd0f1f0 100755
--- a/tools/precompilation/test_linux_simarm.sh
+++ b/tools/precompilation/test_linux_simarm.sh
@@ -10,6 +10,6 @@
 
 ./out/DebugSIMARM/dart_no_snapshot --gen-precompiled-snapshot --package-root=out/DebugX64/packages/ "$1"
 
-gcc -m32 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
+gcc -nostartfiles -m32 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
 
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugSIMARM/dart_precompiled --run-precompiled-snapshot not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugSIMARM/dart_precompiled_runtime --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_macos.sh b/tools/precompilation/test_macos.sh
index 57e02dc..ed90d12 100755
--- a/tools/precompilation/test_macos.sh
+++ b/tools/precompilation/test_macos.sh
@@ -10,6 +10,6 @@
 
 ./xcodebuild/DebugX64/dart_no_snapshot --gen-precompiled-snapshot --package-root=xcodebuild/DebugX64/packages/ "$1"
 
-clang -m64 -dynamiclib -o libprecompiled.dylib precompiled.S
+clang -nostartfiles -m64 -dynamiclib -o libprecompiled.dylib precompiled.S
 
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart_precompiled --run-precompiled-snapshot not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart_precompiled_runtime --run-precompiled-snapshot not_used.dart
diff --git a/tools/sdks/linux/dart-sdk.tar.gz.sha1 b/tools/sdks/linux/dart-sdk.tar.gz.sha1
index 90b6e73..9083f2b 100644
--- a/tools/sdks/linux/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/linux/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-2709941a74b808414feb005dfa50986680f9bd20
\ No newline at end of file
+360de5bc1ad8b525f2ccc98c80fd87131caaefe2
\ No newline at end of file
diff --git a/tools/sdks/mac/dart-sdk.tar.gz.sha1 b/tools/sdks/mac/dart-sdk.tar.gz.sha1
index 9f3c196..292199a 100644
--- a/tools/sdks/mac/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/mac/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-8d928e400289862483a11e798743e49815c06c43
\ No newline at end of file
+45bb23f239c67de5e01a24e7efcf4b323eb9c36c
\ No newline at end of file
diff --git a/tools/sdks/win/dart-sdk.tar.gz.sha1 b/tools/sdks/win/dart-sdk.tar.gz.sha1
index a5b7f6a..54587b2 100644
--- a/tools/sdks/win/dart-sdk.tar.gz.sha1
+++ b/tools/sdks/win/dart-sdk.tar.gz.sha1
@@ -1 +1 @@
-90d43da115a1eafe707f6f5c5c0d718ff716c227
\ No newline at end of file
+1264ca2ff3131284a53ccffadeb230835300c602
\ No newline at end of file
diff --git a/tools/test.py b/tools/test.py
index 69b9ed8..9a32fa5 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -16,7 +16,8 @@
   tools_dir = os.path.dirname(os.path.realpath(__file__))
   dart_script_name = 'test.dart'
   dart_test_script = string.join([tools_dir, dart_script_name], os.sep)
-  command = [utils.DartBinary(), '--checked', dart_test_script] + args
+  command = [utils.CheckedInSdkExecutable(),
+             '--checked', dart_test_script] + args
   exit_code = subprocess.call(command)
   utils.DiagnoseExitCode(exit_code, command)
   return exit_code
diff --git a/tools/testing/bin/linux/dart-arm.sha1 b/tools/testing/bin/linux/dart-arm.sha1
deleted file mode 100644
index c00a011..0000000
--- a/tools/testing/bin/linux/dart-arm.sha1
+++ /dev/null
@@ -1 +0,0 @@
-5246a42926c8d5c2ac785c952b76b746270c9484
\ No newline at end of file
diff --git a/tools/testing/bin/linux/dart-mips.sha1 b/tools/testing/bin/linux/dart-mips.sha1
deleted file mode 100644
index 6100eae..0000000
--- a/tools/testing/bin/linux/dart-mips.sha1
+++ /dev/null
@@ -1 +0,0 @@
-7ab189bca5c5cf2997b9ab5770a5b418cd4fa5b1
\ No newline at end of file
diff --git a/tools/testing/bin/linux/dart.sha1 b/tools/testing/bin/linux/dart.sha1
deleted file mode 100644
index d8f03be..0000000
--- a/tools/testing/bin/linux/dart.sha1
+++ /dev/null
@@ -1 +0,0 @@
-701c1f2bda5c7fa3cc0f044d7515237bdc2cc163
\ No newline at end of file
diff --git a/tools/testing/bin/macos/dart.sha1 b/tools/testing/bin/macos/dart.sha1
deleted file mode 100644
index c30354b..0000000
--- a/tools/testing/bin/macos/dart.sha1
+++ /dev/null
@@ -1 +0,0 @@
-ecefe6ba96b8da00d171e199b2801982f98cc78d
\ No newline at end of file
diff --git a/tools/testing/bin/windows/dart.exe.sha1 b/tools/testing/bin/windows/dart.exe.sha1
deleted file mode 100644
index c43f346..0000000
--- a/tools/testing/bin/windows/dart.exe.sha1
+++ /dev/null
@@ -1 +0,0 @@
-c1394c6a589c47f7a6a1315eb1f9885d66852d67
\ No newline at end of file
diff --git a/tools/testing/dart/co19_test.dart b/tools/testing/dart/co19_test.dart
index f138688e..d826263 100644
--- a/tools/testing/dart/co19_test.dart
+++ b/tools/testing/dart/co19_test.dart
@@ -11,7 +11,7 @@
  * co19.
  *
  * Usage:
- * [: ./tools/testing/bin/$OS/dart tools/testing/dart/co19_test.dart :]
+ * [: dart tools/testing/dart/co19_test.dart :]
  */
 
 library co19_test;
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index a89aad5..4794992 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -61,7 +61,6 @@
     bool useSdk = configuration['use_sdk'];
     bool isCsp = configuration['csp'];
     bool useCps = configuration['cps_ir'];
-    bool useNoopt = configuration['noopt'];
 
     switch (compiler) {
       case 'dart2analyzer':
@@ -74,13 +73,17 @@
             isHostChecked: isHostChecked, useCps: useCps, useSdk: useSdk,
             isCsp: isCsp, extraDart2jsOptions:
                 TestUtils.getExtraOptions(configuration, 'dart2js_options'));
+      case 'dart2app':
+        return new Dart2AppSnapshotCompilerConfiguration(
+            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,
-            isHostChecked: isHostChecked, useSdk: useSdk, useNoopt: useNoopt);
+            isHostChecked: isHostChecked, useSdk: useSdk);
       default:
         throw "Unknown compiler '$compiler'";
     }
@@ -142,17 +145,15 @@
 
 /// The "none" compiler.
 class NoneCompilerConfiguration extends CompilerConfiguration {
-  final bool useNoopt;
 
   NoneCompilerConfiguration({
       bool isDebug,
       bool isChecked,
       bool isHostChecked,
-      bool useSdk,
-      bool useNoopt})
+      bool useSdk})
       : super._subclass(
           isDebug: isDebug, isChecked: isChecked,
-          isHostChecked: isHostChecked, useSdk: useSdk), useNoopt = useNoopt;
+          isHostChecked: isHostChecked, useSdk: useSdk);
 
   bool get hasCompiler => false;
 
@@ -169,9 +170,6 @@
       args.add('--enable_asserts');
       args.add('--enable_type_checks');
     }
-    if (useNoopt) {
-      args.add('--noopt');
-    }
     return args
         ..addAll(vmOptions)
         ..addAll(sharedOptions)
@@ -305,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;
@@ -330,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');
@@ -341,15 +354,176 @@
       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) {
+    List<String> args = [];
+    if (isChecked) {
+      args.add('--enable_asserts');
+      args.add('--enable_type_checks');
+    }
+    return args
+        ..addAll(filterVmOptions(vmOptions))
+        ..addAll(sharedOptions)
+        ..addAll(originalArguments);
+  }
+
+  List<String> computeRuntimeArguments(
+      RuntimeConfiguration runtimeConfiguration,
+      String buildDir,
+      TestInformation info,
+      List<String> vmOptions,
+      List<String> sharedOptions,
+      List<String> originalArguments,
+      CommandArtifact artifact) {
+    List<String> args = [];
+    if (isChecked) {
+      args.add('--enable_asserts');
+      args.add('--enable_type_checks');
+    }
+    return args
+        ..addAll(vmOptions)
+        ..addAll(sharedOptions)
+        ..addAll(originalArguments);
+  }
+}
+
+
+class Dart2AppSnapshotCompilerConfiguration extends CompilerConfiguration {
+  Dart2AppSnapshotCompilerConfiguration({
+      bool isDebug,
+      bool isChecked})
+      : super._subclass(isDebug: isDebug, isChecked: isChecked);
+
+  int computeTimeoutMultiplier() {
+    int multiplier = 2;
+    if (isDebug) multiplier *= 4;
+    if (isChecked) multiplier *= 2;
+    return multiplier;
+  }
+
+  CommandArtifact computeCompilationArtifact(
+      String buildDir,
+      String tempDir,
+      CommandBuilder commandBuilder,
+      List arguments,
+      Map<String, String> environmentOverrides) {
+    String outputName = computeOutputName(tempDir);
+    return new CommandArtifact(
+        <Command>[
+            this.computeCompilationCommand(
+                outputName,
+                buildDir,
+                CommandBuilder.instance,
+                arguments,
+                environmentOverrides)],
+        outputName,
+        'application/dart-snapshot');
+  }
+
+  String computeOutputName(String tempDir) {
+    var randName = TestUtils.getRandomNumber().toString();
+    return '$tempDir/test.$randName';
+  }
+
+  CompilationCommand computeCompilationCommand(
+      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=$outputName");
+    args.addAll(arguments);
+
+    return commandBuilder.getCompilationCommand(
+        'dart2snapshot', outputName, !useSdk,
         bootstrapDependencies(buildDir),
         exec, args, environmentOverrides);
   }
diff --git a/tools/testing/dart/http_server.dart b/tools/testing/dart/http_server.dart
index 843aaaf..1cfdb65 100644
--- a/tools/testing/dart/http_server.dart
+++ b/tools/testing/dart/http_server.dart
@@ -172,7 +172,7 @@
   }
 
   String httpServerCommandline() {
-    var dart = TestUtils.dartTestExecutable.toNativePath();
+    var dart = Platform.resolvedExecutable;
     var dartDir = TestUtils.dartDir;
     var script = dartDir.join(new Path("tools/testing/dart/http_server.dart"));
     var buildDirectory = _buildDirectory.toNativePath();
diff --git a/tools/testing/dart/runtime_configuration.dart b/tools/testing/dart/runtime_configuration.dart
index 55810eb..c2b2aed 100644
--- a/tools/testing/dart/runtime_configuration.dart
+++ b/tools/testing/dart/runtime_configuration.dart
@@ -52,6 +52,9 @@
       case 'vm':
         return new StandaloneDartRuntimeConfiguration();
 
+      case 'dart_product':
+        return new DartProductRuntimeConfiguration();
+
       case 'dart_precompiled':
         return new DartPrecompiledRuntimeConfiguration();
 
@@ -66,7 +69,7 @@
   RuntimeConfiguration._subclass();
 
   int computeTimeoutMultiplier({
-      bool isDebug: false,
+      String mode,
       bool isChecked: false,
       String arch}) {
     return 1;
@@ -165,13 +168,15 @@
       : super._subclass();
 
   int computeTimeoutMultiplier({
-      bool isDebug: false,
+      String mode,
       bool isChecked: false,
       String arch}) {
     int multiplier = 1;
     switch (arch) {
       case 'simarm':
       case 'arm':
+      case 'simarmv6':
+      case 'armv6':
       case' simarmv5te':
       case 'armv5te':
       case 'simmips':
@@ -180,7 +185,7 @@
         multiplier *= 4;
         break;
     }
-    if (isDebug) {
+    if (mode == 'debug') {
       multiplier *= 2;
     }
     return multiplier;
@@ -191,7 +196,7 @@
 /// program named Dump Render Tree, hence the name.
 class DrtRuntimeConfiguration extends DartVmRuntimeConfiguration {
   int computeTimeoutMultiplier({
-      bool isDebug: false,
+      String mode,
       bool isChecked: false,
       String arch}) {
     return 4 // Allow additional time for browser testing to run.
@@ -199,7 +204,7 @@
         // JavaScript and Dart code.  I'm not convinced the inherited timeout
         // multiplier is relevant for JavaScript.
         * super.computeTimeoutMultiplier(
-            isDebug: isDebug, isChecked: isChecked);
+            mode: mode, isChecked: isChecked);
   }
 }
 
@@ -216,11 +221,37 @@
     if (script != null && type != 'application/dart') {
       throw "Dart VM cannot run files of type '$type'.";
     }
+    String executable = suite.configuration['noopt']
+        ? suite.dartVmNooptBinaryFileName
+        : suite.dartVmBinaryFileName;
     return <Command>[commandBuilder.getVmCommand(
-          suite.dartVmBinaryFileName, arguments, environmentOverrides)];
+          executable, arguments, environmentOverrides)];
   }
 }
 
+class DartProductRuntimeConfiguration extends DartVmRuntimeConfiguration {
+  List<Command> computeRuntimeCommands(
+      TestSuite suite,
+      CommandBuilder commandBuilder,
+      CommandArtifact artifact,
+      List<String> arguments,
+      Map<String, String> environmentOverrides) {
+    String script = artifact.filename;
+    String type = artifact.mimeType;
+    if (script != null && type != 'application/dart-snapshot') {
+      throw "dart_product cannot run files of type '$type'.";
+    }
+
+    var augmentedArgs = new List();
+    augmentedArgs.add("--run-full-snapshot=${artifact.filename}");
+    augmentedArgs.addAll(arguments);
+
+    return <Command>[commandBuilder.getVmCommand(
+          suite.dartVmProductBinaryFileName,
+          augmentedArgs,
+          environmentOverrides)];
+  }
+}
 
 class DartPrecompiledRuntimeConfiguration extends DartVmRuntimeConfiguration {
   List<Command> computeRuntimeCommands(
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_options.dart b/tools/testing/dart/test_options.dart
index 92514fe..26d5249 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -50,7 +50,7 @@
               'mode',
               'Mode in which to run the tests',
               ['-m', '--mode'],
-              ['all', 'debug', 'release'],
+              ['all', 'debug', 'release', 'product'],
               'debug'),
           new _TestOptionSpecification(
               'compiler',
@@ -65,9 +65,13 @@
          none (compile only)),
 
    dart2analyzer: Perform static analysis on Dart code by running the analyzer
-          (only valid with the following runtimes: none)''',
+          (only valid with the following runtimes: none)
+
+   dart2app: Compile the Dart code into an app snapshot before running the test
+          (only valid with the following runtimes: dart_product)''',
               ['-c', '--compiler'],
-              ['none', 'precompiler', 'dart2js', 'dart2analyzer'],
+              ['none', 'precompiler', 'dart2js', 'dart2analyzer',
+               'dart2app'],
               'none'),
           // TODO(antonm): fix the option drt.
           new _TestOptionSpecification(
@@ -78,6 +82,8 @@
     dart_precompiled: Run a precompiled snapshot on a variant of the standalone
                       dart vm lacking a JIT.
 
+    dart_product: Run a full app snapshot in product mode.
+
     d8: Run JavaScript from the command line using v8.
 
     jsshell: Run JavaScript from the command line using firefox js-shell.
@@ -98,7 +104,8 @@
     none: No runtime, compile only (for example, used for dart2analyzer static
           analysis tests).''',
               ['-r', '--runtime'],
-              ['vm', 'dart_precompiled', 'd8', 'jsshell', 'drt', 'dartium',
+              ['vm', 'dart_precompiled', 'dart_product',
+               'd8', 'jsshell', 'drt', 'dartium',
                'ff', 'firefox',
                'chrome', 'safari', 'ie9', 'ie10', 'ie11', 'opera',
                'chromeOnAndroid', 'safarimobilesim',
@@ -108,8 +115,8 @@
               'arch',
               'The architecture to run tests for',
               ['-a', '--arch'],
-              ['all', 'ia32', 'x64', 'arm', 'armv5te', 'arm64', 'mips',
-               'simarm', 'simarmv5te', 'simarm64', 'simmips'],
+              ['all', 'ia32', 'x64', 'arm', 'armv6', 'armv5te', 'arm64', 'mips',
+               'simarm', 'simarmv6', 'simarmv5te', 'simarm64', 'simmips'],
               'x64'),
           new _TestOptionSpecification(
               'system',
@@ -648,6 +655,9 @@
       case 'dart2analyzer':
         validRuntimes = const ['none'];
         break;
+      case 'dart2app':
+        validRuntimes = const ['dart_product'];
+        break;
       case 'precompiler':
         validRuntimes = const ['dart_precompiled'];
         break;
@@ -692,7 +702,7 @@
       configuration['arch'] = 'ia32,x64,simarm,simarm64,simmips';
     }
     if (configuration['mode'] == 'all') {
-      configuration['mode'] = 'debug,release';
+      configuration['mode'] = 'debug,release,product';
     }
 
     if (configuration['report_in_json']) {
@@ -808,7 +818,7 @@
           new CompilerConfiguration(configuration).computeTimeoutMultiplier();
       int runtimeMultiplier =
           new RuntimeConfiguration(configuration).computeTimeoutMultiplier(
-              isDebug: configuration['mode'] == 'debug',
+              mode: configuration['mode'],
               isChecked: configuration['checked'],
               arch: configuration['arch']);
       configuration['timeout'] = 60 * compilerMulitiplier * runtimeMultiplier;
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index ffd9921..a4abf47 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -292,7 +292,7 @@
       retry == other.retry;
 
   String get reproductionCommand {
-    var parts = [TestUtils.dartTestExecutable.toString(),
+    var parts = [io.Platform.resolvedExecutable,
                 'tools/testing/dart/launch_browser.dart',
                 browser,
                 url];
@@ -1679,7 +1679,8 @@
     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 533c01c..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";
@@ -212,13 +213,43 @@
     return dartExecutable;
   }
 
+  String get dartVmNooptBinaryFileName {
+    // Controlled by user with the option "--dart".
+    String dartExecutable = configuration['dart'];
+
+    if (dartExecutable == '') {
+      String suffix = executableBinarySuffix;
+      dartExecutable = useSdk
+          ? '$buildDir/dart-sdk/bin/dart_noopt$suffix'
+          : '$buildDir/dart_noopt$suffix';
+    }
+
+    TestUtils.ensureExists(dartExecutable, configuration);
+    return dartExecutable;
+  }
+
   String get dartPrecompiledBinaryFileName {
     // Controlled by user with the option "--dart_precompiled".
     String dartExecutable = configuration['dart_precompiled'];
 
     if (dartExecutable == null || dartExecutable == '') {
       String suffix = executableBinarySuffix;
-      dartExecutable = '$buildDir/dart_precompiled$suffix';
+      dartExecutable = '$buildDir/dart_precompiled_runtime$suffix';
+    }
+
+    TestUtils.ensureExists(dartExecutable, configuration);
+    return dartExecutable;
+  }
+
+  String get dartVmProductBinaryFileName {
+    // Controlled by user with the option "--dart".
+    String dartExecutable = configuration['dart'];
+
+    if (dartExecutable == '') {
+      String suffix = executableBinarySuffix;
+      dartExecutable = useSdk
+          ? '$buildDir/dart-sdk/bin/dart_product$suffix'
+          : '$buildDir/dart_product$suffix';
     }
 
     TestUtils.ensureExists(dartExecutable, configuration);
@@ -987,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,
@@ -1019,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);
@@ -1033,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 =
@@ -1792,8 +1835,9 @@
   }
 
   List<List<String>> getVmOptions(Map optionsFromFile) {
-    var COMPILERS = const ['none', 'precompiler'];
-    var RUNTIMES = const ['none', 'dart_precompiled', 'vm', 'drt', 'dartium',
+    var COMPILERS = const ['none', 'precompiler', 'dart2app'];
+    var RUNTIMES = const ['none', 'dart_precompiled', 'dart_product', 'vm',
+                          'drt', 'dartium',
                           'ContentShellOnAndroid', 'DartiumOnAndroid'];
     var needsVmOptions = COMPILERS.contains(configuration['compiler']) &&
                          RUNTIMES.contains(configuration['runtime']);
@@ -2118,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();
@@ -2126,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.
    */
@@ -2201,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");
   }
@@ -2325,7 +2393,20 @@
     // is an X in front of the arch. We don't allow both a cross compiled
     // and a normal version to be present (except if you specifically pass
     // in the build_directory).
-    var mode = (configuration['mode'] == 'debug') ? 'Debug' : 'Release';
+    var mode;
+    switch (configuration['mode']) {
+      case 'debug':
+        mode = 'Debug';
+        break;
+      case 'release':
+        mode = 'Release';
+        break;
+      case 'product':
+        mode = 'Product';
+        break;
+      default:
+        throw 'Unrecognized mode configuration: ${configuration['mode']}';
+    }
     var arch = configuration['arch'].toUpperCase();
     var normal = '$mode$arch';
     var cross = '${mode}X$arch';
@@ -2343,19 +2424,6 @@
   }
 
   /**
-   * Returns the path to the dart binary checked into the repo, used for
-   * bootstrapping test.dart.
-   */
-  static Path get dartTestExecutable {
-    var path = '$dartDir/tools/testing/bin/'
-        '${Platform.operatingSystem}/dart';
-    if (Platform.operatingSystem == 'windows') {
-      path = '$path.exe';
-    }
-    return new Path(path);
-  }
-
-  /**
    * Gets extra options under [key] passed to the testing script.
    */
   static List<String> getExtraOptions(Map configuration, String key) {
diff --git a/tools/utils.py b/tools/utils.py
index aaef94c..6965a1c 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -52,6 +52,8 @@
   os_id = platform.machine()
   if os_id.startswith('armv5te'):
     return 'armv5te'
+  elif os_id.startswith('armv6'):
+    return 'armv6'
   elif os_id.startswith('arm'):
     return 'arm'
   elif os_id.startswith('aarch64'):
@@ -213,6 +215,7 @@
 BUILD_MODES = {
   'debug': 'Debug',
   'release': 'Release',
+  'product': 'Product',
 }
 
 
@@ -228,10 +231,12 @@
   'ia32': 'ia32',
   'x64': 'ia32',
   'arm': 'arm',
+  'armv6': 'arm',
   'armv5te': 'arm',
   'arm64': 'arm',
   'mips': 'mips',
   'simarm': 'ia32',
+  'simarmv6': 'ia32',
   'simarmv5te': 'ia32',
   'simmips': 'ia32',
   'simarm64': 'ia32',
@@ -524,6 +529,7 @@
   print "GuessVisualStudioPath() -> ", GuessVisualStudioPath()
   print "GetGitRevision() -> ", GetGitRevision()
   print "GetVersionFileContent() -> ", GetVersionFileContent()
+  print "GetGitNumber() -> ", GetGitNumber()
 
 class Error(Exception):
   pass
@@ -568,35 +574,6 @@
   return pipe.returncode, output
 
 
-def DartBinary():
-  # TODO(24311): Replace all uses of this with CheckedInSdk[Fix]Executable().
-  tools_dir = os.path.dirname(os.path.realpath(__file__))
-  dart_binary_prefix = os.path.join(tools_dir, 'testing', 'bin')
-  if IsWindows():
-    return os.path.join(dart_binary_prefix, 'windows', 'dart.exe')
-  else:
-    arch = GuessArchitecture()
-    system = GuessOS()
-    if arch == 'armv5te':
-      # TODO(zra): This binary does not exist, yet. Check one in once we have
-      # sufficient stability.
-      return os.path.join(dart_binary_prefix, system, 'dart-armv5te')
-    elif arch == 'arm':
-      return os.path.join(dart_binary_prefix, system, 'dart-arm')
-    elif arch == 'arm64':
-      return os.path.join(dart_binary_prefix, system, 'dart-arm64')
-    elif arch == 'mips':
-      return os.path.join(dart_binary_prefix, system, 'dart-mips')
-    else:
-      return os.path.join(dart_binary_prefix, system, 'dart')
-
-
-def DartSdkBinary():
-  tools_dir = os.path.dirname(os.path.realpath(__file__))
-  dart_binary_prefix = os.path.join(tools_dir, '..', 'sdk' , 'bin')
-  return os.path.join(dart_binary_prefix, 'dart')
-
-
 # The checked-in SDKs are documented at
 #     https://github.com/dart-lang/sdk/wiki/The-checked-in-SDK-in-tools
 def CheckedInSdkPath():
@@ -627,7 +604,14 @@
     elif arch == 'arm':
       name = 'dart-arm'
     elif arch == 'arm64':
-      name = 'dart-arm'
+      name = 'dart-arm64'
+    elif arch == 'armv5te':
+      # TODO(zra): This binary does not exist, yet. Check one in once we have
+      # sufficient stability.
+      name = 'dart-armv5te'
+    elif arch == 'armv6':
+      # TODO(zra): Ditto.
+      name = 'dart-armv6'
   return os.path.join(CheckedInSdkPath(), 'bin', name)
 
 
diff --git a/utils/dartanalyzer/dartanalyzer.gyp b/utils/dartanalyzer/dartanalyzer.gyp
index 9617f05..6aec554 100644
--- a/utils/dartanalyzer/dartanalyzer.gyp
+++ b/utils/dartanalyzer/dartanalyzer.gyp
@@ -30,6 +30,25 @@
             '../../pkg/analyzer_cli/bin/analyzer.dart',
           ],
         },
+        {
+          'action_name': 'generate_summaries',
+          'inputs': [
+            '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
+            '<(SHARED_INTERMEDIATE_DIR)/packages.stamp',
+            '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../sdk/lib"])',
+            '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../pkg/analyzer"])',
+          ],
+          'outputs': [
+            '<(SHARED_INTERMEDIATE_DIR)/spec.sum',
+            '<(SHARED_INTERMEDIATE_DIR)/strong.sum',
+          ],
+          'action': [
+            '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
+            '--package-root=<(PRODUCT_DIR)/packages/',
+            '../../pkg/analyzer/tool/summary/build_sdk_summaries.dart',
+            '<(SHARED_INTERMEDIATE_DIR)',
+          ],
+        },
       ],
     },
   ],